diff --git a/src/epggrab.h b/src/epggrab.h index 9583e0ad..ddb46a41 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -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 */ diff --git a/src/epggrab/channel.c b/src/epggrab/channel.c index a3846bf9..db73b288 100644 --- a/src/epggrab/channel.c +++ b/src/epggrab/channel.c @@ -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; diff --git a/src/epggrab/module.c b/src/epggrab/module.c index facd3f78..5eded322 100644 --- a/src/epggrab/module.c +++ b/src/epggrab/module.c @@ -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 ) diff --git a/src/epggrab/module/opentv.c b/src/epggrab/module/opentv.c index 2d7bdc4d..79f824d9 100644 --- a/src/epggrab/module/opentv.c +++ b/src/epggrab/module/opentv.c @@ -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; diff --git a/src/epggrab/module/pyepg.c b/src/epggrab/module/pyepg.c index 0eda3ade..abb3e264 100644 --- a/src/epggrab/module/pyepg.c +++ b/src/epggrab/module/pyepg.c @@ -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); } } diff --git a/src/epggrab/module/xmltv.c b/src/epggrab/module/xmltv.c index 8ff3af0a..3e0049b1 100644 --- a/src/epggrab/module/xmltv.c +++ b/src/epggrab/module/xmltv.c @@ -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; } diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 658b37c1..b4432c64 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -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); + } } } } diff --git a/src/webui/static/app/chconf.js b/src/webui/static/app/chconf.js index 0e4b5435..3a68d385 100644 --- a/src/webui/static/app/chconf.js +++ b/src/webui/static/app/chconf.js @@ -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...',