Now have full EPG save/load, I have included internal IDs in all objects though I think they are redundant (and except for broadcast they are not saved).

This commit is contained in:
Adam Sutton 2012-05-22 16:20:25 +01:00
parent 2224146b2b
commit aba9000a62
2 changed files with 351 additions and 62 deletions

379
src/epg.c
View file

@ -33,17 +33,28 @@
#include "dvr/dvr.h"
#include "htsp.h"
#include "htsmsg_binary.h"
#include "epggrab.h"
struct epg_brand_tree epg_brands;
struct epg_season_tree epg_seasons;
struct epg_episode_tree epg_episodes;
struct epg_channel_tree epg_channels;
/* Element lists */
struct epg_brand_tree epg_brands;
struct epg_season_tree epg_seasons;
struct epg_episode_tree epg_episodes;
struct epg_channel_tree epg_channels;
struct epg_broadcast_tree epg_broadcasts; // TODO: do we need this
/* Unlinked channels */
LIST_HEAD(epg_unlinked_channel_list1, epg_channel);
LIST_HEAD(epg_unlinked_channel_list2, channel);
struct epg_unlinked_channel_list1 epg_unlinked_channels1;
struct epg_unlinked_channel_list2 epg_unlinked_channels2;
/* Global counters */
static uint32_t _epg_channel_idx = 0;
static uint32_t _epg_brand_idx = 0;
static uint32_t _epg_season_idx = 0;
static uint32_t _epg_episode_idx = 0;
static uint32_t _epg_broadcast_idx = 0;
/* **************************************************************************
* Comparators
* *************************************************************************/
@ -170,6 +181,13 @@ static int _epg_write ( int fd, htsmsg_t *m )
return ret;
}
static int _epg_write_sect ( int fd, const char *sect )
{
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "__section__", sect);
return _epg_write(fd, m);
}
void epg_save ( void )
{
int fd;
@ -183,18 +201,25 @@ void epg_save ( void )
// TODO: requires markers in the file or some other means of
// determining where the various object types are?
fd = hts_settings_open_file(1, "epgdb");
/* Channels */
if ( _epg_write_sect(fd, "channels") ) return;
RB_FOREACH(ec, &epg_channels, ec_link) {
if (_epg_write(fd, epg_channel_serialize(ec))) return;
}
if ( _epg_write_sect(fd, "brands") ) return;
RB_FOREACH(eb, &epg_brands, eb_link) {
if (_epg_write(fd, epg_brand_serialize(eb))) return;
}
if ( _epg_write_sect(fd, "seasons") ) return;
RB_FOREACH(es, &epg_seasons, es_link) {
if (_epg_write(fd, epg_season_serialize(es))) return;
}
if ( _epg_write_sect(fd, "episodes") ) return;
RB_FOREACH(ee, &epg_episodes, ee_link) {
if (_epg_write(fd, epg_episode_serialize(ee))) return;
}
if ( _epg_write_sect(fd, "broadcasts") ) return;
RB_FOREACH(ec, &epg_channels, ec_link) {
RB_FOREACH(ebc, &ec->ec_schedule, eb_slink) {
if (_epg_write(fd, epg_broadcast_serialize(ebc))) return;
@ -204,26 +229,102 @@ void epg_save ( void )
void epg_init ( void )
{
int save, fd;
struct stat st;
int fd = hts_settings_open_file(0, "epgdb");
size_t remain;
uint8_t *mem, *rp;
fstat(fd, &st);
char *sect = NULL;
const char *s;
epggrab_stats_t stats;
/* Map file to memory */
fd = hts_settings_open_file(0, "epgdb");
if ( fd < 0 ) {
tvhlog(LOG_DEBUG, "epg", "database does not exist");
return;
}
if ( fstat(fd, &st) != 0 ) {
tvhlog(LOG_ERR, "epg", "failed to detect database size");
return;
}
if ( !st.st_size ) {
tvhlog(LOG_DEBUG, "epg", "database is empty");
return;
}
remain = st.st_size;
rp = mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
//TODO:if ( mem == MAP_FAILED ) return;
remain = st.st_size;
if ( mem == MAP_FAILED ) {
tvhlog(LOG_ERR, "epg", "failed to mmap database");
return;
}
/* Process */
memset(&stats, 0, sizeof(stats));
while ( remain > 4 ) {
// TODO: would be nice if htsmsg_binary handled this for us!
/* Get message length */
int msglen = (rp[0] << 24) | (rp[1] << 16) | (rp[2] << 8) | rp[3];
remain -= 4;
rp += 4;
remain -= 4;
rp += 4;
/* Extract message */
htsmsg_t *m = htsmsg_binary_deserialize(rp, msglen, NULL);
/* Process */
if(m) {
//htsmsg_print(m);
/* New section */
s = htsmsg_get_str(m, "__section__");
if (s) {
if (sect) free(sect);
sect = strdup(s);
/* Channel */
} else if ( !strcmp(sect, "channels") ) {
if (epg_channel_deserialize(m, 1, &save)) stats.channels.total++;
/* Brand */
} else if ( !strcmp(sect, "brands") ) {
if (epg_brand_deserialize(m, 1, &save)) stats.brands.total++;
/* Season */
} else if ( !strcmp(sect, "seasons") ) {
if (epg_season_deserialize(m, 1, &save)) stats.seasons.total++;
/* Episode */
} else if ( !strcmp(sect, "episodes") ) {
if (epg_episode_deserialize(m, 1, &save)) stats.episodes.total++;
/* Broadcasts */
} else if ( !strcmp(sect, "broadcasts") ) {
if (epg_broadcast_deserialize(m, 1, &save)) stats.broadcasts.total++;
/* Unknown */
} else {
tvhlog(LOG_DEBUG, "epg", "malformed database section [%s]", sect);
//htsmsg_print(m);
}
/* Cleanup */
htsmsg_destroy(m);
}
rp += msglen;
/* Next */
rp += msglen;
remain -= msglen;
}
/* Stats */
tvhlog(LOG_DEBUG, "epg", "database loaded");
tvhlog(LOG_DEBUG, "epg", "channels %d", stats.channels.total);
tvhlog(LOG_DEBUG, "epg", "brands %d", stats.brands.total);
tvhlog(LOG_DEBUG, "epg", "seasons %d", stats.seasons.total);
tvhlog(LOG_DEBUG, "epg", "episodes %d", stats.episodes.total);
tvhlog(LOG_DEBUG, "epg", "broadcasts %d", stats.broadcasts.total);
/* Close file */
munmap(mem, st.st_size);
close(fd);
}
@ -267,6 +368,7 @@ epg_brand_t* epg_brand_find_by_uri
if ( skel == NULL ) skel = calloc(1, sizeof(epg_brand_t));
skel->eb_uri = (char*)id;
skel->eb_id = _epg_brand_idx;
/* Find */
if ( !create ) {
@ -276,16 +378,26 @@ epg_brand_t* epg_brand_find_by_uri
} else {
eb = RB_INSERT_SORTED(&epg_brands, skel, eb_link, eb_uri_cmp);
if ( eb == NULL ) {
eb = skel;
skel = NULL;
*save |= 1;
eb = skel;
skel = NULL;
eb->eb_uri = strdup(id);
*save |= 1;
_epg_brand_idx++;
}
}
return eb;
}
epg_brand_t *epg_brand_find_by_id ( uint32_t id )
{
epg_brand_t *eb;
RB_FOREACH(eb, &epg_brands, eb_link) {
if ( eb->eb_id == id ) return eb;
}
return NULL;
}
int epg_brand_set_title ( epg_brand_t *brand, const char *title )
{
int save = 0;
@ -383,11 +495,9 @@ int epg_brand_rem_episode ( epg_brand_t *brand, epg_episode_t *episode, int u )
htsmsg_t *epg_brand_serialize ( epg_brand_t *brand )
{
htsmsg_t *m;
if ( !brand ) return NULL;
if ( !brand || !brand->eb_uri ) return NULL;
m = htsmsg_create_map();
// TODO: ID
if (brand->eb_uri)
htsmsg_add_str(m, "uri", brand->eb_uri);
htsmsg_add_str(m, "uri", brand->eb_uri);
if (brand->eb_title)
htsmsg_add_str(m, "title", brand->eb_title);
if (brand->eb_summary)
@ -397,6 +507,25 @@ htsmsg_t *epg_brand_serialize ( epg_brand_t *brand )
return m;
}
epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create, int *save )
{
epg_brand_t *eb;
uint32_t u32;
const char *str;
if ( !(str = htsmsg_get_str(m, "uri")) ) return NULL;
if ( !(eb = epg_brand_find_by_uri(str, create, save)) ) return NULL;
if ( (str = htsmsg_get_str(m, "title")) )
*save |= epg_brand_set_title(eb, str);
if ( (str = htsmsg_get_str(m, "summary")) )
*save |= epg_brand_set_summary(eb, str);
if ( !htsmsg_get_u32(m, "season-count", &u32) )
*save |= epg_brand_set_season_count(eb, u32);
return eb;
}
/* **************************************************************************
* Season
* *************************************************************************/
@ -411,6 +540,7 @@ epg_season_t* epg_season_find_by_uri
if ( skel == NULL ) skel = calloc(1, sizeof(epg_season_t));
skel->es_uri = (char*)id;
skel->es_id = _epg_season_idx;
/* Find */
if ( !create ) {
@ -420,16 +550,26 @@ epg_season_t* epg_season_find_by_uri
} else {
es = RB_INSERT_SORTED(&epg_seasons, skel, es_link, es_uri_cmp);
if ( es == NULL ) {
es = skel;
skel = NULL;
*save |= 1;
es = skel;
skel = NULL;
es->es_uri = strdup(id);
*save |= 1;
_epg_season_idx++;
}
}
return es;
}
epg_season_t *epg_season_find_by_id ( uint32_t id )
{
epg_season_t *es;
RB_FOREACH(es, &epg_seasons, es_link) {
if ( es->es_id == id ) return es;
}
return NULL;
}
int epg_season_set_summary ( epg_season_t *season, const char *summary )
{
int save = 0;
@ -512,10 +652,9 @@ int epg_season_rem_episode
htsmsg_t *epg_season_serialize ( epg_season_t *season )
{
htsmsg_t *m;
if (!season) return NULL;
if (!season || !season->es_uri) return NULL;
m = htsmsg_create_map();
if (season->es_uri)
htsmsg_add_str(m, "uri", season->es_uri);
htsmsg_add_str(m, "uri", season->es_uri);
if (season->es_summary)
htsmsg_add_str(m, "summary", season->es_summary);
if (season->es_number)
@ -523,11 +662,34 @@ htsmsg_t *epg_season_serialize ( epg_season_t *season )
if (season->es_episode_count)
htsmsg_add_u32(m, "episode-count", season->es_episode_count);
if (season->es_brand)
htsmsg_add_str(m, "brand-id", season->es_brand->eb_uri);
// TODO: change to ID
htsmsg_add_str(m, "brand", season->es_brand->eb_uri);
return m;
}
epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save )
{
epg_season_t *es;
epg_brand_t *eb;
uint32_t u32;
const char *str;
if ( !(str = htsmsg_get_str(m, "uri")) ) return NULL;
if ( !(es = epg_season_find_by_uri(str, create, save)) ) return NULL;
if ( (str = htsmsg_get_str(m, "summary")) )
*save |= epg_season_set_summary(es, str);
if ( !htsmsg_get_u32(m, "number", &u32) )
*save |= epg_season_set_number(es, u32);
if ( !htsmsg_get_u32(m, "episode-count", &u32) )
*save |= epg_season_set_episode_count(es, u32);
if ( (str = htsmsg_get_str(m, "brand")) )
if ( (eb = epg_brand_find_by_uri(str, 0, NULL)) )
*save |= epg_season_set_brand(es, eb, 1);
return es;
}
/* **************************************************************************
* Episode
* *************************************************************************/
@ -542,6 +704,7 @@ epg_episode_t* epg_episode_find_by_uri
if ( skel == NULL ) skel = calloc(1, sizeof(epg_episode_t));
skel->ee_uri = (char*)id;
skel->ee_id = _epg_episode_idx;
/* Find */
if ( !create ) {
@ -551,16 +714,26 @@ epg_episode_t* epg_episode_find_by_uri
} else {
ee = RB_INSERT_SORTED(&epg_episodes, skel, ee_link, ee_uri_cmp);
if ( ee == NULL ) {
ee = skel;
skel = NULL;
*save |= 1;
ee = skel;
skel = NULL;
ee->ee_uri = strdup(id);
*save |= 1;
_epg_episode_idx++;
}
}
return ee;
}
epg_episode_t *epg_episode_find_by_id ( uint32_t id )
{
epg_episode_t *ee;
RB_FOREACH(ee, &epg_episodes, ee_link) {
if ( ee->ee_id == id ) return ee;
}
return NULL;
}
int epg_episode_set_title ( epg_episode_t *episode, const char *title )
{
int save = 0;
@ -713,10 +886,9 @@ int epg_episode_get_number_onscreen
htsmsg_t *epg_episode_serialize ( epg_episode_t *episode )
{
htsmsg_t *m;
if (!episode) return NULL;
if (!episode || !episode->ee_uri) return NULL;
m = htsmsg_create_map();
if (episode->ee_uri)
htsmsg_add_str(m, "uri", episode->ee_uri);
htsmsg_add_str(m, "uri", episode->ee_uri);
if (episode->ee_title)
htsmsg_add_str(m, "title", episode->ee_title);
if (episode->ee_subtitle)
@ -731,21 +903,52 @@ htsmsg_t *epg_episode_serialize ( epg_episode_t *episode )
htsmsg_add_u32(m, "part-number", episode->ee_part_number);
htsmsg_add_u32(m, "part-count", episode->ee_part_count);
}
// TODO: use ids
if (episode->ee_brand)
htsmsg_add_str(m, "brand-id", episode->ee_brand->eb_uri);
htsmsg_add_str(m, "brand", episode->ee_brand->eb_uri);
if (episode->ee_season)
htsmsg_add_str(m, "season-id", episode->ee_season->es_uri);
htsmsg_add_str(m, "season", episode->ee_season->es_uri);
return m;
}
epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save )
{
epg_episode_t *ee;
epg_season_t *es;
epg_brand_t *eb;
uint32_t u32, u32a;
const char *str;
if ( !(str = htsmsg_get_str(m, "uri")) ) return NULL;
if ( !(ee = epg_episode_find_by_uri(str, create, save)) ) return NULL;
if ( (str = htsmsg_get_str(m, "title")) )
*save |= epg_episode_set_title(ee, str);
if ( (str = htsmsg_get_str(m, "subtitle")) )
*save |= epg_episode_set_subtitle(ee, str);
if ( (str = htsmsg_get_str(m, "summary")) )
*save |= epg_episode_set_summary(ee, str);
if ( (str = htsmsg_get_str(m, "description")) )
*save |= epg_episode_set_description(ee, str);
if ( !htsmsg_get_u32(m, "number", &u32) )
*save |= epg_episode_set_number(ee, u32);
if ( !htsmsg_get_u32(m, "part-number", &u32) &&
!htsmsg_get_u32(m, "part-count", &u32a) )
*save |= epg_episode_set_part(ee, u32, u32a);
if ( (str = htsmsg_get_str(m, "brand")) )
if ( (eb = epg_brand_find_by_uri(str, 0, NULL)) )
*save |= epg_episode_set_brand(ee, eb, 1);
if ( (str = htsmsg_get_str(m, "season")) )
if ( (es = epg_season_find_by_uri(str, 0, NULL)) )
*save |= epg_episode_set_season(ee, es, 1);
return ee;
}
/* **************************************************************************
* Broadcast
* *************************************************************************/
static int _epg_broadcast_idx = 0;
// Note: will find broadcast playing at this time (not necessarily
// one that starts at this time)
//
// Note: do we need to pass in stop?
@ -774,9 +977,9 @@ epg_broadcast_t* epg_broadcast_find_by_time
} else {
eb = RB_INSERT_SORTED(&channel->ec_schedule, skel, eb_slink, ebc_win_cmp);
if ( eb == NULL ) {
eb = skel;
skel = NULL;
*save |= 1;
eb = skel;
skel = NULL;
_epg_broadcast_idx++;
}
}
@ -784,9 +987,9 @@ epg_broadcast_t* epg_broadcast_find_by_time
return eb;
}
epg_broadcast_t *epg_broadcast_find_by_id ( int id )
// TODO: optional channel?
epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id )
{
// TODO: do this properly
epg_channel_t *ec;
epg_broadcast_t *ebc;
RB_FOREACH(ec, &epg_channels, ec_link) {
@ -820,19 +1023,59 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast )
{
htsmsg_t *m;
if (!broadcast) return NULL;
if (!broadcast->eb_channel || !broadcast->eb_channel->ec_uri) return NULL;
if (!broadcast->eb_episode || !broadcast->eb_episode->ee_uri) return NULL;
m = htsmsg_create_map();
htsmsg_add_u32(m, "id", broadcast->eb_id);
htsmsg_add_u32(m, "start", broadcast->eb_start);
htsmsg_add_u32(m, "stop", broadcast->eb_stop);
// TODO: should these be optional?
htsmsg_add_str(m, "channel", broadcast->eb_channel->ec_uri);
htsmsg_add_str(m, "episode", broadcast->eb_episode->ee_uri);
if (broadcast->eb_dvb_id)
htsmsg_add_u32(m, "dvb-id", broadcast->eb_dvb_id);
// TODO: add other metadata fields
// TODO: use ID
if (broadcast->eb_episode)
htsmsg_add_str(m, "episode-id", broadcast->eb_episode->ee_uri);
return m;
}
epg_broadcast_t *epg_broadcast_deserialize
( htsmsg_t *m, int create, int *save )
{
epg_broadcast_t *ebc;
epg_channel_t *ec;
epg_episode_t *ee;
const char *str;
uint32_t id, start, stop;
if ( htsmsg_get_u32(m, "id", &id) ) return NULL;
if ( htsmsg_get_u32(m, "start", &start) ) return NULL;
if ( htsmsg_get_u32(m, "stop", &stop) ) return NULL;
// TODO: should these be optional?
if ( !(str = htsmsg_get_str(m, "channel")) ) return NULL;
if ( !(ec = epg_channel_find_by_uri(str, 0, NULL)) ) return NULL;
if ( !(str = htsmsg_get_str(m, "episode")) ) return NULL;
if ( !(ee = epg_episode_find_by_uri(str, 0, NULL)) ) return NULL;
ebc = epg_broadcast_find_by_time(ec, start, stop, create, save);
if ( !ebc ) return NULL;
*save |= epg_broadcast_set_episode(ebc, ee, 1);
/* Bodge the ID - keep them the same */
ebc->eb_id = id;
if ( id >= _epg_broadcast_idx ) _epg_broadcast_idx = id + 1;
#if TODO_BROADCAST_METADATA
if ( !htsmsg_get_u32(m, "dvb-id", &u32) )
save |= epg_broadcast_set_dvb_id(ebc, u32);
// TODO: more metadata
#endif
return ebc;
}
/* **************************************************************************
* Channel
* *************************************************************************/
@ -855,6 +1098,7 @@ epg_channel_t* epg_channel_find_by_uri
if ( skel == NULL ) skel = calloc(1, sizeof(epg_channel_t));
skel->ec_uri = (char*)id;
skel->ec_id = _epg_channel_idx;
/* Find */
if ( !create ) {
@ -864,17 +1108,27 @@ epg_channel_t* epg_channel_find_by_uri
} else {
ec = RB_INSERT_SORTED(&epg_channels, skel, ec_link, ec_uri_cmp);
if ( ec == NULL ) {
ec = skel;
skel = NULL;
*save |= 1;
ec = skel;
skel = NULL;
ec->ec_uri = strdup(id);
LIST_INSERT_HEAD(&epg_unlinked_channels1, ec, ec_ulink);
*save |= 1;
_epg_channel_idx++;
}
}
return ec;
}
epg_channel_t *epg_channel_find_by_id ( uint32_t id )
{
epg_channel_t *ec;
RB_FOREACH(ec, &epg_channels, ec_link) {
if (ec->ec_id == id) return ec;
}
return NULL;
}
int epg_channel_set_name ( epg_channel_t *channel, const char *name )
{
int save = 0;
@ -898,16 +1152,35 @@ epg_broadcast_t *epg_channel_get_current_broadcast ( epg_channel_t *channel )
htsmsg_t *epg_channel_serialize ( epg_channel_t *channel )
{
htsmsg_t *m;
if (!channel) return NULL;
if (!channel || !channel->ec_uri) return NULL;
m = htsmsg_create_map();
if (channel->ec_uri)
htsmsg_add_str(m, "uri", channel->ec_uri);
htsmsg_add_str(m, "uri", channel->ec_uri);
if (channel->ec_channel)
htsmsg_add_u32(m, "channel-id", channel->ec_channel->ch_id);
htsmsg_add_u32(m, "channel", channel->ec_channel->ch_id);
// TODO: other data
return m;
}
epg_channel_t *epg_channel_deserialize ( htsmsg_t *m, int create, int *save )
{
epg_channel_t *ec;
#if TODO_CHANNEL_LINK
channel_t *ch;
uint32_t u32;
#endif
const char *str;
if ( !(str = htsmsg_get_str(m, "uri")) ) return NULL;
if ( !(ec = epg_channel_find_by_uri(str, create, save)) ) return NULL;
#if TODO_CHANNEL_LINK
if ( !htsmsg_get_u32(m, "channel", &u32) )
if ( (ch = channel_find_by_identifier(u32)) )
#endif
return ec;
}
/* **************************************************************************
* Querying
* *************************************************************************/

View file

@ -16,6 +16,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* TODO LIST:
*
* URI in the objects limits us to single grabber, might want something
* more flexible to try and merge grabbers? Is that feasible?
*/
#ifndef EPG_H
#define EPG_H
@ -50,6 +57,7 @@ typedef struct epg_brand
{
RB_ENTRY(epg_brand) eb_link; ///< Global list link
uint32_t eb_id; ///< Internal ID
char *eb_uri; ///< Grabber URI
char *eb_title; ///< Brand name
char *eb_summary; ///< Brand summary
@ -64,6 +72,7 @@ typedef struct epg_brand
/* 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 );
/* Mutators */
int epg_brand_set_title ( epg_brand_t *b, const char *title )
@ -83,7 +92,7 @@ int epg_brand_rem_episode ( epg_brand_t *b, epg_episode_t *s, int u )
/* Serialization */
htsmsg_t *epg_brand_serialize ( epg_brand_t *b );
epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create );
epg_brand_t *epg_brand_deserialize ( htsmsg_t *m, int create, int *save );
/* ************************************************************************
* Season
@ -95,6 +104,7 @@ typedef struct epg_season
RB_ENTRY(epg_season) es_link; ///< Global list link
RB_ENTRY(epg_season) es_blink; ///< Brand list link
uint32_t es_id; ///< Internal ID
char *es_uri; ///< Grabber URI
char *es_summary; ///< Season summary
uint16_t es_number; ///< The season number
@ -110,6 +120,7 @@ typedef struct epg_season
/* 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 );
/* Mutators */
int epg_season_set_summary ( epg_season_t *s, const char *summary )
@ -127,7 +138,7 @@ int epg_season_rem_episode ( epg_season_t *s, epg_episode_t *e, int u )
/* Serialization */
htsmsg_t *epg_season_serialize ( epg_season_t *b );
epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create );
epg_season_t *epg_season_deserialize ( htsmsg_t *m, int create, int *save );
/* ************************************************************************
* Episode
@ -142,6 +153,7 @@ typedef struct epg_episode
RB_ENTRY(epg_episode) ee_blink; ///< Brand link
RB_ENTRY(epg_episode) ee_slink; ///< Season link
uint32_t ee_id; ///< Internal ID
char *ee_uri; ///< Grabber URI
char *ee_title; ///< Title
char *ee_subtitle; ///< Sub-title
@ -162,6 +174,7 @@ typedef struct epg_episode
/* 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 );
/* Mutators */
int epg_episode_set_title ( epg_episode_t *e, const char *title )
@ -191,7 +204,7 @@ int epg_episode_get_number_onscreen ( epg_episode_t *e, char *b, int c );
/* Serialization */
htsmsg_t *epg_episode_serialize ( epg_episode_t *b );
epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create );
epg_episode_t *epg_episode_deserialize ( htsmsg_t *m, int create, int *save );
/* ************************************************************************
* Broadcast - specific airing (channel & time) of an episode
@ -203,8 +216,8 @@ typedef struct epg_broadcast
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
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
@ -232,7 +245,7 @@ typedef struct epg_broadcast
/* 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 ( int id );
epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id );
/* Mutators */
int epg_broadcast_set_episode ( epg_broadcast_t *b, epg_episode_t *e, int u )
@ -243,7 +256,8 @@ epg_broadcast_t *epg_broadcast_get_next ( epg_broadcast_t *b );
/* Serialization */
htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *b );
epg_broadcast_t *epg_broadcast_deserialize ( htsmsg_t *m, int create );
epg_broadcast_t *epg_broadcast_deserialize
( htsmsg_t *m, int create, int *save );
/* ************************************************************************
* Channel - provides mapping from EPG channels to real channels
@ -254,7 +268,8 @@ typedef struct epg_channel
{
RB_ENTRY(epg_channel) ec_link; ///< Global link
char *ec_uri; ///< Channel URI
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)
@ -269,6 +284,7 @@ typedef struct epg_channel
/* 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 );
/* Mutators */
int epg_channel_set_name ( epg_channel_t *c, const char *n )
@ -279,7 +295,7 @@ epg_broadcast_t *epg_channel_get_current_broadcast ( epg_channel_t *c );
/* Serialization */
htsmsg_t *epg_channel_serialize ( epg_channel_t *b );
epg_channel_t *epg_channel_deserialize ( htsmsg_t *m, int create );
epg_channel_t *epg_channel_deserialize ( htsmsg_t *m, int create, int *save );
/* ************************************************************************
* Querying