diff --git a/modules/arte/backend.py b/modules/arte/backend.py index a68d46f5..69e0486f 100644 --- a/modules/arte/backend.py +++ b/modules/arte/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.value import Value @@ -31,7 +32,7 @@ from .video import ArteVideo __all__ = ['ArteBackend'] -class ArteBackend(BaseBackend, ICapVideo): +class ArteBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'arte' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -50,7 +51,7 @@ class ArteBackend(BaseBackend, ICapVideo): with self.browser: return self.browser.get_video(_id) - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) @@ -65,4 +66,21 @@ class ArteBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest Arte videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {ArteVideo: fill_video} diff --git a/modules/arte/browser.py b/modules/arte/browser.py index 7328befe..57938e86 100644 --- a/modules/arte/browser.py +++ b/modules/arte/browser.py @@ -36,7 +36,7 @@ class ArteBrowser(BaseBrowser): r'http://videos.arte.tv/\w+/videos/(?P.+)\.html': VideoPage } - SEARCH_LANG = {'fr': 'recherche', 'de':'suche', 'en': 'search'} + SEARCH_LANG = {'fr': 'recherche', 'de': 'suche', 'en': 'search'} def __init__(self, lang, quality, *args, **kwargs): BaseBrowser.__init__(self, *args, **kwargs) @@ -52,9 +52,11 @@ class ArteBrowser(BaseBrowser): self.location('http://videos.arte.tv/fr/videos/toutesLesVideos') def search_videos(self, pattern): - if not pattern: - self.home() - else: - self.location(self.buildurl('/%s/do_search/videos/%s' % (self.lang, self.SEARCH_LANG[self.lang]), q=pattern.encode('utf-8'))) + self.location(self.buildurl('/%s/do_search/videos/%s' % (self.lang, self.SEARCH_LANG[self.lang]), q=pattern.encode('utf-8'))) + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/arte/test.py b/modules/arte/test.py index ec9926ab..81ada165 100644 --- a/modules/arte/test.py +++ b/modules/arte/test.py @@ -19,13 +19,22 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + class ArteTest(BackendTest): BACKEND = 'arte' - def test_arte(self): + def test_search(self): l = list(self.backend.search_videos('arte')) if 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)) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + assert len(l) + 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)) diff --git a/modules/canalplus/backend.py b/modules/canalplus/backend.py index 0da5afe0..2578f36a 100644 --- a/modules/canalplus/backend.py +++ b/modules/canalplus/backend.py @@ -48,7 +48,7 @@ class CanalplusBackend(BaseBackend, ICapVideo, ICapCollection): def create_default_browser(self): return self.create_browser(quality=self.config['quality'].get()) - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) diff --git a/modules/cappedtv/backend.py b/modules/cappedtv/backend.py index a34c52c9..8a1efb3b 100644 --- a/modules/cappedtv/backend.py +++ b/modules/cappedtv/backend.py @@ -10,7 +10,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend from .browser import CappedBrowser, CappedVideo @@ -18,7 +19,7 @@ from .browser import CappedBrowser, CappedVideo __all__ = ['CappedBackend'] -class CappedBackend(BaseBackend, ICapVideo): +class CappedBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'cappedtv' MAINTAINER = 'Lord' EMAIL = 'lord@lordtoniok.com' @@ -31,7 +32,7 @@ class CappedBackend(BaseBackend, ICapVideo): with self.browser: return self.browser.get_video(_id) - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=None, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=None, max_results=None): with self.browser: return self.browser.search_videos(pattern) @@ -45,4 +46,21 @@ class CappedBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest CappedTV videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {CappedVideo: fill_video} diff --git a/modules/cappedtv/browser.py b/modules/cappedtv/browser.py index bcd38cfa..6da8a597 100644 --- a/modules/cappedtv/browser.py +++ b/modules/cappedtv/browser.py @@ -67,7 +67,7 @@ class IndexPage(BasePage): seconds = parts[0] elif len(parts) == 2: hours = 0 - minutes , seconds = parts + minutes, seconds = parts elif len(parts) == 3: hours, minutes, seconds = parts else: @@ -78,7 +78,6 @@ class IndexPage(BasePage): yield video - # parser for the video page class VideoPage(BasePage): def get_video(self, video=None): @@ -118,10 +117,12 @@ class CappedBrowser(BaseBrowser): assert self.is_on_page(VideoPage), 'Should be on video page.' return self.page.get_video(video) - def search_videos(self,pattern): - if not pattern: - self.home() - else: - self.location('/search?s=%s' % (urllib.quote_plus(pattern.encode('utf-8')))) + def search_videos(self, pattern): + self.location('/search?s=%s' % (urllib.quote_plus(pattern.encode('utf-8')))) + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/cappedtv/test.py b/modules/cappedtv/test.py index 1278b60b..01d7334c 100644 --- a/modules/cappedtv/test.py +++ b/modules/cappedtv/test.py @@ -10,18 +10,23 @@ from weboob.tools.test import BackendTest - - -__all__ = ['CappedTest'] +from weboob.capabilities.video import BaseVideo class CappedTest(BackendTest): BACKEND = 'cappedtv' - def test_capped(self): + def test_search(self): l = list(self.backend.search_videos('kewlers')) self.assertTrue(len(l) > 0) v = l[0] self.backend.fillobj(v, ('url',)) self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) self.backend.browser.openurl(v.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + self.assertTrue(len(l) > 0) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) diff --git a/modules/dailymotion/backend.py b/modules/dailymotion/backend.py index 4421cf24..616b5a91 100644 --- a/modules/dailymotion/backend.py +++ b/modules/dailymotion/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend from .browser import DailymotionBrowser @@ -30,7 +31,7 @@ from .video import DailymotionVideo __all__ = ['DailymotionBackend'] -class DailymotionBackend(BaseBackend, ICapVideo): +class DailymotionBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'dailymotion' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -44,7 +45,7 @@ class DailymotionBackend(BaseBackend, ICapVideo): return self.browser.get_video(_id) SORTBY = ['relevance', 'rated', 'visited', None] - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern, self.SORTBY[sortby]) @@ -59,4 +60,21 @@ class DailymotionBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest Dailymotion videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {DailymotionVideo: fill_video} diff --git a/modules/dailymotion/browser.py b/modules/dailymotion/browser.py index d4121a76..0674ba36 100644 --- a/modules/dailymotion/browser.py +++ b/modules/dailymotion/browser.py @@ -47,15 +47,18 @@ class DailymotionBrowser(BaseBrowser): self.location('/1') def search_videos(self, pattern, sortby): - if not pattern: - self.home() + pattern = pattern.replace('/', '').encode('utf-8') + if sortby is None: + url = '/search/%s/1' % quote_plus(pattern) else: - pattern = pattern.replace('/', '').encode('utf-8') - if sortby is None: - url = '/search/%s/1' % quote_plus(pattern) - else: - url = '/%s/search/%s/1' % (sortby, quote_plus(pattern)) - self.location(url) + url = '/%s/search/%s/1' % (sortby, quote_plus(pattern)) + self.location(url) + + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/dailymotion/test.py b/modules/dailymotion/test.py index af7a9f16..e069267f 100644 --- a/modules/dailymotion/test.py +++ b/modules/dailymotion/test.py @@ -19,14 +19,23 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + class DailymotionTest(BackendTest): BACKEND = 'dailymotion' - def test_dailymotion(self): + def test_search(self): l = list(self.backend.search_videos('chirac')) self.assertTrue(len(l) > 0) v = l[0] self.backend.fillobj(v, ('url',)) self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) self.backend.browser.openurl(v.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + assert len(l) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) diff --git a/modules/ehentai/backend.py b/modules/ehentai/backend.py index 0d9daaa7..40adb45d 100644 --- a/modules/ehentai/backend.py +++ b/modules/ehentai/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement import re -from weboob.capabilities.gallery import ICapGallery +from weboob.capabilities.gallery import ICapGallery, BaseGallery +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.misc import ratelimit from weboob.tools.value import Value, ValueBackendPassword @@ -32,7 +33,7 @@ from .gallery import EHentaiGallery, EHentaiImage __all__ = ['EHentaiBackend'] -class EHentaiBackend(BaseBackend, ICapGallery): +class EHentaiBackend(BaseBackend, ICapGallery, ICapCollection): NAME = 'ehentai' MAINTAINER = 'Roger Philibert' EMAIL = 'roger.philibert@gmail.com' @@ -53,7 +54,7 @@ class EHentaiBackend(BaseBackend, ICapGallery): password = None return self.create_browser(self.config['domain'].get(), username, password) - def search_gallery(self, pattern=None, sortby=None, max_results=None): + def search_gallery(self, pattern, sortby=None, max_results=None): with self.browser: return self.browser.search_gallery(pattern) @@ -94,6 +95,23 @@ class EHentaiBackend(BaseBackend, ICapGallery): ratelimit("ehentai_get", 2) image.data = self.browser.readurl(image.url) + def iter_resources(self, objs, split_path): + if BaseGallery in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest_nsfw']) + if collection.split_path == [u'latest_nsfw']: + for gallery in self.browser.latest_gallery(): + yield gallery + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseGallery in objs and collection.split_path == [u'latest_nsfw']: + collection.title = u'Latest E-Hentai galleries (NSFW)' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = { EHentaiGallery: fill_gallery, EHentaiImage: fill_image} diff --git a/modules/ehentai/browser.py b/modules/ehentai/browser.py index c799a8fe..d8b5e6e5 100644 --- a/modules/ehentai/browser.py +++ b/modules/ehentai/browser.py @@ -56,6 +56,11 @@ class EHentaiBrowser(BaseBrowser): assert self.is_on_page(IndexPage) return self.page.iter_galleries() + def latest_gallery(self): + self.location('/') + assert self.is_on_page(IndexPage) + return self.page.iter_galleries() + def iter_gallery_images(self, gallery): self.location(gallery.url) assert self.is_on_page(GalleryPage) diff --git a/modules/ehentai/test.py b/modules/ehentai/test.py index 9a78a66b..15979d4b 100644 --- a/modules/ehentai/test.py +++ b/modules/ehentai/test.py @@ -19,12 +19,13 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.gallery import BaseGallery class EHentaiTest(BackendTest): BACKEND = 'ehentai' - def test_ehentai(self): + def test_search(self): l = list(self.backend.search_gallery('lol')) self.assertTrue(len(l) > 0) v = l[0] @@ -36,3 +37,7 @@ class EHentaiTest(BackendTest): self.backend.fillobj(img, ('url',)) self.assertTrue(v.url and v.url.startswith('http://'), 'URL for first image in gallery "%s" not found: %s' % (v.id, img.url)) self.backend.browser.openurl(img.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseGallery], [u'latest_nsfw'])) + assert len(l) > 0 diff --git a/modules/francetelevisions/backend.py b/modules/francetelevisions/backend.py index da7e1d9b..b2f734b1 100644 --- a/modules/francetelevisions/backend.py +++ b/modules/francetelevisions/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend from .browser import PluzzBrowser @@ -30,7 +31,7 @@ from .video import PluzzVideo __all__ = ['PluzzBackend'] -class PluzzBackend(BaseBackend, ICapVideo): +class PluzzBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'francetelevisions' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -43,7 +44,7 @@ class PluzzBackend(BaseBackend, ICapVideo): with self.browser: return self.browser.get_video(_id) - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) @@ -58,4 +59,21 @@ class PluzzBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest France Télévisions videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {PluzzVideo: fill_video} diff --git a/modules/francetelevisions/browser.py b/modules/francetelevisions/browser.py index 0ca6c10d..1978c829 100644 --- a/modules/francetelevisions/browser.py +++ b/modules/francetelevisions/browser.py @@ -59,10 +59,13 @@ class PluzzBrowser(BaseBrowser): self.location('/replay/1') def search_videos(self, pattern): - if not pattern: - self.home() - else: - self.location(self.buildurl('/recherche.html', q=pattern.encode('utf-8'))) + self.location(self.buildurl('/recherche.html', q=pattern.encode('utf-8'))) + + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() @@ -79,11 +82,11 @@ class PluzzBrowser(BaseBrowser): for vid in root.find('videos'): if vid.findtext('statut') == 'ONLINE' and vid.findtext('format') == 'wmv': - video.url = vid.findtext('url') + video.url = vid.findtext('url') date = root.findtext('diffusions/diffusion') if date: - video.date = datetime.datetime.strptime(date, '%d/%m/%Y %H:%M') + video.date = datetime.datetime.strptime(date, '%d/%m/%Y %H:%M') video.description = root.findtext('synopsis') diff --git a/modules/francetelevisions/test.py b/modules/francetelevisions/test.py index d0c1896d..0d7acd29 100644 --- a/modules/francetelevisions/test.py +++ b/modules/francetelevisions/test.py @@ -19,14 +19,22 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo class PluzzTest(BackendTest): BACKEND = 'francetelevisions' - def test_francetelevisions(self): + def test_search(self): # If the test fails, it might be good news! l = list(self.backend.search_videos('Plus belle la vie')) self.assertTrue(len(l) > 0) v = l[0] self.backend.fillobj(v, ('url',)) self.assertTrue(v.url and v.url.startswith('mms://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + assert len(l) + v = l[0] + self.backend.fillobj(v, ('url',)) + assert v.url diff --git a/modules/ina/backend.py b/modules/ina/backend.py index 025d2c23..1f9a1d1b 100644 --- a/modules/ina/backend.py +++ b/modules/ina/backend.py @@ -42,7 +42,7 @@ class InaBackend(BaseBackend, ICapVideo): def get_video(self, _id): return self.browser.get_video(_id) - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) diff --git a/modules/nolifetv/backend.py b/modules/nolifetv/backend.py index 0ac0e967..ef17cf5e 100644 --- a/modules/nolifetv/backend.py +++ b/modules/nolifetv/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.value import Value, ValueBackendPassword from weboob.tools.backend import BaseBackend, BackendConfig @@ -31,7 +32,7 @@ from .video import NolifeTVVideo __all__ = ['NolifeTVBackend'] -class NolifeTVBackend(BaseBackend, ICapVideo): +class NolifeTVBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'nolifetv' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -55,7 +56,7 @@ class NolifeTVBackend(BaseBackend, ICapVideo): video = self.browser.get_video(_id) return video - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): with self.browser: return self.browser.search_videos(pattern) @@ -70,4 +71,21 @@ class NolifeTVBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest NoLiveTV videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {NolifeTVVideo: fill_video} diff --git a/modules/nolifetv/browser.py b/modules/nolifetv/browser.py index b8cb1006..827b8f91 100644 --- a/modules/nolifetv/browser.py +++ b/modules/nolifetv/browser.py @@ -70,9 +70,11 @@ class NolifeTVBrowser(BaseBrowser): return self.page.get_video(video) def search_videos(self, pattern): - if not pattern: - self.home() - else: - self.location('/index.php?', 'search=%s' % urllib.quote_plus(pattern.encode('utf-8'))) + self.location('/index.php?', 'search=%s' % urllib.quote_plus(pattern.encode('utf-8'))) + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/nolifetv/test.py b/modules/nolifetv/test.py index 8443c834..452c4b0f 100644 --- a/modules/nolifetv/test.py +++ b/modules/nolifetv/test.py @@ -19,12 +19,15 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + from .pages.video import ForbiddenVideo + class NolifeTVTest(BackendTest): BACKEND = 'nolifetv' - def test_nolife(self): + def test_search(self): l = list(self.backend.search_videos('nolife')) self.assertTrue(len(l) > 0) for v in l: @@ -35,3 +38,15 @@ class NolifeTVTest(BackendTest): else: self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) break + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + assert len(l) > 0 + for v in l: + try: + self.backend.fillobj(v, ('url',)) + except ForbiddenVideo: + continue + else: + self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) + break diff --git a/modules/youjizz/backend.py b/modules/youjizz/backend.py index aefbafb5..48592131 100644 --- a/modules/youjizz/backend.py +++ b/modules/youjizz/backend.py @@ -20,7 +20,8 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.backend import BaseBackend from .browser import YoujizzBrowser @@ -30,7 +31,7 @@ from .video import YoujizzVideo __all__ = ['YoujizzBackend'] -class YoujizzBackend(BaseBackend, ICapVideo): +class YoujizzBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'youjizz' MAINTAINER = 'Roger Philibert' EMAIL = 'roger.philibert@gmail.com' @@ -44,7 +45,7 @@ class YoujizzBackend(BaseBackend, ICapVideo): video = self.browser.get_video(_id) return video - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): if not nsfw: return set() with self.browser: @@ -61,4 +62,21 @@ class YoujizzBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest_nsfw']) + if collection.split_path == [u'latest_nsfw']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest_nsfw']: + collection.title = u'Latest Youjizz videos (NSFW)' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {YoujizzVideo: fill_video} diff --git a/modules/youjizz/browser.py b/modules/youjizz/browser.py index be78630a..cb6ce374 100644 --- a/modules/youjizz/browser.py +++ b/modules/youjizz/browser.py @@ -47,9 +47,11 @@ class YoujizzBrowser(BaseBrowser): return self.page.get_video(video) def search_videos(self, pattern): - if not pattern: - self.home() - else: - self.location('/search/%s-1.html' % (urllib.quote_plus(pattern.encode('utf-8')))) + self.location('/search/%s-1.html' % (urllib.quote_plus(pattern.encode('utf-8')))) + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/youjizz/test.py b/modules/youjizz/test.py index 5a6de6b8..a2a75848 100644 --- a/modules/youjizz/test.py +++ b/modules/youjizz/test.py @@ -19,17 +19,25 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo class YoujizzTest(BackendTest): BACKEND = 'youjizz' - def test_youjizz(self): + def test_search(self): self.assertTrue(len(self.backend.search_videos('anus', nsfw=False)) == 0) - l = list(self.backend.search_videos('sex', nsfw=True)) + l = list(self.backend.search_videos('anus', nsfw=True)) self.assertTrue(len(l) > 0) v = l[0] self.backend.fillobj(v, ('url',)) self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) self.backend.browser.openurl(v.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest_nsfw'])) + self.assertTrue(len(l) > 0) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) diff --git a/modules/youporn/backend.py b/modules/youporn/backend.py index cc6a24f0..93ef1877 100644 --- a/modules/youporn/backend.py +++ b/modules/youporn/backend.py @@ -20,8 +20,9 @@ from __future__ import with_statement -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo from weboob.tools.backend import BaseBackend +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from .browser import YoupornBrowser from .video import YoupornVideo @@ -30,7 +31,7 @@ from .video import YoupornVideo __all__ = ['YoupornBackend'] -class YoupornBackend(BaseBackend, ICapVideo): +class YoupornBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'youporn' MAINTAINER = 'Romain Bignon' EMAIL = 'romain@weboob.org' @@ -45,7 +46,7 @@ class YoupornBackend(BaseBackend, ICapVideo): SORTBY = ['relevance', 'rating', 'views', 'time'] - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): if not nsfw: return set() with self.browser: @@ -62,4 +63,21 @@ class YoupornBackend(BaseBackend, ICapVideo): return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest_nsfw']) + if collection.split_path == [u'latest_nsfw']: + for video in self.browser.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest_nsfw']: + collection.title = u'Latest YouPorn videos (NSFW)' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {YoupornVideo: fill_video} diff --git a/modules/youporn/browser.py b/modules/youporn/browser.py index 70a151ab..68630d19 100644 --- a/modules/youporn/browser.py +++ b/modules/youporn/browser.py @@ -44,9 +44,11 @@ class YoupornBrowser(BaseBrowser): return self.page.get_video(video) def search_videos(self, pattern, sortby): - if not pattern: - self.home() - else: - self.location(self.buildurl('/search/%s' % sortby, query=pattern.encode('utf-8'))) + self.location(self.buildurl('/search/%s' % sortby, query=pattern.encode('utf-8'))) + assert self.is_on_page(IndexPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() assert self.is_on_page(IndexPage) return self.page.iter_videos() diff --git a/modules/youporn/test.py b/modules/youporn/test.py index f1de56d3..e3f1bb90 100644 --- a/modules/youporn/test.py +++ b/modules/youporn/test.py @@ -19,12 +19,14 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + class YoupornTest(BackendTest): BACKEND = 'youporn' - def test_youporn(self): - self.assertTrue(len(self.backend.search_videos('penis', nsfw=False)) == 0) + def test_search(self): + self.assertTrue(len(self.backend.search_videos('ass to mouth', nsfw=False)) == 0) l = list(self.backend.search_videos('ass to mouth', nsfw=True)) self.assertTrue(len(l) > 0) @@ -32,3 +34,10 @@ class YoupornTest(BackendTest): self.backend.fillobj(v, ('url',)) self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) self.backend.browser.openurl(v.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest_nsfw'])) + self.assertTrue(len(l) > 0) + v = l[0] + self.backend.fillobj(v, ('url',)) + self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) diff --git a/modules/youtube/backend.py b/modules/youtube/backend.py index 8d3ed4a1..18961c45 100644 --- a/modules/youtube/backend.py +++ b/modules/youtube/backend.py @@ -26,7 +26,8 @@ import re import urllib from weboob.capabilities.base import NotAvailable -from weboob.capabilities.video import ICapVideo +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound from weboob.tools.capabilities.thumbnail import Thumbnail from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.misc import to_unicode @@ -39,7 +40,7 @@ from .video import YoutubeVideo __all__ = ['YoutubeBackend'] -class YoutubeBackend(BaseBackend, ICapVideo): +class YoutubeBackend(BaseBackend, ICapVideo, ICapCollection): NAME = 'youtube' MAINTAINER = 'Christophe Benz' EMAIL = 'christophe.benz@gmail.com' @@ -110,7 +111,7 @@ class YoutubeBackend(BaseBackend, ICapVideo): video.set_empty_fields(NotAvailable) return video - def search_videos(self, pattern=None, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False, max_results=None): YOUTUBE_MAX_RESULTS = 50 YOUTUBE_MAX_START_INDEX = 1000 yt_service = gdata.youtube.service.YouTubeService() @@ -144,6 +145,9 @@ class YoutubeBackend(BaseBackend, ICapVideo): if nb_yielded == max_results: return + def latest_videos(self): + return self.search_videos(None, ICapVideo.SEARCH_DATE) + def fill_video(self, video, fields): if 'thumbnail' in fields: video.thumbnail.data = urllib.urlopen(video.thumbnail.url).read() @@ -151,4 +155,21 @@ class YoutubeBackend(BaseBackend, ICapVideo): self._set_video_url(video) return video + def iter_resources(self, objs, split_path): + if BaseVideo in objs: + collection = self.get_collection(objs, split_path) + if collection.path_level == 0: + yield self.get_collection(objs, [u'latest']) + if collection.split_path == [u'latest']: + for video in self.latest_videos(): + yield video + + def validate_collection(self, objs, collection): + if collection.path_level == 0: + return + if BaseVideo in objs and collection.split_path == [u'latest']: + collection.title = u'Latest YouTube videos' + return + raise CollectionNotFound(collection.split_path) + OBJECTS = {YoutubeVideo: fill_video} diff --git a/modules/youtube/test.py b/modules/youtube/test.py index 6fb87037..d1373627 100644 --- a/modules/youtube/test.py +++ b/modules/youtube/test.py @@ -19,11 +19,13 @@ from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + class YoutubeTest(BackendTest): BACKEND = 'youtube' - def test_youtube(self): + def test_search(self): l = list(self.backend.search_videos('lol')) self.assertTrue(len(l) > 0) v = l[0] @@ -31,3 +33,7 @@ class YoutubeTest(BackendTest): self.assertTrue(v.url and v.url.startswith('http://'), 'URL for video "%s" not found: %s' % (v.id, v.url)) assert self.backend.get_video(v.shorturl) self.backend.browser.openurl(v.url) + + def test_latest(self): + l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) + assert len(l) > 0 diff --git a/weboob/applications/galleroob/galleroob.py b/weboob/applications/galleroob/galleroob.py index 1e0b0c36..9e3ab32e 100644 --- a/weboob/applications/galleroob/galleroob.py +++ b/weboob/applications/galleroob/galleroob.py @@ -25,7 +25,7 @@ from re import search, sub from weboob.tools.application.repl import ReplApplication from weboob.capabilities.base import NotLoaded -from weboob.capabilities.gallery import ICapGallery +from weboob.capabilities.gallery import ICapGallery, BaseGallery, BaseImage from weboob.tools.application.formatters.iformatter import IFormatter @@ -60,22 +60,23 @@ class Galleroob(ReplApplication): DESCRIPTION = 'galleroob browses and downloads web image galleries' CAPS = ICapGallery EXTRA_FORMATTERS = {'gallery_list': GalleryListFormatter} - COMMANDS_FORMATTERS = {'search': 'gallery_list'} + COMMANDS_FORMATTERS = {'search': 'gallery_list', 'ls': 'gallery_list'} + COLLECTION_OBJECTS = (BaseGallery, BaseImage, ) def __init__(self, *args, **kwargs): ReplApplication.__init__(self, *args, **kwargs) - def do_search(self, pattern=None): + def do_search(self, pattern): """ search PATTERN List galleries matching a PATTERN. - - If PATTERN is not given, the command will list all the galleries """ + if not pattern: + print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('search', short=True) + return 2 - self.set_formatter_header(u'Search pattern: %s' % - pattern if pattern else u'Latest galleries') + self.set_formatter_header(u'Search pattern: %s' % pattern) for backend, gallery in self.do('search_gallery', pattern=pattern, max_results=self.options.count): self.add_object(gallery) diff --git a/weboob/applications/videoob/videoob.py b/weboob/applications/videoob/videoob.py index 4d6dd053..6e865a11 100644 --- a/weboob/applications/videoob/videoob.py +++ b/weboob/applications/videoob/videoob.py @@ -94,7 +94,7 @@ class Videoob(ReplApplication): _id, dest = self.parse_command_args(line, 2, 1) video = self.get_object(_id, 'get_video', ['url']) if not video: - print >>sys.stderr, 'Video not found: %s' % _id + print >>sys.stderr, 'Video not found: %s' % _id return 3 if not video.url: @@ -109,7 +109,6 @@ class Videoob(ReplApplication): return False return True - if dest is None: ext = video.ext if not ext: @@ -148,7 +147,7 @@ class Videoob(ReplApplication): video = self.get_object(_id, 'get_video', ['url']) if not video: - print >>sys.stderr, 'Video not found: %s' % _id + print >>sys.stderr, 'Video not found: %s' % _id return 3 if not video.url: print >>sys.stderr, 'Error: the direct URL is not available.' @@ -179,7 +178,7 @@ class Videoob(ReplApplication): video = self.get_object(_id, 'get_video') if not video: - print >>sys.stderr, 'Video not found: %s' % _id + print >>sys.stderr, 'Video not found: %s' % _id return 3 self.format(video) self.flush() @@ -207,22 +206,17 @@ class Videoob(ReplApplication): else: print "on" if self.nsfw else "off" - def do_search(self, pattern=None): + def do_search(self, pattern): """ - search [PATTERN] + search PATTERN Search for videos matching a PATTERN. - - If PATTERN is not given, this command will search for the latest videos. """ - if len(self.enabled_backends) == 0: - if self.interactive: - print >>sys.stderr, 'No backend loaded. Please use the "backends" command.' - else: - print >>sys.stderr, 'No backend loaded.' - return 1 + if not pattern: + print >>sys.stderr, 'This command takes an argument: %s' % self.get_command_help('search', short=True) + return 2 - self.set_formatter_header(u'Search pattern: %s' % pattern if pattern else u'Latest videos') + self.set_formatter_header(u'Search pattern: %s' % pattern) self.change_path([u'search']) for backend, video in self.do('search_videos', pattern=pattern, nsfw=self.nsfw, max_results=self.options.count): diff --git a/weboob/capabilities/gallery.py b/weboob/capabilities/gallery.py index afe3f652..1f3e50b0 100644 --- a/weboob/capabilities/gallery.py +++ b/weboob/capabilities/gallery.py @@ -39,8 +39,8 @@ class BaseGallery(CapBaseObject): self.add_field('description', basestring) self.add_field('cardinality', int) self.add_field('date', datetime, date) - self.add_field('rating', (int,long,float), rating) - self.add_field('rating_max', (int,long,float), rating_max) + self.add_field('rating', (int, long, float), rating) + self.add_field('rating_max', (int, long, float), rating_max) self.add_field('thumbnail', Thumbnail, thumbnail) @classmethod @@ -55,13 +55,14 @@ class BaseGallery(CapBaseObject): def iter_image(self): raise NotImplementedError() + class BaseImage(CapBaseObject): def __init__(self, _id, index=None, thumbnail=NotLoaded, url=NotLoaded, ext=NotLoaded, gallery=None): CapBaseObject.__init__(self, unicode(_id)) - self.add_field('index', int, index) # usually page number + self.add_field('index', int, index) # usually page number self.add_field('thumbnail', Thumbnail, thumbnail) self.add_field('url', basestring, url) self.add_field('ext', basestring, ext) @@ -77,6 +78,7 @@ class BaseImage(CapBaseObject): def __iscomplete__(self): return self.data is not NotLoaded + class ICapGallery(IBaseCap): """ This capability represents the ability for a website backend to provide videos. @@ -86,10 +88,9 @@ class ICapGallery(IBaseCap): SEARCH_VIEWS, SEARCH_DATE) = range(4) - def search_gallery(self, pattern=None, sortby=SEARCH_RELEVANCE, max_results=None): + def search_gallery(self, pattern, sortby=SEARCH_RELEVANCE, max_results=None): """ - Iter results of a search on a pattern. Note that if pattern is None, - it get the latest videos. + Iter results of a search on a pattern. @param pattern [str] pattern to search on @param sortby [enum] sort by... diff --git a/weboob/capabilities/video.py b/weboob/capabilities/video.py index fb77d986..6359b8ea 100644 --- a/weboob/capabilities/video.py +++ b/weboob/capabilities/video.py @@ -66,10 +66,9 @@ class ICapVideo(IBaseCap): SEARCH_VIEWS, SEARCH_DATE) = range(4) - def search_videos(self, pattern=None, sortby=SEARCH_RELEVANCE, nsfw=False, max_results=None): + def search_videos(self, pattern, sortby=SEARCH_RELEVANCE, nsfw=False, max_results=None): """ - Iter results of a search on a pattern. Note that if pattern is None, - it get the latest videos. + Iter results of a search on a pattern. @param pattern [str] pattern to search on @param sortby [enum] sort by...