summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntti Ajanki <antti.ajanki@iki.fi>2011-07-06 17:04:33 +0300
committerAntti Ajanki <antti.ajanki@iki.fi>2011-07-06 17:04:33 +0300
commitbd88072b5df85c392917e4bce11a40c0058c4657 (patch)
treec822a94e501a1f6fecf6d0742b772771f2b34441
parent195fcc2ea284489240d58a72859f0963ad82e27a (diff)
downloadvdr-plugin-webvideo-bd88072b5df85c392917e4bce11a40c0058c4657.tar.gz
vdr-plugin-webvideo-bd88072b5df85c392917e4bce11a40c0058c4657.tar.bz2
Properly implement timeout callback (bug #619), bump SONAME because of API changes
-rw-r--r--debian/control6
-rw-r--r--debian/libwebvi0.install1
-rw-r--r--debian/libwebvi1.docs (renamed from debian/libwebvi0.docs)0
-rw-r--r--debian/libwebvi1.install1
-rw-r--r--src/libwebvi/Makefile4
-rw-r--r--src/libwebvi/libwebvi.c53
-rw-r--r--src/libwebvi/libwebvi.h38
-rw-r--r--src/libwebvi/webvi/api.py66
-rw-r--r--src/libwebvi/webvi/asyncurl.py34
-rw-r--r--src/libwebvi/webvi/constants.py7
-rw-r--r--src/libwebvi/webvi/request.py6
-rw-r--r--src/vdr-plugin/download.c60
-rw-r--r--src/vdr-plugin/download.h4
-rw-r--r--src/webvicli/webvicli/client.py34
14 files changed, 240 insertions, 74 deletions
diff --git a/debian/control b/debian/control
index f24d954..728b215 100644
--- a/debian/control
+++ b/debian/control
@@ -20,7 +20,7 @@ Description: Web video downloader library - Python module
This is the Python module.
XB-Python-Version: ${python:Versions}
-Package: libwebvi0
+Package: libwebvi1
Architecture: any
Section: libs
Depends: ${shlibs:Depends}, ${misc:Depends}, python, python-webvi
@@ -34,7 +34,7 @@ XB-Python-Version: ${python:Versions}
Package: libwebvi-dev
Architecture: any
Section: libdevel
-Depends: ${misc:Depends}, libc-dev
+Depends: ${misc:Depends}, libc-dev, python-dev
Description: Web video downloader library - development files
This package provides a library for downloading video and audio
streams from media sharing websites, such as YouTube or Google Video.
@@ -44,7 +44,7 @@ Description: Web video downloader library - development files
Package: vdr-plugin-webvideo
Architecture: any
Section: video
-Depends: ${shlibs:Depends}, ${misc:Depends}, ${vdr:Depends}, libwebvi0
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${vdr:Depends}, libwebvi1
Suggests: vdr-plugin-mplayer | vdr-plugin-xineliboutput
Description: VDR plugin for downloading videos from the Web
This plugin for the Linux Video Disc Recorder (VDR) provides ability
diff --git a/debian/libwebvi0.install b/debian/libwebvi0.install
deleted file mode 100644
index 6c9de3d..0000000
--- a/debian/libwebvi0.install
+++ /dev/null
@@ -1 +0,0 @@
-src/libwebvi/libwebvi.so.0* usr/lib/
diff --git a/debian/libwebvi0.docs b/debian/libwebvi1.docs
index 1333ed7..1333ed7 100644
--- a/debian/libwebvi0.docs
+++ b/debian/libwebvi1.docs
diff --git a/debian/libwebvi1.install b/debian/libwebvi1.install
new file mode 100644
index 0000000..ef3ed62
--- /dev/null
+++ b/debian/libwebvi1.install
@@ -0,0 +1 @@
+src/libwebvi/libwebvi.so.1* usr/lib/
diff --git a/src/libwebvi/Makefile b/src/libwebvi/Makefile
index d5a2ff1..47d5826 100644
--- a/src/libwebvi/Makefile
+++ b/src/libwebvi/Makefile
@@ -2,8 +2,8 @@ PREFIX ?= /usr/local
SYSLIBDIR = $(PREFIX)/lib
LIBNAME=libwebvi.so
-LIBSONAME=$(LIBNAME).0
-LIBMINOR=$(LIBSONAME).4
+LIBSONAME=$(LIBNAME).1
+LIBMINOR=$(LIBSONAME).0
VERSION:=$(shell grep VERSION webvi/version.py | cut -d \' -f 2)
PYLIB:=$(shell python pythonlibname.py)
diff --git a/src/libwebvi/libwebvi.c b/src/libwebvi/libwebvi.c
index d8a7b9c..0f1c129 100644
--- a/src/libwebvi/libwebvi.c
+++ b/src/libwebvi/libwebvi.c
@@ -231,9 +231,11 @@ WebviCtx webvi_initialize_context(void) {
/* These are used to wrap C-callbacks into Python callables.
Keep in sync with libwebvi.h. */
- if (PyRun_SimpleString("from ctypes import CFUNCTYPE, c_int, c_size_t, c_char_p, c_void_p\n"
- "WriteCallback = CFUNCTYPE(c_size_t, c_char_p, c_size_t, c_void_p)\n"
- "ReadCallback = CFUNCTYPE(c_size_t, c_char_p, c_size_t, c_void_p)\n") != 0) {
+ if (PyRun_SimpleString(
+ "from ctypes import CFUNCTYPE, c_int, c_long, c_size_t, c_char_p, c_void_p\n"
+ "WriteCallback = CFUNCTYPE(c_size_t, c_char_p, c_size_t, c_void_p)\n"
+ "ReadCallback = CFUNCTYPE(c_size_t, c_char_p, c_size_t, c_void_p)\n"
+ "TimeoutCallback = CFUNCTYPE(c_long, c_void_p)\n") != 0) {
debug("callback definitions failed\n");
goto err;
}
@@ -322,18 +324,51 @@ const char* webvi_strerror(WebviCtx ctx, WebviResult res) {
return c->last_error;
}
-WebviResult webvi_set_config(WebviCtx ctx, WebviConfig conf, const char *value) {
+WebviResult webvi_set_config(WebviCtx ctx, WebviConfig conf, ...) {
+ va_list argptr;
WebviResult res;
per_interpreter_data *c = (per_interpreter_data *)ctx;
PyEval_AcquireThread(c->interp);
- PyObject *args = Py_BuildValue("(is)", conf, value);
- PyObject *v = call_python(c->webvi_module, "set_config", args);
- Py_DECREF(args);
+ PyObject *m = PyImport_AddModule("__main__");
+ if (!m) {
+ handle_pyerr();
+ PyEval_ReleaseThread(c->interp);
+ return WEBVIERR_UNKNOWN_ERROR;
+ }
- res = pyint_as_webviresult(v);
- Py_XDECREF(v);
+ va_start(argptr, conf);
+
+ PyObject *args = NULL;
+ if (conf == WEBVI_CONFIG_TIMEOUT_CALLBACK) {
+ PyObject *maindict = PyModule_GetDict(m);
+ PyObject *prototype = PyDict_GetItemString(maindict, "TimeoutCallback");
+ PyObject *cb_addr = Py_BuildValue("(l)", va_arg(argptr, long));
+ PyObject *cb_as_pyobject = PyObject_CallObject(prototype, cb_addr);
+ args = Py_BuildValue("(iO)", conf, cb_as_pyobject);
+ Py_DECREF(cb_as_pyobject);
+ Py_DECREF(cb_addr);
+
+ } else if (conf == WEBVI_CONFIG_TIMEOUT_DATA) {
+ args = Py_BuildValue("(il)", conf, va_arg(argptr, long));
+
+ } else {
+ args = Py_BuildValue("(is)", conf, va_arg(argptr, char *));
+ }
+
+ if (args) {
+ PyObject *v = call_python(c->webvi_module, "set_config", args);
+ Py_DECREF(args);
+
+ res = pyint_as_webviresult(v);
+ Py_XDECREF(v);
+ } else {
+ handle_pyerr();
+ res = WEBVIERR_UNKNOWN_ERROR;
+ }
+
+ va_end(argptr);
PyEval_ReleaseThread(c->interp);
diff --git a/src/libwebvi/libwebvi.h b/src/libwebvi/libwebvi.h
index 9253eea..e80ce43 100644
--- a/src/libwebvi/libwebvi.h
+++ b/src/libwebvi/libwebvi.h
@@ -26,6 +26,7 @@
typedef int WebviHandle;
typedef ssize_t (*webvi_callback)(const char *, size_t, void *);
+typedef void (*webvi_timeout_callback)(long, void *);
typedef enum {
WEBVIMSG_DONE
@@ -65,8 +66,10 @@ typedef enum {
WEBVIINFO_STREAM_TITLE
} WebviInfo;
+#define WEBVI_SELECT_TIMEOUT -1
+
typedef enum {
- WEBVI_SELECT_TIMEOUT = 0,
+ WEBVI_SELECT_CHECK = 0,
WEBVI_SELECT_READ = 1,
WEBVI_SELECT_WRITE = 2,
WEBVI_SELECT_EXCEPTION = 4
@@ -74,7 +77,9 @@ typedef enum {
typedef enum {
WEBVI_CONFIG_TEMPLATE_PATH,
- WEBVI_CONFIG_DEBUG
+ WEBVI_CONFIG_DEBUG,
+ WEBVI_CONFIG_TIMEOUT_CALLBACK,
+ WEBVI_CONFIG_TIMEOUT_DATA
} WebviConfig;
typedef long WebviCtx;
@@ -133,12 +138,24 @@ const char* webvi_strerror(WebviCtx ctx, WebviResult err);
* Set a new value for a global configuration option conf.
*
* Possible values and their meanings:
- * TEMPLATE_PATH Set the base directory for the XSLT templates
- * DEBUG If value is not "0", print debug output to stdin
*
- * The string pointed by value is copied to the library.
+ * WEBVI_CONFIG_TEMPLATE_PATH
+ * Set the base directory for the XSLT templates (char *)
+ *
+ * WEBVI_CONFIG_DEBUG
+ * If value is not "0", print debug output to stdin (char *)
+ *
+ * WEBVI_CONFIG_TIMEOUT_CALLBACK
+ * Set timeout callback function (webvi_timeout_callback)
+ *
+ * WEBVI_CONFIG_TIMEOUT_DATA
+ * Set user data which will passed as second argument of the timeout
+ * callback (void *)
+ *
+ * The strings (char * arguments) are copied to the library (the user
+ * can free their original copy).
*/
-WebviResult webvi_set_config(WebviCtx ctx, WebviConfig conf, const char *value);
+WebviResult webvi_set_config(WebviCtx ctx, WebviConfig conf, ...);
/*
* Creates a new download request.
@@ -301,14 +318,13 @@ WebviResult webvi_fdset(WebviCtx ctx, fd_set *readfd, fd_set *writefd, fd_set *e
* WEBVI_SELECT_READ, WEBVI_SELECT_WRITE, WEBVI_SELECT_EXCEPTION to
* indicate that activefd has been signalled to be ready for reading,
* writing or being in exception state, respectively. ev_bitmask can
- * also set to WEBVI_SELECT_TIMEOUT which means that the state is
+ * also set to WEBVI_SELECT_CHECK which means that the state is
* checked internally. On return, running_handles will contain the
* number of still active file descriptors.
*
- * This function should be called with activefd set to 0 and
- * ev_bitmask to WEBVI_SELECT_TIMEOUT periodically (every few seconds)
- * even if no file descriptors have become ready to allow for timeout
- * handling and other internal tasks.
+ * If a timeout occurs before any file descriptor becomes ready, this
+ * function should be called with sockfd set to WEBVI_SELECT_TIMEOUT
+ * and ev_bitmask set to WEBVI_SELECT_CHECK.
*/
WebviResult webvi_perform(WebviCtx ctx, int sockfd, int ev_bitmask, long *running_handles);
diff --git a/src/libwebvi/webvi/api.py b/src/libwebvi/webvi/api.py
index f7f4ad1..6dfa31e 100644
--- a/src/libwebvi/webvi/api.py
+++ b/src/libwebvi/webvi/api.py
@@ -23,29 +23,45 @@ Example workflow:
handle = new_request(ref, WebviRequestType.MENU)
-2) Setup a callback function:
+2) Setup a timeout callback:
-setopt(handle, WebviOpt.WRITEFUNC, my_callback)
+def timeout_func(t, ignored):
+ global alarm
+ now = current_time_in_milliseconds()
+ alarm = now + t
-3) Start the network transfer:
+set_config(WebviConfig.TIMEOUT_CALLBACK, timeout_func)
+
+3) Setup a data callback:
+
+set_opt(handle, WebviOpt.WRITEFUNC, write_func)
+
+4) Start the network transfer:
start_handle(handle)
-4) Get active file descriptors, wait for activity on them, and let
-webvi process the file descriptor.
+5) Get active file descriptors, wait for activity using the timeout
+value supplied by timeout callback, and let webvi process the file
+descriptor.
import select
...
readfd, writefd, excfd = fdset()[1:4]
-readfd, writefd, excfd = select.select(readfd, writefd, excfd, 5.0)
-for fd in readfd:
- perform(fd, WebviSelectBitmask.READ)
-for fd in writefd:
- perform(fd, WebviSelectBitmask.WRITE)
-
-5) Iterate 4) until pop_message returns handle, which indicates that
+timeout = alarm - current_time_in_milliseconds()
+if timeout < 0:
+ timeout = 10.0
+readfd, writefd, excfd = select.select(readfd, writefd, excfd, timeout)
+if readfd == writefd == excfd == []: # timeout
+ perform(WebviSelect.TIMEOUT, WebviSelectBitmask.CHECK)
+else:
+ for fd in readfd:
+ perform(fd, WebviSelectBitmask.READ)
+ for fd in writefd:
+ perform(fd, WebviSelectBitmask.WRITE)
+
+6) Iterate 5) until pop_message returns handle, which indicates that
the request has been completed.
finished, status, errmsg, remaining = pop_message()
@@ -105,6 +121,12 @@ def set_config(conf, value):
else:
request.DEBUG = True
return WebviErr.OK
+ elif conf == WebviConfig.TIMEOUT_CALLBACK:
+ request.set_timeout_callback(value)
+ return WebviErr.OK
+ elif conf == WebviConfig.TIMEOUT_DATA:
+ request.timeout_data = value
+ return WebviErr.OK
else:
return WebviErr.INVALID_PARAMETER
@@ -242,7 +264,7 @@ def fdset():
"""Get the list of file descriptors that are currently in use by
the library.
- Returrns a tuple, where the first item is a constants.WebviErr
+ Returns a tuple, where the first item is a constants.WebviErr
value indicating the success of the call, the next three values
are lists of descriptors that should be monitored for reading,
writing, and exceptional conditions, respectively. The last item
@@ -272,24 +294,24 @@ def perform(fd, ev_bitmask):
select() or similar system call. ev_bitmask specifies what kind of
activity has been detected using values of
constants.WebviSelectBitmask. If ev_bitmask is
- constants.WebviSelectBitmask.TIMEOUT the type of activity is check
- by the function.
+ constants.WebviSelectBitmask.CHECK the type of activity is
+ checked by the function.
- This function should be called every few seconds with fd=-1,
- ev_bitmask=constants.WebviSelectBitmask.TIMEOUT even if no
- activity has been signalled on the file descriptors to ensure
- correct handling of timeouts and other internal processing.
+ If a timeout occurs before any file descriptor becomes ready, this
+ function should be called with fd set to
+ constants.WebviSelect.TIMEOUT and ev_bitmask set to
+ constants.WebviSelectBitmask.CHECK.
"""
if fd < 0:
- asyncurl.poll()
+ asyncurl.poll_timeout()
else:
disp = socket_map.get(fd)
if disp is not None:
if ev_bitmask & WebviSelectBitmask.READ != 0 or \
- (ev_bitmask == 0 and disp.readable()):
+ (ev_bitmask == WebviSelectBitmask.CHECK and disp.readable()):
disp.handle_read_event()
if ev_bitmask & WebviSelectBitmask.WRITE != 0 or \
- (ev_bitmask == 0 and disp.writable()):
+ (ev_bitmask == WebviSelectBitmask.CHECK and disp.writable()):
disp.handle_write_event()
return (WebviErr.OK, len(socket_map))
diff --git a/src/libwebvi/webvi/asyncurl.py b/src/libwebvi/webvi/asyncurl.py
index 585f090..6b17893 100644
--- a/src/libwebvi/webvi/asyncurl.py
+++ b/src/libwebvi/webvi/asyncurl.py
@@ -40,7 +40,8 @@ def poll(timeout=0.0, map=None, mdisp=None):
if mdisp is None:
mdisp = multi_dispatcher
if map:
- timeout = min(timeout, mdisp.timeout/1000.0)
+ if mdisp.timeout != -1:
+ timeout = min(timeout, mdisp.timeout/1000.0)
r = []; w = []; e = []
for fd, obj in map.items():
@@ -53,7 +54,8 @@ def poll(timeout=0.0, map=None, mdisp=None):
if is_r or is_w:
e.append(fd)
if [] == r == w == e:
- time.sleep(timeout)
+ if timeout > 0:
+ time.sleep(timeout)
else:
try:
r, w, e = select.select(r, w, e, timeout)
@@ -85,6 +87,11 @@ def poll(timeout=0.0, map=None, mdisp=None):
continue
asyncore._exception(obj)
+def poll_timeout(mdisp=None):
+ if mdisp is None:
+ mdisp = multi_dispatcher
+ mdisp.socket_action(SOCKET_TIMEOUT, 0)
+
def loop(timeout=30.0, use_poll=False, map=None, count=None, mdisp=None):
if map is None:
map = asyncore.socket_map
@@ -118,13 +125,15 @@ class curl_multi_dispatcher:
else:
self._map = socket_map
self.dispatchers = {}
- self.timeout = 1000
+ self.timeout = -1
+ # The lambda is to avoid "not callable" error from pylint
+ self.timeout_callback = lambda x, y: None
self._sockets_removed = False
self._curlm = pycurl.CurlMulti()
- self._curlm.setopt(pycurl.M_SOCKETFUNCTION, self.socket_callback)
- self._curlm.setopt(pycurl.M_TIMERFUNCTION, self.timeout_callback)
+ self._curlm.setopt(pycurl.M_SOCKETFUNCTION, self._socket_callback)
+ self._curlm.setopt(pycurl.M_TIMERFUNCTION, self._update_timeout)
- def socket_callback(self, action, socket, user_data, socket_data):
+ def _socket_callback(self, action, socket, user_data, socket_data):
# print 'socket callback: %d, %s' % \
# (socket, {pycurl.POLL_NONE: "NONE",
# pycurl.POLL_IN: "IN",
@@ -155,8 +164,10 @@ class curl_multi_dispatcher:
obj.set_readable(True)
obj.set_writable(True)
- def timeout_callback(self, msec):
+ def _update_timeout(self, msec):
self.timeout = msec
+ if self.timeout_callback:
+ self.timeout_callback(self, msec)
def attach(self, curldisp):
"""Starts a transfer on curl handle by attaching it to this
@@ -168,9 +179,9 @@ class curl_multi_dispatcher:
# the curl object is already on this multi-stack
pass
- while self._curlm.socket_all()[0] == pycurl.E_CALL_MULTI_PERFORM:
- pass
-
+ # _curlm.timeout() seems to be needed, although curl
+ # documentation doesn't mention it.
+ self._update_timeout(self._curlm.timeout())
self.check_completed(True)
def detach(self, curldisp):
@@ -181,9 +192,6 @@ class curl_multi_dispatcher:
# libcurl does not send POLL_REMOVE when a handle is aborted
for socket, curlobj in self._map.items():
if curlobj == curldisp:
-
- print 'handle stopped but socket in map'
-
del self._map[socket]
break
diff --git a/src/libwebvi/webvi/constants.py b/src/libwebvi/webvi/constants.py
index 2d29700..16e1f92 100644
--- a/src/libwebvi/webvi/constants.py
+++ b/src/libwebvi/webvi/constants.py
@@ -41,11 +41,16 @@ class WebviInfo:
STREAM_TITLE = 3
class WebviSelectBitmask:
- TIMEOUT = 0
+ CHECK = 0
READ = 1
WRITE = 2
EXCEPTION = 4
+class WebviSelect:
+ TIMEOUT = -1
+
class WebviConfig:
TEMPLATE_PATH = 0
DEBUG = 1
+ TIMEOUT_CALLBACK = 2
+ TIMEOUT_DATA = 3
diff --git a/src/libwebvi/webvi/request.py b/src/libwebvi/webvi/request.py
index 87dcf87..cab15f7 100644
--- a/src/libwebvi/webvi/request.py
+++ b/src/libwebvi/webvi/request.py
@@ -24,12 +24,14 @@ import download
import sys
import utils
import json2xml
+import asyncurl
from constants import WebviRequestType
DEBUG = False
DEFAULT_TEMPLATE_PATH = '/usr/local/share/webvi/templates'
template_path = DEFAULT_TEMPLATE_PATH
+timeout_data = None
def debug(msg):
if DEBUG:
@@ -49,6 +51,10 @@ def set_template_path(path):
debug("set_template_path " + template_path)
+def set_timeout_callback(callback):
+ c_api_callback = lambda mdisp, timeout: callback(timeout, timeout_data)
+ asyncurl.multi_dispatcher.timeout_callback = c_api_callback
+
def parse_reference(reference):
"""Parses URLs of the following form:
diff --git a/src/vdr-plugin/download.c b/src/vdr-plugin/download.c
index ffdfa54..4b7a971 100644
--- a/src/vdr-plugin/download.c
+++ b/src/vdr-plugin/download.c
@@ -14,6 +14,19 @@
#include "download.h"
#include "common.h"
+static void diff_timeval(struct timeval *a, struct timeval *b,
+ struct timeval *result) {
+ long usec_diff = a->tv_usec - b->tv_usec;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+
+ while (usec_diff < 0) {
+ usec_diff += 1000000;
+ result->tv_sec -= 1;
+ }
+
+ result->tv_usec = usec_diff;
+}
+
// --- cWebviThread --------------------------------------------------------
cWebviThread::cWebviThread() {
@@ -25,8 +38,13 @@ cWebviThread::cWebviThread() {
newreqwrite = pipefd[1];
//fcntl(newreqread, F_SETFL, O_NONBLOCK);
//fcntl(newreqwrite, F_SETFL, O_NONBLOCK);
+ timerActive = false;
webvi = webvi_initialize_context();
+ if (webvi != 0) {
+ webvi_set_config(webvi, WEBVI_CONFIG_TIMEOUT_DATA, this);
+ webvi_set_config(webvi, WEBVI_CONFIG_TIMEOUT_CALLBACK, UpdateTimeout);
+ }
}
cWebviThread::~cWebviThread() {
@@ -47,6 +65,24 @@ cWebviThread::~cWebviThread() {
}
}
+void cWebviThread::UpdateTimeout(long timeout, void *instance) {
+ cWebviThread *self = (cWebviThread *)instance;
+ if (!self)
+ return;
+
+ if (timeout < 0) {
+ self->timerActive = false;
+ } else {
+ struct timeval now;
+ long alrm;
+ gettimeofday(&now, NULL);
+ alrm = timeout + now.tv_usec/1000;
+ self->timer.tv_sec = now.tv_sec + alrm/1000;
+ self->timer.tv_usec = (alrm % 1000) * 1000;
+ self->timerActive = true;
+ }
+}
+
cWebviThread &cWebviThread::Instance() {
static cWebviThread instance;
@@ -128,8 +164,8 @@ void cWebviThread::Stop() {
void cWebviThread::Action(void) {
fd_set readfds, writefds, excfds;
- int maxfd;
- struct timeval timeout;
+ int maxfd, s;
+ struct timeval timeout, now;
long running_handles;
bool check_done = false;
bool has_request_files = false;
@@ -161,11 +197,20 @@ void cWebviThread::Action(void) {
}
requestMutex.Unlock();
- timeout.tv_sec = 5;
- timeout.tv_usec = 0;
+ if (!timerActive) {
+ timeout.tv_sec = 60;
+ timeout.tv_usec = 0;
+ } else {
+ gettimeofday(&now, NULL);
+ diff_timeval(&timer, &now, &timeout);
+ if (timeout.tv_sec < 0 || timeout.tv_usec < 0) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+ }
- int s = TEMP_FAILURE_RETRY(select(maxfd+1, &readfds, &writefds, NULL,
- &timeout));
+ s = TEMP_FAILURE_RETRY(select(maxfd+1, &readfds, &writefds, NULL,
+ &timeout));
if (s == -1) {
// select error
LOG_ERROR_STR("select() error in webvideo downloader thread:");
@@ -173,7 +218,8 @@ void cWebviThread::Action(void) {
} else if (s == 0) {
// timeout
- webvi_perform(webvi, 0, WEBVI_SELECT_TIMEOUT, &running_handles);
+ timerActive = false;
+ webvi_perform(webvi, WEBVI_SELECT_TIMEOUT, WEBVI_SELECT_CHECK, &running_handles);
check_done = true;
} else {
diff --git a/src/vdr-plugin/download.h b/src/vdr-plugin/download.h
index 5f29150..14a5c66 100644
--- a/src/vdr-plugin/download.h
+++ b/src/vdr-plugin/download.h
@@ -9,6 +9,7 @@
#ifndef __WEBVIDEO_DOWNLOAD_H
#define __WEBVIDEO_DOWNLOAD_H
+#include <sys/time.h>
#include <vdr/thread.h>
#include <libwebvi.h>
#include "request.h"
@@ -23,6 +24,8 @@ private:
cRequestVector newRequestList;
cRequestVector finishedRequestList;
int newreqread, newreqwrite;
+ bool timerActive;
+ struct timeval timer;
void MoveToFinishedList(cMenuRequest *req);
void ActivateNewRequest();
@@ -30,6 +33,7 @@ private:
protected:
void Action(void);
+ static void UpdateTimeout(long timeout, void *data);
public:
cWebviThread();
diff --git a/src/webvicli/webvicli/client.py b/src/webvicli/webvicli/client.py
index e0a8baa..0c86c0d 100644
--- a/src/webvicli/webvicli/client.py
+++ b/src/webvicli/webvicli/client.py
@@ -26,6 +26,7 @@ import os.path
import subprocess
import time
import re
+import datetime
import urllib
import libxml2
import webvi.api
@@ -33,7 +34,7 @@ import webvi.utils
from optparse import OptionParser
from ConfigParser import RawConfigParser
from urlparse import urlparse
-from webvi.constants import WebviRequestType, WebviOpt, WebviInfo, WebviSelectBitmask, WebviConfig
+from webvi.constants import WebviRequestType, WebviOpt, WebviInfo, WebviSelectBitmask, WebviConfig, WebviSelect
from . import menu
VERSION = '0.4.2'
@@ -188,6 +189,15 @@ class WVClient:
self.quality_limits = {'download': downloadlimits,
'stream': streamlimits}
self.vfatfilenames = vfatfilenames
+ self.alarm = None
+ webvi.api.set_config(WebviConfig.TIMEOUT_CALLBACK, self.update_timeout)
+
+ def update_timeout(self, timeout_ms, data):
+ if timeout_ms < 0:
+ self.alarm = None
+ else:
+ now = datetime.datetime.now()
+ self.alarm = now + datetime.timedelta(milliseconds=timeout_ms)
def parse_page(self, page):
if page is None:
@@ -226,7 +236,7 @@ class WVClient:
node = node.next
doc.freeDoc()
return menupage
-
+
def parse_link(self, node):
label = ''
ref = None
@@ -319,10 +329,24 @@ class WVClient:
return (501, 'Unexpected handle (got %d, expected %d)' % (finished, handle))
elif status != -1 or errmsg:
return (status, errmsg)
- else:
- return (502, 'empty fdset but handle is not ready!')
- readyread, readywrite, readyexc = select.select(readfds, writefds, excfds, 30.0)
+ if self.alarm is None:
+ timeout = 10.0
+ else:
+ delta = self.alarm - datetime.datetime.now()
+ if delta < datetime.timedelta(0):
+ timeout = 10.0
+ self.alarm = None
+ else:
+ timeout = delta.microseconds/1000000.0 + delta.seconds
+
+ readyread, readywrite, readyexc = \
+ select.select(readfds, writefds, excfds, timeout)
+
+ if readyread == readywrite == readyexc == []:
+ webvi.api.perform(WebviSelect.TIMEOUT, WebviSelectBitmask.CHECK)
+ self.alarm = None
+ continue
for fd in readyread:
webvi.api.perform(fd, WebviSelectBitmask.READ)