From c51b16224f417fa44287204f23ec3b52970bd111 Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Wed, 7 Jan 2015 12:33:42 +0200 Subject: [PATCH] [dvr] add "directory" option to auto and time recorder entries to override directory settings for matching recordings. Useful for e.g. recording multiple different shows into a single directory (e.g. news). Fixes #2123, fixes #2448 --- docs/html/dvr_autorec.html | 4 +++ docs/html/dvr_timerec.html | 4 +++ src/dvr/dvr.h | 9 ++++-- src/dvr/dvr_autorec.c | 11 ++++++- src/dvr/dvr_db.c | 15 +++++++++- src/dvr/dvr_rec.c | 59 ++++++++++++++++++++++--------------- src/dvr/dvr_timerec.c | 10 ++++++- src/htsp_server.c | 38 ++++++++++++++---------- src/webui/static/app/dvr.js | 10 ++++--- 9 files changed, 112 insertions(+), 48 deletions(-) diff --git a/docs/html/dvr_autorec.html b/docs/html/dvr_autorec.html index 1a482ecfd..a69e4e041 100644 --- a/docs/html/dvr_autorec.html +++ b/docs/html/dvr_autorec.html @@ -51,6 +51,10 @@ Check or clear this box to enable or disable this rule.
The name you've given to the rule, e.g. 'Stuff involving Jeremy Clarkson'.

+

Directory +
+When specified, this setting overrides the subdirectory rules specified by the DVR configuration and puts all recordings done by this entry into the specified subdirectory. Useful for e.g. recording multiple different news broadcasts into one common subdirectory called "News". +

Title (Regexp)
The title of the programme to look for. Note that this accepts case-insensitive regular expressions, so you can use pattern matching as Tvheadend scans the EPG for programmes to record. diff --git a/docs/html/dvr_timerec.html b/docs/html/dvr_timerec.html index 9643d2800..083e76bbe 100644 --- a/docs/html/dvr_timerec.html +++ b/docs/html/dvr_timerec.html @@ -50,6 +50,10 @@ Check or clear this box to enable or disable this rule.
The name you've given to the rule, e.g. 'Evening cartoons for the children'.

+

Directory +
+When specified, this setting overrides the subdirectory rules specified by the DVR configuration and puts all recordings done by this entry into the specified subdirectory. Useful for e.g. recording multiple different news broadcasts into one common subdirectory called "News". +

Title
Not sure how this differs from **Name* * diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index c4f1a93c1..91bd20960 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -159,6 +159,8 @@ typedef struct dvr_entry { char *de_comment; char *de_filename; /* Initially null if no filename has been generated yet */ + char *de_directory; /* Can be set for autorec entries, will override any + directory setting from the configuration */ lang_str_t *de_title; /* Title in UTF-8 (from EPG) */ lang_str_t *de_desc; /* Description in UTF-8 (from EPG) */ uint32_t de_content_type; /* Content type (from EPG) (only code) */ @@ -240,6 +242,7 @@ typedef struct dvr_autorec_entry { TAILQ_ENTRY(dvr_autorec_entry) dae_link; char *dae_name; + char *dae_directory; dvr_config_t *dae_config; LIST_ENTRY(dvr_autorec_entry) dae_config_link; @@ -294,6 +297,7 @@ typedef struct dvr_timerec_entry { TAILQ_ENTRY(dvr_timerec_entry) dte_link; char *dte_name; + char *dte_directory; dvr_config_t *dte_config; LIST_ENTRY(dvr_timerec_entry) dte_config_link; @@ -490,7 +494,7 @@ dvr_autorec_create_htsp(const char *dvr_config_name, const char *title, time_t stop_extra, dvr_prio_t pri, int retention, int min_duration, int max_duration, const char *owner, const char *creator, - const char *comment, const char *name); + const char *comment, const char *name, const char *directory); dvr_autorec_entry_t * dvr_autorec_add_series_link(const char *dvr_config_name, @@ -542,7 +546,8 @@ dvr_timerec_entry_t* dvr_timerec_create_htsp(const char *dvr_config_name, const char *title, channel_t *ch, uint32_t enabled, uint32_t start, uint32_t stop, uint32_t weekdays, dvr_prio_t pri, int retention, - const char *owner, const char *creator, const char *comment, const char *name); + const char *owner, const char *creator, const char *comment, + const char *name, const char *directory); static inline dvr_timerec_entry_t * dvr_timerec_find_by_uuid(const char *uuid) diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index be7ef861b..7e5f07096 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -210,7 +210,8 @@ dvr_autorec_create_htsp(const char *dvr_config_name, const char *title, uint32_t weekdays, time_t start_extra, time_t stop_extra, dvr_prio_t pri, int retention, int min_duration, int max_duration, - const char *owner, const char *creator, const char *comment, const char *name) + const char *owner, const char *creator, const char *comment, + const char *name, const char *directory) { dvr_autorec_entry_t *dae; htsmsg_t *conf, *days; @@ -231,6 +232,7 @@ dvr_autorec_create_htsp(const char *dvr_config_name, const char *title, htsmsg_add_str(conf, "creator", creator ?: ""); htsmsg_add_str(conf, "comment", comment ?: ""); htsmsg_add_str(conf, "name", name ?: ""); + htsmsg_add_str(conf, "directory", directory ?: ""); if (start >= 0) htsmsg_add_s32(conf, "start", start); @@ -308,6 +310,7 @@ autorec_entry_destroy(dvr_autorec_entry_t *dae, int delconf) LIST_REMOVE(dae, dae_config_link); free(dae->dae_name); + free(dae->dae_directory); free(dae->dae_owner); free(dae->dae_creator); free(dae->dae_comment); @@ -848,6 +851,12 @@ const idclass_t dvr_autorec_entry_class = { .id = "name", .name = "Name", .off = offsetof(dvr_autorec_entry_t, dae_name), + }, + { + .type = PT_STR, + .id = "directory", + .name = "Directory", + .off = offsetof(dvr_autorec_entry_t, dae_directory), }, { .type = PT_STR, diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 91f233461..f96c84c6c 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -514,9 +514,15 @@ dvr_entry_create_(const char *config_uuid, epg_broadcast_t *e, if (e) htsmsg_add_u32(conf, "broadcast", e->id); if (dae) + { htsmsg_add_str(conf, "autorec", idnode_uuid_as_str(&dae->dae_id)); + htsmsg_add_str(conf, "directory", dae->dae_directory ?: ""); + } if (dte) + { htsmsg_add_str(conf, "timerec", idnode_uuid_as_str(&dte->dte_id)); + htsmsg_add_str(conf, "directory", dte->dte_directory ?: ""); + } de = dvr_entry_create(NULL, conf); @@ -1845,6 +1851,13 @@ const idclass_t dvr_entry_class = { .off = offsetof(dvr_entry_t, de_filename), .opts = PO_RDONLY, }, + { + .type = PT_STR, + .id = "directory", + .name = "Directory", + .off = offsetof(dvr_entry_t, de_directory), + .opts = PO_RDONLY, + }, { .type = PT_U32, .id = "errorcode", @@ -2047,7 +2060,7 @@ dvr_entry_delete(dvr_entry_t *de) snprintf(path, sizeof(path), "%s", cfg->dvr_storage); - if(cfg->dvr_title_dir || cfg->dvr_channel_dir || cfg->dvr_dir_per_day) { + if(cfg->dvr_title_dir || cfg->dvr_channel_dir || cfg->dvr_dir_per_day || de->de_directory) { char *p; int l; diff --git a/src/dvr/dvr_rec.c b/src/dvr/dvr_rec.c index ab893fbdb..7784e2c32 100644 --- a/src/dvr/dvr_rec.c +++ b/src/dvr/dvr_rec.c @@ -198,39 +198,50 @@ pvr_generate_filename(dvr_entry_t *de, const streaming_start_t *ss) if (path[strlen(path)-1] == '/') path[strlen(path)-1] = '\0'; - /* Append per-day directory */ - if (cfg->dvr_dir_per_day) { - localtime_r(&de->de_start, &tm); - strftime(fullname, sizeof(fullname), "%F", &tm); - s = cleanup_filename(fullname, cfg); + /* Use the specified directory if set, otherwise construct it from the DVR + configuration */ + if (de->de_directory) { + char *directory = strdup(de->de_directory); + s = cleanup_filename(directory, cfg); if (s == NULL) return -1; snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); free(s); - } + } else { + /* Append per-day directory */ + if (cfg->dvr_dir_per_day) { + localtime_r(&de->de_start, &tm); + strftime(fullname, sizeof(fullname), "%F", &tm); + s = cleanup_filename(fullname, cfg); + if (s == NULL) + return -1; + snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); + free(s); + } - /* Append per-channel directory */ - if (cfg->dvr_channel_dir) { - char *chname = strdup(DVR_CH_NAME(de)); - s = cleanup_filename(chname, cfg); - free(chname); - if (s == NULL) + /* Append per-channel directory */ + if (cfg->dvr_channel_dir) { + char *chname = strdup(DVR_CH_NAME(de)); + s = cleanup_filename(chname, cfg); + free(chname); + if (s == NULL) return -1; - snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); - free(s); - } + snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); + free(s); + } - // TODO: per-brand, per-season + // TODO: per-brand, per-season - /* Append per-title directory */ - if (cfg->dvr_title_dir) { - char *title = strdup(lang_str_get(de->de_title, NULL)); - s = cleanup_filename(title, cfg); - free(title); - if (s == NULL) + /* Append per-title directory */ + if (cfg->dvr_title_dir) { + char *title = strdup(lang_str_get(de->de_title, NULL)); + s = cleanup_filename(title, cfg); + free(title); + if (s == NULL) return -1; - snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); - free(s); + snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s); + free(s); + } } if (makedirs(path, cfg->dvr_muxcnf.m_directory_permissions) != 0) diff --git a/src/dvr/dvr_timerec.c b/src/dvr/dvr_timerec.c index a593318a0..5d2957763 100644 --- a/src/dvr/dvr_timerec.c +++ b/src/dvr/dvr_timerec.c @@ -204,7 +204,8 @@ dvr_timerec_entry_t* dvr_timerec_create_htsp(const char *dvr_config_name, const char *title, channel_t *ch, uint32_t enabled, uint32_t start, uint32_t stop, uint32_t weekdays, dvr_prio_t pri, int retention, - const char *owner, const char *creator, const char *comment, const char *name) + const char *owner, const char *creator, const char *comment, + const char *name, const char *directory) { dvr_timerec_entry_t *dte; htsmsg_t *conf, *days; @@ -221,6 +222,7 @@ dvr_timerec_create_htsp(const char *dvr_config_name, const char *title, htsmsg_add_str(conf, "creator", creator ?: ""); htsmsg_add_str(conf, "comment", comment ?: ""); htsmsg_add_str(conf, "name", name ?: ""); + htsmsg_add_str(conf, "directory", directory ?: ""); htsmsg_add_u32(conf, "start", start); htsmsg_add_u32(conf, "stop", stop); @@ -539,6 +541,12 @@ const idclass_t dvr_timerec_entry_class = { .off = offsetof(dvr_timerec_entry_t, dte_title), .def.s = "Time-%x-%R", }, + { + .type = PT_STR, + .id = "directory", + .name = "Directory", + .off = offsetof(dvr_timerec_entry_t, dte_directory), + }, { .type = PT_STR, .id = "channel", diff --git a/src/htsp_server.c b/src/htsp_server.c index 673540a57..2206d4847 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -68,7 +68,7 @@ static void *htsp_server, *htsp_server_2; -#define HTSP_PROTO_VERSION 18 +#define HTSP_PROTO_VERSION 19 #define HTSP_ASYNC_OFF 0x00 #define HTSP_ASYNC_ON 0x01 @@ -766,15 +766,17 @@ htsp_build_autorecentry(dvr_autorec_entry_t *dae, const char *method) htsmsg_add_s64(out, "stopExtra", dae->dae_stop_extra); if(dae->dae_title) - htsmsg_add_str(out, "title", dae->dae_title); + htsmsg_add_str(out, "title", dae->dae_title); if(dae->dae_name) - htsmsg_add_str(out, "name", dae->dae_name); + htsmsg_add_str(out, "name", dae->dae_name); + if(dae->dae_directory) + htsmsg_add_str(out, "directory", dae->dae_directory); if(dae->dae_owner) - htsmsg_add_str(out, "owner", dae->dae_owner); + htsmsg_add_str(out, "owner", dae->dae_owner); if(dae->dae_creator) - htsmsg_add_str(out, "creator", dae->dae_creator); + htsmsg_add_str(out, "creator", dae->dae_creator); if(dae->dae_channel) - htsmsg_add_u32(out, "channel", channel_get_id(dae->dae_channel)); + htsmsg_add_u32(out, "channel", channel_get_id(dae->dae_channel)); htsmsg_add_str(out, "method", method); @@ -798,15 +800,17 @@ htsp_build_timerecentry(dvr_timerec_entry_t *dte, const char *method) htsmsg_add_s32(out, "stop", dte->dte_stop); if(dte->dte_title) - htsmsg_add_str(out, "title", dte->dte_title); + htsmsg_add_str(out, "title", dte->dte_title); if(dte->dte_name) - htsmsg_add_str(out, "name", dte->dte_name); + htsmsg_add_str(out, "name", dte->dte_name); + if(dte->dte_directory) + htsmsg_add_str(out, "directory", dte->dte_directory); if(dte->dte_owner) - htsmsg_add_str(out, "owner", dte->dte_owner); + htsmsg_add_str(out, "owner", dte->dte_owner); if(dte->dte_creator) - htsmsg_add_str(out, "creator", dte->dte_creator); + htsmsg_add_str(out, "creator", dte->dte_creator); if(dte->dte_channel) - htsmsg_add_u32(out, "channel", channel_get_id(dte->dte_channel)); + htsmsg_add_u32(out, "channel", channel_get_id(dte->dte_channel)); htsmsg_add_str(out, "method", method); @@ -1588,7 +1592,7 @@ htsp_method_addAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in) { htsmsg_t *out; dvr_autorec_entry_t *dae; - const char *dvr_config_name, *title, *creator, *comment, *name; + const char *dvr_config_name, *title, *creator, *comment, *name, *directory; int64_t start_extra, stop_extra; uint32_t u32, days_of_week, priority, min_duration, max_duration, retention, enabled; int32_t approx_time, start, start_window; @@ -1637,6 +1641,8 @@ htsp_method_addAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in) comment = ""; if (!(name = htsmsg_get_str(in, "name"))) name = ""; + if (!(directory = htsmsg_get_str(in, "directory"))) + directory = ""; /* Check access */ if (ch && !htsp_user_access_channel(htsp, ch)) @@ -1644,7 +1650,7 @@ htsp_method_addAutorecEntry(htsp_connection_t *htsp, htsmsg_t *in) dae = dvr_autorec_create_htsp(dvr_config_name, title, ch, enabled, start, start_window, days_of_week, start_extra, stop_extra, priority, retention, min_duration, max_duration, - htsp->htsp_granted_access->aa_username, creator, comment, name); + htsp->htsp_granted_access->aa_username, creator, comment, name, directory); /* create response */ out = htsmsg_create_map(); @@ -1697,7 +1703,7 @@ htsp_method_addTimerecEntry(htsp_connection_t *htsp, htsmsg_t *in) { htsmsg_t *out; dvr_timerec_entry_t *dte; - const char *dvr_config_name, *title, *creator, *comment, *name; + const char *dvr_config_name, *title, *creator, *comment, *name, *directory; uint32_t u32, days_of_week, priority, retention, start, stop, enabled; channel_t *ch = NULL; @@ -1728,6 +1734,8 @@ htsp_method_addTimerecEntry(htsp_connection_t *htsp, htsmsg_t *in) comment = ""; if (!(name = htsmsg_get_str(in, "name"))) name = ""; + if (!(directory = htsmsg_get_str(in, "directory"))) + directory = ""; /* Check access */ if (ch && !htsp_user_access_channel(htsp, ch)) @@ -1735,7 +1743,7 @@ htsp_method_addTimerecEntry(htsp_connection_t *htsp, htsmsg_t *in) /* Add actual timerec */ dte = dvr_timerec_create_htsp(dvr_config_name, title, ch, enabled, start, stop, days_of_week, - priority, retention, htsp->htsp_granted_access->aa_username, creator, comment, name); + priority, retention, htsp->htsp_granted_access->aa_username, creator, comment, name, directory); /* create response */ out = htsmsg_create_map(); diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index 2d81cfd86..d617076a9 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -434,6 +434,7 @@ tvheadend.autorec_editor = function(panel, index) { columns: { enabled: { width: 50 }, name: { width: 200 }, + directory: { width: 200 }, title: { width: 300 }, channel: { width: 200 }, tag: { width: 200 }, @@ -452,13 +453,13 @@ tvheadend.autorec_editor = function(panel, index) { add: { url: 'api/dvr/autorec', params: { - list: 'enabled,name,title,channel,tag,content_type,minduration,' + + list: 'enabled,name,directory,title,channel,tag,content_type,minduration,' + 'maxduration,weekdays,start,start_window,pri,config_name,comment' }, create: { } }, del: true, - list: 'enabled,name,title,channel,tag,content_type,minduration,' + + list: 'enabled,name,directory,title,channel,tag,content_type,minduration,' + 'maxduration,weekdays,start,start_window,pri,config_name,owner,creator,comment', columns: { weekdays: { @@ -492,6 +493,7 @@ tvheadend.timerec_editor = function(panel, index) { columns: { enabled: { width: 50 }, name: { width: 200 }, + directory: { width: 200 }, title: { width: 300 }, channel: { width: 200 }, weekdays: { width: 160 }, @@ -506,12 +508,12 @@ tvheadend.timerec_editor = function(panel, index) { add: { url: 'api/dvr/timerec', params: { - list: 'enabled,name,title,channel,weekdays,start,stop,pri,config_name,comment' + list: 'enabled,name,directory,title,channel,weekdays,start,stop,pri,config_name,comment' }, create: { } }, del: true, - list: 'enabled,name,title,channel,weekdays,start,stop,pri,config_name,owner,creator,comment', + list: 'enabled,name,directory,title,channel,weekdays,start,stop,pri,config_name,owner,creator,comment', columns: { weekdays: { renderer: function(st) { return tvheadend.weekdaysRenderer(st); } -- 2.47.2