summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libwebvi/libwebvi.c4
-rw-r--r--src/libwebvi/libwebvi.h6
-rw-r--r--src/libwebvi/link.c2
-rw-r--r--src/libwebvi/link.h2
-rw-r--r--src/libwebvi/linktemplates.c9
-rw-r--r--src/libwebvi/menubuilder.c2
-rw-r--r--src/libwebvi/pipecomponent.c223
-rw-r--r--src/libwebvi/pipecomponent.h7
-rw-r--r--src/libwebvi/request.c28
-rw-r--r--src/libwebvi/webvicontext.c15
-rw-r--r--src/libwebvi/webvicontext.h3
-rwxr-xr-xsrc/menuscripts/stream-areena14
-rwxr-xr-xsrc/menuscripts/stream-quvi19
-rwxr-xr-xsrc/menuscripts/utils.sh15
-rw-r--r--src/pywebvi/pywebvi.py10
-rw-r--r--src/webvicli/webvicli/client.py22
16 files changed, 212 insertions, 169 deletions
diff --git a/src/libwebvi/libwebvi.c b/src/libwebvi/libwebvi.c
index feeec28..cd6df13 100644
--- a/src/libwebvi/libwebvi.c
+++ b/src/libwebvi/libwebvi.c
@@ -101,6 +101,10 @@ WebviResult webvi_set_config(WebviCtx ctxhandle, WebviConfig conf, ...) {
webvi_context_set_timeout_data(ctx, data);
break;
}
+ case WEBVI_CONFIG_MENU_SCRIPT_PATH:
+ p = va_arg(argptr, char *);
+ webvi_context_set_menu_script_path(ctx, p);
+ break;
default:
res = WEBVIERR_INVALID_PARAMETER;
};
diff --git a/src/libwebvi/libwebvi.h b/src/libwebvi/libwebvi.h
index 8efe953..74c9f6c 100644
--- a/src/libwebvi/libwebvi.h
+++ b/src/libwebvi/libwebvi.h
@@ -102,7 +102,8 @@ typedef enum {
WEBVI_CONFIG_TEMPLATE_PATH,
WEBVI_CONFIG_DEBUG,
WEBVI_CONFIG_TIMEOUT_CALLBACK,
- WEBVI_CONFIG_TIMEOUT_DATA
+ WEBVI_CONFIG_TIMEOUT_DATA,
+ WEBVI_CONFIG_MENU_SCRIPT_PATH
} WebviConfig;
typedef struct {
@@ -167,6 +168,9 @@ LIBWEBVI_DLL_EXPORT const char* webvi_strerror(WebviResult err);
* WEBVI_CONFIG_TEMPLATE_PATH
* Set the base directory for the XSLT templates (char *)
*
+ * WEBVI_CONFIG_MENU_SCRIPT_PATH
+ * Specify the directory where to look for the menu scripts (char *)
+ *
* WEBVI_CONFIG_DEBUG
* If value is not "0", print debug output to stdin (char *)
*
diff --git a/src/libwebvi/link.c b/src/libwebvi/link.c
index 501e70a..fbce59b 100644
--- a/src/libwebvi/link.c
+++ b/src/libwebvi/link.c
@@ -73,7 +73,7 @@ struct ActionTypeMessage {
const char *link_action_type_to_string(LinkActionType atype) {
static struct ActionTypeMessage messages[] =
{{LINK_ACTION_PARSE, "regular link"},
- {LINK_ACTION_STREAM_LIBQUVI, "stream"},
+ {LINK_ACTION_STREAM, "stream"},
{LINK_ACTION_EXTERNAL_COMMAND, "external command"}};
for (int i=0; i<(sizeof(messages)/sizeof(messages[0])); i++) {
diff --git a/src/libwebvi/link.h b/src/libwebvi/link.h
index 0ddc05c..9fac1f4 100644
--- a/src/libwebvi/link.h
+++ b/src/libwebvi/link.h
@@ -22,7 +22,7 @@
typedef enum {
LINK_ACTION_PARSE,
- LINK_ACTION_STREAM_LIBQUVI,
+ LINK_ACTION_STREAM,
LINK_ACTION_EXTERNAL_COMMAND
} LinkActionType;
diff --git a/src/libwebvi/linktemplates.c b/src/libwebvi/linktemplates.c
index a193df3..e7f76fd 100644
--- a/src/libwebvi/linktemplates.c
+++ b/src/libwebvi/linktemplates.c
@@ -126,15 +126,12 @@ LinkAction *parse_action(const gchar *actionstr) {
if (*actionstr == '\0') {
return link_action_create(LINK_ACTION_PARSE, NULL);
- } else if (strcmp(actionstr, STREAM_LIBQUVI_SELECTOR) == 0) {
- return link_action_create(LINK_ACTION_STREAM_LIBQUVI, NULL);
+ } else if (strncmp(actionstr, STREAM_SELECTOR, STREAM_SELECTOR_LEN) == 0) {
+ const gchar *command = actionstr + STREAM_SELECTOR_LEN;
+ return link_action_create(LINK_ACTION_STREAM, command);
} else if (strncmp(actionstr, EXT_CMD_SELECTOR, EXT_CMD_SELECTOR_LEN) == 0) {
const gchar *command = actionstr + EXT_CMD_SELECTOR_LEN;
return link_action_create(LINK_ACTION_EXTERNAL_COMMAND, command);
- } else if (strncmp(actionstr, STREAM_SELECTOR, STREAM_SELECTOR_LEN) == 0) {
- g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
- "Unknown streamer %s in link template file", actionstr);
- return NULL;
} else {
g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
"Invalid action %s in link template file", actionstr);
diff --git a/src/libwebvi/menubuilder.c b/src/libwebvi/menubuilder.c
index d2b54ce..bffbc1e 100644
--- a/src/libwebvi/menubuilder.c
+++ b/src/libwebvi/menubuilder.c
@@ -67,7 +67,7 @@ void add_link_to_menu(gpointer data, gpointer instance) {
void menu_builder_append_link(MenuBuilder *self, const Link *link) {
const char *class;
- if (link_get_type(link) == LINK_ACTION_STREAM_LIBQUVI) {
+ if (link_get_type(link) == LINK_ACTION_STREAM) {
class = "stream";
} else {
class = "webvi";
diff --git a/src/libwebvi/pipecomponent.c b/src/libwebvi/pipecomponent.c
index 34e7634..7390bf3 100644
--- a/src/libwebvi/pipecomponent.c
+++ b/src/libwebvi/pipecomponent.c
@@ -52,8 +52,11 @@ struct PipeMainMenuDownloader {
struct PipeExternalDownloader {
PipeComponent pipe_data;
+ gchar *command;
gchar *url;
- int fd;
+ gchar *menu_script_path;
+ GPid pid;
+ gint fd;
};
struct PipeLocalFile {
@@ -62,11 +65,8 @@ struct PipeLocalFile {
int fd;
};
-struct PipeLibquvi {
+struct PipeMenuValidator {
PipeComponent pipe_data;
- gchar *url;
- GPid pid;
- gint quvi_output;
xmlParserCtxtPtr parser;
};
@@ -108,15 +108,9 @@ static gboolean pipe_external_downloader_handle_socket(
PipeComponent *instance, int fd, int bitmask);
static void pipe_external_downloader_delete(PipeComponent *instance);
-static void pipe_libquvi_fdset(PipeComponent *instance, fd_set *readfd,
- fd_set *writefd, fd_set *excfd, int *maxfd);
-static gboolean pipe_libquvi_handle_socket(PipeComponent *instance,
- int fd, int bitmask);
-static gboolean pipe_libquvi_parse(PipeComponent *instance, char *buf, size_t len);
-static void pipe_libquvi_finished(PipeComponent *instance, RequestState state);
-static xmlChar *quvi_xml_get_stream_url(xmlDoc *doc);
-static xmlChar *quvi_xml_get_stream_title(xmlDoc *doc);
-static void pipe_libquvi_delete(PipeComponent *instance);
+static gboolean pipe_menu_validator_parse(PipeComponent *instance, char *buf, size_t len);
+static void pipe_menu_validator_validate(PipeComponent *instance, RequestState state);
+static void pipe_menu_validator_delete(PipeComponent *instance);
static CURL *start_curl(const char *url, CURLM *curlmulti,
PipeComponent *instance);
@@ -173,7 +167,7 @@ void pipe_component_finished(PipeComponent *self, RequestState state) {
if (self->finished)
self->finished(self, state);
if (self->next)
- pipe_component_finished(self->next, state);
+ pipe_component_finished(self->next, self->state);
}
}
@@ -470,14 +464,16 @@ void pipe_local_file_delete(PipeComponent *instance) {
/***** PipeExternalDownloader *****/
-PipeExternalDownloader *pipe_external_downloader_create(const gchar *url,
- const gchar *command)
+PipeExternalDownloader *pipe_external_downloader_create(
+ const gchar *url, const gchar *command, const gchar *menu_script_path)
{
INITIALIZE_PIPE_WITH_FDSET(PipeExternalDownloader, NULL, NULL,
pipe_external_downloader_delete,
pipe_external_downloader_fdset,
pipe_external_downloader_handle_socket);
+ self->command = g_strdup(command);
self->url = g_strdup(url);
+ self->menu_script_path = g_strdup(menu_script_path);
self->fd = -1;
g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
@@ -487,8 +483,21 @@ PipeExternalDownloader *pipe_external_downloader_create(const gchar *url,
}
void pipe_external_downloader_start(PipeExternalDownloader *self) {
- // FIXME
- pipe_component_finished((PipeComponent *)self, WEBVISTATE_INTERNAL_ERROR);
+ GError *error = NULL;
+ gchar *argv[] = {self->command, self->url, NULL};
+ /* gchar *envpath = g_strconcat("PATH=", LIBWEBVI_SCRIPT_PATH, */
+ /* ":/usr/bin:/bin:/usr/local/bin", NULL); */
+ /* gchar *envp[] = {envpath, NULL}; */
+ g_spawn_async_with_pipes(self->menu_script_path, argv, NULL, 0,
+ NULL, NULL, &self->pid, NULL, &self->fd,
+ NULL, &error);
+ if (error) {
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_INFO,
+ "Executing '%s %s' failed: %s", self->command, self->url,
+ error->message);
+ pipe_component_finished((PipeComponent *)self, WEBVISTATE_SUBPROCESS_FAILED);
+ }
+ /* g_free(envpath); */
}
void pipe_external_downloader_fdset(PipeComponent *instance, fd_set *readfd,
@@ -507,164 +516,102 @@ gboolean pipe_external_downloader_handle_socket(PipeComponent *instance,
void pipe_external_downloader_delete(PipeComponent *instance) {
PipeExternalDownloader *self = (PipeExternalDownloader *)instance;
- if (self->fd != -1)
+ if (self->fd != -1) {
close(self->fd);
+ }
+ if (self->pid != -1) {
+ g_spawn_close_pid(self->pid);
+ }
g_free(self->url);
- g_free(self);
+ g_free(self->command);
+ g_free(self->menu_script_path);
+ free(self);
}
-/***** PipeLibquvi *****/
+/***** PipeMenuValidator *****/
-PipeLibquvi *pipe_libquvi_create(const gchar *url) {
- INITIALIZE_PIPE_WITH_FDSET(PipeLibquvi,
- pipe_libquvi_parse,
- pipe_libquvi_finished,
- pipe_libquvi_delete,
- pipe_libquvi_fdset,
- pipe_libquvi_handle_socket);
- self->url = g_strdup(url);
- self->pid = -1;
- self->quvi_output = -1;
+PipeMenuValidator *pipe_menu_validator_create() {
+ INITIALIZE_PIPE(PipeMenuValidator, pipe_menu_validator_parse,
+ pipe_menu_validator_validate,
+ pipe_menu_validator_delete);
return self;
}
-void pipe_libquvi_start(PipeLibquvi *self) {
- GError *error = NULL;
- gchar *argv[] = {"quvi", "--xml", self->url};
-
- g_spawn_async_with_pipes(NULL, argv, NULL,
- G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL,
- NULL, NULL, &self->pid, NULL, &self->quvi_output,
- NULL, &error);
- if (error) {
- g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
- "Calling quvi failed: %s", error->message);
- pipe_component_finished((PipeComponent *)self, WEBVISTATE_SUBPROCESS_FAILED);
- }
-}
-
-void pipe_libquvi_fdset(PipeComponent *instance, fd_set *readfd,
- fd_set *writefd, fd_set *excfd, int *maxfd)
-{
- PipeLibquvi *self = (PipeLibquvi *)instance;
- append_to_fdset(self->quvi_output, readfd, maxfd);
-}
-
-gboolean pipe_libquvi_handle_socket(PipeComponent *instance,
- int fd, int bitmask)
-{
- PipeLibquvi *self = (PipeLibquvi *)instance;
- return read_from_fd_to_pipe(instance, &self->quvi_output, fd, bitmask);
-}
-
-gboolean pipe_libquvi_parse(PipeComponent *instance, char *buf, size_t len) {
- PipeLibquvi *self = (PipeLibquvi *)instance;
+gboolean pipe_menu_validator_parse(PipeComponent *instance, char *buf, size_t len) {
+ PipeMenuValidator *self = (PipeMenuValidator *)instance;
if (!self->parser) {
- self->parser = xmlCreatePushParserCtxt(NULL, NULL, buf, len, "quvioutput.xml");
- g_assert(self->parser);
+ self->parser = xmlCreatePushParserCtxt(NULL, NULL, buf, len,
+ "externalscript.xml");
+ if (!self->parser) {
+ pipe_component_finished(instance, WEBVISTATE_MEMORY_ALLOCATION_ERROR);
+ }
} else {
- xmlParseChunk(self->parser, buf, len, 0);
+ int err = xmlParseChunk(self->parser, buf, len, 0);
+ if (err) {
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_INFO,
+ "Menu is not valid XML (libxml2 error %d)", err);
+ pipe_component_finished(instance, WEBVISTATE_SUBPROCESS_FAILED);
+ return FALSE;
+ }
}
-
- return FALSE;
+ return TRUE;
}
-void pipe_libquvi_finished(PipeComponent *instance, RequestState state) {
+void pipe_menu_validator_validate(PipeComponent *instance, RequestState state) {
+ PipeMenuValidator *self = (PipeMenuValidator *)instance;
if (state != WEBVISTATE_FINISHED_OK) {
- pipe_component_finished(instance, state);
return;
}
- PipeLibquvi *self = (PipeLibquvi *)instance;
if (!self->parser) {
- g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "No output from quvi!");
- pipe_component_finished(instance, WEBVISTATE_SUBPROCESS_FAILED);
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "no menu to validate");
+ return;
+ }
+
+ int err = xmlParseChunk(self->parser, NULL, 0, 1);
+ if (err) {
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_INFO,
+ "Menu is not valid XML (xmlParserErrors %d)", err);
+ instance->state = WEBVISTATE_SUBPROCESS_FAILED;
return;
}
- xmlParseChunk(self->parser, NULL, 0, 1);
xmlDoc *doc = self->parser->myDoc;
+ if (!doc) {
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_INFO,
+ "XML parser returned no document");
+ instance->state = WEBVISTATE_SUBPROCESS_FAILED;
+ return;
+ }
xmlChar *dump;
int dumpLen;
xmlDocDumpMemory(doc, &dump, &dumpLen);
- g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "quvi output:\n%s", dump);
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "validating menu:\n%s", dump);
xmlFree(dump);
dump = NULL;
- xmlChar *encoded_url = quvi_xml_get_stream_url(doc);
- if (!encoded_url) {
- g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_WARNING, "No url in quvi output!");
- pipe_component_finished(instance, WEBVISTATE_SUBPROCESS_FAILED);
- return;
- }
-
- /* URLs in quvi XML output are encoded by curl_easy_escape */
- char *url = curl_unescape((char *)encoded_url, strlen((char *)encoded_url));
- xmlChar *title = quvi_xml_get_stream_title(doc);
-
- MenuBuilder *menu_builder = menu_builder_create();
- menu_builder_set_title(menu_builder, (char *)title);
- menu_builder_append_link_plain(menu_builder, url, (char *)title, NULL);
- char *menu = menu_builder_to_string(menu_builder);
- if (self->pipe_data.next) {
- pipe_component_append(self->pipe_data.next, menu, strlen(menu));
- pipe_component_finished(self->pipe_data.next, state);
- }
-
- free(menu);
- menu_builder_delete(menu_builder);
- xmlFree(title);
- curl_free(url);
- xmlFree(encoded_url);
-}
-
-xmlChar *quvi_xml_get_stream_url(xmlDoc *doc) {
xmlNode *root = xmlDocGetRootElement(doc);
- xmlNode *node = root->children;
- while (node) {
- if (xmlStrEqual(node->name, BAD_CAST "link")) {
- xmlNode *link_child = node->children;
- while (link_child) {
- if (xmlStrEqual(link_child->name, BAD_CAST "url")) {
- return xmlNodeGetContent(link_child);
- }
- link_child = link_child->next;
- }
- }
- node = node->next;
- }
-
- return NULL;
-}
-
-xmlChar *quvi_xml_get_stream_title(xmlDoc *doc) {
- xmlNode *root = xmlDocGetRootElement(doc);
- xmlNode *node = root->children;
- while (node) {
- if (xmlStrEqual(node->name, BAD_CAST "page_title")) {
- return xmlNodeGetContent(node);
- }
- node = node->next;
+ if (!xmlStrEqual(root->name, BAD_CAST "wvmenu")) {
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_INFO,
+ "Unexpected root node: %s", (char *)root->name);
+ instance->state = WEBVISTATE_SUBPROCESS_FAILED;
+ return;
}
- return NULL;
+ g_log(LIBWEBVI_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Menu is valid");
}
-void pipe_libquvi_delete(PipeComponent *instance) {
- PipeLibquvi *self = (PipeLibquvi *)instance;
- if (self->quvi_output != -1) {
- close(self->quvi_output);
- }
- if (self->pid != -1) {
- g_spawn_close_pid(self->pid);
- }
+void pipe_menu_validator_delete(PipeComponent *instance) {
+ PipeMenuValidator *self = (PipeMenuValidator *)instance;
if (self->parser) {
+ if (self->parser->myDoc) {
+ xmlFreeDoc(self->parser->myDoc);
+ }
xmlFreeParserCtxt(self->parser);
}
- g_free(self->url);
free(self);
}
diff --git a/src/libwebvi/pipecomponent.h b/src/libwebvi/pipecomponent.h
index 00a05ef..451cc96 100644
--- a/src/libwebvi/pipecomponent.h
+++ b/src/libwebvi/pipecomponent.h
@@ -47,6 +47,7 @@ typedef struct PipeMainMenuDownloader PipeMainMenuDownloader;
typedef struct PipeLocalFile PipeLocalFile;
typedef struct PipeExternalDownloader PipeExternalDownloader;
typedef struct PipeLibquvi PipeLibquvi;
+typedef struct PipeMenuValidator PipeMenuValidator;
void pipe_component_initialize(PipeComponent *self,
gboolean (*process_cb)(PipeComponent *, char *, size_t),
@@ -85,11 +86,13 @@ PipeCallbackWrapper *pipe_callback_wrapper_create(
void (*finish_callback)(RequestState, void *),
void *finishdata);
-PipeExternalDownloader *pipe_external_downloader_create(const gchar *url,
- const gchar *command);
+PipeExternalDownloader *pipe_external_downloader_create(
+ const gchar *url, const gchar *command, const gchar *menu_script_path);
void pipe_external_downloader_start(PipeExternalDownloader *self);
PipeLibquvi *pipe_libquvi_create(const gchar *url);
void pipe_libquvi_start(PipeLibquvi *self);
+PipeMenuValidator *pipe_menu_validator_create();
+
#endif // __PIPECOMPONENT_H
diff --git a/src/libwebvi/request.c b/src/libwebvi/request.c
index af078c4..fc2b635 100644
--- a/src/libwebvi/request.c
+++ b/src/libwebvi/request.c
@@ -28,7 +28,6 @@ static PipeComponent *build_and_start_mainmenu_pipe(const WebviRequest *self);
static PipeComponent *build_and_start_local_pipe(const WebviRequest *self);
static PipeComponent *build_and_start_external_pipe(const WebviRequest *self,
const char *command);
-static PipeComponent *build_and_start_libquvi_pipe(const WebviRequest *self);
static PipeComponent *build_and_start_menu_pipe(const WebviRequest *self);
WebviRequest *request_create(const char *url, struct WebviContext *ctx) {
@@ -73,9 +72,8 @@ PipeComponent *pipe_factory(const WebviRequest *self) {
const LinkAction *action = link_templates_get_action(
get_link_templates(self->ctx), self->url);
LinkActionType action_type = action ? link_action_get_type(action) : LINK_ACTION_PARSE;
- if (action_type == LINK_ACTION_STREAM_LIBQUVI) {
- head = build_and_start_libquvi_pipe(self);
- } else if (action_type == LINK_ACTION_EXTERNAL_COMMAND) {
+ if ((action_type == LINK_ACTION_STREAM) ||
+ (action_type == LINK_ACTION_EXTERNAL_COMMAND)) {
const char *command = link_action_get_command(action);
head = build_and_start_external_pipe(self, command);
} else {
@@ -108,26 +106,22 @@ PipeComponent *build_and_start_local_pipe(const WebviRequest *self) {
return (PipeComponent *)p1;
}
-PipeComponent *build_and_start_external_pipe(const WebviRequest *self, const char *command) {
- PipeExternalDownloader *p1 = pipe_external_downloader_create(self->url, command);
- PipeComponent *p2 = (PipeComponent *)pipe_callback_wrapper_create(
+PipeComponent *build_and_start_external_pipe(const WebviRequest *self,
+ const char *command)
+{
+ const char *path = webvi_context_get_menu_script_path(self->ctx);
+ PipeExternalDownloader *p1 = pipe_external_downloader_create(
+ self->url, command, path);
+ PipeComponent *p2 = (PipeComponent *)pipe_menu_validator_create();
+ PipeComponent *p3 = (PipeComponent *)pipe_callback_wrapper_create(
self->read_cb, self->readdata, notify_pipe_finished, (void *)self);
pipe_component_set_next((PipeComponent *)p1, p2);
+ pipe_component_set_next((PipeComponent *)p2, p3);
pipe_external_downloader_start(p1);
return (PipeComponent *)p1;
}
-PipeComponent *build_and_start_libquvi_pipe(const WebviRequest *self) {
- PipeLibquvi *p1 = pipe_libquvi_create(self->url);
- PipeComponent *p2 = (PipeComponent *)pipe_callback_wrapper_create(
- self->read_cb, self->readdata, notify_pipe_finished, (void *)self);
- pipe_component_set_next((PipeComponent *)p1, p2);
- pipe_libquvi_start(p1);
-
- return (PipeComponent *)p1;
-}
-
PipeComponent *build_and_start_menu_pipe(const WebviRequest *self) {
CURLM *curlmulti = webvi_context_get_curl_multi_handle(self->ctx);
PipeDownloader *p1 = pipe_downloader_create(self->url, curlmulti);
diff --git a/src/libwebvi/webvicontext.c b/src/libwebvi/webvicontext.c
index 16cba10..c6c43a4 100644
--- a/src/libwebvi/webvicontext.c
+++ b/src/libwebvi/webvicontext.c
@@ -6,6 +6,7 @@
#include "request.h"
#define DEFAULT_TEMPLATE_PATH "/etc/webvi/websites"
+#define DEFAULT_MENU_SCRIPT_PATH "/usr/local/bin/webvi/menuscripts"
#define MAX_MESSAGE_LENGTH 128
struct WebviContext {
@@ -14,6 +15,7 @@ struct WebviContext {
WebviHandle next_request;
CURLM *curl_multi_handle;
gchar *template_path;
+ gchar *menu_script_path;
webvi_timeout_callback timeout_callback;
void *timeout_data;
GArray *finish_messages;
@@ -128,13 +130,24 @@ void webvi_context_set_template_path(WebviContext *self, const char *path) {
if (self->template_path) {
g_free(self->template_path);
}
- self->template_path = path ? g_strdup(path) : NULL;
+ self->template_path = g_strdup(path);
}
const char *webvi_context_get_template_path(const WebviContext *self) {
return self->template_path ? self->template_path : DEFAULT_TEMPLATE_PATH;
}
+void webvi_context_set_menu_script_path(WebviContext *self, const char *path) {
+ if (self->menu_script_path) {
+ g_free(self->menu_script_path);
+ }
+ self->menu_script_path = g_strdup(path);
+}
+
+const char *webvi_context_get_menu_script_path(const WebviContext *self) {
+ return self->menu_script_path ? self->menu_script_path : DEFAULT_MENU_SCRIPT_PATH;
+}
+
const LinkTemplates *get_link_templates(WebviContext *self) {
if (!self->link_templates) {
self->link_templates = link_templates_create();
diff --git a/src/libwebvi/webvicontext.h b/src/libwebvi/webvicontext.h
index b3beb0e..210d940 100644
--- a/src/libwebvi/webvicontext.h
+++ b/src/libwebvi/webvicontext.h
@@ -41,6 +41,9 @@ void webvi_context_set_debug(WebviContext *self,
void webvi_context_set_template_path(WebviContext *self,
const char *path);
const char *webvi_context_get_template_path(const WebviContext *self);
+void webvi_context_set_menu_script_path(WebviContext *self,
+ const char *path);
+const char *webvi_context_get_menu_script_path(const WebviContext *self);
const LinkTemplates *get_link_templates(WebviContext *self);
CURLM *webvi_context_get_curl_multi_handle(WebviContext *self);
void webvi_context_set_timeout_callback(WebviContext *ctx,
diff --git a/src/menuscripts/stream-areena b/src/menuscripts/stream-areena
new file mode 100755
index 0000000..7b0c41f
--- /dev/null
+++ b/src/menuscripts/stream-areena
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+
+. utils.sh
+
+if [ "x$1" = "x" ]; then
+ exit 1
+fi
+
+STREAMURL=$(yle-dl --showurl "$1")
+STREAMTITLE=$(yle-dl --showtitle "$1")
+
+outputWebviMenu "$STREAMURL" "$STREAMTITLE"
diff --git a/src/menuscripts/stream-quvi b/src/menuscripts/stream-quvi
new file mode 100755
index 0000000..b1d7662
--- /dev/null
+++ b/src/menuscripts/stream-quvi
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+. utils.sh
+
+if [ "x$1" = "x" ]; then
+ exit 1
+fi
+
+Q=$(quvi "$1")
+if [ "x$Q" = "x" ]; then
+ exit 1
+fi
+
+STREAMURL=$(echo "$Q" | sed -n 's/.*"url": "\(.*\)".*/\1/p' | head -n1)
+STREAMTITLE=$(echo "$Q" | sed -n 's/.*"page_title": "\(.*\)".*/\1/p' | head -n1)
+
+outputWebviMenu "$STREAMURL" "$STREAMTITLE"
diff --git a/src/menuscripts/utils.sh b/src/menuscripts/utils.sh
new file mode 100755
index 0000000..0be2324
--- /dev/null
+++ b/src/menuscripts/utils.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+function XMLEscape() {
+ echo "$1" | sed "s/\&/\&amp;/g;s/>/\&gt;/g;s/</\&lt;/g;s/'/\&apos;/g"
+}
+
+function outputWebviMenu() {
+ local url=$(XMLEscape "$1")
+ local title=$(XMLEscape "$2")
+ echo '<?xml version="1.0" encoding="UTF-8"?>'
+ echo -n '<wvmenu><title>'"$title"'</title>'
+ echo -n '<ul><li>'
+ echo -n '<a href="'"$url"'">'"$title"'</a>'
+ echo '</li></ul></wvmenu>'
+}
diff --git a/src/pywebvi/pywebvi.py b/src/pywebvi/pywebvi.py
index b3df416..3815d0f 100644
--- a/src/pywebvi/pywebvi.py
+++ b/src/pywebvi/pywebvi.py
@@ -20,6 +20,7 @@ _WEBVI_CONFIG_TEMPLATE_PATH = 0
_WEBVI_CONFIG_DEBUG = 1
_WEBVI_CONFIG_TIMEOUT_CALLBACK = 2
_WEBVI_CONFIG_TIMEOUT_DATA = 3
+_WEBVI_CONFIG_MENU_SCRIPT_PATH = 4
class WebviState:
NOT_FINISHED = 0
@@ -107,6 +108,15 @@ class WebviContext:
set_config.restype = raise_if_webvi_result_not_ok
set_config(self.handle, _WEBVI_CONFIG_TEMPLATE_PATH, path)
+ def set_menu_script_path(self, path):
+ if self.handle is None:
+ return
+
+ set_config = libwebvi.webvi_set_config
+ set_config.argtypes = [c_long, c_int, c_char_p]
+ set_config.restype = raise_if_webvi_result_not_ok
+ set_config(self.handle, _WEBVI_CONFIG_MENU_SCRIPT_PATH, path)
+
def set_debug(self, enabled):
if self.handle is None:
return
diff --git a/src/webvicli/webvicli/client.py b/src/webvicli/webvicli/client.py
index 0af470d..9247fa1 100644
--- a/src/webvicli/webvicli/client.py
+++ b/src/webvicli/webvicli/client.py
@@ -106,6 +106,11 @@ def next_available_file_name(basename, ext):
i += 1
return '%s-%d%s' % (basename, i, ext)
+def is_rtmp_url(url):
+ RTMP_SCHEMES = ['rtmp://', 'rtmpe://', 'rtmps://',
+ 'rtmpt://', 'rtmpte://', 'rtmpts://']
+ return any(url.startswith(x) for x in RTMP_SCHEMES)
+
class WebviURLopener(urllib.FancyURLopener):
version = WEBVI_STREAM_USER_AGENT
@@ -242,7 +247,10 @@ class WVClient:
def set_template_path(self, path):
self.webvi.set_template_path(path)
-
+
+ def set_menu_script_path(self, path):
+ self.webvi.set_menu_script_path(path)
+
def update_timeout(self, timeout_ms):
if timeout_ms < 0:
self.alarm = None
@@ -429,6 +437,10 @@ class WVClient:
return (menu[0].activate(), menu[0].label)
def download_stream(self, url, title):
+ if is_rtmp_url(url):
+ print 'FIXME: downloading RTMP stream'
+ return
+
try:
(tmpfilename, headers) = \
urllib.urlretrieve(url, reporthook=dl_progress)
@@ -757,6 +769,10 @@ def parse_command_line(cmdlineargs, options):
dest='templatepath',
help='read video site templates from DIR', metavar='DIR',
default=None)
+ parser.add_option('-m', '--menuscriptpath', type='string',
+ dest='menuscriptpath',
+ help='read menu scripts from DIR', metavar='DIR',
+ default=None)
parser.add_option('-v', '--verbose', action='store_const', const=1,
dest='verbose', help='debug output', default=0)
parser.add_option('--vfat', action='store_true',
@@ -770,6 +786,8 @@ def parse_command_line(cmdlineargs, options):
if cmdlineopt.templatepath is not None:
options['templatepath'] = cmdlineopt.templatepath
+ if cmdlineopt.menuscriptpath is not None:
+ options['menuscriptpath'] = cmdlineopt.menuscriptpath
if cmdlineopt.verbose > 0:
options['verbose'] = cmdlineopt.verbose
if cmdlineopt.vfat:
@@ -815,6 +833,8 @@ def main(argv):
client.set_debug(options['verbose'])
if options.has_key('templatepath'):
client.set_template_path(options['templatepath'])
+ if options.has_key('menuscriptpath'):
+ client.set_menu_script_path(options['menuscriptpath'])
if options.has_key('url'):
stream = options['url']