Add support for mapping tags to channels.

This commit is contained in:
Andreas Öman 2008-09-07 08:54:16 +00:00
parent d8fca6b5f0
commit 704f80a017
5 changed files with 251 additions and 66 deletions

View file

@ -45,7 +45,11 @@ 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;
struct channel_tag_queue channel_tags;
static void channel_tag_map(channel_t *ch, channel_tag_t *ct, int check);
static channel_tag_t *channel_tag_find(const char *id, int create);
static void channel_tag_mapping_destroy(channel_tag_mapping_t *ctm);
static int
dictcmp(const char *a, const char *b)
@ -212,6 +216,9 @@ channel_load_one(htsmsg_t *c, int id)
channel_t *ch;
const char *s;
const char *name = htsmsg_get_str(c, "name");
htsmsg_t *tags;
htsmsg_field_t *f;
channel_tag_t *ct;
if(name == NULL)
return;
@ -238,6 +245,15 @@ channel_load_one(htsmsg_t *c, int id)
LIST_INSERT_HEAD(&ch->ch_xc->xc_channels, ch, ch_xc_link);
else
LIST_INSERT_HEAD(&channels_not_xmltv_mapped, ch, ch_xc_link);
if((tags = htsmsg_get_array(c, "tags")) != NULL) {
HTSMSG_FOREACH(f, tags) {
if(f->hmf_type == HMF_STR &&
(ct = channel_tag_find(f->hmf_str, 0)) != NULL) {
channel_tag_map(ch, ct, 1);
}
}
}
}
@ -267,6 +283,8 @@ static void
channel_save(channel_t *ch)
{
htsmsg_t *m = htsmsg_create();
htsmsg_t *tags;
channel_tag_mapping_t *ctm;
lock_assert(&global_lock);
@ -282,6 +300,12 @@ channel_save(channel_t *ch)
val2str(ch->ch_commercial_detection,
commercial_detect_tab) ?: "?");
tags = htsmsg_create_array();
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
htsmsg_add_str(tags, NULL, ctm->ctm_tag->ct_identifier);
htsmsg_add_msg(m, "tags", tags);
hts_settings_save(m, "channels/%d", ch->ch_id);
htsmsg_destroy(m);
}
@ -323,9 +347,13 @@ channel_delete(channel_t *ch)
{
th_transport_t *t;
th_subscription_t *s;
channel_tag_mapping_t *ctm;
lock_assert(&global_lock);
while((ctm = LIST_FIRST(&ch->ch_ctms)) != NULL)
channel_tag_mapping_destroy(ctm);
tvhlog(LOG_NOTICE, "channels", "Channel \"%s\" deleted",
ch->ch_name);
@ -428,6 +456,100 @@ channel_set_xmltv_source(channel_t *ch, xmltv_channel_t *xc)
channel_save(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);
}
}
if(change)
channel_save(ch);
}
/**
*
*/
static void
channel_tag_map(channel_t *ch, channel_tag_t *ct, int check)
{
channel_tag_mapping_t *ctm;
if(check) {
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
if(ctm->ctm_tag == ct)
return;
LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
if(ctm->ctm_channel == ch)
return;
}
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link)
assert(ctm->ctm_tag != ct);
LIST_FOREACH(ctm, &ct->ct_ctms, ctm_tag_link)
assert(ctm->ctm_channel != ch);
ctm = malloc(sizeof(channel_tag_mapping_t));
ctm->ctm_channel = ch;
LIST_INSERT_HEAD(&ch->ch_ctms, ctm, ctm_channel_link);
ctm->ctm_tag = ct;
LIST_INSERT_HEAD(&ct->ct_ctms, ctm, ctm_tag_link);
ctm->ctm_mark = 0;
}
/**
@ -467,7 +589,7 @@ channel_tag_find(const char *id, int create)
snprintf(buf, sizeof(buf), "%d", tally);
id = buf;
} else {
tally = atoi(id);
tally = MAX(atoi(id), tally);
}
ct->ct_identifier = strdup(id);
@ -485,9 +607,13 @@ static void
channel_tag_destroy(channel_tag_t *ct)
{
channel_tag_mapping_t *ctm;
channel_t *ch;
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL)
while((ctm = LIST_FIRST(&ct->ct_ctms)) != NULL) {
ch = ctm->ctm_channel;
channel_tag_mapping_destroy(ctm);
channel_save(ch);
}
free(ct->ct_identifier);
free(ct->ct_name);

View file

@ -22,6 +22,9 @@
LIST_HEAD(channel_tag_mapping_list, channel_tag_mapping);
TAILQ_HEAD(channel_tag_queue, channel_tag);
extern struct channel_tag_queue channel_tags;
/*
* Channel definition
*/
@ -88,6 +91,8 @@ typedef struct channel_tag_mapping {
LIST_ENTRY(channel_tag_mapping) ctm_tag_link;
channel_tag_t *ctm_tag;
int ctm_mark;
} channel_tag_mapping_t;
@ -113,6 +118,8 @@ void channel_set_icon(channel_t *ch, const char *icon);
struct xmltv_channel;
void channel_set_xmltv_source(channel_t *ch, struct xmltv_channel *xc);
void channel_set_tags_from_list(channel_t *ch, const char *maplist);
extern struct channel_list channels_not_xmltv_mapped;
#endif /* CHANNELS_H */

View file

@ -566,6 +566,8 @@ extjs_channel(http_connection_t *hc, const char *remain, void *opaque)
th_transport_t *t;
int reloadchlist = 0;
htsmsg_t *out, *array, *r;
channel_tag_mapping_t *ctm;
char buf[200];
pthread_mutex_lock(&global_lock);
@ -584,6 +586,14 @@ extjs_channel(http_connection_t *hc, const char *remain, void *opaque)
if(ch->ch_xc != NULL)
htsmsg_add_str(r, "xmltvchannel", ch->ch_xc->xc_displayname);
buf[0] = 0;
LIST_FOREACH(ctm, &ch->ch_ctms, ctm_channel_link) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
"%s%s", strlen(buf) == 0 ? "" : ",",
ctm->ctm_tag->ct_identifier);
}
htsmsg_add_str(r, "tags", buf);
out = json_single_record(r, "channels");
} else if(!strcmp(op, "gettransports")) {
@ -620,6 +630,9 @@ extjs_channel(http_connection_t *hc, const char *remain, void *opaque)
} else if(!strcmp(op, "save")) {
if((s = http_arg_get(&hc->hc_req_args, "tags")) != NULL)
channel_set_tags_from_list(ch, s);
s = http_arg_get(&hc->hc_req_args, "xmltvchannel");
channel_set_xmltv_source(ch, s?xmltv_channel_find_by_displayname(s):NULL);
@ -699,6 +712,52 @@ extjs_xmltv(http_connection_t *hc, const char *remain, void *opaque)
}
/**
*
*/
static int
extjs_channeltags(http_connection_t *hc, const char *remain, void *opaque)
{
htsbuf_queue_t *hq = &hc->hc_reply;
const char *op = http_arg_get(&hc->hc_req_args, "op");
htsmsg_t *out, *array, *e;
channel_tag_t *ct;
pthread_mutex_lock(&global_lock);
if(!strcmp(op, "listTags")) {
out = htsmsg_create();
array = htsmsg_create_array();
TAILQ_FOREACH(ct, &channel_tags, ct_link) {
if(!ct->ct_enabled)
continue;
e = htsmsg_create();
htsmsg_add_str(e, "identifier", ct->ct_identifier);
htsmsg_add_str(e, "name", ct->ct_name);
htsmsg_add_msg(array, NULL, e);
}
htsmsg_add_msg(out, "entries", array);
} else {
pthread_mutex_unlock(&global_lock);
return HTTP_STATUS_BAD_REQUEST;
}
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;
}
/**
* WEB user interface
*/
@ -713,4 +772,5 @@ extjs_start(void)
http_path_add("/chlist", NULL, extjs_chlist, ACCESS_WEB_INTERFACE);
http_path_add("/channel", NULL, extjs_channel, ACCESS_WEB_INTERFACE);
http_path_add("/xmltv", NULL, extjs_xmltv, ACCESS_WEB_INTERFACE);
http_path_add("/channeltags", NULL, extjs_channeltags, ACCESS_WEB_INTERFACE);
}

View file

@ -1,3 +1,17 @@
/**
* Channel tags
*/
tvheadend.channelTags = new Ext.data.JsonStore({
autoLoad:true,
root:'entries',
fields: [{name: 'identifier'}, {name: 'name'}],
url:'channeltags',
baseParams: {op: 'listTags'}
});
/**
* Channel details
*/
@ -89,7 +103,7 @@ tvheadend.channeldetails = function(chid, chname) {
var confreader = new Ext.data.JsonReader({
root: 'channels',
}, ['name', 'comdetect','xmltvchannel']);
}, ['name','xmltvchannel','tags']);
var xmltvChannels = new Ext.data.JsonStore({
@ -99,6 +113,7 @@ tvheadend.channeldetails = function(chid, chname) {
baseParams: {op: 'listChannels'}
});
var confpanel = new Ext.FormPanel({
border:false,
disabled:true,
@ -108,7 +123,6 @@ tvheadend.channeldetails = function(chid, chname) {
labelWidth: 150,
waitMsgTarget: true,
reader: confreader,
// defaultType: 'textfield',
items: [{
layout:'column',
@ -118,68 +132,40 @@ tvheadend.channeldetails = function(chid, chname) {
columnWidth:.5,
layout: 'form',
defaultType: 'textfield',
items: [
{
fieldLabel: 'Channel name',
name: 'name',
},new Ext.form.ComboBox({
loadingText: 'Loading...',
fieldLabel: 'XML-TV Source',
name: 'xmltvchannel',
width: 300,
displayField:'xcTitle',
valueField:'xcTitle',
store: xmltvChannels,
forceSelection: true,
mode: 'remote',
editable: false,
triggerAction: 'all',
emptyText: 'None'
})
]
},{
border:false,
columnWidth:.5,
layout: 'form',
items: [{
fieldLabel: 'Channel name',
name: 'name',
},
new Ext.form.ComboBox({
loadingText: 'Loading...',
fieldLabel: 'XML-TV Source',
name: 'xmltvchannel',
width: 300,
displayField:'xcTitle',
valueField:'xcTitle',
store: xmltvChannels,
forceSelection: true,
mode: 'remote',
editable: false,
triggerAction: 'all',
emptyText: 'None'
})
/*
,
new Ext.form.ComboBox({
allowBlank: false,
fieldLabel: 'Commercial detection',
name: 'comdetect',
displayField:'mode',
valueField:'imode',
mode: 'local',
triggerAction: 'all',
selectOnFocus:true,
editable:false,
store: new Ext.data.SimpleStore({
fields: ['imode', 'mode'],
data: [
['none', 'None'],
['tt192', 'Teletext page 192']]
})
})
*/
]
}
/*
,{
columnWidth:.5,
layout: 'form',
items: [{
xtype: 'checkboxgroup',
fieldLabel: 'Tags',
itemCls: 'x-check-group-alt',
columns: 1,
vertical: true,
items: [{
boxLabel: 'Favourites', name: 'favourite'},{
boxLabel: 'Sports', name: 'sports'},{
boxLabel: 'News', name: 'news'},{
boxLabel: 'Movies', name: 'movies'},{
boxLabel: 'Children', name: 'children'}
]
}
]
} */
]
fieldLabel: 'Tags',
xtype:"multiselect",
name:"tags",
valueField:"identifier",
displayField:"name",
width:250,
height:200,
store:tvheadend.channelTags,
}]
}]
}]
});

View file

@ -14,6 +14,12 @@ tvheadend.comet_poller = function() {
var m = response.messages[x];
switch(m.notificationClass) {
case 'channeltags':
if(m.reload != null) {
tvheadend.channelTags.reload();
}
break;
case 'logmessage':
var sl = Ext.get('systemlog');