#include "api.h"
#include "notify.h"
-static int
-api_mapper_start
- ( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
-{
- service_mapper_conf_t conf = { 0 };
- htsmsg_t *uuids;
-#define get_u32(x)\
- conf.x = htsmsg_get_bool_or_default(args, #x, 0)
-
- /* Get config */
- uuids = htsmsg_get_list(args, "uuids");
- get_u32(check_availability);
- get_u32(encrypted);
- get_u32(merge_same_name);
- get_u32(provider_tags);
- get_u32(network_tags);
-
- pthread_mutex_lock(&global_lock);
- service_mapper_start(&conf, uuids);
- pthread_mutex_unlock(&global_lock);
-
- return 0;
-}
-
static int
api_mapper_stop
( access_t *perm, void *opaque, const char *op, htsmsg_t *args, htsmsg_t **resp )
{
extern const idclass_t service_class;
static api_hook_t ah[] = {
- { "service/mapper/start", ACCESS_ADMIN, api_mapper_start, NULL },
+ { "service/mapper/load", ACCESS_ADMIN, api_idnode_load_simple, &service_mapper_conf },
+ { "service/mapper/save", ACCESS_ADMIN, api_idnode_save_simple, &service_mapper_conf },
{ "service/mapper/stop", ACCESS_ADMIN, api_mapper_stop, NULL },
{ "service/mapper/status", ACCESS_ADMIN, api_mapper_status, NULL },
- { "service/list", ACCESS_ADMIN, api_idnode_load_by_class,
- (void*)&service_class },
+ { "service/list", ACCESS_ADMIN, api_idnode_load_by_class, (void*)&service_class },
{ "service/streams", ACCESS_ADMIN, api_service_streams, NULL },
{ NULL },
};
/* List */
if (p->islist) {
assert(p->get); /* requirement */
- htsmsg_add_msg(m, name, (htsmsg_t*)val);
+ if (val)
+ htsmsg_add_msg(m, name, (htsmsg_t*)val);
/* Single */
} else {
static service_mapper_status_t service_mapper_stat;
static pthread_cond_t service_mapper_cond;
static TAILQ_HEAD(, service_mapper_item) service_mapper_queue;
+service_mapper_t service_mapper_conf;
static void *service_mapper_thread ( void *p );
-/**
- * Initialise
- */
-pthread_t service_mapper_tid;
-
-void
-service_mapper_init ( void )
-{
- TAILQ_INIT(&service_mapper_queue);
- pthread_cond_init(&service_mapper_cond, NULL);
- tvhthread_create(&service_mapper_tid, NULL, service_mapper_thread, NULL, "svcmap");
-}
-
-void
-service_mapper_done ( void )
-{
- pthread_cond_signal(&service_mapper_cond);
- pthread_join(service_mapper_tid, NULL);
-}
-
/*
* Get status
*/
/*
* Start a new mapping
*/
-void
+static void
service_mapper_start ( const service_mapper_conf_t *conf, htsmsg_t *uuids )
{
int e, tr, qd = 0;
service_mapper_link(s, chn, chn);
/* Type tags */
- if (service_is_hdtv(s)) {
- channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
- channel_tag_map(channel_tag_find_by_name("HDTV", 1), chn, chn);
- } else if (service_is_sdtv(s)) {
- channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
- channel_tag_map(channel_tag_find_by_name("SDTV", 1), chn, chn);
- } else if (service_is_radio(s)) {
- channel_tag_map(channel_tag_find_by_name("Radio", 1), chn, chn);
+ if (conf->type_tags) {
+ if (service_is_hdtv(s)) {
+ channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
+ channel_tag_map(channel_tag_find_by_name("HDTV", 1), chn, chn);
+ } else if (service_is_sdtv(s)) {
+ channel_tag_map(channel_tag_find_by_name("TV channels", 1), chn, chn);
+ channel_tag_map(channel_tag_find_by_name("SDTV", 1), chn, chn);
+ } else if (service_is_radio(s)) {
+ channel_tag_map(channel_tag_find_by_name("Radio", 1), chn, chn);
+ }
}
/* Custom tags */
service_mapper_stat.fail = 0;
service_mapper_stat.active = NULL;
}
+
+/*
+ * Save settings
+ */
+static void service_mapper_conf_class_save ( idnode_t *self )
+{
+ htsmsg_t *m;
+
+ m = htsmsg_create_map();
+ idnode_save(&service_mapper_conf.idnode, m);
+ hts_settings_save(m, "service_mapper/config");
+ htsmsg_destroy(m);
+
+ if (!htsmsg_is_empty(service_mapper_conf.services))
+ service_mapper_start(&service_mapper_conf.d, service_mapper_conf.services);
+ htsmsg_destroy(service_mapper_conf.services);
+ service_mapper_conf.services = NULL;
+}
+
+/*
+ * Class
+ */
+
+static const void *
+service_mapper_services_get ( void *obj )
+{
+ return NULL;
+}
+
+static char *
+service_mapper_services_rend ( void *obj, const char *lang )
+{
+ return strdup("");
+}
+
+static int
+service_mapper_services_set ( void *obj, const void *p )
+{
+ service_mapper_t *sm = obj;
+ htsmsg_destroy(sm->services);
+ sm->services = htsmsg_copy((htsmsg_t *)p);
+ return 1;
+}
+
+static htsmsg_t *
+service_mapper_services_enum ( void *obj, const char *lang )
+{
+ 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_bool(e, "enum", 1);
+ htsmsg_add_msg(m, "params", e);
+ return m;
+}
+
+static const idclass_t service_mapper_conf_class = {
+ .ic_snode = &service_mapper_conf.idnode,
+ .ic_class = "service_mapper",
+ .ic_caption = N_("Service mapper"),
+ .ic_event = "service_mapper",
+ .ic_perm_def = ACCESS_ADMIN,
+ .ic_save = service_mapper_conf_class_save,
+ .ic_properties = (const property_t[]){
+ {
+ .type = PT_STR,
+ .islist = 1,
+ .id = "services",
+ .name = N_("Services"),
+ .get = service_mapper_services_get,
+ .set = service_mapper_services_set,
+ .list = service_mapper_services_enum,
+ .rend = service_mapper_services_rend
+ },
+ {
+ .type = PT_BOOL,
+ .id = "check_availability",
+ .name = N_("Check availability"),
+ .off = offsetof(service_mapper_t, d.check_availability),
+ .opts = PO_ADVANCED
+ },
+ {
+ .type = PT_BOOL,
+ .id = "encrypted",
+ .name = N_("Map encrypted services"),
+ .off = offsetof(service_mapper_t, d.encrypted),
+ },
+ {
+ .type = PT_BOOL,
+ .id = "merge_same_name",
+ .name = N_("Merge same name"),
+ .off = offsetof(service_mapper_t, d.merge_same_name),
+ },
+ {
+ .type = PT_BOOL,
+ .id = "type_tags",
+ .name = N_("Create type based tags"),
+ .desc = N_("Create SDTV/HDTV/Radio tags"),
+ .off = offsetof(service_mapper_t, d.type_tags),
+ .opts = PO_ADVANCED
+ },
+ {
+ .type = PT_BOOL,
+ .id = "provider_tags",
+ .name = N_("Create provider name tags"),
+ .off = offsetof(service_mapper_t, d.provider_tags),
+ .opts = PO_ADVANCED
+ },
+ {
+ .type = PT_BOOL,
+ .id = "network_tags",
+ .name = N_("Create network name tags"),
+ .off = offsetof(service_mapper_t, d.network_tags),
+ .opts = PO_ADVANCED
+ },
+ {}
+ }
+};
+
+/*
+ *
+ */
+
+pthread_t service_mapper_tid;
+
+void service_mapper_init ( void )
+{
+ htsmsg_t *m;
+
+ TAILQ_INIT(&service_mapper_queue);
+ pthread_cond_init(&service_mapper_cond, NULL);
+ tvhthread_create(&service_mapper_tid, NULL, service_mapper_thread, NULL, "svcmap");
+
+ /* Defaults */
+ memset(&service_mapper_conf, 0, sizeof(service_mapper_conf));
+ service_mapper_conf.idnode.in_class = &service_mapper_conf_class;
+ service_mapper_conf.d.type_tags = 1;
+ service_mapper_conf.d.encrypted = 1;
+
+ /* Load settings */
+ if ((m = hts_settings_load("service_mapper/config"))) {
+ idnode_load(&service_mapper_conf.idnode, m);
+ htsmsg_destroy(m);
+ }
+}
+
+
+void service_mapper_done ( void )
+{
+ pthread_cond_signal(&service_mapper_cond);
+ pthread_join(service_mapper_tid, NULL);
+ htsmsg_destroy(service_mapper_conf.services);
+ service_mapper_conf.services = NULL;
+}
typedef struct service_mapper_conf
{
- uint8_t check_availability; ///< Check service is receivable
- uint8_t encrypted; ///< Include encrypted services
- uint8_t merge_same_name; ///< Merge entries with the same name
- uint8_t provider_tags; ///< Create tags based on provider name
- uint8_t network_tags; ///< Create tags based on network name (useful for multi adapter equipments)
+ int check_availability; ///< Check service is receivable
+ int encrypted; ///< Include encrypted services
+ int merge_same_name; ///< Merge entries with the same name
+ int type_tags; ///< Create tags based on the service type (SDTV/HDTV/Radio)
+ int provider_tags; ///< Create tags based on provider name
+ int network_tags; ///< Create tags based on network name (useful for multi adapter equipments)
} service_mapper_conf_t;
+typedef struct service_mapper {
+ idnode_t idnode;
+ service_mapper_conf_t d;
+ htsmsg_t *services;
+} service_mapper_t;
+
typedef struct service_mapper_status
{
int total;
service_t *active;
} service_mapper_status_t;
+extern service_mapper_t service_mapper_conf;
+
void service_mapper_init ( void );
void service_mapper_done ( void );
-// Start new mapping
-void service_mapper_start
- ( const service_mapper_conf_t *conf, htsmsg_t *uuids );
-
// Stop pending services (remove from Q)
void service_mapper_stop ( void );
text: conf.saveText || _('Save'),
iconCls: conf.saveIconCls || 'save',
handler: function() {
- if (panel.getForm().isDirty()) {
+ if (panel.getForm().isDirty() || conf.alwaysDirty) {
var node = panel.getForm().getFieldValues();
node.uuid = conf.uuids ? conf.uuids : item.uuid;
tvheadend.Ajax({
/*
*
*/
-tvheadend.idnode_editor_win = function(_uilevel, item, conf)
+tvheadend.idnode_editor_win = function(_uilevel, conf)
{
- var p = tvheadend.idnode_editor(_uilevel, item, conf);
- var width = p.fixedWidth;
- var w = new Ext.ux.Window({
- title: conf.winTitle,
- iconCls: conf.iconCls || 'edit',
- layout: 'fit',
- autoWidth: width ? false : true,
- autoHeight: true,
- autoScroll: true,
- plain: true,
- items: p
- });
- conf.win = w;
- if (width)
- w.setWidth(width);
- w.show();
- return w;
+ function display(item, conf, title) {
+ var p = tvheadend.idnode_editor(_uilevel, item, conf);
+ var width = p.fixedWidth;
+ var w = new Ext.ux.Window({
+ title: title,
+ iconCls: conf.iconCls || 'edit',
+ layout: 'fit',
+ autoWidth: width ? false : true,
+ autoHeight: true,
+ autoScroll: true,
+ plain: true,
+ items: p
+ });
+ conf.win = w;
+ if (width)
+ w.setWidth(width);
+ w.show();
+ return w;
+ }
+
+ if (!conf.cancel)
+ conf.cancel = function(conf) {
+ conf.win.close();
+ conf.win = null;
+ }
+
+ var params = conf.params || {};
+
+ var uuids = null;
+ if (conf.selections) {
+ var r = conf.selections;
+ if (!r || r.length <= 0)
+ return;
+
+ uuids = [];
+ for (var i = 0; i < r.length; i++)
+ uuids.push(r[i].id);
+
+ params['uuid'] = r[0].id;
+ }
+
+ params['meta'] = 1;
+
+ conf.win = null;
+
+ tvheadend.Ajax({
+ url: conf.loadURL ? conf.loadURL : 'api/idnode/load',
+ params: params,
+ success: function(d) {
+ d = json_decode(d);
+ d = d[0];
+ if (conf.modifyData)
+ conf.modifyData(conf, d);
+ var title = conf.title;
+ if (!title) {
+ if (uuids && uuids.length > 1)
+ title = String.format(_('Edit {0} ({1} entries)'),
+ conf.titleS, uuids.length);
+ else
+ title = String.format(_('Edit {0}'), conf.titleS);
+ }
+ if (uuids && uuids.length > 1)
+ conf.uuids = uuids;
+ display(d, conf, title);
+ }
+ });
}
/*
w.show();
}
} else {
- var r = select.getSelections();
- if (r && r.length > 0) {
- var uuids = [];
- for (var i = 0; i < r.length; i++)
- uuids.push(r[i].id);
- var params = {};
- if (conf.edit && conf.edit.params)
- params = conf.edit.params;
- params['uuid'] = r[0].id;
- params['meta'] = 1;
- tvheadend.Ajax({
- url: 'api/idnode/load',
- params: params,
- success: function(d) {
- d = json_decode(d);
- var c = {
- win: null,
- cancel: function(conf) {
- conf.win.close();
- conf.win = null;
- }
- };
- if (uuids.length > 1) {
- c.winTitle = String.format(_('Edit {0} ({1} entries)'),
- conf.titleS, uuids.length);
- c.uuids = uuids;
- } else {
- c.winTitle = String.format(_('Edit {0}'), conf.titleS);
- }
- tvheadend.idnode_editor_win(uilevel, d[0], c);
- }
- });
- }
+ tvheadend.idnode_editor_win(uilevel, {
+ selections: select.getSelections(),
+ params: conf.edit && conf.edit.params ? conf.edit.params : null
+ });
}
}
});
* Status dialog
*/
-tvheadend.service_mapper_status_panel = null;
-
tvheadend.service_mapper_status = function(panel, index)
{
/* Fields */
/* Panel */
var mpanel = new Ext.FormPanel({
+ id: 'service_mapper',
method: 'get',
title: _('Service Mapper'),
iconCls: 'serviceMapper',
var panel = null;
var win = null;
- /* Form fields */
- var availCheck = new Ext.form.Checkbox({
- name: 'check_availability',
- fieldLabel: _('Check availability'),
- checked: false
- });
- var ftaCheck = new Ext.form.Checkbox({
- name: 'encrypted',
- fieldLabel: _('Include encrypted services'),
- checked: false
- // TODO: make dependent on CSA config
- });
- var mergeCheck = new Ext.form.Checkbox({
- name: 'merge_same_name',
- fieldLabel: _('Merge same name'),
- checked: false
- });
- var provtagCheck = new Ext.form.Checkbox({
- name: 'provider_tags',
- fieldLabel: _('Create provider tags'),
- checked: false
- });
- var nettagCheck = new Ext.form.Checkbox({
- name: 'network_tags',
- fieldLabel: _('Create network tags'),
- checked: false
- });
-
- // TODO: provider list
- items = [availCheck, ftaCheck, mergeCheck, provtagCheck, nettagCheck];
-
- /* Form */
- var undoBtn = new Ext.Button({
- text: _('Cancel'),
- handler: function() {
- win.close();
- }
- });
-
- var saveBtn = new Ext.Button({
- text: _('Map'),
- tooltip: _('Begin mapping'),
- handler: function() {
- p = null;
- if (select) {
- var r = select.getSelections();
- if (r.length > 0) {
- var uuids = [];
- for (var i = 0; i < r.length; i++)
- uuids.push(r[i].id);
- p = {uuids: Ext.encode(uuids)};
- }
+ function modify_data(conf, d) {
+ for (var i = 0; i < d.params.length; i++)
+ if (d.params[i].id === 'services')
+ break;
+ if (select && i < d.params.length) {
+ var r = select.getSelections();
+ if (r.length > 0) {
+ var uuids = [];
+ for (var j = 0; j < r.length; j++)
+ uuids.push(r[j].id);
+ d.params[i].value = uuids;
}
-
-
- panel.getForm().submit({
- url: 'api/service/mapper/start',
- waitMessage: _('Mapping services...'),
- params: p
- });
-
- win.hide();
-
- /* Dialog */
- win = new Ext.Window({
- title: _('Service Mapper Status'),
- iconCls: 'clone',
- layout: 'fit',
- autoWidth: true,
- autoHeight: true,
- plain: false,
- items: tvheadend.service_mapper_status_panel
- // TODO: buttons
- });
- win.show();
+ }
+ }
+
+ tvheadend.idnode_editor_win(tvheadend.uilevel, {
+ loadURL: 'api/service/mapper/load',
+ saveURL: 'api/service/mapper/save',
+ saveText: _('Map services'),
+ alwaysDirty: true,
+ noApply: true,
+ modifyData: modify_data,
+ postsave: function() {
+ tvheadend.select_tab('service_mapper');
+ },
+ help: function() {
+ new tvheadend.help(_('Map services'), 'config_mapper.html');
}
});
-
- panel = new Ext.FormPanel({
- method: 'post',
- frame: true,
- border: true,
- bodyStyle: 'padding: 5px',
- labelAlign: 'left',
- labelWidth: 200,
- autoWidth: true,
- autoHeight: true,
- defaultType: 'textfield',
- buttonAlign: 'left',
- items: items,
- buttons: [undoBtn, saveBtn]
- });
-
- /* Create window */
- win = new Ext.Window({
- title: _('Map services'),
- iconCls: 'clone',
- layout: 'fit',
- autoWidth: true,
- autoHeight: true,
- plain: true,
- items: panel
- });
-
- win.show();
}
return true;
}
+/*
+ * Select specific tab
+ */
+tvheadend.select_tab = function(id)
+{
+ var i = Ext.getCmp(id);
+ var c = i ? i.ownerCt : null;
+ while (c) {
+ if ('activeTab' in c)
+ c.setActiveTab(i);
+ i = c;
+ c = c.ownerCt;
+ }
+}
+
/**
* Displays a help popup window
*/
tvheadend.wizard = page;
- if (page in tabMapping) {
- var i = Ext.getCmp(tabMapping[page]);
- var c = i ? i.ownerCt : null;
- while (c) {
- if ('activeTab' in c)
- c.setActiveTab(i);
- i = c;
- c = c.ownerCt;
- }
- }
+ if (page in tabMapping)
+ tvheadend.select_tab(tabMapping[page]);
tvheadend.Ajax({
url: 'api/wizard/' + page + '/load',