bouquets: add auto-map, auto-remove features
This commit is contained in:
parent
7134315e0f
commit
42901e6140
12 changed files with 265 additions and 71 deletions
|
@ -25,6 +25,28 @@
|
|||
#include "access.h"
|
||||
#include "api.h"
|
||||
|
||||
static int
|
||||
api_bouquet_list
|
||||
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
bouquet_t *bq;
|
||||
htsmsg_t *l, *e;
|
||||
|
||||
l = htsmsg_create_list();
|
||||
pthread_mutex_lock(&global_lock);
|
||||
RB_FOREACH(bq, &bouquets, bq_link) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(&bq->bq_id));
|
||||
htsmsg_add_str(e, "val", bq->bq_name ?: "");
|
||||
htsmsg_add_msg(l, NULL, e);
|
||||
}
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
*resp = htsmsg_create_map();
|
||||
htsmsg_add_msg(*resp, "entries", l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
api_bouquet_grid
|
||||
( access_t *perm, idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
|
@ -57,6 +79,7 @@ api_bouquet_create
|
|||
void api_bouquet_init ( void )
|
||||
{
|
||||
static api_hook_t ah[] = {
|
||||
{ "bouquet/list", ACCESS_ADMIN, api_bouquet_list, NULL },
|
||||
{ "bouquet/class", ACCESS_ADMIN, api_idnode_class, (void*)&bouquet_class },
|
||||
{ "bouquet/grid", ACCESS_ADMIN, api_idnode_grid, api_bouquet_grid },
|
||||
{ "bouquet/create", ACCESS_ADMIN, api_bouquet_create, NULL },
|
||||
|
|
137
src/bouquet.c
137
src/bouquet.c
|
@ -21,6 +21,8 @@
|
|||
#include "access.h"
|
||||
#include "bouquet.h"
|
||||
#include "service.h"
|
||||
#include "channels.h"
|
||||
#include "service_mapper.h"
|
||||
|
||||
bouquet_tree_t bouquets;
|
||||
|
||||
|
@ -47,6 +49,7 @@ bouquet_create(const char *uuid, htsmsg_t *conf,
|
|||
|
||||
bq = calloc(1, sizeof(bouquet_t));
|
||||
bq->bq_services = idnode_set_create();
|
||||
bq->bq_active_services = idnode_set_create();
|
||||
|
||||
if (idnode_insert(&bq->bq_id, uuid, &bouquet_class, 0)) {
|
||||
if (uuid)
|
||||
|
@ -93,6 +96,7 @@ bouquet_destroy(bouquet_t *bq)
|
|||
RB_REMOVE(&bouquets, bq, bq_link);
|
||||
idnode_unlink(&bq->bq_id);
|
||||
|
||||
idnode_set_free(bq->bq_active_services);
|
||||
idnode_set_free(bq->bq_services);
|
||||
free(bq->bq_name);
|
||||
free(bq->bq_src);
|
||||
|
@ -136,6 +140,21 @@ bouquet_find_by_source(const char *name, const char *src, int create)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
bouquet_map_channel(bouquet_t *bq, service_t *t)
|
||||
{
|
||||
channel_service_mapping_t *csm;
|
||||
|
||||
LIST_FOREACH(csm, &t->s_channels, csm_svc_link)
|
||||
if (csm->csm_chn->ch_bouquet == bq)
|
||||
break;
|
||||
if (!csm)
|
||||
service_mapper_process(t, bq);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
@ -145,8 +164,88 @@ bouquet_add_service(bouquet_t *bq, service_t *s)
|
|||
lock_assert(&global_lock);
|
||||
|
||||
if (!idnode_set_exists(bq->bq_services, &s->s_id)) {
|
||||
tvhtrace("bouquet", "add service %s to %s", s->s_nicename, bq->bq_name ?: "<unknown>");
|
||||
idnode_set_add(bq->bq_services, &s->s_id, NULL);
|
||||
bq->bq_saveflag = 1;
|
||||
if (bq->bq_enabled && bq->bq_maptoch)
|
||||
bouquet_map_channel(bq, s);
|
||||
}
|
||||
if (!bq->bq_in_load &&
|
||||
!idnode_set_exists(bq->bq_active_services, &s->s_id))
|
||||
idnode_set_add(bq->bq_active_services, &s->s_id, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
bouquet_unmap_channel(bouquet_t *bq, service_t *t)
|
||||
{
|
||||
channel_service_mapping_t *csm, *csm_next;
|
||||
|
||||
csm = LIST_FIRST(&t->s_channels);
|
||||
while (csm) {
|
||||
csm_next = LIST_NEXT(csm, csm_svc_link);
|
||||
if (csm->csm_chn->ch_bouquet == bq) {
|
||||
tvhinfo("bouquet", "%s / %s: unmapped from %s",
|
||||
channel_get_name(csm->csm_chn), t->s_nicename,
|
||||
bq->bq_name ?: "<unknown>");
|
||||
channel_delete(csm->csm_chn, 1);
|
||||
}
|
||||
csm = csm_next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
static void
|
||||
bouquet_remove_service(bouquet_t *bq, service_t *s)
|
||||
{
|
||||
tvhtrace("bouquet", "remove service %s from %s", s->s_nicename, bq->bq_name ?: "<unknown>");
|
||||
idnode_set_remove(bq->bq_services, &s->s_id);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_completed(bouquet_t *bq)
|
||||
{
|
||||
idnode_set_t *remove;
|
||||
size_t z;
|
||||
|
||||
tvhtrace("bouquet", "completed: active=%zi old=%zi",
|
||||
bq->bq_active_services->is_count, bq->bq_services->is_count);
|
||||
|
||||
remove = idnode_set_create();
|
||||
for (z = 0; z < bq->bq_services->is_count; z++)
|
||||
if (!idnode_set_exists(bq->bq_active_services, bq->bq_services->is_array[z]))
|
||||
idnode_set_add(remove, bq->bq_services->is_array[z], NULL);
|
||||
for (z = 0; z < remove->is_count; z++)
|
||||
bouquet_remove_service(bq, (service_t *)remove->is_array[z]);
|
||||
idnode_set_free(remove);
|
||||
|
||||
idnode_set_free(bq->bq_active_services);
|
||||
bq->bq_active_services = idnode_set_create();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_map_to_channels(bouquet_t *bq)
|
||||
{
|
||||
service_t *t;
|
||||
size_t z;
|
||||
|
||||
for (z = 0; z < bq->bq_services->is_count; z++) {
|
||||
t = (service_t *)bq->bq_services->is_array[z];
|
||||
if (bq->bq_enabled && bq->bq_maptoch) {
|
||||
bouquet_map_channel(bq, t);
|
||||
} else {
|
||||
bouquet_unmap_channel(bq, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,20 +301,27 @@ bouquet_class_get_title (idnode_t *self)
|
|||
return bq->bq_name ?: "";
|
||||
}
|
||||
|
||||
/* exported for others */
|
||||
htsmsg_t *
|
||||
bouquet_class_get_list(void *o)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "bouquet/list");
|
||||
htsmsg_add_str(m, "event", "bouquet");
|
||||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
bouquet_class_enabled_notify ( void *obj )
|
||||
{
|
||||
bouquet_t *bq = obj;
|
||||
service_t *s;
|
||||
size_t z;
|
||||
bouquet_map_to_channels((bouquet_t *)obj);
|
||||
}
|
||||
|
||||
if (!bq->bq_enabled) {
|
||||
for (z = 0; z < bq->bq_services->is_count; z++) {
|
||||
s = (service_t *)bq->bq_services->is_array[z];
|
||||
if (s->s_master_bouquet == bq)
|
||||
s->s_master_bouquet = NULL;
|
||||
}
|
||||
}
|
||||
static void
|
||||
bouquet_class_maptoch_notify ( void *obj )
|
||||
{
|
||||
bouquet_map_to_channels((bouquet_t *)obj);
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
@ -280,6 +386,13 @@ const idclass_t bouquet_class = {
|
|||
.off = offsetof(bouquet_t, bq_enabled),
|
||||
.notify = bouquet_class_enabled_notify,
|
||||
},
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "maptoch",
|
||||
.name = "Auto-Map to Channels",
|
||||
.off = offsetof(bouquet_t, bq_maptoch),
|
||||
.notify = bouquet_class_maptoch_notify,
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "name",
|
||||
|
@ -334,6 +447,7 @@ bouquet_init(void)
|
|||
{
|
||||
htsmsg_t *c, *m;
|
||||
htsmsg_field_t *f;
|
||||
bouquet_t *bq;
|
||||
|
||||
RB_INIT(&bouquets);
|
||||
|
||||
|
@ -341,7 +455,8 @@ bouquet_init(void)
|
|||
if ((c = hts_settings_load("bouquet")) != NULL) {
|
||||
HTSMSG_FOREACH(f, c) {
|
||||
if (!(m = htsmsg_field_get_map(f))) continue;
|
||||
(void)bouquet_create(f->hmf_name, m, NULL, NULL);
|
||||
bq = bouquet_create(f->hmf_name, m, NULL, NULL);
|
||||
bq->bq_saveflag = 0;
|
||||
}
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
|
|
@ -29,13 +29,16 @@ typedef struct bouquet {
|
|||
|
||||
int bq_saveflag;
|
||||
int bq_in_load;
|
||||
time_t bq_updated;
|
||||
|
||||
int bq_shield;
|
||||
int bq_enabled;
|
||||
int bq_maptoch;
|
||||
char *bq_name;
|
||||
char *bq_src;
|
||||
char *bq_comment;
|
||||
idnode_set_t *bq_services;
|
||||
idnode_set_t *bq_active_services;
|
||||
htsmsg_t *bq_services_waiting;
|
||||
uint32_t bq_lcn_offset;
|
||||
|
||||
|
@ -50,37 +53,30 @@ extern const idclass_t bouquet_class;
|
|||
/**
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_create(const char *uuid, htsmsg_t *conf,
|
||||
const char *name, const char *src);
|
||||
|
||||
htsmsg_t * bouquet_class_get_list(void *o);
|
||||
|
||||
bouquet_t * bouquet_create(const char *uuid, htsmsg_t *conf,
|
||||
const char *name, const char *src);
|
||||
|
||||
void bouquet_destroy_by_service(service_t *t);
|
||||
|
||||
static inline bouquet_t *
|
||||
bouquet_find_by_uuid(const char *uuid)
|
||||
{ return (bouquet_t *)idnode_find(uuid, &bouquet_class, NULL); }
|
||||
|
||||
bouquet_t * bouquet_find_by_source(const char *name, const char *src, int create);
|
||||
|
||||
void bouquet_map_to_channels(bouquet_t *bq);
|
||||
void bouquet_add_service(bouquet_t *bq, service_t *s);
|
||||
void bouquet_completed(bouquet_t *bq);
|
||||
|
||||
void bouquet_save(bouquet_t *bq, int notify);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_destroy_by_service(service_t *t);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bouquet_t *
|
||||
bouquet_find_by_source(const char *name, const char *src, int create);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_add_service(bouquet_t *bq, service_t *s);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
bouquet_save(bouquet_t *bq, int notify);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void bouquet_init(void);
|
||||
void bouquet_service_resolve(void);
|
||||
void bouquet_done(void);
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "imagecache.h"
|
||||
#include "service_mapper.h"
|
||||
#include "htsbuf.h"
|
||||
#include "bouquet.h"
|
||||
#include "intlconv.h"
|
||||
|
||||
struct channel_tree channels;
|
||||
|
@ -273,6 +274,33 @@ channel_class_epggrab_list ( void *o )
|
|||
return m;
|
||||
}
|
||||
|
||||
static const void *
|
||||
channel_class_bouquet_get ( void *o )
|
||||
{
|
||||
static const char *sbuf;
|
||||
channel_t *ch = o;
|
||||
if (ch->ch_bouquet)
|
||||
sbuf = idnode_uuid_as_str(&ch->ch_bouquet->bq_id);
|
||||
else
|
||||
sbuf = "";
|
||||
return &sbuf;
|
||||
}
|
||||
|
||||
static int
|
||||
channel_class_bouquet_set ( void *o, const void *v )
|
||||
{
|
||||
channel_t *ch = o;
|
||||
bouquet_t *bq = bouquet_find_by_uuid(v);
|
||||
if (bq == NULL && ch->ch_bouquet) {
|
||||
ch->ch_bouquet = NULL;
|
||||
return 1;
|
||||
} else if (bq != ch->ch_bouquet) {
|
||||
ch->ch_bouquet = bq;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const idclass_t channel_class = {
|
||||
.ic_class = "channel",
|
||||
.ic_caption = "Channel",
|
||||
|
@ -363,6 +391,15 @@ const idclass_t channel_class = {
|
|||
.list = channel_tag_class_get_list,
|
||||
.rend = channel_class_tags_rend
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "bouquet",
|
||||
.name = "Bouquet (auto)",
|
||||
.get = channel_class_bouquet_get,
|
||||
.set = channel_class_bouquet_set,
|
||||
.list = bouquet_class_get_list,
|
||||
.opts = PO_RDONLY
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
@ -527,12 +564,20 @@ channel_get_name ( channel_t *ch )
|
|||
int64_t
|
||||
channel_get_number ( channel_t *ch )
|
||||
{
|
||||
int n;
|
||||
int64_t n = 0;
|
||||
channel_service_mapping_t *csm;
|
||||
if (ch->ch_number) return ch->ch_number;
|
||||
LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
|
||||
if ((n = service_get_channel_number(csm->csm_svc)))
|
||||
return n;
|
||||
if (ch->ch_number) {
|
||||
n = ch->ch_number;
|
||||
} else {
|
||||
LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
|
||||
if ((n = service_get_channel_number(csm->csm_svc)))
|
||||
break;
|
||||
}
|
||||
if (n) {
|
||||
if (ch->ch_bouquet)
|
||||
n += (int64_t)ch->ch_bouquet->bq_lcn_offset * CHANNEL_SPLIT;
|
||||
return n;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "idnode.h"
|
||||
|
||||
struct access;
|
||||
struct bouquet;
|
||||
|
||||
RB_HEAD(channel_tree, channel);
|
||||
|
||||
|
@ -52,6 +53,7 @@ typedef struct channel
|
|||
int64_t ch_number;
|
||||
char *ch_icon;
|
||||
struct channel_tag_mapping_list ch_ctms;
|
||||
struct bouquet *ch_bouquet;
|
||||
|
||||
/* Service/subscriptions */
|
||||
LIST_HEAD(, channel_service_mapping) ch_services;
|
||||
|
|
|
@ -111,6 +111,7 @@ typedef struct mpegts_table_state
|
|||
int version;
|
||||
int complete;
|
||||
uint32_t sections[8];
|
||||
void *bouquet;
|
||||
RB_ENTRY(mpegts_table_state) link;
|
||||
} mpegts_table_state_t;
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ dvb_desc_service_list
|
|||
|
||||
static int
|
||||
dvb_desc_local_channel
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm, bouquet_t *bq )
|
||||
( const char *dstr, const uint8_t *ptr, int len, mpegts_mux_t *mm )
|
||||
{
|
||||
int save = 0;
|
||||
uint16_t sid, lcn;
|
||||
|
@ -358,11 +358,6 @@ dvb_desc_local_channel
|
|||
if (lcn && mm) {
|
||||
mpegts_service_t *s = mpegts_service_find(mm, sid, 0, 0, &save);
|
||||
if (s) {
|
||||
if (bq && bq->bq_lcn_offset &&
|
||||
(!s->s_master_bouquet || s->s_master_bouquet == bq)) {
|
||||
lcn += bq->bq_lcn_offset;
|
||||
s->s_master_bouquet = bq;
|
||||
}
|
||||
if (s->s_dvb_channel_num != lcn) {
|
||||
s->s_dvb_channel_num = lcn;
|
||||
s->s_config_save((service_t*)s);
|
||||
|
@ -740,6 +735,13 @@ dvb_nit_callback
|
|||
if (tableid != 0x40 && tableid != 0x41 && tableid != 0x4A && tableid != 0xBC)
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, &st, §, &last, &ver);
|
||||
if (r == 0) {
|
||||
if (tableid != 0xBC /* fastscan */) {
|
||||
RB_FOREACH(st, &mt->mt_state, link)
|
||||
if (st->bouquet)
|
||||
bouquet_completed((bouquet_t *)st->bouquet);
|
||||
}
|
||||
}
|
||||
if (r != 1) return r;
|
||||
|
||||
/* NIT */
|
||||
|
@ -805,9 +807,9 @@ dvb_nit_callback
|
|||
|
||||
#if ENABLE_MPEGTS_DVB
|
||||
dauth[0] = 0;
|
||||
if (mux && *name && tableid == 0x4A /* BAT */) {
|
||||
if (idnode_is_instance(&mux->mm_id, &dvb_mux_dvbs_class)) {
|
||||
dvb_mux_conf_t *mc = &((dvb_mux_t *)mux)->lm_tuning;
|
||||
if (!bq && *name && tableid == 0x4A /* BAT */) {
|
||||
if (idnode_is_instance(&mm->mm_id, &dvb_mux_dvbs_class)) {
|
||||
dvb_mux_conf_t *mc = &((dvb_mux_t *)mm)->lm_tuning;
|
||||
if (mc->u.dmc_fe_qpsk.orbital_dir) {
|
||||
int pos = mc->u.dmc_fe_qpsk.orbital_pos;
|
||||
if (mc->u.dmc_fe_qpsk.orbital_dir == 'W')
|
||||
|
@ -825,6 +827,7 @@ dvb_nit_callback
|
|||
if (bq2 != bq && bq && bq->bq_saveflag)
|
||||
bouquet_save(bq, 1);
|
||||
bq = bq2;
|
||||
st->bouquet = bq;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -881,7 +884,7 @@ dvb_nit_callback
|
|||
mpegts_mux_set_crid_authority(mux, dauth);
|
||||
break;
|
||||
case DVB_DESC_LOCAL_CHAN:
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux, bq))
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux))
|
||||
return -1;
|
||||
break;
|
||||
case DVB_DESC_SERVICE_LIST:
|
||||
|
@ -1170,6 +1173,7 @@ dvb_fs_sdt_callback
|
|||
if (tableid != 0xBD)
|
||||
return -1;
|
||||
r = dvb_table_begin(mt, ptr, len, tableid, nbid, 7, &st, §, &last, &ver);
|
||||
if (r == 0) bouquet_completed(bq);
|
||||
if (r != 1) return r;
|
||||
if (len < 5) return -1;
|
||||
ptr += 5;
|
||||
|
@ -1216,7 +1220,7 @@ dvb_fs_sdt_callback
|
|||
LIST_FOREACH(mux, &mn->mn_muxes, mm_network_link)
|
||||
if (mux->mm_onid == onid && mux->mm_tsid == tsid)
|
||||
break;
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux, bq))
|
||||
if (dvb_desc_local_channel(mt->mt_name, dptr, dlen, mux))
|
||||
return -1;
|
||||
break;
|
||||
case DVB_DESC_SAT_DEL:
|
||||
|
|
|
@ -443,11 +443,6 @@ typedef struct service {
|
|||
|
||||
int64_t s_current_pts;
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
void *s_master_bouquet;
|
||||
|
||||
} service_t;
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "streaming.h"
|
||||
#include "service.h"
|
||||
#include "profile.h"
|
||||
#include "bouquet.h"
|
||||
#include "api.h"
|
||||
|
||||
static service_mapper_status_t service_mapper_stat;
|
||||
|
@ -38,7 +39,6 @@ static pthread_cond_t service_mapper_cond;
|
|||
static struct service_queue service_mapper_queue;
|
||||
static service_mapper_conf_t service_mapper_conf;
|
||||
|
||||
static void service_mapper_process ( service_t *s );
|
||||
static void *service_mapper_thread ( void *p );
|
||||
|
||||
/**
|
||||
|
@ -80,7 +80,8 @@ service_mapper_start ( const service_mapper_conf_t *conf, htsmsg_t *uuids )
|
|||
service_t *s;
|
||||
|
||||
/* Reset stat counters */
|
||||
service_mapper_reset_stats();
|
||||
if (TAILQ_EMPTY(&service_mapper_queue))
|
||||
service_mapper_reset_stats();
|
||||
|
||||
/* Store config */
|
||||
service_mapper_conf = *conf;
|
||||
|
@ -135,7 +136,7 @@ service_mapper_start ( const service_mapper_conf_t *conf, htsmsg_t *uuids )
|
|||
/* Process */
|
||||
} else {
|
||||
tvhtrace("service_mapper", " process");
|
||||
service_mapper_process(s);
|
||||
service_mapper_process(s, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,29 +265,32 @@ service_mapper_clean ( service_t *s, channel_t *c, void *origin )
|
|||
* Process a service
|
||||
*/
|
||||
void
|
||||
service_mapper_process ( service_t *s )
|
||||
service_mapper_process ( service_t *s, bouquet_t *bq )
|
||||
{
|
||||
channel_t *chn = NULL;
|
||||
const char *name;
|
||||
|
||||
/* Ignore */
|
||||
if (s->s_status == SERVICE_ZOMBIE) {
|
||||
service_mapper_stat.ignore++;
|
||||
if (!bq)
|
||||
service_mapper_stat.ignore++;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Safety check (in-case something has been mapped manually in the interim) */
|
||||
if (LIST_FIRST(&s->s_channels)) {
|
||||
if (!bq && LIST_FIRST(&s->s_channels)) {
|
||||
service_mapper_stat.ignore++;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Find existing channel */
|
||||
name = service_get_channel_name(s);
|
||||
if (service_mapper_conf.merge_same_name && name && *name)
|
||||
if (!bq && service_mapper_conf.merge_same_name && name && *name)
|
||||
chn = channel_find_by_name(name);
|
||||
if (!chn)
|
||||
if (!chn) {
|
||||
chn = channel_create(NULL, NULL, NULL);
|
||||
chn->ch_bouquet = bq;
|
||||
}
|
||||
|
||||
/* Map */
|
||||
if (chn) {
|
||||
|
@ -313,9 +317,12 @@ service_mapper_process ( service_t *s )
|
|||
idnode_notify_simple(&chn->ch_id);
|
||||
channel_save(chn);
|
||||
}
|
||||
service_mapper_stat.ok++;
|
||||
|
||||
tvhinfo("service_mapper", "%s: success", s->s_nicename);
|
||||
if (!bq) {
|
||||
service_mapper_stat.ok++;
|
||||
tvhinfo("service_mapper", "%s: success", s->s_nicename);
|
||||
} else {
|
||||
tvhinfo("bouquet", "%s: mapped service from %s", s->s_nicename, bq->bq_name ?: "<unknown>");
|
||||
}
|
||||
|
||||
/* Remove */
|
||||
exit:
|
||||
|
@ -430,7 +437,7 @@ service_mapper_thread ( void *aux )
|
|||
tvhinfo("service_mapper", "%s: failed [err %s]", s->s_nicename, err);
|
||||
service_mapper_stat.fail++;
|
||||
} else
|
||||
service_mapper_process(s);
|
||||
service_mapper_process(s, NULL);
|
||||
|
||||
service_unref(s);
|
||||
service_mapper_stat.active = NULL;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#ifndef __TVH_SERVICE_MAPPER_H__
|
||||
#define __TVH_SERVICE_MAPPER_H__
|
||||
|
||||
struct bouquet;
|
||||
|
||||
typedef struct service_mapper_conf
|
||||
{
|
||||
int check_availability; ///< Check service is receivable
|
||||
|
@ -72,6 +74,9 @@ 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 );
|
||||
|
||||
// Resets the stat counters
|
||||
void service_mapper_reset_stats ( void );
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ tvheadend.cteditor = function(panel, index)
|
|||
*/
|
||||
tvheadend.bouquet = function(panel, index)
|
||||
{
|
||||
var list = 'enabled,name,source,services_count,comment,lcn_off';
|
||||
var list = 'enabled,name,maptoch,source,services_count,comment,lcn_off';
|
||||
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url: 'api/bouquet',
|
||||
|
|
|
@ -383,6 +383,7 @@ tvheadend.IdNodeField = function(conf)
|
|||
case 'u32':
|
||||
case 'u16':
|
||||
case 's32':
|
||||
case 's64':
|
||||
case 'dbl':
|
||||
case 'time':
|
||||
if (this.hexa) {
|
||||
|
|
Loading…
Add table
Reference in a new issue