support repositories to manage backends (closes #747)
This commit is contained in:
parent
ef16a5b726
commit
14a7a1d362
410 changed files with 1079 additions and 297 deletions
22
modules/canalplus/__init__.py
Normal file
22
modules/canalplus/__init__.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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 CanalplusBackend
|
||||
|
||||
__all__ = ['CanalplusBackend']
|
||||
71
modules/canalplus/backend.py
Normal file
71
modules/canalplus/backend.py
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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 __future__ import with_statement
|
||||
|
||||
from weboob.capabilities.video import ICapVideo
|
||||
from weboob.tools.backend import BaseBackend, BackendConfig
|
||||
from weboob.tools.value import Value
|
||||
|
||||
from .browser import CanalplusBrowser
|
||||
from .pages import CanalplusVideo
|
||||
|
||||
from weboob.capabilities.collection import ICapCollection
|
||||
|
||||
|
||||
__all__ = ['CanalplusBackend']
|
||||
|
||||
|
||||
class CanalplusBackend(BaseBackend, ICapVideo, ICapCollection):
|
||||
NAME = 'canalplus'
|
||||
MAINTAINER = 'Nicolas Duhamel'
|
||||
EMAIL = 'nicolas@jombi.fr'
|
||||
VERSION = '0.a'
|
||||
DESCRIPTION = 'Canal plus french TV'
|
||||
LICENSE = 'AGPLv3+'
|
||||
CONFIG = BackendConfig(Value('quality', label='Quality of videos', choices=['hd', 'sd'], default='hd'))
|
||||
BROWSER = CanalplusBrowser
|
||||
|
||||
def create_default_browser(self):
|
||||
return self.create_browser(quality=self.config['quality'].get())
|
||||
|
||||
def iter_search_results(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None):
|
||||
with self.browser:
|
||||
return self.browser.iter_search_results(pattern)
|
||||
|
||||
def get_video(self, _id):
|
||||
with self.browser:
|
||||
return self.browser.get_video(_id)
|
||||
|
||||
def fill_video(self, video, fields):
|
||||
if fields != ['thumbnail']:
|
||||
# if we don't want only the thumbnail, we probably want also every fields
|
||||
with self.browser:
|
||||
video = self.browser.get_video(CanalplusVideo.id2url(video.id), video)
|
||||
if 'thumbnail' in fields and video.thumbnail:
|
||||
with self.browser:
|
||||
video.thumbnail.data = self.browser.readurl(video.thumbnail.url)
|
||||
return video
|
||||
|
||||
OBJECTS = {CanalplusVideo: fill_video}
|
||||
|
||||
def iter_resources(self, splited_path):
|
||||
with self.browser:
|
||||
return self.browser.iter_resources(splited_path)
|
||||
93
modules/canalplus/browser.py
Normal file
93
modules/canalplus/browser.py
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
|
||||
import urllib
|
||||
|
||||
import lxml.etree
|
||||
|
||||
from weboob.tools.browser import BaseBrowser
|
||||
from weboob.tools.browser.decorators import id2url
|
||||
|
||||
from .pages import InitPage, CanalplusVideo, VideoPage
|
||||
|
||||
from weboob.capabilities.collection import Collection, CollectionNotFound
|
||||
|
||||
__all__ = ['CanalplusBrowser']
|
||||
|
||||
|
||||
class XMLParser(object):
|
||||
def parse(self, data, encoding=None):
|
||||
if encoding is None:
|
||||
parser = None
|
||||
else:
|
||||
parser = lxml.etree.XMLParser(encoding=encoding, strip_cdata=False)
|
||||
return lxml.etree.XML(data.get_data(), parser)
|
||||
|
||||
|
||||
class CanalplusBrowser(BaseBrowser):
|
||||
DOMAIN = u'service.canal-plus.com'
|
||||
ENCODING = 'utf-8'
|
||||
PAGES = {
|
||||
r'http://service.canal-plus.com/video/rest/initPlayer/cplus/': InitPage,
|
||||
r'http://service.canal-plus.com/video/rest/search/cplus/.*': VideoPage,
|
||||
r'http://service.canal-plus.com/video/rest/getVideosLiees/cplus/(?P<id>.+)': VideoPage,
|
||||
r'http://service.canal-plus.com/video/rest/getMEAs/cplus/.*': VideoPage,
|
||||
}
|
||||
|
||||
#We need lxml.etree.XMLParser for read CDATA
|
||||
PARSER = XMLParser()
|
||||
FORMATS = {
|
||||
'sd': 'BAS_DEBIT',
|
||||
'hd': 'HD',
|
||||
}
|
||||
|
||||
def __init__(self, quality, *args, **kwargs):
|
||||
BaseBrowser.__init__(self, parser= self.PARSER, *args, **kwargs)
|
||||
if quality in self.FORMATS:
|
||||
self.quality = self.FORMATS[quality]
|
||||
else:
|
||||
self.quality = 'HD'
|
||||
|
||||
def home(self):
|
||||
self.location('http://service.canal-plus.com/video/rest/initPlayer/cplus/')
|
||||
|
||||
def iter_search_results(self, pattern):
|
||||
self.location('http://service.canal-plus.com/video/rest/search/cplus/' + urllib.quote_plus(pattern.encode('utf-8')))
|
||||
return self.page.iter_results()
|
||||
|
||||
@id2url(CanalplusVideo.id2url)
|
||||
def get_video(self, url, video=None):
|
||||
self.location(url)
|
||||
return self.page.get_video(video, self.quality)
|
||||
|
||||
def iter_resources(self, splited_path):
|
||||
self.home()
|
||||
collections = self.page.collections
|
||||
|
||||
def walk_res(path, collections):
|
||||
if len(path) == 0 or not isinstance(collections, (list, Collection)):
|
||||
return collections
|
||||
i = path[0]
|
||||
if i not in [collection.title for collection in collections]:
|
||||
raise CollectionNotFound()
|
||||
|
||||
return walk_res(path[1:], [collection.children for collection in collections if collection.title == i][0])
|
||||
|
||||
return walk_res(splited_path, collections)
|
||||
BIN
modules/canalplus/favicon.png
Normal file
BIN
modules/canalplus/favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 652 B |
24
modules/canalplus/pages/__init__.py
Normal file
24
modules/canalplus/pages/__init__.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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 .initpage import InitPage
|
||||
from .video import CanalplusVideo
|
||||
from .videopage import VideoPage
|
||||
|
||||
__all__ = ['InitPage', 'VideoPage', 'CanalplusVideo']
|
||||
49
modules/canalplus/pages/initpage.py
Normal file
49
modules/canalplus/pages/initpage.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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.browser import BasePage
|
||||
|
||||
from weboob.capabilities.collection import Collection
|
||||
|
||||
__all__ = ['InitPage']
|
||||
|
||||
|
||||
class InitPage(BasePage):
|
||||
|
||||
def on_loaded(self):
|
||||
self.collections = []
|
||||
|
||||
def do(id):
|
||||
self.browser.location("http://service.canal-plus.com/video/rest/getMEAs/cplus/" + id)
|
||||
return self.browser.page.iter_channel()
|
||||
|
||||
### Parse liste des channels
|
||||
for elem in self.document[2].getchildren():
|
||||
coll = Collection()
|
||||
for e in elem.getchildren():
|
||||
if e.tag == "NOM":
|
||||
coll.title = e.text.strip().encode('utf-8')
|
||||
elif e.tag == "SELECTIONS":
|
||||
for select in e:
|
||||
sub = Collection(title=select[1].text.strip().encode('utf-8'))
|
||||
sub.id = select[0].text
|
||||
sub.children = do
|
||||
coll.appendchild(sub)
|
||||
self.collections.append(coll)
|
||||
31
modules/canalplus/pages/video.py
Normal file
31
modules/canalplus/pages/video.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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.capabilities.video import BaseVideo
|
||||
|
||||
|
||||
__all__ = ['CanalplusVideo']
|
||||
|
||||
|
||||
class CanalplusVideo(BaseVideo):
|
||||
swf_player = False
|
||||
@classmethod
|
||||
def id2url(cls, _id):
|
||||
return 'http://service.canal-plus.com/video/rest/getVideosLiees/cplus/%s' % _id
|
||||
96
modules/canalplus/pages/videopage.py
Normal file
96
modules/canalplus/pages/videopage.py
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Nicolas Duhamel
|
||||
#
|
||||
# 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 datetime import datetime
|
||||
|
||||
from weboob.capabilities.base import NotAvailable
|
||||
from weboob.tools.capabilities.thumbnail import Thumbnail
|
||||
from weboob.tools.browser import BasePage
|
||||
from .video import CanalplusVideo
|
||||
|
||||
|
||||
__all__ = ['VideoPage']
|
||||
|
||||
|
||||
class VideoPage(BasePage):
|
||||
def parse_video(self, el, video=None, quality=None):
|
||||
_id = el.find('ID').text
|
||||
if _id == '-1':
|
||||
# means the video is not found
|
||||
return None
|
||||
|
||||
if not video:
|
||||
video = CanalplusVideo(_id)
|
||||
|
||||
infos = el.find('INFOS')
|
||||
video.title = u''
|
||||
for part in infos.find('TITRAGE'):
|
||||
if len(part.text.strip()) == 0:
|
||||
continue
|
||||
if len(video.title) > 0:
|
||||
video.title += u' — '
|
||||
video.title += part.text.strip()
|
||||
video.description = infos.find('DESCRIPTION').text
|
||||
|
||||
media = el.find('MEDIA')
|
||||
url = media.find('IMAGES').find('PETIT').text
|
||||
if url:
|
||||
video.thumbnail = Thumbnail(url)
|
||||
else:
|
||||
video.thumbnail = NotAvailable
|
||||
lastest_format = None
|
||||
for format in media.find('VIDEOS'):
|
||||
if format.text is None:
|
||||
continue
|
||||
if format.tag == quality:
|
||||
video.url = format.text
|
||||
break
|
||||
lastest_format = format
|
||||
if not video.url and lastest_format is not None:
|
||||
video.url = lastest_format.text
|
||||
|
||||
day, month, year = map(int, infos.find('PUBLICATION').find('DATE').text.split('/'))
|
||||
hour, minute, second = map(int, infos.find('PUBLICATION').find('HEURE').text.split(':'))
|
||||
video.date = datetime(year, month, day, hour, minute, second)
|
||||
|
||||
return video
|
||||
|
||||
def iter_results(self):
|
||||
for vid in self.document.getchildren():
|
||||
yield self.parse_video(vid)
|
||||
|
||||
def iter_channel(self):
|
||||
for vid in self.document.getchildren():
|
||||
yield self.parse_video_channel(vid)
|
||||
|
||||
def parse_video_channel(self,el):
|
||||
_id = el[0].text
|
||||
video = CanalplusVideo(_id)
|
||||
video.title = el[2][3][0].text
|
||||
video.date = datetime.now()
|
||||
return video
|
||||
|
||||
|
||||
def get_video(self, video, quality):
|
||||
_id = self.group_dict['id']
|
||||
for vid in self.document.getchildren():
|
||||
if not _id in vid.find('ID').text:
|
||||
continue
|
||||
return self.parse_video(vid, video, quality)
|
||||
31
modules/canalplus/test.py
Normal file
31
modules/canalplus/test.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright(C) 2010-2011 Romain Bignon
|
||||
#
|
||||
# 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 CanalPlusTest(BackendTest):
|
||||
BACKEND = 'canalplus'
|
||||
|
||||
def test_canalplus(self):
|
||||
l = list(self.backend.iter_search_results('guignol'))
|
||||
self.assertTrue(len(l) > 0)
|
||||
v = l[0]
|
||||
self.backend.fillobj(v, ('url',))
|
||||
self.assertTrue(v.url and v.url.startswith('rtmp://'), 'URL for video "%s" not found: %s' % (v.id, v.url))
|
||||
Loading…
Add table
Add a link
Reference in a new issue