diff --git a/src/bouquet.c b/src/bouquet.c index adb779ac..d3fd56fd 100644 --- a/src/bouquet.c +++ b/src/bouquet.c @@ -140,19 +140,56 @@ bouquet_find_by_source(const char *name, const char *src, int create) return NULL; } +/* + * + */ +static channel_tag_t * +bouquet_tag(bouquet_t *bq, int create) +{ + char buf[128]; + /* TODO: cache the channel_tag_t * pointer */ + snprintf(buf, sizeof(buf), "*** %s", bq->bq_name ?: "???"); + return channel_tag_find_by_name(buf, create); +} + +/* + * + */ +static int +noname(const char *s) +{ + if (!s) + return 1; + while (*s) { + if (*s > ' ') + return 0; + s++; + } + return 1; +} + /* * */ static void bouquet_map_channel(bouquet_t *bq, service_t *t) { + channel_t *ch = NULL; channel_service_mapping_t *csm; + if (!bq->bq_mapnolcn && service_get_channel_number(t) <= 0) + return; + if (!bq->bq_mapnoname && noname(service_get_channel_name(t))) + return; LIST_FOREACH(csm, &t->s_channels, csm_svc_link) if (csm->csm_chn->ch_bouquet == bq) break; if (!csm) - service_mapper_process(t, bq); + ch = service_mapper_process(t, bq); + else + ch = csm->csm_chn; + if (ch && bq->bq_chtag) + channel_tag_map(ch, bouquet_tag(bq, 1)); } /* @@ -324,6 +361,68 @@ bouquet_class_maptoch_notify ( void *obj ) bouquet_map_to_channels((bouquet_t *)obj); } +static void +bouquet_class_mapnolcn_notify ( void *obj ) +{ + bouquet_t *bq = obj; + service_t *t; + size_t z; + + if (!bq->bq_mapnolcn && bq->bq_enabled && bq->bq_maptoch) { + for (z = 0; z < bq->bq_services->is_count; z++) { + t = (service_t *)bq->bq_services->is_array[z]; + if (service_get_channel_number(t) <= 0) + bouquet_unmap_channel(bq, t); + } + } else { + bouquet_map_to_channels((bouquet_t *)obj); + } +} + +static void +bouquet_class_mapnoname_notify ( void *obj ) +{ + bouquet_t *bq = obj; + service_t *t; + size_t z; + + if (!bq->bq_mapnoname && bq->bq_enabled && bq->bq_maptoch) { + for (z = 0; z < bq->bq_services->is_count; z++) { + t = (service_t *)bq->bq_services->is_array[z]; + if (noname(service_get_channel_name(t))) + bouquet_unmap_channel(bq, t); + } + } else { + bouquet_map_to_channels((bouquet_t *)obj); + } +} + +static void +bouquet_class_chtag_notify ( void *obj ) +{ + bouquet_t *bq = obj; + service_t *t; + channel_service_mapping_t *csm; + channel_tag_t *ct; + size_t z; + + if (!bq->bq_chtag && bq->bq_enabled && bq->bq_maptoch) { + ct = bouquet_tag(bq, 0); + if (!ct) + return; + for (z = 0; z < bq->bq_services->is_count; z++) { + t = (service_t *)bq->bq_services->is_array[z]; + LIST_FOREACH(csm, &t->s_channels, csm_svc_link) + if (csm->csm_chn->ch_bouquet == bq) + break; + if (csm) + channel_tag_unmap(csm->csm_chn, ct); + } + } else { + bouquet_map_to_channels((bouquet_t *)obj); + } +} + static const void * bouquet_class_services_get ( void *obj ) { @@ -393,6 +492,27 @@ const idclass_t bouquet_class = { .off = offsetof(bouquet_t, bq_maptoch), .notify = bouquet_class_maptoch_notify, }, + { + .type = PT_BOOL, + .id = "mapnolcn", + .name = "Map Zero Numbers", + .off = offsetof(bouquet_t, bq_mapnolcn), + .notify = bouquet_class_mapnolcn_notify, + }, + { + .type = PT_BOOL, + .id = "mapnoname", + .name = "Map No Name", + .off = offsetof(bouquet_t, bq_mapnoname), + .notify = bouquet_class_mapnoname_notify, + }, + { + .type = PT_BOOL, + .id = "chtag", + .name = "Create Tag", + .off = offsetof(bouquet_t, bq_chtag), + .notify = bouquet_class_chtag_notify, + }, { .type = PT_STR, .id = "name", diff --git a/src/bouquet.h b/src/bouquet.h index fa577e60..98654165 100644 --- a/src/bouquet.h +++ b/src/bouquet.h @@ -34,6 +34,9 @@ typedef struct bouquet { int bq_shield; int bq_enabled; int bq_maptoch; + int bq_mapnolcn; + int bq_mapnoname; + int bq_chtag; char *bq_name; char *bq_src; char *bq_comment; diff --git a/src/channels.c b/src/channels.c index 8d9a7be2..141497e6 100644 --- a/src/channels.c +++ b/src/channels.c @@ -912,6 +912,25 @@ channel_tag_mapping_destroy(channel_tag_mapping_t *ctm, int flags) } } +/** + * + */ +void +channel_tag_unmap(channel_t *ch, channel_tag_t *ct) +{ + channel_tag_mapping_t *ctm, *n; + + for (ctm = LIST_FIRST(&ch->ch_ctms); ctm != NULL; ctm = n) { + n = LIST_NEXT(ctm, ctm_channel_link); + if (ctm->ctm_channel == ch) { + LIST_REMOVE(ctm, ctm_channel_link); + LIST_REMOVE(ctm, ctm_tag_link); + free(ctm); + channel_tag_save(ct); + return; + } + } +} /** * diff --git a/src/channels.h b/src/channels.h index a1fd54e3..cc38bcd1 100644 --- a/src/channels.h +++ b/src/channels.h @@ -179,6 +179,7 @@ const char * channel_tag_get_icon(channel_tag_t *ct); int channel_access(channel_t *ch, struct access *a, const char *username); int channel_tag_map(channel_t *ch, channel_tag_t *ct); +void channel_tag_unmap(channel_t *ch, channel_tag_t *ct); void channel_save(channel_t *ch); diff --git a/src/service_mapper.c b/src/service_mapper.c index 4f8f46a9..ddfe8360 100644 --- a/src/service_mapper.c +++ b/src/service_mapper.c @@ -264,7 +264,7 @@ service_mapper_clean ( service_t *s, channel_t *c, void *origin ) /* * Process a service */ -void +channel_t * service_mapper_process ( service_t *s, bouquet_t *bq ) { channel_t *chn = NULL; @@ -327,6 +327,7 @@ service_mapper_process ( service_t *s, bouquet_t *bq ) /* Remove */ exit: service_mapper_remove(s); + return chn; } /** diff --git a/src/service_mapper.h b/src/service_mapper.h index c7e94ffa..f10118fe 100644 --- a/src/service_mapper.h +++ b/src/service_mapper.h @@ -75,7 +75,7 @@ void service_mapper_unlink ( struct service *s, struct channel *c, void *origin int service_mapper_clean ( struct service *s, struct channel *ch, void *origin ); // Process one service -void service_mapper_process ( struct service *s, struct bouquet *bq ); +struct channel *service_mapper_process ( struct service *s, struct bouquet *bq ); // Resets the stat counters void service_mapper_reset_stats ( void ); diff --git a/src/webui/static/app/cteditor.js b/src/webui/static/app/cteditor.js index bbba0392..2755c2dc 100644 --- a/src/webui/static/app/cteditor.js +++ b/src/webui/static/app/cteditor.js @@ -32,7 +32,7 @@ tvheadend.cteditor = function(panel, index) */ tvheadend.bouquet = function(panel, index) { - var list = 'enabled,name,maptoch,source,services_count,comment,lcn_off'; + var list = 'enabled,name,maptoch,mapnolcn,lcn_off,mapnoname,chtag,source,services_count,comment'; tvheadend.idnode_grid(panel, { url: 'api/bouquet', @@ -40,6 +40,18 @@ tvheadend.bouquet = function(panel, index) titleP: 'Bouquets', iconCls: 'bouquets', tabIndex: index, + columns: { + enabled: { width: 50 }, + name: { width: 200 }, + maptoch: { width: 100 }, + mapnolcn: { width: 100 }, + lcn_off: { width: 100 }, + mapnoname: { width: 100 }, + chtag: { width: 100 }, + source: { width: 200 }, + services_count: { width: 100 }, + comment: { width: 200 }, + }, list: list, del: true, edit: { params: { list: list } },