[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
This commit is contained in:
parent
09bd4c4d0e
commit
c51b16224f
9 changed files with 114 additions and 50 deletions
|
@ -51,6 +51,10 @@ Check or clear this box to enable or disable this rule.
|
|||
<dd>
|
||||
The name you've given to the rule, e.g. 'Stuff involving Jeremy Clarkson'.
|
||||
<p>
|
||||
<dt><b>Directory</b>
|
||||
<dd>
|
||||
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".
|
||||
<p>
|
||||
<dt><b>Title (Regexp)</b>
|
||||
<dd>
|
||||
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.
|
||||
|
|
|
@ -50,6 +50,10 @@ Check or clear this box to enable or disable this rule.
|
|||
<dd>
|
||||
The name you've given to the rule, e.g. 'Evening cartoons for the children'.
|
||||
<p>
|
||||
<dt><b>Directory</b>
|
||||
<dd>
|
||||
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".
|
||||
<p>
|
||||
<dt><b>Title</b>
|
||||
<dd>
|
||||
Not sure how this differs from **Name* *
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
} 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);
|
||||
}
|
||||
snprintf(path + strlen(path), sizeof(path) - strlen(path), "/%s", s);
|
||||
free(s);
|
||||
}
|
||||
|
||||
// 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-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
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (makedirs(path, cfg->dvr_muxcnf.m_directory_permissions) != 0)
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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); }
|
||||
|
|
Loading…
Add table
Reference in a new issue