From 965da2562e5a9db4b7f7c3740dd3c533c816e11f Mon Sep 17 00:00:00 2001 From: Roger Philibert Date: Fri, 15 Nov 2013 13:02:16 +0100 Subject: [PATCH] add module jacquieetmichel --- AUTHORS | 2 +- modules/jacquieetmichel/__init__.py | 22 ++++++++ modules/jacquieetmichel/backend.py | 80 ++++++++++++++++++++++++++++ modules/jacquieetmichel/browser.py | 54 +++++++++++++++++++ modules/jacquieetmichel/favicon.png | Bin 0 -> 1112 bytes modules/jacquieetmichel/pages.py | 75 ++++++++++++++++++++++++++ modules/jacquieetmichel/test.py | 43 +++++++++++++++ modules/jacquieetmichel/video.py | 35 ++++++++++++ 8 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 modules/jacquieetmichel/__init__.py create mode 100644 modules/jacquieetmichel/backend.py create mode 100644 modules/jacquieetmichel/browser.py create mode 100644 modules/jacquieetmichel/favicon.png create mode 100644 modules/jacquieetmichel/pages.py create mode 100644 modules/jacquieetmichel/test.py create mode 100644 modules/jacquieetmichel/video.py diff --git a/AUTHORS b/AUTHORS index 58a0bd94a2..324052cde9 100644 --- a/AUTHORS +++ b/AUTHORS @@ -40,7 +40,7 @@ Christophe Benz * Bouygues, INA, SFR and Youtube modules maintainer. Roger Philibert - * Ehentai, Izneo, OKC and Youjizz modules maintainer. + * Ehentai, Izneo, JacquieEtMichel, OKC and Youjizz modules maintainer. Nicolas Duhamel * BP, CanalPlus and Orange modules maintainer. diff --git a/modules/jacquieetmichel/__init__.py b/modules/jacquieetmichel/__init__.py new file mode 100644 index 0000000000..88ea550b84 --- /dev/null +++ b/modules/jacquieetmichel/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 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 . + +from .backend import JacquieEtMichelBackend + +__all__ = ['JacquieEtMichelBackend'] diff --git a/modules/jacquieetmichel/backend.py b/modules/jacquieetmichel/backend.py new file mode 100644 index 0000000000..cb83b7f0cc --- /dev/null +++ b/modules/jacquieetmichel/backend.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# 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 . + +from weboob.capabilities.video import ICapVideo, BaseVideo +from weboob.capabilities.collection import ICapCollection, CollectionNotFound +from weboob.tools.backend import BaseBackend + +from .browser import JacquieEtMichelBrowser +from .video import JacquieEtMichelVideo + + +__all__ = ['JacquieEtMichelBackend'] + + +class JacquieEtMichelBackend(BaseBackend, ICapVideo, ICapCollection): + NAME = 'jacquieetmichel' + MAINTAINER = u'Roger Philibert' + EMAIL = 'roger.philibert@gmail.com' + VERSION = '0.h' + DESCRIPTION = 'Jacquie et Michel TV' + LICENSE = 'AGPLv3+' + BROWSER = JacquieEtMichelBrowser + + def get_video(self, _id): + with self.browser: + video = self.browser.get_video(_id) + return video + + def search_videos(self, pattern, sortby=ICapVideo.SEARCH_RELEVANCE, nsfw=False): + if not nsfw: + return iter([]) + + with self.browser: + return self.browser.search_videos(pattern) + + 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(JacquieEtMichelVideo.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 + + 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 Jacquie & Michel videos (NSFW)' + return + raise CollectionNotFound(collection.split_path) + + OBJECTS = {JacquieEtMichelVideo: fill_video} diff --git a/modules/jacquieetmichel/browser.py b/modules/jacquieetmichel/browser.py new file mode 100644 index 0000000000..238837ebe2 --- /dev/null +++ b/modules/jacquieetmichel/browser.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# 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 . + +import urllib + +from weboob.tools.browser import BaseBrowser +from weboob.tools.browser.decorators import id2url + +from .video import JacquieEtMichelVideo +from .pages import VideoPage, ResultsPage + + +__all__ = ['JacquieEtMichelBrowser'] + + +class JacquieEtMichelBrowser(BaseBrowser): + DOMAIN = u'jacquieetmicheltv.net' + ENCODING = None + PAGES = {r'https?://.*jacquieetmicheltv.net/': ResultsPage, + r'https?://.*jacquieetmicheltv.net/videolist/.*': ResultsPage, + r'https?://.*jacquieetmicheltv.net/showvideo/(?P\d+)/.*': VideoPage, + } + + @id2url(JacquieEtMichelVideo.id2url) + def get_video(self, url, video=None): + self.location(url) + assert self.is_on_page(VideoPage), 'Should be on video page.' + return self.page.get_video(video) + + def search_videos(self, pattern): + self.location('/videolist/searchmodevideo/query%s/' % (urllib.quote(pattern.encode('utf-8')))) + assert self.is_on_page(ResultsPage) + return self.page.iter_videos() + + def latest_videos(self): + self.home() + assert self.is_on_page(ResultsPage) + return self.page.iter_videos() diff --git a/modules/jacquieetmichel/favicon.png b/modules/jacquieetmichel/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..cb8548498dcbd0b26e12b255770a7c0a4d1ee03c GIT binary patch literal 1112 zcmV-e1gHCnP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00Y2DL_t(|+U=N6XdHDE$3HEB zNNN!pu~N{3*vqzh7d-?$coEj4podZ~{sRS1dQ=oa@n94WJ$TS43ZA@3mkmo*jBH1< z#<D2k#e zilQirq9}@@D2k$Vkgls2M}hM|0dN5WYy+2o*MR#5^ee#gJ;uCnz_{TANVtK?CV{WB z*{t}!FJTz&xth&pKMRsHK@bS=bB{4gK@jX2*UR6;h@<6|d_Mo^%*+gN9J9K*isLx= zzE38TA(P1rJn_WD1U7me1istHJ|(}170yU{ft9dWd5 zcUCk#4e;0~CT+LdL{W4(j$_u=)@}jLb(x&2R;!b791}%RvE6QuEd@SJBES}{E#U59 z{W^{#g+k%!VzDU37y*7u*&P9{7-OVZEJ~qJIPW;lSW@5^@R>2D6SnnwU4Y+#J4fJm z3fQ%2Ai%@c?hznK57*k=bOG)Gel3+s*X3-jRukYC;PwOd_^m$t&NiD(X|-Acd~WZ3 z(Q37lE%vsKA-Q1u(7crz>mOf={bGh7vN$ae$S@9 zc4&8&FclSN#v#BP)oL{z@*mlT=&Q5{l}bf`?}1yBm#9{&V!O9~{C;bUkw&8-uIsKf z8jYkbd^2F(8d`uWN#R>sS`y$?sw=$cI8H}|<>h5rSXd~O%jKj_uKPAAC zWU|zv_v19MI6FHlzVCNlG~EzYDwW#$`ubmuMx$GVxBkrn+?7mb!*;jFuk{namq68~ zLIC^$T(G;t8Q|(Z2Nti7;2>sHWA~o0)a!K-5edUkfS(S_G1w{K8Q@wF1nHLc%|mkr zxV5z<$?=lyv$t)*`~M4IjFB)5#rJ(#Sy>TV$sagOr@#SF19HGish=1{Q4~c{6h%=K eMNyRhJbwc}_M)jBgIIw80000. + + +import re + +from weboob.capabilities.base import NotAvailable +from weboob.tools.capabilities.thumbnail import Thumbnail +from weboob.tools.browser import BasePage, BrokenPageError +from weboob.tools.misc import to_unicode + +from .video import JacquieEtMichelVideo + + +__all__ = ['ResultsPage', 'VideoPage'] + + +class ResultsPage(BasePage): + def iter_videos(self): + for span in self.document.xpath('//ul[@id="list"]/li'): + a = self.parser.select(span, 'a', 1) + url = a.attrib['href'] + _id = re.sub(r'/showvideo/(\d+)/.*', r'\1', url) + + video = JacquieEtMichelVideo(_id) + + video.thumbnail = Thumbnail(unicode(span.find('.//img').attrib['src'])) + + title_el = self.parser.select(span, 'h2', 1) + video.title = to_unicode(title_el.text.strip()) + video.description = self.parser.tocleanstring(span.xpath('.//div[@class="desc"]')[0]) + video.set_empty_fields(NotAvailable, ('url,')) + + yield video + + +class VideoPage(BasePage): + def get_video(self, video=None): + _id = to_unicode(self.group_dict['id']) + if video is None: + video = JacquieEtMichelVideo(_id) + title_el = self.parser.select(self.document.getroot(), 'h1', 1) + video.title = to_unicode(title_el.text.strip()) + video.description = self.document.xpath('//meta[@name="description"]')[0].attrib['content'] + + for script in self.document.xpath('.//script'): + if script.text is None: + continue + m = re.search('"(http://[^"]+.mp4)"', script.text, re.MULTILINE) + if m: + video.url = to_unicode(m.group(1)) + break + + if not video.url: + raise BrokenPageError('Unable to find URL') + + video.set_empty_fields(NotAvailable) + + return video diff --git a/modules/jacquieetmichel/test.py b/modules/jacquieetmichel/test.py new file mode 100644 index 0000000000..cc3162c059 --- /dev/null +++ b/modules/jacquieetmichel/test.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# 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 . + + +from weboob.tools.test import BackendTest +from weboob.capabilities.video import BaseVideo + + +class JacquieEtMichelTest(BackendTest): + BACKEND = 'jacquieetmichel' + + def test_search(self): + self.assertTrue(len(list(self.backend.search_videos('anus', nsfw=False))) == 0) + + 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/jacquieetmichel/video.py b/modules/jacquieetmichel/video.py new file mode 100644 index 0000000000..5dc52139a9 --- /dev/null +++ b/modules/jacquieetmichel/video.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2013 Roger Philibert +# +# 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 . + + +from weboob.capabilities.video import BaseVideo + + +__all__ = ['JacquieEtMichelVideo'] + + +class JacquieEtMichelVideo(BaseVideo): + def __init__(self, *args, **kwargs): + BaseVideo.__init__(self, *args, **kwargs) + self.ext = u'mp4' + self.nsfw = True + + @classmethod + def id2url(cls, _id): + return 'http://jacquieetmicheltv.net/showvideo/%s/t/' % _id -- GitLab