diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 1290e20c..237f9128 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -137,7 +137,7 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e) // Note: dae_epnum is unset then all values are 0 and this will // always return 1 - epg_episode_number_full(e->episode, &epnum); + epg_episode_get_epnum(e->episode, &epnum); if(epg_episode_number_cmp(&dae->dae_epnum, &epnum) < 0) return 0; @@ -580,7 +580,7 @@ void dvr_autorec_add_series_link atime = (t.tm_hour * 60) + t.tm_min; } if (cfg->dvr_sl_more_recent) { - epg_episode_number_full(ee, &epnum); + epg_episode_get_epnum(ee, &epnum); epnump = &epnum; } _dvr_autorec_add(dvr_config_name, event->episode->title, diff --git a/src/dvr/mkmux.c b/src/dvr/mkmux.c index faaa7477..37fbc750 100644 --- a/src/dvr/mkmux.c +++ b/src/dvr/mkmux.c @@ -501,12 +501,6 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc) if(ch) addtag(q, build_tag_string("TVCHANNEL", ch->ch_name, 0, NULL)); -#if TODO_EP_NUMBER_ONSCREEN - if(ee && ee->onscreen) - addtag(q, build_tag_string("SYNOPSIS", - ee->onscreen, 0, NULL)); -#endif - if(de && de->de_desc) addtag(q, build_tag_string("SUMMARY", de->de_desc, 0, NULL)); else if (ee && ee->description) @@ -515,15 +509,20 @@ _mk_build_metadata(const dvr_entry_t *de, const epg_broadcast_t *ebc) addtag(q, build_tag_string("SUMMARY", ee->summary, 0, NULL)); if (ee) { - if(ee->number) - addtag(q, build_tag_int("PART_NUMBER", ee->number, + epg_episode_num_t num; + epg_episode_get_epnum(ee, &num); + if(num.e_num) + addtag(q, build_tag_int("PART_NUMBER", num.e_num, 0, NULL)); - if(ee->season && ee->season->number) - addtag(q, build_tag_int("PART_NUMBER", ee->season->number, + if(num.s_num) + addtag(q, build_tag_int("PART_NUMBER", num.s_num, 60, "SEASON")); - if(ee->part_number) - addtag(q, build_tag_int("PART_NUMBER", ee->part_number, + if(num.p_num) + addtag(q, build_tag_int("PART_NUMBER", num.p_num, 40, "PART")); + if (num.text) + addtag(q, build_tag_string("SYNOPSIS", + num.text, 0, NULL)); } return q; diff --git a/src/epg.c b/src/epg.c index 7f1fec79..f62390ab 100644 --- a/src/epg.c +++ b/src/epg.c @@ -80,16 +80,23 @@ static int _season_order ( const void *_a, const void *_b ) return a->number - b->number; } +// Note: this will do nothing with text episode numbering static int _episode_order ( const void *_a, const void *_b ) { - int r; + int r, as, bs; const epg_episode_t *a = (const epg_episode_t*)_a; const epg_episode_t *b = (const epg_episode_t*)_b; - r = _season_order(a->season, b->season); + if (!a) return -1; + if (!b) return 1; + if (a->season) as = a->season->number; + else as = a->epnum.s_num; + if (b->season) bs = b->season->number; + else bs = b->epnum.s_num; + r = as - bs; if (r) return r; - if (!a || !a->number) return 1; - if (!b || !b->number) return -1; - return a->number - b->number; + r = a->epnum.e_num - b->epnum.e_num; + if (r) return r; + return a->epnum.p_num - b->epnum.p_num; } /* ************************************************************************** @@ -817,6 +824,53 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save ) * Episode * *************************************************************************/ +static htsmsg_t *epg_episode_num_serialize ( epg_episode_num_t *num ) +{ + htsmsg_t *m; + if (!num) return NULL; + m = htsmsg_create_map(); + if (num->e_num) + htsmsg_add_u32(m, "e_num", num->e_num); + if (num->e_cnt) + htsmsg_add_u32(m, "e_cnt", num->e_cnt); + if (num->s_num) + htsmsg_add_u32(m, "s_num", num->e_num); + if (num->s_cnt) + htsmsg_add_u32(m, "s_cnt", num->e_cnt); + if (num->p_num) + htsmsg_add_u32(m, "p_num", num->e_num); + if (num->p_cnt) + htsmsg_add_u32(m, "p_cnt", num->e_cnt); + if (num->text) + htsmsg_add_str(m, "text", num->text); + return m; +} + +static epg_episode_num_t *epg_episode_num_deserialize + ( htsmsg_t *m, epg_episode_num_t *num ) +{ + const char *str; + uint32_t u32; + if (!m) return NULL; + if (!num) num = calloc(1, sizeof(epg_episode_num_t)); + if (!htsmsg_get_u32(m, "e_num", &u32)) + num->e_num = u32; + if (!htsmsg_get_u32(m, "e_cnt", &u32)) + num->e_cnt = u32; + if (!htsmsg_get_u32(m, "s_num", &u32)) + num->s_num = u32; + if (!htsmsg_get_u32(m, "s_cnt", &u32)) + num->s_cnt = u32; + if (!htsmsg_get_u32(m, "p_num", &u32)) + num->p_num = u32; + if (!htsmsg_get_u32(m, "p_cnt", &u32)) + num->p_cnt = u32; + if ((str = htsmsg_get_str(m, "text"))) + num->text = strdup(str); + + return num; +} + static void _epg_episode_destroy ( epg_object_t *eo ) { epg_episode_t *ee = (epg_episode_t*)eo; @@ -839,6 +893,7 @@ static void _epg_episode_destroy ( epg_object_t *eo ) if (ee->description) free(ee->description); if (ee->genre) free(ee->genre); if (ee->image) free(ee->image); + if (ee->epnum.text) free(ee->epnum.text); free(ee); } @@ -901,8 +956,8 @@ int epg_episode_set_number ( epg_episode_t *episode, uint16_t number ) { int save = 0; if ( !episode || !number ) return 0; - if ( episode->number != number ) { - episode->number = number; + if ( episode->epnum.e_num != number ) { + episode->epnum.e_num = number; _epg_object_set_updated((epg_object_t*)episode); save = 1; } @@ -913,19 +968,40 @@ int epg_episode_set_part ( epg_episode_t *episode, uint16_t part, uint16_t count { int save = 0; if ( !episode || !part ) return 0; - if ( episode->part_number != part ) { - episode->part_number = part; + if ( episode->epnum.p_num != part ) { + episode->epnum.p_num = part; _epg_object_set_updated((epg_object_t*)episode); save = 1; } - if ( count && episode->part_count != count ) { - episode->part_count = count; + if ( count && episode->epnum.p_cnt != count ) { + episode->epnum.p_cnt = count; _epg_object_set_updated((epg_object_t*)episode); save = 1; } return save; } +int epg_episode_set_epnum ( epg_episode_t *episode, epg_episode_num_t *num ) +{ + int save = 0; + if (!episode || !num || (!num->e_num && !num->text)) return 0; + if ( episode->epnum.e_num != num->e_num ) save = 1; + else if ( episode->epnum.e_cnt != num->e_cnt ) save = 1; + else if ( episode->epnum.s_num != num->s_num ) save = 1; + else if ( episode->epnum.s_cnt != num->s_cnt ) save = 1; + else if ( episode->epnum.p_num != num->p_num ) save = 1; + else if ( episode->epnum.p_cnt != num->p_cnt ) save = 1; + else if ( !episode->epnum.text || + (num->text && strcmp(num->text, episode->epnum.text)) ) save = 1; + if (save) { + if (episode->epnum.text) free(episode->epnum.text); + episode->epnum = *num; + if (episode->epnum.text) strdup(episode->epnum.text); + save = 1; + } + return save; +} + int epg_episode_set_brand ( epg_episode_t *episode, epg_brand_t *brand ) { int save = 0; @@ -1030,7 +1106,7 @@ size_t epg_episode_number_format size_t i = 0; if (!episode) return 0; epg_episode_num_t num; - epg_episode_number_full(episode, &num); + epg_episode_get_epnum(episode, &num); if ( num.e_num ) { if (pre) i += snprintf(&buf[i], len-i, "%s", pre); if ( sfmt && num.s_num ) { @@ -1042,17 +1118,17 @@ size_t epg_episode_number_format 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); + } else if ( num.text ) { + strncpy(buf, num.text, len); + i = MAX(strlen(num.text), len); } return i; } -void epg_episode_number_full ( epg_episode_t *ee, epg_episode_num_t *num ) +void epg_episode_get_epnum ( epg_episode_t *ee, epg_episode_num_t *num ) { if (!ee || !num) return; - memset(num, 0, sizeof(epg_episode_num_t)); - num->e_num = ee->number; - num->p_num = ee->part_number; - num->p_cnt = ee->part_count; + *num = ee->epnum; if (ee->season) { num->e_cnt = ee->season->episode_count; num->s_num = ee->season->number; @@ -1102,12 +1178,7 @@ htsmsg_t *epg_episode_serialize ( epg_episode_t *episode ) htsmsg_add_str(m, "summary", episode->summary); if (episode->description) htsmsg_add_str(m, "description", episode->description); - if (episode->number) - htsmsg_add_u32(m, "number", episode->number); - if (episode->part_count && episode->part_count) { - htsmsg_add_u32(m, "part-number", episode->part_number); - htsmsg_add_u32(m, "part-count", episode->part_count); - } + htsmsg_add_msg(m, "epnum", epg_episode_num_serialize(&episode->epnum)); if (episode->brand) htsmsg_add_str(m, "brand", episode->brand->uri); if (episode->season) @@ -1123,6 +1194,8 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save ) epg_brand_t *eb; uint32_t u32, u32a; const char *str; + epg_episode_num_t num; + htsmsg_t *sub; if ( !_epg_object_deserialize(m, *skel) ) return NULL; if ( !(ee = epg_episode_find_by_uri((*skel)->uri, create, save)) ) return NULL; @@ -1135,6 +1208,12 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save ) *save |= epg_episode_set_summary(ee, str); if ( (str = htsmsg_get_str(m, "description")) ) *save |= epg_episode_set_description(ee, str); + if ( (sub = htsmsg_get_map(m, "epnum")) ) { + epg_episode_num_deserialize(sub, &num); + *save |= epg_episode_set_epnum(ee, &num); + if (num.text) free(num.text); + } + // Note: retained for compat if ( !htsmsg_get_u32(m, "number", &u32) ) *save |= epg_episode_set_number(ee, u32); if ( !htsmsg_get_u32(m, "part-number", &u32) && diff --git a/src/epg.h b/src/epg.h index 2714d344..a978067c 100644 --- a/src/epg.h +++ b/src/epg.h @@ -181,12 +181,13 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save ); */ 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 + 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 + char *text; ///< Arbitary text description of episode num } epg_episode_num_t; /* Object */ @@ -200,9 +201,8 @@ struct epg_episode char *description; ///< An extended description uint8_t *genre; ///< Episode genre(s) int genre_cnt; ///< Genre count - uint16_t number; ///< The episode number - uint16_t part_number; ///< For multipart episodes - uint16_t part_count; ///< For multipart episodes + epg_episode_num_t epnum; ///< Episode numbering + // Note: do not use epnum directly! use the accessor routine char *image; ///< Episode image // TODO: certification and rating @@ -231,11 +231,11 @@ int epg_episode_set_description ( epg_episode_t *e, const char *description ) __attribute__((warn_unused_result)); int epg_episode_set_number ( epg_episode_t *e, uint16_t number ) __attribute__((warn_unused_result)); -int epg_episode_set_onscreen ( epg_episode_t *e, const char *onscreen ) - __attribute__((warn_unused_result)); int epg_episode_set_part ( epg_episode_t *e, uint16_t number, uint16_t count ) __attribute__((warn_unused_result)); +int epg_episode_set_epnum ( epg_episode_t *e, epg_episode_num_t *num ) + __attribute__((warn_unused_result)); int epg_episode_set_brand ( epg_episode_t *e, epg_brand_t *b ) __attribute__((warn_unused_result)); int epg_episode_set_season ( epg_episode_t *e, epg_season_t *s ) @@ -247,6 +247,9 @@ int epg_episode_set_genre_str ( epg_episode_t *e, const char **s ) int epg_episode_set_image ( epg_episode_t *e, const char *i ) __attribute__((warn_unused_result)); +// Note: this does NOT strdup the text field +void epg_episode_get_epnum + ( epg_episode_t *e, epg_episode_num_t *epnum ); /* EpNum format helper */ // output string will be: // if (episode_num) @@ -262,8 +265,6 @@ 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 ); int epg_episode_number_cmp ( epg_episode_num_t *a, epg_episode_num_t *b );