channel: migrated channel_t to an idnode
Also since the channel name is no longer unique various other things have had to be updated.
This commit is contained in:
parent
b9c1171a7d
commit
65c304fb9a
32 changed files with 713 additions and 907 deletions
1
Makefile
1
Makefile
|
@ -112,6 +112,7 @@ SRCS = src/version.c \
|
|||
SRCS += \
|
||||
src/api.c \
|
||||
src/api/api_idnode.c \
|
||||
src/api/api_channel.c \
|
||||
src/api/api_service.c \
|
||||
src/api/api_mpegts.c \
|
||||
|
||||
|
|
|
@ -118,4 +118,5 @@ void api_init ( void )
|
|||
api_idnode_init();
|
||||
api_mpegts_init();
|
||||
api_service_init();
|
||||
api_channel_init();
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ void api_init ( void );
|
|||
void api_idnode_init ( void );
|
||||
void api_mpegts_init ( void );
|
||||
void api_service_init ( void );
|
||||
void api_channel_init ( void );
|
||||
|
||||
/*
|
||||
* IDnode
|
||||
|
@ -85,4 +86,7 @@ int api_idnode_class
|
|||
int api_idnode_tree
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
int api_idnode_load_by_class
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp );
|
||||
|
||||
#endif /* __TVH_API_H__ */
|
||||
|
|
74
src/api/api_channel.c
Normal file
74
src/api/api_channel.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* API - channel related calls
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TVH_API_SERVICE_H__
|
||||
#define __TVH_API_SERVICE_H__
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "channels.h"
|
||||
#include "access.h"
|
||||
#include "api.h"
|
||||
|
||||
// TODO: this will need converting to an idnode system
|
||||
static int
|
||||
api_channel_list
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
channel_t *ch;
|
||||
htsmsg_t *l, *e;
|
||||
|
||||
l = htsmsg_create_list();
|
||||
pthread_mutex_lock(&global_lock);
|
||||
CHANNEL_FOREACH(ch) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(&ch->ch_id));
|
||||
htsmsg_add_str(e, "val", ch->ch_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_channel_grid
|
||||
( idnode_set_t *ins, api_idnode_grid_conf_t *conf )
|
||||
{
|
||||
channel_t *ch;
|
||||
|
||||
CHANNEL_FOREACH(ch)
|
||||
idnode_set_add(ins, (idnode_t*)ch, &conf->filter);
|
||||
}
|
||||
|
||||
void api_channel_init ( void )
|
||||
{
|
||||
static api_hook_t ah[] = {
|
||||
{ "channel/class", ACCESS_ANONYMOUS, api_idnode_class, (void*)&channel_class },
|
||||
{ "channel/grid", ACCESS_ANONYMOUS, api_idnode_grid, api_channel_grid },
|
||||
{ "channel/list", ACCESS_ANONYMOUS, api_channel_list, NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
api_register_all(ah);
|
||||
}
|
||||
|
||||
|
||||
#endif /* __TVH_API_IDNODE_H__ */
|
|
@ -133,9 +133,9 @@ api_idnode_grid
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
api_idnode_load_by_class
|
||||
( const char *class, htsmsg_t *args, htsmsg_t **resp )
|
||||
( void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
|
||||
{
|
||||
int i, _enum;
|
||||
const idclass_t *idc;
|
||||
|
@ -149,10 +149,8 @@ api_idnode_load_by_class
|
|||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Find class */
|
||||
if (!(idc = idclass_find(class))) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return EINVAL;
|
||||
}
|
||||
idc = opaque;
|
||||
assert(idc);
|
||||
|
||||
l = htsmsg_create_list();
|
||||
if ((is = idnode_find_all(idc))) {
|
||||
|
@ -162,7 +160,7 @@ api_idnode_load_by_class
|
|||
/* Name/UUID only */
|
||||
if (_enum) {
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(in));
|
||||
htsmsg_add_str(e, "key", idnode_uuid_as_str(in));
|
||||
htsmsg_add_str(e, "val", idnode_get_title(in));
|
||||
|
||||
/* Full record */
|
||||
|
@ -192,8 +190,16 @@ api_idnode_load
|
|||
const char *uuid, *class;
|
||||
|
||||
/* Class based */
|
||||
if ((class = htsmsg_get_str(args, "class")))
|
||||
return api_idnode_load_by_class(class, args, resp);
|
||||
if ((class = htsmsg_get_str(args, "class"))) {
|
||||
const idclass_t *idc;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
idc = idclass_find(class);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
if (!idc)
|
||||
return EINVAL;
|
||||
// TODO: bit naff that 2 locks are required here
|
||||
return api_idnode_load_by_class((void*)idc, NULL, args, resp);
|
||||
}
|
||||
|
||||
/* UUIDs */
|
||||
if (!(f = htsmsg_field_find(args, "uuid")))
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define __TVH_API_SERVICE_H__
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "service.h"
|
||||
#include "service_mapper.h"
|
||||
#include "access.h"
|
||||
#include "api.h"
|
||||
|
@ -75,10 +76,13 @@ api_mapper_status
|
|||
|
||||
void api_service_init ( void )
|
||||
{
|
||||
extern const idclass_t service_class;
|
||||
static api_hook_t ah[] = {
|
||||
{ "service/mapper/start", ACCESS_ADMIN, api_mapper_start, NULL },
|
||||
{ "service/mapper/stop", ACCESS_ADMIN, api_mapper_stop, NULL },
|
||||
{ "service/mapper/status", ACCESS_ADMIN, api_mapper_status, NULL },
|
||||
{ "service/list", ACCESS_ANONYMOUS, api_idnode_load_by_class,
|
||||
(void*)&service_class },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
|
|
746
src/channels.c
746
src/channels.c
|
@ -40,12 +40,14 @@
|
|||
#include "htsp_server.h"
|
||||
#include "imagecache.h"
|
||||
#include "service_mapper.h"
|
||||
#include "htsbuf.h"
|
||||
|
||||
struct channel_tree channels;
|
||||
|
||||
struct channel_tree channel_name_tree;
|
||||
static struct channel_tree channel_identifier_tree;
|
||||
struct channel_tag_queue channel_tags;
|
||||
static dtable_t *channeltags_dtable;
|
||||
|
||||
static void channel_tag_init ( void );
|
||||
static channel_tag_t *channel_tag_find(const char *id, int create);
|
||||
static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm,
|
||||
int flags);
|
||||
|
@ -53,520 +55,389 @@ static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm,
|
|||
#define CTM_DESTROY_UPDATE_TAG 0x1
|
||||
#define CTM_DESTROY_UPDATE_CHANNEL 0x2
|
||||
|
||||
static int
|
||||
ch_id_cmp ( channel_t *a, channel_t *b )
|
||||
{
|
||||
return channel_get_id(a) - channel_get_id(b);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Class definition
|
||||
* *************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
channel_list_changed(void)
|
||||
channel_class_save ( idnode_t *self )
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_u32(m, "reload", 1);
|
||||
notify_by_msg("channels", m);
|
||||
channel_save((channel_t*)self);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dictcmp(const char *a, const char *b)
|
||||
static const void *
|
||||
channel_class_services_get ( void *obj )
|
||||
{
|
||||
long int da, db;
|
||||
static char *s = NULL;
|
||||
const char *uuid;
|
||||
int first = 1;
|
||||
channel_t *ch = obj;
|
||||
htsbuf_queue_t hq;
|
||||
channel_service_mapping_t *csm;
|
||||
|
||||
/* Free previous */
|
||||
if (s) free(s);
|
||||
s = NULL;
|
||||
|
||||
while(1) {
|
||||
switch((*a >= '0' && *a <= '9' ? 1 : 0)|(*b >= '0' && *b <= '9' ? 2 : 0)) {
|
||||
case 0: /* 0: a is not a digit, nor is b */
|
||||
if(*a != *b)
|
||||
return *(const unsigned char *)a - *(const unsigned char *)b;
|
||||
if(*a == 0)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
break;
|
||||
case 1: /* 1: a is a digit, b is not */
|
||||
case 2: /* 2: a is not a digit, b is */
|
||||
return *(const unsigned char *)a - *(const unsigned char *)b;
|
||||
case 3: /* both are digits, switch to integer compare */
|
||||
da = strtol(a, (char **)&a, 10);
|
||||
db = strtol(b, (char **)&b, 10);
|
||||
if(da != db)
|
||||
return da - db;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
channelcmp(const channel_t *a, const channel_t *b)
|
||||
{
|
||||
return dictcmp(a->ch_name, b->ch_name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
chidcmp(const channel_t *a, const channel_t *b)
|
||||
{
|
||||
return a->ch_id - b->ch_id;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
channel_set_name(channel_t *ch, const char *name)
|
||||
{
|
||||
const char *n2;
|
||||
int l, i;
|
||||
char *cp, c;
|
||||
|
||||
free((void *)ch->ch_name);
|
||||
free((void *)ch->ch_sname);
|
||||
|
||||
ch->ch_name = strdup(name);
|
||||
|
||||
l = strlen(name);
|
||||
ch->ch_sname = cp = malloc(l + 1);
|
||||
|
||||
n2 = strdup(name);
|
||||
|
||||
for(i = 0; i < strlen(n2); i++) {
|
||||
c = tolower(n2[i]);
|
||||
if(isalnum(c))
|
||||
*cp++ = c;
|
||||
/* Add all */
|
||||
LIST_FOREACH(csm, &ch->ch_services, csm_svc_link) {
|
||||
if (first)
|
||||
htsbuf_queue_init(&hq, 0);
|
||||
else
|
||||
*cp++ = '_';
|
||||
}
|
||||
*cp = 0;
|
||||
|
||||
free((void *)n2);
|
||||
|
||||
RB_INSERT_SORTED(&channel_name_tree, ch, ch_name_link, channelcmp);
|
||||
//assert(x == NULL);
|
||||
|
||||
/* Notify clients */
|
||||
channel_list_changed();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static channel_t *
|
||||
channel_create2(const char *name, int number)
|
||||
{
|
||||
channel_t *ch, *x;
|
||||
int id;
|
||||
char buf[32];
|
||||
|
||||
ch = RB_LAST(&channel_identifier_tree);
|
||||
if(ch == NULL) {
|
||||
id = 1;
|
||||
} else {
|
||||
id = ch->ch_id + 1;
|
||||
htsbuf_append(&hq, ",", 1);
|
||||
uuid = idnode_uuid_as_str(&csm->csm_svc->s_id);
|
||||
htsbuf_append(&hq, uuid, strlen(uuid));
|
||||
first = 0;
|
||||
}
|
||||
|
||||
if (!name || !*name) {
|
||||
snprintf(buf, sizeof(buf), "Channel %d", id);
|
||||
name = buf;
|
||||
/* Build string */
|
||||
if (!first) {
|
||||
s = htsbuf_to_string(&hq);
|
||||
htsbuf_queue_flush(&hq);
|
||||
}
|
||||
|
||||
ch = calloc(1, sizeof(channel_t));
|
||||
channel_set_name(ch, name);
|
||||
ch->ch_number = number;
|
||||
|
||||
ch->ch_id = id;
|
||||
x = RB_INSERT_SORTED(&channel_identifier_tree, ch,
|
||||
ch_identifier_link, chidcmp);
|
||||
|
||||
assert(x == NULL);
|
||||
|
||||
epggrab_channel_add(ch);
|
||||
|
||||
htsp_channel_add(ch);
|
||||
return ch;
|
||||
return &s;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
channel_t *
|
||||
channel_create ( const char *name )
|
||||
static int
|
||||
channel_class_services_set ( void *obj, const void *p )
|
||||
{
|
||||
channel_t *ch = channel_create2(name, 0);
|
||||
channel_save(ch);
|
||||
return ch;
|
||||
return channel_set_services_by_list(obj, p);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
channel_t *
|
||||
channel_find_by_name(const char *name, int create, int channel_number)
|
||||
static htsmsg_t *
|
||||
channel_class_services_enum ( void *obj )
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
channel_t *ch, skel;
|
||||
htsmsg_t *e, *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "service/list");
|
||||
htsmsg_add_str(m, "event", "service");
|
||||
e = htsmsg_create_map();
|
||||
htsmsg_add_u32(e, "enum", 1);
|
||||
htsmsg_add_msg(m, "params", e);
|
||||
return m;
|
||||
}
|
||||
|
||||
if (name) {
|
||||
skel.ch_name = (char *)name;
|
||||
ch = RB_FIND(&channel_name_tree, &skel, ch_name_link, channelcmp);
|
||||
if(ch != NULL || create == 0)
|
||||
return ch;
|
||||
static const void *
|
||||
channel_class_tags_get ( void *obj )
|
||||
{
|
||||
static char *s = NULL;
|
||||
int first = 1;
|
||||
channel_t *ch = obj;
|
||||
htsbuf_queue_t hq;
|
||||
channel_tag_mapping_t *ctm;
|
||||
|
||||
/* Free previous */
|
||||
if (s) free(s);
|
||||
s = NULL;
|
||||
|
||||
/* Add all */
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
|
||||
if (first)
|
||||
htsbuf_queue_init(&hq, 0);
|
||||
else
|
||||
htsbuf_append(&hq, ",", 1);
|
||||
htsbuf_append(&hq, ctm->ctm_tag->ct_name, strlen(ctm->ctm_tag->ct_name));
|
||||
first = 0;
|
||||
}
|
||||
return channel_create2(name, channel_number);
|
||||
|
||||
/* Build string */
|
||||
if (!first) {
|
||||
s = htsbuf_to_string(&hq);
|
||||
htsbuf_queue_flush(&hq);
|
||||
}
|
||||
|
||||
return &s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
channel_t *
|
||||
channel_find_by_identifier(int id)
|
||||
static int
|
||||
channel_class_tags_set ( void *obj, const void *p )
|
||||
{
|
||||
channel_t skel, *ch;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
skel.ch_id = id;
|
||||
ch = RB_FIND(&channel_identifier_tree, &skel, ch_identifier_link, chidcmp);
|
||||
return ch;
|
||||
return channel_set_tags_by_list(obj, p);
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
channel_class_tags_enum ( void *obj )
|
||||
{
|
||||
channel_tag_t *ct;
|
||||
htsmsg_t *m = htsmsg_create_list();
|
||||
TAILQ_FOREACH(ct, &channel_tags, ct_link)
|
||||
htsmsg_add_str(m, NULL, ct->ct_name);
|
||||
return m;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
channel_load_one(htsmsg_t *c, int id)
|
||||
channel_class_icon_notify ( void *obj )
|
||||
{
|
||||
channel_t *ch = obj;
|
||||
if (ch->ch_icon)
|
||||
imagecache_get_id(ch->ch_icon);
|
||||
}
|
||||
|
||||
static const char *
|
||||
channel_class_get_title ( idnode_t *self )
|
||||
{
|
||||
channel_t *ch = (channel_t*)self;
|
||||
return ch->ch_name;
|
||||
}
|
||||
|
||||
const idclass_t channel_class = {
|
||||
.ic_class = "service",
|
||||
.ic_caption = "Service",
|
||||
.ic_save = channel_class_save,
|
||||
.ic_get_title = channel_class_get_title,
|
||||
.ic_properties = (const property_t[]){
|
||||
#if 0
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
.id = "enabled",
|
||||
.name = "Enabled",
|
||||
.off = offsetof(service_t, s_enabled),
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "name",
|
||||
.name = "Name",
|
||||
.off = offsetof(channel_t, ch_name),
|
||||
},
|
||||
{
|
||||
.type = PT_INT,
|
||||
.id = "number",
|
||||
.name = "Number",
|
||||
.off = offsetof(channel_t, ch_number),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "icon",
|
||||
.name = "Icon",
|
||||
.off = offsetof(channel_t, ch_icon),
|
||||
.notify = channel_class_icon_notify,
|
||||
},
|
||||
{
|
||||
.type = PT_INT,
|
||||
.id = "dvr_pre_time",
|
||||
.name = "DVR Pre", // TODO: better text?
|
||||
.off = offsetof(channel_t, ch_dvr_extra_time_pre),
|
||||
},
|
||||
{
|
||||
.type = PT_INT,
|
||||
.id = "dvr_pst_time",
|
||||
.name = "DVR Post", // TODO: better text?
|
||||
.off = offsetof(channel_t, ch_dvr_extra_time_post),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "services",
|
||||
.name = "Services",
|
||||
.get = channel_class_services_get,
|
||||
.set = channel_class_services_set,
|
||||
.list = channel_class_services_enum,
|
||||
.opts = PO_MULTI
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "tags",
|
||||
.name = "Tags",
|
||||
.get = channel_class_tags_get,
|
||||
.set = channel_class_tags_set,
|
||||
.list = channel_class_tags_enum,
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
||||
/* **************************************************************************
|
||||
* Find
|
||||
* *************************************************************************/
|
||||
|
||||
// Note: since channel names are no longer unique this method will simply
|
||||
// return the first entry encountered, so could be somewhat random
|
||||
channel_t *
|
||||
channel_find_by_name ( const char *name )
|
||||
{
|
||||
channel_t *ch;
|
||||
const char *name = htsmsg_get_str(c, "name");
|
||||
htsmsg_t *tags;
|
||||
htsmsg_field_t *f;
|
||||
channel_tag_t *ct;
|
||||
char buf[32];
|
||||
|
||||
if(name == NULL)
|
||||
return;
|
||||
|
||||
ch = calloc(1, sizeof(channel_t));
|
||||
ch->ch_id = id;
|
||||
if(RB_INSERT_SORTED(&channel_identifier_tree, ch,
|
||||
ch_identifier_link, chidcmp)) {
|
||||
/* ID collision, should not happen unless there is something
|
||||
wrong in the setting storage */
|
||||
free(ch);
|
||||
return;
|
||||
}
|
||||
|
||||
channel_set_name(ch, name);
|
||||
|
||||
epggrab_channel_add(ch);
|
||||
|
||||
tvh_str_update(&ch->ch_icon, htsmsg_get_str(c, "icon"));
|
||||
imagecache_get_id(ch->ch_icon);
|
||||
|
||||
htsmsg_get_s32(c, "dvr_extra_time_pre", &ch->ch_dvr_extra_time_pre);
|
||||
htsmsg_get_s32(c, "dvr_extra_time_post", &ch->ch_dvr_extra_time_post);
|
||||
htsmsg_get_s32(c, "channel_number", &ch->ch_number);
|
||||
|
||||
if((tags = htsmsg_get_list(c, "tags")) != NULL) {
|
||||
HTSMSG_FOREACH(f, tags) {
|
||||
if(f->hmf_type == HMF_S64) {
|
||||
snprintf(buf, sizeof(buf), "%" PRId64 , f->hmf_s64);
|
||||
|
||||
if((ct = channel_tag_find(buf, 0)) != NULL)
|
||||
channel_tag_map(ch, ct, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: load services
|
||||
CHANNEL_FOREACH(ch)
|
||||
if (!strcmp(ch->ch_name ?: "", name))
|
||||
break;
|
||||
return ch;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
channels_load(void)
|
||||
channel_t *
|
||||
channel_find_by_id ( uint32_t i )
|
||||
{
|
||||
htsmsg_t *l, *c;
|
||||
htsmsg_field_t *f;
|
||||
channel_t skel;
|
||||
memcpy(skel.ch_id.in_uuid, &i, sizeof(i));
|
||||
|
||||
if((l = hts_settings_load("channels")) != NULL) {
|
||||
HTSMSG_FOREACH(f, l) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL)
|
||||
continue;
|
||||
channel_load_one(c, atoi(f->hmf_name));
|
||||
}
|
||||
htsmsg_destroy(l);
|
||||
}
|
||||
return RB_FIND(&channels, &skel, ch_link, ch_id_cmp);
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Property updating
|
||||
* *************************************************************************/
|
||||
|
||||
/**
|
||||
* Write out a config file for a channel
|
||||
*/
|
||||
void
|
||||
channel_save(channel_t *ch)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_t *tags;
|
||||
channel_tag_mapping_t *ctm;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
htsmsg_add_str(m, "name", ch->ch_name);
|
||||
|
||||
if(ch->ch_icon != NULL)
|
||||
htsmsg_add_str(m, "icon", ch->ch_icon);
|
||||
|
||||
tags = htsmsg_create_list();
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
|
||||
htsmsg_add_u32(tags, NULL, ctm->ctm_tag->ct_identifier);
|
||||
|
||||
htsmsg_add_msg(m, "tags", tags);
|
||||
|
||||
htsmsg_add_u32(m, "dvr_extra_time_pre", ch->ch_dvr_extra_time_pre);
|
||||
htsmsg_add_u32(m, "dvr_extra_time_post", ch->ch_dvr_extra_time_post);
|
||||
htsmsg_add_s32(m, "channel_number", ch->ch_number);
|
||||
|
||||
/* TODO: save services */
|
||||
|
||||
hts_settings_save(m, "channels/%d", ch->ch_id);
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a channel and all tied services
|
||||
*/
|
||||
int
|
||||
channel_rename(channel_t *ch, const char *newname)
|
||||
channel_set_services_by_list ( channel_t *ch, const char *svcs )
|
||||
{
|
||||
dvr_entry_t *de;
|
||||
int save = 0;
|
||||
char *tmp, *ret, *tok;
|
||||
service_t *svc;
|
||||
channel_service_mapping_t *csm, *n;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
/* Mark all for deletion */
|
||||
LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
|
||||
csm->csm_mark = 1;
|
||||
|
||||
if (!newname || !*newname) return 0;
|
||||
/* Link */
|
||||
tmp = strdup(svcs);
|
||||
tok = strtok_r(tmp, ",", &ret);
|
||||
while (tok) {
|
||||
if ((svc = service_find(tok)))
|
||||
save |= service_mapper_link(svc, ch);
|
||||
tok = strtok_r(NULL, ",", &ret);
|
||||
}
|
||||
free(tmp);
|
||||
|
||||
if(channel_find_by_name(newname, 0, 0))
|
||||
return -1;
|
||||
|
||||
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" renamed to \"%s\"",
|
||||
ch->ch_name, newname);
|
||||
|
||||
RB_REMOVE(&channel_name_tree, ch, ch_name_link);
|
||||
channel_set_name(ch, newname);
|
||||
epggrab_channel_mod(ch);
|
||||
|
||||
LIST_FOREACH(de, &ch->ch_dvrs, de_channel_link) {
|
||||
dvr_entry_save(de);
|
||||
dvr_entry_notify(de);
|
||||
/* Remove */
|
||||
for (csm = LIST_FIRST(&ch->ch_services); csm != NULL; csm = n) {
|
||||
n = LIST_NEXT(csm, csm_chn_link);
|
||||
if (csm->csm_mark) {
|
||||
LIST_REMOVE(csm, csm_chn_link);
|
||||
LIST_REMOVE(csm, csm_svc_link);
|
||||
free(csm);
|
||||
save = 1;
|
||||
}
|
||||
}
|
||||
|
||||
channel_save(ch);
|
||||
htsp_channel_update(ch);
|
||||
return save;
|
||||
}
|
||||
|
||||
int
|
||||
channel_set_tags_by_list ( channel_t *ch, const char *tags )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete channel
|
||||
*/
|
||||
void
|
||||
channel_delete(channel_t *ch)
|
||||
/* **************************************************************************
|
||||
* Creation/Deletion
|
||||
* *************************************************************************/
|
||||
|
||||
channel_t *
|
||||
channel_create0
|
||||
( channel_t *ch, const idclass_t *idc, const char *uuid, htsmsg_t *conf,
|
||||
const char *name )
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
idnode_insert(&ch->ch_id, uuid, idc);
|
||||
if (RB_INSERT_SORTED(&channels, ch, ch_link, ch_id_cmp)) {
|
||||
tvherror("channel", "id collision!");
|
||||
abort();
|
||||
}
|
||||
|
||||
if (conf)
|
||||
idnode_load(&ch->ch_id, conf);
|
||||
|
||||
/* Override the name */
|
||||
if (name) {
|
||||
free(ch->ch_name);
|
||||
ch->ch_name = strdup(name);
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void
|
||||
channel_delete ( channel_t *ch )
|
||||
{
|
||||
channel_service_mapping_t *t;
|
||||
th_subscription_t *s;
|
||||
channel_tag_mapping_t *ctm;
|
||||
channel_service_mapping_t *csm;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhinfo("channel", "%s - deleting", ch->ch_name);
|
||||
|
||||
/* Tags */
|
||||
while((ctm = LIST_FIRST(&ch->ch_ctms)) != NULL)
|
||||
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_TAG);
|
||||
|
||||
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" deleted",
|
||||
ch->ch_name);
|
||||
|
||||
/* DVR */
|
||||
autorec_destroy_by_channel(ch);
|
||||
|
||||
dvr_destroy_by_channel(ch);
|
||||
|
||||
while((t = LIST_FIRST(&ch->ch_services)) != NULL)
|
||||
service_mapper_unlink(t->csm_svc, ch);
|
||||
/* Services */
|
||||
while((csm = LIST_FIRST(&ch->ch_services)) != NULL)
|
||||
service_mapper_unlink(csm->csm_svc, ch);
|
||||
|
||||
/* Subscriptions */
|
||||
while((s = LIST_FIRST(&ch->ch_subscriptions)) != NULL) {
|
||||
LIST_REMOVE(s, ths_channel_link);
|
||||
s->ths_channel = NULL;
|
||||
}
|
||||
|
||||
/* EPG */
|
||||
#if 0
|
||||
epggrab_channel_rem(ch);
|
||||
epg_channel_unlink(ch);
|
||||
#endif
|
||||
|
||||
hts_settings_remove("channels/%d", ch->ch_id);
|
||||
|
||||
htsp_channel_delete(ch);
|
||||
|
||||
RB_REMOVE(&channel_name_tree, ch, ch_name_link);
|
||||
RB_REMOVE(&channel_identifier_tree, ch, ch_identifier_link);
|
||||
/* Settings */
|
||||
hts_settings_remove("channel/%s", idnode_uuid_as_str(&ch->ch_id));
|
||||
|
||||
/* Free memory */
|
||||
RB_REMOVE(&channels, ch, ch_link);
|
||||
idnode_unlink(&ch->ch_id);
|
||||
free(ch->ch_name);
|
||||
free(ch->ch_sname);
|
||||
free(ch->ch_icon);
|
||||
|
||||
channel_list_changed();
|
||||
|
||||
free(ch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Merge services from channel 'src' to channel 'dst'
|
||||
*
|
||||
* Then, destroy the 'src' channel
|
||||
/*
|
||||
* Save
|
||||
*/
|
||||
void
|
||||
channel_merge(channel_t *dst, channel_t *src)
|
||||
channel_save ( channel_t *ch )
|
||||
{
|
||||
channel_service_mapping_t *t;
|
||||
htsmsg_t *c = htsmsg_create_map();
|
||||
idnode_save(&ch->ch_id, c);
|
||||
hts_settings_save(c, "channel/%s", idnode_uuid_as_str(&ch->ch_id));
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
lock_assert(&global_lock);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
channel_init ( void )
|
||||
{
|
||||
htsmsg_t *c, *e;
|
||||
htsmsg_field_t *f;
|
||||
RB_INIT(&channels);
|
||||
|
||||
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" merged into \"%s\"",
|
||||
src->ch_name, dst->ch_name);
|
||||
/* Tags */
|
||||
channel_tag_init();
|
||||
|
||||
while((t = LIST_FIRST(&src->ch_services)) != NULL)
|
||||
service_mapper_link(t->csm_svc, dst);
|
||||
|
||||
channel_delete(src);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
channel_set_icon(channel_t *ch, const char *icon)
|
||||
{
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if(ch->ch_icon != NULL && !strcmp(ch->ch_icon, icon))
|
||||
/* Channels */
|
||||
if (!(c = hts_settings_load_r(1, "channel")))
|
||||
return;
|
||||
|
||||
free(ch->ch_icon);
|
||||
ch->ch_icon = strdup(icon);
|
||||
imagecache_get_id(icon);
|
||||
channel_save(ch);
|
||||
htsp_channel_update(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of minutes to start before / end after recording on a channel
|
||||
*/
|
||||
void
|
||||
channel_set_epg_postpre_time(channel_t *ch, int pre, int mins)
|
||||
{
|
||||
if (mins < -10000 || mins > 10000)
|
||||
mins = 0;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
tvhlog(LOG_NOTICE, "channels",
|
||||
"Channel \"%s\" epg %s-time set to %d minutes",
|
||||
ch->ch_name, pre ? "pre":"post", mins);
|
||||
|
||||
if (pre) {
|
||||
if (ch->ch_dvr_extra_time_pre == mins)
|
||||
return;
|
||||
else
|
||||
ch->ch_dvr_extra_time_pre = mins;
|
||||
} else {
|
||||
if (ch->ch_dvr_extra_time_post == mins)
|
||||
return;
|
||||
else
|
||||
ch->ch_dvr_extra_time_post = mins;
|
||||
HTSMSG_FOREACH(f, c) {
|
||||
if (!(e = htsmsg_field_get_map(f))) continue;
|
||||
(void)channel_create(f->hmf_name, e, NULL);
|
||||
}
|
||||
channel_save(ch);
|
||||
htsp_channel_update(ch);
|
||||
htsmsg_destroy(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channel number
|
||||
/* ***
|
||||
* Channel tags TODO
|
||||
*/
|
||||
void
|
||||
channel_set_number(channel_t *ch, int number)
|
||||
{
|
||||
if(ch->ch_number == number)
|
||||
return;
|
||||
ch->ch_number = number;
|
||||
channel_save(ch);
|
||||
htsp_channel_update(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
channel_set_tags_from_list(channel_t *ch, const char *maplist)
|
||||
{
|
||||
channel_tag_mapping_t *ctm, *n;
|
||||
channel_tag_t *ct;
|
||||
char buf[40];
|
||||
int i, change = 0;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
|
||||
ctm->ctm_mark = 1; /* Mark for delete */
|
||||
|
||||
while(*maplist) {
|
||||
for(i = 0; i < sizeof(buf) - 1; i++) {
|
||||
buf[i] = *maplist;
|
||||
if(buf[i] == 0)
|
||||
break;
|
||||
|
||||
maplist++;
|
||||
if(buf[i] == ',') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = 0;
|
||||
if((ct = channel_tag_find(buf, 0)) == NULL)
|
||||
continue;
|
||||
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
|
||||
if(ctm->ctm_tag == ct) {
|
||||
ctm->ctm_mark = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if(ctm == NULL) {
|
||||
/* Need to create mapping */
|
||||
change = 1;
|
||||
channel_tag_map(ch, ct, 0);
|
||||
}
|
||||
}
|
||||
|
||||
for(ctm = LIST_FIRST(&ch->ch_ctms); ctm != NULL; ctm = n) {
|
||||
n = LIST_NEXT(ctm, ctm_channel_link);
|
||||
if(ctm->ctm_mark) {
|
||||
change = 1;
|
||||
channel_tag_mapping_destroy(ctm, CTM_DESTROY_UPDATE_TAG |
|
||||
CTM_DESTROY_UPDATE_CHANNEL);
|
||||
}
|
||||
}
|
||||
|
||||
if(change)
|
||||
channel_save(ch);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -883,17 +754,10 @@ channel_tag_find_by_identifier(uint32_t id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
channels_init(void)
|
||||
static void
|
||||
channel_tag_init ( void )
|
||||
{
|
||||
TAILQ_INIT(&channel_tags);
|
||||
|
||||
channeltags_dtable = dtable_create(&channel_tags_dtc, "channeltags", NULL);
|
||||
dtable_load(channeltags_dtable);
|
||||
|
||||
channels_load();
|
||||
}
|
||||
|
|
|
@ -20,51 +20,54 @@
|
|||
#define CHANNELS_H
|
||||
|
||||
#include "epg.h"
|
||||
#include "idnode.h"
|
||||
|
||||
RB_HEAD(channel_tree, channel);
|
||||
|
||||
LIST_HEAD(channel_tag_mapping_list, channel_tag_mapping);
|
||||
TAILQ_HEAD(channel_tag_queue, channel_tag);
|
||||
|
||||
extern struct channel_tag_queue channel_tags;
|
||||
extern struct channel_tree channels;
|
||||
|
||||
#define CHANNEL_FOREACH(ch) RB_FOREACH(ch, &channels, ch_link)
|
||||
|
||||
/*
|
||||
* Channel definition
|
||||
*/
|
||||
typedef struct channel {
|
||||
typedef struct channel
|
||||
{
|
||||
idnode_t ch_id;
|
||||
|
||||
RB_ENTRY(channel) ch_link;
|
||||
|
||||
int ch_refcount;
|
||||
int ch_zombie;
|
||||
|
||||
RB_ENTRY(channel) ch_name_link;
|
||||
/* Channel info */
|
||||
char *ch_name;
|
||||
char *ch_sname;
|
||||
|
||||
RB_ENTRY(channel) ch_identifier_link;
|
||||
int ch_id;
|
||||
int ch_number;
|
||||
char *ch_icon;
|
||||
struct channel_tag_mapping_list ch_ctms;
|
||||
|
||||
/* Service/subscriptions */
|
||||
LIST_HEAD(, channel_service_mapping) ch_services;
|
||||
LIST_HEAD(, th_subscription) ch_subscriptions;
|
||||
LIST_HEAD(, th_subscription) ch_subscriptions;
|
||||
|
||||
/* EPG fields */
|
||||
epg_broadcast_tree_t ch_epg_schedule;
|
||||
epg_broadcast_t *ch_epg_now;
|
||||
epg_broadcast_t *ch_epg_next;
|
||||
gtimer_t ch_epg_timer;
|
||||
gtimer_t ch_epg_timer_head;
|
||||
gtimer_t ch_epg_timer_current;
|
||||
|
||||
gtimer_t ch_epg_timer_head;
|
||||
gtimer_t ch_epg_timer_current;
|
||||
int ch_dvr_extra_time_pre;
|
||||
int ch_dvr_extra_time_post;
|
||||
int ch_number; // User configurable number
|
||||
char *ch_icon;
|
||||
|
||||
/* DVR */
|
||||
int ch_dvr_extra_time_pre;
|
||||
int ch_dvr_extra_time_post;
|
||||
struct dvr_entry_list ch_dvrs;
|
||||
|
||||
struct dvr_autorec_entry_list ch_autorecs;
|
||||
|
||||
struct channel_tag_mapping_list ch_ctms;
|
||||
|
||||
|
||||
} channel_t;
|
||||
|
||||
|
||||
|
@ -85,7 +88,6 @@ typedef struct channel_tag {
|
|||
struct dvr_autorec_entry_list ct_autorecs;
|
||||
} channel_tag_t;
|
||||
|
||||
|
||||
/**
|
||||
* Channel tag mapping
|
||||
*/
|
||||
|
@ -100,39 +102,41 @@ typedef struct channel_tag_mapping {
|
|||
|
||||
} channel_tag_mapping_t;
|
||||
|
||||
/*
|
||||
* Service mappings
|
||||
*/
|
||||
typedef struct channel_service_mapping {
|
||||
LIST_ENTRY(channel_service_mapping) csm_chn_link;
|
||||
LIST_ENTRY(channel_service_mapping) csm_svc_link;
|
||||
|
||||
struct channel *csm_chn;
|
||||
struct service *csm_svc;
|
||||
|
||||
int csm_mark;
|
||||
} channel_service_mapping_t;
|
||||
|
||||
void channels_init(void);
|
||||
extern const idclass_t channel_class;
|
||||
|
||||
channel_t *channel_create(const char *name);
|
||||
void channel_init(void);
|
||||
|
||||
channel_t *channel_find_by_name(const char *name, int create, int number);
|
||||
|
||||
channel_t *channel_find_by_identifier(int id);
|
||||
|
||||
void channel_set_teletext_rundown(channel_t *ch, int v);
|
||||
|
||||
void channel_settings_write(channel_t *ch);
|
||||
|
||||
int channel_rename(channel_t *ch, const char *newname);
|
||||
channel_t *channel_create0
|
||||
(channel_t *ch, const idclass_t *idc, const char *uuid, htsmsg_t *conf,
|
||||
const char *name);
|
||||
#define channel_create(u, c, n)\
|
||||
channel_create0(calloc(1, sizeof(channel_t)), &channel_class, u, c, n)
|
||||
|
||||
void channel_delete(channel_t *ch);
|
||||
|
||||
void channel_merge(channel_t *dst, channel_t *src);
|
||||
channel_t *channel_find_by_name(const char *name);
|
||||
#define channel_find_by_uuid(u)\
|
||||
(channel_t*)idnode_find(NULL, &channel_class)
|
||||
|
||||
void channel_set_epg_postpre_time(channel_t *ch, int pre, int mins);
|
||||
channel_t *channel_find_by_id(uint32_t id);
|
||||
|
||||
void channel_set_number(channel_t *ch, int number);
|
||||
#define channel_find channel_find_by_uuid
|
||||
|
||||
void channel_set_icon(channel_t *ch, const char *icon);
|
||||
|
||||
void channel_set_tags_from_list(channel_t *ch, const char *maplist);
|
||||
int channel_set_tags_by_list ( channel_t *ch, const char *tags );
|
||||
int channel_set_services_by_list ( channel_t *ch, const char *svcs );
|
||||
|
||||
channel_tag_t *channel_tag_find_by_name(const char *name, int create);
|
||||
|
||||
|
@ -142,4 +146,8 @@ int channel_tag_map(channel_t *ch, channel_tag_t *ct, int check);
|
|||
|
||||
void channel_save(channel_t *ch);
|
||||
|
||||
#define channel_get_uuid(ch) idnode_uuid_as_str(&ch->ch_id)
|
||||
|
||||
#define channel_get_id(ch) idnode_get_short_uuid((&ch->ch_id))
|
||||
|
||||
#endif /* CHANNELS_H */
|
||||
|
|
|
@ -362,7 +362,7 @@ autorec_record_update(void *opaque, const char *id, htsmsg_t *values,
|
|||
LIST_REMOVE(dae, dae_channel_link);
|
||||
dae->dae_channel = NULL;
|
||||
}
|
||||
if((ch = channel_find_by_name(s, 0, 0)) != NULL) {
|
||||
if((ch = channel_find(s)) != NULL) {
|
||||
LIST_INSERT_HEAD(&ch->ch_autorecs, dae, dae_channel_link);
|
||||
dae->dae_channel = ch;
|
||||
}
|
||||
|
@ -553,7 +553,7 @@ dvr_autorec_add(const char *config_name,
|
|||
const char *creator, const char *comment)
|
||||
{
|
||||
channel_t *ch = NULL;
|
||||
if(channel != NULL) ch = channel_find_by_name(channel, 0, 0);
|
||||
if(channel != NULL) ch = channel_find(channel);
|
||||
_dvr_autorec_add(config_name, title, ch, tag, content_type,
|
||||
NULL, NULL, NULL, 0, NULL, creator, comment);
|
||||
}
|
||||
|
@ -624,7 +624,7 @@ dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge)
|
|||
if (purge)
|
||||
dvr_autorec_purge_spawns(dae);
|
||||
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
CHANNEL_FOREACH(ch) {
|
||||
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
|
||||
if(autorec_cmp(dae, e))
|
||||
dvr_entry_create_by_autorec(e, dae);
|
||||
|
|
|
@ -519,7 +519,7 @@ static void
|
|||
dvr_db_load_one(htsmsg_t *c, int id)
|
||||
{
|
||||
dvr_entry_t *de;
|
||||
const char *chname, *s, *creator;
|
||||
const char *chuuid, *chname, *s, *creator;
|
||||
channel_t *ch;
|
||||
uint32_t start, stop, bcid, u32;
|
||||
int d;
|
||||
|
@ -531,9 +531,15 @@ dvr_db_load_one(htsmsg_t *c, int id)
|
|||
if(htsmsg_get_u32(c, "stop", &stop))
|
||||
return;
|
||||
|
||||
if((chname = htsmsg_get_str(c, "channel")) == NULL)
|
||||
return;
|
||||
ch = channel_find_by_name(chname, 0, 0);
|
||||
chname = htsmsg_get_str(c, "channel_name");
|
||||
chuuid = htsmsg_get_str(c, "channel");
|
||||
ch = chuuid ? channel_find(chuuid) : NULL;
|
||||
|
||||
/* Backwards compat */
|
||||
if (!ch && !chname) {
|
||||
chname = chuuid;
|
||||
ch = channel_find_by_name(chname);
|
||||
}
|
||||
|
||||
s = htsmsg_get_str(c, "config_name");
|
||||
cfg = dvr_config_find_by_name_default(s);
|
||||
|
@ -648,6 +654,8 @@ dvr_entry_save(dvr_entry_t *de)
|
|||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
if (de->de_channel)
|
||||
htsmsg_add_str(m, "channel", channel_get_uuid(de->de_channel));
|
||||
htsmsg_add_str(m, "channel", DVR_CH_NAME(de));
|
||||
htsmsg_add_u32(m, "start", de->de_start);
|
||||
htsmsg_add_u32(m, "stop", de->de_stop);
|
||||
|
|
19
src/epg.c
19
src/epg.c
|
@ -1721,8 +1721,8 @@ epg_episode_t *epg_broadcast_get_episode
|
|||
if (!ebc) return NULL;
|
||||
if (ebc->episode) return ebc->episode;
|
||||
if (!create) return NULL;
|
||||
snprintf(uri, sizeof(uri)-1, "tvh://channel-%d/bcast-%u/episode",
|
||||
ebc->channel->ch_id, ebc->id);
|
||||
snprintf(uri, sizeof(uri)-1, "tvh://channel-%s/bcast-%u/episode",
|
||||
idnode_uuid_as_str(&ebc->channel->ch_id), ebc->id);
|
||||
if ((ee = epg_episode_find_by_uri(uri, 1, save)))
|
||||
*save |= epg_broadcast_set_episode(ebc, ee, ebc->grabber);
|
||||
return ee;
|
||||
|
@ -1756,7 +1756,7 @@ htsmsg_t *epg_broadcast_serialize ( epg_broadcast_t *broadcast )
|
|||
htsmsg_add_s64(m, "stop", broadcast->stop);
|
||||
htsmsg_add_str(m, "episode", broadcast->episode->uri);
|
||||
if (broadcast->channel)
|
||||
htsmsg_add_u32(m, "channel", broadcast->channel->ch_id);
|
||||
htsmsg_add_str(m, "channel", channel_get_uuid(broadcast->channel));
|
||||
if (broadcast->dvb_eid)
|
||||
htsmsg_add_u32(m, "dvb_eid", broadcast->dvb_eid);
|
||||
if (broadcast->is_widescreen)
|
||||
|
@ -1796,7 +1796,7 @@ epg_broadcast_t *epg_broadcast_deserialize
|
|||
epg_serieslink_t *esl;
|
||||
lang_str_t *ls;
|
||||
const char *str;
|
||||
uint32_t chid, eid, u32;
|
||||
uint32_t eid, u32;
|
||||
int64_t start, stop;
|
||||
|
||||
if ( htsmsg_get_s64(m, "start", &start) ) return NULL;
|
||||
|
@ -1818,9 +1818,8 @@ epg_broadcast_t *epg_broadcast_deserialize
|
|||
}
|
||||
|
||||
/* Get channel */
|
||||
if ( !htsmsg_get_u32(m, "channel", &chid) ) {
|
||||
ch = channel_find_by_identifier(chid);
|
||||
}
|
||||
if ((str = htsmsg_get_str(m, "channel")))
|
||||
ch = channel_find(str);
|
||||
if (!ch) return NULL;
|
||||
|
||||
/* Create */
|
||||
|
@ -2254,9 +2253,11 @@ void epg_query0
|
|||
|
||||
/* All channels */
|
||||
} else {
|
||||
#if TODO
|
||||
RB_FOREACH(channel, &channel_name_tree, ch_name_link) {
|
||||
_eqr_add_channel(eqr, channel, genre, preg, now, lang);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (preg) regfree(preg);
|
||||
|
||||
|
@ -2266,8 +2267,8 @@ void epg_query0
|
|||
void epg_query(epg_query_result_t *eqr, const char *channel, const char *tag,
|
||||
epg_genre_t *genre, const char *title, const char *lang)
|
||||
{
|
||||
channel_t *ch = channel ? channel_find_by_name(channel, 0, 0) : NULL;
|
||||
channel_tag_t *ct = tag ? channel_tag_find_by_name(tag, 0) : NULL;
|
||||
channel_t *ch = channel ? channel_find(channel) : NULL;
|
||||
channel_tag_t *ct = tag ? channel_tag_find_by_name(tag, 0) : NULL;
|
||||
epg_query0(eqr, ch, ct, genre, title, lang);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ extern epg_object_tree_t epg_serieslinks;
|
|||
/*
|
||||
* Use for v1 databases
|
||||
*/
|
||||
#if DEPRECATED
|
||||
static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
|
||||
{
|
||||
channel_t *ch;
|
||||
|
@ -94,6 +95,7 @@ static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
|
|||
/* Set episode */
|
||||
save |= epg_broadcast_set_episode(ebc, ee, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Process v2 data
|
||||
|
@ -207,8 +209,7 @@ void epg_init ( void )
|
|||
case 2:
|
||||
_epgdb_v2_process(m, &stats);
|
||||
break;
|
||||
default: /* v0/1 */
|
||||
_epgdb_v1_process(m, &stats);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -267,8 +268,10 @@ void epg_save ( void *p )
|
|||
{
|
||||
int fd;
|
||||
epg_object_t *eo;
|
||||
#if 0
|
||||
epg_broadcast_t *ebc;
|
||||
channel_t *ch;
|
||||
#endif
|
||||
epggrab_stats_t stats;
|
||||
extern gtimer_t epggrab_save_timer;
|
||||
|
||||
|
@ -300,12 +303,14 @@ void epg_save ( void *p )
|
|||
stats.seasons.total++;
|
||||
}
|
||||
if ( _epg_write_sect(fd, "broadcasts") ) return;
|
||||
#if 0
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
|
||||
if (_epg_write(fd, epg_broadcast_serialize(ebc))) return;
|
||||
stats.broadcasts.total++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stats */
|
||||
tvhlog(LOG_INFO, "epgdb", "saved");
|
||||
|
|
|
@ -57,12 +57,14 @@ void epggrab_channel_link ( epggrab_channel_t *ec, channel_t *ch )
|
|||
ecl = calloc(1, sizeof(epggrab_channel_link_t));
|
||||
ecl->channel = ch;
|
||||
LIST_INSERT_HEAD(&ec->channels, ecl, link);
|
||||
#if 0
|
||||
if (ec->name && epggrab_channel_rename)
|
||||
channel_rename(ch, ec->name);
|
||||
if (ec->icon && epggrab_channel_reicon)
|
||||
channel_set_icon(ch, ec->icon);
|
||||
if (ec->number>0 && epggrab_channel_renumber)
|
||||
channel_set_number(ch, ec->number);
|
||||
#endif
|
||||
|
||||
/* Save */
|
||||
if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec);
|
||||
|
@ -82,6 +84,7 @@ int epggrab_channel_match_and_link ( epggrab_channel_t *ec, channel_t *ch )
|
|||
int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name )
|
||||
{
|
||||
int save = 0;
|
||||
#if 0
|
||||
epggrab_channel_link_t *ecl;
|
||||
if (!ec || !name) return 0;
|
||||
if (!ec->name || strcmp(ec->name, name)) {
|
||||
|
@ -92,6 +95,7 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name )
|
|||
channel_rename(ecl->channel, name);
|
||||
save = 1;
|
||||
}
|
||||
#endif
|
||||
return save;
|
||||
}
|
||||
|
||||
|
@ -99,6 +103,7 @@ int epggrab_channel_set_name ( epggrab_channel_t *ec, const char *name )
|
|||
int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon )
|
||||
{
|
||||
int save = 0;
|
||||
#if 0
|
||||
epggrab_channel_link_t *ecl;
|
||||
if (!ec->icon || strcmp(ec->icon, icon) ) {
|
||||
if (!ec | !icon) return 0;
|
||||
|
@ -109,6 +114,7 @@ int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon )
|
|||
channel_set_icon(ecl->channel, icon);
|
||||
save = 1;
|
||||
}
|
||||
#endif
|
||||
return save;
|
||||
}
|
||||
|
||||
|
@ -116,6 +122,7 @@ int epggrab_channel_set_icon ( epggrab_channel_t *ec, const char *icon )
|
|||
int epggrab_channel_set_number ( epggrab_channel_t *ec, int number )
|
||||
{
|
||||
int save = 0;
|
||||
#if 0
|
||||
epggrab_channel_link_t *ecl;
|
||||
if (!ec || (number <= 0)) return 0;
|
||||
if (ec->number != number) {
|
||||
|
@ -125,12 +132,14 @@ int epggrab_channel_set_number ( epggrab_channel_t *ec, int number )
|
|||
channel_set_number(ecl->channel, number);
|
||||
save = 1;
|
||||
}
|
||||
#endif
|
||||
return save;
|
||||
}
|
||||
|
||||
/* Channel settings updated */
|
||||
void epggrab_channel_updated ( epggrab_channel_t *ec )
|
||||
{
|
||||
#if 0
|
||||
channel_t *ch;
|
||||
if (!ec) return;
|
||||
|
||||
|
@ -141,6 +150,7 @@ void epggrab_channel_updated ( epggrab_channel_t *ec )
|
|||
|
||||
/* Save */
|
||||
if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ID comparison */
|
||||
|
|
|
@ -154,7 +154,7 @@ void epggrab_module_ch_save ( void *_m, epggrab_channel_t *ch )
|
|||
htsmsg_add_str(m, "icon", ch->icon);
|
||||
LIST_FOREACH(ecl, &ch->channels, link) {
|
||||
if (!a) a = htsmsg_create_list();
|
||||
htsmsg_add_u32(a, NULL, ecl->channel->ch_id);
|
||||
htsmsg_add_u32(a, NULL, channel_get_id(ecl->channel));
|
||||
}
|
||||
if (a) htsmsg_add_msg(m, "channels", a);
|
||||
if (ch->number)
|
||||
|
@ -214,7 +214,7 @@ static void _epggrab_module_channel_load
|
|||
egc->number = u32;
|
||||
if ((a = htsmsg_get_list(m, "channels"))) {
|
||||
HTSMSG_FOREACH(f, a) {
|
||||
if ((ch = channel_find_by_identifier((uint32_t)f->hmf_s64))) {
|
||||
if ((ch = channel_find_by_id((uint32_t)f->hmf_s64))) {
|
||||
epggrab_channel_link_t *ecl = calloc(1, sizeof(epggrab_channel_link_t));
|
||||
ecl->channel = ch;
|
||||
LIST_INSERT_HEAD(&egc->channels, ecl, link);
|
||||
|
@ -223,7 +223,7 @@ static void _epggrab_module_channel_load
|
|||
|
||||
/* Compat with older 3.1 code */
|
||||
} else if (!htsmsg_get_u32(m, "channel", &u32)) {
|
||||
if ((ch = channel_find_by_identifier(u32))) {
|
||||
if ((ch = channel_find_by_id(u32))) {
|
||||
epggrab_channel_link_t *ecl = calloc(1, sizeof(epggrab_channel_link_t));
|
||||
ecl->channel = ch;
|
||||
LIST_INSERT_HEAD(&egc->channels, ecl, link);
|
||||
|
|
|
@ -463,7 +463,7 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp)
|
|||
htsmsg_t *tags = htsmsg_create_list();
|
||||
htsmsg_t *services = htsmsg_create_list();
|
||||
|
||||
htsmsg_add_u32(out, "channelId", ch->ch_id);
|
||||
htsmsg_add_u32(out, "channelId", channel_get_id(ch));
|
||||
htsmsg_add_u32(out, "channelNumber", ch->ch_number);
|
||||
|
||||
htsmsg_add_str(out, "channelName", ch->ch_name);
|
||||
|
@ -545,7 +545,7 @@ htsp_build_tag(channel_tag_t *ct, const char *method, int include_channels)
|
|||
|
||||
if(members != NULL) {
|
||||
LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
|
||||
htsmsg_add_u32(members, NULL, ctm->ctm_channel->ch_id);
|
||||
htsmsg_add_u32(members, NULL, channel_get_id(ctm->ctm_channel));
|
||||
htsmsg_add_msg(out, "members", members);
|
||||
}
|
||||
|
||||
|
@ -566,7 +566,7 @@ htsp_build_dvrentry(dvr_entry_t *de, const char *method)
|
|||
|
||||
htsmsg_add_u32(out, "id", de->de_id);
|
||||
if (de->de_channel)
|
||||
htsmsg_add_u32(out, "channel", de->de_channel->ch_id);
|
||||
htsmsg_add_u32(out, "channel", channel_get_id(de->de_channel));
|
||||
|
||||
htsmsg_add_s64(out, "start", de->de_start);
|
||||
htsmsg_add_s64(out, "stop", de->de_stop);
|
||||
|
@ -647,7 +647,7 @@ htsp_build_event
|
|||
htsmsg_add_str(out, "method", method);
|
||||
|
||||
htsmsg_add_u32(out, "eventId", e->id);
|
||||
htsmsg_add_u32(out, "channelId", e->channel->ch_id);
|
||||
htsmsg_add_u32(out, "channelId", channel_get_id(e->channel));
|
||||
htsmsg_add_s64(out, "start", e->start);
|
||||
htsmsg_add_s64(out, "stop", e->stop);
|
||||
if ((str = epg_broadcast_get_title(e, lang)))
|
||||
|
@ -846,7 +846,7 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
htsp_send_message(htsp, htsp_build_tag(ct, "tagAdd", 0), NULL);
|
||||
|
||||
/* Send all channels */
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
|
||||
CHANNEL_FOREACH(ch)
|
||||
htsp_send_message(htsp, htsp_build_channel(ch, "channelAdd", htsp), NULL);
|
||||
|
||||
/* Send all enabled and external tags (now with channel mappings) */
|
||||
|
@ -860,7 +860,7 @@ htsp_method_async(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
|
||||
/* Send EPG updates */
|
||||
if (epg) {
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
|
||||
CHANNEL_FOREACH(ch)
|
||||
RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) {
|
||||
if (epgMaxTime && ebc->start > epgMaxTime) break;
|
||||
htsmsg_t *e = htsp_build_event(ebc, "eventAdd", lang, lastUpdate, htsp);
|
||||
|
@ -915,7 +915,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
|
||||
/* Optional fields */
|
||||
if (!htsmsg_get_u32(in, "channelId", &u32))
|
||||
if (!(ch = channel_find_by_identifier(u32)))
|
||||
if (!(ch = channel_find_by_id(u32)))
|
||||
return htsp_error("Channel does not exist");
|
||||
if (!htsmsg_get_u32(in, "eventId", &u32))
|
||||
if (!(e = epg_broadcast_find_by_id(u32, ch)))
|
||||
|
@ -944,7 +944,7 @@ htsp_method_getEvents(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
/* All channels */
|
||||
} else {
|
||||
events = htsmsg_create_list();
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
CHANNEL_FOREACH(ch) {
|
||||
int num = numFollowing;
|
||||
RB_FOREACH(e, &ch->ch_epg_schedule, sched_link) {
|
||||
if (maxTime && e->start > maxTime) break;
|
||||
|
@ -984,7 +984,7 @@ htsp_method_epgQuery(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
|
||||
/* Optional */
|
||||
if(!(htsmsg_get_u32(in, "channelId", &u32)))
|
||||
if (!(ch = channel_find_by_identifier(u32)))
|
||||
if (!(ch = channel_find_by_id(u32)))
|
||||
return htsp_error("Channel does not exist");
|
||||
if(!(htsmsg_get_u32(in, "tagId", &u32)))
|
||||
if (!(ct = channel_tag_find_by_identifier(u32)))
|
||||
|
@ -1072,7 +1072,7 @@ htsp_method_addDvrEntry(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
if(htsmsg_get_s64(in, "stopExtra", &stop_extra))
|
||||
stop_extra = 0;
|
||||
if(!htsmsg_get_u32(in, "channelId", &u32))
|
||||
ch = channel_find_by_identifier(u32);
|
||||
ch = channel_find_by_id(u32);
|
||||
if(!htsmsg_get_u32(in, "eventId", &eventid))
|
||||
e = epg_broadcast_find_by_id(eventid, ch);
|
||||
if(htsmsg_get_u32(in, "priority", &priority))
|
||||
|
@ -1256,18 +1256,18 @@ htsp_method_subscribe(htsp_connection_t *htsp, htsmsg_t *in)
|
|||
#if ENABLE_TIMESHIFT
|
||||
uint32_t timeshiftPeriod = 0;
|
||||
#endif
|
||||
const char *str;
|
||||
channel_t *ch;
|
||||
htsp_subscription_t *hs;
|
||||
const char *str;
|
||||
if(htsmsg_get_u32(in, "subscriptionId", &sid))
|
||||
return htsp_error("Missing argument 'subscriptionId'");
|
||||
|
||||
if(!htsmsg_get_u32(in, "channelId", &chid)) {
|
||||
|
||||
if((ch = channel_find_by_identifier(chid)) == NULL)
|
||||
if((ch = channel_find_by_id(chid)) == NULL)
|
||||
return htsp_error("Requested channel does not exist");
|
||||
} else if((str = htsmsg_get_str(in, "channelName")) != NULL) {
|
||||
if((ch = channel_find_by_name(str, 0, 0)) == NULL)
|
||||
if((ch = channel_find_by_name(str)) == NULL)
|
||||
return htsp_error("Requested channel does not exist");
|
||||
|
||||
} else {
|
||||
|
@ -2043,7 +2043,7 @@ htsp_channel_update_current(channel_t *ch)
|
|||
|
||||
m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "method", "channelUpdate");
|
||||
htsmsg_add_u32(m, "channelId", ch->ch_id);
|
||||
htsmsg_add_u32(m, "channelId", channel_get_id(ch));
|
||||
|
||||
now = ch->ch_epg_now;
|
||||
next = ch->ch_epg_next;
|
||||
|
@ -2086,7 +2086,7 @@ void
|
|||
htsp_channel_delete(channel_t *ch)
|
||||
{
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
htsmsg_add_u32(m, "channelId", ch->ch_id);
|
||||
htsmsg_add_u32(m, "channelId", channel_get_id(ch));
|
||||
htsmsg_add_str(m, "method", "channelDelete");
|
||||
htsp_async_send(m, HTSP_ASYNC_ON);
|
||||
}
|
||||
|
|
|
@ -206,6 +206,14 @@ idnode_delete(idnode_t *in)
|
|||
* Info
|
||||
* *************************************************************************/
|
||||
|
||||
uint32_t
|
||||
idnode_get_short_uuid (const idnode_t *in)
|
||||
{
|
||||
uint32_t u32;
|
||||
memcpy(&u32, in->in_uuid, sizeof(u32));
|
||||
return u32;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
|
@ -110,6 +110,7 @@ void idnode_init(void);
|
|||
int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc);
|
||||
void idnode_unlink(idnode_t *in);
|
||||
|
||||
uint32_t idnode_get_short_uuid (const idnode_t *in);
|
||||
const char *idnode_uuid_as_str (const idnode_t *in);
|
||||
idnode_set_t *idnode_get_childs (idnode_t *in);
|
||||
const char *idnode_get_title (idnode_t *in);
|
||||
|
|
|
@ -49,7 +49,7 @@ tsfile_network_create_service
|
|||
if (s) {
|
||||
char buf[128];
|
||||
sprintf(buf, "channel-%d", t);
|
||||
channel_t *c = channel_find_by_name(buf, 1, t);
|
||||
channel_t *c = channel_create(NULL, NULL, buf);
|
||||
service_mapper_link((service_t*)s, c);
|
||||
t++;
|
||||
}
|
||||
|
|
29
src/main.c
29
src/main.c
|
@ -701,7 +701,21 @@ main(int argc, char **argv)
|
|||
|
||||
service_init();
|
||||
|
||||
channels_init();
|
||||
#if ENABLE_TSFILE
|
||||
if(opt_tsfile.num) {
|
||||
tsfile_init(opt_tsfile_tuner ?: opt_tsfile.num);
|
||||
for (i = 0; i < opt_tsfile.num; i++)
|
||||
tsfile_add_file(opt_tsfile.str[i]);
|
||||
}
|
||||
#endif
|
||||
#if ENABLE_IPTV
|
||||
iptv_init();
|
||||
#endif
|
||||
#if ENABLE_LINUXDVB
|
||||
linuxdvb_init(adapter_mask);
|
||||
#endif
|
||||
|
||||
channel_init();
|
||||
|
||||
subscription_init();
|
||||
|
||||
|
@ -726,19 +740,6 @@ main(int argc, char **argv)
|
|||
|
||||
htsp_init(opt_bindaddr);
|
||||
|
||||
#if ENABLE_TSFILE
|
||||
if(opt_tsfile.num) {
|
||||
tsfile_init(opt_tsfile_tuner ?: opt_tsfile.num);
|
||||
for (i = 0; i < opt_tsfile.num; i++)
|
||||
tsfile_add_file(opt_tsfile.str[i]);
|
||||
}
|
||||
#endif
|
||||
#if ENABLE_IPTV
|
||||
iptv_init();
|
||||
#endif
|
||||
#if ENABLE_LINUXDVB
|
||||
linuxdvb_init(adapter_mask);
|
||||
#endif
|
||||
|
||||
if(opt_subscribe != NULL)
|
||||
subscription_dummy_join(opt_subscribe, 1);
|
||||
|
|
|
@ -246,6 +246,8 @@ prop_serialize(void *obj, const property_t *pl, htsmsg_t *msg, int optmask, htsm
|
|||
htsmsg_add_u32(m, "nosave", 1);
|
||||
if (pl->opts & PO_WRONCE)
|
||||
htsmsg_add_u32(m, "wronce", 1);
|
||||
if (pl->opts & PO_MULTI)
|
||||
htsmsg_add_u32(m, "multi", 1);
|
||||
|
||||
/* Enum list */
|
||||
if (pl->list)
|
||||
|
|
|
@ -43,6 +43,7 @@ typedef enum {
|
|||
#define PO_RDONLY 0x01 // Property is read-only
|
||||
#define PO_NOSAVE 0x02 // Property is transient (not saved)
|
||||
#define PO_WRONCE 0x04 // Property is write-once (i.e. on creation)
|
||||
#define PO_MULTI 0x08 // Multi-select
|
||||
|
||||
/*
|
||||
* Property definition
|
||||
|
|
115
src/service.c
115
src/service.c
|
@ -49,24 +49,101 @@ static void service_class_save(struct idnode *self);
|
|||
|
||||
struct service_queue service_all;
|
||||
|
||||
#if 0
|
||||
static const void *service_class_channel_get(void *obj);
|
||||
static int service_class_channel_set(void *obj, const void *str);
|
||||
static htsmsg_t *service_class_channel_enum(void *p)
|
||||
static const void *
|
||||
service_class_channel_get ( void *obj )
|
||||
{
|
||||
channel_t *ch;
|
||||
htsmsg_t *list = htsmsg_create_list();
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link)
|
||||
if (ch->ch_name)
|
||||
htsmsg_add_str(list, NULL, ch->ch_name);
|
||||
return list;
|
||||
service_t *svc = obj;
|
||||
channel_service_mapping_t *csm;
|
||||
static char buf[2048], *s;
|
||||
// TODO: make this dynamic length
|
||||
int first = 1;
|
||||
|
||||
*buf = 0;
|
||||
LIST_FOREACH(csm, &svc->s_channels, csm_chn_link) {
|
||||
if (!first)
|
||||
strcat(buf, ",");
|
||||
strcat(buf, idnode_uuid_as_str(&csm->csm_chn->ch_id));
|
||||
first = 0;
|
||||
}
|
||||
s = first ? NULL : buf;
|
||||
|
||||
return &s;
|
||||
}
|
||||
|
||||
static int
|
||||
service_class_channel_set
|
||||
( void *obj, const void *str )
|
||||
{
|
||||
int save = 0;
|
||||
service_t *svc = obj;
|
||||
char *tmp, *tok, *sptr;
|
||||
channel_t *ch;
|
||||
channel_service_mapping_t *csm, *n;
|
||||
|
||||
/* Mark all for deletion */
|
||||
LIST_FOREACH(csm, &svc->s_channels, csm_chn_link)
|
||||
csm->csm_mark = 1;
|
||||
|
||||
/* Make new links */
|
||||
tmp = strdup(str);
|
||||
tok = strtok_r(tmp, ",", &sptr);
|
||||
while (tok) {
|
||||
ch = channel_find(tok);
|
||||
if (ch) {
|
||||
save |= service_mapper_link(svc, ch);
|
||||
}
|
||||
tok = strtok_r(NULL, ",", &sptr);
|
||||
}
|
||||
|
||||
/* Delete unlinked */
|
||||
for (csm = LIST_FIRST(&svc->s_channels); csm != NULL; csm = n ) {
|
||||
n = LIST_NEXT(csm, csm_chn_link);
|
||||
if (csm->csm_mark) {
|
||||
save = 1;
|
||||
LIST_REMOVE(csm, csm_chn_link);
|
||||
LIST_REMOVE(csm, csm_svc_link);
|
||||
free(csm);
|
||||
}
|
||||
}
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
static htsmsg_t *
|
||||
service_class_channel_enum
|
||||
( void *obj )
|
||||
{
|
||||
htsmsg_t *p, *m = htsmsg_create_map();
|
||||
htsmsg_add_str(m, "type", "api");
|
||||
htsmsg_add_str(m, "uri", "channel/list");
|
||||
htsmsg_add_str(m, "event", "channel");
|
||||
p = htsmsg_create_map();
|
||||
htsmsg_add_u32(p, "enum", 1);
|
||||
htsmsg_add_msg(m, "params", p);
|
||||
return m;
|
||||
}
|
||||
|
||||
static const char *
|
||||
service_class_get_title ( idnode_t *self )
|
||||
{
|
||||
static char *ret = NULL;
|
||||
service_t *s = (service_t*)self;
|
||||
if (ret) {
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
}
|
||||
pthread_mutex_lock(&s->s_stream_mutex);
|
||||
if (s->s_nicename)
|
||||
ret = strdup(s->s_nicename);
|
||||
pthread_mutex_unlock(&s->s_stream_mutex);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
const idclass_t service_class = {
|
||||
.ic_class = "service",
|
||||
.ic_caption = "Service",
|
||||
.ic_save = service_class_save,
|
||||
.ic_get_title = service_class_get_title,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
.type = PT_BOOL,
|
||||
|
@ -74,16 +151,15 @@ const idclass_t service_class = {
|
|||
.name = "Enabled",
|
||||
.off = offsetof(service_t, s_enabled),
|
||||
},
|
||||
#if 0
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "channel",
|
||||
.name = "Channel",
|
||||
.get = service_class_channel_get,
|
||||
.set = service_class_channel_set,
|
||||
.list = service_class_channel_enum
|
||||
.list = service_class_channel_enum,
|
||||
.opts = PO_MULTI | PO_NOSAVE
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
@ -451,7 +527,7 @@ service_create0
|
|||
* Find a service based on the given identifier
|
||||
*/
|
||||
service_t *
|
||||
service_find_by_identifier(const char *identifier)
|
||||
service_find(const char *identifier)
|
||||
{
|
||||
return idnode_find(identifier, &service_class);
|
||||
}
|
||||
|
@ -650,15 +726,18 @@ service_is_hdtv(service_t *t)
|
|||
int
|
||||
service_is_radio(service_t *t)
|
||||
{
|
||||
int ret = 0;
|
||||
if (t->s_servicetype == ST_RADIO)
|
||||
return 1;
|
||||
else if (t->s_servicetype == ST_NONE) {
|
||||
elementary_stream_t *st;
|
||||
TAILQ_FOREACH(st, &t->s_components, es_link)
|
||||
if (SCT_ISAUDIO(st->es_type))
|
||||
return 1;
|
||||
if (SCT_ISVIDEO(st->es_type))
|
||||
return 0;
|
||||
else if (SCT_ISAUDIO(st->es_type))
|
||||
ret = 1;
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,8 @@ extern const idclass_t service_class;
|
|||
|
||||
extern struct service_queue service_all;
|
||||
|
||||
struct channel;
|
||||
|
||||
/**
|
||||
* Stream, one media component for a service.
|
||||
*/
|
||||
|
@ -232,6 +234,7 @@ typedef struct service {
|
|||
*/
|
||||
enum {
|
||||
ST_NONE,
|
||||
ST_OTHER,
|
||||
ST_SDTV,
|
||||
ST_HDTV,
|
||||
ST_RADIO
|
||||
|
@ -433,7 +436,8 @@ void service_unref(service_t *t);
|
|||
|
||||
void service_ref(service_t *t);
|
||||
|
||||
service_t *service_find_by_identifier(const char *identifier);
|
||||
service_t *service_find(const char *identifier);
|
||||
#define service_find_by_identifier service_find
|
||||
|
||||
service_instance_t *service_find_instance(struct service *s,
|
||||
struct channel *ch,
|
||||
|
@ -455,6 +459,7 @@ const char *service_servicetype_txt(service_t *t);
|
|||
int service_is_sdtv(service_t *t);
|
||||
int service_is_hdtv(service_t *t);
|
||||
int service_is_radio(service_t *t);
|
||||
int service_is_other(service_t *t);
|
||||
#define service_is_tv(s) (service_is_hdtv(s) || service_is_sdtv(s))
|
||||
|
||||
int service_is_encrypted ( service_t *t );
|
||||
|
|
|
@ -141,15 +141,17 @@ service_mapper_remove ( service_t *s )
|
|||
/*
|
||||
* Link service and channel
|
||||
*/
|
||||
void
|
||||
int
|
||||
service_mapper_link ( service_t *s, channel_t *c )
|
||||
{
|
||||
channel_service_mapping_t *csm;
|
||||
|
||||
/* Already linked */
|
||||
LIST_FOREACH(csm, &s->s_channels, csm_chn_link)
|
||||
if (csm->csm_chn == c)
|
||||
return;
|
||||
if (csm->csm_chn == c) {
|
||||
csm->csm_mark = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Link */
|
||||
csm = calloc(1, sizeof(channel_service_mapping_t));
|
||||
|
@ -157,6 +159,7 @@ service_mapper_link ( service_t *s, channel_t *c )
|
|||
csm->csm_svc = s;
|
||||
LIST_INSERT_HEAD(&s->s_channels, csm, csm_svc_link);
|
||||
LIST_INSERT_HEAD(&c->ch_services, csm, csm_chn_link);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -182,7 +185,7 @@ void
|
|||
service_mapper_process ( service_t *s )
|
||||
{
|
||||
int num;
|
||||
channel_t *chn;
|
||||
channel_t *chn = NULL;
|
||||
|
||||
/* Ignore */
|
||||
if (s->s_status == SERVICE_ZOMBIE)
|
||||
|
@ -194,10 +197,12 @@ service_mapper_process ( service_t *s )
|
|||
|
||||
/* Find existing channel */
|
||||
num = s->s_channel_number(s);
|
||||
#if 0
|
||||
if (service_mapper_conf.merge_same_name)
|
||||
chn = channel_find_by_name(s->s_channel_name(s), 1, num);
|
||||
else
|
||||
chn = channel_create(s->s_channel_name(s));
|
||||
chn = channel_find_by_name(s->s_channel_name(s));
|
||||
#endif
|
||||
if (!chn)
|
||||
chn = channel_create(NULL, NULL, s->s_channel_name(s));
|
||||
|
||||
/* Map */
|
||||
if (chn) {
|
||||
|
|
|
@ -42,7 +42,7 @@ void service_mapper_remove ( struct service *t );
|
|||
int service_mapper_qlen ( void );
|
||||
|
||||
// Link service to channel
|
||||
void service_mapper_link ( struct service *s, struct channel *c );
|
||||
int service_mapper_link ( struct service *s, struct channel *c );
|
||||
|
||||
// Unlink service from channel
|
||||
void service_mapper_unlink ( struct service *s, struct channel *c );
|
||||
|
|
|
@ -147,9 +147,6 @@ void gtimer_disarm(gtimer_t *gti);
|
|||
* List / Queue header declarations
|
||||
*/
|
||||
LIST_HEAD(th_subscription_list, th_subscription);
|
||||
RB_HEAD(channel_tree, channel);
|
||||
TAILQ_HEAD(channel_queue, channel);
|
||||
LIST_HEAD(channel_list, channel);
|
||||
LIST_HEAD(dvr_config_list, dvr_config);
|
||||
LIST_HEAD(dvr_entry_list, dvr_entry);
|
||||
TAILQ_HEAD(ref_update_queue, ref_update);
|
||||
|
@ -481,7 +478,6 @@ int rate_to_sri(int rate);
|
|||
|
||||
extern time_t dispatch_clock;
|
||||
extern struct service_list all_transports;
|
||||
extern struct channel_tree channel_name_tree;
|
||||
|
||||
extern void scopedunlock(pthread_mutex_t **mtxp);
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "channels.h"
|
||||
|
||||
#include "dvr/dvr.h"
|
||||
#include "service_mapper.h"
|
||||
#include "epggrab.h"
|
||||
#include "epg.h"
|
||||
#include "muxer.h"
|
||||
|
@ -318,221 +317,6 @@ extjs_tablemgr(http_connection_t *hc, const char *remain, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
extjs_channels_delete(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
channel_t *ch;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link)
|
||||
if(f->hmf_type == HMF_S64 &&
|
||||
(ch = channel_find_by_identifier(f->hmf_s64)) != NULL)
|
||||
channel_delete(ch);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
extjs_channels_update(htsmsg_t *in)
|
||||
{
|
||||
htsmsg_field_t *f;
|
||||
channel_t *ch;
|
||||
htsmsg_t *c;
|
||||
uint32_t id;
|
||||
const char *s;
|
||||
|
||||
TAILQ_FOREACH(f, &in->hm_fields, hmf_link) {
|
||||
if((c = htsmsg_get_map_by_field(f)) == NULL ||
|
||||
htsmsg_get_u32(c, "id", &id))
|
||||
continue;
|
||||
|
||||
if((ch = channel_find_by_identifier(id)) == NULL)
|
||||
continue;
|
||||
|
||||
if((s = htsmsg_get_str(c, "name")) != NULL)
|
||||
channel_rename(ch, s);
|
||||
|
||||
if((s = htsmsg_get_str(c, "ch_icon")) != NULL)
|
||||
channel_set_icon(ch, s);
|
||||
|
||||
if((s = htsmsg_get_str(c, "tags")) != NULL)
|
||||
channel_set_tags_from_list(ch, s);
|
||||
|
||||
if((s = htsmsg_get_str(c, "epg_pre_start")) != NULL)
|
||||
channel_set_epg_postpre_time(ch, 1, atoi(s));
|
||||
|
||||
if((s = htsmsg_get_str(c, "epg_post_end")) != NULL)
|
||||
channel_set_epg_postpre_time(ch, 0, atoi(s));
|
||||
|
||||
if((s = htsmsg_get_str(c, "number")) != NULL)
|
||||
channel_set_number(ch, atoi(s));
|
||||
|
||||
if((s = htsmsg_get_str(c, "epggrabsrc")) != NULL) {
|
||||
char *tmp = strdup(s);
|
||||
char *sptr = NULL, *sptr2 = NULL;
|
||||
char *modecid = strtok_r(tmp, ",", &sptr);
|
||||
char *modid, *ecid;
|
||||
epggrab_module_t *mod;
|
||||
epggrab_channel_t *ec;
|
||||
epggrab_channel_link_t *ecl;
|
||||
|
||||
/* Clear existing */
|
||||
LIST_FOREACH(mod, &epggrab_modules, link) {
|
||||
if (mod->type != EPGGRAB_OTA && mod->channels) {
|
||||
RB_FOREACH(ec, mod->channels, link) {
|
||||
LIST_FOREACH(ecl, &ec->channels, link) {
|
||||
if (ecl->channel == ch) {
|
||||
LIST_REMOVE(ecl, link);
|
||||
free(ecl);
|
||||
mod->ch_save(mod, ec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add new */
|
||||
while (modecid) {
|
||||
modid = strtok_r(modecid, "|", &sptr2);
|
||||
ecid = strtok_r(NULL, "|", &sptr2);
|
||||
modecid = strtok_r(NULL, ",", &sptr);
|
||||
|
||||
if (!(mod = epggrab_module_find_by_id(modid)))
|
||||
continue;
|
||||
if (!mod->channels)
|
||||
continue;
|
||||
if (!(ec = epggrab_channel_find(mod->channels, ecid, 0, NULL, mod)))
|
||||
continue;
|
||||
|
||||
epggrab_channel_link(ec, ch);
|
||||
}
|
||||
|
||||
/* Cleanup */
|
||||
free(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static htsmsg_t *
|
||||
build_record_channel ( channel_t *ch )
|
||||
{
|
||||
char buf[1024];
|
||||
channel_tag_mapping_t *ctm;
|
||||
htsmsg_t *c;
|
||||
char *epggrabsrc;
|
||||
epggrab_module_t *mod;
|
||||
epggrab_channel_t *ec;
|
||||
epggrab_channel_link_t *ecl;
|
||||
|
||||
c = htsmsg_create_map();
|
||||
htsmsg_add_str(c, "name", ch->ch_name);
|
||||
htsmsg_add_u32(c, "chid", ch->ch_id);
|
||||
|
||||
if(ch->ch_icon != NULL) {
|
||||
htsmsg_add_imageurl(c, "chicon", "imagecache/%d", ch->ch_icon);
|
||||
htsmsg_add_str(c, "ch_icon", ch->ch_icon);
|
||||
}
|
||||
|
||||
buf[0] = 0;
|
||||
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
|
||||
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
|
||||
"%s%d", strlen(buf) == 0 ? "" : ",",
|
||||
ctm->ctm_tag->ct_identifier);
|
||||
}
|
||||
htsmsg_add_str(c, "tags", buf);
|
||||
|
||||
htsmsg_add_s32(c, "epg_pre_start", ch->ch_dvr_extra_time_pre);
|
||||
htsmsg_add_s32(c, "epg_post_end", ch->ch_dvr_extra_time_post);
|
||||
htsmsg_add_s32(c, "number", ch->ch_number);
|
||||
|
||||
epggrabsrc = NULL;
|
||||
LIST_FOREACH(mod, &epggrab_modules, link) {
|
||||
if (mod->type != EPGGRAB_OTA && mod->channels) {
|
||||
RB_FOREACH(ec, mod->channels, link) {
|
||||
LIST_FOREACH(ecl, &ec->channels, link) {
|
||||
if (ecl->channel == ch) {
|
||||
char id[100];
|
||||
sprintf(id, "%s|%s", mod->id, ec->id);
|
||||
if (!epggrabsrc) {
|
||||
epggrabsrc = strdup(id);
|
||||
} else {
|
||||
epggrabsrc = realloc(epggrabsrc, strlen(epggrabsrc) + 2 + strlen(id));
|
||||
strcat(epggrabsrc, ",");
|
||||
strcat(epggrabsrc, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (epggrabsrc) htsmsg_add_str(c, "epggrabsrc", epggrabsrc);
|
||||
free(epggrabsrc);
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_channels(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *array;
|
||||
channel_t *ch;
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
const char *entries = http_arg_get(&hc->hc_req_args, "entries");
|
||||
|
||||
if(op == NULL)
|
||||
return 400;
|
||||
|
||||
htsmsg_t *in =
|
||||
entries != NULL ? htsmsg_json_deserialize(entries) : NULL;
|
||||
|
||||
htsmsg_t *out = htsmsg_create_map();
|
||||
|
||||
scopedgloballock();
|
||||
|
||||
if(!strcmp(op, "list")) {
|
||||
array = htsmsg_create_list();
|
||||
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
htsmsg_add_msg(array, NULL, build_record_channel(ch));
|
||||
}
|
||||
|
||||
htsmsg_add_msg(out, "entries", array);
|
||||
|
||||
} else if(!strcmp(op, "create")) {
|
||||
htsmsg_destroy(out);
|
||||
out = build_record_channel(channel_create(NULL));
|
||||
|
||||
} else if(!strcmp(op, "delete") && in != NULL) {
|
||||
extjs_channels_delete(in);
|
||||
|
||||
} else if(!strcmp(op, "update") && in != NULL) {
|
||||
extjs_channels_update(in);
|
||||
|
||||
} else {
|
||||
htsmsg_destroy(in);
|
||||
htsmsg_destroy(out);
|
||||
return 400;
|
||||
}
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
htsmsg_destroy(in);
|
||||
htsmsg_destroy(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* EPG Content Groups
|
||||
*/
|
||||
|
@ -924,7 +708,7 @@ extjs_epg(http_connection_t *hc, const char *remain, void *opaque)
|
|||
m = htsmsg_create_map();
|
||||
|
||||
htsmsg_add_str(m, "channel", ch->ch_name);
|
||||
htsmsg_add_u32(m, "channelid", ch->ch_id);
|
||||
htsmsg_add_u32(m, "channelid", channel_get_id(ch));
|
||||
if(ch->ch_icon != NULL)
|
||||
htsmsg_add_imageurl(m, "chicon", "imagecache/%d", ch->ch_icon);
|
||||
|
||||
|
@ -1186,7 +970,7 @@ extjs_dvr(http_connection_t *hc, const char *remain, void *opaque)
|
|||
const char *channel = http_arg_get(&hc->hc_req_args, "channelid");
|
||||
const char *pri = http_arg_get(&hc->hc_req_args, "pri");
|
||||
|
||||
channel_t *ch = channel ? channel_find_by_identifier(atoi(channel)) : NULL;
|
||||
channel_t *ch = channel ? channel_find_by_id(atoi(channel)) : NULL;
|
||||
|
||||
if(ch == NULL || title == NULL ||
|
||||
datestr == NULL || strlen(datestr) != 10 ||
|
||||
|
@ -1653,49 +1437,6 @@ extjs_servicedetails(http_connection_t *hc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
extjs_mergechannel(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
const char *target = http_arg_get(&hc->hc_req_args, "targetID");
|
||||
htsmsg_t *out;
|
||||
channel_t *src, *dst;
|
||||
|
||||
if(remain == NULL || target == NULL)
|
||||
return 400;
|
||||
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
src = channel_find_by_identifier(atoi(remain));
|
||||
dst = channel_find_by_identifier(atoi(target));
|
||||
|
||||
if(src == NULL || dst == NULL) {
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
return 404;
|
||||
}
|
||||
|
||||
out = htsmsg_create_map();
|
||||
|
||||
if(src != dst) {
|
||||
channel_merge(dst, src);
|
||||
htsmsg_add_u32(out, "success", 1);
|
||||
} else {
|
||||
|
||||
htsmsg_add_u32(out, "success", 0);
|
||||
htsmsg_add_str(out, "msg", "Target same as source");
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -1972,67 +1713,6 @@ extjs_timeshift(http_connection_t *hc, const char *remain, void *opaque)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
extjs_service_mapping
|
||||
(http_connection_t *hc, const char *remain, void *opaque)
|
||||
{
|
||||
htsbuf_queue_t *hq = &hc->hc_reply;
|
||||
htsmsg_t *out;
|
||||
service_mapper_conf_t conf = { 0 };
|
||||
const char *op = http_arg_get(&hc->hc_req_args, "op");
|
||||
|
||||
if (!op)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
/* Status */
|
||||
if (!strcmp(op, "status")) {
|
||||
int num;
|
||||
pthread_mutex_lock(&global_lock);
|
||||
num = service_mapper_qlen();
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
out = htsmsg_create_map();
|
||||
htsmsg_add_u32(out, "remaining", num);
|
||||
|
||||
/* Start */
|
||||
} else if (!strcmp(op, "start")) {
|
||||
|
||||
/* Get config */
|
||||
if (http_arg_get(&hc->hc_req_args, "check_availability") != NULL)
|
||||
conf.check_availability = 1;
|
||||
if (http_arg_get(&hc->hc_req_args, "encrypted") != NULL)
|
||||
conf.encrypted = 1;
|
||||
if (http_arg_get(&hc->hc_req_args, "merge_same_name") != NULL)
|
||||
conf.merge_same_name = 1;
|
||||
if (http_arg_get(&hc->hc_req_args, "provider_tags") != NULL)
|
||||
conf.provider_tags = 1;
|
||||
|
||||
/* Start */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
service_mapper_start(&conf);
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
out = htsmsg_create_map();
|
||||
|
||||
/* Stop */
|
||||
} else if (!strcmp(op, "stop")) {
|
||||
pthread_mutex_lock(&global_lock);
|
||||
service_mapper_stop();
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
out = htsmsg_create_map();
|
||||
|
||||
/* Invalid */
|
||||
} else {
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
}
|
||||
|
||||
|
||||
htsmsg_json_serialize(out, hq, 0);
|
||||
htsmsg_destroy(out);
|
||||
http_output_content(hc, "text/x-json; charset=UTF-8");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* WEB user interface
|
||||
*/
|
||||
|
@ -2043,7 +1723,6 @@ extjs_start(void)
|
|||
http_path_add("/extjs.html", NULL, extjs_root, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/capabilities", NULL, extjs_capabilities, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/tablemgr", NULL, extjs_tablemgr, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/channels", NULL, extjs_channels, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/epggrab", NULL, extjs_epggrab, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/confignames", NULL, extjs_confignames, ACCESS_WEB_INTERFACE);
|
||||
|
@ -2059,15 +1738,12 @@ extjs_start(void)
|
|||
http_path_add("/ecglist", NULL, extjs_ecglist, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/config", NULL, extjs_config, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/languages", NULL, extjs_languages, ACCESS_WEB_INTERFACE);
|
||||
http_path_add("/mergechannel", NULL, extjs_mergechannel, ACCESS_ADMIN);
|
||||
http_path_add("/servicedetails", NULL, extjs_servicedetails, ACCESS_ADMIN);
|
||||
#if ENABLE_TIMESHIFT
|
||||
http_path_add("/timeshift", NULL, extjs_timeshift, ACCESS_ADMIN);
|
||||
#endif
|
||||
http_path_add("/tvhlog", NULL, extjs_tvhlog, ACCESS_ADMIN);
|
||||
|
||||
http_path_add("/api/service_mapping", NULL, extjs_service_mapping, ACCESS_ADMIN);
|
||||
|
||||
#if ENABLE_V4L
|
||||
extjs_start_v4l();
|
||||
#endif
|
||||
|
|
|
@ -55,7 +55,7 @@ dumpchannels(htsbuf_queue_t *hq)
|
|||
channel_t *ch;
|
||||
outputtitle(hq, 0, "Channels");
|
||||
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
CHANNEL_FOREACH(ch) {
|
||||
|
||||
htsbuf_qprintf(hq, "%s (%d)\n", ch->ch_name, ch->ch_id);
|
||||
htsbuf_qprintf(hq,
|
||||
|
|
|
@ -25,6 +25,7 @@ tvheadend.channelrec = new Ext.data.Record.create(
|
|||
[ 'name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start',
|
||||
'epg_post_end', 'number' ]);
|
||||
|
||||
/*
|
||||
tvheadend.channels = new Ext.data.JsonStore({
|
||||
autoLoad : true,
|
||||
root : 'entries',
|
||||
|
@ -43,6 +44,7 @@ tvheadend.channels = new Ext.data.JsonStore({
|
|||
tvheadend.comet.on('channels', function(m) {
|
||||
if (m.reload != null) tvheadend.channels.reload();
|
||||
});
|
||||
*/
|
||||
|
||||
/*
|
||||
* Service mapping
|
||||
|
@ -466,3 +468,24 @@ tvheadend.chconf = function() {
|
|||
|
||||
return grid;
|
||||
}
|
||||
|
||||
tvheadend.channel_tab = function(panel)
|
||||
{
|
||||
var mapButton = new Ext.Toolbar.Button({
|
||||
tooltip : 'Map services to channels',
|
||||
iconCls : '',
|
||||
text : 'Map Services',
|
||||
handler : tvheadend.mapServices,
|
||||
disabled : false,
|
||||
});
|
||||
|
||||
tvheadend.idnode_grid(panel, {
|
||||
url : 'api/channel',
|
||||
comet : 'channel',
|
||||
titleS : 'Channel',
|
||||
titleP : 'Channels',
|
||||
add : false,
|
||||
del : false,
|
||||
tbar : [ mapButton ]
|
||||
});
|
||||
}
|
||||
|
|
|
@ -111,7 +111,10 @@ tvheadend.idnode_editor_field = function(f, create)
|
|||
switch(f.type) {
|
||||
case 'str':
|
||||
if (f.enum) {
|
||||
return new Ext.form.ComboBox({
|
||||
var cons = Ext.form.ComboBox;
|
||||
if (f.multi)
|
||||
cons = Ext.ux.form.LovCombo;
|
||||
return new cons({
|
||||
fieldLabel : f.caption,
|
||||
name : f.id,
|
||||
value : f.value,
|
||||
|
@ -124,7 +127,17 @@ tvheadend.idnode_editor_field = function(f, create)
|
|||
typeAhead : true,
|
||||
forceSelection : true,
|
||||
triggerAction : 'all',
|
||||
emptyText :'Select ' + f.caption +' ...'
|
||||
emptyText :'Select ' + f.caption +' ...',
|
||||
listeners : {
|
||||
keyup: function() {
|
||||
this.store.filter('val', this.getRawValue(), true, false);
|
||||
},
|
||||
beforequery: function(queryEvent) {
|
||||
queryEvent.combo.onLoad();
|
||||
// prevent doQuery from firing and clearing out my filter.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return new Ext.form.TextField({
|
||||
|
@ -615,14 +628,24 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
}
|
||||
});
|
||||
buttons.push(editBtn);
|
||||
buttons.push('->');
|
||||
|
||||
/* Extra buttons */
|
||||
if (conf.tbar) {
|
||||
buttons.push('-')
|
||||
for (i = 0; i < conf.tbar.length; i++)
|
||||
buttons.push(conf.tbar[i])
|
||||
}
|
||||
|
||||
/* Help */
|
||||
if (conf.help) {
|
||||
buttons.push('->');
|
||||
buttons.push({
|
||||
text : 'Help',
|
||||
handler : conf.help
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Grid Panel */
|
||||
var auto = new Ext.form.Checkbox({
|
||||
checked : true,
|
||||
|
|
|
@ -290,11 +290,11 @@ function accessUpdate(o) {
|
|||
title : 'Channel / EPG',
|
||||
iconCls : 'television',
|
||||
items : [
|
||||
new tvheadend.chconf,
|
||||
new tvheadend.cteditor,
|
||||
new tvheadend.epggrab
|
||||
]
|
||||
});
|
||||
tvheadend.channel_tab(tvheadend.conf_chepg);
|
||||
tabs1.push(tvheadend.conf_chepg);
|
||||
|
||||
/* DVR / Timeshift */
|
||||
|
|
|
@ -290,7 +290,7 @@ http_channel_playlist(http_connection_t *hc, channel_t *channel)
|
|||
hq = &hc->hc_reply;
|
||||
host = http_arg_get(&hc->hc_args, "Host");
|
||||
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel->ch_id);
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(channel));
|
||||
|
||||
htsbuf_qprintf(hq, "#EXTM3U\n");
|
||||
htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", channel->ch_name);
|
||||
|
@ -319,7 +319,7 @@ http_tag_playlist(http_connection_t *hc, channel_tag_t *tag)
|
|||
|
||||
htsbuf_qprintf(hq, "#EXTM3U\n");
|
||||
LIST_FOREACH(ctm, &tag->ct_ctms, ctm_tag_link) {
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", ctm->ctm_channel->ch_id);
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ctm->ctm_channel));
|
||||
htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", ctm->ctm_channel->ch_name);
|
||||
htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf,
|
||||
access_ticket_create(buf));
|
||||
|
@ -377,8 +377,8 @@ http_channel_list_playlist(http_connection_t *hc)
|
|||
host = http_arg_get(&hc->hc_args, "Host");
|
||||
|
||||
htsbuf_qprintf(hq, "#EXTM3U\n");
|
||||
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", ch->ch_id);
|
||||
CHANNEL_FOREACH(ch) {
|
||||
snprintf(buf, sizeof(buf), "/stream/channelid/%d", channel_get_id(ch));
|
||||
|
||||
htsbuf_qprintf(hq, "#EXTINF:-1,%s\n", ch->ch_name);
|
||||
htsbuf_qprintf(hq, "http://%s%s?ticket=%s\n", host, buf,
|
||||
|
@ -511,9 +511,9 @@ page_http_playlist(http_connection_t *hc, const char *remain, void *opaque)
|
|||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
if(nc == 2 && !strcmp(components[0], "channelid"))
|
||||
ch = channel_find_by_identifier(atoi(components[1]));
|
||||
ch = channel_find_by_id(atoi(components[1]));
|
||||
else if(nc == 2 && !strcmp(components[0], "channel"))
|
||||
ch = channel_find_by_name(components[1], 0, 0);
|
||||
ch = channel_find_by_name(components[1]);
|
||||
else if(nc == 2 && !strcmp(components[0], "dvrid"))
|
||||
de = dvr_entry_find_by_id(atoi(components[1]));
|
||||
else if(nc == 2 && !strcmp(components[0], "tagid"))
|
||||
|
@ -748,9 +748,9 @@ http_stream(http_connection_t *hc, const char *remain, void *opaque)
|
|||
scopedgloballock();
|
||||
|
||||
if(!strcmp(components[0], "channelid")) {
|
||||
ch = channel_find_by_identifier(atoi(components[1]));
|
||||
ch = channel_find_by_id(atoi(components[1]));
|
||||
} else if(!strcmp(components[0], "channel")) {
|
||||
ch = channel_find_by_name(components[1], 0, 0);
|
||||
ch = channel_find_by_name(components[1]);
|
||||
} else if(!strcmp(components[0], "service")) {
|
||||
service = service_find_by_identifier(components[1]);
|
||||
#if 0//ENABLE_LINUXDVB
|
||||
|
|
Loading…
Add table
Reference in a new issue