Merge pull request #364 from ProfYaffle/master

Addition of user options for file and directory permissions
This commit is contained in:
perexg 2014-05-21 09:12:08 +02:00
commit d490918540
12 changed files with 422 additions and 179 deletions

View file

@ -8,11 +8,14 @@
<p>
Configuration options:
<dl>
<dt>Recording system path
<dd>Path to where Tvheadend will write recorded events. If components of
the path does not exist, Tvheadend will try to create them.
<br><br>
<hr>
<b>DVR Behaviour</b>
<hr>
<dt>Media container
<dd>Select the container format used to store recordings.
@ -34,88 +37,18 @@
<dd>Combination of two above variants.
</dl>
<dt>Rewrite PAT in passthrough mode
<dd>Rewrite the original Program Association Table to only include
the active service. When this option is disabled, Tvheadend will
write the original PAT as broadcast, which lists all services from
the original multiplex.
<dt>Rewrite PMT in passthrough mode
<dd>Generate a Program Map Table only listing the streams actually in
the output transport stream. When this option is disabled,
Tvheadend will write the original Program Map Table as
broadcast, which may include references to excluded streams such
as data and ECMs.
<dt>DVR Log retention time (days)
<dd>Time that Tvheadend will keep information about the recording in
its internal database. Notice that the actual recorded file will not
be deleted when the log entry is deleted.
<dd>Time that Tvheadend will keep information about the recording in its internal database. Notice that the actual recorded file will not be deleted when the log entry is deleted.
<dt>Extra time before recordings (minutes)
<dd>Specify the number of minutes to record before the events scheduled
start time. Used to cope with small scheduling errors.
<dd>Specify the number of minutes to record before the events scheduled start time. Used to cope with small scheduling errors.
<dt>Extra time after recordings (minutes)
<dd>Specify the number of minutes to record after the events scheduled
stop time. Used to cope with small scheduling errors.
<dt>Make sub-directories per day
<dd>If checked, Tvheadend will create a new directory per day in the
recording system path. Only days when anything is recorded will be
created. The format of the directory will be 'YYYY-MM-DD' (ISO standard)
<dt>Make sub-directories per channel
<dd>If checked, Tvheadend will create a directory per channel when storing
events. If both this and the 'directory per day' checkbox is enabled,
the date-directory will be parent to the per-channel directory.
<dt>Make sub-directories per title
<dd>If checked, Tvheadend will create a directory per title when storing
events. If the day/channel directory checkboxes are also enabled, those
directories will be parents of this directory.
<dt>Include channel name in title
<dd>If checked, Tvheadend will include the name of the channel in the
event title. This applies to both the titled stored in the file
and to the file name itself.
<dt>Include date in title
<dd>If checked, Tvheadend will include the date for the recording in the
event title. This applies to both the titled stored in the file
and to the file name itself.
<dt>Include time in title
<dd>If checked, Tvheadend will include the time for the recording in the
event title. This applies to both the titled stored in the file
and to the file name itself.
<dt>Include episode in title
<dd>If checked, Tvheadend will include the season and episode in the
title (if such info is available).
<dt>Remove all unsafe characters from filename
<dd>If checked, all characters that could possibly cause problems for
filenaming will be removed.
<dt>Replace whitespace in title with '-'
<dd>If checked, all whitespace characters will be replaced with '-'.
<dt>Tag files with metadata
<dd>If checked, media containers that support metadata will be tagged with
the metadata associated with the event being recorded.
<dt>Skip commercials
<dd>If checked, commercials will be dropped from the recordings. At the
moment, commercial detection only works for the swedish channel TV4.
<dd>Specify the number of minutes to record after the events scheduled stop time. Used to cope with small scheduling errors.
<dt>Post-processor command
<dd>Command to run after finishing a recording. The command will be
run in background and is executed even if a recording is aborted
or an error occurred. Use the %e error formatting string to check
for errors, the error string is empty if recording finished
successfully.
<dd>Command to run after finishing a recording. The command will be run in background and is executed even if a recording is aborted or an error occurred. Use the %e error formatting string to check for errors, the error string is empty if recording finished successfully.
<br><br>
Support format strings:<br>
<table class="hts-doc-text" border="0">
@ -133,7 +66,100 @@
<br>
Example usage: /path/to/ffmpeg -i %f -vcodec libx264 -acodec copy "/path/with white space/%b"<br>
You need to use quotes or escape white spaces if you want white spaces in an argument.
<br><br>
<hr>
<b>Recording File Options</b>
<hr>
<dt>Recording system path
<dd>Path to where Tvheadend will write recorded events. If components of the path does not exist, Tvheadend will try to create them.
<dt>File permissions
<dd>The permissions to be set on the resultant recording files. This is useful if you need to manipulate the files after recording under a different user ID, e.g. to chop out commercials.
<table class="hts-doc-text" border="0">
<tr><td>Common examples:</td></tr>
<br>
<tr><td>0644 == rw-r--r--</td></tr>
<tr><td>0664 == rw-rw-r-- (default)</td></tr>
<tr><td>0666 == rw-rw-rw-</td></tr>
</table>
Note that the applicable umask applies, so 0666 with umask 0022 will produce 0644 (rw-r--r--).
See also <i>Directory permissions</i> in <i>Subdirectory Options</i>.
<dt>Rewrite PAT in passthrough mode
<dd>Rewrite the original Program Association Table to only include the active service. When this option is disabled, Tvheadend will write the original PAT as broadcast, which lists all services from the original multiplex.
<dt>Rewrite PMT in passthrough mode
<dd>Generate a Program Map Table only listing the streams actually in the output transport stream. When this option is disabled, Tvheadend will write the original Program Map Table as broadcast, which may include references to excluded streams such as data and ECMs.
<dt>Tag files with metadata
<dd>If checked, media containers that support metadata will be tagged with the metadata associated with the event being recorded.
<dt>Skip commercials
<dd>If checked, commercials will be dropped from the recordings. At the moment, commercial detection only works for the swedish channel TV4.
<br><br>
<hr>
<b>Subdirectory Options</b>
<hr>
<dt>Directory permissions
<dd>The permissions to be set on any sub-directories created for recordings. This is useful if you need to manipulate the files after recording under a different user ID, e.g. to chop out commercials.
<table class="hts-doc-text" border="0">
<tr><td>Common examples:</td></tr>
<br>
<tr><td>0755 == rwxr-xr-x</td></tr>
<tr><td>0775 == rwxrwxr-x (default)</td></tr>
<tr><td>0777 == rwxrwxrwx</td></tr>
</table>
Note that the applicable umask applies, so 0777 with umask 0022 will produce 0755 (rwxr-xr-x).
See also <i>File permissions</i> in <i>Recording File Options</i>.
<dt>Make sub-directories per day
<dd>If checked, create a new directory per day in the recording system path. Only days when anything is recorded will be created. The format of the directory will be 'YYYY-MM-DD' (ISO standard)
<dt>Make sub-directories per channel
<dd>If checked, create a directory per channel when storing events. If both this and the 'directory per day' checkbox is enabled, the date-directory will be parent to the per-channel directory.
<dt>Make sub-directories per title
<dd>If checked, create a directory per title when storing events. If the day/channel directory checkboxes are also enabled, those directories will be parents of this directory.
<br><br>
<hr>
<b>Filename Options</b>
<hr>
<dt>Include channel name in title
<dd>If checked, include the name of the channel in the event title. This applies to both the titled stored in the file and to the file name itself.
<dt>Include date in title
<dd>If checked, include the date for the recording in the event title. This applies to both the titled stored in the file and to the file name itself.
<dt>Include time in title
<dd>If checked, include the time for the recording in the event title. This applies to both the titled stored in the file and to the file name itself.
<dt>Include episode in title
<dd>If checked, include the season and episode in the title (if such info is available).
<dt>Include subtitle in title
<dd>If checked, include the episode subtitle in the title (if such info is available).
<dt>Put episode in filename before date and time
<dd>If checked, insert the episode number before the data and time rather than after (assumes <i>Include date</i>, <i>Include time</i> and <i>Include episode</i> options are set).
<dt>Remove all unsafe characters from filename
<dd>If checked, all characters that could possibly cause problems for filenaming will be removed.
<dt>Replace whitespace in title with '-'
<dd>If checked, all whitespace characters will be replaced with '-'.
</dl>
Changes to any of these settings must be confirmed by pressing the
'Save configuration' button before taking effect.
Changes to any of these settings must be confirmed by pressing the 'Save configuration' button before taking effect.
</div>

View file

@ -332,6 +332,10 @@ void dvr_storage_set(dvr_config_t *cfg, const char *storage);
void dvr_container_set(dvr_config_t *cfg, const char *container);
void dvr_file_permissions_set(dvr_config_t *cfg, int permissions);
void dvr_directory_permissions_set(dvr_config_t *cfg, int permissions);
void dvr_mux_cache_set(dvr_config_t *cfg, int mcache);
void dvr_postproc_set(dvr_config_t *cfg, const char *postproc);

View file

@ -1140,6 +1140,17 @@ dvr_init(void)
htsmsg_get_u32(m, "retention-days", &cfg->dvr_retention_days);
tvh_str_set(&cfg->dvr_storage, htsmsg_get_str(m, "storage"));
/*
* Convert 0xxx format permission strings to integer for internal use
* Note no checking that strtol won't overflow int - this should never happen with three-digit numbers
*/
if ((s = htsmsg_get_str(m, "file-permissions")))
cfg->dvr_muxcnf.m_file_permissions = (int)strtol(s,NULL,0);
if ((s = htsmsg_get_str(m, "directory-permissions")))
cfg->dvr_muxcnf.m_directory_permissions = (int)strtol(s,NULL,0);
if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
cfg->dvr_flags |= DVR_DIR_PER_DAY;
@ -1319,6 +1330,11 @@ dvr_config_create(const char *name)
/* dup detect */
cfg->dvr_dup_detect_episode = 1; // detect dup episodes
/* Default recording file and directory permissions */
cfg->dvr_muxcnf.m_file_permissions = 0664;
cfg->dvr_muxcnf.m_directory_permissions = 0775;
LIST_INSERT_HEAD(&dvrconfigs, cfg, config_link);
return LIST_FIRST(&dvrconfigs);
@ -1357,9 +1373,20 @@ static void
dvr_save(dvr_config_t *cfg)
{
htsmsg_t *m = htsmsg_create_map();
char buffer[5]; // Permissions buffer: leading zero, three octal digits plus terminating null
if (cfg->dvr_config_name != NULL && strlen(cfg->dvr_config_name) != 0)
htsmsg_add_str(m, "config_name", cfg->dvr_config_name);
htsmsg_add_str(m, "storage", cfg->dvr_storage);
/* Convert permissions to 0xxx octal format and output */
snprintf(buffer,sizeof(buffer),"%04o",cfg->dvr_muxcnf.m_file_permissions);
htsmsg_add_str(m, "file-permissions", buffer);
snprintf(buffer,sizeof(buffer),"%04o",cfg->dvr_muxcnf.m_directory_permissions);
htsmsg_add_str(m, "directory-permissions", buffer);
htsmsg_add_u32(m, "container", cfg->dvr_mc);
htsmsg_add_u32(m, "cache", cfg->dvr_muxcnf.m_cache);
htsmsg_add_u32(m, "rewrite-pat",
@ -1404,6 +1431,32 @@ dvr_storage_set(dvr_config_t *cfg, const char *storage)
dvr_save(cfg);
}
/**
*
*/
void
dvr_file_permissions_set(dvr_config_t *cfg, int permissions)
{
if(cfg->dvr_muxcnf.m_file_permissions == permissions)
return;
cfg->dvr_muxcnf.m_file_permissions = permissions;
dvr_save(cfg);
}
/**
*
*/
void
dvr_directory_permissions_set(dvr_config_t *cfg, int permissions)
{
if(cfg->dvr_muxcnf.m_directory_permissions == permissions)
return;
cfg->dvr_muxcnf.m_directory_permissions = permissions;
dvr_save(cfg);
}
/**
*
*/
@ -1468,7 +1521,7 @@ dvr_retention_set(dvr_config_t *cfg, int days)
cfg->dvr_retention_days = days;
/* Also, rearm all timres */
/* Also, rearm all timers */
LIST_FOREACH(de, &dvrentries, de_global_link)
if(de->de_sched_state == DVR_COMPLETED)

View file

@ -204,9 +204,7 @@ pvr_generate_filename(dvr_entry_t *de, const streaming_start_t *ss)
free(title);
}
/* */
if(makedirs(path, 0755) != 0) {
if(makedirs(path, cfg->dvr_muxcnf.m_directory_permissions) != 0) {
return -1;
}
@ -324,6 +322,7 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
"adapter: \"%s\", "
"network: \"%s\", mux: \"%s\", provider: \"%s\", "
"service: \"%s\"",
de->de_filename ?: lang_str_get(de->de_title, NULL),
si->si_adapter ?: "<N/A>",
si->si_network ?: "<N/A>",

View file

@ -45,8 +45,16 @@ typedef enum {
/* Muxer configuration used when creating a muxer. */
typedef struct muxer_config {
int m_flags;
int m_flags;
muxer_cache_type_t m_cache;
/*
* directory_permissions should really be in dvr.h as it's not really needed for the muxer
* but it's kept with file_permissions for neatness
*/
int m_file_permissions;
int m_directory_permissions;
} muxer_config_t;
struct muxer;

View file

@ -378,7 +378,10 @@ pass_muxer_open_file(muxer_t *m, const char *filename)
int fd;
pass_muxer_t *pm = (pass_muxer_t*)m;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
tvhtrace("pass", "Creating file \"%s\" with file permissions \"%o\"", filename, pm->m_config.m_file_permissions);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, pm->m_config.m_file_permissions);
if(fd < 0) {
pm->pm_error = errno;
tvhlog(LOG_ERR, "pass", "%s: Unable to create file, open failed -- %s",

View file

@ -138,7 +138,7 @@ tvh_muxer_open_file(muxer_t *m, const char *filename)
{
tvh_muxer_t *tm = (tvh_muxer_t*)m;
if(mk_mux_open_file(tm->tm_ref, filename)) {
if(mk_mux_open_file(tm->tm_ref, filename, tm->m_config.m_file_permissions)) {
tm->m_errors++;
return -1;
}

View file

@ -1046,11 +1046,14 @@ mk_mux_open_stream(mk_mux_t *mkm, int fd)
*
*/
int
mk_mux_open_file(mk_mux_t *mkm, const char *filename)
mk_mux_open_file(mk_mux_t *mkm, const char *filename, int permissions)
{
int fd;
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
tvhtrace("mkv", "Creating file \"%s\" with file permissions \"%o\"", filename, permissions);
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, permissions);
if(fd < 0) {
mkm->error = errno;
tvhlog(LOG_ERR, "mkv", "%s: Unable to create file, open failed -- %s",

View file

@ -30,7 +30,7 @@ struct event;
mk_mux_t *mk_mux_create(muxer_t *m, int webm);
int mk_mux_open_file (mk_mux_t *mkm, const char *filename);
int mk_mux_open_file (mk_mux_t *mkm, const char *filename, int permissions);
int mk_mux_open_stream(mk_mux_t *mkm, int fd);
int mk_mux_init(mk_mux_t *mkm, const char *title,

View file

@ -441,6 +441,7 @@ makedirs ( const char *inpath, int mode )
path[x] = 0;
if (stat(path, &st)) {
err = mkdir(path, mode);
tvhtrace("settings", "Creating directory \"%s\" with octal permissions \"%o\"", path, mode);
} else {
err = S_ISDIR(st.st_mode) ? 0 : 1;
errno = ENOTDIR;

View file

@ -971,6 +971,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
int flags = 0;
dvr_config_t *cfg;
epg_broadcast_t *e;
char buffer[5]; // Permissions buffer: leading zero, three octal digits plus terminating null
if(op == NULL)
op = "loadSettings";
@ -1127,6 +1128,14 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
r = htsmsg_create_map();
htsmsg_add_str(r, "storage", cfg->dvr_storage);
htsmsg_add_str(r, "container", muxer_container_type2txt(cfg->dvr_mc));
/* Convert integer permissions to an octal-format 0xxx string and store it in the config file */
snprintf(buffer,sizeof(buffer),"%04o",cfg->dvr_muxcnf.m_file_permissions);
htsmsg_add_str(r, "filePermissions", buffer);
snprintf(buffer,sizeof(buffer),"%04o",cfg->dvr_muxcnf.m_directory_permissions);
htsmsg_add_str(r, "dirPermissions", buffer);
htsmsg_add_u32(r, "cache", cfg->dvr_muxcnf.m_cache);
htsmsg_add_u32(r, "rewritePAT",
!!(cfg->dvr_muxcnf.m_flags & MC_REWRITE_PAT));
@ -1168,6 +1177,17 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if((s = http_arg_get(&hc->hc_req_args, "container")) != NULL)
dvr_container_set(cfg,s);
/*
* Convert 0xxx format permission strings to integer for internal use
* Note no checking that strtol won't overflow int - this should never happen with three-digit numbers
*/
if((s = http_arg_get(&hc->hc_req_args, "filePermissions")) != NULL)
dvr_file_permissions_set(cfg,(int)strtol(s,NULL,0));
if((s = http_arg_get(&hc->hc_req_args, "dirPermissions")) != NULL)
dvr_directory_permissions_set(cfg,(int)strtol(s,NULL,0));
if((s = http_arg_get(&hc->hc_req_args, "cache")) != NULL)
dvr_mux_cache_set(cfg,atoi(s));

View file

@ -744,10 +744,11 @@ tvheadend.dvrsettings = function() {
var confreader = new Ext.data.JsonReader({
root : 'dvrSettings'
}, [ 'storage', 'postproc', 'retention', 'dayDirs', 'channelDirs',
}, [ 'storage', 'filePermissions', 'dirPermissions', 'postproc', 'retention', 'dayDirs', 'channelDirs',
'channelInTitle', 'container', 'cache', 'dateInTitle', 'timeInTitle',
'preExtraTime', 'postExtraTime', 'whitespaceInTitle', 'titleDirs',
'episodeInTitle', 'cleanTitle', 'tagFiles', 'commSkip', 'subtitleInTitle', 'episodeBeforeDate', 'rewritePAT', 'rewritePMT' ]);
'episodeInTitle', 'cleanTitle', 'tagFiles', 'commSkip', 'subtitleInTitle',
'episodeBeforeDate', 'rewritePAT', 'rewritePMT' ]);
var confcombo = new Ext.form.ComboBox({
store : tvheadend.configNames,
@ -768,6 +769,215 @@ tvheadend.dvrsettings = function() {
disabled : true
});
/* Config panel variables */
/* DVR Behaviour */
var recordingContainer = new Ext.form.ComboBox({
store : tvheadend.containers,
fieldLabel : 'Media container',
triggerAction : 'all',
displayField : 'description',
valueField : 'name',
editable : false,
width : 200,
hiddenName : 'container'
});
var cacheScheme = new Ext.form.ComboBox({
store : tvheadend.caches,
fieldLabel : 'Cache scheme',
triggerAction : 'all',
displayField : 'description',
valueField : 'index',
editable : false,
width : 200,
hiddenName : 'cache'
});
var logRetention = new Ext.form.NumberField({
allowNegative : false,
allowDecimals : false,
minValue : 1,
fieldLabel : 'DVR Log retention time (days)',
name : 'retention'
});
var timeBefore = new Ext.form.NumberField({
allowDecimals : false,
fieldLabel : 'Extra time before recordings (minutes)',
name : 'preExtraTime'
});
var timeAfter = new Ext.form.NumberField({
allowDecimals : false,
fieldLabel : 'Extra time after recordings (minutes)',
name : 'postExtraTime'
});
var postProcessing = new Ext.form.TextField({
width : 300,
fieldLabel : 'Post-processor command',
name : 'postproc'
});
/* Recording File Options */
var recordingPath = new Ext.form.TextField({
width : 300,
fieldLabel : 'Recording system path',
name : 'storage'
});
/* NB: recordingPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */
var recordingPermissions = new Ext.form.TextField({
regex : /^[0][0-7]{3}$/,
maskRe : /[0-7]/,
width : 100,
allowBlank : false,
blankText : 'You must provide a value - use octal chmod notation, e.g. 0664',
fieldLabel : 'File permissions (octal, e.g. 0664)',
name : 'filePermissions'
});
/* TO DO - Add 'override user umask?' option, then trigger fchmod in mkmux.c, muxer_pass.c after file created */
var PATrewrite = new Ext.form.Checkbox({
fieldLabel : 'Rewrite PAT in passthrough mode',
name : 'rewritePAT'
});
var PMTrewrite = new Ext.form.Checkbox({
fieldLabel : 'Rewrite PMT in passthrough mode',
name : 'rewritePMT'
});
var tagMetadata = new Ext.form.Checkbox({
fieldLabel : 'Tag files with metadata',
name : 'tagFiles'
});
var skipCommercials = new Ext.form.Checkbox({
fieldLabel : 'Skip commercials',
name : 'commSkip'
});
/* Subdirectories and filename handling */
/* NB: directoryPermissions is defined as a TextField for validation purposes (leading zeros), but is ultimately a number */
var directoryPermissions = new Ext.form.TextField({
regex : /^[0][0-7]{3}$/,
maskRe : /[0-7]/,
width : 100,
allowBlank : false,
blankText : 'You must provide a value - use octal chmod notation, e.g. 0775',
fieldLabel : 'Directory permissions (octal, e.g. 0775)',
name : 'dirPermissions'
});
/* TO DO - Add 'override user umask?' option, then trigger fchmod in utils.c after directory created */
var dirsPerDay = new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per day',
name : 'dayDirs'
});
var dirsPerChannel = new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per channel',
name : 'channelDirs'
});
var dirsPerTitle = new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per title',
name : 'titleDirs'
});
var incChannelInTitle = new Ext.form.Checkbox({
fieldLabel : 'Include channel name in filename',
name : 'channelInTitle'
});
var incDateInTitle = new Ext.form.Checkbox({
fieldLabel : 'Include date in filename',
name : 'dateInTitle'
});
var incTimeInTitle = new Ext.form.Checkbox({
fieldLabel : 'Include time in filename',
name : 'timeInTitle'
});
var incEpisodeInTitle = new Ext.form.Checkbox({
fieldLabel : 'Include episode in filename',
name : 'episodeInTitle'
});
var incSubtitleInTitle = new Ext.form.Checkbox({
fieldLabel : 'Include subtitle in filename',
name : 'subtitleInTitle'
});
var episodeFirst = new Ext.form.Checkbox({
fieldLabel : 'Put episode in filename before date and time',
name : 'episodeBeforeDate'
});
var stripUnsafeChars = new Ext.form.Checkbox({
fieldLabel : 'Remove all unsafe characters from filename',
name : 'cleanTitle'
});
var stripWhitespace = new Ext.form.Checkbox({
fieldLabel : 'Replace whitespace in title with \'-\'',
name : 'whitespaceInTitle'
});
/* Sub-Panel - DVR behaviour */
var DVRBehaviour = new Ext.form.FieldSet({
title: 'DVR Behaviour',
width: 700,
autoHeight: true,
collapsible: true,
items : [ recordingContainer, cacheScheme, logRetention, timeBefore, timeAfter, postProcessing ]
});
/* Sub-Panel - File Output */
var FileOutputPanel = new Ext.form.FieldSet({
title: 'Recording File Options',
width: 700,
autoHeight: true,
collapsible: true,
items : [ recordingPath, recordingPermissions, PATrewrite, PMTrewrite, tagMetadata, skipCommercials ]
});
/* Sub-Panel - Directory operations */
var DirHandlingPanel = new Ext.form.FieldSet({
title: 'Subdirectory Options',
width: 700,
autoHeight: true,
collapsible: true,
items : [ directoryPermissions, dirsPerDay, dirsPerChannel, dirsPerTitle ]
});
/* Sub-Panel - File operations */
var FileHandlingPanel = new Ext.form.FieldSet({
title: 'Filename Options',
width: 700,
autoHeight: true,
collapsible: true,
items : [ incChannelInTitle, incDateInTitle, incTimeInTitle, incEpisodeInTitle,
incSubtitleInTitle, episodeFirst, stripUnsafeChars, stripWhitespace ]
});
/* Main (form) panel */
var confpanel = new Ext.FormPanel({
title : 'Digital Video Recorder',
iconCls : 'drive',
@ -780,92 +990,8 @@ tvheadend.dvrsettings = function() {
reader : confreader,
defaultType : 'textfield',
layout : 'form',
items : [ {
width : 300,
fieldLabel : 'Recording system path',
name : 'storage'
}, new Ext.form.ComboBox({
store : tvheadend.containers,
fieldLabel : 'Media container',
triggerAction : 'all',
displayField : 'description',
valueField : 'name',
editable : false,
width : 200,
hiddenName : 'container'
}), new Ext.form.ComboBox({
store : tvheadend.caches,
fieldLabel : 'Cache scheme',
triggerAction : 'all',
displayField : 'description',
valueField : 'index',
editable : false,
width : 200,
hiddenName : 'cache'
}), new Ext.form.Checkbox({
fieldLabel : 'Rewrite PAT in passthrough mode',
name : 'rewritePAT'
}), new Ext.form.Checkbox({
fieldLabel : 'Rewrite PMT in passthrough mode',
name : 'rewritePMT'
}), new Ext.form.NumberField({
allowNegative : false,
allowDecimals : false,
minValue : 1,
fieldLabel : 'DVR Log retention time (days)',
name : 'retention'
}), new Ext.form.NumberField({
allowDecimals : false,
fieldLabel : 'Extra time before recordings (minutes)',
name : 'preExtraTime'
}), new Ext.form.NumberField({
allowDecimals : false,
fieldLabel : 'Extra time after recordings (minutes)',
name : 'postExtraTime'
}), new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per day',
name : 'dayDirs'
}), new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per channel',
name : 'channelDirs'
}), new Ext.form.Checkbox({
fieldLabel : 'Make subdirectories per title',
name : 'titleDirs'
}), new Ext.form.Checkbox({
fieldLabel : 'Include channel name in filename',
name : 'channelInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Include date in filename',
name : 'dateInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Include time in filename',
name : 'timeInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Include episode in filename',
name : 'episodeInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Remove all unsafe characters from filename',
name : 'cleanTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Replace whitespace in title with \'-\'',
name : 'whitespaceInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Tag files with metadata',
name : 'tagFiles'
}), new Ext.form.Checkbox({
fieldLabel : 'Skip commercials',
name : 'commSkip'
}), new Ext.form.Checkbox({
fieldLabel : 'Include subtitle in filename',
name : 'subtitleInTitle'
}), new Ext.form.Checkbox({
fieldLabel : 'Put episode in filename before date and time',
name : 'episodeBeforeDate'
}), {
width : 300,
fieldLabel : 'Post-processor command',
name : 'postproc'
} ],
items : [ DVRBehaviour, FileOutputPanel, DirHandlingPanel, FileHandlingPanel ],
tbar : [ confcombo, {
tooltip : 'Save changes made to dvr configuration below',
iconCls : 'save',