new video backend: quvi

This commit is contained in:
Vincent A 2013-09-07 20:38:04 +02:00 committed by Romain Bignon
commit ad5b80e1f6
5 changed files with 318 additions and 0 deletions

24
modules/quvi/__init__.py Normal file
View file

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Vincent A
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from .backend import QuviBackend, QuviVideo
__all__ = ['QuviBackend', 'QuviVideo']

117
modules/quvi/backend.py Normal file
View file

@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Vincent A
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
# sample usage: youtube.XXXXXX@quvi
# or also: https://www.youtube.com/watch?v=XXXXXX@quvi
# shortened URLs are also supported
# this backend requires the quvi 0.4 C library to be installed
import datetime
from weboob.capabilities.base import UserError, StringField
from weboob.capabilities.video import ICapVideo, BaseVideo
from weboob.tools.backend import BaseBackend
from weboob.tools.capabilities.thumbnail import Thumbnail
from weboob.tools.misc import to_unicode
from quvi import LibQuvi, QuviError
__all__ = ['QuviBackend', 'QuviVideo']
class QuviBackend(BaseBackend, ICapVideo):
NAME = 'quvi'
DESCRIPTION = u'Multi-website video helper with quvi. Handles Youtube, BBC, and a lot more'
MAINTAINER = u'Vincent A'
EMAIL = 'dev@indigo.re'
LICENSE = 'AGPLv3+'
VERSION = '0.h'
BROWSER = None
def get_video(self, _id):
video = QuviVideo(_id)
parser = LibQuvi()
if not parser.load():
raise UserError('Make sure libquvi 0.4 is installed')
try:
info = parser.get_info(video.page_url)
except QuviError as qerror:
raise UserError(qerror.message)
video.url = to_unicode(info.get('url'))
if not video.url:
raise NotImplementedError()
video.ext = to_unicode(info.get('suffix'))
video.title = to_unicode(info.get('title'))
video.page = to_unicode(info.get('page'))
duration = int(info.get('duration', 0))
if duration:
video.duration = datetime.timedelta(milliseconds=duration)
if info.get('thumbnail'):
video.thumbnail = Thumbnail(info.get('thumbnail'))
return video
class QuviVideo(BaseVideo):
BACKENDS = {
'youtube': 'https://www.youtube.com/watch?v=%s',
'vimeo': 'http://vimeo.com/%s',
'dailymotion': 'http://www.dailymotion.com/video/%s',
'metacafe': 'http://www.metacafe.com/watch/%s/',
'arte': 'http://videos.arte.tv/fr/videos/plop--%s.html',
'videa': 'http://videa.hu/videok/%s/',
'wimp': 'http://www.wimp.com/%s/',
'funnyordie': 'http://www.funnyordie.com/videos/%s/',
'tapuz': 'http://flix.tapuz.co.il/v/watch-%s-.html',
'liveleak': 'http://www.liveleak.com/view?i=%s',
# nsfw
'xhamster': 'https://xhamster.com/movies/%s/plop.html',
'xvideos': 'http://www.xvideos.com/video%s/',
'redtube': 'http://www.redtube.com/%s',
'xnxx': 'http://video.xnxx.com/video%s/',
# more websites are supported, but <service>.<id> isn't always enough
# however, URLs are supported, like this:
# https://www.youtube.com/watch?v=BaW_jenozKc@quvi
}
page = StringField('Page URL of the video')
@classmethod
def id2url(cls, _id):
if _id.startswith('http'):
return _id
sub_backend, sub_id = _id.split('.', 1)
try:
return cls.BACKENDS[sub_backend] % sub_id
except KeyError:
raise NotImplementedError()
@property
def page_url(self):
if self.page:
return self.page
else:
return self.id2url(self.id)

BIN
modules/quvi/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

129
modules/quvi/quvi.py Normal file
View file

@ -0,0 +1,129 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Vincent A
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from ctypes import cdll, c_char_p, c_double, c_void_p, byref
from ctypes.util import find_library
__all__ = ['LibQuvi', 'QuviError']
class QuviError(Exception):
pass
class LibQuvi04(object):
QUVI_VERSION = 0
QUVIOPT_FORMAT = 0
QUVIOPT_CATEGORY = 4
QUVI_OK = 0
QUVI_LAST = 5
QUVIPROP_PAGEURL = 0x100002
QUVIPROP_PAGETITLE = 0x100003
QUVIPROP_MEDIAID = 0x100004
QUVIPROP_MEDIAURL = 0x100005
QUVIPROP_FILESUFFIX = 0x100008
#~ QUVIPROP_FORMAT = 0x10000A
QUVIPROP_MEDIATHUMBNAILURL = 0x10000C
QUVIPROP_MEDIACONTENTLENGTH = 0x300006
QUVIPROP_MEDIADURATION = 0x30000D
QUVIPROTO_HTTP = 1
QUVIPROTO_RTMP = 8
def __init__(self, lib=None):
self.lib = lib
self.qh = c_void_p()
self.qmh = c_void_p()
def load(self):
path = find_library('quvi')
if not path:
return False
self.lib = cdll.LoadLibrary(path)
if self.lib is None:
return False
version_str = c_char_p(self.lib.quvi_version(self.QUVI_VERSION)).value
if version_str.startswith('v0.4'):
return True
else:
return False
def _cleanup(self):
if self.qmh:
self.lib.quvi_parse_close(byref(self.qmh))
self.qmh = c_void_p()
if self.qh:
self.lib.quvi_close(byref(self.qh))
self.qh = c_void_p()
def get_info(self, url):
try:
return self._get_info(url)
finally:
self._cleanup()
def _get_info(self, url):
status = self.lib.quvi_init(byref(self.qh))
self._assert_ok(status)
status = self.lib.quvi_setopt(self.qh, self.QUVIOPT_FORMAT, 'best')
self._assert_ok(status)
status = self.lib.quvi_parse(self.qh, c_char_p(url), byref(self.qmh))
self._assert_ok(status)
info = {}
info['url'] = self._get_str(self.QUVIPROP_MEDIAURL)
info['title'] = self._get_str(self.QUVIPROP_PAGETITLE)
info['suffix'] = self._get_str(self.QUVIPROP_FILESUFFIX)
info['page'] = self._get_str(self.QUVIPROP_PAGEURL) # uncut!
info['media_id'] = self._get_str(self.QUVIPROP_MEDIAID)
info['thumbnail'] = self._get_str(self.QUVIPROP_MEDIATHUMBNAILURL)
info['duration'] = self._get_double(self.QUVIPROP_MEDIADURATION)
info['size'] = self._get_double(self.QUVIPROP_MEDIACONTENTLENGTH)
return info
def _assert_ok(self, status):
if status != self.QUVI_OK:
c_msg = c_char_p(self.lib.quvi_strerror(self.qh, status))
raise QuviError(c_msg.value)
def _get_str(self, prop):
c_value = c_char_p()
status = self.lib.quvi_getprop(self.qmh, prop, byref(c_value))
self._assert_ok(status)
return c_value.value
def _get_double(self, prop):
c_value = c_double()
status = self.lib.quvi_getprop(self.qmh, prop, byref(c_value))
self._assert_ok(status)
return c_value.value
LibQuvi = LibQuvi04

48
modules/quvi/test.py Normal file
View file

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Copyright(C) 2013 Vincent A
#
# This file is part of weboob.
#
# weboob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# weboob 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with weboob. If not, see <http://www.gnu.org/licenses/>.
from weboob.tools.test import BackendTest
class QuviTest(BackendTest):
BACKEND = 'quvi'
def test_get_id(self):
v = self.backend.get_video('youtube.BaW_jenozKc')
assert len(v.url)
assert len(v.title)
assert (v.page_url == 'https://www.youtube.com/watch?v=BaW_jenozKc')
def test_get_url(self):
v = self.backend.get_video('https://www.youtube.com/watch?v=BaW_jenozKc')
assert len(v.url)
assert len(v.title)
# did we retrieve more?
assert len(v.ext)
assert v.duration
assert v.thumbnail
assert v.page_url == 'https://www.youtube.com/watch?v=BaW_jenozKc'
def test_get_shortened(self):
v = self.backend.get_video('http://youtu.be/BaW_jenozKc')
assert len(v.url)
assert len(v.title)
assert v.page_url.startswith('http://www.youtube.com/watch?v=BaW_jenozKc')