From 026a7bbc2cceb93125bbda580c86e55c05bd976d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sat, 20 Sep 2008 12:59:23 +0000 Subject: [PATCH] Add support for configuring DVR settings. --- dvr/dvr.h | 5 +- dvr/dvr_db.c | 109 +++++++++++++++++++++++++++++++--- webui/extjs.c | 25 +++++++- webui/static/app/dvr.js | 68 +++++++++++++++++++++ webui/static/app/tvheadend.js | 1 + 5 files changed, 198 insertions(+), 10 deletions(-) diff --git a/dvr/dvr.h b/dvr/dvr.h index 52b50792..c32462e8 100644 --- a/dvr/dvr.h +++ b/dvr/dvr.h @@ -27,7 +27,7 @@ extern char *dvr_storage; extern char *dvr_format; extern char *dvr_file_postfix; - +extern uint32_t dvr_retention_days; LIST_HEAD(dvr_rec_stream_list, dvr_rec_stream); @@ -127,6 +127,9 @@ void dvr_entry_cancel(dvr_entry_t *de); void dvr_entry_dec_ref(dvr_entry_t *de); +void dvr_storage_set(const char *storage); + +void dvr_retention_set(int days); /** * Query interface diff --git a/dvr/dvr_db.c b/dvr/dvr_db.c index 94d65845..6c21be94 100644 --- a/dvr/dvr_db.c +++ b/dvr/dvr_db.c @@ -17,6 +17,8 @@ */ #include +#include +#include #include #include @@ -29,15 +31,15 @@ char *dvr_storage; char *dvr_format; char *dvr_file_postfix; +uint32_t dvr_retention_days; static int de_tally; -static int dvr_retention_time = 86400 * 31; struct dvr_entry_list dvrentries; -static void dvr_save(dvr_entry_t *de); +static void dvr_entry_save(dvr_entry_t *de); static void dvr_timer_expire(void *aux); static void dvr_timer_start_recording(void *aux); @@ -75,7 +77,7 @@ dvr_entry_link(dvr_entry_t *de) if(now >= de->de_stop || de->de_dont_reschedule) { de->de_sched_state = DVR_COMPLETED; gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, - de->de_stop + dvr_retention_time); + de->de_stop + dvr_retention_days * 86400); } else { de->de_sched_state = DVR_SCHEDULED; @@ -125,7 +127,7 @@ dvr_entry_create_by_event(event_t *e, const char *creator) de->de_title, de->de_channel->ch_name, tbuf, creator); dvrdb_changed(); - dvr_save(de); + dvr_entry_save(de); } @@ -244,7 +246,7 @@ dvr_db_load(void) * */ static void -dvr_save(dvr_entry_t *de) +dvr_entry_save(dvr_entry_t *de) { htsmsg_t *m = htsmsg_create(); @@ -304,10 +306,10 @@ dvr_stop_recording(dvr_entry_t *de, const char *errmsg) de->de_error ?: "Program ended"); dvrdb_changed(); - dvr_save(de); + dvr_entry_save(de); gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, - de->de_stop + dvr_retention_time); + de->de_stop + dvr_retention_days * 86400); } @@ -387,13 +389,104 @@ dvr_entry_cancel(dvr_entry_t *de) void dvr_init(void) { - dvr_storage = strdup("/home/andoma/media/dvr"); + htsmsg_t *m; + char buf[500]; + const char *homedir; + struct stat st; + + /* Default settings */ + + dvr_retention_days = 31; dvr_format = strdup("matroska"); dvr_file_postfix = strdup("mkv"); + /* Override settings with config */ + + if((m = hts_settings_load("dvr")) != NULL) { + htsmsg_get_u32(m, "retention-days", &dvr_retention_days); + tvh_str_set(&dvr_storage, htsmsg_get_str(m, "storage")); + + htsmsg_destroy(m); + } + + if(dvr_storage == NULL) { + /* Try to figure out a good place to put them videos */ + + homedir = getenv("HOME"); + + if(homedir != NULL) { + snprintf(buf, sizeof(buf), "%s/Videos", homedir); + if(stat(buf, &st) == 0 && S_ISDIR(st.st_mode)) + dvr_storage = strdup(buf); + + else if(stat(homedir, &st) == 0 && S_ISDIR(st.st_mode)) + dvr_storage = strdup(homedir); + else + dvr_storage = strdup(getcwd(buf, sizeof(buf))); + } + + fprintf(stderr, + "\nNotice: Digital Video Recorder\n"); + fprintf(stderr, + " Output directory for video recording is not yet configured.\n"); + fprintf(stderr, + " Defaulting to to \"%s\".\n", dvr_storage); + fprintf(stderr, + " This can be changed from the web user interface.\n"); + } + dvr_db_load(); } +/** + * + */ +static void +dvr_save(void) +{ + htsmsg_t *m = htsmsg_create(); + htsmsg_add_str(m, "storage", dvr_storage); + htsmsg_add_u32(m, "retention-days", dvr_retention_days); + + hts_settings_save(m, "dvr"); + htsmsg_destroy(m); +} + +/** + * + */ +void +dvr_storage_set(const char *storage) +{ + if(!strcmp(dvr_storage, storage)) + return; + + tvh_str_set(&dvr_storage, storage); + dvr_save(); +} + + +/** + * + */ +void +dvr_retention_set(int days) +{ + dvr_entry_t *de; + if(days < 1 || dvr_retention_days == days) + return; + + dvr_retention_days = days; + + /* Also, rearm all timres */ + + LIST_FOREACH(de, &dvrentries, de_global_link) + if(de->de_sched_state == DVR_COMPLETED) + gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de, + de->de_stop + dvr_retention_days * 86400); + dvr_save(); +} + /** * diff --git a/webui/extjs.c b/webui/extjs.c index ee2664d0..b4cf40b2 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -887,11 +887,14 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hc->hc_reply; const char *op = http_arg_get(&hc->hc_req_args, "op"); - htsmsg_t *out; + htsmsg_t *out, *r; event_t *e; dvr_entry_t *de; const char *s; + if(op == NULL) + op = "loadSettings"; + pthread_mutex_lock(&global_lock); if(!strcmp(op, "recordEvent")) { @@ -918,6 +921,26 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque) out = htsmsg_create(); htsmsg_add_u32(out, "success", 1); + + } else if(!strcmp(op, "loadSettings")) { + + r = htsmsg_create(); + htsmsg_add_str(r, "storage", dvr_storage); + htsmsg_add_u32(r, "retention", dvr_retention_days); + out = json_single_record(r, "dvrSettings"); + + } else if(!strcmp(op, "saveSettings")) { + + if((s = http_arg_get(&hc->hc_req_args, "storage")) != NULL) + dvr_storage_set(s); + + if((s = http_arg_get(&hc->hc_req_args, "retention")) != NULL) + dvr_retention_set(atoi(s)); + + + out = htsmsg_create(); + htsmsg_add_u32(out, "success", 1); + } else { pthread_mutex_unlock(&global_lock); diff --git a/webui/static/app/dvr.js b/webui/static/app/dvr.js index e511574f..3ba774b9 100644 --- a/webui/static/app/dvr.js +++ b/webui/static/app/dvr.js @@ -188,3 +188,71 @@ tvheadend.dvr = function() { return panel; } + + +/** + * Configuration panel (located under configuration) + */ +tvheadend.dvrsettings = function() { + + var confreader = new Ext.data.JsonReader({ + root: 'dvrSettings', + }, ['storage','retention']); + + + var confpanel = new Ext.FormPanel({ + title:'Digital Video Recorder', + border:false, + bodyStyle:'padding:15px', + anchor: '100% 50%', + labelAlign: 'right', + labelWidth: 150, + waitMsgTarget: true, + reader: confreader, + defaultType: 'textfield', + layout: 'form', + items: [{ + width: 300, + fieldLabel: 'Recording system path', + name: 'storage' + }, new Ext.form.NumberField({ + allowNegative: false, + allowDecimals: false, + minValue: 1, + fieldLabel: 'Retention time (days)', + name: 'retention' + })], + tbar: [{ + tooltip: 'Save changes made to channel configuration below', + iconCls:'save', + text: "Save configuration", + handler: saveChanges + }], + + }); + + confpanel.on('render', function() { + confpanel.getForm().load({ + url:'/dvr', + params:{'op':'loadSettings'}, + success:function(form, action) { + confpanel.enable(); + } + }); + }); + + + function saveChanges() { + confpanel.getForm().submit({ + url:'/dvr', + params:{'op':'saveSettings'}, + waitMsg:'Saving Data...', + failure: function(form, action) { + Ext.Msg.alert('Save failed', action.result.errormsg); + } + }); + } + + return confpanel; +} + diff --git a/webui/static/app/tvheadend.js b/webui/static/app/tvheadend.js index a2672b68..862f5c9d 100644 --- a/webui/static/app/tvheadend.js +++ b/webui/static/app/tvheadend.js @@ -103,6 +103,7 @@ tvheadend.app = function() { title: 'Configuration', items: [new tvheadend.chconf, new tvheadend.cteditor, + new tvheadend.dvrsettings, new tvheadend.dvb, new tvheadend.acleditor, new tvheadend.cwceditor]