From a1e3cffd492578b417a9ecc3de7ccf9a09025d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96man?= Date: Sun, 2 Dec 2007 16:26:13 +0000 Subject: [PATCH] Make channel group management work --- channels.c | 72 +++++++++++++++--- channels.h | 6 ++ htmlui.c | 216 ++++++++++++++++++++++++++++++++++++++++------------- tvhead.h | 9 ++- 4 files changed, 236 insertions(+), 67 deletions(-) diff --git a/channels.c b/channels.c index 07bb4c63..a4b3994c 100644 --- a/channels.c +++ b/channels.c @@ -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; +} diff --git a/channels.h b/channels.h index b8c3a7ef..97243e7e 100644 --- a/channels.h +++ b/channels.h @@ -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 */ diff --git a/htmlui.c b/htmlui.c index eb74a435..b9a54da3 100644 --- a/htmlui.c +++ b/htmlui.c @@ -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, "
  • System Status
  • "); + if(html_verify_access(hc, "admin")) + tcp_qprintf(tq, "
  • Manage channel groups
  • "); + + if(html_verify_access(hc, "admin")) + tcp_qprintf(tq, "
  • Manage channels
  • "); + tcp_qprintf(tq, ""); 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, "
    "); - if(!simple) { - tcp_qprintf(&tq, "
    "); - if(ch->ch_icon) { - tcp_qprintf(&tq, "" - "" - "", - ch->ch_tag, - refstr_get(ch->ch_icon)); - } - tcp_qprintf(&tq, "
    "); - } - - tcp_qprintf(&tq, "
    "); tcp_qprintf(&tq, - "" - "%s", - ch->ch_tag, ch->ch_name); - - if(tvheadend_streaming_host != NULL) { - tcp_qprintf(&tq, - "Watch live
    ", - tvheadend_streaming_host, http_port, ch->ch_sname); - } else { - tcp_qprintf(&tq, "
    "); - } - - 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, "
    "); + "
    %s
    ", + tcg->tcg_name); box_bottom(&tq); - tcp_qprintf(&tq, "
    \r\n"); + tcp_qprintf(&tq, "
    "); + + LIST_FOREACH(ch, &tcg->tcg_channels, ch_group_link) { + box_top(&tq, "box"); + tcp_qprintf(&tq, "
    "); + + if(!simple) { + tcp_qprintf(&tq, "
    "); + if(ch->ch_icon) { + tcp_qprintf(&tq, "" + "" + "", + ch->ch_tag, + refstr_get(ch->ch_icon)); + } + tcp_qprintf(&tq, "
    "); + } + + tcp_qprintf(&tq, "
    "); + tcp_qprintf(&tq, + "" + "%s", + ch->ch_tag, ch->ch_name); + + if(tvheadend_streaming_host != NULL) { + tcp_qprintf(&tq, + "Watch live
    ", + tvheadend_streaming_host, http_port, ch->ch_sname); + } else { + tcp_qprintf(&tq, "
    "); + } + + 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, "
    "); + box_bottom(&tq); + tcp_qprintf(&tq, "
    \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, "
    "); + tcp_qprintf(&tq, "
    "); tcp_qprintf(&tq, "
    Input devices
    "); tcp_qprintf(&tq, "
    "); box_bottom(&tq); @@ -1020,7 +1046,7 @@ page_status(http_connection_t *hc, const char *remain, void *opaque) tcp_qprintf(&tq, "
    "); box_top(&tq, "box"); - tcp_qprintf(&tq, "
    "); + tcp_qprintf(&tq, "
    "); tcp_qprintf(&tq, "
    Active transports
    "); tcp_qprintf(&tq, "
    "); box_bottom(&tq); @@ -1123,7 +1149,7 @@ page_status(http_connection_t *hc, const char *remain, void *opaque) tcp_qprintf(&tq, "
    "); box_top(&tq, "box"); - tcp_qprintf(&tq, "
    "); + tcp_qprintf(&tq, "
    "); tcp_qprintf(&tq, "
    Subscriptions
    "); tcp_qprintf(&tq, "
    "); 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, "
    "); + + box_top(&tq, "box"); + tcp_qprintf(&tq, "
    " + " " + "" + "
    "); + + box_bottom(&tq); + tcp_qprintf(&tq, "

    \r\n"); + + + TAILQ_FOREACH(tcg, &all_channel_groups, tcg_global_link) { + + tcp_qprintf(&tq, "
    "); + + box_top(&tq, "box"); + tcp_qprintf(&tq, "
    "); + + cnt = 0; + LIST_FOREACH(ch, &tcg->tcg_channels, ch_group_link) + cnt++; + + tcp_qprintf(&tq, "%s (%d channels)
    ", tcg->tcg_name, cnt); + + if(tcg->tcg_cant_delete_me == 0) { + tcp_qprintf(&tq, + "" + "
    ", tcg->tcg_tag); + } + + tcp_qprintf(&tq, "
    "); + box_bottom(&tq); + tcp_qprintf(&tq, "
    \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); } diff --git a/tvhead.h b/tvhead.h index 5636b614..2aa15404 100644 --- a/tvhead.h +++ b/tvhead.h @@ -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;