diff --git a/src/epg.c b/src/epg.c
index d2864325..7fd851b9 100644
--- a/src/epg.c
+++ b/src/epg.c
@@ -16,8 +16,6 @@
* along with this program. If not, see .
*/
-// TODO:
-
#include
#include
#include
@@ -66,8 +64,6 @@ static int ec_uri_cmp ( const epg_channel_t *a, const epg_channel_t *b )
static int ebc_win_cmp ( const epg_broadcast_t *a, const epg_broadcast_t *b )
{
- printf("check a %ld against b %ld to %ld\n", a->eb_start, b->eb_start, b->eb_stop);
-// TODO: some le-way?
if ( a->eb_start < b->eb_start ) return -1;
if ( a->eb_start >= b->eb_stop ) return 1;
return 0;
@@ -142,7 +138,7 @@ void epg_save ( void )
void epg_updated ( void )
{
- _epg_dump();
+ if (0)_epg_dump();
}
@@ -546,6 +542,21 @@ int epg_episode_rem_broadcast
return save;
}
+int epg_episode_get_number_onscreen
+ ( epg_episode_t *episode, char *buf, int len )
+{
+ int i = 0;
+ if ( episode->ee_number ) {
+ // TODO: add counts
+ if ( episode->ee_season && episode->ee_season->es_number ) {
+ i += snprintf(&buf[i], len-i, "Season %d ",
+ episode->ee_season->es_number);
+ }
+ i += snprintf(&buf[i], len-i, "Episode %d", episode->ee_number);
+ }
+ return i;
+}
+
/* **************************************************************************
* Broadcast
* *************************************************************************/
@@ -566,8 +577,9 @@ epg_broadcast_t* epg_broadcast_find_by_time
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_broadcast_t));
- skel->eb_start = start;
- skel->eb_stop = stop;
+ skel->eb_channel = channel;
+ skel->eb_start = start;
+ skel->eb_stop = stop;
/* Find */
if ( !create ) {
@@ -592,7 +604,7 @@ int epg_broadcast_set_episode
if ( !broadcast || !episode ) return 0;
if ( broadcast->eb_episode != episode ) {
broadcast->eb_episode = episode;
- //if ( u ) epg_episode_add_broadcast(episode, broadcast, 0);
+ if ( u ) save |= epg_episode_add_broadcast(episode, broadcast, 0);
save = 1;
}
return save;
@@ -629,38 +641,56 @@ epg_channel_t* epg_channel_find_by_uri ( const char *id, int create )
return ec;
}
-epg_channel_t* epg_channel_find
- ( const char *id, const char *name, const char **sname, const int **sid )
+int epg_channel_set_name ( epg_channel_t *channel, const char *name )
{
- epg_channel_t* channel;
-
- /* Find or create */
- if ((channel = epg_channel_find_by_uri(id, 1)) == NULL) return NULL;
-
- /* Update fields? */
-
- return channel;
+ int save = 0;
+ if ( !channel || !name ) return 0;
+ if ( !channel->ec_name || strcmp(channel->ec_name, name) ) {
+ channel->ec_name = strdup(name);
+ // TODO: lookup real channel
+ save = 1;
+ }
+ return save;
}
/* **************************************************************************
* Querying
* *************************************************************************/
+static void _eqr_add ( epg_query_result_t *eqr, epg_broadcast_t *e )
+{
+ /* More space */
+ if ( eqr->eqr_entries == eqr->eqr_alloced ) {
+ eqr->eqr_alloced = MAX(100, eqr->eqr_alloced * 2);
+ eqr->eqr_array = realloc(eqr->eqr_array,
+ eqr->eqr_alloced * sizeof(epg_broadcast_t));
+ }
+
+ /* Store */
+ eqr->eqr_array[eqr->eqr_entries++] = e;
+ // TODO: ref counting
+}
+
+static void _eqr_add_channel
+ ( epg_query_result_t *eqr, epg_channel_t *ec )
+{
+ epg_broadcast_t *ebc;
+ RB_FOREACH(ebc, &ec->ec_schedule, eb_slink) {
+ if ( ebc->eb_episode ) _eqr_add(eqr, ebc);
+ }
+}
+
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
const char *contentgroup, const char *title)
{
+ // TODO: will need some real code here
epg_channel_t *ec;
- epg_broadcast_t *ebc;
- eqr->eqr_array = calloc(2, sizeof(epg_broadcast_t*));
+
+ /* Clear (just incase) */
+ memset(eqr, 0, sizeof(epg_query_result_t));
+
RB_FOREACH(ec, &epg_channels, ec_link) {
- RB_FOREACH(ebc, &ec->ec_schedule, eb_slink) {
- if ( ebc->eb_episode ) {
- eqr->eqr_array[0] = ebc;
- eqr->eqr_entries = 1;
- eqr->eqr_alloced = 2;
- return;
- }
- }
+ _eqr_add_channel(eqr, ec);
}
return;
}
@@ -668,8 +698,16 @@ void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
void epg_query_free(epg_query_result_t *eqr)
{
free(eqr->eqr_array);
+ // TODO: reference counting
+}
+
+static int _epg_sort_start_ascending ( const void *a, const void *b )
+{
+ return (*(epg_broadcast_t**)a)->eb_start - (*(epg_broadcast_t**)b)->eb_start;
}
void epg_query_sort(epg_query_result_t *eqr)
{
+ qsort(eqr->eqr_array, eqr->eqr_entries, sizeof(epg_broadcast_t*),
+ _epg_sort_start_ascending);
}
diff --git a/src/epg.h b/src/epg.h
index f779dbbc..fe64852c 100644
--- a/src/epg.h
+++ b/src/epg.h
@@ -22,19 +22,6 @@
#include "channels.h"
#include "settings.h"
-/* ************************************************************************
- * Type definitions
- * ***********************************************************************/
-
-/*
- * Forward declarations
- */
-struct epg_brand;
-struct epg_season;
-struct epg_episode;
-struct epg_broadcast;
-struct epg_channel;
-
/*
* Map types
*/
@@ -43,12 +30,22 @@ RB_HEAD(epg_season_tree, epg_season);
RB_HEAD(epg_episode_tree, epg_episode);
RB_HEAD(epg_channel_tree, epg_channel);
RB_HEAD(epg_broadcast_tree, epg_broadcast);
-// TODO: not sure above wants to be an RB, prob just LIST
-/*
- * Represents a specific show
- * e.g. The Simpsons, 24, Eastenders, etc...
+/*
+ * Forward declerations
*/
+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;
+
+/* ************************************************************************
+ * Brand - Represents a specific show
+ * e.g. The Simpsons, 24, Eastenders, etc...
+ * ***********************************************************************/
+
+/* Object */
typedef struct epg_brand
{
RB_ENTRY(epg_brand) eb_link; ///< Global list link
@@ -60,14 +57,34 @@ typedef struct epg_brand
struct epg_season_tree eb_seasons; ///< Season list
struct epg_episode_tree eb_episodes; ///< Episode list
- // TODO: should this only include unattached episodes?
int eb_refcount; ///< Reference counting
} epg_brand_t;
-/*
- * Represents a season
- */
+/* Lookup */
+epg_brand_t *epg_brand_find_by_uri ( const char *uri, int create );
+
+/* Mutators */
+int epg_brand_set_title ( epg_brand_t *b, const char *title )
+ __attribute__((warn_unused_result));
+int epg_brand_set_summary ( epg_brand_t *b, const char *summary )
+ __attribute__((warn_unused_result));
+int epg_brand_set_season_count ( epg_brand_t *b, uint16_t season_count )
+ __attribute__((warn_unused_result));
+int epg_brand_add_season ( epg_brand_t *b, epg_season_t *s, int u )
+ __attribute__((warn_unused_result));
+int epg_brand_rem_season ( epg_brand_t *b, epg_season_t *s, int u )
+ __attribute__((warn_unused_result));
+int epg_brand_add_episode ( epg_brand_t *b, epg_episode_t *s, int u )
+ __attribute__((warn_unused_result));
+int epg_brand_rem_episode ( epg_brand_t *b, epg_episode_t *s, int u )
+ __attribute__((warn_unused_result));
+
+/* ************************************************************************
+ * Season
+ * ***********************************************************************/
+
+/* Object */
typedef struct epg_season
{
RB_ENTRY(epg_season) es_link; ///< Global list link
@@ -85,9 +102,30 @@ typedef struct epg_season
} epg_season_t;
-/*
- * Represents a particular episode
- */
+/* Lookup */
+epg_season_t *epg_season_find_by_uri ( const char *uri, int create );
+
+/* Mutators */
+int epg_season_set_summary ( epg_season_t *s, const char *summary )
+ __attribute__((warn_unused_result));
+int epg_season_set_number ( epg_season_t *s, uint16_t number )
+ __attribute__((warn_unused_result));
+int epg_season_set_episode_count ( epg_season_t *s, uint16_t episode_count )
+ __attribute__((warn_unused_result));
+int epg_season_set_brand ( epg_season_t *s, epg_brand_t *b, int u )
+ __attribute__((warn_unused_result));
+int epg_season_add_episode ( epg_season_t *s, epg_episode_t *e, int u )
+ __attribute__((warn_unused_result));
+int epg_season_rem_episode ( epg_season_t *s, epg_episode_t *e, int u )
+ __attribute__((warn_unused_result));
+
+/* ************************************************************************
+ * Episode
+ *
+ * TODO: ee_genre needs to be a list
+ * ***********************************************************************/
+
+/* Object */
typedef struct epg_episode
{
RB_ENTRY(epg_episode) ee_link; ///< Global link
@@ -100,7 +138,6 @@ typedef struct epg_episode
char *ee_summary; ///< Summary
char *ee_description; ///< An extended description
uint8_t ee_genre; ///< Episode genre
- // TODO: genre needs to be a list (should it be a string?)
uint16_t ee_number; ///< The episode number
uint16_t ee_part_number; ///< For multipart episodes
uint16_t ee_part_count; ///< For multipart episodes
@@ -112,9 +149,41 @@ typedef struct epg_episode
int ee_refcount; ///< Reference counting
} epg_episode_t;
-/*
- * A specific broadcast of an episode
- */
+/* Lookup */
+epg_episode_t *epg_episode_find_by_uri ( const char *uri, int create );
+
+/* Mutators */
+int epg_episode_set_title ( epg_episode_t *e, const char *title )
+ __attribute__((warn_unused_result));
+int epg_episode_set_subtitle ( epg_episode_t *e, const char *subtitle )
+ __attribute__((warn_unused_result));
+int epg_episode_set_summary ( epg_episode_t *e, const char *summary )
+ __attribute__((warn_unused_result));
+int epg_episode_set_description ( epg_episode_t *e, const char *description )
+ __attribute__((warn_unused_result));
+int epg_episode_set_number ( epg_episode_t *e, uint16_t number )
+ __attribute__((warn_unused_result));
+int epg_episode_set_part ( epg_episode_t *e,
+ uint16_t number, uint16_t count )
+ __attribute__((warn_unused_result));
+int epg_episode_set_brand ( epg_episode_t *e, epg_brand_t *b, int u )
+ __attribute__((warn_unused_result));
+int epg_episode_set_season ( epg_episode_t *e, epg_season_t *s, int u )
+ __attribute__((warn_unused_result));
+int epg_episode_add_broadcast ( epg_episode_t *e, epg_broadcast_t *b, int u )
+ __attribute__((warn_unused_result));
+int epg_episode_rem_broadcast ( epg_episode_t *e, epg_broadcast_t *b, int u )
+ __attribute__((warn_unused_result));
+
+/* Acessors */
+int epg_episode_get_number_onscreen ( epg_episode_t *e, char *b, int c );
+
+
+/* ************************************************************************
+ * Broadcast - specific airing (channel & time) of an episode
+ * ***********************************************************************/
+
+/* Object */
typedef struct epg_broadcast
{
RB_ENTRY(epg_broadcast) eb_slink; ///< Schedule link
@@ -141,19 +210,29 @@ typedef struct epg_broadcast
uint8_t eb_repeat; ///< Repeat screening
epg_episode_t *eb_episode; ///< Episode shown
- channel_t *eb_channel; ///< Channel being broadcast on
+ epg_channel_t *eb_channel; ///< Channel being broadcast on
int eb_refcount; ///< Reference counting
} epg_broadcast_t;
-/*
- * Channel for mappings
- */
+/* Lookup */
+epg_broadcast_t *epg_broadcast_find_by_time ( epg_channel_t *ch, time_t start, time_t stop, int create );
+
+/* Mutators */
+int epg_broadcast_set_episode ( epg_broadcast_t *b, epg_episode_t *e, int u )
+ __attribute__((warn_unused_result));
+
+/* ************************************************************************
+ * Channel - provides mapping from EPG channels to real channels
+ * ***********************************************************************/
+
+/* Object */
typedef struct epg_channel
{
RB_ENTRY(epg_channel) ec_link; ///< Global link
char *ec_uri; ///< Channel URI
+ char *ec_name; ///< Channel name
char **ec_sname; ///< DVB svc names (to map)
int **ec_sid; ///< DVB svc ids (to map)
@@ -163,6 +242,17 @@ typedef struct epg_channel
} epg_channel_t;
+/* Lookup */
+epg_channel_t *epg_channel_find_by_uri ( const char *uri, int create );
+
+/* Mutators */
+int epg_channel_set_name ( epg_channel_t *c, const char *n )
+ __attribute__((warn_unused_result));
+
+/* ************************************************************************
+ * Querying
+ * ***********************************************************************/
+
/*
* Query result
*/
@@ -172,6 +262,14 @@ typedef struct epg_query_result {
int eqr_alloced;
} epg_query_result_t;
+void epg_query0(epg_query_result_t *eqr, channel_t *ch, channel_tag_t *ct,
+ uint8_t type, const char *title);
+void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
+ const char *contentgroup, const char *title);
+void epg_query_free(epg_query_result_t *eqr);
+void epg_query_sort(epg_query_result_t *eqr);
+
+
/* ************************************************************************
* Function prototypes
* ***********************************************************************/
@@ -183,93 +281,12 @@ typedef struct epg_query_result {
void epg_init(void);
void epg_save(void);
-/**
- * All the epg_X_set_ function return 1 if it actually changed
- * the EPG records. otherwise it returns 0.
- *
- * If the caller detects that something has changed, it should call
- * epg_event_updated().
- *
- * There reason to put the burden on the caller is that the caller
- * can combine multiple set()'s into one update
- *
- */
-
-/* Brand set() calls */
-int epg_brand_set_title ( epg_brand_t *b, const char *title )
- __attribute__((warn_unused_result));
-int epg_brand_set_summary ( epg_brand_t *b, const char *summary )
- __attribute__((warn_unused_result));
-int epg_brand_set_season_count ( epg_brand_t *b, uint16_t season_count )
- __attribute__((warn_unused_result));
-int epg_brand_add_season ( epg_brand_t *b, epg_season_t *s, int u )
- __attribute__((warn_unused_result));
-int epg_brand_rem_season ( epg_brand_t *b, epg_season_t *s, int u )
- __attribute__((warn_unused_result));
-int epg_brand_add_episode ( epg_brand_t *b, epg_episode_t *s, int u )
- __attribute__((warn_unused_result));
-int epg_brand_rem_episode ( epg_brand_t *b, epg_episode_t *s, int u )
- __attribute__((warn_unused_result));
-
-/* Season set() calls */
-int epg_season_set_summary ( epg_season_t *s, const char *summary )
- __attribute__((warn_unused_result));
-int epg_season_set_number ( epg_season_t *s, uint16_t number )
- __attribute__((warn_unused_result));
-int epg_season_set_episode_count ( epg_season_t *s, uint16_t episode_count )
- __attribute__((warn_unused_result));
-int epg_season_set_brand ( epg_season_t *s, epg_brand_t *b, int u )
- __attribute__((warn_unused_result));
-int epg_season_add_episode ( epg_season_t *s, epg_episode_t *e, int u )
- __attribute__((warn_unused_result));
-int epg_season_rem_episode ( epg_season_t *s, epg_episode_t *e, int u )
- __attribute__((warn_unused_result));
-
-/* Episode set() calls */
-int epg_episode_set_title ( epg_episode_t *e, const char *title )
- __attribute__((warn_unused_result));
-int epg_episode_set_subtitle ( epg_episode_t *e, const char *subtitle )
- __attribute__((warn_unused_result));
-int epg_episode_set_summary ( epg_episode_t *e, const char *summary )
- __attribute__((warn_unused_result));
-int epg_episode_set_description ( epg_episode_t *e, const char *description )
- __attribute__((warn_unused_result));
-int epg_episode_set_number ( epg_episode_t *e, uint16_t number )
- __attribute__((warn_unused_result));
-int epg_episode_set_part ( epg_episode_t *e,
- uint16_t number, uint16_t count )
- __attribute__((warn_unused_result));
-int epg_episode_set_brand ( epg_episode_t *e, epg_brand_t *b, int u )
- __attribute__((warn_unused_result));
-int epg_episode_set_season ( epg_episode_t *e, epg_season_t *s, int u )
- __attribute__((warn_unused_result));
-int epg_episode_add_broadcast ( epg_episode_t *e, epg_broadcast_t *b, int u )
- __attribute__((warn_unused_result));
-int epg_episode_rem_broadcast ( epg_episode_t *e, epg_broadcast_t *b, int u )
- __attribute__((warn_unused_result));
-
-
-/* Broadcast set() calls */
-int epg_broadcast_set_episode ( epg_broadcast_t *b, epg_episode_t *e, int u )
- __attribute__((warn_unused_result));
-
-// TODO: need to think how this will work with the new hierarchy
void epg_updated ( void );
-void epg_brand_updated ( epg_brand_t *b );
-void epg_season_updated ( epg_season_t *s );
-void epg_episode_updated ( epg_episode_t *e );
-void epg_broadcast_updated ( epg_broadcast_t *b );
/*
* Simple lookup
*/
-epg_brand_t *epg_brand_find_by_uri ( const char *uri, int create );
-epg_season_t *epg_season_find_by_uri ( const char *uri, int create );
-epg_episode_t *epg_episode_find_by_uri ( const char *uri, int create );
-epg_channel_t *epg_channel_find_by_uri ( const char *uri, int create );
-epg_channel_t *epg_channel_find ( const char *uri, const char *name, const char **sname, const int **sid );
-epg_broadcast_t *epg_broadcast_find_by_time ( epg_channel_t *ch, time_t start, time_t stop, int create );
epg_broadcast_t *epg_event_find_by_id(int eventid);
@@ -277,13 +294,6 @@ epg_broadcast_t *epg_event_find_by_id(int eventid);
* Advanced Query
*/
-void epg_query0(epg_query_result_t *eqr, channel_t *ch, channel_tag_t *ct,
- uint8_t type, const char *title);
-void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
- const char *contentgroup, const char *title);
-void epg_query_free(epg_query_result_t *eqr);
-void epg_query_sort(epg_query_result_t *eqr);
-
/*
* Genres?
*/
diff --git a/src/epggrab/pyepg.c b/src/epggrab/pyepg.c
index 2442fed5..5fc95e82 100644
--- a/src/epggrab/pyepg.c
+++ b/src/epggrab/pyepg.c
@@ -42,9 +42,14 @@ static int _pyepg_parse_channel ( htsmsg_t *data )
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
/* Find channel */
- if ((channel = epg_channel_find(id, name, NULL, NULL)) == NULL) return 0;
+ if ((channel = epg_channel_find_by_uri(id, 1)) == NULL) return 0;
// TODO: need to save if created
+ /* Set name */
+ name = htsmsg_xml_get_cdata_str(tags, "name");
+ if ( name ) save |= epg_channel_set_name(channel, name);
+
+
return save;
}
@@ -237,10 +242,7 @@ static int _pyepg_parse_broadcast ( htsmsg_t *data, epg_channel_t *channel )
if (!_pyepg_parse_time(stop, &tm_stop)) return 0;
/* Find broadcast */
- printf("%s find broadcast %ld to %ld\n",
- channel->ec_uri, tm_start, tm_stop);
broadcast = epg_broadcast_find_by_time(channel, tm_start, tm_stop, 1);
- printf("%s broadcast %p\n", channel->ec_uri, broadcast);
if ( broadcast == NULL ) return 0;
/* Set episode */
diff --git a/src/webui/extjs.c b/src/webui/extjs.c
index 03a30b02..d8e4ecec 100644
--- a/src/webui/extjs.c
+++ b/src/webui/extjs.c
@@ -676,6 +676,7 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
//epg_brand_t *eb = NULL;
int start = 0, end, limit, i;
const char *s;
+ char buf[100];
const char *channel = http_arg_get(&hc->hc_req_args, "channel");
const char *tag = http_arg_get(&hc->hc_req_args, "tag");
const char *cgrp = http_arg_get(&hc->hc_req_args, "contentgrp");
@@ -708,24 +709,21 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
end = MIN(start + limit, eqr.eqr_entries);
for(i = start; i < end; i++) {
- //const char *s;
- //eb = NULL; es = NULL; ee = NULL;
e = eqr.eqr_array[i];
ee = e->eb_episode;
- //if (ee) es = ee->ee_season;
- //if (ee) eb = ee->ee_brand;
m = htsmsg_create_map();
-#if TODO
- if(e->e_channel != NULL) {
- htsmsg_add_str(m, "channel", e->e_channel->ch_name);
+ if(e->eb_channel != NULL) {
+ // TODO: this should probably be the real channel!
+ htsmsg_add_str(m, "channel", e->eb_channel->ec_name);
+#if TODO_ADD_FULL_CHANNEL_INFO
htsmsg_add_u32(m, "channelid", e->e_channel->ch_id);
if(e->e_channel->ch_icon != NULL)
htsmsg_add_str(m, "chicon", e->e_channel->ch_icon);
- }
#endif
+ }
if(ee->ee_title != NULL)
htsmsg_add_str(m, "title", ee->ee_title);
@@ -735,12 +733,10 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
else if(ee->ee_summary != NULL)
htsmsg_add_str(m, "description", ee->ee_summary);
-#if TODO
- if(e->e_episode.ee_onscreen != NULL)
- htsmsg_add_str(m, "episode", e->e_episode.ee_onscreen);
-#endif
+ if (epg_episode_get_number_onscreen(ee, buf, 100))
+ htsmsg_add_str(m, "episode", strdup(buf));
-#if TODO
+#if TODO_REMOVE_THIS_QQ
if(e->e_ext_desc != NULL)
htsmsg_add_str(m, "ext_desc", e->e_ext_desc);
@@ -751,15 +747,19 @@ 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->e_id);
+#if TODO_ARE_WE_JUNKING_THIS
+ htsmsg_add_u32(m, "id", e->e_id);
+#endif
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);
-#if TODO
+#if TODO_INCLUDE_GENRE_SUPORT
if((s = epg_content_group_get_name(e->e_content_type)) != NULL)
htsmsg_add_str(m, "contentgrp", s);
+#endif
+#if TODO_UPDATE_DVR_CODE
dvr_entry_t *de;
if((de = dvr_entry_find_by_event(e)) != NULL)
htsmsg_add_str(m, "schedstate", dvr_entry_schedstatus(de));