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:
parent
c3fe6fae73
commit
8fb625f6f5
8 changed files with 111 additions and 52 deletions
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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...',
|
||||
|
|
Loading…
Add table
Reference in a new issue