Some minor changes to code layout, added better epg query support (ala old code) so I can start to get stuff into UI EPG (to help with testing).

This commit is contained in:
Adam Sutton 2012-05-18 12:24:10 +01:00
parent f19f272e5b
commit 6c8c585bc5
4 changed files with 217 additions and 167 deletions

View file

@ -16,8 +16,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO:
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdio.h>
@ -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);
}

250
src/epg.h
View file

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

View file

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

View file

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