Update the EPG code to include text at broadcast level, removing title/desc hashing for URI and add a broadcast level linkage mechanism (series link, which shoudl be more like a standard STB). Fixes #1108.
This commit is contained in:
parent
ece441fd7a
commit
13bab26a1e
11 changed files with 426 additions and 182 deletions
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
197
src/epg.c
197
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);
|
||||
|
||||
|
|
91
src/epg.h
91
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 );
|
||||
|
|
11
src/epgdb.c
11
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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
14
src/htsp.c
14
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);
|
||||
}
|
||||
|
|
|
@ -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", ".",
|
||||
|
|
|
@ -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,
|
||||
"<a href=\"/eventinfo/%"PRIu64"\">"
|
||||
"%02d:%02d-%02d:%02d %s%s%s</a><br>",
|
||||
|
@ -265,12 +265,11 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
|
||||
htsbuf_qprintf(hq, "</form>");
|
||||
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);
|
||||
|
|
Loading…
Add table
Reference in a new issue