From: Jaroslav Kysela Date: Thu, 29 Oct 2015 14:49:01 +0000 (+0100) Subject: channel: v2 - add possibility to reuse EPG from another channel, fixes #3217 X-Git-Tag: v4.2.1~1745 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4c54e631583856f037c7099333f529e9e39a0bef;p=thirdparty%2Ftvheadend.git channel: v2 - add possibility to reuse EPG from another channel, fixes #3217 --- diff --git a/src/channels.c b/src/channels.c index b1301f71a..52548c791 100644 --- a/src/channels.c +++ b/src/channels.c @@ -51,9 +51,12 @@ struct channel_tree channels; 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 ) @@ -285,6 +288,45 @@ channel_class_bouquet_set ( void *o, const void *v ) 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"), @@ -397,6 +439,15 @@ const idclass_t channel_class = { .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 + }, {} } }; @@ -489,6 +540,31 @@ chtags_ok: 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 * *************************************************************************/ @@ -787,6 +863,7 @@ channel_delete ( channel_t *ch, int delconf ) { th_subscription_t *s; idnode_list_mapping_t *ilm; + channel_t *ch1, *ch2; lock_assert(&global_lock); @@ -815,6 +892,15 @@ channel_delete ( channel_t *ch, int delconf ) /* 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); @@ -826,6 +912,7 @@ channel_delete ( channel_t *ch, int delconf ) /* 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); @@ -848,6 +935,9 @@ channel_save ( channel_t *ch ) epggrab_channel_add(ch); } + + + /** * */ @@ -856,8 +946,11 @@ channel_init ( void ) { htsmsg_t *c, *e; htsmsg_field_t *f; - RB_INIT(&channels); + channel_t *ch, *parent; + char *s; + RB_INIT(&channels); + /* Tags */ channel_tag_init(); @@ -865,11 +958,23 @@ channel_init ( void ) 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); } /** diff --git a/src/channels.h b/src/channels.h index 7a8c75508..49607d776 100644 --- a/src/channels.h +++ b/src/channels.h @@ -61,6 +61,9 @@ typedef struct channel 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; @@ -68,7 +71,7 @@ typedef struct channel 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 */ @@ -154,6 +157,8 @@ const char * channel_tag_get_icon(channel_tag_t *ct); 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); diff --git a/src/epg.c b/src/epg.c index aae95c023..6b0dddc8f 100644 --- a/src/epg.c +++ b/src/epg.c @@ -210,7 +210,7 @@ static void _epg_object_create ( void *o ) } } -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 ) { @@ -1599,6 +1599,7 @@ static void _epg_broadcast_updated ( void *eo ) } dvr_event_updated(eo); dvr_autorec_check_event(eo); + channel_event_updated(eo); } static epg_broadcast_t **_epg_broadcast_skel ( void ) @@ -1630,6 +1631,33 @@ epg_broadcast_t* epg_broadcast_find_by_time 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); diff --git a/src/epg.h b/src/epg.h index c02b17b9f..7abdbe61c 100644 --- a/src/epg.h +++ b/src/epg.h @@ -457,6 +457,10 @@ epg_broadcast_t *epg_broadcast_find_by_time 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 ) diff --git a/src/epgdb.c b/src/epgdb.c index 47e19f3c2..f0a6b2f70 100644 --- a/src/epgdb.c +++ b/src/epgdb.c @@ -362,6 +362,7 @@ void epg_save ( void ) } 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++;