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;
epg_brand_t *dae_brand;
epg_season_t *dae_season;
+ epg_episode_num_t dae_epnum;
} dvr_autorec_entry_t;
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;
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);
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 */
( 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);
}
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);
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 )
* 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
{
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