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:
Adam Sutton 2012-09-04 17:17:36 +01:00
parent ece441fd7a
commit 13bab26a1e
11 changed files with 426 additions and 182 deletions

View file

@ -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);

View file

@ -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
View file

@ -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);

View file

@ -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 );

View file

@ -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) {

View file

@ -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 */

View file

@ -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 */

View file

@ -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);

View file

@ -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);
}

View file

@ -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", ".",

View file

@ -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&nbsp;%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);