Some more work on getting import from pyepg working. I think I have a slightly better idea how things are likely to work. Current broadcast search is probably a bit noddy, but will do for now.

This commit is contained in:
Adam Sutton 2012-05-17 17:38:35 +01:00
parent 9f247955fc
commit cfb0179e80
3 changed files with 562 additions and 197 deletions

544
src/epg.c
View file

@ -16,6 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// TODO:
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdio.h>
@ -38,6 +40,93 @@ struct epg_season_tree epg_seasons;
struct epg_episode_tree epg_episodes;
struct epg_channel_tree epg_channels;
/* **************************************************************************
* Comparators
* *************************************************************************/
static int eb_uri_cmp ( const epg_brand_t *a, const epg_brand_t *b )
{
return strcmp(a->eb_uri, b->eb_uri);
}
static int es_uri_cmp ( const epg_season_t *a, const epg_season_t *b )
{
return strcmp(a->es_uri, b->es_uri);
}
static int ee_uri_cmp ( const epg_episode_t *a, const epg_episode_t *b )
{
return strcmp(a->ee_uri, b->ee_uri);
}
static int ec_uri_cmp ( const epg_channel_t *a, const epg_channel_t *b )
{
return strcmp(a->ec_uri, b->ec_uri);
}
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;
}
/* **************************************************************************
* Testing/Debug
* *************************************************************************/
static void _epg_dump ( void )
{
epg_brand_t *eb;
epg_season_t *es;
epg_episode_t *ee;
epg_channel_t *ec;
epg_broadcast_t *ebc;
printf("dump epg\n");
/* Go down the brand/season/episode */
RB_FOREACH(eb, &epg_brands, eb_link) {
printf("BRAND: %p %s\n", eb, eb->eb_uri);
RB_FOREACH(es, &eb->eb_seasons, es_blink) {
printf(" SEASON: %p %s\n", es, es->es_uri);
RB_FOREACH(ee, &es->es_episodes, ee_slink) {
printf(" EPISODE: %p %s\n", ee, ee->ee_uri);
}
}
RB_FOREACH(ee, &eb->eb_episodes, ee_blink) {
if ( !ee->ee_season ) printf(" EPISODE: %p %s\n", ee, ee->ee_uri);
}
}
RB_FOREACH(es, &epg_seasons, es_link) {
if ( !es->es_brand ) {
printf("SEASON: %p %s\n", es, es->es_uri);
RB_FOREACH(ee, &es->es_episodes, ee_slink) {
printf(" EPISODE: %p %s\n", ee, ee->ee_uri);
}
}
}
RB_FOREACH(ee, &epg_episodes, ee_link) {
if ( !ee->ee_brand && !ee->ee_season ) {
printf("EPISODE: %p %s\n", ee, ee->ee_uri);
}
}
RB_FOREACH(ec, &epg_channels, ec_link) {
printf("CHANNEL: %s\n", ec->ec_uri);
RB_FOREACH(ebc, &ec->ec_schedule, eb_slink) {
if ( ebc->eb_episode ) {
printf(" BROADCAST: %s @ %ld to %ld\n", ebc->eb_episode->ee_uri,
ebc->eb_start, ebc->eb_stop);
}
}
}
}
/* **************************************************************************
* Setup / Update
* *************************************************************************/
void epg_init ( void )
{
}
@ -48,80 +137,13 @@ void epg_save ( void )
void epg_updated ( void )
{
_epg_dump();
}
int epg_brand_set_title ( epg_brand_t *brand, const char *title )
{
return 0;
}
int epg_brand_set_summary ( epg_brand_t *brand, const char *summary )
{
return 0;
}
int epg_brand_set_season_count ( epg_brand_t *brand, uint16_t count )
{
return 0;
}
int epg_season_set_brand ( epg_season_t *season, epg_brand_t *brand )
{
return 0;
}
int epg_season_set_summary ( epg_season_t *season, const char *summary )
{
return 0;
}
int epg_season_set_episode_count ( epg_season_t *season, uint16_t count )
{
return 0;
}
int epg_season_set_number ( epg_season_t *season, uint16_t number )
{
return 0;
}
int epg_episode_set_title ( epg_episode_t *episode, const char *title )
{
return 0;
}
int epg_episode_set_subtitle ( epg_episode_t *episode, const char *title )
{
return 0;
}
int epg_episode_set_summary ( epg_episode_t *episode, const char *summary )
{
return 0;
}
int epg_episode_set_description ( epg_episode_t *episode, const char *desc )
{
return 0;
}
int epg_episode_set_brand ( epg_episode_t *episode, epg_brand_t *brand )
{
return 0;
}
int epg_episode_set_season ( epg_episode_t *episode, epg_season_t *season )
{
return 0;
}
int epg_episode_set_number ( epg_episode_t *episode, uint16_t number )
{
return 0;
}
int epg_episode_set_part ( epg_episode_t *episode, uint16_t part, uint16_t count )
{
return 0;
}
static int eb_uri_cmp ( const epg_brand_t *a, const epg_brand_t *b )
{
return strcmp(a->eb_uri, b->eb_uri);
}
/* **************************************************************************
* Brand
* *************************************************************************/
epg_brand_t* epg_brand_find_by_uri ( const char *id, int create )
{
@ -131,31 +153,123 @@ epg_brand_t* epg_brand_find_by_uri ( const char *id, int create )
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_brand_t));
skel->eb_uri = (char*)id;
/* Find */
skel->eb_uri = (char*)id;
eb = RB_FIND(&epg_brands, skel, eb_link, eb_uri_cmp);
if ( eb ) printf("found brand %s @ %p\n", id, eb);
if ( !create ) {
eb = RB_FIND(&epg_brands, skel, eb_link, eb_uri_cmp);
/* Create */
if ( !eb && create ) {
} else {
eb = RB_INSERT_SORTED(&epg_brands, skel, eb_link, eb_uri_cmp);
if ( eb == NULL ) {
eb = skel;
skel = NULL;
eb->eb_uri = strdup(id);
printf("create brand %s @ %p\n", id, eb);
}
}
return eb;
}
static int es_uri_cmp ( const epg_season_t *a, const epg_season_t *b )
int epg_brand_set_title ( epg_brand_t *brand, const char *title )
{
return strcmp(a->es_uri, b->es_uri);
int save = 0;
if ( !brand || !title ) return 0;
if ( !brand->eb_title || strcmp(brand->eb_title, title) ) {
if ( brand->eb_title ) free(brand->eb_title);
brand->eb_title = strdup(title);
save = 1;
}
return save;
}
int epg_brand_set_summary ( epg_brand_t *brand, const char *summary )
{
int save = 0;
if ( !brand || !summary ) return 0;
if ( !brand->eb_summary || strcmp(brand->eb_summary, summary) ) {
if ( brand->eb_summary ) free(brand->eb_summary);
brand->eb_summary = strdup(summary);
save = 1;
}
return save;
}
int epg_brand_set_season_count ( epg_brand_t *brand, uint16_t count )
{
// TODO: could set only if less?
int save = 0;
if ( !brand || !count ) return 0;
if ( brand->eb_season_count != count ) {
brand->eb_season_count = count;
save = 1;
}
return save;
}
int epg_brand_add_season ( epg_brand_t *brand, epg_season_t *season, int u )
{
int save = 0;
epg_season_t *es;
if ( !brand || !season ) return 0;
es = RB_INSERT_SORTED(&brand->eb_seasons, season, es_blink, es_uri_cmp);
if ( es == NULL ) {
if ( u ) save |= epg_season_set_brand(season, brand, 0);
save = 1;
}
// TODO?: else assert(es == season)
return save;
}
int epg_brand_rem_season ( epg_brand_t *brand, epg_season_t *season, int u )
{
int save = 0;
epg_season_t *es;
if ( !brand || !season ) return 0;
es = RB_FIND(&brand->eb_seasons, season, es_blink, es_uri_cmp);
if ( es != NULL ) {
// TODO: assert(es == season)
if ( u ) save |= epg_season_set_brand(season, NULL, 0); // TODO: this will do nothing
RB_REMOVE(&brand->eb_seasons, season, es_blink);
save = 1;
}
return save;
}
int epg_brand_add_episode ( epg_brand_t *brand, epg_episode_t *episode, int u )
{
int save = 0;
epg_episode_t *ee;
if ( !brand || !episode ) return 0;
ee = RB_INSERT_SORTED(&brand->eb_episodes, episode, ee_blink, ee_uri_cmp);
if ( ee == NULL ) {
if ( u ) save |= epg_episode_set_brand(episode, brand, 0);
save = 1;
}
// TODO?: else assert(ee == episode)
return save;
}
int epg_brand_rem_episode ( epg_brand_t *brand, epg_episode_t *episode, int u )
{
int save = 0;
epg_episode_t *ee;
if ( !brand || !episode ) return 0;
ee = RB_FIND(&brand->eb_episodes, episode, ee_blink, ee_uri_cmp);
if ( ee != NULL ) {
// TODO?: assert(ee == episode)
if ( u ) save |= epg_episode_set_brand(episode, NULL, 0); // TODO: will do nothing
RB_REMOVE(&brand->eb_episodes, episode, ee_blink);
save = 1;
}
return save;
}
/* **************************************************************************
* Season
* *************************************************************************/
epg_season_t* epg_season_find_by_uri ( const char *id, int create )
{
epg_season_t *es;
@ -164,31 +278,108 @@ epg_season_t* epg_season_find_by_uri ( const char *id, int create )
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_season_t));
skel->es_uri = (char*)id;
/* Find */
skel->es_uri = (char*)id;
es = RB_FIND(&epg_seasons, skel, es_link, es_uri_cmp);
if ( es ) printf("found season %s @ %p\n", id, es);
if ( !create ) {
es = RB_FIND(&epg_seasons, skel, es_link, es_uri_cmp);
/* Create */
if ( !es && create ) {
} else {
es = RB_INSERT_SORTED(&epg_seasons, skel, es_link, es_uri_cmp);
if ( es == NULL ) {
es = skel;
skel = NULL;
es->es_uri = strdup(id);
printf("create season %s @ %p\n", id, es);
}
}
return es;
}
static int ee_uri_cmp ( const epg_episode_t *a, const epg_episode_t *b )
int epg_season_set_summary ( epg_season_t *season, const char *summary )
{
return strcmp(a->ee_uri, b->ee_uri);
int save = 0;
if ( !season || !summary ) return 0;
if ( !season->es_summary || strcmp(season->es_summary, summary) ) {
if ( season->es_summary ) free(season->es_summary);
season->es_summary = strdup(summary);
save = 1;
}
return save;
}
int epg_season_set_episode_count ( epg_season_t *season, uint16_t count )
{
int save = 0;
if ( !season || !count ) return 0;
// TODO: should we only update if number is larger
if ( season->es_episode_count != count ) {
season->es_episode_count = count;
save = 1;
}
return save;
}
int epg_season_set_number ( epg_season_t *season, uint16_t number )
{
int save = 0;
if ( !season || !number ) return 0;
if ( season->es_number != number ) {
season->es_number = number;
save = 1;
}
return save;
}
int epg_season_set_brand ( epg_season_t *season, epg_brand_t *brand, int u )
{
int save = 0;
if ( !season || !brand ) return 0;
if ( season->es_brand != brand ) {
if ( u ) save |= epg_brand_rem_season(season->es_brand, season, 0);
season->es_brand = brand;
if ( u ) save |= epg_brand_add_season(season->es_brand, season, 0);
save = 1;
}
return save;
}
int epg_season_add_episode
( epg_season_t *season, epg_episode_t *episode, int u )
{
int save = 0;
epg_episode_t *ee;
if ( !season || !episode ) return 0;
ee = RB_INSERT_SORTED(&season->es_episodes, episode, ee_slink, ee_uri_cmp);
if ( ee == NULL ) {
if ( u ) save |= epg_episode_set_season(episode, season, 0);
save = 1;
}
// TODO?: else assert(ee == episode)
return save;
}
int epg_season_rem_episode
( epg_season_t *season, epg_episode_t *episode, int u )
{
int save = 0;
epg_episode_t *ee;
if ( !season || !episode ) return 0;
ee = RB_FIND(&season->es_episodes, episode, ee_slink, ee_uri_cmp);
if ( ee != NULL ) {
// TODO?: assert(ee == episode)
if ( u ) save |= epg_episode_set_season(episode, NULL, 0); // does nothing
RB_REMOVE(&season->es_episodes, episode, ee_slink);
save = 1;
}
return save;
}
/* **************************************************************************
* Episode
* *************************************************************************/
epg_episode_t* epg_episode_find_by_uri ( const char *id, int create )
{
epg_episode_t *ee;
@ -197,62 +388,215 @@ epg_episode_t* epg_episode_find_by_uri ( const char *id, int create )
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_episode_t));
skel->ee_uri = (char*)id;
/* Find */
skel->ee_uri = (char*)id;
ee = RB_FIND(&epg_episodes, skel, ee_link, ee_uri_cmp);
if ( ee ) printf("found episode %s @ %p\n", id, ee);
if ( !create ) {
ee = RB_FIND(&epg_episodes, skel, ee_link, ee_uri_cmp);
/* Create */
if ( !ee && create ) {
} else {
ee = RB_INSERT_SORTED(&epg_episodes, skel, ee_link, ee_uri_cmp);
if ( ee == NULL ) {
ee = skel;
skel = NULL;
ee->ee_uri = strdup(id);
printf("create epsiode %s @ %p\n", id, ee);
}
}
return ee;
}
static int ec_uri_cmp ( const epg_channel_t *a, const epg_channel_t *b )
int epg_episode_set_title ( epg_episode_t *episode, const char *title )
{
return strcmp(a->ec_uri, b->ec_uri);
int save = 0;
if ( !episode || !title ) return 0;
if ( !episode->ee_title || strcmp(episode->ee_title, title) ) {
if ( episode->ee_title ) free(episode->ee_title);
episode->ee_title = strdup(title);
save = 1;
}
return save;
}
int epg_episode_set_subtitle ( epg_episode_t *episode, const char *subtitle )
{
int save = 0;
if ( !episode || !subtitle ) return 0;
if ( !episode->ee_subtitle || strcmp(episode->ee_subtitle, subtitle) ) {
if ( episode->ee_subtitle ) free(episode->ee_subtitle);
episode->ee_subtitle = strdup(subtitle);
save = 1;
}
return save;
}
int epg_episode_set_summary ( epg_episode_t *episode, const char *summary )
{
int save = 0;
if ( !episode || !summary ) return 0;
if ( !episode->ee_summary || strcmp(episode->ee_summary, summary) ) {
if ( episode->ee_summary ) free(episode->ee_summary);
episode->ee_summary = strdup(summary);
save = 1;
}
return save;
}
int epg_episode_set_description ( epg_episode_t *episode, const char *desc )
{
int save = 0;
if ( !episode || !desc ) return 0;
if ( !episode->ee_description || strcmp(episode->ee_description, desc) ) {
if ( episode->ee_description ) free(episode->ee_description);
episode->ee_description = strdup(desc);
save = 1;
}
return save;
}
int epg_episode_set_number ( epg_episode_t *episode, uint16_t number )
{
int save = 0;
if ( !episode || !number ) return 0;
if ( episode->ee_number != number ) {
episode->ee_number = number;
save = 1;
}
return save;
}
int epg_episode_set_part ( epg_episode_t *episode, uint16_t part, uint16_t count )
{
int save = 0;
// TODO: could treat part/count independently
if ( !episode || !part || !count ) return 0;
if ( episode->ee_part_number != part ) {
episode->ee_part_number = part;
save |= 1;
}
if ( episode->ee_part_count != count ) {
episode->ee_part_count = count;
save |= 1;
}
return save;
}
int epg_episode_set_brand ( epg_episode_t *episode, epg_brand_t *brand, int u )
{
int save = 0;
if ( !episode || !brand ) return 0;
if ( episode->ee_brand != brand ) {
if ( u ) save |= epg_brand_rem_episode(episode->ee_brand, episode, 0); /// does nothing
episode->ee_brand = brand;
if ( u ) save |= epg_brand_add_episode(episode->ee_brand, episode, 0);
save |= 1;
}
return save;
}
int epg_episode_set_season ( epg_episode_t *episode, epg_season_t *season, int u )
{
int save = 0;
if ( !episode || !season ) return 0;
if ( episode->ee_season != season ) {
if ( u ) save |= epg_season_rem_episode(episode->ee_season, episode, 0);
episode->ee_season = season;
if ( u && episode->ee_season ) {
save |= epg_season_add_episode(episode->ee_season, episode, 0);
save |= epg_brand_add_episode(episode->ee_season->es_brand, episode, 0);
// TODO: is this the right place?
}
save = 1;
}
return save;
}
/* **************************************************************************
* Broadcast
* *************************************************************************/
// Note: will find broadcast playing at this time (not necessarily
// one that starts at this time)
//
// Note: do we need to pass in stop?
epg_broadcast_t* epg_broadcast_find_by_time
( epg_channel_t *channel, time_t start, time_t stop, int create )
{
epg_broadcast_t *eb;
static epg_broadcast_t *skel = NULL;
if ( !channel || !start || !stop ) return 0;
if ( stop < start ) return 0;
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_broadcast_t));
skel->eb_start = start;
skel->eb_stop = stop;
/* Find */
if ( !create ) {
eb = RB_FIND(&channel->ec_schedule, skel, eb_slink, ebc_win_cmp);
/* Create */
} else {
eb = RB_INSERT_SORTED(&channel->ec_schedule, skel, eb_slink, ebc_win_cmp);
if ( eb == NULL ) {
eb = skel;
skel = NULL;
}
}
return eb;
}
int epg_broadcast_set_episode
( epg_broadcast_t *broadcast, epg_episode_t *episode, int u )
{
int save = 0;
if ( !broadcast || !episode ) return 0;
if ( broadcast->eb_episode != episode ) {
broadcast->eb_episode = episode;
//if ( u ) epg_episode_add_broadcast(episode, broadcast, 0);
save = 1;
}
return save;
}
/* **************************************************************************
* Channel
* *************************************************************************/
epg_channel_t* epg_channel_find_by_uri ( const char *id, int create )
{
epg_channel_t *ec;
static epg_channel_t *skel = NULL;
// TODO: is it really that beneficial to save a few bytes on the stack?
// TODO: does this really need to be the global lock?
lock_assert(&global_lock); // pointless!
if ( skel == NULL ) skel = calloc(1, sizeof(epg_channel_t));
skel->ec_uri = (char*)id;
/* Find */
skel->ec_uri = (char*)id;
ec = RB_FIND(&epg_channels, skel, ec_link, ec_uri_cmp);
if ( ec ) printf("found channel %s @ %p\n", id, ec);
if ( !create ) {
ec = RB_FIND(&epg_channels, skel, ec_link, ec_uri_cmp);
/* Create */
if ( !ec && create ) {
} else {
ec = RB_INSERT_SORTED(&epg_channels, skel, ec_link, ec_uri_cmp);
if ( ec == NULL ) {
ec = skel;
skel = NULL;
ec->ec_uri = strdup(id);
printf("create channel %s @ %p\n", id, ec);
}
}
return ec;
}
epg_channel_t* epg_channel_find ( const char *id, const char *name, const char **sname, const int **sid )
epg_channel_t* epg_channel_find
( const char *id, const char *name, const char **sname, const int **sid )
{
epg_channel_t* channel;

172
src/epg.h
View file

@ -34,10 +34,16 @@ struct epg_season;
struct epg_episode;
struct epg_broadcast;
struct epg_channel;
RB_HEAD(epg_brand_tree, epg_brand);
RB_HEAD(epg_season_tree, epg_season);
RB_HEAD(epg_episode_tree, epg_episode);
RB_HEAD(epg_channel_tree, epg_channel);
/*
* Map types
*/
RB_HEAD(epg_brand_tree, epg_brand);
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
@ -45,19 +51,18 @@ RB_HEAD(epg_channel_tree, epg_channel);
*/
typedef struct epg_brand
{
RB_ENTRY(epg_brand) eb_link;
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
RB_ENTRY(epg_brand) eb_link; ///< Global list link
LIST_HEAD(, epg_season_t) eb_seasons; ///< Attached seasons
LIST_HEAD(, epg_episode_t) eb_episodes; ///< Un(-seasoned) episodes??
char *eb_uri; ///< Grabber URI
char *eb_title; ///< Brand name
char *eb_summary; ///< Brand summary
uint16_t eb_season_count; ///< Total number of seasons
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
int eb_refcount; ///< Reference counting
} epg_brand_t;
/*
@ -65,17 +70,18 @@ typedef struct epg_brand
*/
typedef struct epg_season
{
RB_ENTRY(epg_season) es_link;
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
RB_ENTRY(epg_season) es_link; ///< Global list link
RB_ENTRY(epg_season) es_blink; ///< Brand list link
epg_brand_t *es_brand; ///< Parent brand
LIST_HEAD(, epg_episode_t) es_episodes; ///< Child episodes
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
int es_refcount; ///< Reference counting
epg_brand_t *es_brand; ///< Parent brand
struct epg_episode_tree es_episodes; ///< Episode list
int es_refcount; ///< Reference counting
} epg_season_t;
@ -84,23 +90,26 @@ typedef struct epg_season
*/
typedef struct epg_episode
{
RB_ENTRY(epg_episode) ee_link;
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 (TODO: need a list?)
uint16_t ee_number; ///< The episode number
uint16_t ee_part_number; ///< For multipart episodes
uint16_t ee_part_count; ///< For multipart episodes
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_brand_t *ee_brand; ///< (Grand-)Parent brand
epg_season_t *ee_season; ///< Parent season
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
// 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
int ee_refcount; ///< Reference counting
epg_brand_t *ee_brand; ///< (Grand-)Parent brand
epg_season_t *ee_season; ///< Parent season
struct epg_broadcast_tree ee_broadcasts; ///< Broadcast list
int ee_refcount; ///< Reference counting
} epg_episode_t;
/*
@ -108,27 +117,33 @@ typedef struct epg_episode
*/
typedef struct epg_broadcast
{
int eb_id; ///< Internal ID
int eb_dvb_id; ///< DVB identifier
time_t eb_start; ///< Start time
time_t eb_stop; ///< End time
epg_episode_t *eb_episode; ///< Episode shown
channel_t* eb_channel; ///< Channel being broadcast on
RB_ENTRY(epg_broadcast) eb_slink; ///< Schedule link
RB_ENTRY(epg_broadcast) eb_elink; ///< Episode link
int eb_id; ///< Internal ID
int eb_dvb_id; ///< DVB identifier
time_t eb_start; ///< Start time
time_t eb_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 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)
/* 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 eb_deafsigned; ///< In screen signing
uint8_t eb_subtitled; ///< Teletext subtitles
uint8_t eb_audio_desc; ///< Audio description
/* Misc flags */
uint8_t eb_new; ///< New series / file premiere
uint8_t eb_repeat; ///< Repeat screening
uint8_t eb_new; ///< New series / file premiere
uint8_t eb_repeat; ///< Repeat screening
epg_episode_t *eb_episode; ///< Episode shown
channel_t *eb_channel; ///< Channel being broadcast on
int eb_refcount; ///< Reference counting
} epg_broadcast_t;
/*
@ -136,13 +151,16 @@ typedef struct epg_broadcast
*/
typedef struct epg_channel
{
RB_ENTRY(epg_channel) ec_link; ///< Link to channel map
char *ec_uri; ///< Internal ID (defined by grabbers)
char **ec_sname; ///< DVB service name (for searching)
int **ec_sid; ///< DVB service ids (for searching)
channel_t *ec_channel; ///< Link to real channel
// TODO: further links?
// TODO: reference counter?
RB_ENTRY(epg_channel) ec_link; ///< Global link
char *ec_uri; ///< Channel URI
char **ec_sname; ///< DVB svc names (to map)
int **ec_sid; ///< DVB svc ids (to map)
channel_t *ec_channel; ///< Link to real channel
struct epg_broadcast_tree ec_schedule; ///< Schedule (broadcasts)
} epg_channel_t;
/*
@ -178,30 +196,36 @@ void epg_save(void);
*/
/* Brand set() calls */
int epg_brand_set_uri ( epg_brand_t *b, const char *uri )
__attribute__((warn_unused_result));
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));
__attribute__((warn_unused_result));
int epg_brand_set_season_count ( epg_brand_t *b, uint16_t season_count )
__attribute__((warn_unused_result));
__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_uri ( epg_season_t *s, const char *uri )
__attribute__((warn_unused_result));
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 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_uri ( epg_episode_t *e, const char *uri )
__attribute__((warn_unused_result));
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 )
@ -215,14 +239,14 @@ int epg_episode_set_number ( epg_episode_t *e, uint16_t number )
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 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 epg_episode_set_season ( epg_episode_t *e, epg_season_t *s, int u )
__attribute__((warn_unused_result));
// Note: you don't need to call set_brand() if you set_season() using a season
// on which you've called set_brand()
/* 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 );
@ -240,9 +264,7 @@ 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 ( epg_channel_t *ch, epg_episode_t *ep, time_t start, time_t stop, int create );
epg_broadcast_t *epg_event_find_by_time(channel_t *ch, time_t t);
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);

View file

@ -2,9 +2,11 @@
* PyEPG grabber
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "htsmsg_xml.h"
#include "tvheadend.h"
#include "spawn.h"
@ -15,10 +17,15 @@
* Parsing
* *************************************************************************/
static int _pyepg_parse_time ( const char *str, time_t *tm )
static int _pyepg_parse_time ( const char *str, time_t *out )
{
// TODO: implement
return 0;
int ret = 0;
struct tm tm;
if ( strptime(str, "%F %T %z", &tm) != NULL ) {
*out = mktime(&tm);
ret = 1;
}
return ret;
}
static int _pyepg_parse_channel ( htsmsg_t *data )
@ -33,7 +40,6 @@ static int _pyepg_parse_channel ( htsmsg_t *data )
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((id = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
printf("parse_channel(%s)\n", id);
/* Find channel */
if ((channel = epg_channel_find(id, name, NULL, NULL)) == NULL) return 0;
@ -55,7 +61,6 @@ static int _pyepg_parse_brand ( htsmsg_t *data )
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
printf("parse_brand(%s)\n", str);
/* Find brand */
if ((brand = epg_brand_find_by_uri(str, 1)) == NULL) return 0;
@ -100,18 +105,15 @@ static int _pyepg_parse_season ( htsmsg_t *data )
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
printf("parse_season(%s)\n", str);
/* Find series */
if ((season = epg_season_find_by_uri(str, 1)) == NULL) return 0;
// TODO: do we need to save if created?
printf("have season\n");
/* Set brand */
if ((str = htsmsg_get_str(attr, "brand"))) {
printf("lookup brand(%s)\n", str);
if ((brand = epg_brand_find_by_uri(str, 0))) {
save |= epg_season_set_brand(season, brand);
save |= epg_season_set_brand(season, brand, 1);
}
}
@ -160,26 +162,22 @@ static int _pyepg_parse_episode ( htsmsg_t *data )
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "id")) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
printf("parse_episode(%s)\n", str);
/* Find episode */
if ((episode = epg_episode_find_by_uri(str, 1)) == NULL) return 0;
// TODO: do we need to save if created?
printf("have episode\n");
/* Set brand */
if ((str = htsmsg_get_str(attr, "brand"))) {
printf("lookup brand(%s)\n", str);
if ((brand = epg_brand_find_by_uri(str, 0))) {
save |= epg_episode_set_brand(episode, brand);
save |= epg_episode_set_brand(episode, brand, 1);
}
}
/* Set season */
if ((str = htsmsg_get_str(attr, "series"))) {
printf("lookup season(%s)\n", str);
if ((season = epg_season_find_by_uri(str, 0))) {
save |= epg_episode_set_season(episode, season);
save |= epg_episode_set_season(episode, season, 1);
}
}
@ -230,7 +228,6 @@ static int _pyepg_parse_broadcast ( htsmsg_t *data, epg_channel_t *channel )
if ((id = htsmsg_get_str(attr, "episode")) == NULL) return 0;
if ((start = htsmsg_get_str(attr, "start")) == NULL ) return 0;
if ((stop = htsmsg_get_str(attr, "stop")) == NULL ) return 0;
printf("parse_broadcast(ep=%s, start=%s, stop=%s)\n", id, start, stop);
/* Find episode */
if ((episode = epg_episode_find_by_uri(id, 1)) == NULL) return 0;
@ -240,9 +237,14 @@ static int _pyepg_parse_broadcast ( htsmsg_t *data, epg_channel_t *channel )
if (!_pyepg_parse_time(stop, &tm_stop)) return 0;
/* Find broadcast */
// TODO: need to think about this
if ((broadcast = epg_broadcast_find(channel, episode, tm_start, tm_stop, 1)) == NULL) return 0;
save = 1;
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 */
save |= epg_broadcast_set_episode(broadcast, episode, 1);
/* TODO: extra metadata */
@ -261,7 +263,6 @@ static int _pyepg_parse_schedule ( htsmsg_t *data )
if ((attr = htsmsg_get_map(data, "attrib")) == NULL) return 0;
if ((str = htsmsg_get_str(attr, "channel")) == NULL) return 0;
printf("parse_schedule(ch=%s)\n", str);
if ((channel = epg_channel_find_by_uri(str, 0)) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
@ -279,7 +280,6 @@ static int _pyepg_parse_epg ( htsmsg_t *data )
int save = 0;
htsmsg_t *tags;
htsmsg_field_t *f;
printf("parse_epg()\n");
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
@ -304,7 +304,6 @@ static int _pyepg_parse ( htsmsg_t *data )
{
htsmsg_t *tags, *epg;
epggrab_module_t *mod;
printf("parse()\n");
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;