Add support for multiple DVR configurations.

Patch by sbi

Ticket #303
This commit is contained in:
Andreas Öman 2010-10-21 12:36:29 +00:00
parent 92219d11be
commit 801ba2a1c6
12 changed files with 598 additions and 198 deletions

View file

@ -39,7 +39,7 @@
#include "diseqc.h"
#include "notify.h"
#include "transports.h"
#include "dvr/dvr.h"
/**
* Front end monitor
@ -197,7 +197,6 @@ dvb_adapter_open_dump_file(th_dvb_adapter_t *tda)
struct dmx_pes_filter_params dmx_param;
char fullname[1000];
char path[500];
extern char *dvr_storage;
const char *fname = tda->tda_mux_current->tdmi_identifier;
int fd = tvh_open(tda->tda_demux_path, O_RDWR, 0);
@ -220,7 +219,8 @@ dvb_adapter_open_dump_file(th_dvb_adapter_t *tda)
return;
}
snprintf(path, sizeof(path), "%s/muxdumps", dvr_storage);
snprintf(path, sizeof(path), "%s/muxdumps",
dvr_config_find_by_name_default("")->dvr_storage);
if(mkdir(path, 0777) && errno != EEXIST) {
tvhlog(LOG_ERR, "dvb", "\"%s\" unable to create mux dump dir %s -- %s",

View file

@ -24,14 +24,22 @@
#include "channels.h"
#include "subscriptions.h"
extern char *dvr_storage;
extern char *dvr_format;
extern char *dvr_file_postfix;
extern uint32_t dvr_retention_days;
extern int dvr_flags;
extern char *dvr_postproc;
extern int dvr_extra_time_pre;
extern int dvr_extra_time_post;
typedef struct dvr_config {
char *dvr_config_name;
char *dvr_storage;
char *dvr_format;
char *dvr_file_postfix;
uint32_t dvr_retention_days;
int dvr_flags;
char *dvr_postproc;
int dvr_extra_time_pre;
int dvr_extra_time_post;
LIST_ENTRY(dvr_config) config_link;
} dvr_config_t;
extern struct dvr_config_list dvrconfigs;
extern struct dvr_entry_list dvrentries;
#define DVR_DIR_PER_DAY 0x1
@ -98,6 +106,8 @@ typedef struct dvr_entry {
* These meta fields will stay valid as long as reference count > 0
*/
char *de_config_name;
time_t de_start;
time_t de_stop;
@ -172,6 +182,8 @@ typedef struct dvr_autorec_entry {
TAILQ_ENTRY(dvr_autorec_entry) dae_link;
char *dae_id;
char *dae_config_name;
int dae_enabled;
char *dae_creator;
char *dae_comment;
@ -202,6 +214,14 @@ typedef struct dvr_autorec_entry {
* Prototypes
*/
dvr_config_t *dvr_config_find_by_name(const char *name);
dvr_config_t *dvr_config_find_by_name_default(const char *name);
dvr_config_t *dvr_config_create(const char *name);
void dvr_config_delete(const char *name);
void dvr_entry_notify(dvr_entry_t *de);
const char *dvr_entry_status(dvr_entry_t *de);
@ -210,11 +230,13 @@ const char *dvr_entry_schedstatus(dvr_entry_t *de);
void dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae);
dvr_entry_t *dvr_entry_create_by_event(event_t *e, const char *creator,
dvr_entry_t *dvr_entry_create_by_event(const char *dvr_config_name,
event_t *e, const char *creator,
dvr_autorec_entry_t *dae,
dvr_prio_t pri);
dvr_entry_t *dvr_entry_create(channel_t *ch, time_t start, time_t stop,
dvr_entry_t *dvr_entry_create(const char *dvr_config_name,
channel_t *ch, time_t start, time_t stop,
const char *title, const char *description,
const char *creator, dvr_autorec_entry_t *dae,
epg_episode_t *ee, uint8_t content_type,
@ -240,17 +262,17 @@ dvr_entry_t *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_storage_set(dvr_config_t *cfg, const char *storage);
void dvr_postproc_set(const char *postproc);
void dvr_postproc_set(dvr_config_t *cfg, const char *postproc);
void dvr_retention_set(int days);
void dvr_retention_set(dvr_config_t *cfg, int days);
void dvr_flags_set(int flags);
void dvr_flags_set(dvr_config_t *cfg, int flags);
void dvr_extra_time_pre_set(int d);
void dvr_extra_time_pre_set(dvr_config_t *cfg, int d);
void dvr_extra_time_post_set(int d);
void dvr_extra_time_post_set(dvr_config_t *cfg, int d);
/**
* Query interface
@ -268,7 +290,8 @@ void dvr_query_sort(dvr_query_result_t *dqr);
/**
*
*/
void dvr_autorec_add(const char *title, const char *channel,
void dvr_autorec_add(const char *dvr_config_name,
const char *title, const char *channel,
const char *tag, uint8_t content_type,
const char *creator, const char *comment);

View file

@ -166,6 +166,7 @@ autorec_entry_destroy(dvr_autorec_entry_t *dae)
free(dae->dae_id);
free(dae->dae_config_name);
free(dae->dae_creator);
free(dae->dae_comment);
@ -227,6 +228,8 @@ autorec_record_build(dvr_autorec_entry_t *dae)
htsmsg_add_str(e, "id", dae->dae_id);
htsmsg_add_u32(e, "enabled", !!dae->dae_enabled);
if (dae->dae_config_name != NULL)
htsmsg_add_str(e, "config_name", dae->dae_config_name);
if(dae->dae_creator != NULL)
htsmsg_add_str(e, "creator", dae->dae_creator);
if(dae->dae_comment != NULL)
@ -307,6 +310,7 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
if((dae = autorec_entry_find(id, maycreate)) == NULL)
return NULL;
tvh_str_update(&dae->dae_config_name, htsmsg_get_str(values, "config_name"));
tvh_str_update(&dae->dae_creator, htsmsg_get_str(values, "creator"));
tvh_str_update(&dae->dae_comment, htsmsg_get_str(values, "comment"));
@ -417,7 +421,8 @@ dvr_autorec_init(void)
*
*/
void
dvr_autorec_add(const char *title, const char *channel,
dvr_autorec_add(const char *config_name,
const char *title, const char *channel,
const char *tag, uint8_t content_type,
const char *creator, const char *comment)
{
@ -429,6 +434,7 @@ dvr_autorec_add(const char *title, const char *channel,
if((dae = autorec_entry_find(NULL, 1)) == NULL)
return;
tvh_str_set(&dae->dae_config_name, config_name);
tvh_str_set(&dae->dae_creator, creator);
tvh_str_set(&dae->dae_comment, comment);

View file

@ -30,18 +30,11 @@
#include "htsp.h"
#include "streaming.h"
char *dvr_storage;
char *dvr_format;
char *dvr_file_postfix;
uint32_t dvr_retention_days;
int dvr_flags;
int dvr_extra_time_pre;
int dvr_extra_time_post;
char *dvr_postproc;
int dvr_iov_max;
static int de_tally;
int dvr_iov_max;
struct dvr_config_list dvrconfigs;
struct dvr_entry_list dvrentries;
static void dvr_entry_save(dvr_entry_t *de);
@ -129,6 +122,17 @@ dvrdb_changed(void)
notify_by_msg("dvrdb", m);
}
/**
*
*/
static void
dvrconfig_changed(void)
{
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_u32(m, "reload", 1);
notify_by_msg("dvrconfig", m);
}
/**
*
@ -155,8 +159,9 @@ dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
struct tm tm;
char buf[40];
int i;
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
if(dvr_flags & DVR_CHANNEL_IN_TITLE)
if(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE)
snprintf(output, outlen, "%s-", de->de_channel->ch_name);
else
output[0] = 0;
@ -166,17 +171,17 @@ dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
localtime_r(&de->de_start, &tm);
if(dvr_flags & DVR_DATE_IN_TITLE) {
if(cfg->dvr_flags & DVR_DATE_IN_TITLE) {
strftime(buf, sizeof(buf), "%F", &tm);
snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
}
if(dvr_flags & DVR_TIME_IN_TITLE) {
if(cfg->dvr_flags & DVR_TIME_IN_TITLE) {
strftime(buf, sizeof(buf), "%H-%M", &tm);
snprintf(output + strlen(output), outlen - strlen(output), ".%s", buf);
}
if(dvr_flags & DVR_EPISODE_IN_TITLE) {
if(cfg->dvr_flags & DVR_EPISODE_IN_TITLE) {
if(de->de_episode.ee_season && de->de_episode.ee_episode)
snprintf(output + strlen(output), outlen - strlen(output),
@ -189,7 +194,7 @@ dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
de->de_episode.ee_episode);
}
if(dvr_flags & DVR_CLEAN_TITLE) {
if(cfg->dvr_flags & DVR_CLEAN_TITLE) {
for (i=0;i<strlen(output);i++) {
if (
output[i]<32 ||
@ -212,6 +217,7 @@ dvr_entry_link(dvr_entry_t *de)
{
time_t now, preamble;
char buf[100];
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
dvr_make_title(buf, sizeof(buf), de);
@ -231,7 +237,7 @@ dvr_entry_link(dvr_entry_t *de)
else
de->de_sched_state = DVR_COMPLETED;
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
de->de_stop + dvr_retention_days * 86400);
de->de_stop + cfg->dvr_retention_days * 86400);
} else {
de->de_sched_state = DVR_SCHEDULED;
@ -246,7 +252,8 @@ dvr_entry_link(dvr_entry_t *de)
*
*/
dvr_entry_t *
dvr_entry_create(channel_t *ch, time_t start, time_t stop,
dvr_entry_create(const char *config_name,
channel_t *ch, time_t start, time_t stop,
const char *title, const char *description,
const char *creator, dvr_autorec_entry_t *dae,
epg_episode_t *ee, uint8_t content_type, dvr_prio_t pri)
@ -255,6 +262,7 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop,
char tbuf[30];
struct tm tm;
time_t t;
dvr_config_t *cfg = dvr_config_find_by_name_default(config_name);
LIST_FOREACH(de, &ch->ch_dvrs, de_channel_link)
if(de->de_start == start && de->de_sched_state != DVR_COMPLETED)
@ -272,11 +280,12 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop,
if (ch->ch_dvr_extra_time_pre)
de->de_start_extra = ch->ch_dvr_extra_time_pre;
else
de->de_start_extra = dvr_extra_time_pre;
de->de_start_extra = cfg->dvr_extra_time_pre;
if (ch->ch_dvr_extra_time_post)
de->de_stop_extra = ch->ch_dvr_extra_time_post;
else
de->de_stop_extra = dvr_extra_time_post;
de->de_stop_extra = cfg->dvr_extra_time_post;
de->de_config_name = strdup(cfg->dvr_config_name);
de->de_creator = strdup(creator);
de->de_title = strdup(title);
de->de_desc = description ? strdup(description) : NULL;
@ -315,13 +324,15 @@ dvr_entry_create(channel_t *ch, time_t start, time_t stop,
*
*/
dvr_entry_t *
dvr_entry_create_by_event(event_t *e, const char *creator,
dvr_entry_create_by_event(const char *config_name,
event_t *e, const char *creator,
dvr_autorec_entry_t *dae, dvr_prio_t pri)
{
if(e->e_channel == NULL || e->e_title == NULL)
return NULL;
return dvr_entry_create(e->e_channel, e->e_start, e->e_stop,
return dvr_entry_create(config_name,
e->e_channel, e->e_start, e->e_stop,
e->e_title, e->e_desc, creator, dae, &e->e_episode,
e->e_content_type, pri);
}
@ -340,7 +351,7 @@ dvr_entry_create_by_autorec(event_t *e, dvr_autorec_entry_t *dae)
} else {
snprintf(buf, sizeof(buf), "Auto recording");
}
dvr_entry_create_by_event(e, buf, dae, dae->dae_pri);
dvr_entry_create_by_event(dae->dae_config_name, e, buf, dae, dae->dae_pri);
}
@ -360,6 +371,7 @@ dvr_entry_dec_ref(dvr_entry_t *de)
if(de->de_autorec != NULL)
LIST_REMOVE(de, de_autorec_link);
free(de->de_config_name);
free(de->de_creator);
free(de->de_title);
free(de->de_ititle);
@ -406,6 +418,7 @@ dvr_db_load_one(htsmsg_t *c, int id)
channel_t *ch;
uint32_t start, stop;
int d;
dvr_config_t *cfg;
if(htsmsg_get_u32(c, "start", &start))
return;
@ -417,6 +430,9 @@ dvr_db_load_one(htsmsg_t *c, int id)
if((ch = channel_find_by_name(s, 0, 0)) == NULL)
return;
s = htsmsg_get_str(c, "config_name");
cfg = dvr_config_find_by_name_default(s);
if((title = htsmsg_get_str(c, "title")) == NULL)
return;
@ -433,17 +449,18 @@ dvr_db_load_one(htsmsg_t *c, int id)
de->de_start = start;
de->de_stop = stop;
de->de_config_name = strdup(cfg->dvr_config_name);
de->de_creator = strdup(creator);
de->de_title = strdup(title);
de->de_pri = dvr_pri2val(htsmsg_get_str(c, "pri"));
if(htsmsg_get_s32(c, "start_extra", &d))
de->de_start_extra = dvr_extra_time_pre;
de->de_start_extra = cfg->dvr_extra_time_pre;
else
de->de_start_extra = d;
if(htsmsg_get_s32(c, "stop_extra", &d))
de->de_stop_extra = dvr_extra_time_post;
de->de_stop_extra = cfg->dvr_extra_time_post;
else
de->de_stop_extra = d;
@ -519,6 +536,8 @@ dvr_entry_save(dvr_entry_t *de)
htsmsg_add_s32(m, "start_extra", de->de_start_extra);
htsmsg_add_s32(m, "stop_extra", de->de_stop_extra);
htsmsg_add_str(m, "config_name", de->de_config_name);
htsmsg_add_str(m, "creator", de->de_creator);
if(de->de_filename != NULL)
@ -577,6 +596,8 @@ dvr_timer_expire(void *aux)
static void
dvr_stop_recording(dvr_entry_t *de, int stopcode)
{
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
dvr_rec_unsubscribe(de, stopcode);
de->de_sched_state = DVR_COMPLETED;
@ -591,7 +612,7 @@ dvr_stop_recording(dvr_entry_t *de, int stopcode)
dvr_entry_notify(de);
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
de->de_stop + dvr_retention_days * 86400);
de->de_stop + cfg->dvr_retention_days * 86400);
}
@ -719,84 +740,98 @@ dvr_destroy_by_channel(channel_t *ch)
void
dvr_init(void)
{
htsmsg_t *m;
htsmsg_t *m, *l;
htsmsg_field_t *f;
const char *s;
char buf[500];
const char *homedir;
struct stat st;
uint32_t u32;
dvr_config_t *cfg;
dvr_iov_max = sysconf(_SC_IOV_MAX);
/* Default settings */
dvr_retention_days = 31;
dvr_format = strdup("matroska");
dvr_file_postfix = strdup("mkv");
LIST_INIT(&dvrconfigs);
cfg = dvr_config_create("");
/* Override settings with config */
dvr_flags = DVR_TAG_FILES;
l = hts_settings_load("dvr");
if(l != NULL) {
HTSMSG_FOREACH(f, l) {
m = htsmsg_get_map_by_field(f);
if(m == NULL)
continue;
if((m = hts_settings_load("dvr/config")) != NULL) {
s = htsmsg_get_str(m, "config_name");
cfg = dvr_config_find_by_name(s);
if(cfg == NULL)
cfg = dvr_config_create(s);
htsmsg_get_s32(m, "pre-extra-time", &dvr_extra_time_pre);
htsmsg_get_s32(m, "post-extra-time", &dvr_extra_time_post);
htsmsg_get_u32(m, "retention-days", &dvr_retention_days);
tvh_str_set(&dvr_storage, htsmsg_get_str(m, "storage"));
htsmsg_get_s32(m, "pre-extra-time", &cfg->dvr_extra_time_pre);
htsmsg_get_s32(m, "post-extra-time", &cfg->dvr_extra_time_post);
htsmsg_get_u32(m, "retention-days", &cfg->dvr_retention_days);
tvh_str_set(&cfg->dvr_storage, htsmsg_get_str(m, "storage"));
if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
dvr_flags |= DVR_DIR_PER_DAY;
if(!htsmsg_get_u32(m, "day-dir", &u32) && u32)
cfg->dvr_flags |= DVR_DIR_PER_DAY;
if(!htsmsg_get_u32(m, "channel-dir", &u32) && u32)
dvr_flags |= DVR_DIR_PER_CHANNEL;
if(!htsmsg_get_u32(m, "channel-dir", &u32) && u32)
cfg->dvr_flags |= DVR_DIR_PER_CHANNEL;
if(!htsmsg_get_u32(m, "channel-in-title", &u32) && u32)
dvr_flags |= DVR_CHANNEL_IN_TITLE;
if(!htsmsg_get_u32(m, "channel-in-title", &u32) && u32)
cfg->dvr_flags |= DVR_CHANNEL_IN_TITLE;
if(!htsmsg_get_u32(m, "date-in-title", &u32) && u32)
dvr_flags |= DVR_DATE_IN_TITLE;
if(!htsmsg_get_u32(m, "date-in-title", &u32) && u32)
cfg->dvr_flags |= DVR_DATE_IN_TITLE;
if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
dvr_flags |= DVR_TIME_IN_TITLE;
if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
dvr_flags |= DVR_WHITESPACE_IN_TITLE;
if(!htsmsg_get_u32(m, "title-dir", &u32) && u32)
dvr_flags |= DVR_DIR_PER_TITLE;
if(!htsmsg_get_u32(m, "episode-in-title", &u32) && u32)
dvr_flags |= DVR_EPISODE_IN_TITLE;
if(!htsmsg_get_u32(m, "tag-files", &u32) && !u32)
dvr_flags &= ~DVR_TAG_FILES;
if(!htsmsg_get_u32(m, "time-in-title", &u32) && u32)
cfg->dvr_flags |= DVR_TIME_IN_TITLE;
tvh_str_set(&dvr_postproc, htsmsg_get_str(m, "postproc"));
if(!htsmsg_get_u32(m, "whitespace-in-title", &u32) && u32)
cfg->dvr_flags |= DVR_WHITESPACE_IN_TITLE;
htsmsg_destroy(m);
}
if(!htsmsg_get_u32(m, "title-dir", &u32) && u32)
cfg->dvr_flags |= DVR_DIR_PER_TITLE;
if(dvr_storage == NULL) {
/* Try to figure out a good place to put them videos */
if(!htsmsg_get_u32(m, "episode-in-title", &u32) && u32)
cfg->dvr_flags |= DVR_EPISODE_IN_TITLE;
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)));
if(!htsmsg_get_u32(m, "tag-files", &u32) && !u32)
cfg->dvr_flags &= ~DVR_TAG_FILES;
tvh_str_set(&cfg->dvr_postproc, htsmsg_get_str(m, "postproc"));
}
tvhlog(LOG_WARNING, "dvr",
"Output directory for video recording is not yet configured. "
"Defaulting to to \"%s\". "
"This can be changed from the web user interface.",
dvr_storage);
htsmsg_destroy(l);
}
LIST_FOREACH(cfg, &dvrconfigs, config_link) {
if(cfg->dvr_storage == NULL || !strlen(cfg->dvr_storage)) {
/* 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))
cfg->dvr_storage = strdup(buf);
else if(stat(homedir, &st) == 0 && S_ISDIR(st.st_mode))
cfg->dvr_storage = strdup(homedir);
else
cfg->dvr_storage = strdup(getcwd(buf, sizeof(buf)));
}
tvhlog(LOG_WARNING, "dvr",
"Output directory for video recording is not yet configured "
"for DVR configuration \"%s\". "
"Defaulting to to \"%s\". "
"This can be changed from the web user interface.",
cfg->dvr_config_name, cfg->dvr_storage);
}
}
dvr_autorec_init();
@ -804,57 +839,150 @@ dvr_init(void)
dvr_db_load();
}
/**
* find a dvr config by name, return NULL if not found
*/
dvr_config_t *
dvr_config_find_by_name(const char *name)
{
dvr_config_t *cfg;
if (name == NULL)
name = "";
LIST_FOREACH(cfg, &dvrconfigs, config_link)
if (!strcmp(name, cfg->dvr_config_name))
return cfg;
return NULL;
}
/**
* find a dvr config by name, return the default config if not found
*/
dvr_config_t *
dvr_config_find_by_name_default(const char *name)
{
dvr_config_t *cfg;
cfg = dvr_config_find_by_name(name);
if (cfg == NULL) {
tvhlog(LOG_WARNING, "dvr", "Configuration '%s' not found", name);
cfg = dvr_config_find_by_name("");
}
if (cfg == NULL) {
cfg = dvr_config_create("");
}
return cfg;
}
/**
* create a new named dvr config; the caller is responsible
* to avoid duplicates
*/
dvr_config_t *
dvr_config_create(const char *name)
{
dvr_config_t *cfg;
if (name == NULL)
name = "";
tvhlog(LOG_INFO, "dvr", "Creating new configuration '%s'", name);
cfg = calloc(1, sizeof(dvr_config_t));
cfg->dvr_config_name = strdup(name);
cfg->dvr_retention_days = 31;
cfg->dvr_format = strdup("matroska");
cfg->dvr_file_postfix = strdup("mkv");
cfg->dvr_flags = DVR_TAG_FILES;
LIST_INSERT_HEAD(&dvrconfigs, cfg, config_link);
return LIST_FIRST(&dvrconfigs);
}
/**
*
*/
void
dvr_config_delete(const char *name)
{
dvr_config_t *cfg;
if (name == NULL || strlen(name) == 0) {
tvhlog(LOG_WARNING,"dvr","Attempt to delete default config ignored");
return;
}
cfg = dvr_config_find_by_name(name);
if (cfg != NULL) {
tvhlog(LOG_INFO, "dvr", "Deleting configuration '%s'",
cfg->dvr_config_name);
hts_settings_remove("dvr/config%s", cfg->dvr_config_name);
LIST_REMOVE(cfg, config_link);
dvrconfig_changed();
}
}
/**
*
*/
static void
dvr_save(void)
dvr_save(dvr_config_t *cfg)
{
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "storage", dvr_storage);
htsmsg_add_u32(m, "retention-days", dvr_retention_days);
htsmsg_add_u32(m, "pre-extra-time", dvr_extra_time_pre);
htsmsg_add_u32(m, "post-extra-time", dvr_extra_time_post);
htsmsg_add_u32(m, "day-dir", !!(dvr_flags & DVR_DIR_PER_DAY));
htsmsg_add_u32(m, "channel-dir", !!(dvr_flags & DVR_DIR_PER_CHANNEL));
htsmsg_add_u32(m, "channel-in-title", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
htsmsg_add_u32(m, "date-in-title", !!(dvr_flags & DVR_DATE_IN_TITLE));
htsmsg_add_u32(m, "time-in-title", !!(dvr_flags & DVR_TIME_IN_TITLE));
htsmsg_add_u32(m, "whitespace-in-title", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
htsmsg_add_u32(m, "title-dir", !!(dvr_flags & DVR_DIR_PER_TITLE));
htsmsg_add_u32(m, "episode-in-title", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
htsmsg_add_u32(m, "tag-files", !!(dvr_flags & DVR_TAG_FILES));
if(dvr_postproc != NULL)
htsmsg_add_str(m, "postproc", dvr_postproc);
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);
htsmsg_add_u32(m, "retention-days", cfg->dvr_retention_days);
htsmsg_add_u32(m, "pre-extra-time", cfg->dvr_extra_time_pre);
htsmsg_add_u32(m, "post-extra-time", cfg->dvr_extra_time_post);
htsmsg_add_u32(m, "day-dir", !!(cfg->dvr_flags & DVR_DIR_PER_DAY));
htsmsg_add_u32(m, "channel-dir", !!(cfg->dvr_flags & DVR_DIR_PER_CHANNEL));
htsmsg_add_u32(m, "channel-in-title", !!(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE));
htsmsg_add_u32(m, "date-in-title", !!(cfg->dvr_flags & DVR_DATE_IN_TITLE));
htsmsg_add_u32(m, "time-in-title", !!(cfg->dvr_flags & DVR_TIME_IN_TITLE));
htsmsg_add_u32(m, "whitespace-in-title", !!(cfg->dvr_flags & DVR_WHITESPACE_IN_TITLE));
htsmsg_add_u32(m, "title-dir", !!(cfg->dvr_flags & DVR_DIR_PER_TITLE));
htsmsg_add_u32(m, "episode-in-title", !!(cfg->dvr_flags & DVR_EPISODE_IN_TITLE));
htsmsg_add_u32(m, "tag-files", !!(cfg->dvr_flags & DVR_TAG_FILES));
if(cfg->dvr_postproc != NULL)
htsmsg_add_str(m, "postproc", cfg->dvr_postproc);
hts_settings_save(m, "dvr/config");
hts_settings_save(m, "dvr/config%s", cfg->dvr_config_name);
htsmsg_destroy(m);
dvrconfig_changed();
}
/**
*
*/
void
dvr_storage_set(const char *storage)
dvr_storage_set(dvr_config_t *cfg, const char *storage)
{
if(!strcmp(dvr_storage, storage))
if(cfg->dvr_storage != NULL && !strcmp(cfg->dvr_storage, storage))
return;
tvh_str_set(&dvr_storage, storage);
dvr_save();
tvh_str_set(&cfg->dvr_storage, storage);
dvr_save(cfg);
}
/**
*
*/
void
dvr_postproc_set(const char *postproc)
dvr_postproc_set(dvr_config_t *cfg, const char *postproc)
{
if(dvr_postproc != NULL && !strcmp(dvr_postproc, postproc))
if(cfg->dvr_postproc != NULL && !strcmp(cfg->dvr_postproc, postproc))
return;
tvh_str_set(&dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
dvr_save();
tvh_str_set(&cfg->dvr_postproc, !strcmp(postproc, "") ? NULL : postproc);
dvr_save(cfg);
}
@ -862,21 +990,21 @@ dvr_postproc_set(const char *postproc)
*
*/
void
dvr_retention_set(int days)
dvr_retention_set(dvr_config_t *cfg, int days)
{
dvr_entry_t *de;
if(days < 1 || dvr_retention_days == days)
if(days < 1 || cfg->dvr_retention_days == days)
return;
dvr_retention_days = days;
cfg->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();
de->de_stop + cfg->dvr_retention_days * 86400);
dvr_save(cfg);
}
@ -884,13 +1012,13 @@ dvr_retention_set(int days)
*
*/
void
dvr_flags_set(int flags)
dvr_flags_set(dvr_config_t *cfg, int flags)
{
if(dvr_flags == flags)
if(cfg->dvr_flags == flags)
return;
dvr_flags = flags;
dvr_save();
cfg->dvr_flags = flags;
dvr_save(cfg);
}
@ -898,12 +1026,13 @@ dvr_flags_set(int flags)
*
*/
void
dvr_extra_time_pre_set(int d)
dvr_extra_time_pre_set(dvr_config_t *cfg, int d)
{
if(dvr_extra_time_pre == d)
if(cfg->dvr_extra_time_pre == d)
return;
dvr_extra_time_pre = d;
dvr_save();
cfg->dvr_extra_time_pre = d;
dvr_save(cfg);
}
@ -911,12 +1040,13 @@ dvr_extra_time_pre_set(int d)
*
*/
void
dvr_extra_time_post_set(int d)
dvr_extra_time_post_set(dvr_config_t *cfg, int d)
{
if(dvr_extra_time_post == d)
if(cfg->dvr_extra_time_post == d)
return;
dvr_extra_time_post = d;
dvr_save();
cfg->dvr_extra_time_post = d;
dvr_save(cfg);
}

View file

@ -40,7 +40,7 @@
*
*/
static void *dvr_thread(void *aux);
static void dvr_spawn_postproc(dvr_entry_t *de);
static void dvr_spawn_postproc(dvr_entry_t *de, const char *dvr_postproc);
static void dvr_thread_epilog(dvr_entry_t *de);
@ -157,7 +157,7 @@ makedirs(const char *path)
* Replace various chars with a dash
*/
static void
cleanupfilename(char *s)
cleanupfilename(char *s, int dvr_flags)
{
int i, len = strlen(s);
for(i = 0; i < len; i++) {
@ -186,28 +186,29 @@ pvr_generate_filename(dvr_entry_t *de)
struct stat st;
char *filename;
struct tm tm;
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
filename = strdup(de->de_ititle);
cleanupfilename(filename);
cleanupfilename(filename,cfg->dvr_flags);
snprintf(path, sizeof(path), "%s", dvr_storage);
snprintf(path, sizeof(path), "%s", cfg->dvr_storage);
/* Append per-day directory */
if(dvr_flags & DVR_DIR_PER_DAY) {
if(cfg->dvr_flags & DVR_DIR_PER_DAY) {
localtime_r(&de->de_start, &tm);
strftime(fullname, sizeof(fullname), "%F", &tm);
cleanupfilename(fullname);
cleanupfilename(fullname,cfg->dvr_flags);
snprintf(path + strlen(path), sizeof(path) - strlen(path),
"/%s", fullname);
}
/* Append per-channel directory */
if(dvr_flags & DVR_DIR_PER_CHANNEL) {
if(cfg->dvr_flags & DVR_DIR_PER_CHANNEL) {
char *chname = strdup(de->de_channel->ch_name);
cleanupfilename(chname);
cleanupfilename(chname,cfg->dvr_flags);
snprintf(path + strlen(path), sizeof(path) - strlen(path),
"/%s", chname);
free(chname);
@ -215,10 +216,10 @@ pvr_generate_filename(dvr_entry_t *de)
/* Append per-title directory */
if(dvr_flags & DVR_DIR_PER_TITLE) {
if(cfg->dvr_flags & DVR_DIR_PER_TITLE) {
char *title = strdup(de->de_title);
cleanupfilename(title);
cleanupfilename(title,cfg->dvr_flags);
snprintf(path + strlen(path), sizeof(path) - strlen(path),
"/%s", title);
free(title);
@ -233,7 +234,7 @@ pvr_generate_filename(dvr_entry_t *de)
/* Construct final name */
snprintf(fullname, sizeof(fullname), "%s/%s.%s",
path, filename, dvr_file_postfix);
path, filename, cfg->dvr_file_postfix);
while(1) {
if(stat(fullname, &st) == -1) {
@ -248,7 +249,7 @@ pvr_generate_filename(dvr_entry_t *de)
tally++;
snprintf(fullname, sizeof(fullname), "%s/%s-%d.%s",
path, filename, tally, dvr_file_postfix);
path, filename, tally, cfg->dvr_file_postfix);
}
tvh_str_set(&de->de_filename, fullname);
@ -301,6 +302,7 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
const source_info_t *si = &ss->ss_si;
const streaming_start_component_t *ssc;
int i;
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
if(pvr_generate_filename(de) != 0) {
dvr_rec_fatal_error(de, "Unable to create directories");
@ -308,7 +310,7 @@ dvr_rec_start(dvr_entry_t *de, const streaming_start_t *ss)
}
de->de_mkmux = mk_mux_create(de->de_filename, ss, de,
!!(dvr_flags & DVR_TAG_FILES));
!!(cfg->dvr_flags & DVR_TAG_FILES));
if(de->de_mkmux == NULL) {
dvr_rec_fatal_error(de, "Unable to open file");
@ -497,7 +499,7 @@ dvr_thread(void *aux)
*
*/
static void
dvr_spawn_postproc(dvr_entry_t *de)
dvr_spawn_postproc(dvr_entry_t *de, const char *dvr_postproc)
{
char *fmap[256];
char **args;
@ -553,6 +555,7 @@ dvr_thread_epilog(dvr_entry_t *de)
mk_mux_close(de->de_mkmux);
de->de_mkmux = NULL;
if(dvr_postproc)
dvr_spawn_postproc(de);
dvr_config_t *cfg = dvr_config_find_by_name_default(de->de_config_name);
if(cfg->dvr_postproc)
dvr_spawn_postproc(de,cfg->dvr_postproc);
}

View file

@ -493,15 +493,19 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
event_t *e;
dvr_entry_t *de;
dvr_entry_sched_state_t dvr_status;
const char *dvr_config_name;
if(htsmsg_get_u32(in, "eventId", &eventid))
return htsp_error("Missing argument 'eventId'");
if((e = epg_event_find_by_id(eventid)) == NULL)
return htsp_error("Event does not exist");
if((dvr_config_name = htsmsg_get_str(in, "configName")) == NULL)
dvr_config_name = "";
//create the dvr entry
de = dvr_entry_create_by_event(e,
de = dvr_entry_create_by_event(dvr_config_name,e,
htsp->htsp_username ?
htsp->htsp_username : "anonymous",
NULL, DVR_PRIO_NORMAL);
@ -698,8 +702,9 @@ htsp_method_getDiskSpace(htsp_connection_t *htsp, htsmsg_t *in)
{
htsmsg_t *out;
struct statvfs diskdata;
dvr_config_t *cfg = dvr_config_find_by_name_default("");
if(statvfs(dvr_storage,&diskdata) == -1)
if(statvfs(cfg->dvr_storage,&diskdata) == -1)
return htsp_error("Unable to stat path");
out = htsmsg_create_map();

View file

@ -104,6 +104,7 @@ TAILQ_HEAD(channel_queue, channel);
LIST_HEAD(channel_list, channel);
LIST_HEAD(event_list, event);
RB_HEAD(event_tree, event);
LIST_HEAD(dvr_config_list, dvr_config);
LIST_HEAD(dvr_entry_list, dvr_entry);
TAILQ_HEAD(ref_update_queue, ref_update);
LIST_HEAD(th_transport_list, th_transport);

View file

@ -568,7 +568,7 @@ extjs_channeltags(http_connection_t *hc, const char *remain, void *opaque)
pthread_mutex_lock(&global_lock);
if(!strcmp(op, "listTags")) {
if(op != NULL && !strcmp(op, "listTags")) {
out = htsmsg_create_map();
array = htsmsg_create_list();
@ -599,6 +599,50 @@ extjs_channeltags(http_connection_t *hc, const char *remain, void *opaque)
}
/**
*
*/
static int
extjs_confignames(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, *array, *e;
dvr_config_t *cfg;
pthread_mutex_lock(&global_lock);
if(op != NULL && !strcmp(op, "list")) {
out = htsmsg_create_map();
array = htsmsg_create_list();
LIST_FOREACH(cfg, &dvrconfigs, config_link) {
e = htsmsg_create_map();
htsmsg_add_str(e, "identifier", cfg->dvr_config_name);
if (strlen(cfg->dvr_config_name) == 0)
htsmsg_add_str(e, "name", "(default)");
else
htsmsg_add_str(e, "name", cfg->dvr_config_name);
htsmsg_add_msg(array, NULL, e);
}
htsmsg_add_msg(out, "entries", array);
} else {
pthread_mutex_unlock(&global_lock);
return HTTP_STATUS_BAD_REQUEST;
}
pthread_mutex_unlock(&global_lock);
htsmsg_json_serialize(out, hq, 0);
htsmsg_destroy(out);
http_output_content(hc, "text/x-json; charset=UTF-8");
return 0;
}
/**
*
*/
@ -713,6 +757,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
dvr_entry_t *de;
const char *s;
int flags = 0;
dvr_config_t *cfg;
if(op == NULL)
op = "loadSettings";
@ -725,14 +770,17 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
}
if(!strcmp(op, "recordEvent")) {
s = http_arg_get(&hc->hc_req_args, "eventId");
const char *config_name = http_arg_get(&hc->hc_req_args, "config_name");
s = http_arg_get(&hc->hc_req_args, "eventId");
if((e = epg_event_find_by_id(atoi(s))) == NULL) {
pthread_mutex_unlock(&global_lock);
return HTTP_STATUS_BAD_REQUEST;
}
dvr_entry_create_by_event(e, hc->hc_representative, NULL, DVR_PRIO_NORMAL);
dvr_entry_create_by_event(config_name,
e, hc->hc_representative, NULL, DVR_PRIO_NORMAL);
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
@ -751,6 +799,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
} else if(!strcmp(op, "createEntry")) {
const char *config_name = http_arg_get(&hc->hc_req_args, "config_name");
const char *title = http_arg_get(&hc->hc_req_args, "title");
const char *datestr = http_arg_get(&hc->hc_req_args, "date");
const char *startstr = http_arg_get(&hc->hc_req_args, "starttime");
@ -787,7 +836,8 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if(stop < start)
stop += 86400;
dvr_entry_create(ch, start, stop, title, NULL, hc->hc_representative,
dvr_entry_create(config_name,
ch, start, stop, title, NULL, hc->hc_representative,
NULL, NULL, 0, dvr_pri2val(pri));
out = htsmsg_create_map();
@ -798,7 +848,8 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
dvr_autorec_add(http_arg_get(&hc->hc_req_args, "title"),
dvr_autorec_add(http_arg_get(&hc->hc_req_args, "config_name"),
http_arg_get(&hc->hc_req_args, "title"),
http_arg_get(&hc->hc_req_args, "channel"),
http_arg_get(&hc->hc_req_args, "tag"),
cgrp ? epg_content_group_find_by_name(cgrp) : 0,
@ -809,42 +860,54 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
} else if(!strcmp(op, "loadSettings")) {
s = http_arg_get(&hc->hc_req_args, "config_name");
if (s == NULL)
s = "";
cfg = dvr_config_find_by_name_default(s);
r = htsmsg_create_map();
htsmsg_add_str(r, "storage", dvr_storage);
if(dvr_postproc != NULL)
htsmsg_add_str(r, "postproc", dvr_postproc);
htsmsg_add_u32(r, "retention", dvr_retention_days);
htsmsg_add_u32(r, "preExtraTime", dvr_extra_time_pre);
htsmsg_add_u32(r, "postExtraTime", dvr_extra_time_post);
htsmsg_add_u32(r, "dayDirs", !!(dvr_flags & DVR_DIR_PER_DAY));
htsmsg_add_u32(r, "channelDirs", !!(dvr_flags & DVR_DIR_PER_CHANNEL));
htsmsg_add_u32(r, "channelInTitle", !!(dvr_flags & DVR_CHANNEL_IN_TITLE));
htsmsg_add_u32(r, "dateInTitle", !!(dvr_flags & DVR_DATE_IN_TITLE));
htsmsg_add_u32(r, "timeInTitle", !!(dvr_flags & DVR_TIME_IN_TITLE));
htsmsg_add_u32(r, "whitespaceInTitle", !!(dvr_flags & DVR_WHITESPACE_IN_TITLE));
htsmsg_add_u32(r, "titleDirs", !!(dvr_flags & DVR_DIR_PER_TITLE));
htsmsg_add_u32(r, "episodeInTitle", !!(dvr_flags & DVR_EPISODE_IN_TITLE));
htsmsg_add_u32(r, "cleanTitle", !!(dvr_flags & DVR_CLEAN_TITLE));
htsmsg_add_u32(r, "tagFiles", !!(dvr_flags & DVR_TAG_FILES));
htsmsg_add_str(r, "storage", cfg->dvr_storage);
if(cfg->dvr_postproc != NULL)
htsmsg_add_str(r, "postproc", cfg->dvr_postproc);
htsmsg_add_u32(r, "retention", cfg->dvr_retention_days);
htsmsg_add_u32(r, "preExtraTime", cfg->dvr_extra_time_pre);
htsmsg_add_u32(r, "postExtraTime", cfg->dvr_extra_time_post);
htsmsg_add_u32(r, "dayDirs", !!(cfg->dvr_flags & DVR_DIR_PER_DAY));
htsmsg_add_u32(r, "channelDirs", !!(cfg->dvr_flags & DVR_DIR_PER_CHANNEL));
htsmsg_add_u32(r, "channelInTitle", !!(cfg->dvr_flags & DVR_CHANNEL_IN_TITLE));
htsmsg_add_u32(r, "dateInTitle", !!(cfg->dvr_flags & DVR_DATE_IN_TITLE));
htsmsg_add_u32(r, "timeInTitle", !!(cfg->dvr_flags & DVR_TIME_IN_TITLE));
htsmsg_add_u32(r, "whitespaceInTitle", !!(cfg->dvr_flags & DVR_WHITESPACE_IN_TITLE));
htsmsg_add_u32(r, "titleDirs", !!(cfg->dvr_flags & DVR_DIR_PER_TITLE));
htsmsg_add_u32(r, "episodeInTitle", !!(cfg->dvr_flags & DVR_EPISODE_IN_TITLE));
htsmsg_add_u32(r, "cleanTitle", !!(cfg->dvr_flags & DVR_CLEAN_TITLE));
htsmsg_add_u32(r, "tagFiles", !!(cfg->dvr_flags & DVR_TAG_FILES));
out = json_single_record(r, "dvrSettings");
} else if(!strcmp(op, "saveSettings")) {
s = http_arg_get(&hc->hc_req_args, "config_name");
cfg = dvr_config_find_by_name(s);
if (cfg == NULL)
cfg = dvr_config_create(s);
tvhlog(LOG_INFO,"dvr","Saving configuration '%s'", cfg->dvr_config_name);
if((s = http_arg_get(&hc->hc_req_args, "storage")) != NULL)
dvr_storage_set(s);
dvr_storage_set(cfg,s);
if((s = http_arg_get(&hc->hc_req_args, "postproc")) != NULL)
dvr_postproc_set(s);
dvr_postproc_set(cfg,s);
if((s = http_arg_get(&hc->hc_req_args, "retention")) != NULL)
dvr_retention_set(atoi(s));
dvr_retention_set(cfg,atoi(s));
if((s = http_arg_get(&hc->hc_req_args, "preExtraTime")) != NULL)
dvr_extra_time_pre_set(atoi(s));
dvr_extra_time_pre_set(cfg,atoi(s));
if((s = http_arg_get(&hc->hc_req_args, "postExtraTime")) != NULL)
dvr_extra_time_post_set(atoi(s));
dvr_extra_time_post_set(cfg,atoi(s));
if(http_arg_get(&hc->hc_req_args, "dayDirs") != NULL)
flags |= DVR_DIR_PER_DAY;
@ -867,7 +930,15 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
if(http_arg_get(&hc->hc_req_args, "tagFiles") != NULL)
flags |= DVR_TAG_FILES;
dvr_flags_set(flags);
dvr_flags_set(cfg,flags);
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
} else if(!strcmp(op, "deleteSettings")) {
s = http_arg_get(&hc->hc_req_args, "config_name");
dvr_config_delete(s);
out = htsmsg_create_map();
htsmsg_add_u32(out, "success", 1);
@ -941,6 +1012,8 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(m, "chicon", de->de_channel->ch_icon);
}
htsmsg_add_str(m, "config_name", de->de_config_name);
if(de->de_title != NULL)
htsmsg_add_str(m, "title", de->de_title);
@ -1401,6 +1474,7 @@ extjs_start(void)
http_path_add("/channels", NULL, extjs_channels, ACCESS_WEB_INTERFACE);
http_path_add("/xmltv", NULL, extjs_xmltv, ACCESS_WEB_INTERFACE);
http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
http_path_add("/confignames", NULL, extjs_confignames, ACCESS_WEB_INTERFACE);
http_path_add("/epg", NULL, extjs_epg, ACCESS_WEB_INTERFACE);
http_path_add("/dvr", NULL, extjs_dvr, ACCESS_WEB_INTERFACE);
http_path_add("/dvrlist", NULL, extjs_dvrlist, ACCESS_WEB_INTERFACE);

View file

@ -210,7 +210,7 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
de = dvr_entry_find_by_event(e);
if((http_arg_get(&hc->hc_req_args, "rec")) != NULL) {
de = dvr_entry_create_by_event(e, hc->hc_username ?: "anonymous", NULL,
de = dvr_entry_create_by_event("", e, hc->hc_username ?: "anonymous", NULL,
DVR_PRIO_NORMAL);
} else if(de != NULL && (http_arg_get(&hc->hc_req_args, "cancel")) != NULL) {
de = dvr_entry_cancel(de);

View file

@ -12,6 +12,7 @@ Ext.extend(tvheadend.Comet = function() {
channeltags: true,
autorec: true,
dvrdb: true,
dvrconfig: true,
channels: true
});
}, Ext.util.Observable);

View file

@ -27,6 +27,28 @@ tvheadend.dvrprio = new Ext.data.SimpleStore({
]
});
/**
* Configuration names
*/
tvheadend.configNames = new Ext.data.JsonStore({
autoLoad:true,
root:'entries',
fields: ['identifier','name'],
id: 'identifier',
url:'confignames',
baseParams: {
op: 'list'
}
});
tvheadend.configNames.setDefaultSort('name', 'ASC');
tvheadend.comet.on('dvrconfig', function(m) {
if(m.reload != null)
tvheadend.configNames.reload();
});
/**
*
*/
@ -190,6 +212,18 @@ tvheadend.dvrschedule = function() {
hidden:true,
dataIndex: 'creator'
},{
width: 200,
id:'config_name',
header: "DVR Configuration",
renderer: function(value, metadata, record, row, col, store) {
if (!value) {
return '<span class="tvh-grid-unset">(default)</span>';
} else {
return value;
}
},
dataIndex: 'config_name'
},{
width: 200,
id:'status',
header: "Status",
@ -267,7 +301,19 @@ tvheadend.dvrschedule = function() {
allowBlank: false,
fieldLabel: 'Title',
name: 'title'
}
},
new Ext.form.ComboBox({
store: tvheadend.configNames,
triggerAction: 'all',
mode: 'local',
fieldLabel: 'DVR Configuration',
valueField: 'identifier',
displayField: 'name',
name: 'config_name',
emptyText: '(default)',
value: '',
editable: false
})
],
buttons: [{
text: 'Create',
@ -285,6 +331,18 @@ tvheadend.dvrschedule = function() {
items: panel
});
win.show();
new Ext.form.ComboBox({
store: tvheadend.configNames,
triggerAction: 'all',
mode: 'local',
fieldLabel: 'DVR Configuration',
valueField: 'identifier',
displayField: 'name',
name: 'config_name',
emptyText: '(default)',
value: '',
editable: false
})
};
@ -448,6 +506,26 @@ tvheadend.autoreceditor = function() {
valueField: 'identifier',
displayField: 'name'
})
},{
header: "DVR Configuration",
dataIndex: 'config_name',
renderer: function(value, metadata, record, row, col, store) {
if (!value) {
return '<span class="tvh-grid-unset">(default)</span>';
} else {
return value;
}
},
editor: new Ext.form.ComboBox({
store: tvheadend.configNames,
triggerAction: 'all',
mode: 'local',
valueField: 'identifier',
displayField: 'name',
name: 'config_name',
emptyText: '(default)',
editable: false
})
},{
header: "Created by",
dataIndex: 'creator',
@ -484,6 +562,7 @@ tvheadend.dvr = function() {
{name: 'chicon'},
{name: 'start', type: 'date', dateFormat: 'U' /* unix time */},
{name: 'end', type: 'date', dateFormat: 'U' /* unix time */},
{name: 'config_name'},
{name: 'status'},
{name: 'schedstate'},
{name: 'creator'},
@ -522,7 +601,7 @@ tvheadend.dvr = function() {
tvheadend.autorecRecord = Ext.data.Record.create([
'enabled','title','channel','tag','creator','contentgrp','comment',
'weekdays', 'pri', 'approx_time'
'weekdays', 'pri', 'approx_time', 'config_name'
]);
@ -568,6 +647,25 @@ tvheadend.dvrsettings = function() {
'preExtraTime', 'postExtraTime', 'whitespaceInTitle',
'titleDirs', 'episodeInTitle', 'cleanTitle', 'tagFiles']);
var confcombo = new Ext.form.ComboBox({
store: tvheadend.configNames,
triggerAction: 'all',
mode: 'local',
displayField: 'name',
name: 'config_name',
emptyText: '(default)',
value: '',
editable: true
});
var delButton = new Ext.Toolbar.Button({
tooltip: 'Delete named configuration',
iconCls:'remove',
text: "Delete configuration",
handler: deleteConfiguration,
disabled: true
});
var confpanel = new Ext.FormPanel({
title:'Digital Video Recorder',
iconCls: 'drive',
@ -633,43 +731,85 @@ tvheadend.dvrsettings = function() {
fieldLabel: 'Post-processor command',
name: 'postproc'
}],
tbar: [{
tooltip: 'Save changes made to channel configuration below',
tbar: [confcombo, {
tooltip: 'Save changes made to dvr configuration below',
iconCls:'save',
text: "Save configuration",
handler: saveChanges
}, '->', {
}, delButton, '->', {
text: 'Help',
handler: function() {
new tvheadend.help('DVR configuration',
'config_dvr.html');
}
}]
});
confpanel.on('render', function() {
function loadConfig() {
confpanel.getForm().load({
url:'dvr',
params:{'op':'loadSettings'},
params:{'op':'loadSettings','config_name':confcombo.getValue()},
success:function(form, action) {
confpanel.enable();
}
});
}
confcombo.on('select', function() {
if (confcombo.getValue() == '')
delButton.disable();
else
delButton.enable();
loadConfig();
});
confpanel.on('render', function() {
loadConfig();
});
function saveChanges() {
var config_name = confcombo.getValue();
confpanel.getForm().submit({
url:'dvr',
params:{'op':'saveSettings'},
params:{'op':'saveSettings','config_name':config_name},
waitMsg:'Saving Data...',
success: function(form, action) {
confcombo.setValue(config_name);
confcombo.fireEvent('select');
},
failure: function(form, action) {
Ext.Msg.alert('Save failed', action.result.errormsg);
}
});
}
function deleteConfiguration() {
if (confcombo.getValue() != "") {
Ext.MessageBox.confirm('Message',
'Do you really want to delete DVR configuration \'' +
confcombo.getValue() + '\'?',
deleteAction);
}
}
function deleteAction(btn) {
if (btn == 'yes') {
confpanel.getForm().submit({
url:'dvr',
params:{'op':'deleteSettings','config_name':confcombo.getValue()},
waitMsg:'Deleting Data...',
success: function(form, action) {
confcombo.setValue('');
confcombo.fireEvent('select');
},
failure: function(form, action) {
Ext.Msg.alert('Delete failed', action.result.errormsg);
}
});
}
}
return confpanel;
}

View file

@ -34,6 +34,18 @@ tvheadend.epgDetails = function(event) {
'http://akas.imdb.org/find?q=' + event.title + '">Search IMDB</a></div>'
var confcombo = new Ext.form.ComboBox({
store: tvheadend.configNames,
triggerAction: 'all',
mode: 'local',
valueField: 'identifier',
displayField: 'name',
name: 'config_name',
emptyText: '(default)',
value: '',
editable: false
});
var win = new Ext.Window({
title: event.title,
bodyStyle: 'margin: 5px',
@ -42,6 +54,7 @@ tvheadend.epgDetails = function(event) {
height: 300,
constrainHeader: true,
buttons: [
confcombo,
new Ext.Button({
handler: recordEvent,
text: "Record program"
@ -56,7 +69,11 @@ tvheadend.epgDetails = function(event) {
function recordEvent() {
Ext.Ajax.request({
url: 'dvr',
params: {eventId: event.id, op: 'recordEvent'},
params: {
eventId: event.id,
op: 'recordEvent',
config_name: confcombo.getValue()
},
success:function(response, options) {
win.close();