diff --git a/ajaxui/ajaxui.css b/ajaxui/ajaxui.css index a5a8deeb..d58d951e 100644 --- a/ajaxui/ajaxui.css +++ b/ajaxui/ajaxui.css @@ -54,6 +54,16 @@ img { border: 0; } * Misc classes */ +.iconbackdrop { + background: #fff; + height: 64px; + width: 64px; + float: left; + margin: 2px; + text-align: center; + margin-right: 4px; +} + .infoprefix { float: left; width: 50px; diff --git a/ajaxui/ajaxui_config_xmltv.c b/ajaxui/ajaxui_config_xmltv.c index a917fe05..4da96209 100644 --- a/ajaxui/ajaxui_config_xmltv.c +++ b/ajaxui/ajaxui_config_xmltv.c @@ -120,6 +120,78 @@ ajax_config_xmltv_tab(http_connection_t *hc, http_reply_t *hr) return 0; } +/** + * Generate displaylisting + */ +static void +xmltv_grabber_chlist(tcp_queue_t *tq, xmltv_grabber_t *xg) +{ + xmltv_channel_t *xc; + th_channel_group_t *tcg; + th_channel_t *ch; + + tcp_qprintf(tq, + "
"); + + TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) { + + tcp_qprintf(tq, + "
"); + + tcp_qprintf(tq, "
"); + if(xc->xc_icon_url != NULL) { + tcp_qprintf(tq, + "", + xc->xc_icon_url); + } else { + tcp_qprintf(tq, + "
" + "No icon
"); + } + tcp_qprintf(tq, "
"); /* iconbackdrop */ + + + tcp_qprintf(tq, + "
Name:
" + "
%s (%s)
", xc->xc_displayname, xc->xc_name); + + tcp_qprintf(tq, + "
Best match:
" + "
%s
", xc->xc_bestmatch ?: "(no channel)"); + + tcp_qprintf(tq, + "
Mapped to:
" + ""); + tcp_qprintf(tq, "

\r\n"); + } + tcp_qprintf(tq, "
"); +} + /** * Display detailes about a grabber @@ -154,10 +226,12 @@ ajax_xmltvgrabber(http_connection_t *hc, http_reply_t *hr, case XMLTV_GRABBER_GRABBING: case XMLTV_GRABBER_UNCONFIGURED: case XMLTV_GRABBER_DYSFUNCTIONAL: - case XMLTV_GRABBER_IDLE: tcp_qprintf(tq, "

%s

", xmltv_grabber_status_long(xg, xg->xg_status)); break; + case XMLTV_GRABBER_IDLE: + xmltv_grabber_chlist(tq, xg); + break; } @@ -185,7 +259,7 @@ ajax_xmltvgrabbermode(http_connection_t *hc, http_reply_t *hr, xmltv_grabber_enable(xg); - tcp_qprintf(tq,"$('details_%s').innerHTML='Ok, please wait...';", + tcp_qprintf(tq,"$('details_%s').innerHTML='Please wait...';", xg->xg_identifier); http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); @@ -194,13 +268,88 @@ ajax_xmltvgrabbermode(http_connection_t *hc, http_reply_t *hr, +/** + * Enable / Disable a grabber + */ +static int +ajax_xmltvgrabberlist(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) +{ + xmltv_grabber_t *xg; + tcp_queue_t *tq = &hr->hr_tq; + + if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) + return HTTP_STATUS_NOT_FOUND; + + xmltv_grabber_chlist(tq, xg); + + http_output_html(hc, hr); + return 0; +} + + +/** + * Change mapping of a channel for a grabber + */ +static int +ajax_xmltvgrabberchmap(http_connection_t *hc, http_reply_t *hr, + const char *remain, void *opaque) +{ + xmltv_grabber_t *xg; + xmltv_channel_t *xc; + const char *xmltvname; + const char *chname; + th_channel_t *ch; + // tcp_queue_t *tq = &hr->hr_tq; + + if(remain == NULL || (xg = xmltv_grabber_find(remain)) == NULL) + return HTTP_STATUS_NOT_FOUND; + + if((xmltvname = http_arg_get(&hc->hc_req_args, "xmltvch")) == NULL) + return HTTP_STATUS_BAD_REQUEST; + + if((chname = http_arg_get(&hc->hc_req_args, "channel")) == NULL) + return HTTP_STATUS_BAD_REQUEST; + + TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) + if(!strcmp(xc->xc_name, xmltvname)) + break; + + if(xc == NULL) + return HTTP_STATUS_BAD_REQUEST; + + pthread_mutex_lock(&xg->xg_mutex); + + free(xc->xc_channel); + xc->xc_channel = NULL; + xc->xc_disabled = 0; + + if(!strcmp(chname, "none")) { + xc->xc_disabled = 1; + } else if(!strcmp(chname, "auto")) { + } else if((ch = channel_by_tag(atoi(chname))) != NULL) { + xc->xc_disabled = 0; + xc->xc_channel = strdup(ch->ch_name); + } + pthread_mutex_unlock(&xg->xg_mutex); + + xmltv_config_save(); + + http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0); + return 0; +} + + + /** * */ void ajax_config_xmltv_init(void) { - http_path_add("/ajax/xmltvgrabber" , NULL, ajax_xmltvgrabber); - http_path_add("/ajax/xmltvgrabbermode" , NULL, ajax_xmltvgrabbermode); - + http_path_add("/ajax/xmltvgrabber" , NULL, ajax_xmltvgrabber); + http_path_add("/ajax/xmltvgrabbermode" , NULL, ajax_xmltvgrabbermode); + http_path_add("/ajax/xmltvgrabberlist" , NULL, ajax_xmltvgrabberlist); + http_path_add("/ajax/xmltvgrabberchmap" , NULL, ajax_xmltvgrabberchmap); + } diff --git a/ajaxui/ajaxui_mailbox.c b/ajaxui/ajaxui_mailbox.c index 43a16542..6be0f5cf 100644 --- a/ajaxui/ajaxui_mailbox.c +++ b/ajaxui/ajaxui_mailbox.c @@ -36,8 +36,8 @@ #define MAILBOX_EMPTY_REPLY_TIMEOUT 10 -//#define mbdebug(fmt...) printf(fmt); -#define mbdebug(fmt...) +#define mbdebug(fmt...) printf(fmt); +//#define mbdebug(fmt...) static LIST_HEAD(, ajaxui_mailbox) mailboxes; @@ -453,13 +453,23 @@ ajax_mailbox_tda_change(th_dvb_adapter_t *tda) void ajax_mailbox_xmltv_grabber_status_change(xmltv_grabber_t *xg, int status) { + char buf[500]; + ajax_mailbox_update_div("xmltvgrabbers", "status", xg->xg_identifier, xmltv_grabber_status(xg)); - ajax_mailbox_update_div(xg->xg_identifier, - "details", xg->xg_identifier, - xmltv_grabber_status_long(xg, status)); + + if(status == XMLTV_GRABBER_IDLE) { + snprintf(buf, sizeof(buf), "/ajax/xmltvgrabberlist/%s", xg->xg_identifier); + ajax_mailbox_reload_div("xmltvgrabbers", + "details", xg->xg_identifier, + buf); + } else { + ajax_mailbox_update_div(xg->xg_identifier, + "details", xg->xg_identifier, + xmltv_grabber_status_long(xg, status)); + } } diff --git a/epg_xmltv.c b/epg_xmltv.c index 8b2e4531..45d526ef 100644 --- a/epg_xmltv.c +++ b/epg_xmltv.c @@ -45,6 +45,7 @@ struct xmltv_grabber_list xmltv_grabbers; struct xmltv_grabber_queue xmltv_grabber_workq; static pthread_mutex_t xmltv_work_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t xmltv_work_cond = PTHREAD_COND_INITIALIZER; +static void xmltv_config_load(void); static xmltv_channel_t * @@ -52,14 +53,14 @@ xc_find(xmltv_grabber_t *xg, const char *name) { xmltv_channel_t *xc; - LIST_FOREACH(xc, &xg->xg_channels, xc_link) + TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) if(!strcmp(xc->xc_name, name)) return xc; xc = calloc(1, sizeof(xmltv_channel_t)); xc->xc_name = strdup(name); TAILQ_INIT(&xc->xc_events); - LIST_INSERT_HEAD(&xg->xg_channels, xc, xc_link); + TAILQ_INSERT_TAIL(&xg->xg_channels, xc, xc_link); return xc; } @@ -213,7 +214,7 @@ xmltv_flush_events(xmltv_grabber_t *xg) xmltv_channel_t *xc; event_t *e; - LIST_FOREACH(xc, &xg->xg_channels, xc_link) { + TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) { while((e = TAILQ_FIRST(&xc->xc_events)) != NULL) { TAILQ_REMOVE(&xc->xc_events, e, e_link); epg_event_free(e); @@ -321,6 +322,7 @@ xmltv_transfer(void) } #endif + /* * Execute grabber and parse result, * @@ -443,6 +445,9 @@ xmltv_find_grabbers(const char *prog) continue; xg = calloc(1, sizeof(xmltv_grabber_t)); + pthread_mutex_init(&xg->xg_mutex, NULL); + + TAILQ_INIT(&xg->xg_channels); xg->xg_path = a; xg->xg_title = b; @@ -451,6 +456,7 @@ xmltv_find_grabbers(const char *prog) LIST_INSERT_SORTED(&xmltv_grabbers, xg, xg_link, grabbercmp); } + xmltv_config_load(); return 0; } @@ -559,13 +565,14 @@ xmltv_grabber_enable(xmltv_grabber_t *xg) { pthread_mutex_lock(&xmltv_work_lock); - if(xg->xg_status == XMLTV_GRABBER_DISABLED) { + if(xg->xg_status != XMLTV_GRABBER_ENQUEUED) { xg->xg_status = XMLTV_GRABBER_ENQUEUED; TAILQ_INSERT_TAIL(&xmltv_grabber_workq, xg, xg_work_link); pthread_cond_signal(&xmltv_work_cond); } pthread_mutex_unlock(&xmltv_work_lock); + xmltv_config_save(); } /** @@ -647,3 +654,112 @@ xmltv_grabber_status_long(xmltv_grabber_t *xg, int status) return "Unknown status"; } } + + +/* + * Write grabber configuration + */ +void +xmltv_config_save(void) +{ + char buf[PATH_MAX]; + xmltv_grabber_t *xg; + xmltv_channel_t *xc; + FILE *fp; + + snprintf(buf, sizeof(buf), "%s/xmltv-settings.cfg", settings_dir); + + if((fp = settings_open_for_write(buf)) == NULL) + return; + + LIST_FOREACH(xg, &xmltv_grabbers, xg_link) { + if(xg->xg_status == XMLTV_GRABBER_DISABLED) + continue; + + fprintf(fp, "grabber {\n"); + fprintf(fp, "\ttitle = %s\n", xg->xg_title); + + TAILQ_FOREACH(xc, &xg->xg_channels, xc_link) { + fprintf(fp, "\tchannel {\n"); + fprintf(fp, "\t\tdisplayname = %s\n", xc->xc_displayname); + fprintf(fp, "\t\ticon = %s\n", xc->xc_icon_url); + fprintf(fp, "\t\tname = %s\n", xc->xc_name); + if(xc->xc_disabled) + fprintf(fp, "\t\tmapping = disabled\n"); + else + fprintf(fp, "\t\tmapping = %s\n", xc->xc_channel ?: "auto"); + fprintf(fp, "\t}\n"); + } + fprintf(fp, "}\n"); + } + fclose(fp); +} + +/** + * + */ +static void +xmltv_config_load(void) +{ + struct config_head cl; + config_entry_t *ce, *ce2; + char buf[PATH_MAX]; + const char *title, *name, *s; + xmltv_channel_t *xc; + xmltv_grabber_t *xg; + + TAILQ_INIT(&cl); + + snprintf(buf, sizeof(buf), "%s/xmltv-settings.cfg", settings_dir); + + config_read_file0(buf, &cl); + + pthread_mutex_lock(&xmltv_work_lock); + + TAILQ_FOREACH(ce, &cl, ce_link) { + if(ce->ce_type != CFG_SUB || strcasecmp("grabber", ce->ce_key)) + continue; + + if((title = config_get_str_sub(&ce->ce_sub, "title", NULL)) == NULL) + continue; + + LIST_FOREACH(xg, &xmltv_grabbers, xg_link) + if(!strcmp(title, xg->xg_title)) + break; + if(xg == NULL) + continue; + + xg->xg_status = XMLTV_GRABBER_ENQUEUED; + TAILQ_INSERT_TAIL(&xmltv_grabber_workq, xg, xg_work_link); + + TAILQ_FOREACH(ce2, &ce->ce_sub, ce_link) { + if(ce2->ce_type != CFG_SUB || strcasecmp("channel", ce2->ce_key)) + continue; + + if((name = config_get_str_sub(&ce2->ce_sub, "name", NULL)) == NULL) + continue; + + xc = xc_find(xg, name); + + if((s = config_get_str_sub(&ce2->ce_sub, "displayname", NULL)) != NULL) + xc->xc_displayname = strdup(s); + + if((s = config_get_str_sub(&ce2->ce_sub, "icon", NULL)) != NULL) + xc->xc_icon_url = strdup(s); + + if((s = config_get_str_sub(&ce2->ce_sub, "mapping", NULL)) != NULL) { + xc->xc_channel = NULL; + if(!strcmp(s, "disabled")) { + xc->xc_disabled = 1; + } else if(!strcmp(s, "auto")) { + } else { + xc->xc_channel = strdup(s); + } + } + } + } + + pthread_mutex_unlock(&xmltv_work_lock); + + config_free0(&cl); +} diff --git a/epg_xmltv.h b/epg_xmltv.h index 7673dd30..324aef8c 100644 --- a/epg_xmltv.h +++ b/epg_xmltv.h @@ -23,7 +23,7 @@ LIST_HEAD(xmltv_grabber_list, xmltv_grabber); TAILQ_HEAD(xmltv_grabber_queue, xmltv_grabber); -LIST_HEAD(xmltv_channel_list, xmltv_channel); +TAILQ_HEAD(xmltv_channel_queue, xmltv_channel); typedef struct xmltv_grabber { LIST_ENTRY(xmltv_grabber) xg_link; @@ -44,7 +44,9 @@ typedef struct xmltv_grabber { time_t xg_nextgrab; - struct xmltv_channel_list xg_channels; + struct xmltv_channel_queue xg_channels; + + pthread_mutex_t xg_mutex; } xmltv_grabber_t; @@ -54,10 +56,16 @@ typedef struct xmltv_grabber { * A channel in the XML-TV world */ typedef struct xmltv_channel { - LIST_ENTRY(xmltv_channel) xc_link; + TAILQ_ENTRY(xmltv_channel) xc_link; char *xc_name; char *xc_displayname; + + char *xc_bestmatch; /* Best matching channel */ + char *xc_channel; + + int xc_disabled; + char *xc_icon_url; struct event_queue xc_events; @@ -82,4 +90,6 @@ xmltv_grabber_t *xmltv_grabber_find(const char *id); const char *xmltv_grabber_status_long(xmltv_grabber_t *xg, int status); +void xmltv_config_save(void); + #endif /* __XMLTV_H__ */