struct channel_tag_queue channel_tags;
+static int channel_in_load;
+
static void channel_tag_init ( void );
static void channel_tag_done ( void );
static void channel_tag_mapping_destroy(idnode_list_mapping_t *ilm, void *origin);
+static void channel_epg_update_all ( channel_t *ch );
static int
ch_id_cmp ( channel_t *a, channel_t *b )
return 0;
}
+static int
+channel_class_epg_parent_set_noupdate
+ ( void *o, const void *v, channel_t **parent )
+{
+ channel_t *ch = o;
+ const char *uuid = v;
+ if (strcmp(v ?: "", ch->ch_epg_parent ?: "")) {
+ if (ch->ch_epg_parent) {
+ LIST_REMOVE(ch, ch_epg_slave_link);
+ free(ch->ch_epg_parent);
+ }
+ ch->ch_epg_parent = NULL;
+ epg_channel_unlink(ch);
+ if (uuid && uuid[0] != '\0') {
+ if (channel_in_load) {
+ ch->ch_epg_parent = strdup(uuid);
+ } else {
+ *parent = channel_find_by_uuid(uuid);
+ if (*parent) {
+ ch->ch_epg_parent = strdup(uuid);
+ LIST_INSERT_HEAD(&(*parent)->ch_epg_slaves, ch, ch_epg_slave_link);
+ }
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static int
+channel_class_epg_parent_set ( void *o, const void *v )
+{
+ channel_t *parent = NULL;
+ int save = channel_class_epg_parent_set_noupdate(o, v, &parent);
+ if (parent)
+ channel_epg_update_all(parent);
+ return save;
+}
+
const idclass_t channel_class = {
.ic_class = "channel",
.ic_caption = N_("Channel"),
.list = bouquet_class_get_list,
.opts = PO_RDONLY
},
+ {
+ .type = PT_STR,
+ .id = "epg_parent",
+ .name = N_("Reuse EPG from"),
+ .set = channel_class_epg_parent_set,
+ .list = channel_class_get_list,
+ .off = offsetof(channel_t, ch_epg_parent),
+ .opts = PO_ADVANCED
+ },
{}
}
};
return 1;
}
+/**
+ *
+ */
+void
+channel_event_updated ( epg_broadcast_t *e )
+{
+ channel_t *ch;
+ int save;
+
+ LIST_FOREACH(ch, &e->channel->ch_epg_slaves, ch_epg_slave_link)
+ epg_broadcast_clone(ch, e, &save);
+}
+
+/**
+ *
+ */
+static void
+channel_epg_update_all ( channel_t *ch )
+{
+ epg_broadcast_t *e;
+
+ RB_FOREACH(e, &ch->ch_epg_schedule, sched_link)
+ channel_event_updated(e);
+}
+
/* **************************************************************************
* Property updating
* *************************************************************************/
{
th_subscription_t *s;
idnode_list_mapping_t *ilm;
+ channel_t *ch1, *ch2;
lock_assert(&global_lock);
/* EPG */
epggrab_channel_rem(ch);
epg_channel_unlink(ch);
+ for (ch1 = LIST_FIRST(&ch->ch_epg_slaves); ch1; ch1 = ch2) {
+ ch2 = LIST_NEXT(ch1, ch_epg_slave_link);
+ LIST_REMOVE(ch1, ch_epg_slave_link);
+ if (delconf) {
+ free(ch1->ch_epg_parent);
+ ch1->ch_epg_parent = NULL;
+ channel_save(ch1);
+ }
+ }
/* HTSP */
htsp_channel_delete(ch);
/* Free memory */
RB_REMOVE(&channels, ch, ch_link);
idnode_unlink(&ch->ch_id);
+ free(ch->ch_epg_parent);
free(ch->ch_name);
free(ch->ch_icon);
free(ch);
epggrab_channel_add(ch);
}
+
+
+
/**
*
*/
{
htsmsg_t *c, *e;
htsmsg_field_t *f;
- RB_INIT(&channels);
+ channel_t *ch, *parent;
+ char *s;
+ RB_INIT(&channels);
+
/* Tags */
channel_tag_init();
if (!(c = hts_settings_load("channel/config")))
return;
+ channel_in_load = 1;
HTSMSG_FOREACH(f, c) {
if (!(e = htsmsg_field_get_map(f))) continue;
(void)channel_create(f->hmf_name, e, NULL);
}
+ channel_in_load = 0;
htsmsg_destroy(c);
+
+ /* Pair slave EPG, set parent again without channel_in_load */
+ CHANNEL_FOREACH(ch)
+ if ((s = ch->ch_epg_parent) != NULL) {
+ ch->ch_epg_parent = NULL;
+ channel_class_epg_parent_set_noupdate(ch, s, &parent);
+ free(s);
+ }
+ CHANNEL_FOREACH(ch)
+ channel_epg_update_all(ch);
}
/**
LIST_HEAD(, th_subscription) ch_subscriptions;
/* EPG fields */
+ char *ch_epg_parent;
+ LIST_HEAD(, channel) ch_epg_slaves;
+ LIST_ENTRY(channel) ch_epg_slave_link;
epg_broadcast_tree_t ch_epg_schedule;
epg_broadcast_t *ch_epg_now;
epg_broadcast_t *ch_epg_next;
gtimer_t ch_epg_timer_head;
gtimer_t ch_epg_timer_current;
- int ch_epgauto;
+ int ch_epgauto;
idnode_list_head_t ch_epggrab; /* 1 = epggrab channel, 2 = channel */
/* DVR */
int channel_access(channel_t *ch, struct access *a, int disabled);
+void channel_event_updated(epg_broadcast_t *e);
+
int channel_tag_map(channel_tag_t *ct, channel_t *ch, void *origin);
void channel_tag_unmap(channel_t *ch, void *origin);
}
}
-static epg_object_t *_epg_object_find_by_uri
+static epg_object_t *_epg_object_find_by_uri
( const char *uri, int create, int *save,
epg_object_tree_t *tree, epg_object_t **skel )
{
}
dvr_event_updated(eo);
dvr_autorec_check_event(eo);
+ channel_event_updated(eo);
}
static epg_broadcast_t **_epg_broadcast_skel ( void )
return _epg_channel_add_broadcast(channel, ebc, create, save);
}
+epg_broadcast_t *epg_broadcast_clone
+ ( channel_t *channel, epg_broadcast_t *src, int *save )
+{
+ epg_broadcast_t *ebc;
+
+ if ( !src ) return NULL;
+ ebc = epg_broadcast_find_by_time(channel, src->start, src->stop,
+ src->dvb_eid, 1, save);
+ if (ebc) {
+ /* Copy metadata */
+ *save |= epg_broadcast_set_is_widescreen(ebc, src->is_widescreen, NULL);
+ *save |= epg_broadcast_set_is_hd(ebc, src->is_hd, NULL);
+ *save |= epg_broadcast_set_lines(ebc, src->lines, NULL);
+ *save |= epg_broadcast_set_aspect(ebc, src->aspect, NULL);
+ *save |= epg_broadcast_set_is_deafsigned(ebc, src->is_deafsigned, NULL);
+ *save |= epg_broadcast_set_is_subtitled(ebc, src->is_subtitled, NULL);
+ *save |= epg_broadcast_set_is_audio_desc(ebc, src->is_audio_desc, NULL);
+ *save |= epg_broadcast_set_is_new(ebc, src->is_new, NULL);
+ *save |= epg_broadcast_set_is_repeat(ebc, src->is_repeat, NULL);
+ *save |= epg_broadcast_set_summary2(ebc, src->summary, NULL);
+ *save |= epg_broadcast_set_description2(ebc, src->description, NULL);
+ *save |= epg_broadcast_set_serieslink(ebc, src->serieslink, NULL);
+ *save |= epg_broadcast_set_episode(ebc, src->episode, NULL);
+ }
+ return ebc;
+}
+
epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id )
{
return (epg_broadcast_t*)epg_object_find_by_id(id, EPG_BROADCAST);
epg_broadcast_t *epg_broadcast_find_by_eid ( struct channel *ch, uint16_t eid );
epg_broadcast_t *epg_broadcast_find_by_id ( uint32_t id );
+/* Special */
+epg_broadcast_t *epg_broadcast_clone
+ ( struct channel *channel, epg_broadcast_t *src, int *save );
+
/* Mutators */
int epg_broadcast_set_episode
( epg_broadcast_t *b, epg_episode_t *e, struct epggrab_module *src )
}
if ( _epg_write_sect(sb, "broadcasts") ) goto error;
CHANNEL_FOREACH(ch) {
+ if (ch->ch_epg_parent) continue;
RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
if (_epg_write(sb, epg_broadcast_serialize(ebc))) goto error;
stats.broadcasts.total++;