From: Andreas Ă–man Date: Sat, 6 Sep 2008 19:08:10 +0000 (+0000) Subject: Add support for channel tags (except for being there they don't add X-Git-Tag: 2.12~897 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ee4901acf3f5e3001de3158676ea19114b07742b;p=thirdparty%2Ftvheadend.git Add support for channel tags (except for being there they don't add any functionality a.t.m) --- diff --git a/channels.c b/channels.c index 6461fa737..d12921619 100644 --- a/channels.c +++ b/channels.c @@ -39,11 +39,13 @@ #include "pvr.h" #include "autorec.h" #include "xmltv.h" +#include "dtable.h" struct channel_list channels_not_xmltv_mapped; struct channel_tree channel_name_tree; static struct channel_tree channel_identifier_tree; +static struct channel_tag_queue channel_tags; static int dictcmp(const char *a, const char *b) @@ -258,17 +260,6 @@ channels_load(void) } -/** - * - */ -void -channels_init(void) -{ - channels_load(); -} - - - /** * Write out a config file for a channel */ @@ -436,3 +427,198 @@ channel_set_xmltv_source(channel_t *ch, xmltv_channel_t *xc) ch->ch_xc = xc; channel_save(ch); } + + + +/** + * + */ +static void +channel_tag_mapping_destroy(channel_tag_mapping_t *ctm) +{ + LIST_REMOVE(ctm, ctm_channel_link); + LIST_REMOVE(ctm, ctm_tag_link); + free(ctm); +} + + +/** + * + */ +static channel_tag_t * +channel_tag_find(const char *id, int create) +{ + channel_tag_t *ct; + char buf[20]; + static int tally; + + if(id != NULL) { + TAILQ_FOREACH(ct, &channel_tags, ct_link) + if(!strcmp(ct->ct_identifier, id)) + return ct; + } + + if(create == 0) + return NULL; + + ct = calloc(1, sizeof(channel_tag_t)); + if(id == NULL) { + tally++; + snprintf(buf, sizeof(buf), "%d", tally); + id = buf; + } else { + tally = atoi(id); + } + + ct->ct_identifier = strdup(id); + ct->ct_name = strdup("New tag"); + ct->ct_comment = strdup(""); + TAILQ_INSERT_TAIL(&channel_tags, ct, ct_link); + return ct; +} + + +/** + * + */ +static void +channel_tag_destroy(channel_tag_t *ct) +{ + channel_tag_mapping_t *ctm; + + while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) + channel_tag_mapping_destroy(ctm); + + free(ct->ct_identifier); + free(ct->ct_name); + free(ct->ct_comment); + TAILQ_REMOVE(&channel_tags, ct, ct_link); + free(ct); +} + + +/** + * + */ +static htsmsg_t * +channel_tag_record_build(channel_tag_t *ct) +{ + htsmsg_t *e = htsmsg_create(); + htsmsg_add_u32(e, "enabled", !!ct->ct_enabled); + htsmsg_add_u32(e, "internal", !!ct->ct_internal); + + htsmsg_add_str(e, "name", ct->ct_name); + htsmsg_add_str(e, "comment", ct->ct_comment); + htsmsg_add_str(e, "id", ct->ct_identifier); + return e; +} + + +/** + * + */ +static htsmsg_t * +channel_tag_record_get_all(void *opaque) +{ + htsmsg_t *r = htsmsg_create_array(); + channel_tag_t *ct; + + TAILQ_FOREACH(ct, &channel_tags, ct_link) + htsmsg_add_msg(r, NULL, channel_tag_record_build(ct)); + + return r; +} + + +/** + * + */ +static htsmsg_t * +channel_tag_record_get(void *opaque, const char *id) +{ + channel_tag_t *ct; + + if((ct = channel_tag_find(id, 0)) == NULL) + return NULL; + return channel_tag_record_build(ct); +} + + +/** + * + */ +static htsmsg_t * +channel_tag_record_create(void *opaque) +{ + return channel_tag_record_build(channel_tag_find(NULL, 1)); +} + + +/** + * + */ +static htsmsg_t * +channel_tag_record_update(void *opaque, const char *id, htsmsg_t *values, + int maycreate) +{ + channel_tag_t *ct; + uint32_t u32; + + if((ct = channel_tag_find(id, maycreate)) == NULL) + return NULL; + + tvh_str_update(&ct->ct_name, htsmsg_get_str(values, "name")); + tvh_str_update(&ct->ct_comment, htsmsg_get_str(values, "comment")); + + if(!htsmsg_get_u32(values, "enabled", &u32)) + ct->ct_enabled = u32; + + if(!htsmsg_get_u32(values, "internal", &u32)) + ct->ct_internal = u32; + + return channel_tag_record_build(ct); +} + + +/** + * + */ +static int +channel_tag_record_delete(void *opaque, const char *id) +{ + channel_tag_t *ct; + + if((ct = channel_tag_find(id, 0)) == NULL) + return -1; + channel_tag_destroy(ct); + return 0; +} + + +/** + * + */ +static const dtable_class_t channel_tags_dtc = { + .dtc_record_get = channel_tag_record_get, + .dtc_record_get_all = channel_tag_record_get_all, + .dtc_record_create = channel_tag_record_create, + .dtc_record_update = channel_tag_record_update, + .dtc_record_delete = channel_tag_record_delete, +}; + + +/** + * + */ +void +channels_init(void) +{ + dtable_t *dt; + + TAILQ_INIT(&channel_tags); + + dt = dtable_create(&channel_tags_dtc, "channeltags", NULL); + dtable_load(dt); + + channels_load(); +} diff --git a/channels.h b/channels.h index e06a8693e..49ad4750d 100644 --- a/channels.h +++ b/channels.h @@ -19,6 +19,8 @@ #ifndef CHANNELS_H #define CHANNELS_H +LIST_HEAD(channel_tag_mapping_list, channel_tag_mapping); +TAILQ_HEAD(channel_tag_queue, channel_tag); /* * Channel definition @@ -57,8 +59,39 @@ typedef struct channel { struct xmltv_channel *ch_xc; LIST_ENTRY(channel) ch_xc_link; + struct channel_tag_mapping_list ch_ctms; + } channel_t; + +/** + * Channel tag + */ +typedef struct channel_tag { + TAILQ_ENTRY(channel_tag) ct_link; + int ct_enabled; + int ct_internal; + char *ct_name; + char *ct_comment; + char *ct_identifier; + struct channel_tag_mapping_list ct_ctms; +} channel_tag_t; + + +/** + * Channel tag mapping + */ +typedef struct channel_tag_mapping { + LIST_ENTRY(channel_tag_mapping) ctm_channel_link; + channel_t *ctm_channel; + + LIST_ENTRY(channel_tag_mapping) ctm_tag_link; + channel_tag_t *ctm_tag; + +} channel_tag_mapping_t; + + + void channels_init(void); channel_t *channel_find_by_name(const char *name, int create); diff --git a/webui/extjs.c b/webui/extjs.c index 4b63ee149..643a30d63 100644 --- a/webui/extjs.c +++ b/webui/extjs.c @@ -104,6 +104,7 @@ extjs_root(http_connection_t *hc, const char *remain, void *opaque) /** * Load all components */ + extjs_load(hq, "static/app/cteditor.js"); extjs_load(hq, "static/app/acleditor.js"); extjs_load(hq, "static/app/cwceditor.js"); extjs_load(hq, "static/app/dvb.js"); diff --git a/webui/static/app/cteditor.js b/webui/static/app/cteditor.js new file mode 100644 index 000000000..f89f14b5c --- /dev/null +++ b/webui/static/app/cteditor.js @@ -0,0 +1,160 @@ + +tvheadend.cteditor = function() { + var fm = Ext.form; + + var enabledColumn = new Ext.grid.CheckColumn({ + header: "Enabled", + dataIndex: 'enabled', + width: 60 + }); + + var internalColumn = new Ext.grid.CheckColumn({ + header: "Internal", + dataIndex: 'internal', + width: 100 + }); + + + var cm = new Ext.grid.ColumnModel([ + enabledColumn, + { + id:'name', + header: "Name", + dataIndex: 'name', + editor: new fm.TextField({ + allowBlank: false + }) + }, + internalColumn, + { + id:'comment', + header: "Comment", + dataIndex: 'comment', + width: 400, + editor: new fm.TextField({ + + }) + } + ]); + + + cm.defaultSortable = true; + + var ChannelTagRecord = Ext.data.Record.create([ + {name: 'enabled'}, + {name: 'name'}, + {name: 'internal'}, + {name: 'comment'} + ]); + + var store = new Ext.data.JsonStore({ + root: 'entries', + fields: ChannelTagRecord, + url: "tablemgr", + autoLoad: true, + id: 'id', + storeid: 'id', + baseParams: {table: "channeltags", op: "get"} + }); + + + function addRecord() { + Ext.Ajax.request({ + url: "tablemgr", params: {op:"create", table:"channeltags"}, + failure:function(response,options){ + Ext.MessageBox.alert('Server Error','Unable to generate new record'); + }, + success:function(response,options){ + var responseData = Ext.util.JSON.decode(response.responseText); + + var p = new ChannelTagRecord(responseData, responseData.id); + grid.stopEditing(); + store.insert(0, p); + grid.startEditing(0, 0); + } + }) + }; + + function delSelected() { + var selectedKeys = grid.selModel.selections.keys; + if(selectedKeys.length > 0) + { + Ext.MessageBox.confirm('Message', + 'Do you really want to delete selection?', + deleteRecord); + } else { + Ext.MessageBox.alert('Message', + 'Please select at least one item to delete'); + } + }; + + + function deleteRecord(btn) { + if(btn=='yes') { + var selectedKeys = grid.selModel.selections.keys; + + Ext.Ajax.request({ + url: "tablemgr", params: {op:"delete", table:"channeltags", + entries:Ext.encode(selectedKeys)}, + failure:function(response,options){ + Ext.MessageBox.alert('Server Error','Unable to delete'); + }, + success:function(response,options){ + store.reload(); + } + }) + } + } + + + + function saveChanges() { + var mr = store.getModifiedRecords(); + var out = new Array(); + for (var x = 0; x < mr.length; x++) { + v = mr[x].getChanges(); + out[x] = v; + out[x].id = mr[x].id; + } + + Ext.Ajax.request({url: "tablemgr", + params: {op:"update", table:"channeltags", + entries:Ext.encode(out)}, + success:function(response,options){ + store.commitChanges(); + }, + failure:function(response,options){ + Ext.MessageBox.alert('Message',response.statusText); + } + }); + } + + var grid = new Ext.grid.EditorGridPanel({ + title: 'Channel Tags', + plugins:[enabledColumn,internalColumn], + store: store, + clicksToEdit: 2, + cm: cm, + selModel: new Ext.grid.RowSelectionModel({singleSelect:false}), + tbar: [{ + tooltip: 'Create a new channel tag entry on the server. ' + + 'The new entry is initially disabled so it must be enabled before it start taking effect.', + iconCls:'add', + text: 'Add entry', + handler: addRecord + }, '-', { + tooltip: 'Delete one or more selected rows', + iconCls:'remove', + text: 'Delete selected', + handler: delSelected + }, '-', { + tooltip: 'Save any changes made (Changed cells have red borders).', + iconCls:'save', + text: "Save changes", + handler: saveChanges + } + ] + }); + + return grid; +} diff --git a/webui/static/app/tvheadend.js b/webui/static/app/tvheadend.js index f0bb680a4..f5aaa734d 100644 --- a/webui/static/app/tvheadend.js +++ b/webui/static/app/tvheadend.js @@ -87,6 +87,7 @@ tvheadend.app = function() { autoScroll:true, title: 'Configuration', items: [new tvheadend.chconf, + new tvheadend.cteditor, new tvheadend.dvb, new tvheadend.acleditor, new tvheadend.cwceditor]