xmltv: fix XMLTV channel configuration

This commit is contained in:
Adam Sutton 2013-11-03 12:59:26 +00:00
parent 8dac141576
commit 01fc249fb5
13 changed files with 234 additions and 74 deletions

View file

@ -119,6 +119,7 @@ SRCS += \
src/api/api_service.c \
src/api/api_mpegts.c \
src/api/api_epg.c \
src/api/api_epggrab.c \
SRCS += \
src/parsers/parsers.c \

View file

@ -121,4 +121,5 @@ void api_init ( void )
api_service_init();
api_channel_init();
api_epg_init();
api_epggrab_init();
}

View file

@ -62,6 +62,7 @@ void api_service_init ( void );
void api_channel_init ( void );
void api_mpegts_init ( void );
void api_epg_init ( void );
void api_epggrab_init ( void );
/*
* IDnode

47
src/api/api_epggrab.c Normal file
View file

@ -0,0 +1,47 @@
/*
* API - epggrab related calls
*
* Copyright (C) 2013 Adam Sutton
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tvheadend.h"
#include "access.h"
#include "api.h"
#include "epggrab.h"
static int
api_epggrab_channel_list
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
htsmsg_t *m;
pthread_mutex_lock(&global_lock);
m = epggrab_channel_list();
pthread_mutex_unlock(&global_lock);
*resp = htsmsg_create_map();
htsmsg_add_msg(*resp, "entries", m);
return 0;
}
void api_epggrab_init ( void )
{
static api_hook_t ah[] = {
{ "epggrab/channel/list", ACCESS_ANONYMOUS,
api_epggrab_channel_list, NULL },
{ NULL },
};
api_register_all(ah);
}

View file

@ -205,6 +205,61 @@ channel_class_get_number ( void *p )
return &i;
}
static const void *
channel_class_epggrab_get ( void *o )
{
channel_t *ch = o;
htsmsg_t *l = htsmsg_create_list();
epggrab_channel_link_t *ecl;
LIST_FOREACH(ecl, &ch->ch_epggrab, ecl_chn_link)
htsmsg_add_str(l, NULL, epggrab_channel_get_id(ecl->ecl_epggrab));
return l;
}
static int
channel_class_epggrab_set ( void *o, const void *v )
{
int save = 0;
channel_t *ch = o;
htsmsg_t *l = (htsmsg_t*)v;
htsmsg_field_t *f;
epggrab_channel_t *ec;
epggrab_channel_link_t *ecl, *n;
/* mark for deletion */
LIST_FOREACH(ecl, &ch->ch_epggrab, ecl_chn_link)
ecl->ecl_mark = 1;
/* Link */
HTSMSG_FOREACH(f, l) {
if ((ec = epggrab_channel_find_by_id(htsmsg_field_get_str(f))))
save |= epggrab_channel_link(ec, ch);
}
/* Delete */
for (ecl = LIST_FIRST(&ch->ch_epggrab); ecl != NULL; ecl = n) {
n = LIST_NEXT(ecl, ecl_chn_link);
if (ecl->ecl_mark) {
epggrab_channel_link_delete(ecl);
save = 1;
}
}
return save;
}
static htsmsg_t *
channel_class_epggrab_list ( void *o )
{
htsmsg_t *e, *m = htsmsg_create_map();
htsmsg_add_str(m, "type", "api");
htsmsg_add_str(m, "uri", "epggrab/channel/list");
htsmsg_add_str(m, "event", "epggrabchannel");
e = htsmsg_create_map();
htsmsg_add_bool(e, "enum", 1);
htsmsg_add_msg(m, "params", e);
return m;
}
const idclass_t channel_class = {
.ic_class = "service",
.ic_caption = "Service",
@ -241,6 +296,16 @@ const idclass_t channel_class = {
.off = offsetof(channel_t, ch_icon),
.notify = channel_class_icon_notify,
},
{
.type = PT_STR,
.islist = 1,
.id = "epggrab",
.name = "EPG Source",
.set = channel_class_epggrab_set,
.get = channel_class_epggrab_get,
.list = channel_class_epggrab_list,
.opts = PO_NOSAVE,
},
{
.type = PT_INT,
.id = "dvr_pre_time",
@ -427,6 +492,9 @@ channel_create0
ch->ch_name = strdup(name);
}
/* EPG */
epggrab_channel_add(ch);
return ch;
}

View file

@ -62,6 +62,8 @@ typedef struct channel
gtimer_t ch_epg_timer_head;
gtimer_t ch_epg_timer_current;
LIST_HEAD(,epggrab_channel_link) ch_epggrab;
/* DVR */
int ch_dvr_extra_time_pre;
int ch_dvr_extra_time_post;
@ -152,6 +154,7 @@ int channel_set_name ( channel_t *ch, const char *s );
int channel_get_number ( channel_t *ch );
const char *channel_get_icon ( channel_t *ch );
int channel_set_icon ( channel_t *ch, const char *icon );
#define channel_get_uuid(ch) idnode_uuid_as_str(&ch->ch_id)

View file

@ -88,8 +88,11 @@ typedef struct epggrab_channel
typedef struct epggrab_channel_link
{
LIST_ENTRY(epggrab_channel_link) link; ///< Link to grab channel
struct channel *channel; ///< Real channel
int ecl_mark;
struct channel *ecl_channel;
struct epggrab_channel *ecl_epggrab;
LIST_ENTRY(epggrab_channel_link) ecl_chn_link;
LIST_ENTRY(epggrab_channel_link) ecl_epg_link;
} epggrab_channel_link_t;
/*
@ -107,7 +110,13 @@ int epggrab_channel_set_number ( epggrab_channel_t *ch, int number );
/*
* Updated/link
*/
void epggrab_channel_updated ( epggrab_channel_t *ch );
void epggrab_channel_updated ( epggrab_channel_t *ch );
void epggrab_channel_link_delete ( epggrab_channel_link_t *ecl );
int epggrab_channel_link ( epggrab_channel_t *ec, struct channel *ch );
/* ID */
const char *epggrab_channel_get_id ( epggrab_channel_t *ch );
epggrab_channel_t *epggrab_channel_find_by_id ( const char *id );
/* **************************************************************************
* Grabber Modules

View file

@ -23,7 +23,6 @@
#include "settings.h"
#include "htsmsg.h"
#include "channels.h"
#include "service.h"
#include "epg.h"
#include "epggrab.h"
#include "epggrab/private.h"
@ -42,33 +41,55 @@ int epggrab_channel_match ( epggrab_channel_t *ec, channel_t *ch )
return 0;
}
/* Destroy */
void
epggrab_channel_link_delete
( epggrab_channel_link_t *ecl )
{
LIST_REMOVE(ecl, ecl_chn_link);
LIST_REMOVE(ecl, ecl_epg_link);
if (ecl->ecl_epggrab->mod->ch_save)
ecl->ecl_epggrab->mod->ch_save(ecl->ecl_epggrab->mod, ecl->ecl_epggrab);
free(ecl);
}
/* Link epggrab channel to real channel */
void epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch )
int
epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch )
{
epggrab_channel_link_t *ecl;
/* No change */
if (!ch) return;
LIST_FOREACH(ecl, &ec->channels, link)
if (ecl->channel == ch) return;
if (!ch) return 0;
/* Already linked */
LIST_FOREACH(ecl, &ec->channels, ecl_epg_link) {
if (ecl->ecl_channel == ch) {
ecl->ecl_mark = 0;
return 0;
}
}
/* New link */
tvhlog(LOG_INFO, ec->mod->id, "linking %s to %s",
ec->id, channel_get_name(ch));
ecl = calloc(1, sizeof(epggrab_channel_link_t));
ecl->channel = ch;
LIST_INSERT_HEAD(&ec->channels, ecl, link);
#if 0
ecl->ecl_channel = ch;
ecl->ecl_epggrab = ec;
LIST_INSERT_HEAD(&ec->channels, ecl, ecl_epg_link);
LIST_INSERT_HEAD(&ch->ch_epggrab, ecl, ecl_chn_link);
#if TODO_CHAN_UPDATE
if (ec->name && epggrab_channel_rename)
channel_rename(ch, ec->name);
if (ec->icon && epggrab_channel_reicon)
channel_set_icon(ch, ec->icon);
if (ec->number>0 && epggrab_channel_renumber)
channel_set_number(ch, ec->number);
if (ec->icon && epggrab_channel_reicon)
channel_set_icon(ch, ec->icon);
#endif
/* Save */
if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec);
return 1;
}
/* Match and link (basically combines two funcs above for ease) */
@ -84,18 +105,19 @@ 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;
#if 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 (epggrab_channel_rename)
#if TODO_CHAN_UPDATE
if (epggrab_channel_rename) {
epggrab_channel_link_t *ecl;
LIST_FOREACH(ecl, &ec->channels, link)
channel_rename(ecl->channel, name);
}
#endif
save = 1;
}
#endif
return save;
}
@ -103,18 +125,19 @@ 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;
#if 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 (epggrab_channel_reicon)
#if TODO_CHAN_UPDATE
if (epggrab_channel_reicon) {
epggrab_channel_link_t *ecl;
LIST_FOREACH(ecl, &ec->channels, link)
channel_set_icon(ecl->channel, icon);
}
#endif
save = 1;
}
#endif
return save;
}
@ -122,35 +145,34 @@ 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;
#if 0
epggrab_channel_link_t *ecl;
if (!ec || (number <= 0)) return 0;
if (ec->number != number) {
ec->number = number;
if (epggrab_channel_renumber)
#if TODO_CHAN_UPDATE
if (epggrab_channel_renumber) {
epggrab_channel_link_t *ecl;
LIST_FOREACH(ecl, &ec->channels, link)
channel_set_number(ecl->channel, number);
}
#endif
save = 1;
}
#endif
return save;
}
/* Channel settings updated */
void epggrab_channel_updated ( epggrab_channel_t *ec )
{
#if 0
channel_t *ch;
if (!ec) return;
/* Find a link */
if (!LIST_FIRST(&ec->channels))
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
CHANNEL_FOREACH(ch)
if (epggrab_channel_match_and_link(ec, ch)) break;
/* Save */
if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec);
#endif
}
/* ID comparison */
@ -167,7 +189,6 @@ epggrab_channel_t *epggrab_channel_find
{
epggrab_channel_t *ec;
static epggrab_channel_t *skel = NULL;
assert(owner);
if (!skel) skel = calloc(1, sizeof(epggrab_channel_t));
skel->id = (char*)id;
@ -179,6 +200,7 @@ epggrab_channel_t *epggrab_channel_find
} else {
ec = RB_INSERT_SORTED(tree, skel, link, _ch_id_cmp);
if (!ec) {
assert(owner);
ec = skel;
skel = NULL;
ec->id = strdup(id);
@ -204,15 +226,11 @@ htsmsg_t *epggrab_channel_list ( void )
if (mod->channels) {
RB_FOREACH(ec, mod->channels, link) {
e = htsmsg_create_map();
htsmsg_add_str(e, "module", mod->id);
htsmsg_add_str(e, "id", ec->id);
if (ec->name)
htsmsg_add_str(e, "name", ec->name);
snprintf(name, sizeof(name), "%s|%s", mod->id, ec->id);
htsmsg_add_str(e, "mod-id", name);
htsmsg_add_str(e, "key", name);
snprintf(name, sizeof(name), "%s: %s (%s)",
mod->name, ec->name, ec->id);
htsmsg_add_str(e, "mod-name", name);
htsmsg_add_str(e, "val", name);
htsmsg_add_msg(m, NULL, e);
}
}
@ -243,3 +261,25 @@ void epggrab_channel_mod ( channel_t *ch )
if (m->ch_mod) m->ch_mod(m, ch);
}
}
const char *
epggrab_channel_get_id ( epggrab_channel_t *ec )
{
static char buf[1024];
epggrab_module_t *m = ec->mod;
snprintf(buf, sizeof(buf), "%s|%s", m->id, ec->id);
return buf;
}
epggrab_channel_t *
epggrab_channel_find_by_id ( const char *id )
{
char buf[1024];
char *mid, *cid;
epggrab_module_t *mod;
strncpy(buf, id, sizeof(buf));
if ((mid = strtok_r(buf, "|", &cid)) && cid)
if ((mod = epggrab_module_find_by_id(mid)) && mod->channels)
return epggrab_channel_find(mod->channels, cid, 0, NULL, NULL);
return NULL;
}

View file

@ -153,9 +153,9 @@ void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch )
htsmsg_add_str(m, "name", ch->name);
if (ch->icon)
htsmsg_add_str(m, "icon", ch->icon);
LIST_FOREACH(ecl, &ch->channels, link) {
LIST_FOREACH(ecl, &ch->channels, ecl_epg_link) {
if (!a) a = htsmsg_create_list();
htsmsg_add_u32(a, NULL, channel_get_id(ecl->channel));
htsmsg_add_str(a, NULL, channel_get_uuid(ecl->ecl_channel));
}
if (a) htsmsg_add_msg(m, "channels", a);
if (ch->number)
@ -175,18 +175,9 @@ 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) {
LIST_FOREACH(egl, &egc->channels, link) {
if (egl->channel == ch) {
LIST_REMOVE(egl, link);
free(egl);
break;
}
}
}
epggrab_channel_link_t *ecl;
while ((ecl = LIST_FIRST(&ch->ch_epggrab)))
epggrab_channel_link_delete(ecl);
}
void epggrab_module_ch_mod ( void *mod, channel_t *ch )
@ -215,20 +206,14 @@ static void _epggrab_module_channel_load
egc->number = u32;
if ((a = htsmsg_get_list(m, "channels"))) {
HTSMSG_FOREACH(f, a) {
if ((ch = channel_find_by_id((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 ((ch = channel_find_by_uuid(f->hmf_str)))
epggrab_channel_link(egc, ch);
}
/* Compat with older 3.1 code */
} else if (!htsmsg_get_u32(m, "channel", &u32)) {
if ((ch = channel_find_by_id(u32))) {
epggrab_channel_link_t *ecl = calloc(1, sizeof(epggrab_channel_link_t));
ecl->channel = ch;
LIST_INSERT_HEAD(&egc->channels, ecl, link);
}
if ((ch = channel_find_by_id(u32)))
epggrab_channel_link(egc, ch);
}
}

View file

@ -290,11 +290,12 @@ opentv_parse_event_section
/* Find broadcast */
if (ev.start && ev.stop) {
ebc = epg_broadcast_find_by_time(ecl->channel, ev.start, ev.stop, ev.eid,
1, &save);
tvhdebug("opentv", "find by time start %ld stop %ld eid %d = %p", ev.start, ev.stop, ev.eid, ebc);
ebc = epg_broadcast_find_by_time(ecl->ecl_channel, ev.start, ev.stop,
ev.eid, 1, &save);
tvhdebug("opentv", "find by time start %ld stop %ld eid %d = %p",
ev.start, ev.stop, ev.eid, ebc);
} else {
ebc = epg_broadcast_find_by_eid(ecl->channel, ev.eid);
ebc = epg_broadcast_find_by_eid(ecl->ecl_channel, ev.eid);
tvhdebug("opentv", "find by eid %d = %p", ev.eid, ebc);
}
if (!ebc)
@ -317,7 +318,7 @@ opentv_parse_event_section
if (ev.serieslink) {
char suri[257];
snprintf(suri, 256, "opentv://channel-%s/series-%d",
channel_get_uuid(ecl->channel), ev.serieslink);
channel_get_uuid(ecl->ecl_channel), ev.serieslink);
if ((es = epg_serieslink_find_by_uri(suri, 1, &save)))
save |= epg_broadcast_set_serieslink(ebc, es, src);
}
@ -385,6 +386,7 @@ opentv_desc_channels
epggrab_channel_t *ec;
epggrab_channel_link_t *ecl;
mpegts_service_t *svc;
channel_t *ch;
int sid, cid, cnum;
int save = 0;
int i = 2;
@ -400,12 +402,16 @@ opentv_desc_channels
if (svc && LIST_FIRST(&svc->s_channels)) {
ec =_opentv_find_epggrab_channel(mod, cid, 1, &save);
ecl = LIST_FIRST(&ec->channels);
ch = LIST_FIRST(&svc->s_channels)->csm_chn;
tvhtrace(mt->mt_name, " ec = %p, ecl = %p", ec, ecl);
if (!ecl) {
ecl = calloc(1, sizeof(epggrab_channel_link_t));
LIST_INSERT_HEAD(&ec->channels, ecl, link);
if (ecl && ecl->ecl_channel != ch) {
epggrab_channel_link_delete(ecl);
ecl = NULL;
}
ecl->channel = LIST_FIRST(&svc->s_channels)->csm_chn;
if (!ecl)
epggrab_channel_link(ec, ch);
save |= epggrab_channel_set_number(ec, cnum);
}
i += 9;

View file

@ -365,9 +365,9 @@ static int _pyepg_parse_schedule
HTSMSG_FOREACH(f, tags) {
if (strcmp(f->hmf_name, "broadcast") == 0) {
LIST_FOREACH(ecl, &ec->channels, link)
LIST_FOREACH(ecl, &ec->channels, ecl_epg_link)
save |= _pyepg_parse_broadcast(mod, htsmsg_get_map_by_field(f),
ecl->channel, stats);
ecl->ecl_channel, stats);
}
}

View file

@ -553,8 +553,8 @@ static int _xmltv_parse_programme
if(stop <= start || stop <= dispatch_clock) return 0;
LIST_FOREACH(ecl, &ch->channels, link)
save |= _xmltv_parse_programme_tags(mod, ecl->channel, tags,
LIST_FOREACH(ecl, &ch->channels, ecl_epg_link)
save |= _xmltv_parse_programme_tags(mod, ecl->ecl_channel, tags,
start, stop, stats);
return save;
}

View file

@ -48,7 +48,6 @@ void epggrab_module_channels_load ( epggrab_module_t *m );
* Channel processing
* *************************************************************************/
void epggrab_channel_link ( epggrab_channel_t *ec, struct channel *ch );
int epggrab_channel_match ( epggrab_channel_t *ec, struct channel *ch );
int epggrab_channel_match_and_link
( epggrab_channel_t *ec, struct channel *ch );