Move the "empty search for latest" to collections

There is now a "latest" collection (or "latest_nsfw").
The feature didn't look much used, since it didn't work on many
backends.
Using collections will make it easy to support other things
like most viewed, featured, etc.
As a bonus, I added tests for every backend with the feature.
This commit is contained in:
Laurent Bachelier 2012-03-16 02:55:58 +01:00
commit e958c229e6
32 changed files with 366 additions and 112 deletions

View file

@ -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}

View file

@ -36,7 +36,7 @@ class ArteBrowser(BaseBrowser):
r'http://videos.arte.tv/\w+/videos/(?P<id>.+)\.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()

View file

@ -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))

View file

@ -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)

View file

@ -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}

View file

@ -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()

View file

@ -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))

View file

@ -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}

View file

@ -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()

View file

@ -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))

View file

@ -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}

View file

@ -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)

View file

@ -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

View file

@ -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}

View file

@ -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')

View file

@ -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

View file

@ -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)

View file

@ -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}

View file

@ -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()

View file

@ -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

View file

@ -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}

View file

@ -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()

View file

@ -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))

View file

@ -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}

View file

@ -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()

View file

@ -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))

View file

@ -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}

View file

@ -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

View file

@ -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)

View file

@ -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):

View file

@ -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...

View file

@ -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...