diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index bcd61a23..70a807b4 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -35,6 +35,15 @@ typedef struct dvr_config { int dvr_extra_time_pre; int dvr_extra_time_post; + /* + * Series link support + */ + int dvr_sl_brand_lock; + int dvr_sl_season_lock; + int dvr_sl_channel_lock; + int dvr_sl_time_lock; + int dvr_sl_more_recent; + LIST_ENTRY(dvr_config) config_link; } dvr_config_t; @@ -212,6 +221,7 @@ typedef struct dvr_autorec_entry { epg_brand_t *dae_brand; epg_season_t *dae_season; + epg_episode_num_t dae_epnum; } dvr_autorec_entry_t; diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 2f37f28c..b026ab3b 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -473,6 +473,7 @@ _dvr_autorec_add(const char *config_name, const char *title, channel_t *ch, const char *tag, uint8_t content_type, epg_brand_t *brand, epg_season_t *season, + int approx_time, epg_episode_num_t *epnum, const char *creator, const char *comment) { dvr_autorec_entry_t *dae; @@ -513,6 +514,11 @@ _dvr_autorec_add(const char *config_name, dae->dae_season = season; season->getref((epg_object_t*)season); } + if(epnum) { + dae->dae_epnum = *epnum; + } + + dae->dae_approx_time = approx_time; m = autorec_record_build(dae); hts_settings_save(m, "%s/%s", "autorec", dae->dae_id); @@ -536,7 +542,7 @@ dvr_autorec_add(const char *config_name, channel_t *ch = NULL; if(channel != NULL) ch = channel_find_by_name(channel, 0, 0); _dvr_autorec_add(config_name, title, ch, tag, content_type, - NULL, NULL, creator, comment); + NULL, NULL, 0, NULL, creator, comment); } /* TODO: configurable brand/series selection */ @@ -544,11 +550,29 @@ void dvr_autorec_add_series_link ( const char *dvr_config_name, epg_broadcast_t *event, const char *creator, const char *comment ) { + int atime = 0; + dvr_config_t *cfg; + epg_episode_t *ee; + epg_episode_num_t *epnump = NULL, epnum; if (!event || !event->episode) return; + + ee = event->episode; + cfg = dvr_config_find_by_name_default(dvr_config_name); + if (cfg->dvr_sl_time_lock) { + struct tm t; + localtime_r(&event->start, &t); + atime = (t.tm_hour * 60) + t.tm_min; + } + if (cfg->dvr_sl_more_recent) { + epg_episode_number_full(ee, &epnum); + epnump = &epnum; + } _dvr_autorec_add(dvr_config_name, event->episode->title, - event->channel, NULL, 0, - event->episode->brand, - event->episode->season, + cfg->dvr_sl_channel_lock ? event->channel : NULL, + NULL, 0, // tag/content type + cfg->dvr_sl_brand_lock ? ee->brand : NULL, + cfg->dvr_sl_season_lock || !ee->brand ? ee->season : NULL, + atime, epnump, creator, comment); } diff --git a/src/dvr/dvr_db.c b/src/dvr/dvr_db.c index 569940bf..e79fa803 100644 --- a/src/dvr/dvr_db.c +++ b/src/dvr/dvr_db.c @@ -1035,6 +1035,13 @@ dvr_config_create(const char *name) cfg->dvr_file_postfix = strdup("mkv"); cfg->dvr_flags = DVR_TAG_FILES; + /* series link support */ + cfg->dvr_sl_brand_lock = 1; // use brand linking + cfg->dvr_sl_season_lock = 0; // ignore season (except if no brand) + cfg->dvr_sl_channel_lock = 1; // channel locked + cfg->dvr_sl_time_lock = 0; // time slot (approx) locked + cfg->dvr_sl_more_recent = 1; // Only record more reason episodes + LIST_INSERT_HEAD(&dvrconfigs, cfg, config_link); return LIST_FIRST(&dvrconfigs); diff --git a/src/epg.c b/src/epg.c index badf017e..d51ab3ed 100644 --- a/src/epg.c +++ b/src/epg.c @@ -939,22 +939,38 @@ size_t epg_episode_number_format const char *cfmt ) { size_t i = 0; - if ( episode->number ) { + epg_episode_num_t num; + epg_episode_number_full(episode, &num); + if ( num.e_num ) { if (pre) i += snprintf(&buf[i], len-i, "%s", pre); - if ( sfmt && episode->season && episode->season->number ) { - i += snprintf(&buf[i], len-i, sfmt, episode->season->number); - if ( cfmt && episode->brand && episode->brand->season_count ) - i += snprintf(&buf[i], len-i, cfmt, - episode->brand->season_count); + if ( sfmt && num.s_num ) { + i += snprintf(&buf[i], len-i, sfmt, num.s_num); + if ( cfmt && num.s_cnt ) + i += snprintf(&buf[i], len-i, cfmt, num.s_cnt); if (sep) i += snprintf(&buf[i], len-i, "%s", sep); } - i += snprintf(&buf[i], len-i, efmt, episode->number); - if ( cfmt && episode->season && episode->season->episode_count) - i+= snprintf(&buf[i], len-i, cfmt, episode->season->episode_count); + i += snprintf(&buf[i], len-i, efmt, num.e_num); + if ( cfmt && num.e_cnt ) + i+= snprintf(&buf[i], len-i, cfmt, num.e_cnt); } return i; } +void epg_episode_number_full ( epg_episode_t *ee, epg_episode_num_t *num ) +{ + if (!ee || !num) return; + num->e_num = ee->number; + num->p_num = ee->part_number; + num->p_cnt = ee->part_count; + if (ee->season) { + num->e_cnt = ee->season->episode_count; + num->s_num = ee->season->number; + } + if (ee->brand) { + num->s_cnt = ee->brand->season_count; + } +} + int epg_episode_fuzzy_match ( epg_episode_t *episode, const char *uri, const char *title, const char *summary, const char *description ) diff --git a/src/epg.h b/src/epg.h index d617436a..d2613a32 100644 --- a/src/epg.h +++ b/src/epg.h @@ -176,6 +176,19 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save ); * Episode * ***********************************************************************/ +/* Episode numbering object - this is for some back-compat and also + * to allow episode information to be "collated" into easy to use object + */ +typedef struct epg_episode_num +{ + uint16_t s_num; ///< Series number + uint16_t s_cnt; ///< Series count + uint16_t e_num; ///< Episode number + uint16_t e_cnt; ///< Episode count + uint16_t p_num; ///< Part number + uint16_t p_cnt; ///< Part count +} epg_episode_num_t; + /* Object */ struct epg_episode { @@ -247,6 +260,8 @@ size_t epg_episode_number_format const char *pre, const char *sfmt, const char *sep, const char *efmt, const char *cfmt ); +void epg_episode_number_full + ( epg_episode_t *e, epg_episode_num_t *epnum ); /* Matching */ int epg_episode_fuzzy_match