From: Jaroslav Kysela Date: Wed, 28 Oct 2015 18:55:49 +0000 (+0100) Subject: http server: add initial version of XMLTV exporter X-Git-Tag: v4.2.1~1752 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=251fc2c8fa296bfa3ac6bed4f2b7f55bd244f80c;p=thirdparty%2Ftvheadend.git http server: add initial version of XMLTV exporter --- diff --git a/Makefile b/Makefile index e73c93f0d..88cb9eb30 100644 --- a/Makefile +++ b/Makefile @@ -273,6 +273,7 @@ SRCS-2 += \ src/webui/statedump.c \ src/webui/html.c\ src/webui/webui_api.c\ + src/webui/xmltv.c SRCS-2 += \ src/muxer.c \ diff --git a/src/http.c b/src/http.c index 9743ccf02..f9214739f 100644 --- a/src/http.c +++ b/src/http.c @@ -503,6 +503,25 @@ http_redirect(http_connection_t *hc, const char *location, free((void *)loc); } +/** + * + */ +char * +http_get_hostpath(http_connection_t *hc) +{ + char buf[256]; + const char *host, *proto; + + host = http_arg_get(&hc->hc_args, "Host") ?: + http_arg_get(&hc->hc_args, "X-Forwarded-Host"); + proto = http_arg_get(&hc->hc_args, "X-Forwarded-Proto"); + + snprintf(buf, sizeof(buf), "%s://%s%s", + proto ?: "http", host, tvheadend_webroot ?: ""); + + return strdup(buf); +} + /** * */ diff --git a/src/http.h b/src/http.h index 74eb1b30e..2c4134bfb 100644 --- a/src/http.h +++ b/src/http.h @@ -243,6 +243,8 @@ void http_deescape(char *s); void http_parse_args(http_arg_list_t *list, char *args); +char *http_get_hostpath(http_connection_t *hc); + /* * HTTP/RTSP Client */ diff --git a/src/webui/webui.c b/src/webui/webui.c index f04250b77..4880dcd0e 100644 --- a/src/webui/webui.c +++ b/src/webui/webui.c @@ -1,6 +1,7 @@ /* * tvheadend, WEBUI / HTML user interface * Copyright (C) 2008 Andreas Öman + * Copyright (C) 2014,2015 Jaroslav Kysela * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -460,21 +461,6 @@ http_stream_run(http_connection_t *hc, profile_chain_t *prch, muxer_close(mux); } -/* - * - */ -static char * -http_get_hostpath(http_connection_t *hc) -{ - char buf[255]; - const char *host = http_arg_get(&hc->hc_args, "Host") ?: http_arg_get(&hc->hc_args, "X-Forwarded-Host"); - const char *proto = http_arg_get(&hc->hc_args, "X-Forwarded-Proto"); - - snprintf(buf, sizeof(buf), "%s://%s%s", proto ?: "http", host, tvheadend_webroot ?: ""); - - return strdup(buf); -} - /* * */ @@ -1818,6 +1804,7 @@ webui_init(int xspf) http_path_add("/dvrfile", NULL, page_dvrfile, ACCESS_ANONYMOUS); http_path_add("/favicon.ico", NULL, favicon, ACCESS_WEB_INTERFACE); http_path_add("/playlist", NULL, page_http_playlist, ACCESS_ANONYMOUS); + http_path_add("/xmltv", NULL, page_xmltv, ACCESS_ANONYMOUS); http_path_add("/state", NULL, page_statedump, ACCESS_ADMIN); diff --git a/src/webui/webui.h b/src/webui/webui.h index 5ffe62125..2aae83501 100644 --- a/src/webui/webui.h +++ b/src/webui/webui.h @@ -34,6 +34,7 @@ size_t html_escaped_len(const char *src); const char* html_escape(char *dst, const char *src, size_t len); int page_static_file(http_connection_t *hc, const char *remain, void *opaque); +int page_xmltv(http_connection_t *hc, const char *remain, void *opaque); #if ENABLE_LINUXDVB void extjs_start_dvb(void); diff --git a/src/webui/xmltv.c b/src/webui/xmltv.c new file mode 100644 index 000000000..128ede060 --- /dev/null +++ b/src/webui/xmltv.c @@ -0,0 +1,253 @@ +/* + * tvheadend, XMLTV exporter + * Copyright (C) 2015 Jaroslav Kysela + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tvheadend.h" +#include "config.h" +#include "webui.h" +#include "channels.h" +#include "http.h" + +/* + * + */ +static void +http_xmltv_time(char *dst, time_t t) +{ + struct tm tm; + /* 20140817060000 +0200 */ + strftime(dst, 32, "%Y%m%d%H%M%S %z", localtime_r(&t, &tm)); +} + +/* + * + */ +static void +http_xmltv_begin(htsbuf_queue_t *hq) +{ + htsbuf_qprintf(hq, "\ +\n\ +\n\ +\n\ +", tvheadend_version, config.server_name); +} + +/* + * + */ +static void +http_xmltv_end(htsbuf_queue_t *hq) +{ + htsbuf_qprintf(hq, "\n"); +} + +/* + * + */ +static void +http_xmltv_channel_add(htsbuf_queue_t *hq, const char *hostpath, channel_t *ch) +{ + htsbuf_qprintf(hq, "\n %s\n\n", + idnode_uuid_as_sstr(&ch->ch_id), channel_get_name(ch)); +} + +/* + * + */ +static void +http_xmltv_programme_one(htsbuf_queue_t *hq, const char *hostpath, + channel_t *ch, epg_broadcast_t *ebc) +{ + char start[32], stop[32]; + epg_episode_t *e = ebc->episode; + lang_str_ele_t *lse; + + if (e == NULL || e->title == NULL) return; + http_xmltv_time(start, ebc->start); + http_xmltv_time(stop, ebc->stop); + htsbuf_qprintf(hq, "\n", + start, stop, idnode_uuid_as_sstr(&ch->ch_id)); + RB_FOREACH(lse, e->title, link) + htsbuf_qprintf(hq, " %s\n", lse->lang, lse->str); + if (e->subtitle) + RB_FOREACH(lse, e->subtitle, link) + htsbuf_qprintf(hq, " %s\n", lse->lang, lse->str); + if (ebc->description) + RB_FOREACH(lse, ebc->description, link) + htsbuf_qprintf(hq, " %s\n", lse->lang, lse->str); + htsbuf_qprintf(hq, "\n"); +} + +/* + * + */ +static void +http_xmltv_programme_add(htsbuf_queue_t *hq, const char *hostpath, channel_t *ch) +{ + epg_broadcast_t *ebc; + + RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) + http_xmltv_programme_one(hq, hostpath, ch, ebc); +} + +/** + * Output a XMLTV containing a single channel + */ +static int +http_xmltv_channel(http_connection_t *hc, channel_t *channel) +{ + char *hostpath; + + if (http_access_verify_channel(hc, ACCESS_STREAMING, channel, 1)) + return HTTP_STATUS_UNAUTHORIZED; + + hostpath = http_get_hostpath(hc); + http_xmltv_begin(&hc->hc_reply); + http_xmltv_channel_add(&hc->hc_reply, hostpath, channel); + http_xmltv_programme_add(&hc->hc_reply, hostpath, channel); + http_xmltv_end(&hc->hc_reply); + free(hostpath); + return 0; +} + + +/** + * Output a playlist containing all channels with a specific tag + */ +static int +http_xmltv_tag(http_connection_t *hc, channel_tag_t *tag) +{ + idnode_list_mapping_t *ilm; + char *hostpath; + channel_t *ch; + + if (hc->hc_access == NULL || + access_verify2(hc->hc_access, ACCESS_STREAMING)) + return HTTP_STATUS_UNAUTHORIZED; + + hostpath = http_get_hostpath(hc); + + http_xmltv_begin(&hc->hc_reply); + LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) { + ch = (channel_t *)ilm->ilm_in2; + if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 0)) + continue; + http_xmltv_channel_add(&hc->hc_reply, hostpath, ch); + } + LIST_FOREACH(ilm, &tag->ct_ctms, ilm_in1_link) { + ch = (channel_t *)ilm->ilm_in2; + if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 0)) + continue; + http_xmltv_programme_add(&hc->hc_reply, hostpath, ch); + } + http_xmltv_end(&hc->hc_reply); + + free(hostpath); + return 0; +} + +/** + * Output a flat playlist with all channels + */ +static int +http_xmltv_channel_list(http_connection_t *hc) +{ + channel_t *ch; + char *hostpath; + + if (hc->hc_access == NULL || + access_verify2(hc->hc_access, ACCESS_STREAMING)) + return HTTP_STATUS_UNAUTHORIZED; + + hostpath = http_get_hostpath(hc); + + http_xmltv_begin(&hc->hc_reply); + CHANNEL_FOREACH(ch) { + if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 0)) + continue; + http_xmltv_channel_add(&hc->hc_reply, hostpath, ch); + } + CHANNEL_FOREACH(ch) { + if (http_access_verify_channel(hc, ACCESS_STREAMING, ch, 0)) + continue; + http_xmltv_programme_add(&hc->hc_reply, hostpath, ch); + } + http_xmltv_end(&hc->hc_reply); + + free(hostpath); + return 0; +} + +/** + * Handle requests for XMLTV export. + */ +int +page_xmltv(http_connection_t *hc, const char *remain, void *opaque) +{ + char *components[2], *cmd; + int nc, r; + channel_t *ch = NULL; + channel_tag_t *tag = NULL; + + if (!remain || *remain == '\0') { + http_redirect(hc, "/xmltv/channels", &hc->hc_req_args, 0); + return HTTP_STATUS_FOUND; + } + + nc = http_tokenize((char *)remain, components, 2, '/'); + if (!nc) + return HTTP_STATUS_BAD_REQUEST; + + cmd = tvh_strdupa(components[0]); + + if (nc == 2) + http_deescape(components[1]); + + pthread_mutex_lock(&global_lock); + + if (nc == 2 && !strcmp(components[0], "channeluuid")) + ch = channel_find_by_uuid(components[1]); + else if (nc == 2 && !strcmp(components[0], "channelnumber")) + ch = channel_find_by_number(components[1]); + else if (nc == 2 && !strcmp(components[0], "channelname")) + ch = channel_find_by_name(components[1]); + else if (nc == 2 && !strcmp(components[0], "channel")) + ch = channel_find(components[1]); + else if (nc == 2 && !strcmp(components[0], "tagid")) + tag = channel_tag_find_by_identifier(atoi(components[1])); + else if (nc == 2 && !strcmp(components[0], "tag")) + tag = channel_tag_find_by_name(components[1], 0); + + if (ch) { + r = http_xmltv_channel(hc, ch); + } else if (tag) { + r = http_xmltv_tag(hc, tag); + } else { + if (!strcmp(cmd, "channels")) { + r = http_xmltv_channel_list(hc); + } else { + r = HTTP_STATUS_BAD_REQUEST; + } + } + + pthread_mutex_unlock(&global_lock); + + if (r == 0) + http_output_content(hc, "text/xml"); + + return r; +}