Significant reworking of EPG code to use an OO style, its still rough and there are quite a few bodges to make it work since its not proper OO (but will be if included in TVH3).

This commit is contained in:
Adam Sutton 2012-05-24 12:02:22 +01:00
parent bc10bb4a00
commit 585a740253
6 changed files with 466 additions and 527 deletions

698
src/epg.c

File diff suppressed because it is too large Load diff

169
src/epg.h
View file

@ -32,6 +32,7 @@
/*
* Map types
*/
RB_HEAD(epg_object_tree, epg_object);
RB_HEAD(epg_brand_tree, epg_brand);
RB_HEAD(epg_season_tree, epg_season);
RB_HEAD(epg_episode_tree, epg_episode);
@ -39,13 +40,40 @@ RB_HEAD(epg_channel_tree, epg_channel);
RB_HEAD(epg_broadcast_tree, epg_broadcast);
/*
* Forward declerations
* Typedefs
*/
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_channel epg_channel_t;
typedef struct epg_object epg_object_t;
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_channel epg_channel_t;
typedef struct epg_object_tree epg_object_tree_t;
typedef struct epg_brand_tree epg_brand_tree_t;
typedef struct epg_season_tree epg_season_tree_t;
typedef struct epg_episode_tree epg_episode_tree_t;
typedef struct epg_channel_tree epg_channel_tree_t;
typedef struct epg_broadcast_tree epg_broadcast_tree_t;
/* ************************************************************************
* Generic Object
* ***********************************************************************/
/* Object */
typedef struct epg_object
{
RB_ENTRY(epg_object) glink; ///< Global list link
RB_ENTRY(epg_object) ulink; ///< Global unref'd link
char *uri; ///< Unique ID (from grabber)
uint64_t id; ///< Internal ID
int refcount; ///< Reference counting
void (*getref) ( epg_object_t* ); ///< Get a reference
void (*putref) ( epg_object_t* ); ///< Release a reference
void (*destroy) ( epg_object_t* ); ///< Delete the object
} epg_object_t;
/* ************************************************************************
* Brand - Represents a specific show
@ -55,24 +83,20 @@ typedef struct epg_channel epg_channel_t;
/* Object */
typedef struct epg_brand
{
RB_ENTRY(epg_brand) eb_link; ///< Global list link
epg_object_t _; ///< Base object
uint32_t eb_id; ///< Internal ID
char *eb_uri; ///< Grabber URI
char *eb_title; ///< Brand name
char *eb_summary; ///< Brand summary
uint16_t eb_season_count; ///< Total number of seasons
char *title; ///< Brand name
char *summary; ///< Brand summary
uint16_t season_count; ///< Total number of seasons
struct epg_season_tree eb_seasons; ///< Season list
struct epg_episode_tree eb_episodes; ///< Episode list
int eb_refcount; ///< Reference counting
epg_season_tree_t seasons; ///< Season list
epg_episode_tree_t episodes; ///< Episode list
} epg_brand_t;
/* Lookup */
epg_brand_t *epg_brand_find_by_uri
( const char *uri, int create, int *save );
epg_brand_t *epg_brand_find_by_id ( uint32_t id );
epg_brand_t *epg_brand_find_by_id ( uint64_t id );
/* Mutators */
int epg_brand_set_title ( epg_brand_t *b, const char *title )
@ -101,26 +125,22 @@ epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create, int *save );
/* Object */
typedef struct epg_season
{
RB_ENTRY(epg_season) es_link; ///< Global list link
RB_ENTRY(epg_season) es_blink; ///< Brand list link
epg_object_t _; ///< Parent object
uint32_t es_id; ///< Internal ID
char *es_uri; ///< Grabber URI
char *es_summary; ///< Season summary
uint16_t es_number; ///< The season number
uint16_t es_episode_count; ///< Total number of episodes
char *summary; ///< Season summary
uint16_t number; ///< The season number
uint16_t episode_count; ///< Total number of episodes
epg_brand_t *es_brand; ///< Parent brand
struct epg_episode_tree es_episodes; ///< Episode list
int es_refcount; ///< Reference counting
RB_ENTRY(epg_season) blink; ///< Brand list link
epg_brand_t *brand; ///< Parent brand
epg_episode_tree_t episodes; ///< Episode list
} epg_season_t;
/* Lookup */
epg_season_t *epg_season_find_by_uri
( const char *uri, int create, int *save );
epg_season_t *epg_season_find_by_id ( uint32_t id );
epg_season_t *epg_season_find_by_id ( uint64_t id );
/* Mutators */
int epg_season_set_summary ( epg_season_t *s, const char *summary )
@ -149,32 +169,29 @@ epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save );
/* Object */
typedef struct epg_episode
{
RB_ENTRY(epg_episode) ee_link; ///< Global link
RB_ENTRY(epg_episode) ee_blink; ///< Brand link
RB_ENTRY(epg_episode) ee_slink; ///< Season link
epg_object_t _; ///< Parent object
uint32_t ee_id; ///< Internal ID
char *ee_uri; ///< Grabber URI
char *ee_title; ///< Title
char *ee_subtitle; ///< Sub-title
char *ee_summary; ///< Summary
char *ee_description; ///< An extended description
uint8_t ee_genre; ///< Episode genre
uint16_t ee_number; ///< The episode number
uint16_t ee_part_number; ///< For multipart episodes
uint16_t ee_part_count; ///< For multipart episodes
char *title; ///< Title
char *subtitle; ///< Sub-title
char *summary; ///< Summary
char *description; ///< An extended description
uint8_t genre; ///< Episode genre
uint16_t number; ///< The episode number
uint16_t part_number; ///< For multipart episodes
uint16_t part_count; ///< For multipart episodes
epg_brand_t *ee_brand; ///< (Grand-)Parent brand
epg_season_t *ee_season; ///< Parent season
struct epg_broadcast_tree ee_broadcasts; ///< Broadcast list
RB_ENTRY(epg_episode) blink; ///< Brand link
RB_ENTRY(epg_episode) slink; ///< Season link
epg_brand_t *brand; ///< (Grand-)Parent brand
epg_season_t *season; ///< Parent season
epg_broadcast_tree_t broadcasts; ///< Broadcast list
int ee_refcount; ///< Reference counting
} epg_episode_t;
/* Lookup */
epg_episode_t *epg_episode_find_by_uri
( const char *uri, int create, int *save );
epg_episode_t *epg_episode_find_by_id ( uint32_t id );
epg_episode_t *epg_episode_find_by_id ( uint64_t id );
/* Mutators */
int epg_episode_set_title ( epg_episode_t *e, const char *title )
@ -213,39 +230,38 @@ epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save );
/* Object */
typedef struct epg_broadcast
{
RB_ENTRY(epg_broadcast) eb_slink; ///< Schedule link
RB_ENTRY(epg_broadcast) eb_elink; ///< Episode link
uint32_t eb_id; ///< Internal ID
uint32_t eb_dvb_id; ///< DVB identifier
time_t eb_start; ///< Start time
time_t eb_stop; ///< End time
epg_object_t _; ///< Parent object
uint32_t dvb_id; ///< DVB identifier
time_t start; ///< Start time
time_t stop; ///< End time
/* Some quality info */
uint8_t eb_widescreen; ///< Is widescreen
uint8_t eb_hd; ///< Is HD
uint16_t eb_lines; ///< Lines in image (quality)
uint16_t eb_aspect; ///< Aspect ratio (*100)
uint8_t is_widescreen; ///< Is widescreen
uint8_t is_hd; ///< Is HD
uint16_t lines; ///< Lines in image (quality)
uint16_t aspect; ///< Aspect ratio (*100)
/* Some accessibility support */
uint8_t eb_deafsigned; ///< In screen signing
uint8_t eb_subtitled; ///< Teletext subtitles
uint8_t eb_audio_desc; ///< Audio description
uint8_t is_deafsigned; ///< In screen signing
uint8_t is_subtitled; ///< Teletext subtitles
uint8_t is_audio_desc; ///< Audio description
/* Misc flags */
uint8_t eb_new; ///< New series / file premiere
uint8_t eb_repeat; ///< Repeat screening
uint8_t is_new; ///< New series / file premiere
uint8_t is_repeat; ///< Repeat screening
epg_episode_t *eb_episode; ///< Episode shown
epg_channel_t *eb_channel; ///< Channel being broadcast on
RB_ENTRY(epg_broadcast) slink; ///< Schedule link
RB_ENTRY(epg_broadcast) elink; ///< Episode link
epg_episode_t *episode; ///< Episode shown
epg_channel_t *channel; ///< Channel being broadcast on
int eb_refcount; ///< Reference counting
} epg_broadcast_t;
/* Lookup */
epg_broadcast_t *epg_broadcast_find_by_time
( epg_channel_t *ch, time_t start, time_t stop, int create, int *save );
epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id );
epg_broadcast_t *epg_broadcast_find_by_id ( uint64_t id );
/* Mutators */
int epg_broadcast_set_episode ( epg_broadcast_t *b, epg_episode_t *e, int u )
@ -266,25 +282,20 @@ epg_broadcast_t *epg_broadcast_deserialize
/* Object */
typedef struct epg_channel
{
RB_ENTRY(epg_channel) ec_link; ///< Global link
epg_object_t _; ///< Parent object
uint32_t ec_id; ///< Internal ID
char *ec_uri; ///< Grabber URI
char *ec_name; ///< Channel name
char **ec_sname; ///< DVB svc names (to map)
int **ec_sid; ///< DVB svc ids (to map)
char *name; ///< Channel name
char **sname; ///< DVB svc names (to map)
int **sid; ///< DVB svc ids (to map)
channel_t *ec_channel; ///< Link to real channel
LIST_ENTRY(epg_channel) ec_ulink; ///< Unlinked list
struct epg_broadcast_tree ec_schedule; ///< Schedule (broadcasts)
channel_t *channel; ///< Link to real channel
epg_object_tree_t schedule; ///< Schedule (broadcasts)
} epg_channel_t;
/* Lookup */
epg_channel_t *epg_channel_find_by_uri
( const char *uri, int create, int *save );
epg_channel_t *epg_channel_find_by_id ( uint32_t id );
epg_channel_t *epg_channel_find_by_id ( uint64_t id );
/* Mutators */
int epg_channel_set_name ( epg_channel_t *c, const char *n )

View file

@ -312,8 +312,8 @@ htsp_build_channel(channel_t *ch, const char *method)
now = epg_channel_get_current_broadcast(ch->ch_epg_channel);
if ( now ) next = epg_broadcast_get_next(now);
htsmsg_add_u32(out, "eventId", now ? now->eb_id : 0);
htsmsg_add_u32(out, "nextEventId", next ? next->eb_id : 0);
htsmsg_add_u32(out, "eventId", now ? now->_.id : 0);
htsmsg_add_u32(out, "nextEventId", next ? next->_.id : 0);
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
ct = ctm->ctm_tag;
@ -730,7 +730,7 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
if( c ) {
eventIds = htsmsg_create_list();
for(i = 0; i < c; ++i) {
htsmsg_add_u32(eventIds, NULL, eqr.eqr_array[i]->eb_id);
htsmsg_add_u32(eventIds, NULL, eqr.eqr_array[i]->_.id);
}
htsmsg_add_msg(out, "eventIds", eventIds);
}
@ -754,18 +754,18 @@ htsp_build_event(epg_broadcast_t *e)
out = htsmsg_create_map();
htsmsg_add_u32(out, "eventId", e->eb_id);
htsmsg_add_u32(out, "eventId", e->_.id);
#if TODO_EPG_CHANNEL
htsmsg_add_u32(out, "channelId", e->e_channel->ch_id);
#endif
htsmsg_add_u32(out, "start", e->eb_start);
htsmsg_add_u32(out, "stop", e->eb_stop);
if(e->eb_episode->ee_title != NULL)
htsmsg_add_str(out, "title", e->eb_episode->ee_title);
if(e->eb_episode->ee_description != NULL)
htsmsg_add_str(out, "description", e->eb_episode->ee_description);
else if(e->eb_episode->ee_summary != NULL)
htsmsg_add_str(out, "description", e->eb_episode->ee_summary);
htsmsg_add_u32(out, "start", e->start);
htsmsg_add_u32(out, "stop", e->stop);
if(e->episode->title != NULL)
htsmsg_add_str(out, "title", e->episode->title);
if(e->episode->description != NULL)
htsmsg_add_str(out, "description", e->episode->description);
else if(e->episode->summary != NULL)
htsmsg_add_str(out, "description", e->episode->summary);
#if TODO_REMOVE_THESE
if(e->e_ext_desc != NULL)
htsmsg_add_str(out, "ext_desc", e->e_ext_desc);
@ -775,8 +775,8 @@ htsp_build_event(epg_broadcast_t *e)
htsmsg_add_str(out, "ext_text", e->e_ext_text);
#endif
if(e->eb_episode->ee_genre)
htsmsg_add_u32(out, "contentType", e->eb_episode->ee_genre);
if(e->episode->genre)
htsmsg_add_u32(out, "contentType", e->episode->genre);
#if TODO_DVR
if((de = dvr_entry_find_by_event(e)) != NULL) {
@ -786,7 +786,7 @@ htsp_build_event(epg_broadcast_t *e)
n = epg_broadcast_get_next(e);
if(n != NULL)
htsmsg_add_u32(out, "nextEventId", n->eb_id);
htsmsg_add_u32(out, "nextEventId", n->_.id);
return out;
}
@ -1427,8 +1427,8 @@ htsp_channel_update_current(channel_t *ch)
now = epg_channel_get_current_broadcast(ch->ch_epg_channel);
next = epg_broadcast_get_next(now);
htsmsg_add_u32(m, "eventId", now ? now->eb_id : 0);
htsmsg_add_u32(m, "nextEventId", next ? next->eb_id : 0);
htsmsg_add_u32(m, "eventId", now ? now->_.id : 0);
htsmsg_add_u32(m, "nextEventId", next ? next->_.id : 0);
htsp_async_send(m);
}

View file

@ -709,8 +709,8 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
for(i = start; i < end; i++) {
e = eqr.eqr_array[i];
ee = e->eb_episode;
ch = e->eb_channel->ec_channel;
ee = e->episode;
ch = e->channel->channel;
if (!ch||!ee) continue;
m = htsmsg_create_map();
@ -720,13 +720,13 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
if(ch->ch_icon != NULL)
htsmsg_add_str(m, "chicon", ch->ch_icon);
if(ee->ee_title != NULL)
htsmsg_add_str(m, "title", ee->ee_title);
if(ee->title != NULL)
htsmsg_add_str(m, "title", ee->title);
if(ee->ee_description != NULL)
htsmsg_add_str(m, "description", ee->ee_description);
else if(ee->ee_summary != NULL)
htsmsg_add_str(m, "description", ee->ee_summary);
if(ee->description != NULL)
htsmsg_add_str(m, "description", ee->description);
else if(ee->summary != NULL)
htsmsg_add_str(m, "description", ee->summary);
if (epg_episode_get_number_onscreen(ee, buf, 100))
htsmsg_add_str(m, "episode", strdup(buf));
@ -742,10 +742,10 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(m, "ext_text", e->e_ext_text);
#endif
htsmsg_add_u32(m, "id", e->eb_id);
htsmsg_add_u32(m, "start", e->eb_start);
htsmsg_add_u32(m, "end", e->eb_stop);
htsmsg_add_u32(m, "duration", e->eb_stop - e->eb_start);
htsmsg_add_u32(m, "id", e->_.id);
htsmsg_add_u32(m, "start", e->start);
htsmsg_add_u32(m, "end", e->stop);
htsmsg_add_u32(m, "duration", e->stop - e->start);
#if TODO_INCLUDE_GENRE_SUPORT
if((s = epg_content_group_get_name(e->e_content_type)) != NULL)
@ -794,49 +794,49 @@ extjs_epgrelated(http_connection_t *hc, const char *remain, void *opaque)
pthread_mutex_lock(&global_lock);
if ( id && type ) {
e = epg_broadcast_find_by_id(atoi(id));
if ( e && e->eb_episode ) {
ee = e->eb_episode;
if ( e && e->episode ) {
ee = e->episode;
/* Alternative broadcasts */
if (!strcmp(type, "alternative")) {
RB_FOREACH(ebc, &ee->ee_broadcasts, eb_elink) {
ch = ebc->eb_channel->ec_channel;
RB_FOREACH(ebc, &ee->broadcasts, elink) {
ch = ebc->channel->channel;
if ( !ch ) continue; // skip something not viewable
if ( ebc == e ) continue; // skip self
count++;
m = htsmsg_create_map();
htsmsg_add_u32(m, "id", ebc->eb_id);
htsmsg_add_u32(m, "id", ebc->_.id);
if ( ch->ch_name ) htsmsg_add_str(m, "channel", ch->ch_name);
if ( ch->ch_icon ) htsmsg_add_str(m, "chicon", ch->ch_icon);
htsmsg_add_u32(m, "start", ebc->eb_start);
htsmsg_add_u32(m, "start", ebc->start);
htsmsg_add_msg(array, NULL, m);
}
/* Related */
} else if (!strcmp(type, "related")) {
// TODO: broadcasts?
if (ee->ee_brand) {
RB_FOREACH(ee2, &ee->ee_brand->eb_episodes, ee_blink) {
if (ee->brand) {
RB_FOREACH(ee2, &ee->brand->episodes, blink) {
if (ee2 == ee) continue;
if (!ee2->ee_title) continue;
if (!ee2->title) continue;
count++;
m = htsmsg_create_map();
htsmsg_add_str(m, "uri", ee2->ee_uri);
htsmsg_add_str(m, "title", ee2->ee_title);
if (ee2->ee_subtitle) htsmsg_add_str(m, "title", ee2->ee_subtitle);
htsmsg_add_str(m, "uri", ee2->_.uri);
htsmsg_add_str(m, "title", ee2->title);
if (ee2->subtitle) htsmsg_add_str(m, "title", ee2->subtitle);
if (epg_episode_get_number_onscreen(ee2, buf, 100))
htsmsg_add_str(m, "episode", strdup(buf));
htsmsg_add_msg(array, NULL, m);
}
} else if (ee->ee_season) {
RB_FOREACH(ee2, &ee->ee_season->es_episodes, ee_slink) {
} else if (ee->season) {
RB_FOREACH(ee2, &ee->season->episodes, slink) {
if (ee2 == ee) continue;
if (!ee2->ee_title) continue;
if (!ee2->title) continue;
count++;
m = htsmsg_create_map();
htsmsg_add_str(m, "uri", ee2->ee_uri);
htsmsg_add_str(m, "title", ee2->ee_title);
if (ee2->ee_subtitle) htsmsg_add_str(m, "title", ee2->ee_subtitle);
htsmsg_add_str(m, "uri", ee2->_.uri);
htsmsg_add_str(m, "title", ee2->title);
if (ee2->subtitle) htsmsg_add_str(m, "title", ee2->subtitle);
if (epg_episode_get_number_onscreen(ee2, buf, 100))
htsmsg_add_str(m, "episode", strdup(buf));
htsmsg_add_msg(array, NULL, m);
@ -1175,8 +1175,8 @@ extjs_dvrlist(http_connection_t *hc, const char *remain, void *opaque)
htsmsg_add_str(m, "description", de->de_desc);
#if TODO_DVR
if(de->de_episode.ee_onscreen)
htsmsg_add_str(m, "episode", de->de_episode.ee_onscreen);
if(de->de_episode.onscreen)
htsmsg_add_str(m, "episode", de->de_episode.onscreen);
#endif
htsmsg_add_u32(m, "id", de->de_id);

View file

@ -108,8 +108,8 @@ page_simple(http_connection_t *hc,
for(k = 0; k < c; k++) {
e = eqr.eqr_array[k];
localtime_r(&e->eb_start, &a);
localtime_r(&e->eb_stop, &b);
localtime_r(&e->start, &a);
localtime_r(&e->stop, &b);
if(a.tm_wday != day.tm_wday || a.tm_mday != day.tm_mday ||
a.tm_mon != day.tm_mon || a.tm_year != day.tm_year) {
@ -128,9 +128,9 @@ page_simple(http_connection_t *hc,
htsbuf_qprintf(hq,
"<a href=\"/eventinfo/%d\">"
"%02d:%02d-%02d:%02d&nbsp;%s%s%s</a><br>",
e->eb_id,
e->_.id,
a.tm_hour, a.tm_min, b.tm_hour, b.tm_min,
e->eb_episode->ee_title,
e->episode->title,
rstatus ? "&nbsp;" : "", rstatus ?: "");
}
}
@ -223,8 +223,8 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
htsbuf_qprintf(hq, "<html>");
htsbuf_qprintf(hq, "<body>");
localtime_r(&e->eb_start, &a);
localtime_r(&e->eb_stop, &b);
localtime_r(&e->start, &a);
localtime_r(&e->stop, &b);
htsbuf_qprintf(hq,
"%s, %d/%d %02d:%02d - %02d:%02d<br>",
@ -233,7 +233,7 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
// TODO: use real channel?
htsbuf_qprintf(hq, "<hr><b>\"%s\": \"%s\"</b><br><br>",
e->eb_channel->ec_name, e->eb_episode->ee_title);
e->channel->name, e->episode->title);
dvr_status = de != NULL ? de->de_sched_state : DVR_NOSTATE;
@ -241,7 +241,7 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
htsbuf_qprintf(hq, "Recording status: %s<br>", rstatus);
htsbuf_qprintf(hq, "<form method=\"post\" action=\"/eventinfo/%d\">",
e->eb_id);
e->_.id);
switch(dvr_status) {
case DVR_SCHEDULED:
@ -265,10 +265,10 @@ page_einfo(http_connection_t *hc, const char *remain, void *opaque)
}
htsbuf_qprintf(hq, "</form>");
if ( e->eb_episode->ee_description )
htsbuf_qprintf(hq, "%s", e->eb_episode->ee_description);
else if ( e->eb_episode->ee_summary )
htsbuf_qprintf(hq, "%s", e->eb_episode->ee_summary);
if ( e->episode->description )
htsbuf_qprintf(hq, "%s", e->episode->description);
else if ( e->episode->summary )
htsbuf_qprintf(hq, "%s", e->episode->summary);
pthread_mutex_unlock(&global_lock);

View file

@ -183,8 +183,8 @@ http_stream_run(http_connection_t *hc, streaming_queue_t *sq, th_subscription_t
epg_broadcast_t *e = NULL;
if(s->ths_channel) e = epg_channel_get_current_broadcast(s->ths_channel->ch_epg_channel);
if(e && event_id != e->eb_id) {
event_id = e->eb_id;
if(e && event_id != e->_.id) {
event_id = e->_.id;
#if TODO_EVENT
run = !mk_mux_append_meta(mkm, e);
#endif