- better duplicate handling - better subtitle handling
This commit is contained in:
parent
ce78f14570
commit
2b22bc75a1
9 changed files with 275 additions and 67 deletions
|
@ -163,6 +163,7 @@ typedef struct dvr_entry {
|
|||
char *de_directory; /* Can be set for autorec entries, will override any
|
||||
directory setting from the configuration */
|
||||
lang_str_t *de_title; /* Title in UTF-8 (from EPG) */
|
||||
lang_str_t *de_subtitle; /* Subtitle in UTF-8 (from EPG) */
|
||||
lang_str_t *de_desc; /* Description in UTF-8 (from EPG) */
|
||||
uint32_t de_content_type; /* Content type (from EPG) (only code) */
|
||||
|
||||
|
@ -244,6 +245,16 @@ typedef struct dvr_entry {
|
|||
|
||||
#define DVR_CH_NAME(e) ((e)->de_channel == NULL ? (e)->de_channel_name : channel_get_name((e)->de_channel))
|
||||
|
||||
typedef enum {
|
||||
DVR_AUTOREC_RECORD_ALL = 0,
|
||||
DVR_AUTOREC_RECORD_DIFFERENT_EPISODE_NUMBER = 1,
|
||||
DVR_AUTOREC_RECORD_DIFFERENT_SUBTITLE = 2,
|
||||
DVR_AUTOREC_RECORD_DIFFERENT_DESCRIPTION = 3,
|
||||
DVR_AUTOREC_RECORD_ONCE_PER_WEEK = 4,
|
||||
DVR_AUTOREC_RECORD_ONCE_PER_DAY = 5
|
||||
} dvr_autorec_dedup_t;
|
||||
|
||||
|
||||
/**
|
||||
* Autorec entry
|
||||
*/
|
||||
|
@ -291,9 +302,12 @@ typedef struct dvr_autorec_entry {
|
|||
int dae_minduration;
|
||||
int dae_maxduration;
|
||||
int dae_retention;
|
||||
|
||||
|
||||
time_t dae_start_extra;
|
||||
time_t dae_stop_extra;
|
||||
|
||||
int dae_record;
|
||||
|
||||
} dvr_autorec_entry_t;
|
||||
|
||||
TAILQ_HEAD(dvr_autorec_entry_queue, dvr_autorec_entry);
|
||||
|
@ -432,7 +446,7 @@ dvr_entry_t *
|
|||
dvr_entry_create_htsp( const char *dvr_config_uuid,
|
||||
channel_t *ch, time_t start, time_t stop,
|
||||
time_t start_extra, time_t stop_extra,
|
||||
const char *title, const char *description,
|
||||
const char *title, const char* subtitle, const char *description,
|
||||
const char *lang, epg_genre_t *content_type,
|
||||
const char *owner, const char *creator,
|
||||
dvr_autorec_entry_t *dae,
|
||||
|
@ -441,7 +455,7 @@ dvr_entry_create_htsp( const char *dvr_config_uuid,
|
|||
|
||||
dvr_entry_t *
|
||||
dvr_entry_update( dvr_entry_t *de,
|
||||
const char* de_title, const char *de_desc, const char *lang,
|
||||
const char* de_title, const char* de_subtitle, const char *de_desc, const char *lang,
|
||||
time_t de_start, time_t de_stop,
|
||||
time_t de_start_extra, time_t de_stop_extra,
|
||||
dvr_prio_t pri, int retention );
|
||||
|
@ -506,7 +520,7 @@ dvr_entry_t *
|
|||
dvr_entry_create_(const char *config_uuid, epg_broadcast_t *e,
|
||||
channel_t *ch, time_t start, time_t stop,
|
||||
time_t start_extra, time_t stop_extra,
|
||||
const char *title, const char *description,
|
||||
const char *title, const char* subtitle, const char *description,
|
||||
const char *lang, epg_genre_t *content_type,
|
||||
const char *owner, const char *creator,
|
||||
dvr_autorec_entry_t *dae, dvr_timerec_entry_t *tae,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* tvheadend, Automatic recordings
|
||||
* Copyright (C) 2010 Andreas Öman
|
||||
* Copyright (C) 2010 Andreas <EFBFBD>man
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -867,6 +867,20 @@ dvr_autorec_entry_class_content_type_list(void *o)
|
|||
return m;
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
dvr_autorec_entry_class_dedup_list ( void *o )
|
||||
{
|
||||
static const struct strtab tab[] = {
|
||||
{ "Record all", DVR_AUTOREC_RECORD_ALL },
|
||||
{ "Record if different episode number", DVR_AUTOREC_RECORD_DIFFERENT_EPISODE_NUMBER },
|
||||
{ "Record if different subtitle", DVR_AUTOREC_RECORD_DIFFERENT_SUBTITLE },
|
||||
{ "Record if different description", DVR_AUTOREC_RECORD_DIFFERENT_DESCRIPTION },
|
||||
{ "Record once per week", DVR_AUTOREC_RECORD_ONCE_PER_WEEK },
|
||||
{ "Record once per day", DVR_AUTOREC_RECORD_ONCE_PER_DAY },
|
||||
};
|
||||
return strtab2htsmsg(tab);
|
||||
}
|
||||
|
||||
const idclass_t dvr_autorec_entry_class = {
|
||||
.ic_class = "dvrautorec",
|
||||
.ic_caption = "DVR Auto-Record Entry",
|
||||
|
@ -999,6 +1013,14 @@ const idclass_t dvr_autorec_entry_class = {
|
|||
.def.i = DVR_PRIO_NORMAL,
|
||||
.off = offsetof(dvr_autorec_entry_t, dae_pri),
|
||||
},
|
||||
{
|
||||
.type = PT_U32,
|
||||
.id = "record",
|
||||
.name = "Duplicate Handling",
|
||||
.def.i = DVR_AUTOREC_RECORD_ALL,
|
||||
.off = offsetof(dvr_autorec_entry_t, dae_record),
|
||||
.list = dvr_autorec_entry_class_dedup_list,
|
||||
},
|
||||
{
|
||||
.type = PT_INT,
|
||||
.id = "retention",
|
||||
|
|
241
src/dvr/dvr_db.c
241
src/dvr/dvr_db.c
|
@ -44,6 +44,7 @@ static void dvr_timer_expire(void *aux);
|
|||
static void dvr_timer_start_recording(void *aux);
|
||||
static void dvr_timer_stop_recording(void *aux);
|
||||
static int dvr_entry_class_disp_title_set(void *o, const void *v);
|
||||
static int dvr_entry_class_disp_subtitle_set(void *o, const void *v);
|
||||
|
||||
/*
|
||||
* Start / stop time calculators
|
||||
|
@ -261,10 +262,9 @@ dvr_make_title(char *output, size_t outlen, dvr_entry_t *de)
|
|||
".", "S%02d", NULL, "E%02d", NULL);
|
||||
}
|
||||
|
||||
if (cfg->dvr_subtitle_in_title) {
|
||||
if(de->de_bcast && de->de_bcast->episode && de->de_bcast->episode->subtitle)
|
||||
if (cfg->dvr_subtitle_in_title && de->de_subtitle) {
|
||||
snprintf(output + strlen(output), outlen - strlen(output),
|
||||
".%s", lang_str_get(de->de_bcast->episode->subtitle, NULL));
|
||||
".%s", lang_str_get(de->de_subtitle, NULL));
|
||||
}
|
||||
|
||||
localtime_r(&de->de_start, &tm);
|
||||
|
@ -306,7 +306,7 @@ dvr_entry_set_timer(dvr_entry_t *de)
|
|||
de->de_sched_state = DVR_MISSED_TIME;
|
||||
else
|
||||
_dvr_entry_completed(de);
|
||||
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
|
||||
gtimer_arm_abs(&de->de_timer, dvr_timer_expire, de,
|
||||
de->de_stop + dvr_entry_get_retention(de) * 86400);
|
||||
|
||||
} else if (de->de_sched_state == DVR_RECORDING) {
|
||||
|
@ -429,6 +429,11 @@ dvr_entry_create(const char *uuid, htsmsg_t *conf)
|
|||
(s = htsmsg_get_str(conf, "disp_title")) != NULL)
|
||||
dvr_entry_class_disp_title_set(de, s);
|
||||
|
||||
/* special case, becaous PO_NOSAVE, load ignores it */
|
||||
if (de->de_subtitle == NULL &&
|
||||
(s = htsmsg_get_str(conf, "disp_subtitle")) != NULL)
|
||||
dvr_entry_class_disp_subtitle_set(de, s);
|
||||
|
||||
de->de_refcnt = 1;
|
||||
|
||||
LIST_INSERT_HEAD(&dvrentries, de, de_global_link);
|
||||
|
@ -456,7 +461,7 @@ dvr_entry_t *
|
|||
dvr_entry_create_(const char *config_uuid, epg_broadcast_t *e,
|
||||
channel_t *ch, time_t start, time_t stop,
|
||||
time_t start_extra, time_t stop_extra,
|
||||
const char *title, const char *description,
|
||||
const char *title, const char* subtitle, const char *description,
|
||||
const char *lang, epg_genre_t *content_type,
|
||||
const char *owner,
|
||||
const char *creator, dvr_autorec_entry_t *dae,
|
||||
|
@ -487,6 +492,8 @@ dvr_entry_create_(const char *config_uuid, epg_broadcast_t *e,
|
|||
htsmsg_add_u32(conf, "dvb_eid", e->dvb_eid);
|
||||
if (e->episode && e->episode->title)
|
||||
lang_str_serialize(e->episode->title, conf, "title");
|
||||
if (e->episode && e->episode->subtitle)
|
||||
lang_str_serialize(e->episode->subtitle, conf, "subtitle");
|
||||
if (e->description)
|
||||
lang_str_serialize(e->description, conf, "description");
|
||||
else if (e->episode && e->episode->description)
|
||||
|
@ -508,6 +515,12 @@ dvr_entry_create_(const char *config_uuid, epg_broadcast_t *e,
|
|||
lang_str_serialize(l, conf, "description");
|
||||
lang_str_destroy(l);
|
||||
}
|
||||
if (subtitle) {
|
||||
l = lang_str_create();
|
||||
lang_str_add(l, subtitle, lang, 0);
|
||||
lang_str_serialize(l, conf, "subtitle");
|
||||
lang_str_destroy(l);
|
||||
}
|
||||
}
|
||||
if (content_type)
|
||||
htsmsg_add_u32(conf, "content_type", content_type->code / 16);
|
||||
|
@ -552,7 +565,7 @@ dvr_entry_t *
|
|||
dvr_entry_create_htsp(const char *config_uuid,
|
||||
channel_t *ch, time_t start, time_t stop,
|
||||
time_t start_extra, time_t stop_extra,
|
||||
const char *title,
|
||||
const char *title, const char* subtitle,
|
||||
const char *description, const char *lang,
|
||||
epg_genre_t *content_type,
|
||||
const char *owner,
|
||||
|
@ -566,7 +579,7 @@ dvr_entry_create_htsp(const char *config_uuid,
|
|||
return dvr_entry_create_(cfg ? idnode_uuid_as_str(&cfg->dvr_id) : NULL,
|
||||
NULL,
|
||||
ch, start, stop, start_extra, stop_extra,
|
||||
title, description, lang, content_type,
|
||||
title, subtitle, description, lang, content_type,
|
||||
owner, creator, dae, NULL, pri, retention,
|
||||
comment);
|
||||
}
|
||||
|
@ -589,47 +602,109 @@ dvr_entry_create_by_event(const char *config_uuid,
|
|||
return dvr_entry_create_(config_uuid, e,
|
||||
e->channel, e->start, e->stop,
|
||||
start_extra, stop_extra,
|
||||
NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
LIST_FIRST(&e->episode->genre),
|
||||
owner, creator, dae, NULL, pri, retention,
|
||||
comment);
|
||||
}
|
||||
|
||||
static inline int strempty(const char* c) {
|
||||
return !c || c[0] == 0;
|
||||
}
|
||||
|
||||
static inline int lang_str_empty(lang_str_t* str) {
|
||||
return strempty(lang_str_get(str, NULL));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int _dvr_duplicate_event ( epg_broadcast_t *e )
|
||||
static dvr_entry_t* _dvr_duplicate_event(dvr_entry_t* de)
|
||||
{
|
||||
dvr_entry_t *de;
|
||||
epg_episode_num_t empty_epnum;
|
||||
int has_epnum = 1;
|
||||
if (!de->de_autorec)
|
||||
return NULL;
|
||||
|
||||
/* skip episode duplicate check below if no episode number */
|
||||
memset(&empty_epnum, 0, sizeof(empty_epnum));
|
||||
if (epg_episode_number_cmp(&empty_epnum, &e->episode->epnum) == 0)
|
||||
has_epnum = 0;
|
||||
int record = de->de_autorec->dae_record;
|
||||
|
||||
LIST_FOREACH(de, &dvrentries, de_global_link) {
|
||||
if (de->de_bcast) {
|
||||
if (de->de_bcast->episode == e->episode) return 1;
|
||||
struct tm de_start;
|
||||
localtime_r(&de->de_start, &de_start);
|
||||
|
||||
if (has_epnum) {
|
||||
int ep_dup_det = de->de_config->dvr_episode_duplicate;
|
||||
switch (record) {
|
||||
case DVR_AUTOREC_RECORD_ALL:
|
||||
return NULL;
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_EPISODE_NUMBER:
|
||||
if (strempty(de->de_episode))
|
||||
return NULL;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_SUBTITLE:
|
||||
if (lang_str_empty(de->de_subtitle))
|
||||
return NULL;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_DESCRIPTION:
|
||||
if (lang_str_empty(de->de_desc))
|
||||
return NULL;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_ONCE_PER_WEEK:
|
||||
de_start.tm_mday -= (de_start.tm_wday + 6) % 7; // week = mon-sun
|
||||
mktime(&de_start); // adjusts de_start
|
||||
break;
|
||||
}
|
||||
|
||||
if (ep_dup_det) {
|
||||
const char* de_title = lang_str_get(de->de_bcast->episode->title, NULL);
|
||||
const char* e_title = lang_str_get(e->episode->title, NULL);
|
||||
// title not defined, can't be deduped
|
||||
if (lang_str_empty(de->de_title))
|
||||
return NULL;
|
||||
|
||||
/* duplicate if title and episode match */
|
||||
if (de_title && e_title && strcmp(de_title, e_title) == 0
|
||||
&& epg_episode_number_cmp(&de->de_bcast->episode->epnum, &e->episode->epnum) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
dvr_entry_t *de2;
|
||||
|
||||
LIST_FOREACH(de2, &dvrentries, de_global_link) {
|
||||
if (de == de2)
|
||||
continue;
|
||||
|
||||
// only earlier recordings qualify as master
|
||||
if (de2->de_start > de->de_start)
|
||||
continue;
|
||||
|
||||
// only successful earlier recordings qualify as master
|
||||
if (de2->de_sched_state == DVR_MISSED_TIME || (de2->de_sched_state == DVR_COMPLETED && de2->de_last_error != SM_CODE_OK))
|
||||
continue;
|
||||
|
||||
// if titles are not defined or do not match, don't dedup
|
||||
if (lang_str_compare(de->de_title, de2->de_title))
|
||||
continue;
|
||||
|
||||
switch (record) {
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_EPISODE_NUMBER:
|
||||
if (!strcmp(de->de_episode, de2->de_episode))
|
||||
return de2;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_SUBTITLE:
|
||||
if (!lang_str_compare(de->de_subtitle, de2->de_subtitle))
|
||||
return de2;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_DIFFERENT_DESCRIPTION:
|
||||
if (!lang_str_compare(de->de_desc, de2->de_desc))
|
||||
return de2;
|
||||
break;
|
||||
case DVR_AUTOREC_RECORD_ONCE_PER_WEEK: {
|
||||
struct tm de2_start;
|
||||
localtime_r(&de2->de_start, &de2_start);
|
||||
de2_start.tm_mday -= (de2_start.tm_wday + 6) % 7; // week = mon-sun
|
||||
mktime(&de2_start); // adjusts de2_start
|
||||
if (de_start.tm_year == de2_start.tm_year && de_start.tm_yday == de2_start.tm_yday)
|
||||
return de2;
|
||||
break;
|
||||
}
|
||||
case DVR_AUTOREC_RECORD_ONCE_PER_DAY: {
|
||||
struct tm de2_start;
|
||||
localtime_r(&de2->de_start, &de2_start);
|
||||
if (de_start.tm_year == de2_start.tm_year && de_start.tm_yday == de2_start.tm_yday)
|
||||
return de2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -641,7 +716,11 @@ dvr_entry_create_by_autorec(epg_broadcast_t *e, dvr_autorec_entry_t *dae)
|
|||
char buf[200];
|
||||
|
||||
/* Dup detection */
|
||||
if (_dvr_duplicate_event(e)) return;
|
||||
dvr_entry_t* de;
|
||||
LIST_FOREACH(de, &dvrentries, de_global_link) {
|
||||
if (de->de_bcast == e || (de->de_bcast && de->de_bcast->episode == e->episode))
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "Auto recording%s%s",
|
||||
dae->dae_creator ? " by: " : "",
|
||||
|
@ -651,6 +730,8 @@ dvr_entry_create_by_autorec(epg_broadcast_t *e, dvr_autorec_entry_t *dae)
|
|||
dae->dae_start_extra, dae->dae_stop_extra,
|
||||
dae->dae_owner, buf, dae, dae->dae_pri, dae->dae_retention,
|
||||
dae->dae_comment);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -684,6 +765,7 @@ dvr_entry_dec_ref(dvr_entry_t *de)
|
|||
free(de->de_creator);
|
||||
free(de->de_comment);
|
||||
if (de->de_title) lang_str_destroy(de->de_title);
|
||||
if (de->de_subtitle) lang_str_destroy(de->de_subtitle);
|
||||
if (de->de_desc) lang_str_destroy(de->de_desc);
|
||||
if (de->de_bcast) de->de_bcast->putref((epg_object_t*)de->de_bcast);
|
||||
free(de->de_channel_name);
|
||||
|
@ -769,7 +851,7 @@ dvr_timer_expire(void *aux)
|
|||
}
|
||||
|
||||
static dvr_entry_t *_dvr_entry_update
|
||||
( dvr_entry_t *de, epg_broadcast_t *e, const char *title,
|
||||
( dvr_entry_t *de, epg_broadcast_t *e, const char *title, const char* subtitle,
|
||||
const char *desc, const char *lang, time_t start, time_t stop,
|
||||
time_t start_extra, time_t stop_extra, dvr_prio_t pri, int retention )
|
||||
{
|
||||
|
@ -819,7 +901,13 @@ static dvr_entry_t *_dvr_entry_update
|
|||
if (!de->de_title) de->de_title = lang_str_create();
|
||||
save = lang_str_add(de->de_title, title, lang, 1);
|
||||
}
|
||||
|
||||
|
||||
/* Subtitle*/
|
||||
if (subtitle) {
|
||||
if (!de->de_subtitle) de->de_subtitle = lang_str_create();
|
||||
save = lang_str_add(de->de_subtitle, subtitle, lang, 1);
|
||||
}
|
||||
|
||||
/* EID */
|
||||
if (e && e->dvb_eid != de->de_dvb_eid) {
|
||||
de->de_dvb_eid = e->dvb_eid;
|
||||
|
@ -873,12 +961,12 @@ static dvr_entry_t *_dvr_entry_update
|
|||
dvr_entry_t *
|
||||
dvr_entry_update
|
||||
(dvr_entry_t *de,
|
||||
const char* de_title, const char *de_desc, const char *lang,
|
||||
const char* de_title, const char* de_subtitle, const char *de_desc, const char *lang,
|
||||
time_t de_start, time_t de_stop,
|
||||
time_t de_start_extra, time_t de_stop_extra,
|
||||
dvr_prio_t pri, int retention)
|
||||
{
|
||||
return _dvr_entry_update(de, NULL, de_title, de_desc, lang,
|
||||
return _dvr_entry_update(de, NULL, de_title, de_subtitle, de_desc, lang,
|
||||
de_start, de_stop, de_start_extra, de_stop_extra,
|
||||
pri, retention);
|
||||
}
|
||||
|
@ -930,7 +1018,7 @@ dvr_event_replaced(epg_broadcast_t *e, epg_broadcast_t *new_e)
|
|||
e->start, e->stop);
|
||||
e->getref(e);
|
||||
de->de_bcast = e;
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -943,7 +1031,7 @@ void dvr_event_updated ( epg_broadcast_t *e )
|
|||
dvr_entry_t *de;
|
||||
de = dvr_entry_find_by_event(e);
|
||||
if (de)
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
else {
|
||||
LIST_FOREACH(de, &dvrentries, de_global_link) {
|
||||
if (de->de_sched_state != DVR_SCHEDULED) continue;
|
||||
|
@ -959,7 +1047,7 @@ void dvr_event_updated ( epg_broadcast_t *e )
|
|||
e->start, e->stop);
|
||||
e->getref(e);
|
||||
de->de_bcast = e;
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
_dvr_entry_update(de, e, NULL, NULL, NULL, NULL, 0, 0, 0, 0, DVR_PRIO_NOTSET, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1020,6 +1108,12 @@ dvr_timer_start_recording(void *aux)
|
|||
return;
|
||||
}
|
||||
|
||||
// if duplicate, then delete it now, don't record!
|
||||
if (_dvr_duplicate_event(de)) {
|
||||
dvr_entry_cancel_delete(de);
|
||||
return;
|
||||
}
|
||||
|
||||
de->de_sched_state = DVR_RECORDING;
|
||||
de->de_rec_state = DVR_RS_PENDING;
|
||||
|
||||
|
@ -1539,13 +1633,46 @@ dvr_entry_class_disp_title_get(void *o)
|
|||
return &s;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dvr_entry_class_disp_subtitle_set(void *o, const void *v)
|
||||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
const char *s = "";
|
||||
if (v == NULL || *((char *)v) == '\0')
|
||||
v = "UnknownSubtitle";
|
||||
if (de->de_subtitle)
|
||||
s = lang_str_get(de->de_subtitle, NULL);
|
||||
if (strcmp(s, v)) {
|
||||
lang_str_destroy(de->de_subtitle);
|
||||
de->de_subtitle = lang_str_create();
|
||||
lang_str_add(de->de_subtitle, v, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const void *
|
||||
dvr_entry_class_disp_subtitle_get(void *o)
|
||||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
static const char *s;
|
||||
s = "";
|
||||
if (de->de_subtitle) {
|
||||
s = lang_str_get(de->de_subtitle, NULL);
|
||||
if (s == NULL)
|
||||
s = "";
|
||||
}
|
||||
return &s;
|
||||
}
|
||||
|
||||
static const void *
|
||||
dvr_entry_class_disp_description_get(void *o)
|
||||
{
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
static const char *s;
|
||||
s = "";
|
||||
if (de->de_title) {
|
||||
if (de->de_desc) {
|
||||
s = lang_str_get(de->de_desc, NULL);
|
||||
if (s == NULL)
|
||||
s = "";
|
||||
|
@ -1654,6 +1781,16 @@ dvr_entry_class_channel_icon_url_get(void *o)
|
|||
return &s;
|
||||
}
|
||||
|
||||
static const void *
|
||||
dvr_entry_class_duplicate_get(void *o)
|
||||
{
|
||||
static time_t null = 0;
|
||||
dvr_entry_t *de = (dvr_entry_t *)o;
|
||||
de = _dvr_duplicate_event(de);
|
||||
return de ? &de->de_start : &null;
|
||||
}
|
||||
|
||||
|
||||
htsmsg_t *
|
||||
dvr_entry_class_duration_list(void *o, const char *not_set, int max, int step)
|
||||
{
|
||||
|
@ -1803,6 +1940,21 @@ const idclass_t dvr_entry_class = {
|
|||
.set = dvr_entry_class_disp_title_set,
|
||||
.opts = PO_NOSAVE,
|
||||
},
|
||||
{
|
||||
.type = PT_LANGSTR,
|
||||
.id = "subtitle",
|
||||
.name = "Subtitle",
|
||||
.off = offsetof(dvr_entry_t, de_subtitle),
|
||||
.opts = PO_RDONLY,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "disp_subtitle",
|
||||
.name = "Subtitle",
|
||||
.get = dvr_entry_class_disp_subtitle_get,
|
||||
.set = dvr_entry_class_disp_subtitle_set,
|
||||
.opts = PO_NOSAVE,
|
||||
},
|
||||
{
|
||||
.type = PT_LANGSTR,
|
||||
.id = "description",
|
||||
|
@ -1984,6 +2136,13 @@ const idclass_t dvr_entry_class = {
|
|||
.get = dvr_entry_class_sched_status_get,
|
||||
.opts = PO_RDONLY | PO_NOSAVE | PO_HIDDEN,
|
||||
},
|
||||
{
|
||||
.type = PT_TIME,
|
||||
.id = "duplicate",
|
||||
.name = "Rerun of",
|
||||
.get = dvr_entry_class_duplicate_get,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "comment",
|
||||
|
@ -2038,7 +2197,7 @@ static struct strtab priotab[] = {
|
|||
{ "high", DVR_PRIO_HIGH },
|
||||
{ "normal", DVR_PRIO_NORMAL },
|
||||
{ "low", DVR_PRIO_LOW },
|
||||
{ "unimportant", DVR_PRIO_UNIMPORTANT },
|
||||
{ "unimportant", DVR_PRIO_UNIMPORTANT }
|
||||
};
|
||||
|
||||
dvr_prio_t
|
||||
|
|
|
@ -155,7 +155,7 @@ dvr_timerec_check(dvr_timerec_entry_t *dte)
|
|||
dte->dte_creator ?: "");
|
||||
de = dvr_entry_create_(idnode_uuid_as_str(&dte->dte_config->dvr_id),
|
||||
NULL, dte->dte_channel,
|
||||
start, stop, 0, 0, title,
|
||||
start, stop, 0, 0, title, NULL,
|
||||
NULL, NULL, NULL, dte->dte_owner, buf,
|
||||
NULL, dte, dte->dte_pri, dte->dte_retention,
|
||||
dte->dte_comment);
|
||||
|
|
|
@ -1289,7 +1289,7 @@ const char *epg_episode_get_subtitle
|
|||
return lang_str_get(e->subtitle, lang);
|
||||
}
|
||||
|
||||
const char *epg_episode_get_summary
|
||||
const char *epg_episode_get_summary
|
||||
( const epg_episode_t *e, const char *lang )
|
||||
{
|
||||
if (!e || !e->summary) return NULL;
|
||||
|
|
|
@ -290,6 +290,8 @@ const char *epg_episode_get_title
|
|||
( const epg_episode_t *e, const char *lang );
|
||||
const char *epg_episode_get_subtitle
|
||||
( const epg_episode_t *e, const char *lang );
|
||||
lang_str_t *epg_episode_get_subtitle2
|
||||
( const epg_episode_t *e );
|
||||
const char *epg_episode_get_summary
|
||||
( const epg_episode_t *e, const char *lang );
|
||||
const char *epg_episode_get_description
|
||||
|
@ -511,6 +513,8 @@ const char *epg_broadcast_get_title
|
|||
( epg_broadcast_t *b, const char *lang );
|
||||
const char *epg_broadcast_get_subtitle
|
||||
( epg_broadcast_t *b, const char *lang );
|
||||
lang_str_t *epg_broadcast_get_subtitle2
|
||||
( epg_broadcast_t *b );
|
||||
const char *epg_broadcast_get_summary
|
||||
( epg_broadcast_t *b, const char *lang );
|
||||
const char *epg_broadcast_get_description
|
||||
|
|
|
@ -1413,7 +1413,7 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
epg_broadcast_t *e = NULL;
|
||||
dvr_entry_t *de;
|
||||
dvr_entry_sched_state_t dvr_status;
|
||||
const char *dvr_config_name, *title, *desc, *creator, *lang, *comment;
|
||||
const char *dvr_config_name, *title, *desc, *subtitle, *creator, *lang, *comment;
|
||||
int64_t start, stop, start_extra, stop_extra;
|
||||
uint32_t u32, priority, retention;
|
||||
channel_t *ch = NULL;
|
||||
|
@ -1454,6 +1454,10 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
!(title = htsmsg_get_str(in, "title")))
|
||||
return htsp_error("Invalid arguments");
|
||||
|
||||
/* Optional attributes */
|
||||
if (!(subtitle = htsmsg_get_str(in, "subtitle")))
|
||||
subtitle = "";
|
||||
|
||||
/* Optional attributes */
|
||||
if (!(desc = htsmsg_get_str(in, "description")))
|
||||
desc = "";
|
||||
|
@ -1461,7 +1465,7 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
// create the dvr entry
|
||||
de = dvr_entry_create_htsp(dvr_config_name, ch, start, stop,
|
||||
start_extra, stop_extra,
|
||||
title, desc, lang, 0,
|
||||
title, subtitle, desc, lang, 0,
|
||||
htsp->htsp_granted_access->aa_username,
|
||||
creator, NULL,
|
||||
priority, retention, comment);
|
||||
|
@ -1506,7 +1510,7 @@ htsp_method_updateDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
uint32_t dvrEntryId;
|
||||
dvr_entry_t *de;
|
||||
time_t start, stop, start_extra, stop_extra, priority, retention;
|
||||
const char *title, *desc, *lang;
|
||||
const char *title, *subtitle, *desc, *lang;
|
||||
|
||||
if(htsmsg_get_u32(in, "id", &dvrEntryId))
|
||||
return htsp_error("Missing argument 'id'");
|
||||
|
@ -1528,11 +1532,12 @@ htsp_method_updateDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
retention = htsmsg_get_u32_or_default(in, "retention", 0);
|
||||
priority = htsmsg_get_u32_or_default(in, "priority", DVR_PRIO_NORMAL);
|
||||
title = htsmsg_get_str(in, "title");
|
||||
subtitle = htsmsg_get_str(in, "title");
|
||||
desc = htsmsg_get_str(in, "description");
|
||||
lang = htsmsg_get_str(in, "language");
|
||||
if (!lang) lang = htsp->htsp_language;
|
||||
|
||||
de = dvr_entry_update(de, title, desc, lang, start, stop,
|
||||
de = dvr_entry_update(de, title, subtitle, desc, lang, start, stop,
|
||||
start_extra, stop_extra, priority, retention);
|
||||
|
||||
//create response
|
||||
|
|
|
@ -799,7 +799,7 @@ main(int argc, char **argv)
|
|||
OPENSSL_config(NULL);
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
|
||||
/* Initialise configuration */
|
||||
uuid_init();
|
||||
idnode_init();
|
||||
|
|
|
@ -11,14 +11,15 @@ tvheadend.dvrDetails = function(uuid) {
|
|||
var params = d[0].params;
|
||||
var chicon = params[0].value;
|
||||
var title = params[1].value;
|
||||
var episode = params[2].value;
|
||||
var start_real = params[3].value;
|
||||
var stop_real = params[4].value;
|
||||
var duration = params[5].value;
|
||||
var desc = params[6].value;
|
||||
var status = params[7].value;
|
||||
var filesize = params[8].value;
|
||||
var comment = params[9].value;
|
||||
var subtitle = params[2].value;
|
||||
var episode = params[3].value;
|
||||
var start_real = params[4].value;
|
||||
var stop_real = params[5].value;
|
||||
var duration = params[6].value;
|
||||
var desc = params[7].value;
|
||||
var status = params[8].value;
|
||||
var filesize = params[9].value;
|
||||
var comment = params[10].value;
|
||||
var content = '';
|
||||
var but;
|
||||
|
||||
|
@ -27,6 +28,8 @@ tvheadend.dvrDetails = function(uuid) {
|
|||
|
||||
if (title)
|
||||
content += '<div class="x-epg-title">' + title + '</div>';
|
||||
if (subtitle)
|
||||
content += '<div class="x-epg-title">' + subtitle + '</div>';
|
||||
if (episode)
|
||||
content += '<div class="x-epg-title">' + episode + '</div>';
|
||||
if (start_real)
|
||||
|
@ -64,7 +67,7 @@ tvheadend.dvrDetails = function(uuid) {
|
|||
url: 'api/idnode/load',
|
||||
params: {
|
||||
uuid: uuid,
|
||||
list: 'channel_icon,disp_title,episode,start_real,stop_real,' +
|
||||
list: 'channel_icon,disp_title,disp_subtitle,episode,start_real,stop_real,' +
|
||||
'duration,disp_description,status,filesize,comment'
|
||||
},
|
||||
success: function(d) {
|
||||
|
@ -214,7 +217,7 @@ tvheadend.dvr_upcoming = function(panel, index) {
|
|||
}
|
||||
},
|
||||
del: true,
|
||||
list: 'disp_title,episode,pri,start_real,stop_real,' +
|
||||
list: 'duplicate,disp_title,disp_subtitle,episode,pri,start_real,stop_real,' +
|
||||
'duration,filesize,channel,owner,creator,config_name,' +
|
||||
'sched_status,errors,data_errors,comment',
|
||||
columns: {
|
||||
|
@ -282,7 +285,7 @@ tvheadend.dvr_finished = function(panel, index) {
|
|||
del: true,
|
||||
delquestion: 'Do you really want to delete the selected recordings?<br/><br/>' +
|
||||
'The associated file will be removed from the storage.',
|
||||
list: 'disp_title,episode,start_real,stop_real,' +
|
||||
list: 'disp_title,disp_subtitle,episode,start_real,stop_real,' +
|
||||
'duration,filesize,channelname,owner,creator,' +
|
||||
'config_name,sched_status,errors,data_errors,url,comment',
|
||||
columns: {
|
||||
|
@ -362,7 +365,7 @@ tvheadend.dvr_failed = function(panel, index) {
|
|||
del: true,
|
||||
delquestion: 'Do you really want to delete the selected recordings?<br/><br/>' +
|
||||
'The associated file will be removed from the storage.',
|
||||
list: 'disp_title,episode,start_real,stop_real,' +
|
||||
list: 'disp_title,disp_subtitle,episode,start_real,stop_real,' +
|
||||
'duration,filesize,channelname,owner,creator,config_name,' +
|
||||
'status,sched_status,errors,data_errors,url,comment',
|
||||
columns: {
|
||||
|
@ -457,6 +460,7 @@ tvheadend.autorec_editor = function(panel, index) {
|
|||
renderer: function(st) { return tvheadend.weekdaysRenderer(st); }
|
||||
},
|
||||
pri: { width: 80 },
|
||||
dedup: { width: 160 },
|
||||
retention: { width: 80 },
|
||||
config_name: { width: 120 },
|
||||
owner: { width: 100 },
|
||||
|
@ -467,13 +471,13 @@ tvheadend.autorec_editor = function(panel, index) {
|
|||
url: 'api/dvr/autorec',
|
||||
params: {
|
||||
list: 'enabled,name,directory,title,fulltext,channel,tag,content_type,minduration,' +
|
||||
'maxduration,weekdays,start,start_window,pri,config_name,comment'
|
||||
'maxduration,weekdays,start,start_window,pri,dedup,config_name,comment'
|
||||
},
|
||||
create: { }
|
||||
},
|
||||
del: true,
|
||||
list: 'enabled,name,directory,title,fulltext,channel,tag,content_type,minduration,' +
|
||||
'maxduration,weekdays,start,start_window,pri,config_name,owner,creator,comment',
|
||||
'maxduration,weekdays,start,start_window,pri,dedup,config_name,owner,creator,comment',
|
||||
sort: {
|
||||
field: 'name',
|
||||
direction: 'ASC'
|
||||
|
|
Loading…
Add table
Reference in a new issue