diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 909f482f..0cfe6db7 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -345,6 +345,7 @@ void dvr_autorec_add_series_link(const char *dvr_config_name, void dvr_autorec_check_event(epg_broadcast_t *e); void dvr_autorec_check_brand(epg_brand_t *b); void dvr_autorec_check_season(epg_season_t *s); +void dvr_autorec_check_serieslink(epg_serieslink_t *s); void autorec_destroy_by_channel(channel_t *ch); diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index d439c273..e414da85 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -604,6 +604,11 @@ void dvr_autorec_check_season(epg_season_t *s) // this will already have been picked up by the check_event call } +void dvr_autorec_check_serieslink(epg_serieslink_t *s) +{ +// TODO: need to implement this +} + /** * */ diff --git a/src/epg.c b/src/epg.c index 2c554b44..4814dc87 100644 --- a/src/epg.c +++ b/src/epg.c @@ -41,6 +41,7 @@ epg_object_tree_t epg_brands; epg_object_tree_t epg_seasons; epg_object_tree_t epg_episodes; +epg_object_tree_t epg_serieslinks; /* Other special case lists */ epg_object_list_t epg_objects[EPG_HASH_WIDTH]; @@ -299,6 +300,17 @@ static int _epg_object_set_lang_str return save; } +static int _epg_object_set_lang_str2 + ( void *o, lang_str_t **old, const lang_str_t *str, epggrab_module_t *src ) +{ + int save = 0; + lang_str_ele_t *ls; + RB_FOREACH(ls, str, link) { + save |= _epg_object_set_lang_str(o, old, ls->str, ls->lang, src); + } + return save; +} + static int _epg_object_set_u8 ( void *o, uint8_t *old, const uint8_t new, epggrab_module_t *src ) { @@ -781,10 +793,17 @@ int epg_episode_set_title ( epg_episode_t *episode, const char *title, const char *lang, epggrab_module_t *src ) { - if (!episode || !title || !*title) return 0; + if (!episode) return 0; return _epg_object_set_lang_str(episode, &episode->title, title, lang, src); } +int epg_episode_set_title2 + ( epg_episode_t *episode, const lang_str_t *str, epggrab_module_t *src ) +{ + if (!episode) return 0; + return _epg_object_set_lang_str2(episode, &episode->title, str, src); +} + int epg_episode_set_subtitle ( epg_episode_t *episode, const char *subtitle, const char *lang, epggrab_module_t *src ) @@ -794,6 +813,13 @@ int epg_episode_set_subtitle subtitle, lang, src); } +int epg_episode_set_subtitle2 + ( epg_episode_t *episode, const lang_str_t *str, epggrab_module_t *src ) +{ + if (!episode) return 0; + return _epg_object_set_lang_str2(episode, &episode->subtitle, str, src); +} + int epg_episode_set_summary ( epg_episode_t *episode, const char *summary, const char *lang, epggrab_module_t *src ) @@ -1141,6 +1167,89 @@ const char *epg_episode_get_description return lang_str_get(e->description, lang); } +/* ************************************************************************** + * Series link + * *************************************************************************/ + +static void _epg_serieslink_destroy ( void *eo ) +{ + epg_serieslink_t *es = (epg_serieslink_t*)eo; + if (LIST_FIRST(&es->broadcasts)) { + tvhlog(LOG_CRIT, "epg", "attempt to destory series link with broadcasts"); + assert(0); + } + _epg_object_destroy(eo, &epg_serieslinks); + free(es); +} + +static void _epg_serieslink_updated ( void *eo ) +{ + dvr_autorec_check_serieslink((epg_serieslink_t*)eo); +} + +static epg_object_t **_epg_serieslink_skel ( void ) +{ + static epg_object_t *skel = NULL; + if ( !skel ) { + skel = calloc(1, sizeof(epg_serieslink_t)); + skel->type = EPG_SERIESLINK; + skel->destroy = _epg_serieslink_destroy; + skel->updated = _epg_serieslink_updated; + } + return &skel; +} + +epg_serieslink_t* epg_serieslink_find_by_uri + ( const char *uri, int create, int *save ) +{ + return (epg_serieslink_t*) + _epg_object_find_by_uri(uri, create, save, + &epg_serieslinks, + _epg_serieslink_skel()); +} + +epg_serieslink_t *epg_serieslink_find_by_id ( uint64_t id ) +{ + return (epg_serieslink_t*)_epg_object_find_by_id(id, EPG_SERIESLINK); +} + +static void _epg_serieslink_add_broadcast + ( epg_serieslink_t *esl, epg_broadcast_t *ebc ) +{ + _epg_object_getref(esl); + _epg_object_set_updated(esl); + LIST_INSERT_HEAD(&esl->broadcasts, ebc, sl_link); +} + +static void _epg_serieslink_rem_broadcast + ( epg_serieslink_t *esl, epg_broadcast_t *ebc ) +{ + LIST_REMOVE(ebc, sl_link); + _epg_object_set_updated(esl); + _epg_object_putref(esl); +} + +htsmsg_t *epg_serieslink_serialize ( epg_serieslink_t *esl ) +{ + htsmsg_t *m; + if (!esl || !esl->uri) return NULL; + if (!(m = _epg_object_serialize((epg_object_t*)esl))) return NULL; + return m; +} + +epg_serieslink_t *epg_serieslink_deserialize + ( htsmsg_t *m, int create, int *save ) +{ + epg_object_t **skel = _epg_serieslink_skel(); + epg_serieslink_t *esl; + + if ( !_epg_object_deserialize(m, *skel) ) return NULL; + if ( !(esl = epg_serieslink_find_by_uri((*skel)->uri, create, save)) ) + return NULL; + + return esl; +} + /* ************************************************************************** * Channel * *************************************************************************/ @@ -1371,6 +1480,21 @@ int epg_broadcast_set_episode return save; } +int epg_broadcast_set_serieslink + ( epg_broadcast_t *ebc, epg_serieslink_t *esl, epggrab_module_t *src ) +{ + int save = 0; + if ( !ebc || !esl ) return 0; + if ( !_epg_object_set_grabber(ebc, src) && ebc->serieslink ) return 0; + if ( ebc->serieslink != esl ) { + if ( ebc->serieslink ) _epg_serieslink_rem_broadcast(ebc->serieslink, ebc); + ebc->serieslink = esl; + _epg_serieslink_add_broadcast(esl, ebc); + save = 1; + } + return save; +} + int epg_broadcast_set_is_widescreen ( epg_broadcast_t *b, uint8_t ws, epggrab_module_t *src ) { @@ -1434,12 +1558,75 @@ int epg_broadcast_set_is_repeat return _epg_object_set_u8(b, &b->is_repeat, r, src); } +int epg_broadcast_set_summary + ( epg_broadcast_t *b, const char *str, const char *lang, + epggrab_module_t *src ) +{ + if (!b) return 0; + return _epg_object_set_lang_str(b, &b->summary, str, lang, src); +} + +int epg_broadcast_set_description + ( epg_broadcast_t *b, const char *str, const char *lang, + epggrab_module_t *src ) +{ + if (!b) return 0; + return _epg_object_set_lang_str(b, &b->description, str, lang, src); +} + +int epg_broadcast_set_summary2 + ( epg_broadcast_t *b, const lang_str_t *str, epggrab_module_t *src ) +{ + if (!b) return 0; + return _epg_object_set_lang_str2(b, &b->summary, str, src); +} + +int epg_broadcast_set_description2 + ( epg_broadcast_t *b, const lang_str_t *str, epggrab_module_t *src ) +{ + if (!b) return 0; + return _epg_object_set_lang_str2(b, &b->description, str, src); +} + epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *broadcast ) { if ( !broadcast ) return NULL; return RB_NEXT(broadcast, sched_link); } +epg_episode_t *epg_broadcast_get_episode + ( epg_broadcast_t *ebc, int create, int *save ) +{ + char uri[256]; + epg_episode_t *ee; + if (!ebc) return NULL; + if (ebc->episode) return ebc->episode; + if (!create) return NULL; + snprintf(uri, sizeof(uri)-1, "tvh://channel-%d/bcast-%"PRIu64"/episode", + ebc->channel->ch_id, ebc->id); + if ((ee = epg_episode_find_by_uri(uri, 1, save))) + *save |= epg_broadcast_set_episode(ebc, ee, ebc->grabber); + return ee; +} + +const char *epg_broadcast_get_title ( epg_broadcast_t *b, const char *lang ) +{ + if (!b || !b->episode) return NULL; + return epg_episode_get_title(b->episode, lang); +} + +const char *epg_broadcast_get_summary ( epg_broadcast_t *b, const char *lang ) +{ + if (!b || !b->summary) return NULL; + return lang_str_get(b->summary, lang); +} + +const char *epg_broadcast_get_description ( epg_broadcast_t *b, const char *lang ) +{ + if (!b || !b->description) return NULL; + return lang_str_get(b->description, lang); +} + htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast ) { htsmsg_t *m; @@ -1471,6 +1658,8 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast ) htsmsg_add_u32(m, "is_new", 1); if (broadcast->is_repeat) htsmsg_add_u32(m, "is_repeat", 1); + if (broadcast->serieslink) + htsmsg_add_str(m, "serieslink", broadcast->serieslink->uri); return m; } @@ -1481,6 +1670,7 @@ epg_broadcast_t *epg_broadcast_deserialize channel_t *ch = NULL; epg_broadcast_t *ebc, **skel = _epg_broadcast_skel(); epg_episode_t *ee; + epg_serieslink_t *esl; const char *str; uint32_t chid, eid, start, stop, u32; @@ -1532,6 +1722,11 @@ epg_broadcast_t *epg_broadcast_deserialize if (!htsmsg_get_u32(m, "is_repeat", &u32)) *save |= epg_broadcast_set_is_repeat(ebc, u32, NULL); + /* Series link */ + if ((str = htsmsg_get_str(m, "serieslink"))) + if ((esl = epg_serieslink_find_by_uri(str, 1, save))) + *save |= epg_broadcast_set_serieslink(ebc, esl, NULL); + /* Set the episode */ *save |= epg_broadcast_set_episode(ebc, ee, NULL); diff --git a/src/epg.h b/src/epg.h index 336a0205..6f21c0e7 100644 --- a/src/epg.h +++ b/src/epg.h @@ -32,14 +32,14 @@ struct epggrab_module; /* * Map/List types */ -LIST_HEAD(epg_object_list, epg_object); -RB_HEAD (epg_object_tree, epg_object); -LIST_HEAD(epg_brand_list, epg_brand); -LIST_HEAD(epg_season_list, epg_season); -LIST_HEAD(epg_episode_list, epg_episode); -LIST_HEAD(epg_broadcast_list, epg_broadcast); -RB_HEAD (epg_broadcast_tree, epg_broadcast); -LIST_HEAD(epg_genre_list, epg_genre); +typedef LIST_HEAD(,epg_object) epg_object_list_t; +typedef RB_HEAD (,epg_object) epg_object_tree_t; +typedef LIST_HEAD(,epg_brand) epg_brand_list_t; +typedef LIST_HEAD(,epg_season) epg_season_list_t; +typedef LIST_HEAD(,epg_episode) epg_episode_list_t; +typedef LIST_HEAD(,epg_broadcast) epg_broadcast_list_t; +typedef RB_HEAD (,epg_broadcast) epg_broadcast_tree_t; +typedef LIST_HEAD(,epg_genre) epg_genre_list_t; /* * Typedefs (most are redundant!) @@ -50,13 +50,7 @@ typedef struct epg_brand epg_brand_t; typedef struct epg_season epg_season_t; typedef struct epg_episode epg_episode_t; typedef struct epg_broadcast epg_broadcast_t; -typedef struct epg_season_list epg_season_list_t; -typedef struct epg_episode_list epg_episode_list_t; -typedef struct epg_broadcast_list epg_broadcast_list_t; -typedef struct epg_broadcast_tree epg_broadcast_tree_t; -typedef struct epg_object_list epg_object_list_t; -typedef struct epg_object_tree epg_object_tree_t; -typedef struct epg_genre_list epg_genre_list_t; +typedef struct epg_serieslink epg_serieslink_t; /* ************************************************************************ * Genres @@ -100,7 +94,8 @@ typedef enum epg_object_type EPG_BRAND, EPG_SEASON, EPG_EPISODE, - EPG_BROADCAST + EPG_BROADCAST, + EPG_SERIESLINK } epg_object_type_t; /* Object */ @@ -329,7 +324,13 @@ int epg_episode_set_image ( epg_episode_t *e, const char *i, struct epggrab_module *src ) __attribute__((warn_unused_result)); int epg_episode_set_is_bw - ( epg_episode_t *b, uint8_t bw, struct epggrab_module *src ) + ( epg_episode_t *e, uint8_t bw, struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_episode_set_title2 + ( epg_episode_t *e, const lang_str_t *str, struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_episode_set_subtitle2 + ( epg_episode_t *e, const lang_str_t *str, struct epggrab_module *src ) __attribute__((warn_unused_result)); // Note: this does NOT strdup the text field @@ -362,6 +363,29 @@ int epg_episode_fuzzy_match htsmsg_t *epg_episode_serialize ( epg_episode_t *b ); epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save ); +/* ************************************************************************ + * Series Link - broadcast level linkage + * ***********************************************************************/ + +/* Object */ +struct epg_serieslink +{ + epg_object_t; + + epg_broadcast_list_t broadcasts; ///< Episode list +}; + +/* Lookup */ +epg_serieslink_t *epg_serieslink_find_by_uri + ( const char *uri, int create, int *save ); +epg_serieslink_t *epg_serieslink_find_by_id + ( uint64_t id ); + +/* Serialization */ +htsmsg_t *epg_serieslink_serialize ( epg_serieslink_t *s ); +epg_serieslink_t *epg_serieslink_deserialize + ( htsmsg_t *m, int create, int *save ); + /* ************************************************************************ * Broadcast - specific airing (channel & time) of an episode * ***********************************************************************/ @@ -390,9 +414,15 @@ struct epg_broadcast uint8_t is_new; ///< New series / file premiere uint8_t is_repeat; ///< Repeat screening + /* Broadcast level text */ + lang_str_t *summary; ///< Summary + lang_str_t *description; ///< Description + RB_ENTRY(epg_broadcast) sched_link; ///< Schedule link LIST_ENTRY(epg_broadcast) ep_link; ///< Episode link epg_episode_t *episode; ///< Episode shown + LIST_ENTRY(epg_broadcast) sl_link; ///< SeriesLink link + epg_serieslink_t *serieslink; ///< SeriesLink; struct channel *channel; ///< Channel being broadcast on }; @@ -435,9 +465,34 @@ int epg_broadcast_set_is_new int epg_broadcast_set_is_repeat ( epg_broadcast_t *b, uint8_t r, struct epggrab_module *src ) __attribute__((warn_unused_result)); +int epg_broadcast_set_summary + ( epg_broadcast_t *b, const char *str, const char *lang, + struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_broadcast_set_description + ( epg_broadcast_t *b, const char *str, const char *lang, + struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_broadcast_set_summary2 + ( epg_broadcast_t *b, const lang_str_t *str, struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_broadcast_set_description2 + ( epg_broadcast_t *b, const lang_str_t *str, struct epggrab_module *src ) + __attribute__((warn_unused_result)); +int epg_broadcast_set_serieslink + ( epg_broadcast_t *b, epg_serieslink_t *sl, struct epggrab_module *src ) + __attribute__((warn_unused_result)); /* Accessors */ -epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *b ); +epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *b ); +epg_episode_t *epg_broadcast_get_episode + ( epg_broadcast_t *b, int create, int *save ); +const char *epg_broadcast_get_title + ( epg_broadcast_t *b, const char *lang ); +const char *epg_broadcast_get_summary + ( epg_broadcast_t *b, const char *lang ); +const char *epg_broadcast_get_description + ( epg_broadcast_t *b, const char *lang ); /* Serialization */ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *b ); diff --git a/src/epgdb.c b/src/epgdb.c index 19433c0a..f56e5982 100644 --- a/src/epgdb.c +++ b/src/epgdb.c @@ -34,6 +34,7 @@ extern epg_object_tree_t epg_brands; extern epg_object_tree_t epg_seasons; extern epg_object_tree_t epg_episodes; +extern epg_object_tree_t epg_serieslinks; /* ************************************************************************** * Load @@ -119,6 +120,10 @@ static void _epgdb_v2_process ( htsmsg_t *m, epggrab_stats_t *stats ) } else if ( !strcmp(sect, "episodes") ) { if (epg_episode_deserialize(m, 1, &save)) stats->episodes.total++; + /* Series link */ + } else if ( !strcmp(sect, "serieslinks") ) { + if (epg_serieslink_deserialize(m, 1, &save)) stats->seasons.total++; + /* Broadcasts */ } else if ( !strcmp(sect, "broadcasts") ) { if (epg_broadcast_deserialize(m, 1, &save)) stats->broadcasts.total++; @@ -284,6 +289,12 @@ void epg_save ( void ) if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) return; stats.episodes.total++; } + if ( _epg_write_sect(fd, "serieslinks") ) return; + RB_FOREACH(eo, &epg_serieslinks, uri_link) { + if (_epg_write(fd, epg_serieslink_serialize((epg_serieslink_t*)eo))) + return; + stats.seasons.total++; + } if ( _epg_write_sect(fd, "broadcasts") ) return; RB_FOREACH(ch, &channel_name_tree, ch_name_link) { RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) { diff --git a/src/epggrab/module/eit.c b/src/epggrab/module/eit.c index c435679c..c58124bc 100644 --- a/src/epggrab/module/eit.c +++ b/src/epggrab/module/eit.c @@ -410,9 +410,8 @@ static int _eit_process_event uint8_t dtag, dlen; epg_broadcast_t *ebc; epg_episode_t *ee; - epg_season_t *es; + epg_serieslink_t *es; eit_event_t ev; - lang_str_ele_t *ls; if ( len < 12 ) return -1; @@ -485,6 +484,16 @@ static int _eit_process_event ptr += dlen; } + /* + * Broadcast + */ + + /* Summary/Description */ + if ( ev.summary ) + *save |= epg_broadcast_set_summary2(ebc, ev.summary, mod); + if ( ev.desc ) + *save |= epg_broadcast_set_description2(ebc, ev.desc, mod); + /* Broadcast Metadata */ *save |= epg_broadcast_set_is_hd(ebc, ev.hd, mod); *save |= epg_broadcast_set_is_widescreen(ebc, ev.ws, mod); @@ -492,51 +501,39 @@ static int _eit_process_event *save |= epg_broadcast_set_is_subtitled(ebc, ev.st, mod); *save |= epg_broadcast_set_is_deafsigned(ebc, ev.ds, mod); - /* Find episode */ - if (*ev.uri) { - ee = epg_episode_find_by_uri(ev.uri, 1, save); - } else if ( !(ee = ebc->episode) ) { - char *uri; - uri = epg_hash(lang_str_get(ev.title, NULL), - lang_str_get(ev.summary, NULL), - lang_str_get(ev.desc, NULL)); - if (uri) { - ee = epg_episode_find_by_uri(uri, 1, save); - free(uri); - } + /* + * Series link + */ + + if (*ev.suri) { + if ((es = epg_serieslink_find_by_uri(ev.suri, 1, save))) + *save |= epg_broadcast_set_serieslink(ebc, es, mod); } - /* Update Broadcast */ - if (ee) *save |= epg_broadcast_set_episode(ebc, ee, mod); + /* + * Episode + */ + + /* Find episode */ + if (*ev.uri) { + if ((ee = epg_episode_find_by_uri(ev.uri, 1, save))) + *save |= epg_broadcast_set_episode(ebc, ee, mod); + + /* Existing/Artificial */ + } else + ee = epg_broadcast_get_episode(ebc, 1, save); /* Update Episode */ if (ee) { *save |= epg_episode_set_is_bw(ee, ev.bw, mod); - if ( ev.title ) { - RB_FOREACH(ls, ev.title, link) - *save |= epg_episode_set_title(ee, ls->str, ls->lang, mod); - } - if ( ev.summary ) { - RB_FOREACH(ls, ev.summary, link) - *save |= epg_episode_set_summary(ee, ls->str, ls->lang, mod); - } - if ( ev.desc ) { - RB_FOREACH(ls, ev.desc, link) - *save |= epg_episode_set_description(ee, ls->str, ls->lang, mod); - } + if ( ev.title ) + *save |= epg_episode_set_title2(ee, ev.title, mod); if ( ev.genre ) *save |= epg_episode_set_genre(ee, ev.genre, mod); #if TODO_ADD_EXTRA if ( ev.extra ) *save |= epg_episode_set_extra(ee, extra, mod); #endif - - /* Season */ - if (*ev.suri) { - es = epg_season_find_by_uri(ev.suri, 1, save); - if (es) - *save |= epg_episode_set_season(ee, es, mod); - } } /* Tidy up */ diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index d98a2b05..a9a58466 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -51,7 +51,7 @@ typedef struct opentv_event char *summary; ///< Event summary char *desc; ///< Event description uint8_t cat; ///< Event category - uint16_t series; ///< Series (link) reference + char *series; ///< Series ID uint8_t type; ///< 0x1=title, 0x2=summary } opentv_event_t; @@ -189,27 +189,6 @@ static epggrab_channel_t *_opentv_find_epggrab_channel (epggrab_module_t*)mod); } -static epg_season_t *_opentv_find_season - ( opentv_module_t *mod, int cid, opentv_event_t *ev, int *save ) -{ - char uri[64]; - sprintf(uri, "%s-%d-%d", mod->id, cid, ev->series); - return epg_season_find_by_uri(uri, 1, save); -} - -static epg_episode_t *_opentv_find_episode - ( opentv_module_t *mod, int cid, opentv_event_t *ev, int *save ) -{ - char uri[100]; - char *tmp = epg_hash(ev->title, ev->summary, ev->desc); - if (tmp) { - snprintf(uri, 100, "%s-%d-%s", mod->id, cid, tmp); - free(tmp); - return epg_episode_find_by_uri(uri, 1, save); - } - return NULL; -} - static service_t *_opentv_find_service ( int tsid, int sid ) { th_dvb_adapter_t *tda; @@ -278,8 +257,9 @@ static char *_opentv_parse_string /* Parse a specific record */ static int _opentv_parse_event_record ( opentv_module_t *prov, opentv_event_t *ev, uint8_t *buf, int len, - time_t mjd ) + time_t mjd, channel_t *ch ) { + char series[256]; uint8_t rtag = buf[0]; uint8_t rlen = buf[1]; if (rlen+2 <= len) { @@ -304,7 +284,11 @@ static int _opentv_parse_event_record ev->desc = _opentv_parse_string(prov, buf+2, rlen); break; case 0xc1: // series link - ev->series = ((uint16_t)buf[2] << 8) | buf[3]; + if (!ev->series) { + sprintf(series, "opentv://%s/%hu", ch->ch_name, + ((uint16_t)buf[2] << 8) | buf[3]); + ev->series = strdup(series); + } break; default: break; @@ -317,7 +301,8 @@ static int _opentv_parse_event_record static int _opentv_parse_event ( opentv_module_t *prov, opentv_status_t *sta, uint8_t *buf, int len, int cid, time_t mjd, - opentv_event_t *ev, int type ) + opentv_event_t *ev, int type, + channel_t *ch ) { int slen = ((int)buf[2] & 0xf << 8) | buf[3]; int i = 4; @@ -337,7 +322,7 @@ static int _opentv_parse_event /* Process records */ while (i < slen+4) { - i += _opentv_parse_event_record(prov, ev, buf+i, len-i, mjd); + i += _opentv_parse_event_record(prov, ev, buf+i, len-i, mjd, ch); } return slen+4; } @@ -352,11 +337,10 @@ static int _opentv_parse_event_section epggrab_channel_t *ec; epg_broadcast_t *ebc; epg_episode_t *ee; - epg_season_t *es; + epg_serieslink_t *es; opentv_event_t ev; epggrab_module_t *src = (epggrab_module_t*)mod; const char *lang = NULL; - const char *str; /* Get language (bit of a hack) */ if (!strcmp(mod->dict->id, "skyit")) lang = "it"; @@ -376,7 +360,12 @@ static int _opentv_parse_event_section i = 7; while (i < len) { memset(&ev, 0, sizeof(opentv_event_t)); - i += _opentv_parse_event(mod, sta, buf+i, len-i, cid, mjd, &ev, type); + i += _opentv_parse_event(mod, sta, buf+i, len-i, cid, mjd, + &ev, type, ec->channel); + + /* + * Broadcast + */ /* Find broadcast */ if (ev.type & OPENTV_TITLE) { @@ -391,40 +380,35 @@ static int _opentv_parse_event_section continue; // don't want to free() anything } - /* Find episode */ + /* Summary / Description */ if (ebc) { - ee = NULL; + if (ev.summary) + save |= epg_broadcast_set_summary(ebc, ev.summary, lang, src); + if (ev.desc) + save |= epg_broadcast_set_description(ebc, ev.desc, lang, src); + } - /* Find episode */ - if (ev.type & OPENTV_SUMMARY || !ebc->episode) - ee = _opentv_find_episode(mod, cid, &ev, &save); + /* + * Series link + */ - /* Use existing */ - if (!ee) ee = ebc->episode; + if (ebc && ev.series) { + if ((es = epg_serieslink_find_by_uri(ev.series, 1, &save))) + save |= epg_broadcast_set_serieslink(ebc, es, src); + } - /* Update */ - if (ee) { - if (!ev.title && ebc->episode) { - if ((str = epg_episode_get_title(ebc->episode, NULL))) - save |= epg_episode_set_title(ee, str, lang, NULL); - } else if (ev.title) - save |= epg_episode_set_title(ee, ev.title, lang, src); - if (ev.summary) - save |= epg_episode_set_summary(ee, ev.summary, lang, src); - if (ev.desc) - save |= epg_episode_set_description(ee, ev.desc, lang, src); - if (ev.cat) { - epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t)); - epg_genre_list_add_by_eit(egl, ev.cat); - save |= epg_episode_set_genre(ee, egl, src); - epg_genre_list_destroy(egl); - } - if (ev.series) { - es = _opentv_find_season(mod, cid, &ev, &save); - if (es) save |= epg_episode_set_season(ee, es, src); - } + /* + * Episode + */ - save |= epg_broadcast_set_episode(ebc, ee, src); + if (ebc && (ee = epg_broadcast_get_episode(ebc, 1, &save))) { + if (ev.title) + save |= epg_episode_set_title(ee, ev.title, lang, src); + if (ev.cat) { + epg_genre_list_t *egl = calloc(1, sizeof(epg_genre_list_t)); + epg_genre_list_add_by_eit(egl, ev.cat); + save |= epg_episode_set_genre(ee, egl, src); + epg_genre_list_destroy(egl); } } @@ -432,6 +416,7 @@ static int _opentv_parse_event_section if (ev.title) free(ev.title); if (ev.summary) free(ev.summary); if (ev.desc) free(ev.desc); + if (ev.series) free(ev.series); } /* Update EPG */ diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 3ff0892e..80dd9f57 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -182,20 +182,24 @@ static void parse_xmltv_ns_episode static void parse_xmltv_dd_progid (epggrab_module_t *mod, const char *s, char **uri, char **suri, int *en ) { + char buf[128]; if (strlen(s) < 2) return; + + /* Raw URI */ + snprintf(buf, sizeof(buf)-1, "ddprogid://%s/%s", mod->id, s); /* SH - series without episode id so ignore */ - if (strncmp("SH", s, 2)) { - *uri = malloc(strlen(mod->id) + 1 + strlen(s)); - sprintf(*uri, "%s-%s", mod->id, s); - } + if (strncmp("SH", s, 2)) *uri = strdup(buf); /* Episode */ if (!strncmp("EP", s, 2)) { - int e = 0; - while (s[e] && s[e] != '.') e++; - *suri = hts_strndup(s, e); - if (s[e] && s[e+1]) sscanf(s+e+1, "%d", en); + int e = strlen(buf); + while (e && s[e] != '.') e--; + if (e) { + buf[e] = '\0'; + *suri = strdup(buf); + if (s[e+1]) sscanf(s+e+1, "%d", en); + } } } @@ -358,7 +362,7 @@ static int _xmltv_parse_programme_tags { int save = 0, save2 = 0, save3 = 0; epg_episode_t *ee = NULL; - epg_season_t *es = NULL; + epg_serieslink_t *es = NULL; epg_broadcast_t *ebc; epg_genre_list_t *egl; int sn = 0, sc = 0, en = 0, ec = 0, pn = 0, pc = 0; @@ -367,22 +371,24 @@ static int _xmltv_parse_programme_tags lang_str_t *title = NULL; lang_str_t *desc = NULL; lang_str_t *subtitle = NULL; - lang_str_ele_t *ls; /* * Broadcast */ - - /* Create/Find broadcast */ - if (!(ebc = epg_broadcast_find_by_time(ch, start, stop, 0, 1, &save2))) return 0; + if (!(ebc = epg_broadcast_find_by_time(ch, start, stop, 0, 1, &save))) + return 0; stats->broadcasts.total++; - if (save2) stats->broadcasts.created++; + if (save) stats->broadcasts.created++; + + /* Description (wait for episode first) */ + if (desc) + save3 |= epg_broadcast_set_description2(ebc, desc, mod); /* Quality metadata */ - save2 |= parse_vid_quality(mod, ebc, ee, htsmsg_get_map(tags, "video")); + save |= parse_vid_quality(mod, ebc, ee, htsmsg_get_map(tags, "video")); /* Accessibility */ - save2 |= xmltv_parse_accessibility(mod, ebc, tags); + save |= xmltv_parse_accessibility(mod, ebc, tags); /* Misc */ if (htsmsg_get_map(tags, "previously-shown")) @@ -391,66 +397,54 @@ static int _xmltv_parse_programme_tags htsmsg_get_map(tags, "new")) save |= epg_broadcast_set_is_new(ebc, 1, mod); - /* Get episode info */ + /* + * Episode/Series info + */ get_episode_info(mod, tags, &uri, &suri, &onscreen, &sn, &sc, &en, &ec, &pn, &pc); - _xmltv_parse_lang_str(&title, tags, "title"); - _xmltv_parse_lang_str(&desc, tags, "desc"); - _xmltv_parse_lang_str(&subtitle, tags, "sub-title"); /* - * Season + * Series Link */ if (suri) { - es = epg_season_find_by_uri(suri, 1, &save3); + es = epg_serieslink_find_by_uri(suri, 1, &save2); free(suri); if (es) stats->seasons.total++; - if (save3) stats->seasons.created++; + if (save2) stats->seasons.created++; + + if (es) + save |= epg_broadcast_set_serieslink(ebc, es, mod); } /* * Episode */ - if (!uri && title) { - uri = epg_hash(lang_str_get(title, NULL), NULL, lang_str_get(desc, NULL)); - } if (uri) { - ee = epg_episode_find_by_uri(uri, 1, &save); + if ((ee = epg_episode_find_by_uri(uri, 1, &save3))) + save |= epg_broadcast_set_episode(ebc, ee, mod); free(uri); + } else { + ee = epg_broadcast_get_episode(ebc, 1, &save3); } + if (ee) stats->episodes.total++; + if (save3) stats->episodes.created++; - /* Update */ if (ee) { - stats->episodes.total++; - if (save) stats->episodes.created++; + _xmltv_parse_lang_str(&title, tags, "title"); + _xmltv_parse_lang_str(&subtitle, tags, "sub-title"); - save2 |= epg_broadcast_set_episode(ebc, ee, mod); - - if (es) - save |= epg_episode_set_season(ee, es, mod); - if (title) { - RB_FOREACH(ls, title, link) { - save |= epg_episode_set_title(ee, ls->str, ls->lang, mod); - } - } - if (subtitle) { - RB_FOREACH(ls, subtitle, link) { - save |= epg_episode_set_subtitle(ee, ls->str, ls->lang, mod); - } - } - if (desc) { - RB_FOREACH(ls, desc, link) { - save |= epg_episode_set_description(ee, ls->str, ls->lang, mod); - } - } + if (title) + save3 |= epg_episode_set_title2(ee, title, mod); + if (subtitle) + save3 |= epg_episode_set_subtitle2(ee, subtitle, mod); if ((egl = _xmltv_parse_categories(tags))) { - save |= epg_episode_set_genre(ee, egl, mod); + save3 |= epg_episode_set_genre(ee, egl, mod); epg_genre_list_destroy(egl); } - if (pn) save |= epg_episode_set_part(ee, pn, pc, mod); - if (en) save |= epg_episode_set_number(ee, en, mod); - if (save) stats->episodes.modified++; + + if (pn) save3 |= epg_episode_set_part(ee, pn, pc, mod); + if (en) save3 |= epg_episode_set_number(ee, en, mod); // TODO: need to handle certification and ratings // TODO: need to handle season numbering! @@ -458,7 +452,9 @@ static int _xmltv_parse_programme_tags } /* Stats */ - if (save2) stats->broadcasts.modified++; + if (save) stats->broadcasts.modified++; + if (save2) stats->seasons.modified++; + if (save3) stats->episodes.modified++; /* Cleanup */ if (title) lang_str_destroy(title); diff --git a/src/htsp.c b/src/htsp.c index 7edce4a6..5d9d52a8 100644 --- a/src/htsp.c +++ b/src/htsp.c @@ -760,14 +760,14 @@ htsp_build_event(epg_broadcast_t *e) htsmsg_add_u32(out, "channelId", e->channel->ch_id); htsmsg_add_u32(out, "start", e->start); htsmsg_add_u32(out, "stop", e->stop); - if (e->episode) { - if ((str = epg_episode_get_title(e->episode, NULL))) - htsmsg_add_str(out, "title", str); - if ((str = epg_episode_get_description(e->episode, NULL))) - htsmsg_add_str(out, "description", str); - else if((str = epg_episode_get_summary(e->episode, NULL))) - htsmsg_add_str(out, "description", str); + if ((str = epg_broadcast_get_title(e, NULL))) + htsmsg_add_str(out, "title", str); + if ((str = epg_broadcast_get_description(e, NULL))) + htsmsg_add_str(out, "description", str); + else if((str = epg_broadcast_get_summary(e, NULL))) + htsmsg_add_str(out, "description", str); + if (e->episode) { if((g = LIST_FIRST(&e->episode->genre))) htsmsg_add_u32(out, "contentType", g->code); } diff --git a/src/webui/extjs.c b/src/webui/extjs.c index c4e3df51..7f2c53fc 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -773,9 +773,9 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque) if((s = epg_episode_get_subtitle(ee, lang))) htsmsg_add_str(m, "subtitle", s); - if((s = epg_episode_get_description(ee, lang))) + if((s = epg_broadcast_get_description(e, lang))) htsmsg_add_str(m, "description", s); - else if((s = epg_episode_get_summary(ee, lang))) + else if((s = epg_broadcast_get_summary(e, lang))) htsmsg_add_str(m, "description", s); if (epg_episode_number_format(ee, buf, 100, NULL, "Season %d", ".", diff --git a/src/webui/simpleui.c b/src/webui/simpleui.c index 6aa8b29e..d3c5e895 100644 --- a/src/webui/simpleui.c +++ b/src/webui/simpleui.c @@ -124,7 +124,7 @@ page_simple(http_connection_t *hc, rstatus = de != NULL ? val2str(de->de_sched_state, recstatustxt) : NULL; - s = epg_episode_get_title(e->episode, lang); + s = epg_broadcast_get_title(e, lang); htsbuf_qprintf(hq, "" "%02d:%02d-%02d:%02d %s%s%s
", @@ -265,12 +265,11 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque) } htsbuf_qprintf(hq, ""); - if (e->episode) { - if ( e->episode->description ) - htsbuf_qprintf(hq, "%s", lang_str_get(e->episode->description, NULL)); - else if ( e->episode->summary ) - htsbuf_qprintf(hq, "%s", lang_str_get(e->episode->summary, NULL)); - } + + if ( (s = epg_broadcast_get_description(e, lang)) ) + htsbuf_qprintf(hq, "%s", s); + else if ( (s = epg_broadcast_get_summary(e, lang)) ) + htsbuf_qprintf(hq, "%s", s); pthread_mutex_unlock(&global_lock);