Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
http server: add initial version of XMLTV exporter
  • Loading branch information
perexg committed Oct 28, 2015
1 parent 240f73a commit 251fc2c
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 15 deletions.
1 change: 1 addition & 0 deletions Makefile
Expand Up @@ -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 \
Expand Down
19 changes: 19 additions & 0 deletions src/http.c
Expand Up @@ -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);
}

/**
*
*/
Expand Down
2 changes: 2 additions & 0 deletions src/http.h
Expand Up @@ -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
*/
Expand Down
17 changes: 2 additions & 15 deletions 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
Expand Down Expand Up @@ -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);
}

/*
*
*/
Expand Down Expand Up @@ -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);

Expand Down
1 change: 1 addition & 0 deletions src/webui/webui.h
Expand Up @@ -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);
Expand Down
253 changes: 253 additions & 0 deletions 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 <http://www.gnu.org/licenses/>.
*/

#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, "\
<?xml version=\"1.0\" ?>\n\
<!DOCTYPE tv SYSTEM \"xmltv.dtd\">\n\
<tv generator-info-name=\"TVHeadend-%s\" source-info-name=\"tvh-%s\">\n\
", tvheadend_version, config.server_name);
}

/*
*
*/
static void
http_xmltv_end(htsbuf_queue_t *hq)
{
htsbuf_qprintf(hq, "</tv>\n");
}

/*
*
*/
static void
http_xmltv_channel_add(htsbuf_queue_t *hq, const char *hostpath, channel_t *ch)
{
htsbuf_qprintf(hq, "<channel id=\"%s\">\n <display-name>%s</display-name>\n</channel>\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, "<programe start=\"%s\" stop=\"%s\" channel=\"%s\">\n",
start, stop, idnode_uuid_as_sstr(&ch->ch_id));
RB_FOREACH(lse, e->title, link)
htsbuf_qprintf(hq, " <title lang=\"%s\">%s</title>\n", lse->lang, lse->str);
if (e->subtitle)
RB_FOREACH(lse, e->subtitle, link)
htsbuf_qprintf(hq, " <sub-title lang=\"%s\">%s</sub-title>\n", lse->lang, lse->str);
if (ebc->description)
RB_FOREACH(lse, ebc->description, link)
htsbuf_qprintf(hq, " <desc lang=\"%s\">%s</desc>\n", lse->lang, lse->str);
htsbuf_qprintf(hq, "</programe>\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;
}

0 comments on commit 251fc2c

Please sign in to comment.