#include "tvhead.h"
#include "http.h"
#include "ajaxui.h"
#include "channels.h"
/**
* Render a channel group widget
*/
static void
ajax_chgroup_build(htsbuf_queue_t *tq, channel_group_t *tcg)
{
htsbuf_qprintf(tq, "", tcg->tcg_tag);
ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL);
htsbuf_qprintf(tq, "");
htsbuf_qprintf(tq,
"
",
tcg->tcg_tag, tcg->tcg_name);
if(tcg != defgroup) {
htsbuf_qprintf(tq,
"
",
tcg->tcg_tag, tcg->tcg_name);
}
htsbuf_qprintf(tq, "
");
ajax_box_end(tq, AJAX_BOX_BORDER);
htsbuf_qprintf(tq, " ");
}
/**
* Update order of channel groups
*/
static int
ajax_chgroup_updateorder(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
channel_group_t *tcg;
htsbuf_queue_t *tq = &hr->hr_q;
http_arg_t *ra;
TAILQ_FOREACH(ra, &hc->hc_req_args, link) {
if(strcmp(ra->key, "channelgrouplist[]") ||
(tcg = channel_group_by_tag(atoi(ra->val))) == NULL)
continue;
TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link);
TAILQ_INSERT_TAIL(&all_channel_groups, tcg, tcg_global_link);
}
channel_group_settings_write();
htsbuf_qprintf(tq, "Updated on server ");
ajax_js(tq, "Effect.Fade('updatedok')");
http_output_html(hc, hr);
return 0;
}
/**
* Add a new channel group
*/
static int
ajax_chgroup_add(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
channel_group_t *tcg;
htsbuf_queue_t *tq = &hr->hr_q;
const char *name;
if((name = http_arg_get(&hc->hc_req_args, "name")) != NULL) {
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link)
if(!strcmp(name, tcg->tcg_name))
break;
if(tcg == NULL) {
tcg = channel_group_find(name, 1);
ajax_chgroup_build(tq, tcg);
/* We must recreate the Sortable object */
ajax_js(tq, "Sortable.destroy(\"channelgrouplist\")");
ajax_js(tq, "Sortable.create(\"channelgrouplist\", "
"{onUpdate:function(){updatelistonserver("
"'channelgrouplist', "
"'/ajax/chgroup_updateorder', "
"'list-info'"
")}});");
}
}
http_output_html(hc, hr);
return 0;
}
/**
* Delete a channel group
*/
static int
ajax_chgroup_del(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
channel_group_t *tcg;
htsbuf_queue_t *tq = &hr->hr_q;
const char *id;
if((id = http_arg_get(&hc->hc_req_args, "id")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if((tcg = channel_group_by_tag(atoi(id))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
htsbuf_qprintf(tq, "$('chgrp_%d').remove();", tcg->tcg_tag);
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
channel_group_destroy(tcg);
return 0;
}
/**
* Channel group & channel configuration
*/
int
ajax_config_channels_tab(http_connection_t *hc, http_reply_t *hr)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_group_t *tcg;
htsbuf_qprintf(tq, "");
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, "channelgroups",
NULL, "Channel groups");
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq, "
");
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
if(tcg->tcg_hidden)
continue;
ajax_chgroup_build(tq, tcg);
}
htsbuf_qprintf(tq, " ");
ajax_js(tq, "Sortable.create(\"channelgrouplist\", "
"{onUpdate:function(){updatelistonserver("
"'channelgrouplist', "
"'/ajax/chgroup_updateorder', "
"'list-info'"
")}});");
/**
* Add new group
*/
htsbuf_qprintf(tq, "
");
ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL);
htsbuf_qprintf(tq,
"
");
ajax_box_end(tq, AJAX_BOX_BORDER);
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq,
"
");
htsbuf_qprintf(tq,
"
");
http_output_html(hc, hr);
return 0;
}
/**
* Display all channels within the group
*/
static int
ajax_chgroup_editor(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch;
channel_group_t *tcg, *tcg2;
th_transport_t *t;
char buf[10];
int nsources;
ajax_table_t ta;
if(remain == NULL || (tcg = channel_group_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
htsbuf_qprintf(tq, "\r\n");
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, tcg->tcg_name);
ajax_table_top(&ta, hc, tq, (const char *[])
{"Channelname", "Sources", "", NULL},
(int[]){8,2,1});
TAILQ_FOREACH(ch, &tcg->tcg_channels, ch_group_link) {
snprintf(buf, sizeof(buf), "%d", ch->ch_tag);
ajax_table_row_start(&ta, buf);
nsources = 0;
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link)
nsources++;
ajax_table_cell(&ta, NULL,
"%s ", ch->ch_tag, ch->ch_name);
ajax_table_cell(&ta, NULL, "%d", nsources);
ajax_table_cell_checkbox(&ta);
}
ajax_table_bottom(&ta);
htsbuf_qprintf(tq, " \r\n");
htsbuf_qprintf(tq, "");
ajax_button(tq, "Select all", "select_all()");
ajax_button(tq, "Select none", "select_none()");
ajax_button(tq, "Invert selection", "select_invert()");
ajax_button(tq, "Select channels with sources", "select_sources()");
htsbuf_qprintf(tq, "
\r\n");
htsbuf_qprintf(tq, " \r\n");
htsbuf_qprintf(tq, "");
ajax_button(tq,
"Delete all selected...",
"select_do('delete', '%d', 0, true);", tcg->tcg_tag);
htsbuf_qprintf(tq,
"", tcg->tcg_tag);
htsbuf_qprintf(tq,
"Move selected channels to group: ");
TAILQ_FOREACH(tcg2, &all_channel_groups, tcg_global_link) {
if(tcg2->tcg_hidden || tcg == tcg2)
continue;
htsbuf_qprintf(tq, "%s ",
tcg2->tcg_tag, tcg2->tcg_name);
}
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq, "");
htsbuf_qprintf(tq, "");
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
http_output_html(hc, hr);
return 0;
}
/**
*
*/
static struct strtab sourcetypetab[] = {
{ "DVB", TRANSPORT_DVB },
{ "V4L", TRANSPORT_V4L },
{ "IPTV", TRANSPORT_IPTV },
{ "AVgen", TRANSPORT_AVGEN },
{ "File", TRANSPORT_STREAMEDFILE },
};
static struct strtab cdlongname[] = {
{ "None", COMMERCIAL_DETECT_NONE },
{ "Swedish TV4 Teletext", COMMERCIAL_DETECT_TTP192 },
};
/**
* Display all channels within the group
*/
static int
ajax_cheditor(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch, *ch2;
channel_group_t *chg;
th_transport_t *t;
const char *s;
int i;
if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, ch->ch_name);
if(ch->ch_icon != NULL) {
htsbuf_qprintf(tq,
""
"
", ch->ch_icon);
}
htsbuf_qprintf(tq, "Sources:
");
LIST_FOREACH(t, &ch->ch_transports, tht_ch_link) {
ajax_box_begin(tq, AJAX_BOX_BORDER, NULL, NULL, NULL);
htsbuf_qprintf(tq, "");
htsbuf_qprintf(tq, "
%s
",
val2str(t->tht_type, sourcetypetab) ?: "???");
htsbuf_qprintf(tq, "
\"%s\"%s
",
t->tht_svcname, t->tht_scrambled ? " - (scrambled)" : "");
s = t->tht_sourcename ? t->tht_sourcename(t) : NULL;
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq,
"
"
" "
"
", t->tht_disabled ? "" : "checked ",
t->tht_identifier);
if(s != NULL)
htsbuf_qprintf(tq, "
%s
",
s);
htsbuf_qprintf(tq, "
");
ajax_box_end(tq, AJAX_BOX_BORDER);
}
htsbuf_qprintf(tq, " \r\n");
htsbuf_qprintf(tq, "");
htsbuf_qprintf(tq,
" ",
ch->ch_tag, ch->ch_name);
htsbuf_qprintf(tq,
" ",
ch->ch_tag, ch->ch_name);
htsbuf_qprintf(tq,
"",
ch->ch_tag);
htsbuf_qprintf(tq, "Merge to channel: ");
TAILQ_FOREACH(chg, &all_channel_groups, tcg_global_link) {
TAILQ_FOREACH(ch2, &chg->tcg_channels, ch_group_link) {
if(ch2 != ch)
htsbuf_qprintf(tq, "%s ",
ch2->ch_tag, ch2->ch_name);
}
}
htsbuf_qprintf(tq, " ");
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq, " \r\n");
htsbuf_qprintf(tq,
""
"Commercial detection:
"
""
"",
ch->ch_tag);
for(i = 0; i < sizeof(cdlongname) / sizeof(cdlongname[0]); i++) {
htsbuf_qprintf(tq, "%s ",
cdlongname[i].val == ch->ch_commercial_detection ?
"selected " : "",
cdlongname[i].val, cdlongname[i].str);
}
htsbuf_qprintf(tq, "
");
htsbuf_qprintf(tq, "");
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
http_output_html(hc, hr);
return 0;
}
/**
* Change group for channel(s)
*/
static int
ajax_changegroup(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch;
channel_group_t *tcg;
http_arg_t *ra;
const char *s;
const char *curgrp;
if((s = http_arg_get(&hc->hc_req_args, "arg1")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if((curgrp = http_arg_get(&hc->hc_req_args, "arg2")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
tcg = channel_group_by_tag(atoi(s));
if(tcg == NULL)
return HTTP_STATUS_BAD_REQUEST;
TAILQ_FOREACH(ra, &hc->hc_req_args, link) {
if(strcmp(ra->val, "selected"))
continue;
if((ch = channel_by_tag(atoi(ra->key))) != NULL)
channel_set_group(ch, tcg);
}
htsbuf_qprintf(tq,
"$('cheditortab').innerHTML=''; "
"new Ajax.Updater('groupeditortab', "
"'/ajax/chgroup_editor/%s', "
"{method: 'get', evalScripts: true});", curgrp);
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
* Change commercial detection type for channel(s)
*/
static int
ajax_chsetcomdetect(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
channel_t *ch;
const char *s;
if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if((s = http_arg_get(&hc->hc_req_args, "how")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
ch->ch_commercial_detection = atoi(s);
channel_settings_write(ch);
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
* Rename a channel
*/
static int
ajax_chrename(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch;
const char *s;
if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if((s = http_arg_get(&hc->hc_req_args, "newname")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if(channel_rename(ch, s)) {
htsbuf_qprintf(tq, "alert('Channel already exist');");
} else {
htsbuf_qprintf(tq,
"new Ajax.Updater('groupeditortab', "
"'/ajax/chgroup_editor/%d', "
"{method: 'get', evalScripts: true});\r\n",
ch->ch_group->tcg_tag);
htsbuf_qprintf(tq,
"new Ajax.Updater('cheditortab', "
"'/ajax/cheditor/%d', "
"{method: 'get', evalScripts: true});\r\n",
ch->ch_tag);
}
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
* Delete channel
*/
static int
ajax_chdelete(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch;
channel_group_t *tcg;
if(remain == NULL || (ch = channel_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
tcg = ch->ch_group;
channel_delete(ch);
htsbuf_qprintf(tq,
"new Ajax.Updater('groupeditortab', "
"'/ajax/chgroup_editor/%d', "
"{method: 'get', evalScripts: true});\r\n",
tcg->tcg_tag);
htsbuf_qprintf(tq, "$('cheditortab').innerHTML='';\r\n");
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
* Merge channel
*/
static int
ajax_chmerge(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *src, *dst;
channel_group_t *tcg;
const char *s;
if(remain == NULL || (src = channel_by_tag(atoi(remain))) == NULL)
return HTTP_STATUS_NOT_FOUND;
if((s = http_arg_get(&hc->hc_req_args, "dst")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
if((dst = channel_by_tag(atoi(s))) == NULL)
return HTTP_STATUS_BAD_REQUEST;
tcg = src->ch_group;
channel_merge(dst, src);
htsbuf_qprintf(tq,
"new Ajax.Updater('groupeditortab', "
"'/ajax/chgroup_editor/%d', "
"{method: 'get', evalScripts: true});\r\n",
tcg->tcg_tag);
htsbuf_qprintf(tq, "$('cheditortab').innerHTML='';\r\n");
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
* Change group for channel(s)
*/
static int
ajax_chdeletemulti(http_connection_t *hc, http_reply_t *hr,
const char *remain, void *opaque)
{
htsbuf_queue_t *tq = &hr->hr_q;
channel_t *ch;
http_arg_t *ra;
const char *curgrp;
if((curgrp = http_arg_get(&hc->hc_req_args, "arg1")) == NULL)
return HTTP_STATUS_BAD_REQUEST;
TAILQ_FOREACH(ra, &hc->hc_req_args, link) {
if(strcmp(ra->val, "selected"))
continue;
if((ch = channel_by_tag(atoi(ra->key))) != NULL)
channel_delete(ch);
}
htsbuf_qprintf(tq,
"$('cheditortab').innerHTML=''; "
"new Ajax.Updater('groupeditortab', "
"'/ajax/chgroup_editor/%s', "
"{method: 'get', evalScripts: true});", curgrp);
http_output(hc, hr, "text/javascript; charset=UTF-8", NULL, 0);
return 0;
}
/**
*
*/
void
ajax_config_channels_init(void)
{
http_path_add("/ajax/chgroup_add" , NULL, ajax_chgroup_add,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chgroup_del" , NULL, ajax_chgroup_del,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chgroup_updateorder", NULL, ajax_chgroup_updateorder,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chgroup_editor", NULL, ajax_chgroup_editor,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/cheditor", NULL, ajax_cheditor,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chop/changegroup", NULL, ajax_changegroup,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chsetcomdetect", NULL, ajax_chsetcomdetect,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chrename", NULL, ajax_chrename,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chdelete", NULL, ajax_chdelete,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chmerge", NULL, ajax_chmerge,
AJAX_ACCESS_CONFIG);
http_path_add("/ajax/chop/delete", NULL, ajax_chdeletemulti,
AJAX_ACCESS_CONFIG);
}