SRCS += \
src/api.c \
src/api/api_idnode.c \
+ src/api/api_channel.c \
src/api/api_service.c \
src/api/api_mpegts.c \
api_idnode_init();
api_mpegts_init();
api_service_init();
+ api_channel_init();
}
void api_idnode_init ( void );
void api_mpegts_init ( void );
void api_service_init ( void );
+void api_channel_init ( void );
/*
* IDnode
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__ */
--- /dev/null
+/*
+ * 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__ */
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;
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))) {
/* 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 */
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")))
#define __TVH_API_SERVICE_H__
#include "tvheadend.h"
+#include "service.h"
#include "service_mapper.h"
#include "access.h"
#include "api.h"
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 },
};
#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);
#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;
-
- 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 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;
+
+ /* Add all */
+ LIST_FOREACH(csm, &ch->ch_services, csm_svc_link) {
+ if (first)
+ htsbuf_queue_init(&hq, 0);
+ else
+ htsbuf_append(&hq, ",", 1);
+ uuid = idnode_uuid_as_str(&csm->csm_svc->s_id);
+ htsbuf_append(&hq, uuid, strlen(uuid));
+ first = 0;
}
-}
+ /* Build string */
+ if (!first) {
+ s = htsbuf_to_string(&hq);
+ htsbuf_queue_flush(&hq);
+ }
-/**
- *
- */
-static int
-channelcmp(const channel_t *a, const channel_t *b)
-{
- return dictcmp(a->ch_name, b->ch_name);
+ return &s;
}
-
-/**
- *
- */
static int
-chidcmp(const channel_t *a, const channel_t *b)
+channel_class_services_set ( void *obj, const void *p )
{
- return a->ch_id - b->ch_id;
+ return channel_set_services_by_list(obj, p);
}
-/**
- *
- */
-static void
-channel_set_name(channel_t *ch, const char *name)
+static htsmsg_t *
+channel_class_services_enum ( void *obj )
{
- 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;
+ 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;
+}
+
+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
- *cp++ = '_';
+ htsbuf_append(&hq, ",", 1);
+ htsbuf_append(&hq, ctm->ctm_tag->ct_name, strlen(ctm->ctm_tag->ct_name));
+ first = 0;
}
- *cp = 0;
-
- free((void *)n2);
-
- RB_INSERT_SORTED(&channel_name_tree, ch, ch_name_link, channelcmp);
- //assert(x == NULL);
- /* Notify clients */
- channel_list_changed();
+ /* Build string */
+ if (!first) {
+ s = htsbuf_to_string(&hq);
+ htsbuf_queue_flush(&hq);
+ }
+ return &s;
}
-
-/**
- *
- */
-static channel_t *
-channel_create2(const char *name, int number)
+static int
+channel_class_tags_set ( void *obj, const void *p )
{
- 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;
- }
-
- if (!name || !*name) {
- snprintf(buf, sizeof(buf), "Channel %d", id);
- name = buf;
- }
-
- 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 channel_set_tags_by_list(obj, p);
}
-/**
- *
- */
-channel_t *
-channel_create ( const char *name )
+static htsmsg_t *
+channel_class_tags_enum ( void *obj )
{
- channel_t *ch = channel_create2(name, 0);
- channel_save(ch);
- return ch;
+ 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;
}
-/**
- *
- */
-channel_t *
-channel_find_by_name(const char *name, int create, int channel_number)
+static void
+channel_class_icon_notify ( void *obj )
{
- lock_assert(&global_lock);
- channel_t *ch, skel;
+ channel_t *ch = obj;
+ if (ch->ch_icon)
+ imagecache_get_id(ch->ch_icon);
+}
- 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 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,
+ },
+ {}
}
- return channel_create2(name, channel_number);
-}
+};
+/* **************************************************************************
+ * 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_identifier(int id)
+channel_find_by_name ( const char *name )
{
- channel_t skel, *ch;
-
- lock_assert(&global_lock);
-
- skel.ch_id = id;
- ch = RB_FIND(&channel_identifier_tree, &skel, ch_identifier_link, chidcmp);
+ channel_t *ch;
+ CHANNEL_FOREACH(ch)
+ if (!strcmp(ch->ch_name ?: "", name))
+ break;
return ch;
}
-/**
- *
- */
-static void
-channel_load_one(htsmsg_t *c, int id)
+channel_t *
+channel_find_by_id ( uint32_t i )
{
- 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];
+ channel_t skel;
+ memcpy(skel.ch_id.in_uuid, &i, sizeof(i));
- 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
+ return RB_FIND(&channels, &skel, ch_link, ch_id_cmp);
}
+/* **************************************************************************
+ * Property updating
+ * *************************************************************************/
-/**
- *
- */
-static void
-channels_load(void)
+int
+channel_set_services_by_list ( channel_t *ch, const char *svcs )
{
- htsmsg_t *l, *c;
- htsmsg_field_t *f;
-
- 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));
+ int save = 0;
+ char *tmp, *ret, *tok;
+ service_t *svc;
+ channel_service_mapping_t *csm, *n;
+
+ /* Mark all for deletion */
+ LIST_FOREACH(csm, &ch->ch_services, csm_chn_link)
+ csm->csm_mark = 1;
+
+ /* 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);
+
+ /* 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;
}
- htsmsg_destroy(l);
}
-}
-
-
-/**
- * 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);
+ return save;
}
-/**
- * Rename a channel and all tied services
- */
int
-channel_rename(channel_t *ch, const char *newname)
+channel_set_tags_by_list ( channel_t *ch, const char *tags )
{
- dvr_entry_t *de;
-
- lock_assert(&global_lock);
+ return 0;
+}
- if (!newname || !*newname) return 0;
+/* **************************************************************************
+ * Creation/Deletion
+ * *************************************************************************/
- if(channel_find_by_name(newname, 0, 0))
- return -1;
+channel_t *
+channel_create0
+ ( channel_t *ch, const idclass_t *idc, const char *uuid, htsmsg_t *conf,
+ const char *name )
+{
+ lock_assert(&global_lock);
- tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" renamed to \"%s\"",
- ch->ch_name, newname);
+ idnode_insert(&ch->ch_id, uuid, idc);
+ if (RB_INSERT_SORTED(&channels, ch, ch_link, ch_id_cmp)) {
+ tvherror("channel", "id collision!");
+ abort();
+ }
- RB_REMOVE(&channel_name_tree, ch, ch_name_link);
- channel_set_name(ch, newname);
- epggrab_channel_mod(ch);
+ if (conf)
+ idnode_load(&ch->ch_id, conf);
- LIST_FOREACH(de, &ch->ch_dvrs, de_channel_link) {
- dvr_entry_save(de);
- dvr_entry_notify(de);
+ /* Override the name */
+ if (name) {
+ free(ch->ch_name);
+ ch->ch_name = strdup(name);
}
- channel_save(ch);
- htsp_channel_update(ch);
- return 0;
+ return ch;
}
-/**
- * Delete channel
- */
void
-channel_delete(channel_t *ch)
+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;
-
- lock_assert(&global_lock);
-
- tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" merged into \"%s\"",
- src->ch_name, dst->ch_name);
-
- while((t = LIST_FIRST(&src->ch_services)) != NULL)
- service_mapper_link(t->csm_svc, dst);
-
- channel_delete(src);
+ 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);
}
/**
*
*/
void
-channel_set_icon(channel_t *ch, const char *icon)
+channel_init ( void )
{
- lock_assert(&global_lock);
+ htsmsg_t *c, *e;
+ htsmsg_field_t *f;
+ RB_INIT(&channels);
+
+ /* Tags */
+ channel_tag_init();
- 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);
-}
-
-
-
/**
*
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();
}
#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;
struct dvr_autorec_entry_list ct_autorecs;
} channel_tag_t;
-
/**
* 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;
-} channel_service_mapping_t;
-
-void channels_init(void);
-
-channel_t *channel_create(const char *name);
-channel_t *channel_find_by_name(const char *name, int create, int number);
-
-channel_t *channel_find_by_identifier(int id);
+ int csm_mark;
+} channel_service_mapping_t;
-void channel_set_teletext_rundown(channel_t *ch, int v);
+extern const idclass_t channel_class;
-void channel_settings_write(channel_t *ch);
+void channel_init(void);
-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);
-
-void channel_set_epg_postpre_time(channel_t *ch, int pre, int mins);
+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_number(channel_t *ch, int number);
+channel_t *channel_find_by_id(uint32_t id);
-void channel_set_icon(channel_t *ch, const char *icon);
+#define channel_find channel_find_by_uuid
-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);
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 */
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;
}
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);
}
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);
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;
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);
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);
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;
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)
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;
}
/* 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 */
/* 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);
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);
}
/*
* Use for v1 databases
*/
+#if DEPRECATED
static void _epgdb_v1_process ( htsmsg_t *c, epggrab_stats_t *stats )
{
channel_t *ch;
/* Set episode */
save |= epg_broadcast_set_episode(ebc, ee, NULL);
}
+#endif
/*
* Process v2 data
case 2:
_epgdb_v2_process(m, &stats);
break;
- default: /* v0/1 */
- _epgdb_v1_process(m, &stats);
+ default:
break;
}
{
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;
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");
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);
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)) {
channel_rename(ecl->channel, name);
save = 1;
}
+#endif
return save;
}
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;
channel_set_icon(ecl->channel, icon);
save = 1;
}
+#endif
return save;
}
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) {
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;
/* Save */
if (ec->mod->ch_save) ec->mod->ch_save(ec->mod, ec);
+#endif
}
/* ID comparison */
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)
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);
/* 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);
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);
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);
}
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);
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)))
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) */
/* 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);
/* 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)))
/* 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;
/* 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)))
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))
#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 {
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;
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);
}
* Info
* *************************************************************************/
+uint32_t
+idnode_get_short_uuid (const idnode_t *in)
+{
+ uint32_t u32;
+ memcpy(&u32, in->in_uuid, sizeof(u32));
+ return u32;
+}
+
/**
*
*/
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);
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++;
}
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();
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);
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)
#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
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 )
{
+ 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;
- 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;
+ 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,
.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
{}
}
};
* 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);
}
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;
}
/**
extern struct service_queue service_all;
+struct channel;
+
/**
* Stream, one media component for a service.
*/
*/
enum {
ST_NONE,
+ ST_OTHER,
ST_SDTV,
ST_HDTV,
ST_RADIO
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,
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 );
/*
* 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));
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
service_mapper_process ( service_t *s )
{
int num;
- channel_t *chn;
+ channel_t *chn = NULL;
/* Ignore */
if (s->s_status == SERVICE_ZOMBIE)
/* 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) {
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 );
* 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);
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);
#include "channels.h"
#include "dvr/dvr.h"
-#include "service_mapper.h"
#include "epggrab.h"
#include "epg.h"
#include "muxer.h"
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
*/
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);
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 ||
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;
-}
-
/**
*
*/
}
#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
*/
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);
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
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,
[ 'name', 'chid', 'epggrabsrc', 'tags', 'ch_icon', 'epg_pre_start',
'epg_post_end', 'number' ]);
+/*
tvheadend.channels = new Ext.data.JsonStore({
autoLoad : true,
root : 'entries',
tvheadend.comet.on('channels', function(m) {
if (m.reload != null) tvheadend.channels.reload();
});
+*/
/*
* Service mapping
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 ]
+ });
+}
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,
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({
}
});
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,
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 */
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);
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));
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,
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"))
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