parent
92219d11be
commit
801ba2a1c6
12 changed files with 598 additions and 198 deletions
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
370
src/dvr/dvr_db.c
370
src/dvr/dvr_db.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -12,6 +12,7 @@ Ext.extend(tvheadend.Comet = function() {
|
|||
channeltags: true,
|
||||
autorec: true,
|
||||
dvrdb: true,
|
||||
dvrconfig: true,
|
||||
channels: true
|
||||
});
|
||||
}, Ext.util.Observable);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue