diff --git a/src/main.c b/src/main.c
index caa22411..3c9756ce 100644
--- a/src/main.c
+++ b/src/main.c
@@ -469,7 +469,8 @@ main(int argc, char **argv)
opt_threadid = 0,
opt_ipv6 = 0,
opt_tsfile_tuner = 0,
- opt_dump = 0;
+ opt_dump = 0,
+ opt_xspf = 0;
const char *opt_config = NULL,
*opt_user = NULL,
*opt_group = NULL,
@@ -523,6 +524,8 @@ main(int argc, char **argv)
OPT_INT, &tvheadend_htsp_port_extra },
{ 0, "useragent", "Specify User-Agent header for the http client",
OPT_STR, &opt_user_agent },
+ { 0, "xspf", "Use xspf playlist instead M3U",
+ OPT_BOOL, &opt_xspf },
{ 0, NULL, "Debug Options", OPT_BOOL, NULL },
{ 'd', "stderr", "Enable debug on stderr", OPT_BOOL, &opt_stderr },
@@ -798,7 +801,7 @@ main(int argc, char **argv)
tcp_server_init(opt_ipv6);
http_server_init(opt_bindaddr);
- webui_init();
+ webui_init(opt_xspf);
#if ENABLE_UPNP
upnp_server_init(opt_bindaddr);
#endif
diff --git a/src/webui/static/app/chconf.js b/src/webui/static/app/chconf.js
index deb0e9b4..04d6a087 100644
--- a/src/webui/static/app/chconf.js
+++ b/src/webui/static/app/chconf.js
@@ -211,7 +211,7 @@ tvheadend.channel_tab = function(panel)
width: 50,
header: 'Play',
renderer: function(v, o, r) {
- return "Play";
+ return "Play";
}
}
],
diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js
index 6a68c755..56d46924 100644
--- a/src/webui/static/app/dvr.js
+++ b/src/webui/static/app/dvr.js
@@ -218,7 +218,7 @@ tvheadend.dvrschedule = function(title, iconCls, dvrStore) {
width: 40,
header: "Play",
renderer: function(v, o, r) {
- return "Play";
+ return 'Play';
}
});
cols.push({
diff --git a/src/webui/static/app/epg.js b/src/webui/static/app/epg.js
index 787139f5..896feb6b 100644
--- a/src/webui/static/app/epg.js
+++ b/src/webui/static/app/epg.js
@@ -61,7 +61,7 @@ tvheadend.epgDetails = function(event) {
now = new Date();
if (event.start < now && event.end > now)
- content += '
';
+ content += '';
var confcombo = new Ext.form.ComboBox({
store: tvheadend.configNames,
diff --git a/src/webui/static/app/mpegts.js b/src/webui/static/app/mpegts.js
index 9df11143..4f72b01e 100644
--- a/src/webui/static/app/mpegts.js
+++ b/src/webui/static/app/mpegts.js
@@ -84,7 +84,7 @@ tvheadend.muxes = function(panel)
width: 50,
header: 'Play',
renderer: function(v, o, r) {
- return "Play";
+ return "Play";
}
}
],
@@ -239,7 +239,7 @@ tvheadend.services = function(panel)
width: 50,
header: 'Play',
renderer: function(v, o, r) {
- return "Play";
+ return "Play";
}
},
actions
diff --git a/src/webui/webui.c b/src/webui/webui.c
index 7929ad29..069bb05b 100644
--- a/src/webui/webui.c
+++ b/src/webui/webui.c
@@ -55,6 +55,8 @@
#include
#endif
+static int webui_xspf;
+
/**
*
*/
@@ -914,6 +916,91 @@ http_stream(http_connection_t *hc, const char *remain, void *opaque)
}
}
+/**
+ * Generate a xspf playlist
+ * http://en.wikipedia.org/wiki/XML_Shareable_Playlist_Format
+ */
+static int
+page_xspf(http_connection_t *hc, const char *remain, void *opaque)
+{
+ size_t maxlen;
+ char *buf;
+ const char *host = http_arg_get(&hc->hc_args, "Host");
+ const char *title;
+ size_t len;
+
+ if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
+ title = "TVHeadend Stream";
+
+ maxlen = strlen(remain) + strlen(title) + 256;
+ buf = alloca(maxlen);
+
+ snprintf(buf, maxlen, "\
+\r\n\
+\r\n\
+ \r\n\
+ \r\n\
+ \r\n\
+\r\n", title, host, remain);
+
+ len = strlen(buf);
+ http_send_header(hc, 200, "application/xspf+xml", len, 0, NULL, 10, 0, NULL);
+ tvh_write(hc->hc_fd, buf, len);
+
+ return 0;
+}
+
+/**
+ * Generate an M3U playlist
+ * http://en.wikipedia.org/wiki/M3U
+ */
+static int
+page_m3u(http_connection_t *hc, const char *remain, void *opaque)
+{
+ size_t maxlen;
+ char *buf;
+ const char *host = http_arg_get(&hc->hc_args, "Host");
+ const char *title;
+ size_t len;
+
+ if ((title = http_arg_get(&hc->hc_req_args, "title")) == NULL)
+ title = "TVHeadend Stream";
+
+ maxlen = strlen(remain) + strlen(title) + 256;
+ buf = alloca(maxlen);
+
+ snprintf(buf, maxlen, "\
+#EXTM3U\r\n\
+#EXTINF:-1,%s\r\n\
+http://%s/%s\r\n", title, host, remain);
+
+ len = strlen(buf);
+ http_send_header(hc, 200, "audio/x-mpegurl", len, 0, NULL, 10, 0, NULL);
+ tvh_write(hc->hc_fd, buf, len);
+
+ return 0;
+}
+
+static int
+page_play(http_connection_t *hc, const char *remain, void *opaque)
+{
+ char *playlist;
+
+ playlist = http_arg_get(&hc->hc_req_args, "playlist");
+ if (playlist) {
+ if (strcmp(playlist, "xspf") == 0)
+ return page_xspf(hc, remain, opaque);
+ if (strcmp(playlist, "m3u") == 0)
+ return page_m3u(hc, remain, opaque);
+ }
+ if (webui_xspf)
+ return page_xspf(hc, remain, opaque);
+ return page_m3u(hc, remain, opaque);
+}
+
/**
* Download a recorded file
*/
@@ -1107,14 +1194,17 @@ int page_statedump(http_connection_t *hc, const char *remain, void *opaque);
* WEB user interface
*/
void
-webui_init(void)
+webui_init(int xspf)
{
+ webui_xspf = xspf;
+
if (tvheadend_webui_debug)
tvhlog(LOG_INFO, "webui", "Running web interface in debug mode");
http_path_add("", NULL, page_root2, ACCESS_WEB_INTERFACE);
http_path_add("/", NULL, page_root, ACCESS_WEB_INTERFACE);
+ http_path_add("/play", NULL, page_play, ACCESS_WEB_INTERFACE);
http_path_add("/dvrfile", NULL, page_dvrfile, ACCESS_WEB_INTERFACE);
http_path_add("/favicon.ico", NULL, favicon, ACCESS_WEB_INTERFACE);
http_path_add("/playlist", NULL, page_http_playlist, ACCESS_WEB_INTERFACE);
diff --git a/src/webui/webui.h b/src/webui/webui.h
index 2a2e3e5c..a1bee1cd 100644
--- a/src/webui/webui.h
+++ b/src/webui/webui.h
@@ -23,7 +23,7 @@
#include "idnode.h"
#include "http.h"
-void webui_init(void);
+void webui_init(int xspf);
void webui_done(void);
void simpleui_start(void);