Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
bouquets: add auto-map, auto-remove features
  • Loading branch information
perexg committed Nov 8, 2014
1 parent 7134315 commit 42901e6
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 68 deletions.
23 changes: 23 additions & 0 deletions src/api/api_bouquet.c
Expand Up @@ -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 )
Expand Down Expand Up @@ -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 },
Expand Down
137 changes: 126 additions & 11 deletions src/bouquet.c
Expand Up @@ -21,6 +21,8 @@
#include "access.h"
#include "bouquet.h"
#include "service.h"
#include "channels.h"
#include "service_mapper.h"

bouquet_tree_t bouquets;

Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}

/*
*
*/
Expand All @@ -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);
}
}
}

Expand Down Expand Up @@ -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 *
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -334,14 +447,16 @@ bouquet_init(void)
{
htsmsg_t *c, *m;
htsmsg_field_t *f;
bouquet_t *bq;

RB_INIT(&bouquets);

/* Load */
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);
}
Expand Down
42 changes: 19 additions & 23 deletions src/bouquet.h
Expand Up @@ -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;

Expand All @@ -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);

/**
*
*/
void
bouquet_destroy_by_service(service_t *t);
htsmsg_t * bouquet_class_get_list(void *o);

/**
*
*/
bouquet_t *
bouquet_find_by_source(const char *name, const char *src, int create);
bouquet_t * bouquet_create(const char *uuid, htsmsg_t *conf,
const char *name, const char *src);

/**
*
*/
void
bouquet_add_service(bouquet_t *bq, service_t *s);
void bouquet_destroy_by_service(service_t *t);

/**
*
*/
void
bouquet_save(bouquet_t *bq, int notify);
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_init(void);
void bouquet_service_resolve(void);
void bouquet_done(void);
Expand Down
55 changes: 50 additions & 5 deletions src/channels.c
Expand Up @@ -42,6 +42,7 @@
#include "imagecache.h"
#include "service_mapper.h"
#include "htsbuf.h"
#include "bouquet.h"
#include "intlconv.h"

struct channel_tree channels;
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
},
{}
}
};
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 42901e6

Please sign in to comment.