Added the ability to map multiple EPG channels to the same TVH channel. Fixes #1163. Also fixed error in opentv which Fixes #1154.

This commit is contained in:
Adam Sutton 2012-09-17 11:09:07 +01:00
parent c3fe6fae73
commit 8fb625f6f5
8 changed files with 111 additions and 52 deletions

View file

@ -81,9 +81,15 @@ typedef struct epggrab_channel
char *icon; ///< Channel icon
int number; ///< Channel number
struct channel *channel; ///< Mapped channel
LIST_HEAD(,epggrab_channel_link) channels; ///< Mapped channels
} epggrab_channel_t;
typedef struct epggrab_channel_link
{
LIST_ENTRY(epggrab_channel_link) link; ///< Link to grab channel
struct channel *channel; ///< Real channel
} epggrab_channel_link_t;
/*
* Access functions
*/

View file

@ -36,7 +36,7 @@
int epggrab_channel_match ( epggrab_channel_t *ec, channel_t *ch )
{
if (!ec || !ch) return 0;
if (ec->channel) return 0; // ignore already paired
if (LIST_FIRST(&ec->channels)) return 0; // ignore already paired
if (ec->name && !strcmp(ec->name, ch->ch_name)) return 1;
return 0;
@ -45,12 +45,18 @@ int epggrab_channel_match ( epggrab_channel_t *ec, channel_t *ch )
/* Link epggrab channel to real channel */
void epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch )
{
epggrab_channel_link_t *ecl;
/* No change */
if (!ch || ch == ec->channel) return;
if (!ch) return;
LIST_FOREACH(ecl, &ec->channels, link)
if (ecl->channel == ch) return;
tvhlog(LOG_INFO, ec->mod->id, "linking %s to %s",
ec->id, ch->ch_name);
ec->channel = ch;
ecl = calloc(1, sizeof(epggrab_channel_link_t));
ecl->channel = ch;
LIST_INSERT_HEAD(&ec->channels, ecl, link);
if (ec->name && epggrab_channel_rename)
channel_rename(ch, ec->name);
if (ec->icon && epggrab_channel_reicon)
@ -76,12 +82,14 @@ int epggrab_channel_match_and_link ( epggrab_channel_t *ec, channel_t *ch )
int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name )
{
int save = 0;
epggrab_channel_link_t *ecl;
if (!ec || !name) return 0;
if (!ec->name || strcmp(ec->name, name)) {
if (ec->name) free(ec->name);
ec->name = strdup(name);
if (ec->channel && epggrab_channel_rename)
channel_rename(ec->channel, name);
if (epggrab_channel_rename)
LIST_FOREACH(ecl, &ec->channels, link)
channel_rename(ecl->channel, name);
save = 1;
}
return save;
@ -91,12 +99,14 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name )
int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon )
{
int save = 0;
epggrab_channel_link_t *ecl;
if (!ec->icon || strcmp(ec->icon, icon) ) {
if (!ec | !icon) return 0;
if (ec->icon) free(ec->icon);
ec->icon = strdup(icon);
if (ec->channel && epggrab_channel_reicon)
channel_set_icon(ec->channel, icon);
if (epggrab_channel_reicon)
LIST_FOREACH(ecl, &ec->channels, link)
channel_set_icon(ecl->channel, icon);
save = 1;
}
return save;
@ -106,11 +116,13 @@ int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon )
int epggrab_channel_set_number ( epggrab_channel_t *ec, int number )
{
int save = 0;
epggrab_channel_link_t *ecl;
if (!ec || (number <= 0)) return 0;
if (ec->number != number) {
ec->number = number;
if (ec->channel && epggrab_channel_renumber)
channel_set_number(ec->channel, number);
if (epggrab_channel_renumber)
LIST_FOREACH(ecl, &ec->channels, link)
channel_set_number(ecl->channel, number);
save = 1;
}
return save;
@ -123,7 +135,7 @@ void epggrab_channel_updated ( epggrab_channel_t *ec )
if (!ec) return;
/* Find a link */
if (!ec->channel)
if (!LIST_FIRST(&ec->channels))
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
if (epggrab_channel_match_and_link(ec, ch)) break;

View file

@ -144,15 +144,19 @@ void epggrab_module_parse
void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch )
{
htsmsg_t *m = htsmsg_create_map();
htsmsg_t *a = NULL, *m = htsmsg_create_map();
epggrab_module_t *mod = _m;
epggrab_channel_link_t *ecl;
if (ch->name)
htsmsg_add_str(m, "name", ch->name);
if (ch->icon)
htsmsg_add_str(m, "icon", ch->icon);
if (ch->channel)
htsmsg_add_u32(m, "channel", ch->channel->ch_id);
LIST_FOREACH(ecl, &ch->channels, link) {
if (!a) a = htsmsg_create_list();
htsmsg_add_u32(a, NULL, ecl->channel->ch_id);
}
if (a) htsmsg_add_msg(m, "channels", a);
if (ch->number)
htsmsg_add_u32(m, "number", ch->number);
@ -171,12 +175,15 @@ void epggrab_module_ch_add ( void *m, channel_t *ch )
void epggrab_module_ch_rem ( void *m, channel_t *ch )
{
epggrab_channel_t *egc;
epggrab_channel_link_t *egl;
epggrab_module_int_t *mod = m;
RB_FOREACH(egc, mod->channels, link) {
if (egc->channel == ch) {
egc->channel = NULL;
if (mod->ch_save) mod->ch_save(mod, egc);
break;
LIST_FOREACH(egl, &egc->channels, link) {
if (egl->channel == ch) {
LIST_REMOVE(egl, link);
free(egl);
break;
}
}
}
}
@ -192,18 +199,36 @@ static void _epggrab_module_channel_load
int save = 0;
const char *str;
uint32_t u32;
htsmsg_t *a;
htsmsg_field_t *f;
channel_t *ch;
epggrab_channel_t *ch = epggrab_channel_find(mod->channels, id, 1, &save, mod);
epggrab_channel_t *egc
= epggrab_channel_find(mod->channels, id, 1, &save, mod);
if ((str = htsmsg_get_str(m, "name")))
ch->name = strdup(str);
egc->name = strdup(str);
if ((str = htsmsg_get_str(m, "icon")))
ch->icon = strdup(str);
egc->icon = strdup(str);
if(!htsmsg_get_u32(m, "number", &u32))
ch->number = u32;
egc->number = u32;
if ((a = htsmsg_get_list(m, "channels"))) {
HTSMSG_FOREACH(f, a) {
if ((ch = channel_find_by_identifier((uint32_t)f->hmf_s64))) {
epggrab_channel_link_t *ecl = calloc(1, sizeof(epggrab_channel_link_t));
ecl->channel = ch;
LIST_INSERT_HEAD(&egc->channels, ecl, link);
}
}
if (!htsmsg_get_u32(m, "channel", &u32))
ch->channel = channel_find_by_identifier(u32);
/* Compat with older 3.1 code */
} else if (!htsmsg_get_u32(m, "channel", &u32)) {
if ((ch = channel_find_by_identifier(u32))) {
epggrab_channel_link_t *ecl = calloc(1, sizeof(epggrab_channel_link_t));
ecl->channel = ch;
LIST_INSERT_HEAD(&egc->channels, ecl, link);
}
}
}
void epggrab_module_channels_load ( epggrab_module_t *mod )

View file

@ -336,6 +336,7 @@ static int _opentv_parse_event_section
opentv_event_t ev;
epggrab_module_t *src = (epggrab_module_t*)mod;
const char *lang = NULL;
epggrab_channel_link_t *ecl;
/* Get language (bit of a hack) */
if (!strcmp(mod->dict->id, "skyit")) lang = "it";
@ -344,8 +345,8 @@ static int _opentv_parse_event_section
/* Channel */
cid = ((int)buf[0] << 8) | buf[1];
if (!(ec = _opentv_find_epggrab_channel(mod, cid, 0, NULL))) return 0;
if (!ec->channel) return 0;
if (!*ec->channel->ch_name) return 0; // ignore unnamed channels
if (!(ecl = LIST_FIRST(&ec->channels))) return 0;
// TODO: it's assumed that opentv channels are always 1-1 mapping!
/* Time (start/stop referenced to this) */
mjd = ((int)buf[5] << 8) | buf[6];
@ -364,11 +365,11 @@ static int _opentv_parse_event_section
/* Find broadcast */
if (ev.type & OPENTV_TITLE) {
ebc = epg_broadcast_find_by_time(ec->channel, ev.start, ev.stop, ev.eid,
ebc = epg_broadcast_find_by_time(ecl->channel, ev.start, ev.stop, ev.eid,
1, &save);
/* Store */
} else if (!(ebc = epg_broadcast_find_by_eid(ec->channel, ev.eid))) {
} else if (!(ebc = epg_broadcast_find_by_eid(ecl->channel, ev.eid))) {
opentv_event_t *skel = malloc(sizeof(opentv_event_t));
memcpy(skel, &ev, sizeof(opentv_event_t));
assert(!RB_INSERT_SORTED(&sta->events, skel, ev_link, _ev_cmp));
@ -390,7 +391,7 @@ static int _opentv_parse_event_section
if (ebc && ev.serieslink) {
char suri[257];
snprintf(suri, 256, "opentv://channel-%d/series-%d",
ec->channel->ch_id, ev.serieslink);
ecl->channel->ch_id, ev.serieslink);
if ((es = epg_serieslink_find_by_uri(suri, 1, &save)))
save |= epg_broadcast_set_serieslink(ebc, es, src);
}
@ -429,6 +430,7 @@ static void _opentv_parse_channels
( opentv_module_t *mod, uint8_t *buf, int len, uint16_t tsid )
{
epggrab_channel_t *ec;
epggrab_channel_link_t *ecl;
service_t *svc;
int sid, cid, cnum;
int save = 0;
@ -440,12 +442,14 @@ static void _opentv_parse_channels
/* Find the service */
svc = _opentv_find_service(tsid, sid);
if (svc && svc->s_ch) {
if (svc && svc->s_ch && service_is_primary_epg(svc)) {
ec =_opentv_find_epggrab_channel(mod, cid, 1, &save);
if (service_is_primary_epg(svc))
ec->channel = svc->s_ch;
else
ec->channel = NULL;
ecl = LIST_FIRST(&ec->channels);
if (!ecl) {
ecl = calloc(1, sizeof(epggrab_channel_link_t));
LIST_INSERT_HEAD(&ec->channels, ecl, link);
}
ecl->channel = svc->s_ch;
save |= epggrab_channel_set_number(ec, cnum);
}
i += 9;

View file

@ -354,6 +354,7 @@ static int _pyepg_parse_schedule
htsmsg_field_t *f;
epggrab_channel_t *ec;
const char *str;
epggrab_channel_link_t *ecl;
if ( data == NULL ) return 0;
@ -361,12 +362,12 @@ static int _pyepg_parse_schedule
if ((str = htsmsg_get_str(attr, "channel")) == NULL) return 0;
if ((ec = _pyepg_channel_find(str, 0, NULL)) == NULL) return 0;
if ((tags = htsmsg_get_map(data, "tags")) == NULL) return 0;
if (!ec->channel) return 0;
HTSMSG_FOREACH(f, tags) {
if (strcmp(f->hmf_name, "broadcast") == 0) {
save |= _pyepg_parse_broadcast(mod, htsmsg_get_map_by_field(f),
ec->channel, stats);
LIST_FOREACH(ecl, &ec->channels, link)
save |= _pyepg_parse_broadcast(mod, htsmsg_get_map_by_field(f),
ecl->channel, stats);
}
}

View file

@ -476,6 +476,7 @@ static int _xmltv_parse_programme
const char *s, *chid;
time_t start, stop;
epggrab_channel_t *ch;
epggrab_channel_link_t *ecl;
if(body == NULL) return 0;
@ -483,7 +484,7 @@ static int _xmltv_parse_programme
if((tags = htsmsg_get_map(body, "tags")) == NULL) return 0;
if((chid = htsmsg_get_str(attribs, "channel")) == NULL) return 0;
if((ch = _xmltv_channel_find(chid, 0, NULL)) == NULL) return 0;
if (ch->channel == NULL) return 0;
if (!LIST_FIRST(&ch->channels)) return 0;
if((s = htsmsg_get_str(attribs, "start")) == NULL) return 0;
start = _xmltv_str2time(s);
if((s = htsmsg_get_str(attribs, "stop")) == NULL) return 0;
@ -491,8 +492,9 @@ static int _xmltv_parse_programme
if(stop <= start || stop <= dispatch_clock) return 0;
save |= _xmltv_parse_programme_tags(mod, ch->channel, tags,
start, stop, stats);
LIST_FOREACH(ecl, &ch->channels, link)
save |= _xmltv_parse_programme_tags(mod, ecl->channel, tags,
start, stop, stats);
return save;
}

View file

@ -349,14 +349,19 @@ extjs_channels_update(htsmsg_t *in)
char *modid, *ecid;
epggrab_module_t *mod;
epggrab_channel_t *ec;
epggrab_channel_link_t *ecl;
/* Clear existing */
LIST_FOREACH(mod, &epggrab_modules, link) {
if (mod->type != EPGGRAB_OTA && mod->channels) {
RB_FOREACH(ec, mod->channels, link) {
if (ec->channel == ch) {
ec->channel = NULL;
mod->ch_save(mod, ec);
LIST_FOREACH(ecl, &ec->channels, link) {
if (ecl->channel == ch) {
LIST_REMOVE(ecl, link);
free(ecl);
mod->ch_save(mod, ec);
break;
}
}
}
}
@ -400,6 +405,7 @@ extjs_channels(http_connection_t *hc, const char *remain, void *opaque)
char *epggrabsrc;
epggrab_module_t *mod;
epggrab_channel_t *ec;
epggrab_channel_link_t *ecl;
if(op == NULL)
return 400;
@ -438,15 +444,17 @@ extjs_channels(http_connection_t *hc, const char *remain, void *opaque)
LIST_FOREACH(mod, &epggrab_modules, link) {
if (mod->type != EPGGRAB_OTA && mod->channels) {
RB_FOREACH(ec, mod->channels, link) {
if (ec->channel == ch) {
char id[100];
sprintf(id, "%s|%s", mod->id, ec->id);
if (!epggrabsrc) {
epggrabsrc = strdup(id);
} else {
epggrabsrc = realloc(epggrabsrc, strlen(epggrabsrc) + 2 + strlen(id));
strcat(epggrabsrc, ",");
strcat(epggrabsrc, id);
LIST_FOREACH(ecl, &ec->channels, link) {
if (ecl->channel == ch) {
char id[100];
sprintf(id, "%s|%s", mod->id, ec->id);
if (!epggrabsrc) {
epggrabsrc = strdup(id);
} else {
epggrabsrc = realloc(epggrabsrc, strlen(epggrabsrc) + 2 + strlen(id));
strcat(epggrabsrc, ",");
strcat(epggrabsrc, id);
}
}
}
}

View file

@ -149,6 +149,7 @@ tvheadend.chconf = function() {
}, {
header : "EPG Grab source",
dataIndex : 'epggrabsrc',
hiddenName : 'epggrabsrc',
width : 150,
editor : new Ext.ux.form.LovCombo({
loadingText : 'Loading...',