Make channel group management work

This commit is contained in:
Andreas Öman 2007-12-02 16:26:13 +00:00
parent f6bed08aef
commit a1e3cffd49
4 changed files with 236 additions and 67 deletions

View file

@ -41,8 +41,11 @@
struct th_channel_list channels;
struct th_transport_list all_transports;
int nchannels;
int grouporder = 1000;
struct th_channel_group_list all_channel_groups;
struct th_channel_group_queue all_channel_groups;
th_channel_group_t *defgroup;
void scanner_init(void);
@ -63,33 +66,56 @@ channel_group_find(const char *name, int create)
{
th_channel_group_t *tcg;
LIST_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
if(!strcmp(name, tcg->tcg_name))
break;
return tcg;
}
if(!create)
return NULL;
tcg = calloc(1, sizeof(th_channel_group_t));
tcg->tcg_name = strdup(name);
LIST_INSERT_HEAD(&all_channel_groups, tcg, tcg_global_link);
tcg->tcg_tag = tag_get();
tcg->tcg_order = grouporder++;
TAILQ_INSERT_HEAD(&all_channel_groups, tcg, tcg_global_link);
return tcg;
}
/**
*
*/
void
channel_set_group(th_channel_t *ch, th_channel_group_t *tcg)
{
if(ch->ch_group != NULL)
LIST_REMOVE(ch, ch_group_link);
ch->ch_group = tcg;
LIST_INSERT_SORTED(&tcg->tcg_channels, ch, ch_group_link, ch_order_cmp);
}
/**
*
*/
void
channel_set_group(th_channel_t *ch, const char *groupname)
channel_group_destroy(th_channel_group_t *tcg)
{
th_channel_group_t *tcg;
th_channel_t *ch;
if(ch->ch_group != NULL)
LIST_REMOVE(ch, ch_group_link);
if(defgroup == tcg)
return;
tcg = channel_group_find(groupname, 1);
ch->ch_group = tcg;
LIST_INSERT_SORTED(&tcg->tcg_channels, ch, ch_group_link, ch_order_cmp);
while((ch = LIST_FIRST(&tcg->tcg_channels)) != NULL) {
channel_set_group(ch, defgroup);
}
TAILQ_REMOVE(&all_channel_groups, tcg, tcg_global_link);
free((void *)tcg->tcg_name);
free(tcg);
}
/**
@ -135,7 +161,7 @@ channel_find(const char *name, int create)
ch->ch_order = nchannels + 1000;
LIST_INSERT_SORTED(&channels, ch, ch_global_link, ch_order_cmp);
channel_set_group(ch, "Default");
channel_set_group(ch, defgroup);
ch->ch_tag = tag_get();
nchannels++;
@ -264,6 +290,11 @@ channels_load(void)
{
config_entry_t *ce;
TAILQ_INIT(&all_channel_groups);
defgroup = channel_group_find("Uncategorized", 1);
defgroup->tcg_cant_delete_me = 1;
TAILQ_FOREACH(ce, &config_list, ce_link) {
if(ce->ce_type == CFG_SUB && !strcasecmp("channel", ce->ce_key)) {
channel_load(&ce->ce_sub);
@ -309,3 +340,20 @@ channel_by_tag(uint32_t tag)
return NULL;
}
/**
*
*/
th_channel_group_t *
channel_group_by_tag(uint32_t tag)
{
th_channel_group_t *tcg;
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link)
if(tcg->tcg_tag == tag)
return tcg;
return NULL;
}

View file

@ -33,4 +33,10 @@ void channel_unsubscribe(th_subscription_t *s);
th_channel_t *channel_find(const char *name, int create);
th_channel_group_t *channel_group_find(const char *name, int create);
th_channel_group_t *channel_group_by_tag(uint32_t tag);
void channel_group_destroy(th_channel_group_t *tcg);
#endif /* CHANNELS_H */

216
htmlui.c
View file

@ -164,6 +164,11 @@ html_header(tcp_queue_t *tq, const char *title, int javascript, int width,
".content {padding-left: 3px; border-left: 1px solid #000000; "
"border-right: 1px solid #000000;}\r\n"
""
".contentbig {padding-left: 3px; "
"border-left: 1px solid #000000; "
"border-right: 1px solid #000000; "
"font: 150% Verdana, Arial, Helvetica, sans-serif;}\r\n"
""
".statuscont {float: left; margin: 4px; width: 400px}\r\n"
""
".logo {padding: 2px; width: 60px; height: 56px; "
@ -261,6 +266,12 @@ top_menu(http_connection_t *hc, tcp_queue_t *tq)
if(html_verify_access(hc, "system-status"))
tcp_qprintf(tq, "<li><a href=\"/status\">System Status</a></li>");
if(html_verify_access(hc, "admin"))
tcp_qprintf(tq, "<li><a href=\"/chgrp\">Manage channel groups</a></li>");
if(html_verify_access(hc, "admin"))
tcp_qprintf(tq, "<li><a href=\"/chadm\">Manage channels</a></li>");
tcp_qprintf(tq, "</div>");
box_bottom(tq);
@ -396,6 +407,7 @@ page_root(http_connection_t *hc, const char *remain, void *opaque)
int i;
int simple = is_client_simple(hc);
time_t firstend = INT32_MAX;
th_channel_group_t *tcg;
if(!html_verify_access(hc, "browse-events"))
return HTTP_STATUS_UNAUTHORIZED;
@ -418,48 +430,59 @@ page_root(http_connection_t *hc, const char *remain, void *opaque)
html_header(&tq, "HTS/tvheadend", !simple, 700, i);
top_menu(hc, &tq);
LIST_FOREACH(ch, &channels, ch_global_link) {
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content3\">");
if(!simple) {
tcp_qprintf(&tq, "<div class=\"logo\">");
if(ch->ch_icon) {
tcp_qprintf(&tq, "<a href=\"channel/%d\">"
"<img src=\"%s\" height=56px>"
"</a>",
ch->ch_tag,
refstr_get(ch->ch_icon));
}
tcp_qprintf(&tq, "</div>");
}
tcp_qprintf(&tq, "<div class=\"over\">");
tcp_qprintf(&tq,
"<span style=\"overflow: hidden; height: 15px; "
"width: 300px; float: left; font-weight:bold\">"
"<a href=\"channel/%d\">%s</a></span>",
ch->ch_tag, ch->ch_name);
if(tvheadend_streaming_host != NULL) {
tcp_qprintf(&tq,
"<i><a href=\"rtsp://%s:%d/%s\">Watch live</a></i><br>",
tvheadend_streaming_host, http_port, ch->ch_sname);
} else {
tcp_qprintf(&tq, "<br>");
}
e = epg_event_find_current_or_upcoming(ch);
for(i = 0; i < 3 && e != NULL; i++) {
output_event(hc, &tq, ch, e, simple);
e = TAILQ_NEXT(e, e_link);
}
tcp_qprintf(&tq, "</div></div>");
"<div class=\"contentbig\"><center><b>%s</b></center></div>",
tcg->tcg_name);
box_bottom(&tq);
tcp_qprintf(&tq, "<br>\r\n");
tcp_qprintf(&tq, "<br>");
LIST_FOREACH(ch, &tcg->tcg_channels, ch_group_link) {
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content3\">");
if(!simple) {
tcp_qprintf(&tq, "<div class=\"logo\">");
if(ch->ch_icon) {
tcp_qprintf(&tq, "<a href=\"channel/%d\">"
"<img src=\"%s\" height=56px>"
"</a>",
ch->ch_tag,
refstr_get(ch->ch_icon));
}
tcp_qprintf(&tq, "</div>");
}
tcp_qprintf(&tq, "<div class=\"over\">");
tcp_qprintf(&tq,
"<span style=\"overflow: hidden; height: 15px; "
"width: 300px; float: left; font-weight:bold\">"
"<a href=\"channel/%d\">%s</a></span>",
ch->ch_tag, ch->ch_name);
if(tvheadend_streaming_host != NULL) {
tcp_qprintf(&tq,
"<i><a href=\"rtsp://%s:%d/%s\">Watch live</a></i><br>",
tvheadend_streaming_host, http_port, ch->ch_sname);
} else {
tcp_qprintf(&tq, "<br>");
}
e = epg_event_find_current_or_upcoming(ch);
for(i = 0; i < 3 && e != NULL; i++) {
output_event(hc, &tq, ch, e, simple);
e = TAILQ_NEXT(e, e_link);
}
tcp_qprintf(&tq, "</div></div>");
box_bottom(&tq);
tcp_qprintf(&tq, "<br>\r\n");
}
}
epg_unlock();
@ -580,7 +603,7 @@ page_event(http_connection_t *hc, const char *remain, void *opaque)
struct tm a, b;
time_t stop;
char desc[4000];
recop_t cmd = 0;
recop_t cmd = -1;
tv_pvr_status_t pvrstatus;
const char *pvr_txt, *pvr_color;
@ -594,23 +617,26 @@ page_event(http_connection_t *hc, const char *remain, void *opaque)
return 404;
}
remain = strchr(remain, '?');
if(remain != NULL) {
if(http_arg_get(&hc->hc_url_args, "rec")) {
if(!html_verify_access(hc, "record-events")) {
epg_unlock();
return HTTP_STATUS_UNAUTHORIZED;
}
remain++;
if(!strncmp(remain, "rec=", 4))
cmd = RECOP_ONCE;
if(!strncmp(remain, "cancel=", 7))
cmd = RECOP_CANCEL;
pvr_event_record_op(e->e_ch, e, cmd);
cmd = RECOP_ONCE;
}
if(http_arg_get(&hc->hc_url_args, "cancel")) {
if(!html_verify_access(hc, "record-events")) {
epg_unlock();
return HTTP_STATUS_UNAUTHORIZED;
}
cmd = RECOP_CANCEL;
}
if(cmd != -1)
pvr_event_record_op(e->e_ch, e, cmd);
pvrstatus = pvr_prog_status(e);
localtime_r(&e->e_start, &a);
@ -884,7 +910,7 @@ page_status(http_connection_t *hc, const char *remain, void *opaque)
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content\">");
tcp_qprintf(&tq, "<div class=\"contentbig\">");
tcp_qprintf(&tq, "<b><center>Input devices</b><br>");
tcp_qprintf(&tq, "</div>");
box_bottom(&tq);
@ -1020,7 +1046,7 @@ page_status(http_connection_t *hc, const char *remain, void *opaque)
tcp_qprintf(&tq, "<div class=\"statuscont\">");
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content\">");
tcp_qprintf(&tq, "<div class=\"contentbig\">");
tcp_qprintf(&tq, "<b><center>Active transports</b><br>");
tcp_qprintf(&tq, "</div>");
box_bottom(&tq);
@ -1123,7 +1149,7 @@ page_status(http_connection_t *hc, const char *remain, void *opaque)
tcp_qprintf(&tq, "<div class=\"statuscont\">");
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content\">");
tcp_qprintf(&tq, "<div class=\"contentbig\">");
tcp_qprintf(&tq, "<b><center>Subscriptions</b><br>");
tcp_qprintf(&tq, "</div>");
box_bottom(&tq);
@ -1191,6 +1217,91 @@ page_status(http_connection_t *hc, const char *remain, void *opaque)
}
/**
* Manage channel groups
*/
static int
page_chgroups(http_connection_t *hc, const char *remain, void *opaque)
{
tcp_queue_t tq;
th_channel_group_t *tcg;
th_channel_t *ch;
int cnt;
const char *grp;
http_arg_t *ra;
if(!html_verify_access(hc, "admin"))
return HTTP_STATUS_UNAUTHORIZED;
if((grp = http_arg_get(&hc->hc_url_args, "newgrpname")) != NULL)
channel_group_find(grp, 1);
LIST_FOREACH(ra, &hc->hc_url_args, link) {
if(!strncmp(ra->key, "delgroup", 8))
break;
}
if(ra != NULL) {
tcg = channel_group_by_tag(atoi(ra->key + 8));
if(tcg != NULL) {
channel_group_destroy(tcg);
}
}
tcp_init_queue(&tq, -1);
html_header(&tq, "HTS/tvheadend", 0, 700, 0);
top_menu(hc, &tq);
tcp_qprintf(&tq, "<form method=\"get\" action=\"/chgrp\">");
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content3\">"
"<input type=\"text\" name=\"newgrpname\"> "
"<input type=\"submit\" name=\"newgrp\""
" value=\"Add new group\">"
"</div>");
box_bottom(&tq);
tcp_qprintf(&tq, "</form><br>\r\n");
TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) {
tcp_qprintf(&tq, "<form method=\"get\" action=\"/chgrp\">");
box_top(&tq, "box");
tcp_qprintf(&tq, "<div class=\"content3\">");
cnt = 0;
LIST_FOREACH(ch, &tcg->tcg_channels, ch_group_link)
cnt++;
tcp_qprintf(&tq, "<b>%s</b> (%d channels)<br>", tcg->tcg_name, cnt);
if(tcg->tcg_cant_delete_me == 0) {
tcp_qprintf(&tq,
"<input type=\"submit\" name=\"delgroup%d\""
" value=\"Delete this group\">"
"</div>", tcg->tcg_tag);
}
tcp_qprintf(&tq, "</div>");
box_bottom(&tq);
tcp_qprintf(&tq, "</form><br>\r\n");
}
http_output_queue(hc, &tq, "text/html; charset=UTF-8");
return 0;
}
/**
* HTML user interface setup code
*/
@ -1202,4 +1313,5 @@ htmlui_start(void)
http_path_add("/channel", NULL, page_channel);
http_path_add("/pvrlog", NULL, page_pvrlog);
http_path_add("/status", NULL, page_status);
http_path_add("/chgrp", NULL, page_chgroups);
}

View file

@ -68,9 +68,8 @@ typedef struct dtimer {
*/
LIST_HEAD(th_subscription_list, th_subscription);
TAILQ_HEAD(th_channel_queue, th_channel);
LIST_HEAD(th_channel_list, th_channel);
LIST_HEAD(th_channel_group_list, th_channel_group);
TAILQ_HEAD(th_channel_group_queue, th_channel_group);
LIST_HEAD(th_dvb_adapter_list, th_dvb_adapter);
LIST_HEAD(th_v4l_adapter_list, th_v4l_adapter);
LIST_HEAD(event_list, event);
@ -91,6 +90,7 @@ extern time_t dispatch_clock;
extern int startupcounter;
extern struct th_transport_list all_transports;
extern struct th_channel_list channels;
extern struct th_channel_group_queue all_channel_groups;
extern struct pvr_rec_list pvrr_global_list;
extern struct th_subscription_list subscriptions;
@ -619,10 +619,13 @@ typedef struct tt_decoder {
* Channel groups
*/
typedef struct th_channel_group {
LIST_ENTRY(th_channel_group) tcg_global_link;
TAILQ_ENTRY(th_channel_group) tcg_global_link;
const char *tcg_name;
struct th_channel_list tcg_channels;
int tcg_tag;
int tcg_order;
int tcg_cant_delete_me;
} th_channel_group_t;