diff --git a/modules/arretsurimages/__init__.py b/modules/arretsurimages/__init__.py deleted file mode 100644 index 8bbfde674c03be46120d6910a520f05a2fc563f8..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 franek -# -# 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 .module import ArretSurImagesModule - - -__all__ = ['ArretSurImagesModule'] diff --git a/modules/arretsurimages/browser.py b/modules/arretsurimages/browser.py deleted file mode 100644 index 789681528db8dca082a8dd6dcd9df3975889ee88..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/browser.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 franek -# -# 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.deprecated.browser import Browser, BrowserIncorrectPassword -from weboob.deprecated.browser.decorators import id2url - -from .pages import VideoPage, IndexPage, LoginPage, LoginRedirectPage -from .video import ArretSurImagesVideo - - -__all__ = ['ArretSurImagesBrowser'] - - -class ArretSurImagesBrowser(Browser): - PROTOCOL = 'http' - DOMAIN = 'www.arretsurimages.net' - ENCODING = None - - PAGES = { - '%s://%s/contenu.php\?id=.+' % (PROTOCOL, DOMAIN): VideoPage, - '%s://%s/emissions.php' % (PROTOCOL, DOMAIN): IndexPage, - '%s://%s/forum/login.php' % (PROTOCOL, DOMAIN): LoginPage, - '%s://%s/forum/index.php' % (PROTOCOL, DOMAIN): LoginRedirectPage, - } - - def home(self): - self.location('http://www.arretsurimages.net') - - def search_videos(self, pattern): - self.location(self.buildurl('/emissions.php')) - assert self.is_on_page(IndexPage) - return self.page.iter_videos(pattern) - - @id2url(ArretSurImagesVideo.id2url) - def get_video(self, url, video=None): - self.login() - self.location(url) - return self.page.get_video(video) - - def is_logged(self): - return not self.is_on_page(LoginPage) - - def login(self): - if not self.is_on_page(LoginPage): - self.location('http://www.arretsurimages.net/forum/login.php', no_login=True) - - self.page.login(self.username, self.password) - - if not self.is_logged(): - raise BrowserIncorrectPassword() - - def latest_videos(self): - self.location(self.buildurl('/emissions.php')) - assert self.is_on_page(IndexPage) - return self.page.iter_videos() diff --git a/modules/arretsurimages/favicon.png b/modules/arretsurimages/favicon.png deleted file mode 100644 index 737fd80a21ae9738c3e5b4b8a21fedfafedd8651..0000000000000000000000000000000000000000 Binary files a/modules/arretsurimages/favicon.png and /dev/null differ diff --git a/modules/arretsurimages/module.py b/modules/arretsurimages/module.py deleted file mode 100644 index 052bb9e83df1336d340436ce86bff2acad098eb1..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/module.py +++ /dev/null @@ -1,85 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 franek -# -# 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 CapVideo, BaseVideo -from weboob.capabilities.collection import CapCollection, CollectionNotFound -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword - -from .browser import ArretSurImagesBrowser -from .video import ArretSurImagesVideo - -__all__ = ['ArretSurImagesModule'] - - -class ArretSurImagesModule(Module, CapVideo, CapCollection): - NAME = 'arretsurimages' - DESCRIPTION = u'arretsurimages website' - MAINTAINER = u'franek' - EMAIL = 'franek@chicour.net' - VERSION = '1.4' - - CONFIG = BackendConfig(ValueBackendPassword('login', label='email', masked=False), - ValueBackendPassword('password', label='Password')) - BROWSER = ArretSurImagesBrowser - - def create_default_browser(self): - return self.create_browser(self.config['login'].get(), self.config['password'].get(), get_home=False) - - def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False): - with self.browser: - return self.browser.search_videos(pattern) -# raise UserError('Search does not work on ASI website, use ls latest command') - - def get_video(self, _id): - if _id.startswith('http://') and not _id.startswith('http://www.arretsurimages.net'): - return None - 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(ArretSurImagesVideo.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']) - 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 ArretSurImages videos' - return - raise CollectionNotFound(collection.split_path) - - OBJECTS = {ArretSurImagesVideo: fill_video} diff --git a/modules/arretsurimages/pages.py b/modules/arretsurimages/pages.py deleted file mode 100644 index 7d4f39bcb7fb3e6887f3ad3696743a14b37a6363..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/pages.py +++ /dev/null @@ -1,126 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 franek -# -# 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 re - -from weboob.capabilities.base import UserError -from weboob.capabilities.image import Thumbnail -from weboob.deprecated.browser import Page, BrokenPageError -from weboob.capabilities import NotAvailable - - -from .video import ArretSurImagesVideo - - -class IndexPage(Page): - def iter_videos(self, pattern=None): - videos = self.document.getroot().cssselect("div[class=bloc-contenu-8]") - for div in videos: - title = self.parser.select(div, 'h1', 1).text_content().replace(' ', ' ') - if pattern: - if pattern.upper() not in title.upper(): - continue - m = re.match(r'/contenu.php\?id=(.*)', div.find('a').attrib['href']) - _id = '' - if m: - _id = m.group(1) - - video = ArretSurImagesVideo(_id) - video.title = unicode(title) - video.rating = None - video.rating_max = None - - thumb = self.parser.select(div, 'img', 1) - url = u'http://www.arretsurimages.net' + thumb.attrib['src'] - video.thumbnail = Thumbnail(url) - video.thumbnail.url = video.thumbnail.id - - yield video - - -class ForbiddenVideo(UserError): - pass - - -class VideoPage(Page): - def is_logged(self): - try: - self.parser.select(self.document.getroot(), '#user-info', 1) - except BrokenPageError: - return False - else: - return True - - def on_loaded(self): - if not self.is_logged(): - raise ForbiddenVideo('This video or group may contain content that is inappropriate for some users') - - def get_video(self, video=None): - if not video: - video = ArretSurImagesVideo(self.get_id()) - video.title = unicode(self.get_title()) - video.url = unicode(self.get_url()) - video.set_empty_fields(NotAvailable) - return video - - def get_firstUrl(self): - obj = self.parser.select(self.document.getroot(), 'a.bouton-telecharger', 1) - firstUrl = obj.attrib['href'] - return firstUrl - - def get_title(self): - title = self.document.getroot().cssselect('div[id=titrage-contenu] h1')[0].text - return title - - def get_id(self): - m = re.match(r'http://videos.arretsurimages.net/telecharger/(.*)', self.get_firstUrl()) - if m: - return m.group(1) - self.logger.warning('Unable to parse ID') - return 0 - - def get_url(self): - firstUrl = self.get_firstUrl() - doc = self.browser.get_document(self.browser.openurl(firstUrl)) - links = doc.xpath('//a') - url = None - i = 1 - for link in links: - # we take the second link of the page - if i == 2: - url = link.attrib['href'] - i += 1 - return url - - -class LoginPage(Page): - def login(self, username, password): - response = self.browser.response() - response.set_data(response.get_data().replace("
", "
")) # Python mechanize is broken, fixing it. - self.browser.set_response(response) - self.browser.select_form(nr=0) - self.browser.form.set_all_readonly(False) - self.browser['redir'] = '/forum/index.php' - self.browser['username'] = username - self.browser['password'] = password - self.browser.submit() - - -class LoginRedirectPage(Page): - pass diff --git a/modules/arretsurimages/test.py b/modules/arretsurimages/test.py deleted file mode 100644 index 01d37ad8a4ba556d29fa5f200f5963ac2948242c..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/test.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 franek -# -# 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 -from weboob.tools.test import BackendTest, SkipTest - - -class ArretSurImagesTest(BackendTest): - MODULE = 'arretsurimages' - - def test_latest_arretsurimages(self): - l = list(self.backend.iter_resources([BaseVideo], [u'latest'])) - assert len(l) - if self.backend.browser.username != u'None': - v = l[0] - self.backend.fillobj(v, ('url',)) - self.assertTrue(v.url, 'URL for video "%s" not found' % (v.id)) - else: - raise SkipTest("User credentials not defined") diff --git a/modules/arretsurimages/video.py b/modules/arretsurimages/video.py deleted file mode 100644 index 1721674a9c19ac940acd8e0410938260eee99915..0000000000000000000000000000000000000000 --- a/modules/arretsurimages/video.py +++ /dev/null @@ -1,27 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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 - - -class ArretSurImagesVideo(BaseVideo): - @classmethod - def id2url(cls, _id): - return 'http://www.arretsurimages.net/contenu.php?id=%s' % _id diff --git a/modules/attilasub/__init__.py b/modules/attilasub/__init__.py deleted file mode 100644 index 257e85bcaf4a3e47b1ef2565e8de7f80d5434f3c..0000000000000000000000000000000000000000 --- a/modules/attilasub/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Julien Veyssier -# -# 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 .module import AttilasubModule - -__all__ = ['AttilasubModule'] diff --git a/modules/attilasub/browser.py b/modules/attilasub/browser.py deleted file mode 100644 index f16db679eaec5db675206655e421a26eef0b066a..0000000000000000000000000000000000000000 --- a/modules/attilasub/browser.py +++ /dev/null @@ -1,52 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Julien Veyssier -# -# 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.deprecated.browser import Browser, BrowserHTTPNotFound - -from .pages import SubtitlesPage, SearchPage - - -__all__ = ['AttilasubBrowser'] - - -class AttilasubBrowser(Browser): - DOMAIN = 'davidbillemont3.free.fr' - PROTOCOL = 'http' - ENCODING = 'windows-1252' - USER_AGENT = Browser.USER_AGENTS['wget'] - PAGES = { - 'http://search.freefind.com/find.html.*': SearchPage, - 'http://davidbillemont3.free.fr/.*.htm': SubtitlesPage, - } - - def iter_subtitles(self, language, pattern): - self.location('http://search.freefind.com/find.html?id=81131980&_charset_=&bcd=%%F7&scs=1&pageid=r&query=%s&mode=Find%%20pages%%20matching%%20ALL%%20words' % - pattern.encode('utf-8')) - assert self.is_on_page(SearchPage) - return self.page.iter_subtitles(language, pattern) - - def get_subtitle(self, id): - url_end = id.split('|')[0] - try: - self.location('http://davidbillemont3.free.fr/%s' % url_end) - except BrowserHTTPNotFound: - return - if self.is_on_page(SubtitlesPage): - return self.page.get_subtitle(id) diff --git a/modules/attilasub/favicon.png b/modules/attilasub/favicon.png deleted file mode 100644 index bca3347873846503755116ca28faa3582aba6784..0000000000000000000000000000000000000000 Binary files a/modules/attilasub/favicon.png and /dev/null differ diff --git a/modules/attilasub/module.py b/modules/attilasub/module.py deleted file mode 100644 index 5f1c6d4f13a37451fa8b9822737f5120f06f88cd..0000000000000000000000000000000000000000 --- a/modules/attilasub/module.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Julien Veyssier -# -# 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.subtitle import CapSubtitle, LanguageNotSupported -from weboob.tools.backend import Module -from weboob.tools.compat import quote_plus - -from .browser import AttilasubBrowser - - -__all__ = ['AttilasubModule'] - - -class AttilasubModule(Module, CapSubtitle): - NAME = 'attilasub' - MAINTAINER = u'Julien Veyssier' - EMAIL = 'julien.veyssier@aiur.fr' - VERSION = '1.4' - DESCRIPTION = '"Attila\'s Website 2.0" French subtitles' - LICENSE = 'AGPLv3+' - LANGUAGE_LIST = ['fr'] - BROWSER = AttilasubBrowser - - def get_subtitle(self, id): - return self.browser.get_subtitle(id) - - def get_subtitle_file(self, id): - subtitle = self.browser.get_subtitle(id) - if not subtitle: - return None - - return self.browser.openurl(subtitle.url.encode('utf-8')).read() - - def iter_subtitles(self, language, pattern): - if language not in self.LANGUAGE_LIST: - raise LanguageNotSupported() - return self.browser.iter_subtitles(language, quote_plus(pattern.encode('utf-8'))) diff --git a/modules/attilasub/pages.py b/modules/attilasub/pages.py deleted file mode 100644 index 7d590c79f92e29da0d0131f8f9f1a5b8fd74abda..0000000000000000000000000000000000000000 --- a/modules/attilasub/pages.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Julien Veyssier -# -# 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.subtitle import Subtitle -from weboob.capabilities.base import NotAvailable -from weboob.deprecated.browser import Page - - -class SearchPage(Page): - def iter_subtitles(self, language, pattern): - fontresult = self.parser.select(self.document.getroot(), 'div.search-results font.search-results') - # for each result in freefind, explore the subtitle list page to iter subtitles - for res in fontresult: - a = self.parser.select(res, 'a', 1) - url = a.attrib.get('href', '') - self.browser.location(url) - assert self.browser.is_on_page(SubtitlesPage) - # subtitles page does the job - for subtitle in self.browser.page.iter_subtitles(language, pattern): - yield subtitle - - -class SubtitlesPage(Page): - def get_subtitle(self, id): - href = id.split('|')[1] - # we have to find the 'tr' which contains the link to this address - a = self.parser.select(self.document.getroot(), 'a[href="%s"]' % href, 1) - line = a.getparent().getparent().getparent().getparent().getparent() - cols = self.parser.select(line, 'td') - traduced_title = self.parser.select(cols[0], 'font', 1).text.lower() - original_title = self.parser.select(cols[1], 'font', 1).text.lower() - nb_cd = self.parser.select(cols[2], 'font', 1).text.strip() - nb_cd = int(nb_cd.split()[0]) - - traduced_title_words = traduced_title.split() - original_title_words = original_title.split() - - # this is to trash special spacing chars - traduced_title = " ".join(traduced_title_words) - original_title = " ".join(original_title_words) - - name = unicode('%s (%s)' % (original_title, traduced_title)) - url = unicode('http://davidbillemont3.free.fr/%s' % href) - subtitle = Subtitle(id, name) - subtitle.url = url - subtitle.ext = url.split('.')[-1] - subtitle.language = unicode('fr') - subtitle.nb_cd = nb_cd - subtitle.description = NotAvailable - return subtitle - - def iter_subtitles(self, language, pattern): - pattern = pattern.strip().replace('+', ' ').lower() - pattern_words = pattern.split() - tab = self.parser.select(self.document.getroot(), 'table[bordercolor="#B8C0B2"]') - if len(tab) == 0: - tab = self.parser.select(self.document.getroot(), 'table[bordercolordark="#B8C0B2"]') - if len(tab) == 0: - return - # some results of freefind point on useless pages - if tab[0].attrib.get('width', '') != '100%': - return - for line in tab[0].getiterator('tr'): - cols = self.parser.select(line, 'td') - traduced_title = self.parser.select(cols[0], 'font', 1).text.lower() - original_title = self.parser.select(cols[1], 'font', 1).text.lower() - - traduced_title_words = traduced_title.split() - original_title_words = original_title.split() - - # if the pattern is one word and in the title OR if the - # intersection between pattern and the title is at least 2 words - if (len(pattern_words) == 1 and pattern in traduced_title_words) or\ - (len(pattern_words) == 1 and pattern in original_title_words) or\ - (len(list(set(pattern_words) & set(traduced_title_words))) > 1) or\ - (len(list(set(pattern_words) & set(original_title_words))) > 1): - - # this is to trash special spacing chars - traduced_title = " ".join(traduced_title_words) - original_title = " ".join(original_title_words) - - nb_cd = self.parser.select(cols[2], 'font', 1).text.strip() - nb_cd = int(nb_cd.strip(' CD')) - name = unicode('%s (%s)' % (original_title, traduced_title)) - href = self.parser.select(cols[3], 'a', 1).attrib.get('href', '') - url = unicode('http://davidbillemont3.free.fr/%s' % href) - id = unicode('%s|%s' % (self.browser.geturl().split('/')[-1], href)) - subtitle = Subtitle(id, name) - subtitle.url = url - subtitle.ext = url.split('.')[-1] - subtitle.language = unicode('fr') - subtitle.nb_cd = nb_cd - subtitle.description = NotAvailable - yield subtitle diff --git a/modules/attilasub/test.py b/modules/attilasub/test.py deleted file mode 100644 index 2d720f5f3d3bb320da89deb3146600e98609baa5..0000000000000000000000000000000000000000 --- a/modules/attilasub/test.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Julien Veyssier -# -# 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 - -import urllib -from random import choice - - -class AttilasubTest(BackendTest): - MODULE = 'attilasub' - - def test_subtitle(self): - subtitles = list(self.backend.iter_subtitles('fr', 'spiderman')) - assert (len(subtitles) > 0) - for subtitle in subtitles: - path, qs = urllib.splitquery(subtitle.url) - assert path.endswith('.rar') - - # get the file of a random sub - if len(subtitles): - subtitle = choice(subtitles) - self.backend.get_subtitle_file(subtitle.id) diff --git a/modules/cappedtv/__init__.py b/modules/cappedtv/__init__.py deleted file mode 100644 index aa03f1ad6efde25a9f49999729120a4e89f2fb3b..0000000000000000000000000000000000000000 --- a/modules/cappedtv/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- - -from .module import CappedModule - -__all__ = ['CappedModule'] diff --git a/modules/cappedtv/browser.py b/modules/cappedtv/browser.py deleted file mode 100644 index 3afe837d4650f13474d06a4565b5cd39a99b93e4..0000000000000000000000000000000000000000 --- a/modules/cappedtv/browser.py +++ /dev/null @@ -1,134 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Lord -# -# This module is free software. It comes without any warranty, to -# the extent permitted by applicable law. You can redistribute it -# and/or modify it under the terms of the Do What The Fuck You Want -# To Public License, Version 2, as published by Sam Hocevar. See -# http://sam.zoy.org/wtfpl/COPYING for more details. - -from collections import OrderedDict -import datetime - -from weboob.capabilities.base import NotAvailable -from weboob.tools.misc import to_unicode -from weboob.deprecated.browser import Page -from weboob.deprecated.browser import BrokenPageError -from weboob.deprecated.browser import Browser -from weboob.deprecated.browser.decorators import id2url -from weboob.capabilities.image import Thumbnail -from weboob.capabilities.video import BaseVideo -from weboob.tools.compat import quote_plus - - -__all__ = ['CappedBrowser'] - - -class CappedVideo(BaseVideo): - def __init__(self, *args, **kwargs): - BaseVideo.__init__(self, *args, **kwargs) - self.nsfw = False - self.ext = u'mp4' - - @classmethod - def id2url(cls, _id): - return 'http://capped.tv/%s' % _id - - -# parser for search pages -class IndexPage(Page): - def iter_videos(self): - # When no results are found, the website returns random results - sb = self.parser.select(self.document.getroot(), 'div.search form input.searchbox', 1) - if sb.value == 'No Results Found': - return - - #Extracting meta data from results page - vidbackdrop_list = self.parser.select(self.document.getroot(), 'div.vidBackdrop ') - for vidbackdrop in vidbackdrop_list: - url = self.parser.select(vidbackdrop, 'a', 1).attrib['href'] - _id = url[2:] - - video = CappedVideo(_id) - video.set_empty_fields(NotAvailable, ('url',)) - - video.title = to_unicode(self.parser.select(vidbackdrop, 'div.vidTitle a', 1).text) - video.author = to_unicode(self.parser.select(vidbackdrop, 'div.vidAuthor a', 1).text) - - thumbnail_url = 'http://cdn.capped.tv/pre/%s.png' % _id - video.thumbnail = Thumbnail(thumbnail_url) - video.thumbnail.url = to_unicode(video.thumbnail.id) - - #we get the description field - duration_tmp = self.parser.select(vidbackdrop, 'div.vidInfo', 1) - #we remove tabs and spaces - duration_tmp2 = duration_tmp.text[7:] - #we remove all fields exept time - duration_tmp3 = duration_tmp2.split(' ')[0] - #we transform it in datetime format - parts = duration_tmp3.split(':') - if len(parts) == 1: - hours = minutes = 0 - seconds = parts[0] - elif len(parts) == 2: - hours = 0 - minutes, seconds = parts - elif len(parts) == 3: - hours, minutes, seconds = parts - else: - raise BrokenPageError('Unable to parse duration %r' % duration_tmp) - - video.duration = datetime.timedelta(hours=int(hours), minutes=int(minutes), seconds=int(seconds)) - - yield video - - -# parser for the video page -class VideoPage(Page): - def get_video(self, video=None): - _id = to_unicode(self.group_dict['id']) - if video is None: - video = CappedVideo(_id) - video.set_empty_fields(NotAvailable) - - title_tmp = self.parser.select(self.document.getroot(), 'title', 1) - video.title = to_unicode(title_tmp.text.strip()) - - # Videopages doesn't have duration information (only results pages) - video.url = u'http://cdn.capped.tv/vhq/%s.mp4' % _id - return video - - -class CappedBrowser(Browser): - DOMAIN = 'capped.tv' - PROTOCOL = 'http' - ENCODING = None - PAGES = OrderedDict(( - (r'http://capped\.tv/?', IndexPage), - (r'http://capped\.tv/newest', IndexPage), - (r'http://capped\.tv/mostviews', IndexPage), - (r'http://capped\.tv/leastviews', IndexPage), - (r'http://capped\.tv/monthtop', IndexPage), - (r'http://capped\.tv/monthbottom', IndexPage), - (r'http://capped\.tv/alpha', IndexPage), - (r'http://capped\.tv/ahpla', IndexPage), - (r'http://capped\.tv/search\?s\=(?P.+)', IndexPage), - (r'http://capped\.tv/(?P.+)', VideoPage), - )) - - @id2url(CappedVideo.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('/search?s=%s' % (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/favicon.png b/modules/cappedtv/favicon.png deleted file mode 100644 index d37866d598306164ea306142ae8c7462e15d13d1..0000000000000000000000000000000000000000 Binary files a/modules/cappedtv/favicon.png and /dev/null differ diff --git a/modules/cappedtv/module.py b/modules/cappedtv/module.py deleted file mode 100644 index 9908add4461b187941dd2de7b4621b40eafe2c73..0000000000000000000000000000000000000000 --- a/modules/cappedtv/module.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Lord -# -# This module is free software. It comes without any warranty, to -# the extent permitted by applicable law. You can redistribute it -# and/or modify it under the terms of the Do What The Fuck You Want -# To Public License, Version 2, as published by Sam Hocevar. See -# http://sam.zoy.org/wtfpl/COPYING for more details. - - -from weboob.capabilities.video import CapVideo, BaseVideo -from weboob.capabilities.collection import CapCollection, CollectionNotFound -from weboob.tools.backend import Module -from .browser import CappedBrowser, CappedVideo - - -__all__ = ['CappedModule'] - - -class CappedModule(Module, CapVideo, CapCollection): - NAME = 'cappedtv' - MAINTAINER = u'Lord' - EMAIL = 'lord@lordtoniok.com' - VERSION = '1.4' - DESCRIPTION = 'Capped.tv demoscene website' - LICENSE = 'WTFPLv2' - BROWSER = CappedBrowser - - def get_video(self, _id): - with self.browser: - return self.browser.get_video(_id) - - def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=None): - with self.browser: - return self.browser.search_videos(pattern) - - def fill_video(self, video, fields): - if fields != ['thumbnail']: - with self.browser: - video = self.browser.get_video(CappedVideo.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']) - 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/test.py b/modules/cappedtv/test.py deleted file mode 100644 index 5215249707e0ed800f1744431f0f7b7938b62106..0000000000000000000000000000000000000000 --- a/modules/cappedtv/test.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Lord -# -# This module is free software. It comes without any warranty, to -# the extent permitted by applicable law. You can redistribute it -# and/or modify it under the terms of the Do What The Fuck You Want -# To Public License, Version 2, as published by Sam Hocevar. See -# http://sam.zoy.org/wtfpl/COPYING for more details. - - -from weboob.tools.test import BackendTest -from weboob.capabilities.video import BaseVideo - - -class CappedTest(BackendTest): - MODULE = 'cappedtv' - - 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) - - l = list(self.backend.search_videos('weboob')) - self.assertTrue(len(l) == 0) - - 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/europarl/__init__.py b/modules/europarl/__init__.py deleted file mode 100644 index 98b72381e4fca9e359cfc4057a3c3c6439b13bd5..0000000000000000000000000000000000000000 --- a/modules/europarl/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import EuroparlModule - -__all__ = ['EuroparlModule'] diff --git a/modules/europarl/browser.py b/modules/europarl/browser.py deleted file mode 100644 index 1770384b7964e952fc1cb6c9d21ad8552507ed9f..0000000000000000000000000000000000000000 --- a/modules/europarl/browser.py +++ /dev/null @@ -1,57 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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.deprecated.browser import Browser -from weboob.deprecated.browser.decorators import id2url - -#from .pages.index import IndexPage -from .pages import VideoPage -from .video import EuroparlVideo - - -__all__ = ['EuroparlBrowser'] - - -class EuroparlBrowser(Browser): - DOMAIN = 'europarl.europa.eu' - ENCODING = None - PAGES = {r'http://[w\.]*europarl\.europa\.eu/ep-live/(?P\w+)/committees/video\?.*event=(?P[^&]+).*': VideoPage, - r'http://[w\.]*europarl\.europa\.eu/ep-live/(?P\w+)/other-events/video\?.*event=(?P[^&]+).*': VideoPage -#TODO:plenaries -# r'http://[w\.]*europarl\.europa\.eu/ep-live/(?P\w+)/plenary/video\?.*date=(?P[^&]+).*': VideoPage -# r'http://[w\.]*europarl\.europa\.eu/ep-live/(?P\w+)/plenary/video\?.*debate=(?P[^&]+).*': VideoPage - } - - @id2url(EuroparlVideo.id2url) - def get_video(self, url, video=None): - self.location(url) - return self.page.get_video(video) - - # def search_videos(self, pattern, sortby): - # return None - # self.location(self.buildurl('http://europarltv.europa.eu/en/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/europarl/favicon.png b/modules/europarl/favicon.png deleted file mode 100644 index fffc442d867908208495c1b977b2e0ce2c9b439a..0000000000000000000000000000000000000000 Binary files a/modules/europarl/favicon.png and /dev/null differ diff --git a/modules/europarl/favicon_europarl.xcf b/modules/europarl/favicon_europarl.xcf deleted file mode 100644 index ea7301492c80a8b11c17e9e7ff19711342973303..0000000000000000000000000000000000000000 Binary files a/modules/europarl/favicon_europarl.xcf and /dev/null differ diff --git a/modules/europarl/module.py b/modules/europarl/module.py deleted file mode 100644 index b9f2629ed7958a4b83a148f87e4f8d870abb7075..0000000000000000000000000000000000000000 --- a/modules/europarl/module.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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 CapVideo, BaseVideo -from weboob.tools.backend import Module -from weboob.capabilities.collection import CapCollection, CollectionNotFound - -from .browser import EuroparlBrowser -from .video import EuroparlVideo - - -__all__ = ['EuroparlModule'] - - -class EuroparlModule(Module, CapVideo, CapCollection): - NAME = 'europarl' - MAINTAINER = u'François Revol' - EMAIL = 'revol@free.fr' - VERSION = '1.4' - DESCRIPTION = 'Europarl parliamentary video streaming website' - LICENSE = 'AGPLv3+' - BROWSER = EuroparlBrowser - - def get_video(self, _id): - with self.browser: - return self.browser.get_video(_id) - - SORTBY = ['relevance', 'rating', 'views', 'time'] - - # def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False): - # with self.browser: - # return self.browser.search_videos(pattern, self.SORTBY[sortby]) - - 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(EuroparlVideo.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']) - 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 Europarl videos' - return - raise CollectionNotFound(collection.split_path) - - OBJECTS = {EuroparlVideo: fill_video} diff --git a/modules/europarl/pages.py b/modules/europarl/pages.py deleted file mode 100644 index 3520098e0b1b5d0cf6a9e140fe1aaf0795540501..0000000000000000000000000000000000000000 --- a/modules/europarl/pages.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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 datetime -import re - -from weboob.capabilities.base import NotAvailable -from weboob.deprecated.browser import BrokenPageError, Page - -from .video import EuroparlVideo - - -class VideoPage(Page): - def get_video(self, video=None): - if video is None: - video = EuroparlVideo(self.group_dict['id']) - video.title = unicode(self.get_title()) - video.url = unicode(self.get_url()) - self.set_details(video) - - video.set_empty_fields(NotAvailable) - return video - - def get_url(self): - # search for - # TODO: plenaries can be downloaded as mp4... - obj = self.parser.select(self.document.getroot(), 'input#codeUrl', 1) - if obj is None: - return None - return obj.attrib['value'] - - def get_title(self): - obj = self.parser.select(self.document.getroot(), 'h1#player_subjectTitle') - if len(obj) < 1: - obj = self.parser.select(self.document.getroot(), 'title') - if len(obj) < 1: - return None - title = obj[0].text.strip() - obj = self.parser.select(self.document.getroot(), 'span.ep_subtitle') - if len(obj) < 1: - return title - - for span in self.parser.select(obj[0], 'span.ep_acronym, span.ep_theme'): - if span.text_content(): - title += ' ' + span.text_content().strip() - - return title - - def set_details(self, v): - v.author = u'European Parliament' - obj = self.parser.select(self.document.getroot(), 'meta[name=available]', 1) - if obj is not None: - value = obj.attrib['content'] - m = re.match('(\d\d)-(\d\d)-(\d\d\d\d)\s*(\d\d):(\d\d)', value) - if not m: - raise BrokenPageError('Unable to parse datetime: %r' % value) - day = m.group(1) - month = m.group(2) - year = m.group(3) - hour = m.group(4) - minute = m.group(5) - v.date = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(hour), - minute=int(minute)) - - obj = self.parser.select(self.document.getroot(), 'span.ep_subtitle', 1) - if obj is not None: - span = self.parser.select(obj, 'span.ep_date', 1) - value = span.text - m = re.match('(\d\d):(\d\d)\s*\/\s*(\d\d):(\d\d)\s*-\s*(\d\d)-(\d\d)-(\d\d\d\d)', value) - if not m: - raise BrokenPageError('Unable to parse datetime: %r' % value) - bhour = m.group(1) - bminute = m.group(2) - ehour = m.group(3) - eminute = m.group(4) - day = m.group(5) - month = m.group(6) - year = m.group(7) - - start = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(bhour), - minute=int(bminute)) - end = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(ehour), - minute=int(eminute)) - - v.duration = end - start diff --git a/modules/europarl/test.py b/modules/europarl/test.py deleted file mode 100644 index 6333e07b986c74c42e568c9728a5beefa4ff45e3..0000000000000000000000000000000000000000 --- a/modules/europarl/test.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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 EuroparlTest(BackendTest): - MODULE = 'europarl' - - # def test_search(self): - # l = list(self.backend.search_videos('neelie kroes')) - # 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/europarl/video.py b/modules/europarl/video.py deleted file mode 100644 index 640970c6a3917ed95e52a947da1c768d740b630e..0000000000000000000000000000000000000000 --- a/modules/europarl/video.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 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 - -import re - - -class EuroparlVideo(BaseVideo): - def __init__(self, *args, **kwargs): - BaseVideo.__init__(self, *args, **kwargs) - self.ext = u'wmv' - - @classmethod - def id2url(cls, _id): - m = re.match('.*-COMMITTEE-.*', _id) - if m: - return u'http://www.europarl.europa.eu/ep-live/en/committees/video?event=%s&format=wmv' % _id - m = re.match('.*-SPECIAL-.*', _id) - if m: - return u'http://www.europarl.europa.eu/ep-live/en/other-events/video?event=%s&format=wmv' % _id - # XXX: not yet supported - m = re.match('\d\d-\d\d-\d\d\d\d', _id) - if m: - return u'http://www.europarl.europa.eu/ep-live/en/plenary/video?date=%s' % _id - # XXX: not yet supported - m = re.match('\d+', _id) - if m: - return u'http://www.europarl.europa.eu/ep-live/en/plenary/video?debate=%s' % _id - return None diff --git a/modules/fourchan/__init__.py b/modules/fourchan/__init__.py deleted file mode 100644 index 474bbcafbc9657d683ac88b64b81058e55cac0a2..0000000000000000000000000000000000000000 --- a/modules/fourchan/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from .module import FourChanModule -from .browser import FourChan - -__all__ = ['FourChanModule', 'FourChan'] diff --git a/modules/fourchan/browser.py b/modules/fourchan/browser.py deleted file mode 100644 index 89bc1ec162cf7eaa986c0e49a30fabd67f5c422f..0000000000000000000000000000000000000000 --- a/modules/fourchan/browser.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- 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 . - - -from weboob.deprecated.browser import Browser - -from .pages.board import BoardPage - - -class FourChan(Browser): - DOMAIN = 'boards.4chan.org' - PAGES = { - 'http://boards.4chan.org/\w+/': BoardPage, - 'http://boards.4chan.org/\w+/res/\d+': BoardPage, - } - - def is_logged(self): - return True - - def get_threads(self, board): - self.location('http://boards.4chan.org/%s/' % board) - return self.page.articles - - def get_thread(self, board, id): - self.location('http://boards.4chan.org/%s/res/%d' % (board, long(id))) - assert len(self.page.articles) == 1 - return self.page.articles[0] diff --git a/modules/fourchan/favicon.png b/modules/fourchan/favicon.png deleted file mode 100644 index 7184f5185703afff3aa9fa75b77f78cf49503584..0000000000000000000000000000000000000000 Binary files a/modules/fourchan/favicon.png and /dev/null differ diff --git a/modules/fourchan/module.py b/modules/fourchan/module.py deleted file mode 100644 index 434d69590cea6b799b8586118bae0e37726d016c..0000000000000000000000000000000000000000 --- a/modules/fourchan/module.py +++ /dev/null @@ -1,125 +0,0 @@ -# -*- 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 . - - -from weboob.capabilities.messages import CapMessages, Message, Thread -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import Value - -from .browser import FourChan - - -__all__ = ['FourChanModule'] - - -class FourChanModule(Module, CapMessages): - NAME = 'fourchan' - MAINTAINER = u'Romain Bignon' - EMAIL = 'romain@weboob.org' - VERSION = '1.4' - LICENSE = 'AGPLv3+' - DESCRIPTION = '4chan image board' - CONFIG = BackendConfig(Value('boards', label='Boards to fetch')) - STORAGE = {'boards': {}} - BROWSER = FourChan - - def _splitid(self, id): - return id.split('.', 1) - - def get_thread(self, id): - thread = None - - if isinstance(id, Thread): - thread = id - id = thread.id - - if '.' not in id: - self.logger.warning('Malformated ID (%s)' % id) - return - - board, thread_id = self._splitid(id) - - with self.browser: - _thread = self.browser.get_thread(board, thread_id) - - flags = 0 - if _thread.id not in self.storage.get('boards', board, default={}): - flags |= Message.IS_UNREAD - - if not thread: - thread = Thread(id) - thread.title = _thread.filename - thread.root = Message(thread=thread, - id=0, # root message - title=_thread.filename, - sender=_thread.author, - receivers=None, - date=_thread.datetime, - parent=None, - content=_thread.text, - signature=None, - children=[], - flags=flags|Message.IS_HTML) - - for comment in _thread.comments: - flags = 0 - if comment.id not in self.storage.get('boards', board, _thread.id, default=[]): - flags |= Message.IS_UNREAD - - m = Message(thread=thread, - id=comment.id, - title=_thread.filename, - sender=comment.author, - receivers=None, - date=comment.datetime, - parent=thread.root, - content=comment.text, - signature=None, - children=None, - flags=flags|Message.IS_HTML) - thread.root.children.append(m) - - return thread - - def iter_threads(self): - for board in self.config['boards'].get().split(' '): - with self.browser: - threads = self.browser.get_threads(board) - for thread in threads: - t = Thread('%s.%s' % (board, thread.id)) - t.title = thread.filename - yield t - - def iter_unread_messages(self): - for thread in self.iter_threads(): - self.fill_thread(thread, 'root') - - for m in thread.iter_all_messages(): - if m.flags & Message.IS_UNREAD: - yield m - - def set_message_read(self, message): - board, thread_id = self._splitid(message.thread.id) - self.storage.set('boards', board, thread_id, self.storage.get('boards', board, thread_id, default=[]) + [message.id]) - self.storage.save() - - def fill_thread(self, thread, fields): - return self.get_thread(thread) - - OBJECTS = {Thread: fill_thread} diff --git a/modules/fourchan/pages/__init__.py b/modules/fourchan/pages/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/modules/fourchan/pages/board.py b/modules/fourchan/pages/board.py deleted file mode 100644 index 663a078c524cb0a0c16bdfdedb745e4004eddcf2..0000000000000000000000000000000000000000 --- a/modules/fourchan/pages/board.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- 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 . - - -import re - -from datetime import datetime - -from weboob.deprecated.browser import Page - - -class Message(object): - def __init__(self, browser, board, id, filename=u'', url=u''): - self.id = id - self.browser = browser - self.board = board - self.filename = filename - self.datetime = datetime.now() - self.url = url - self.author = u'' - self.text = u'' - self.comments = [] - - def add_comment(self, div): - comment = Message(self.browser, self.board, int(div.attrib.get('id', ''))) - comment.author = div.cssselect('span.commentpostername')[0].text - comment.text = self.browser.parser.tostring(div.find('blockquote')) - self.comments.append(comment) - - def __repr__(self): - return '' % (self.id, self.filename, self.url, len(self.comments)) - - -class BoardPage(Page): - URL_REGEXP = re.compile('http://boards.4chan.org/(\w+)/') - - def on_loaded(self): - self.articles = [] - - m = self.URL_REGEXP.match(self.url) - if m: - self.board = m.group(1) - else: - self.logger.warning('Unable to find board') - self.board = 'unknown' - - forms = self.document.getroot().cssselect('form') - form = None - - for f in forms: - if f.attrib.get('name', '') == 'delform': - form = f - break - - if form is None: - self.logger.warning('No delform :(') - - article = None - for div in form.getchildren(): - if div.tag == 'span' and div.attrib.get('class', '') == 'filesize': - url = div.find('a').get('href', '') - filename = 'unknown.jpg' - span = div.find('span') - if span is not None: - filename = span.text - article = Message(self.browser, self.board, 0, filename, url) - self.articles.append(article) - if article is None: - continue - if div.tag == 'input' and div.attrib.get('type', 'checkbox') and div.attrib.get('value', 'delete'): - article.id = int(div.attrib.get('name', '0')) - if div.tag == 'blockquote': - article.text = self.parser.tostring(div) - if div.tag == 'table': - tags = div.cssselect('td.reply') - if tags: - article.add_comment(tags[0]) diff --git a/modules/fourchan/test.py b/modules/fourchan/test.py deleted file mode 100644 index f8436997563e94b8061b9343f860d739dfd03179..0000000000000000000000000000000000000000 --- a/modules/fourchan/test.py +++ /dev/null @@ -1,44 +0,0 @@ -# -*- 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 . - - -from logging import debug -from weboob.tools.test import BackendTest - - -class FourChanTest(BackendTest): - MODULE = 'fourchan' - - def test_new_messages(self): - tot = 0 - for thread in self.backend.iter_threads(): - thread = self.backend.fillobj(thread, 'root') - count = 0 - for m in thread.iter_all_messages(): - count += 1 - debug('Count: %s' % count) - tot += count - - debug('Total messages: %s' % tot) - - count = 0 - for message in self.backend.iter_unread_messages(): - count += 1 - - debug('Unread messages: %s' % count) diff --git a/modules/gazelle/__init__.py b/modules/gazelle/__init__.py deleted file mode 100644 index 3de43fb8e33e0e8301a150be89338457ebb20037..0000000000000000000000000000000000000000 --- a/modules/gazelle/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import GazelleModule - -__all__ = ['GazelleModule'] diff --git a/modules/gazelle/browser.py b/modules/gazelle/browser.py deleted file mode 100644 index 1bf4692f5aff1511d4a3d92227d5c8697d0f6e38..0000000000000000000000000000000000000000 --- a/modules/gazelle/browser.py +++ /dev/null @@ -1,75 +0,0 @@ -# -*- 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 . - - -from weboob.deprecated.browser import Browser, BrowserIncorrectPassword - -from .pages.index import IndexPage, LoginPage -from .pages.torrents import TorrentsPage - - -__all__ = ['GazelleBrowser'] - - -class GazelleBrowser(Browser): - PAGES = {'https?://[^/]+/?(index.php)?': IndexPage, - 'https?://[^/]+/login.php.*': LoginPage, - 'https?://[^/]+/torrents.php.*': TorrentsPage, - } - - def __init__(self, protocol, domain, *args, **kwargs): - self.DOMAIN = domain - self.PROTOCOL = protocol - Browser.__init__(self, *args, **kwargs) - - def login(self): - if not self.is_on_page(LoginPage): - self.location('/login.php', no_login=True) - self.page.login(self.username, self.password) - - # If we are not logged, the on_loaded event on LoginPage has probably - # raised the exception, but to be sure, check here to prevent an - # unfinite loop if we can't find the error message. - if self.is_on_page(LoginPage): - raise BrowserIncorrectPassword() - - def is_logged(self): - if not self.page or self.is_on_page(LoginPage): - return False - if self.is_on_page(IndexPage): - return self.page.is_logged() - return True - - def home(self): - return self.location('%s://%s/' % (self.PROTOCOL, self.DOMAIN)) - - def iter_torrents(self, pattern): - self.location(self.buildurl('/torrents.php', searchstr=pattern.encode('utf-8'))) - - assert self.is_on_page(TorrentsPage) - return self.page.iter_torrents() - - def get_torrent(self, fullid): - if '.' not in fullid: - return None - id, torrentid = fullid.split('.', 1) - self.location(self.buildurl('/torrents.php', id=id, torrentid=torrentid)) - - assert self.is_on_page(TorrentsPage) - return self.page.get_torrent(fullid) diff --git a/modules/gazelle/favicon.png b/modules/gazelle/favicon.png deleted file mode 100644 index e5eff6bde3a2ffc683bc934f6d9b35310021a207..0000000000000000000000000000000000000000 Binary files a/modules/gazelle/favicon.png and /dev/null differ diff --git a/modules/gazelle/module.py b/modules/gazelle/module.py deleted file mode 100644 index de867e3c7b5ac4aac8a7038798ee44ac13a90ade..0000000000000000000000000000000000000000 --- a/modules/gazelle/module.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- 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 . - -from weboob.capabilities.torrent import CapTorrent -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword, Value - -from .browser import GazelleBrowser - - -__all__ = ['GazelleModule'] - - -class GazelleModule(Module, CapTorrent): - NAME = 'gazelle' - MAINTAINER = u'Romain Bignon' - EMAIL = 'romain@weboob.org' - VERSION = '1.4' - DESCRIPTION = 'Gazelle-based BitTorrent trackers' - LICENSE = 'AGPLv3+' - CONFIG = BackendConfig(Value('domain', label='Domain (example "ssl.what.cd")'), - Value('protocol', label='Protocol to use', choices=('http', 'https')), - Value('username', label='Username'), - ValueBackendPassword('password', label='Password')) - BROWSER = GazelleBrowser - - def create_default_browser(self): - return self.create_browser(self.config['protocol'].get(), self.config['domain'].get(), - self.config['username'].get(), self.config['password'].get()) - - def get_torrent(self, id): - return self.browser.get_torrent(id) - - def get_torrent_file(self, id): - torrent = self.browser.get_torrent(id) - if not torrent: - return None - - return self.browser.openurl(torrent.url.encode('utf-8')).read() - - def iter_torrents(self, pattern): - return self.browser.iter_torrents(pattern) diff --git a/modules/gazelle/pages/__init__.py b/modules/gazelle/pages/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/modules/gazelle/pages/base.py b/modules/gazelle/pages/base.py deleted file mode 100644 index d210dec613e815293c8ce23b398e99bff96da2a8..0000000000000000000000000000000000000000 --- a/modules/gazelle/pages/base.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- 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 . - - -from weboob.deprecated.browser import BrowserUnavailable, Page as _BasePage - - -class BasePage(_BasePage): - def on_loaded(self): - errors = [] - for div in self.parser.select(self.document.getroot(), 'div.poetry'): - errors.append(self.parser.tocleanstring(div)) - - if len(errors) > 0: - raise BrowserUnavailable(', '.join(errors)) diff --git a/modules/gazelle/pages/index.py b/modules/gazelle/pages/index.py deleted file mode 100644 index 1e96c3b62ff595009ec257816c295563d8876e22..0000000000000000000000000000000000000000 --- a/modules/gazelle/pages/index.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- 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 . - - -from weboob.deprecated.browser import BrowserIncorrectPassword, BrowserBanned -from .base import BasePage - - -class IndexPage(BasePage): - def is_logged(self): - return 'id' in self.document.find('body').attrib - - -class LoginPage(BasePage): - def on_loaded(self): - BasePage.on_loaded(self) - - warns = self.parser.select(self.document.getroot(), '.warning') - for warn in warns: - text = self.parser.tocleanstring(warn) - if text.startswith('Your '): - raise BrowserIncorrectPassword(text) - if text.startswith('You are banned'): - raise BrowserBanned(text) - - def login(self, login, password): - self.browser.select_form(nr=0) - self.browser['username'] = login - self.browser['password'] = password - self.browser.submit(no_login=True) diff --git a/modules/gazelle/pages/torrents.py b/modules/gazelle/pages/torrents.py deleted file mode 100644 index 32f6ea4212d6c24bb8a343be012648465d1d743e..0000000000000000000000000000000000000000 --- a/modules/gazelle/pages/torrents.py +++ /dev/null @@ -1,209 +0,0 @@ -# -*- 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 . - - -import re -from logging import warning, debug - -from weboob.tools.compat import parse_qs, urlparse -from weboob.tools.misc import get_bytes_size -from weboob.tools.html import html2text -from weboob.capabilities.torrent import Torrent -from weboob.capabilities.base import NotLoaded - -from .base import BasePage - - -class TorrentsPage(BasePage): - TORRENTID_REGEXP = re.compile('torrents\.php\?action=download&id=(\d+)') - - def format_url(self, url): - return '%s://%s/%s' % (self.browser.PROTOCOL, - self.browser.DOMAIN, - url) - - def iter_torrents(self): - table = self.document.getroot().cssselect('table.torrent_table') - if not table: - table = self.document.getroot().cssselect('table#browse_torrent_table') - if table: - table = table[0] - current_group = None - for tr in table.findall('tr'): - if tr.attrib.get('class', '') == 'colhead': - # ignore - continue - if tr.attrib.get('class', '') == 'group': - tds = tr.findall('td') - current_group = u'' - div = tds[-6] - if div.getchildren()[0].tag == 'div': - div = div.getchildren()[0] - for a in div.findall('a'): - if not a.text: - continue - if current_group: - current_group += ' - ' - current_group += a.text - elif tr.attrib.get('class', '').startswith('group_torrent') or \ - tr.attrib.get('class', '').startswith('torrent'): - tds = tr.findall('td') - - title = current_group - if len(tds) == 7: - # Under a group - i = 0 - elif len(tds) in (8, 9): - # An alone torrent - i = len(tds) - 1 - while i >= 0 and tds[i].find('a') is None: - i -= 1 - else: - # Useless title - continue - - if title: - title += u' (%s)' % tds[i].find('a').text - else: - title = ' - '.join([a.text for a in tds[i].findall('a')]) - url = urlparse(tds[i].find('a').attrib['href']) - params = parse_qs(url.query) - if 'torrentid' in params: - id = '%s.%s' % (params['id'][0], params['torrentid'][0]) - else: - url = tds[i].find('span').find('a').attrib['href'] - m = self.TORRENTID_REGEXP.match(url) - if not m: - continue - id = '%s.%s' % (params['id'][0], m.group(1)) - try: - size, unit = tds[i + 3].text.split() - except ValueError: - size, unit = tds[i + 2].text.split() - size = get_bytes_size(float(size.replace(',', '')), unit) - seeders = int(tds[-2].text) - leechers = int(tds[-1].text) - - torrent = Torrent(id, title) - torrent.url = self.format_url(url) - torrent.size = size - torrent.seeders = seeders - torrent.leechers = leechers - yield torrent - else: - debug('unknown attrib: %s' % tr.attrib) - - def get_torrent(self, id): - table = self.browser.parser.select(self.document.getroot(), 'div.thin', 1) - - h2 = table.xpath('.//h2') - if len(h2) > 0: - title = u''.join([txt.strip() for txt in h2[0].itertext()]) - else: - title = self.browser.parser.select(table, 'div.title_text', 1).text - - torrent = Torrent(id, title) - if '.' in id: - torrentid = id.split('.', 1)[1] - else: - torrentid = id - table = self.browser.parser.select(self.document.getroot(), 'table.torrent_table') - if len(table) == 0: - table = self.browser.parser.select(self.document.getroot(), 'div.main_column', 1) - is_table = False - else: - table = table[0] - is_table = True - - for tr in table.findall('tr' if is_table else 'div'): - if is_table and 'group_torrent' in tr.attrib.get('class', ''): - tds = tr.findall('td') - - if not len(tds) == 5: - continue - - url = tds[0].find('span').find('a').attrib['href'] - m = self.TORRENTID_REGEXP.match(url) - if not m: - warning('ID not found') - continue - if m.group(1) != torrentid: - continue - - torrent.url = self.format_url(url) - size, unit = tds[1].text.split() - torrent.size = get_bytes_size(float(size.replace(',', '')), unit) - torrent.seeders = int(tds[3].text) - torrent.leechers = int(tds[4].text) - break - elif not is_table and tr.attrib.get('class', '').startswith('torrent_widget') \ - and tr.attrib.get('class', '').endswith('pad'): - url = tr.cssselect('a[title=Download]')[0].attrib['href'] - m = self.TORRENTID_REGEXP.match(url) - if not m: - warning('ID not found') - continue - if m.group(1) != torrentid: - continue - - torrent.url = self.format_url(url) - size, unit = tr.cssselect('div.details_title strong')[-1].text.strip('()').split() - torrent.size = get_bytes_size(float(size.replace(',', '')), unit) - torrent.seeders = int(tr.cssselect('img[title=Seeders]')[0].tail) - torrent.leechers = int(tr.cssselect('img[title=Leechers]')[0].tail) - break - - if not torrent.url: - warning('Torrent %s not found in list' % torrentid) - return None - - div = self.parser.select(self.document.getroot(), 'div.main_column', 1) - for box in div.cssselect('div.box'): - title = None - body = None - - title_t = box.cssselect('div.head') - if len(title_t) > 0: - title_t = title_t[0] - if title_t.find('strong') is not None: - title_t = title_t.find('strong') - if title_t.text is not None: - title = title_t.text.strip() - - body_t = box.cssselect('div.body,div.desc') - if body_t: - body = html2text(self.parser.tostring(body_t[-1])).strip() - - if title and body: - if torrent.description is NotLoaded: - torrent.description = u'' - torrent.description += u'%s\n\n%s\n' % (title, body) - - divs = self.document.getroot().cssselect('div#files_%s,div#filelist_%s,tr#torrent_%s td' % (torrentid, torrentid, torrentid)) - if divs: - torrent.files = [] - for div in divs: - table = div.find('table') - if table is None: - continue - for tr in table: - if tr.attrib.get('class', None) != 'colhead_dark': - torrent.files.append(tr.find('td').text) - - return torrent diff --git a/modules/gazelle/test.py b/modules/gazelle/test.py deleted file mode 100644 index aaad1449f0c6621d3af470d981d60af1b8a77044..0000000000000000000000000000000000000000 --- a/modules/gazelle/test.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- 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 . - -from weboob.tools.test import BackendTest - - -class GazelleTest(BackendTest): - MODULE = 'gazelle' - - def test_torrent(self): - l = list(self.backend.iter_torrents('sex')) - if len(l) > 0: - self.backend.get_torrent_file(l[0].id) diff --git a/modules/gdcvault/__init__.py b/modules/gdcvault/__init__.py deleted file mode 100644 index e9343edb4e3036566ebd95e10e8ee9b25f6c5d4c..0000000000000000000000000000000000000000 --- a/modules/gdcvault/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import GDCVaultModule - -__all__ = ['GDCVaultModule'] diff --git a/modules/gdcvault/browser.py b/modules/gdcvault/browser.py deleted file mode 100644 index d7a358830ff8376126383359302d4be070fc28d6..0000000000000000000000000000000000000000 --- a/modules/gdcvault/browser.py +++ /dev/null @@ -1,150 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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.deprecated.browser import Browser, BrowserIncorrectPassword, BrowserUnavailable,\ - BrowserBanned -from weboob.deprecated.browser.decorators import id2url -from weboob.tools.compat import urlencode - -#from .pages.index import IndexPage -from .pages import VideoPage, IndexPage, SearchPage -from .video import GDCVaultVideo -#HACK -from urllib2 import HTTPError -import re -from weboob.capabilities.base import NotAvailable - - -__all__ = ['GDCVaultBrowser'] - - -class GDCVaultBrowser(Browser): - DOMAIN = 'gdcvault.com' - ENCODING = 'utf-8' - PAGES = {r'http://[w\.]*gdcvault.com/play/(?P[\d]+)/?.*': VideoPage, - r'http://[w\.]*gdcvault.com/search\.php.*': (SearchPage, "json"), - r'http://[w\.]*gdcvault.com/.*': IndexPage, - } - - def is_logged(self): - if self.password is None: - return True - - if not self.page: - return False - - obj = self.parser.select(self.page.document.getroot(), 'h3[id=welcome_user_name]', 1) - if obj is None: - return False - - return obj.attrib.get('class','') != "hidden" - - def login(self): - if self.password is None: - return - - params = {'remember_me': 0, - 'email': self.username, - 'password': self.password, - } - - data = self.readurl('http://gdcvault.com/api/login.php', - urlencode(params)) - # some data returned as JSON, not sure yet if it's useful - - if data is None: - self.openurl('/logout', '') - raise BrowserBanned('Too many open sessions?') - - self.location('/', no_login=True) - - if not self.is_logged(): - raise BrowserIncorrectPassword() - - def close_session(self): - if self.password is None or not self.is_logged(): - return - - self.openurl('/logout', '') - - @id2url(GDCVaultVideo.id2url) - def get_video(self, url, video=None): - requires_account = False - redir_url = None - - # FIXME: this is quite ugly - # but is required to handle cases like 1013422@gdcvault - self.set_handle_redirect(False) - try: - self.open_novisit(url) - #headers = req.info() - except HTTPError as e: - if e.getcode() == 302 and hasattr(e, 'hdrs'): - if e.hdrs['Location'] in ['/', '/login']: - requires_account = True - else: - # 1015865 redirects to a file with an eacute in the name - redir_url = unicode(e.hdrs['Location'], encoding='utf-8') - self.set_handle_redirect(True) - - if requires_account: - raise BrowserUnavailable('Requires account') - - if redir_url: - if video is None: - m = re.match('http://[w\.]*gdcvault.com/play/(?P[\d]+)/?.*', url) - if m: - video = GDCVaultVideo(int(m.group(1))) - else: - raise BrowserUnavailable('Cannot find ID on page with redirection') - video.url = redir_url - video.set_empty_fields(NotAvailable) - # best effort for now - return video - - self.location(url) - # redirects to /login means the video is not public - if not self.is_on_page(VideoPage): - raise BrowserUnavailable('Requires account') - return self.page.get_video(video) - - def search_videos(self, pattern, sortby): - post_data = {"firstfocus" : "", - "category" : "free", - "keyword" : pattern.encode('utf-8'), - "conference_id" : "", } - post_data = urlencode(post_data) - # probably not required - self.addheaders = [('Referer', 'http://gdcvault.com/'), - ("Content-Type" , 'application/x-www-form-urlencoded') ] - - # is_logged assumes html page - self.location('http://gdcvault.com/search.php', - data=post_data, no_login=True) - - assert self.is_on_page(SearchPage) - return self.page.iter_videos() - - def latest_videos(self): - #self.home() - self.location('/free') - assert self.is_on_page(IndexPage) - return self.page.iter_videos() diff --git a/modules/gdcvault/favicon.png b/modules/gdcvault/favicon.png deleted file mode 100644 index 70ef33e20bb41c825a43e51a42a0cdfc8c89dd36..0000000000000000000000000000000000000000 Binary files a/modules/gdcvault/favicon.png and /dev/null differ diff --git a/modules/gdcvault/favicon.xcf b/modules/gdcvault/favicon.xcf deleted file mode 100644 index 32695aaa5cfdb5863c913b5e077dbbc5859cf43d..0000000000000000000000000000000000000000 Binary files a/modules/gdcvault/favicon.xcf and /dev/null differ diff --git a/modules/gdcvault/module.py b/modules/gdcvault/module.py deleted file mode 100644 index 97b639d0fc7b90bb88718fe0aef0cd28e425e29a..0000000000000000000000000000000000000000 --- a/modules/gdcvault/module.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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 CapVideo, BaseVideo -from weboob.tools.backend import Module, BackendConfig -from weboob.capabilities.collection import CapCollection, CollectionNotFound -from weboob.tools.value import Value, ValueBackendPassword - -from .browser import GDCVaultBrowser -from .video import GDCVaultVideo - - -__all__ = ['GDCVaultModule'] - - -class GDCVaultModule(Module, CapVideo, CapCollection): - NAME = 'gdcvault' - MAINTAINER = u'François Revol' - EMAIL = 'revol@free.fr' - VERSION = '1.4' - DESCRIPTION = 'Game Developers Conferences Vault video streaming website' - LICENSE = 'AGPLv3+' - BROWSER = GDCVaultBrowser - CONFIG = BackendConfig(Value('username', label='Username', default=''), - ValueBackendPassword('password', label='Password', default='')) - - def create_default_browser(self): - username = self.config['username'].get() - if len(username) > 0: - password = self.config['password'].get() - else: - password = None - return self.create_browser(username, password) - - def deinit(self): - # don't need to logout if the browser hasn't been used. - if not self._browser: - return - - with self.browser: - self.browser.close_session() - - def get_video(self, _id): - with self.browser: - return self.browser.get_video(_id) - - SORTBY = ['relevance', 'rating', 'views', 'time'] - - def search_videos(self, pattern, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False): - with self.browser: - return self.browser.search_videos(pattern, self.SORTBY[sortby]) - - 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(GDCVaultVideo.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']) - 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 GDCVault videos' - return - raise CollectionNotFound(collection.split_path) - - OBJECTS = {GDCVaultVideo: fill_video} diff --git a/modules/gdcvault/pages.py b/modules/gdcvault/pages.py deleted file mode 100644 index c9ee873a8e1dc3c8cfed5d6957b3d85b4f17c47b..0000000000000000000000000000000000000000 --- a/modules/gdcvault/pages.py +++ /dev/null @@ -1,367 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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.deprecated.browser import Page -from weboob.tools.compat import quote - -import re -import datetime -from dateutil.parser import parse as parse_dt - -from weboob.capabilities.base import NotAvailable -from weboob.capabilities.image import Thumbnail -from weboob.deprecated.browser import BrokenPageError - -#HACK -from urllib2 import HTTPError - -from .video import GDCVaultVideo - -#import lxml.etree - -# TODO: check title on 1439 - - -class IndexPage(Page): - def iter_videos(self): - for a in self.parser.select(self.document.getroot(), 'section.conference ul.media_items li.featured a.session_item'): - href = a.attrib.get('href', '') - # print href - m = re.match('/play/(\d+)/.*', href) - if not m: - continue - # print m.group(1) - video = GDCVaultVideo(m.group(1)) - - # get title - try: - video.title = unicode(self.parser.select(a, 'div.conference_info p strong', 1).text) - except IndexError: - video.title = NotAvailable - - # get description - try: - video.description = unicode(self.parser.select(a, 'div.conference_info p', 1).text) - except IndexError: - video.description = NotAvailable - - # get thumbnail - img = self.parser.select(a, 'div.featured_image img', 1) - if img is not None: - video.thumbnail = Thumbnail(img.attrib['src']) - video.thumbnail.url = video.thumbnail.id - else: - video.thumbnail = NotAvailable - - #m = re.match('id-(\d+)', a.attrib.get('class', '')) - #if not m: - # continue - # FIXME - yield video - -# the search page class uses a JSON parser, -# since it's what search.php returns when POSTed (from Ajax) - - -class SearchPage(Page): - def iter_videos(self): - if self.document is None or self.document['data'] is None: - raise BrokenPageError('Unable to find JSON data') - for data in self.document['data']: - video = GDCVaultVideo.get_video_from_json(data) - # TODO: split type 4 videos into id and id#slides - if video is None: - continue - yield video - - -class VideoPage(Page): - def get_video(self, video=None): - # check for slides id variant - want_slides = False - m = re.match('.*#slides', self.url) - if m: - want_slides = True - # not sure it's safe - self.group_dict['id'] += '#slides' - - if video is None: - video = GDCVaultVideo(self.group_dict['id']) - - # the config file has it too, but in CDATA and only for type 4 - obj = self.parser.select(self.document.getroot(), 'title') - title = None - if len(obj) > 0: - try: - title = unicode(obj[0].text) - except UnicodeDecodeError as e: - title = None - - if title is None: - obj = self.parser.select(self.document.getroot(), 'meta[name=title]') - if len(obj) > 0: - if 'content' in obj[0].attrib: - try: - # FIXME: 1013483 has buggus title (latin1) - # for now we just pass it as-is - title = obj[0].attrib['content'] - except UnicodeDecodeError as e: - # XXX: this doesn't even works!? - title = obj[0].attrib['content'].decode('iso-5589-15') - - if title is not None: - title = title.strip() - m = re.match('GDC Vault\s+-\s+(.*)', title) - if m: - title = m.group(1) - video.title = title - - #TODO: POST back the title to /search.php and filter == id to get - # cleaner (JSON) data... (though it'd be much slower) - - # try to find an iframe (type 3 and 4) - obj = self.parser.select(self.document.getroot(), 'iframe') - if len(obj) == 0: - # type 1 or 2 (swf+js) - # find which script element contains the swf args - for script in self.parser.select(self.document.getroot(), 'script'): - m = re.match(".*new SWFObject.*addVariable\('type', '(.*)'\).*", unicode(script.text), re.DOTALL) - if m: - video.ext = m.group(1) - - m = re.match(".*new SWFObject.*addVariable\(\"file\", encodeURIComponent\(\"(.*)\"\)\).*", unicode(script.text), re.DOTALL) - if m: - video.url = "http://gdcvault.com%s" % (m.group(1)) - # TODO: for non-free (like 769), - # must be logged to use /mediaProxy.php - - # FIXME: doesn't seem to work yet, we get 2 bytes as html - # 769 should give: - # http://twvideo01.ubm-us.net/o1/gdcradio-net/2007/gdc/GDC07-4889.mp3 - # HACK: we use mechanize directly here for now... FIXME - #print "asking for redirect on '%s'" % (video.url) - #self.browser.addheaders += [['Referer', 'http://gdcvault.com/play/%s' % self.group_dict['id']]] - #print self.browser.addheaders - self.browser.set_handle_redirect(False) - try: - self.browser.open_novisit(video.url) - # headers = req.info() - # if headers.get('Content-Type', '') == 'text/html' and headers.get('Content-Length', '') == '2': - # print 'BUG' - - #print req.code - except HTTPError as e: - #print e.getcode() - if e.getcode() == 302 and hasattr(e, 'hdrs'): - #print e.hdrs['Location'] - video.url = unicode(e.hdrs['Location']) - self.browser.set_handle_redirect(True) - - video.set_empty_fields(NotAvailable) - return video - - #XXX: raise error? - return None - - obj = obj[0] - if obj is None: - return None - # type 3 or 4 (iframe) - # get the config file for the rest - iframe_url = obj.attrib['src'] - - # 1015020 has a boggus url - m = re.match('http:/event(.+)', iframe_url) - if m: - iframe_url = 'http://event' + m.group(1) - - # print iframe_url - # 1013798 has player169.html - # 1012186 has player16x9.html - # some other have /somethingplayer.html... - # 1441 has a space in the xml filename, which we must not strip - m = re.match('(http:.*/)[^/]*player[0-9a-z]*\.html\?.*xmlURL=([^&]+\.xml).*\&token=([^& ]+)', iframe_url) - - if not m: - m = re.match('/play/mediaProxy\.php\?sid=(\d+)', iframe_url) - if m is None: - return None - # TODO: must be logged to use /mediaProxy.php - # type 3 (pdf slides) - video.ext = u'pdf' - video.url = "http://gdcvault.com%s" % (unicode(iframe_url)) - - # HACK: we use mechanize directly here for now... FIXME - # print "asking for redirect on '%s'" % (video.url) - self.browser.set_handle_redirect(False) - try: - self.browser.open_novisit(video.url) - except HTTPError as e: - if e.getcode() == 302 and hasattr(e, 'hdrs'): - video.url = unicode(e.hdrs['Location']) - self.browser.set_handle_redirect(True) - - video.set_empty_fields(NotAvailable) - return video - - # type 4 (dual screen video) - - # token doesn't actually seem required - # 1441 has a space in the xml filename - xml_filename = quote(m.group(2)) - config_url = m.group(1) + xml_filename + '?token=' + m.group(3) - - # self.browser.addheaders += [['Referer', 'http://gdcvault.com/play/%s' % self.group_dict['id']]] - # print self.browser.addheaders - # TODO: fix for 1015021 & others (forbidden) - #config = self.browser.openurl(config_url).read() - config = self.browser.get_document(self.browser.openurl(config_url)) - - obj = self.parser.select(config.getroot(), 'akamaihost', 1) - host = obj.text - if host is None: - raise BrokenPageError('Missing tag in xml config file') - - if host == "smil": - # the rtmp URL is described in a smil file, - # with several available bitrates - obj = self.parser.select(config.getroot(), 'speakervideo', 1) - smil = self.browser.get_document(self.browser.openurl(obj.text)) - obj = self.parser.select(smil.getroot(), 'meta', 1) - # TODO: error checking - base = obj.attrib.get('base', '') - best_bitrate = 0 - path = None - obj = self.parser.select(smil.getroot(), 'video') - # choose the best bitrate - for o in obj: - rate = int(o.attrib.get('system-bitrate', 0)) - if rate > best_bitrate: - path = o.attrib.get('src', '') - video.url = unicode(base + '/' + path) - - else: - # not smil, the rtmp url is directly here as host + path - # for id 1373 host is missing '/ondemand' - # only add it when only a domain is specified without path - m = re.match('^[^\/]+$', host) - if m: - host += "/ondemand" - - videos = {} - - obj = self.parser.select(config.getroot(), 'speakervideo', 1) - if obj.text is not None: - videos['speaker'] = 'rtmp://' + host + '/' + quote(obj.text) - - obj = self.parser.select(config.getroot(), 'slidevideo', 1) - if obj.text is not None: - videos['slides'] = 'rtmp://' + host + '/' + quote(obj.text) - - # print videos - # XXX - if 'speaker' in videos: - video.url = unicode(videos['speaker']) - elif 'slides' in videos: - # 1016627 only has slides, so fallback to them - video.url = unicode(videos['slides']) - - if want_slides: - if 'slides' in videos: - video.url = unicode(videos['slides']) - # if video.url is none: raise ? XXX - - obj = self.parser.select(config.getroot(), 'date', 1) - if obj.text is not None: - # 1016634 has "Invalid Date" - try: - video.date = parse_dt(obj.text) - except ValueError as e: - video.date = NotAvailable - - obj = self.parser.select(config.getroot(), 'duration', 1) - m = re.match('(\d\d):(\d\d):(\d\d)', obj.text) - if m: - video.duration = datetime.timedelta(hours = int(m.group(1)), - minutes = int(m.group(2)), - seconds = int(m.group(3))) - - obj = self.parser.select(config.getroot(), 'speaker', 1) - #print obj.text_content() - - #self.set_details(video) - - video.set_empty_fields(NotAvailable) - return video - - obj = self.parser.select(self.document.getroot(), 'title') - if len(obj) < 1: - return None - title = obj[0].text.strip() - m = re.match('GDC Vault\s+-\s+(.*)', title) - if m: - title = m.group(1) - - def set_details(self, v): - obj = self.parser.select(self.document.getroot(), 'meta[name=available]', 1) - if obj is not None: - value = obj.attrib['content'] - m = re.match('(\d\d)-(\d\d)-(\d\d\d\d)\s*(\d\d):(\d\d)', value) - if not m: - raise BrokenPageError('Unable to parse datetime: %r' % value) - day = m.group(1) - month = m.group(2) - year = m.group(3) - hour = m.group(4) - minute = m.group(5) - v.date = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(hour), - minute=int(minute)) - - obj = self.parser.select(self.document.getroot(), 'span.ep_subtitle', 1) - if obj is not None: - span = self.parser.select(obj, 'span.ep_date', 1) - value = span.text - m = re.match('(\d\d):(\d\d)\s*\/\s*(\d\d):(\d\d)\s*-\s*(\d\d)-(\d\d)-(\d\d\d\d)', value) - if not m: - raise BrokenPageError('Unable to parse datetime: %r' % value) - bhour = m.group(1) - bminute = m.group(2) - ehour = m.group(3) - eminute = m.group(4) - day = m.group(5) - month = m.group(6) - year = m.group(7) - - start = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(bhour), - minute=int(bminute)) - end = datetime.datetime(year=int(year), - month=int(month), - day=int(day), - hour=int(ehour), - minute=int(eminute)) - - v.duration = end - start diff --git a/modules/gdcvault/test.py b/modules/gdcvault/test.py deleted file mode 100644 index 68125d8d86e41cbb282356359c0abac1de44b235..0000000000000000000000000000000000000000 --- a/modules/gdcvault/test.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Romain Bignon -# Copyright(C) 2012 François Revol -# -# 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 GDCVaultTest(BackendTest): - MODULE = 'gdcvault' - - # def test_search(self): - # l = list(self.backend.search_videos('linux')) - # 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/gdcvault/video.py b/modules/gdcvault/video.py deleted file mode 100644 index 08d90a79c8a248d1fe01f2d927a4141bef97522c..0000000000000000000000000000000000000000 --- a/modules/gdcvault/video.py +++ /dev/null @@ -1,92 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 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.image import Thumbnail -from weboob.capabilities.video import BaseVideo -from weboob.capabilities.base import NotAvailable - -import re -from dateutil.parser import parse as parse_dt - - -class GDCVaultVideo(BaseVideo): - def __init__(self, *args, **kwargs): - BaseVideo.__init__(self, *args, **kwargs) - # not always flv... - self.ext = NotAvailable - - @classmethod - def id2url(cls, _id): - # attempt to enlarge the id namespace to differentiate - # videos from the same page - m = re.match('\d+#speaker', _id) - if m: - return u'http://www.gdcvault.com/play/%s#speaker' % _id - m = re.match('\d+#slides', _id) - if m: - return u'http://www.gdcvault.com/play/%s#slides' % _id - return u'http://www.gdcvault.com/play/%s' % _id - - @classmethod - def get_video_from_json(self, data): - # session_id is unique per talk - # vault_media_id is unique per page - # (but can refer to 2 video files for dual screen) - # solr_id is "${vault_media_id}.${conference_id}.${session_id}.$vault_media_type_id{}" - - # XXX: do we filter them or let people know about them? - #if 'anchor' in data: - # if data['anchor']['href'] == '#': - # # file will not be accessible (not free and not logged in) - # return None - - if 'vault_media_id' not in data: - return None - media_id = int(data['vault_media_id']) - video = GDCVaultVideo(media_id) - - # 1013679 has \n in title... - video.title = unicode(data.get('session_name', '').replace('\n', '')) - - # TODO: strip out

,
and other html... - # XXX: 1013422 has all 3 and != - if 'overview' in data: - video.description = unicode(data['overview']) - elif 'spell' in data: - video.description = unicode(data['spell']) - else: - video.description = unicode(data.get('description', '')) - - if 'image' in data: - video.thumbnail = Thumbnail(data['image']) - video.thumbnail.url = video.thumbnail.id - - if 'speakers_name' in data: - video.author = unicode(", ".join(data['speakers_name'])) - - if 'start_date' in data: - video.date = parse_dt(data['start_date']) - - if 'score' in data: - video.rating = data['score'] - - video.set_empty_fields(NotAvailable) - - return video diff --git a/modules/gdfsuez/__init__.py b/modules/gdfsuez/__init__.py deleted file mode 100644 index d16ad8608eaf02ee32bf652384b570880002332b..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import GdfSuezModule - -__all__ = ['GdfSuezModule'] diff --git a/modules/gdfsuez/browser.py b/modules/gdfsuez/browser.py deleted file mode 100644 index 713a648124df31d4e8a676bfae2b3a8675b2ccf4..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/browser.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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 StringIO -from weboob.deprecated.browser import Browser, BrowserIncorrectPassword -from .pages import LoginPage, HomePage, AccountPage, TimeoutPage, HistoryPage, PdfPage - -__all__ = ['GdfSuez'] - - -class GdfSuez(Browser): - PROTOCOL = 'https' - DOMAIN = 'www.gdfsuez-dolcevita.fr' - PAGES = {'.*portail/clients.*?_nfpb=true&_pageLabel=page_identification': LoginPage, - '.*portail/clients.*?_nfpb=true&_pageLabel=page_accueil_compte_en_ligne': HomePage, - '.*p/visualiser_mes_contrats.*?_nfpb=true': AccountPage, - '.*p/page_historique_de_mes_factures': HistoryPage, - '.*clients.*?_nfpb=true&_nfls=false&_pageLabel=page_erreur_timeout_session': TimeoutPage - } - - loginp = '/portailClients/appmanager/portail/clients' - homep = '/portailClients/appmanager/portail/clients?_nfpb=true&_pageLabel=page_accueil_compte_en_ligne' - accountp = '/portailClients/client/p/visualiser_mes_contrats?_nfpb=true' - historyp = '/portailClients/client/p/page_historique_de_mes_factures' - - def __init__(self, *args, **kwargs): - Browser.__init__(self, *args, **kwargs) - - def home(self): - self.location(self.homep) - - def is_logged(self): - if self.is_on_page(LoginPage) or self.is_on_page(TimeoutPage): - return False - return True - - def login(self): - assert isinstance(self.username, basestring) - assert isinstance(self.password, basestring) - #assert isemail(self.username) - if not self.is_on_page(LoginPage): - self.location(self.loginp) - self.page.login(self.username, self.password) - if self.is_on_page(LoginPage): - raise BrowserIncorrectPassword() - - def get_subscription_list(self): - if not self.is_on_page(AccountPage): - self.location(self.accountp) - return self.page.get_subscription_list() - - def get_subscription(self, id): - assert isinstance(id, basestring) - for sub in self.get_subscription_list(): - if sub.id == id: - return sub - - def get_history(self, subscription): - if not self.is_on_page(HistoryPage): - self.location(self.historyp) - return self.page.get_history() - - def get_details(self, subscription): - bills = self.iter_documents() - id = bills[0].id - if not self.is_on_page(HistoryPage): - self.location(self.historyp) - url = 'https://www.gdfsuez-dolcevita.fr/' + self.get_document(id).url - response = self.openurl(url) - pdf = PdfPage(StringIO.StringIO(response.read())) - for detail in pdf.get_details(subscription.label): - yield detail - - def iter_documents(self): - if not self.is_on_page(HistoryPage): - self.location(self.historyp) - return self.page.get_documents() - - def get_document(self, id): - assert isinstance(id, basestring) - for b in self.iter_documents(): - if b.id == id: - return b diff --git a/modules/gdfsuez/favicon.png b/modules/gdfsuez/favicon.png deleted file mode 100644 index 0222cea313f76834a03037fa0c69d87970a3a6c5..0000000000000000000000000000000000000000 Binary files a/modules/gdfsuez/favicon.png and /dev/null differ diff --git a/modules/gdfsuez/module.py b/modules/gdfsuez/module.py deleted file mode 100644 index 6e43d4a7864a62974f80fe0b547e99a351ca65b1..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/module.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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.bill import CapDocument, SubscriptionNotFound,\ - DocumentNotFound, Subscription, Bill -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword -from .browser import GdfSuez - -__all__ = ['GdfSuezModule'] - - -class GdfSuezModule(Module, CapDocument): - NAME = 'gdfsuez' - MAINTAINER = u'Mathieu Jourdan' - EMAIL = 'mathieu.jourdan@gresille.org' - VERSION = '1.4' - LICENSE = 'AGPLv3+' - DESCRIPTION = u'GDF-Suez French energy provider' - CONFIG = BackendConfig(ValueBackendPassword('login', - label='Account ID (e-mail)', - masked=False), - ValueBackendPassword('password', - label='Password', - masked=True) - ) - BROWSER = GdfSuez - - def create_default_browser(self): - return self.create_browser(self.config['login'].get(), - self.config['password'].get()) - - def iter_subscription(self): - for subscription in self.browser.get_subscription_list(): - yield subscription - - def get_subscription(self, _id): - if not _id.isdigit(): - raise SubscriptionNotFound() - with self.browser: - subscription = self.browser.get_subscription(_id) - if not subscription: - raise SubscriptionNotFound() - else: - return subscription - - def iter_documents_history(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - with self.browser: - for history in self.browser.get_history(subscription): - yield history - - def get_details(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - with self.browser: - for detail in self.browser.get_details(subscription): - yield detail - - def iter_documents(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - with self.browser: - for bill in self.browser.iter_documents(): - yield bill - - def get_document(self, id): - with self.browser: - bill = self.browser.get_document(id) - if not bill: - raise DocumentNotFound() - else: - return bill - - def download_document(self, bill): - if not isinstance(bill, Bill): - bill = self.get_document(bill) - with self.browser: - return self.browser.readurl(bill.url) diff --git a/modules/gdfsuez/pages/__init__.py b/modules/gdfsuez/pages/__init__.py deleted file mode 100644 index f77d26906cd4dbe0712774b44517dd5c5f852a29..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/pages/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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 .history import HistoryPage, PdfPage -from .homepage import LoginPage, HomePage, AccountPage, TimeoutPage - -__all__ = ['LoginPage', 'HomePage', 'AccountPage', 'HistoryPage', 'PdfPage', 'TimeoutPage'] diff --git a/modules/gdfsuez/pages/history.py b/modules/gdfsuez/pages/history.py deleted file mode 100644 index 8a3b77f2749ddea1941b06d1fa47f54cb855ecf9..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/pages/history.py +++ /dev/null @@ -1,211 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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 re -import os -import subprocess -import tempfile -import shutil - -from datetime import date -from decimal import Decimal - -from weboob.deprecated.browser import Page -from weboob.capabilities.base import NotAvailable -from weboob.capabilities.bill import Detail, Bill - - -class HistoryPage(Page): - - def on_loaded(self): - self.details = [] - self.bills = [] - - # Latest bill - div = self.document.xpath('//div[@class="consulter_dernierefacture"]')[0] - bdate = div.xpath('p[@class="date"]/span[@class="textetertiaire"]')[0].text - bprice = div.xpath('p[@class="montant"]/span[@class="textetertiaire"]')[0].text - link = div.xpath('a[@id="display_popin"]')[0].attrib['href'] - mydate = date(*reversed([int(x) for x in bdate.split("/")])) - price = Decimal(bprice.strip(u' € TTC').replace(',', '.')) - self.bills.append(self._create_bill(mydate, price, link)) - - # Previous bills - table = self.document.xpath('//table[@class="afficher_factures"]')[0] - for tr in table[0].xpath('//tbody/tr'): - cells = tr.xpath('td') - bdate = unicode(cells[0].text.strip()) - mydate = date(*reversed([int(x) for x in bdate.split("/")])) - bprice = unicode(cells[1].text) - price = Decimal(bprice.strip(u' €').replace(',', '.')) - link = cells[3].xpath('a')[0].attrib['href'] - self.bills.append(self._create_bill(mydate, price, link)) - - def _create_bill(self, date, price, link): - bill = Bill() - bill.id = date.__str__().replace('-', '') - bill.date = date - bill._price = price - bill.url = unicode(link) - bill.format = u'pdf' - bill.type = u'bill' - bill.label = unicode(price) - return bill - - def get_details(self): - return self.details - - def get_documents(self): - return self.bills - - -class PdfPage(): - - def __init__(self, file): - self.pdf = file - - def _parse_pdf(self): - pdffile = tempfile.NamedTemporaryFile(bufsize=100000, mode='w', suffix='.pdf') - temptxt = pdffile.name.replace('.pdf', '.txt') - cmd = "ebook-convert" - stdout = open("/dev/null", "w") - shutil.copyfileobj(self.pdf, pdffile) - pdffile.flush() - subprocess.call([cmd, pdffile.name, temptxt], stdout=stdout) - pdffile.close() - txtfile = open(temptxt, 'r') - txt = txtfile.read() - txtfile.close() - os.remove(temptxt) - return txt - - def _parse_page(self, page): - - # Regexp - footnote = re.compile(r'\([0-9]\) ') # (f) - ht = re.compile('HT par mois') - base = re.compile('la base de') - enddate = re.compile('\d\d\/\d\d\/\d\d') # YY/MM/DD - endwithdigit = re.compile('\d+$') # blah blah 42 - textwithcoma = re.compile('([a-z]|\d{4})\,') # blah 2012, blah blah - - # Parsing - details = [] - for title in ['Abonnement', - 'Consommation', - 'Contributions et taxes liées à l\'énergie']: - section = page.split(title, 1)[1].split('Total ')[0] - - # When a line holds '(0)', a newline is missing. - section = re.sub(footnote, '\n', section) - - lines = section.split('\n') - lines = [x for x in lines if len(x) > 0] # Remove empty lines - detail = None - - for line in lines: - if re.match('[A-Za-z]', line[0]): - - # Things we want to merge with the one just before - if 'facturées' in line: - # Long lines are sometimes split, so we try to join them - # That is the case for: - # 'Déduction du montant des consommations - # estimées facturées du 00/00/00 au 00/00/00' - detail.label = detail.label + u' ' + unicode(line, encoding='utf-8') - - # Things for which we want a new detail - else: - # Entering here, we will instantiate a new detail. - # We hadn't so before because of fragmented lines. - if detail is not None and detail.label is not NotAvailable: - # We have a new element, return the other one - details.append(detail) - detail = Detail() - detail.price = Decimal(0) - - # If the coma is not a decimal separator, then - # this is is probably a loooong sentence. - # When it comes to jokes, keep it short and sweet. - line = re.split(textwithcoma, line)[0] - - # Things we want for sure - if re.findall(enddate, line): - # When a line has been badly split after a date, - # We want the label to end after the date, and maybe - # the second part to be the info - mydate = re.search(enddate, line).group(0) - mylist = line.rpartition(mydate) - label = mylist[0] + mylist[1] - detail.label = unicode(label, encoding='utf-8') - elif re.findall(endwithdigit, line): - # What is this stupid number at the end of the line? - # Line should have been split before the number - detail.label = unicode(re.split(endwithdigit, line)[0], encoding='utf-8') - # Things we don't want for sure - elif ')' in line and '(' not in line: - # First part of the parenthesis should have been drop before - # Avoid to create a new empty detail - detail.label = NotAvailable - elif re.match(base, line): - # This string should come always after a date, - # usually, it will match one of the cases above. - # Sometimes, it appears on a new line we don't need. - detail.label = NotAvailable - elif re.match(ht, line): - # '00,00 € HT par mois' may have been split after HT - # We don't need of the second line - detail.label = NotAvailable - # Things we probably want to keep - else: - # Well, maybe our line is correct, after all. - # Not much to do. - detail.label = unicode(line, encoding='utf-8') - detail.infos = NotAvailable - elif ' %' in line: - if isinstance(detail, Detail): - # Sometimes the vat is not on a new line: - # '00,00 00,0 %' instead of '00,0 %' - vat = line.split()[line.count(' ')-1].replace(',', '.') - detail.infos = unicode('TVA: ' + vat) - elif ' €' in line: - price = line.replace(',', '.') - if isinstance(detail, Detail): - detail.price = Decimal(price.strip(' €')) - elif re.match(enddate, line): - # Line holding dates may have been mixed up - label = detail.label.split(' au ')[0] + u' au ' + unicode(line, encoding='utf-8') - detail.label = label - if detail.label is not NotAvailable: - # Do not append empty details to the list - # It seemed easier to create details anyway than dealing - # with None objects - details.append(detail) - return details - - def get_details(self, label): - txt = self._parse_pdf() - page = None - if label == u'Gaz naturel': - page = txt.split('GAZ NATUREL')[1].split('TOTAL GAZ NATUREL TTC')[0] - elif label == u'Electricité': - page = txt.split('ELECTRICITE')[1].split('TOTAL ELECTRICITE TTC')[0] - else: - pass - return self._parse_page(page) diff --git a/modules/gdfsuez/pages/homepage.py b/modules/gdfsuez/pages/homepage.py deleted file mode 100644 index 8164dbea15ed15b914257f2b11003437c9cd4b6e..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/pages/homepage.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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 datetime import date - -from weboob.deprecated.browser import Page -from weboob.capabilities.bill import Subscription - - -class LoginPage(Page): - - def login(self, login, password): - self.browser.select_form('symConnexionForm') - self.browser["portlet_login_plein_page_3{pageFlow.mForm.login}"] = unicode(login) - self.browser["portlet_login_plein_page_3{pageFlow.mForm.password}"] = unicode(password) - self.browser.submit() - - -class HomePage(Page): - - def on_loaded(self): - pass - - -class AccountPage(Page): - - def get_subscription_list(self): - table = self.document.xpath('//table[@id="ensemble_contrat_N0"]')[0] - if len(table) > 0: - # some clients may have subscriptions to gas and electricity, - # but they receive a single bill - # to avoid "boobill details" and "boobill bills" returning the same - # table twice, we could return only one subscription for both. - # We do not, and "boobill details" will take care of parsing only the - # relevant section in the bill files. - for line in table[0].xpath('//tbody/tr'): - cells = line.xpath('td') - snumber = cells[2].attrib['id'].replace('Contrat_', '') - slabel = cells[0].xpath('a')[0].text.replace('offre', '').strip() - d = unicode(cells[3].xpath('strong')[0].text.strip()) - sdate = date(*reversed([int(x) for x in d.split("/")])) - sub = Subscription(snumber) - sub._id = snumber - sub.label = slabel - sub.subscriber = unicode(cells[1]) - sub.renewdate = sdate - yield sub - - -class TimeoutPage(Page): - - def on_loaded(self): - pass diff --git a/modules/gdfsuez/test.py b/modules/gdfsuez/test.py deleted file mode 100644 index 70f66fd66cf68d145c0dde6dec30313ac3865281..0000000000000000000000000000000000000000 --- a/modules/gdfsuez/test.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Mathieu Jourdan -# -# 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 . - - -# This is a clone of freemobile/test.py for the gdfsuez module -from weboob.tools.test import BackendTest - - -class GdfSuezTest(BackendTest): - MODULE = 'gdfsuez' - - def test_gdfsuez(self): - for subscription in self.backend.iter_subscription(): - list(self.backend.iter_history(subscription.id)) - for bill in self.backend.iter_documents(subscription.id): - self.backend.download_document(bill.id) diff --git a/modules/izneo/__init__.py b/modules/izneo/__init__.py deleted file mode 100644 index 8da0d5594ce092aefcda8c44a0effcf41fde3f39..0000000000000000000000000000000000000000 --- a/modules/izneo/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 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 .module import IzneoModule - -__all__ = ['IzneoModule'] diff --git a/modules/izneo/favicon.png b/modules/izneo/favicon.png deleted file mode 100644 index c883a32d6046f12c582c8927179825a31cb94f4e..0000000000000000000000000000000000000000 Binary files a/modules/izneo/favicon.png and /dev/null differ diff --git a/modules/izneo/module.py b/modules/izneo/module.py deleted file mode 100644 index 03840bb4f5acb3d175b584fce806c8ff45c7af69..0000000000000000000000000000000000000000 --- a/modules/izneo/module.py +++ /dev/null @@ -1,96 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 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 re - -from weboob.capabilities.gallery import CapGallery, BaseGallery, BaseImage -from weboob.tools.json import json -from weboob.tools.backend import Module -from weboob.deprecated.browser import Browser, Page - -__all__ = ['IzneoModule'] - - -class ReaderV2(Page): - def get_ean(self): - return self.document.xpath("//div[@id='viewer']/attribute::rel")[0] - - def iter_gallery_images(self, gallery): - ean = self.get_ean() - pages = json.load(self.browser.openurl( - 'http://www.izneo.com/playerv2/ajax.php?ean=%s&action=get_list_jpg' - % ean)) - - for page in pages['list']: - width = 1200 # maximum width - yield BaseImage(page['page'], - gallery=gallery, - url=("http://www.izneo.com/playerv2/%s/%s/%s/%d/%s" % - (page['expires'], page['token'], ean, width, page['page']))) - - -class IzneoBrowser(Browser): - PAGES = {r'http://.+\.izneo.\w+/readv2-.+': ReaderV2} - - def iter_gallery_images(self, gallery): - self.location(gallery.url) - assert self.is_on_page(ReaderV2) - return self.page.iter_gallery_images(gallery) - - def fill_image(self, image, fields): - if 'data' in fields: - image.data = self.readurl(self.request_class( - image.url, None, {'Referer': image.gallery.url})) - - -class IzneoModule(Module, CapGallery): - NAME = 'izneo' - MAINTAINER = u'Roger Philibert' - EMAIL = 'roger.philibert@gmail.com' - VERSION = '1.4' - DESCRIPTION = 'Izneo digital comics' - LICENSE = 'AGPLv3+' - BROWSER = IzneoBrowser - - def iter_gallery_images(self, gallery): - with self.browser: - return self.browser.iter_gallery_images(gallery) - - def get_gallery(self, _id): - match = re.match(r'(?:(?:.+izneo.com/)?readv2-)?(\d+-\d+)/?$', _id) - if match is None: - return None - - _id = match.group(1) - - gallery = BaseGallery(_id, url=('http://www.izneo.com/readv2-%s' % _id)) - with self.browser: - return gallery - - def fill_gallery(self, gallery, fields): - gallery.title = gallery.id - - def fill_image(self, image, fields): - with self.browser: - self.browser.fill_image(image, fields) - - OBJECTS = { - BaseGallery: fill_gallery, - BaseImage: fill_image} diff --git a/modules/jacquieetmichel/__init__.py b/modules/jacquieetmichel/__init__.py deleted file mode 100644 index c2c25391a84f6bdaab9939445f34faedb66865d8..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- 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 .module import JacquieEtMichelModule - -__all__ = ['JacquieEtMichelModule'] diff --git a/modules/jacquieetmichel/browser.py b/modules/jacquieetmichel/browser.py deleted file mode 100644 index 21a379bda38f0b9b8a171037f1abc74627c828a2..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/browser.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- 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.deprecated.browser import Browser -from weboob.deprecated.browser.decorators import id2url -from weboob.tools.compat import quote - -from .video import JacquieEtMichelVideo -from .pages import VideoPage, ResultsPage - - -__all__ = ['JacquieEtMichelBrowser'] - - -class JacquieEtMichelBrowser(Browser): - 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/' % (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 deleted file mode 100644 index cb8548498dcbd0b26e12b255770a7c0a4d1ee03c..0000000000000000000000000000000000000000 Binary files a/modules/jacquieetmichel/favicon.png and /dev/null differ diff --git a/modules/jacquieetmichel/module.py b/modules/jacquieetmichel/module.py deleted file mode 100644 index 77823bcd4d77582f37cf985d88d1a9082d2bc97f..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/module.py +++ /dev/null @@ -1,80 +0,0 @@ -# -*- 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 CapVideo, BaseVideo -from weboob.capabilities.collection import CapCollection, CollectionNotFound -from weboob.tools.backend import Module - -from .browser import JacquieEtMichelBrowser -from .video import JacquieEtMichelVideo - - -__all__ = ['JacquieEtMichelModule'] - - -class JacquieEtMichelModule(Module, CapVideo, CapCollection): - NAME = 'jacquieetmichel' - MAINTAINER = u'Roger Philibert' - EMAIL = 'roger.philibert@gmail.com' - VERSION = '1.4' - 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=CapVideo.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/pages.py b/modules/jacquieetmichel/pages.py deleted file mode 100644 index 834395203169f56f4faf0568719989a6a847c35a..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/pages.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- 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 re - -from weboob.capabilities.base import NotAvailable -from weboob.capabilities.image import Thumbnail -from weboob.deprecated.browser import Page, BrokenPageError -from weboob.tools.misc import to_unicode - -from .video import JacquieEtMichelVideo - - -class ResultsPage(Page): - 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) - - url = span.find('.//img').attrib['src'] - video.thumbnail = Thumbnail(url) - video.thumbnail.url = video.thumbnail.id - - 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(Page): - 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 deleted file mode 100644 index 9e3b3ee5345e8df1f24ae718751ac8bcb6952338..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/test.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- 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): - MODULE = '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 deleted file mode 100644 index 838f5ad5b4fd076bafdff3f10f579810929f7453..0000000000000000000000000000000000000000 --- a/modules/jacquieetmichel/video.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- 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 - - -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 diff --git a/modules/jvmalin/__init__.py b/modules/jvmalin/__init__.py deleted file mode 100644 index 8e89bd6fa4534997c33cac953b9af5d0635b2e36..0000000000000000000000000000000000000000 --- a/modules/jvmalin/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Alexandre Lissy -# -# 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 .module import JVMalinModule - -__all__ = ['JVMalinModule'] diff --git a/modules/jvmalin/browser.py b/modules/jvmalin/browser.py deleted file mode 100644 index d01934f73fafce65b32985ac069ff8b33cf8359a..0000000000000000000000000000000000000000 --- a/modules/jvmalin/browser.py +++ /dev/null @@ -1,63 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Alexandre Lissy -# -# 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.deprecated.browser import Browser -from .pages import RoadmapSearchPage, RoadmapResultsPage, RoadmapPage, RoadmapAmbiguity - - -__all__ = ['JVMalin'] - - -class JVMalin(Browser): - DOMAIN = 'www.jvmalin.fr' - PAGES = { - 'http://www\.jvmalin\.fr/Itineraires/Recherche.*': RoadmapSearchPage, - 'http://www\.jvmalin\.fr/Itineraires/Precision.*': RoadmapResultsPage, - 'http://www\.jvmalin\.fr/route/vuesearch/result.*': RoadmapPage - } - - def __init__(self, **kwargs): - Browser.__init__(self, '', **kwargs) - - def get_roadmap(self, departure, arrival, filters): - self.location('/Itineraires/Recherche') - - assert self.is_on_page(RoadmapSearchPage) - self.page.search(departure, arrival, filters.departure_time, filters.arrival_time) - - assert self.is_on_page(RoadmapResultsPage) - - dest = '' - try: - dest = self.page.find_best() - except RoadmapAmbiguity: - self.page.resubmit_best_form() - assert self.is_on_page(RoadmapResultsPage) - dest = self.page.find_best() - - self.location(dest) - - roadmap = {} - roadmap['steps'] = list(self.page.get_steps()) - return roadmap - - def is_logged(self): - """ Do not need to be logged """ - return True diff --git a/modules/jvmalin/favicon.png b/modules/jvmalin/favicon.png deleted file mode 100644 index d51f867f111684158b9427d8f24f60cd7e0d6bac..0000000000000000000000000000000000000000 Binary files a/modules/jvmalin/favicon.png and /dev/null differ diff --git a/modules/jvmalin/module.py b/modules/jvmalin/module.py deleted file mode 100644 index 3e3092650b7fcc39afb30c3c52b9d3a2c9b0afaf..0000000000000000000000000000000000000000 --- a/modules/jvmalin/module.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Alexandre Lissy -# -# 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.travel import CapTravel, RoadStep -from weboob.tools.backend import Module - -from .browser import JVMalin - - -__all__ = ['JVMalinModule'] - - -class JVMalinModule(Module, CapTravel): - NAME = 'jvmalin' - MAINTAINER = u'Alexandre Lissy' - EMAIL = 'github@lissy.me' - VERSION = '1.4' - LICENSE = 'AGPLv3+' - DESCRIPTION = u"Multimodal public transportation for whole Région Centre, France" - BROWSER = JVMalin - - def iter_roadmap(self, departure, arrival, filters): - with self.browser: - roadmap = self.browser.get_roadmap(departure, arrival, filters) - - for s in roadmap['steps']: - step = RoadStep(s['id']) - step.line = s['line'] - step.start_time = s['start_time'] - step.end_time = s['end_time'] - step.departure = s['departure'] - step.arrival = s['arrival'] - step.duration = s['duration'] - yield step diff --git a/modules/jvmalin/pages.py b/modules/jvmalin/pages.py deleted file mode 100644 index 6184405e3e0cffdb33a132d18a4903da7f097c8a..0000000000000000000000000000000000000000 --- a/modules/jvmalin/pages.py +++ /dev/null @@ -1,208 +0,0 @@ -# -*- coding: utf-8 -*- - -import datetime -import re - -from mechanize import ItemNotFoundError - -from weboob.capabilities.travel import RoadmapError -from weboob.deprecated.browser import Page -from weboob.tools.misc import to_unicode - - -class RoadmapAmbiguity(RoadmapError): - def __init__(self, error): - RoadmapError.__init__(self, error) - - -class RoadmapSearchPage(Page): - def search(self, departure, arrival, departure_time, arrival_time): - match = -1 - i = 0 - for form in self.browser.forms(): - try: - if form.attrs['id'] == 'rech-iti': - match = i - except KeyError: - pass - i += 1 - - self.browser.select_form(nr=match) - self.browser['Departure'] = departure - self.browser['Destination'] = arrival - - time = None - if departure_time: - self.browser['sens'] = ['1'] - time = departure_time - elif arrival_time: - self.browser['sens'] = ['-1'] - time = arrival_time - - if time: - try: - self.browser['dateFull'] = '%02d/%02d/%d' % (time.day, time.month, time.year) - self.browser['hour'] = ['%02d' % time.hour] - self.browser['minute'] = ['%02d' % (time.minute - (time.minute % 5))] - except ItemNotFoundError: - raise RoadmapError('Unable to establish a roadmap with %s time at "%s"' % ('departure' if departure_time else 'arrival', time)) - self.browser.submit() - - -class RoadmapResultsPage(Page): - def html_br_strip(self, text): - return "".join([l.strip() for l in text.split("\n")]).strip().replace(' ', '%20') - - def find_best(self): - if len(self.parser.select(self.document.getroot(), 'img.img-error')) > 0: - if len(self.parser.select(self.document.getroot(), 'form#iti-ambi')) > 0: - raise RoadmapAmbiguity('Ambigious stop name') - else: - raise RoadmapError('Error when submitting form') - - best = self.parser.select(self.document.getroot(), 'div.alerte-bloc-important div.bloc-iti') - if len(best) == 0: - best = self.parser.select(self.document.getroot(), 'div.bloc-iti') - if len(best) == 0: - raise RoadmapError('Unable to get the best roadmap') - - link = self.parser.select(best[0], 'a.btn-submit') - if len(link) == 0: - raise RoadmapError('Unable to get a link to best roadmap') - - return self.html_br_strip(link[0].attrib['href']) - - def resubmit_best_form(self): - if len(self.parser.select(self.document.getroot(), 'img.img-error')) == 0: - raise RoadmapError('No error reported!') - - ambi = None - i = 0 - for form in self.parser.select(self.document.getroot(), 'form'): - if 'id' in form.attrib and form.attrib['id'] == 'iti-ambi': - ambi = form - break - i += 1 - - if ambi is None: - raise RoadmapError('No ambigous form!') - - props = self.parser.select(ambi, 'span.precision-arret input') - if len(props) == 0: - props = self.parser.select(ambi, 'span.precision-adresse input') - if len(props) == 0: - raise RoadmapError('Nothing to select to get a roadmap') - - self.browser.select_form(nr=i) - propname = props[0].attrib['name'] - propvalue = props[0].attrib['value'].encode('utf-8') - self.browser[propname] = [ propvalue ] - self.browser.submit() - - -class RoadmapPage(Page): - def get_steps(self): - errors = [] - # for p in self.parser.select(self.document.getroot(), 'p.errors'): - # if p.text: - # errors.append(p.text.strip()) - - if len(errors) > 0: - raise RoadmapError('Unable to establish a roadmap: %s' % ', '.join(errors)) - - current_step = None - i = 0 - for tr in self.parser.select(self.document.getroot(), 'table.itineraire-detail tr'): - if current_step is None: - current_step = { - 'id': i, - 'start_time': datetime.datetime.now(), - 'end_time': datetime.datetime.now(), - 'line': '', - 'departure': '', - 'arrival': '', - 'duration': datetime.timedelta() - } - - if 'class' in tr.attrib: - if 'bg-ligne' in tr.attrib['class']: - continue - - if 'iti-map' in tr.attrib['class']: - continue - - for td in self.parser.select(tr, 'td'): - if 'class' not in td.attrib: - continue - - if 'iti-inner' in td.attrib['class']: - continue - - if 'cell-infos' in td.attrib['class']: - if 'id' in td.attrib: - if td.attrib['id'].find('MapOpenLink') >= 0: - hasA = self.parser.select(td, 'a') - if len(hasA) == 0: - if len(current_step['line']) > 0 and \ - len(current_step['departure']) > 0 and \ - len(current_step['arrival']) > 0: - current_step['line'] = to_unicode("%s : %s" % - (current_step['mode'], current_step['line'])) - del current_step['mode'] - yield current_step - i += 1 - current_step = None - continue - - if 'cell-horaires' in td.attrib['class']: - # real start - for heure in self.parser.select(td, 'span.heure'): - if heure.attrib['id'].find('FromTime') >= 0: - current_step['start_time'] = self.parse_time(heure.text) - if heure.attrib['id'].find('ToTime') >= 0: - current_step['end_time'] = self.parse_time(heure.text) - for mode in self.parser.select(td, 'span.mode-locomotion img'): - current_step['mode'] = mode.attrib['title'] - - if 'cell-details' in td.attrib['class']: - # If we get a span, it's a line indication, - # otherwise check for id containing LibDeparture or - # LibDestination - spans = self.parser.select(td, 'span.itineraire-ligne') - if len(spans) == 1: - line = self.html_br_strip(spans[0].text, " ").replace('Ligne ', '') - if line.index('- ') == 0: - line = re.sub(r'^- ', '', line) - current_step['line'] = line - - elif 'id' in td.attrib: - stops = self.parser.select(td, 'strong') - stop = self.html_br_strip(stops[0].text, " ") - - if td.attrib['id'].find('LibDeparture') >= 0: - current_step['departure'] = to_unicode(stop) - - if td.attrib['id'].find('LibDestination') >= 0: - current_step['arrival'] = to_unicode(stop) - - duree = self.parser.select(td, 'span.duree strong') - if len(duree) == 1: - current_step['duration'] = self.parse_duration(duree[0].text) - - def html_br_strip(self, text, joining=""): - return joining.join([l.strip() for l in text.split("\n")]).strip() - - def parse_time(self, time): - time = self.html_br_strip(time) - h, m = time.split('h') - return datetime.time(int(h), int(m)) - - def parse_duration(self, dur): - dur = self.html_br_strip(dur) - m = re.match('(\d+)min', dur) - if m: - return datetime.timedelta(minutes=int(m.group(1))) - m = re.match('(\d+)h(\d+)', dur) - if m: - return datetime.timedelta(hours=int(m.group(1)), - minutes=int(m.group(2))) diff --git a/modules/jvmalin/test.py b/modules/jvmalin/test.py deleted file mode 100644 index b0b954ac7567358419c8fe9a7a62c7832baf8b85..0000000000000000000000000000000000000000 --- a/modules/jvmalin/test.py +++ /dev/null @@ -1,69 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Alexandre Lissy -# -# 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 datetime - -from weboob.capabilities.travel import RoadmapFilters -from weboob.tools.test import BackendTest - - -class JVMalinTest(BackendTest): - MODULE = 'jvmalin' - - def test_roadmap_cities(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('Tours', 'Orléans', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_stop_intercity(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('Tours Jean-Jaurès', 'Orléans', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_stop_intracity(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('Tours Jean-Jaurès', 'Polytech Tours', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_stop_intracity2(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('J.P.Rameau', 'Polytech Tours', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_names(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('Artannes Mairie', 'Château de Blois', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_long(self): - filters = RoadmapFilters() - roadmap = list(self.backend.iter_roadmap('Chartres', 'Ballan-Miré', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_departure(self): - filters = RoadmapFilters() - filters.departure_time = datetime.datetime.now() + datetime.timedelta(days=1) - roadmap = list(self.backend.iter_roadmap('Chartres', 'Ballan-Miré', filters)) - self.assertTrue(len(roadmap) > 0) - - def test_roadmap_arrival(self): - filters = RoadmapFilters() - filters.arrival_time = datetime.datetime.now() + datetime.timedelta(days=1) - roadmap = list(self.backend.iter_roadmap('Chartres', 'Ballan-Miré', filters)) - self.assertTrue(len(roadmap) > 0) diff --git a/modules/leclercmobile/__init__.py b/modules/leclercmobile/__init__.py deleted file mode 100644 index 709018936ef7df6bd9f37b26e96e7e5c01a0850e..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 .module import LeclercMobileModule - -__all__ = ['LeclercMobileModule'] diff --git a/modules/leclercmobile/browser.py b/modules/leclercmobile/browser.py deleted file mode 100644 index e134bd86aa5a10226f40e6bce83f480ec336ac21..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/browser.py +++ /dev/null @@ -1,152 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Fourcot Florent -# -# 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 time -from io import BytesIO - -from weboob.deprecated.browser import Browser, BrowserIncorrectPassword -from .pages import HomePage, LoginPage, HistoryPage, PdfPage -from weboob.capabilities.bill import Detail -from weboob.capabilities.base import NotAvailable - - -__all__ = ['Leclercmobile'] - - -class Leclercmobile(Browser): - DOMAIN = 'www.securelmobile.fr' - PROTOCOL = 'https' - ENCODING = 'utf-8' - PAGES = {'.*pgeWERL008_Login.aspx.*': LoginPage, - '.*EspaceClient/pgeWERL013_Accueil.aspx': HomePage, - '.*pgeWERL009_ReleveConso.aspx.*': HistoryPage, - '.*ReleveConso.ashx.*': PdfPage - } - accueil = "/EspaceClient/pgeWERL013_Accueil.aspx" - login = "/EspaceClient/pgeWERL008_Login.aspx" - conso = "/EspaceClient/pgeWERL009_ReleveConso.aspx" - bills = '/EspaceClient/pgeWERL015_RecupReleveConso.aspx?m=-' - - def __init__(self, *args, **kwargs): - Browser.__init__(self, *args, **kwargs) - - def home(self): - self.location(self.accueil) - - def is_logged(self): - return not self.is_on_page(LoginPage) - - def login(self): - assert isinstance(self.username, basestring) - assert isinstance(self.password, basestring) - assert self.username.isdigit() - - if not self.is_on_page(LoginPage): - self.location(self.login) - - form = self.page.login(self.username, self.password) - - # Site display a javascript popup to wait - while self.page.iswait(): - # In this popup can be an error displayed - if self.page.iserror(): - raise BrowserIncorrectPassword() - time.sleep(1) - self.page.next(self.username, form) - - # The last document contain a redirect url in the javascript - self.location(self.page.getredirect()) - - if self.is_on_page(LoginPage): - raise BrowserIncorrectPassword() - - def viewing_html(self): - # To prevent unknown mimetypes sent by server, we assume we - # are always on a HTML document. - return True - - def get_subscription_list(self): - if not self.is_on_page(HomePage): - self.location(self.acceuil) - - return self.page.get_list() - - def get_subscription(self, id): - assert isinstance(id, basestring) - - if not self.is_on_page(HomePage): - self.location(self.accueil) - - l = self.page.get_list() - for a in l: - if a.id == id: - return a - - return None - - def get_history(self): - if not self.is_on_page(HistoryPage): - self.location(self.conso) - maxid = self.page.getmaxid() - - for i in range(maxid + 1): - response = self.openurl(self.bills + str(i)) - mimetype = response.info().get('Content-Type', '').split(';')[0] - if mimetype == "application/pdf": - pdf = PdfPage(BytesIO(response.read())) - for call in pdf.get_calls(): - call.label = call.label.strip() - yield call - - def get_details(self): - if not self.is_on_page(HistoryPage): - self.location(self.conso) - response = self.openurl(self.bills + "0") - mimetype = response.info().get('Content-Type', '').split(';')[0] - if mimetype == "application/pdf": - pdf = PdfPage(BytesIO(response.read())) - for detail in pdf.get_details(): - yield detail - - def iter_documents(self, parentid): - if not self.is_on_page(HistoryPage): - self.location(self.conso) - return self.page.date_bills(parentid) - - def get_document(self, id): - assert isinstance(id, basestring) - if not self.is_on_page(HistoryPage): - self.location(self.conso) - parentid = id[0:10] - l = self.page.date_bills(parentid) - for a in l: - if a.id == id: - return a - - def get_balance(self): - if not self.is_on_page(HistoryPage): - self.location(self.conso) - detail = Detail() - detail.label = u"Balance" - for calls in self.get_history(): - if "Votre solde" in calls.label: - detail.price = calls.price - return detail - detail.price = NotAvailable - return detail diff --git a/modules/leclercmobile/favicon.png b/modules/leclercmobile/favicon.png deleted file mode 100644 index b2d0c897f6c9921696abd59ec8d53e6a91b8c3d4..0000000000000000000000000000000000000000 Binary files a/modules/leclercmobile/favicon.png and /dev/null differ diff --git a/modules/leclercmobile/module.py b/modules/leclercmobile/module.py deleted file mode 100644 index c9db7639400b56b240df1483039b58b1691b4ece..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/module.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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.bill import CapDocument, SubscriptionNotFound,\ - DocumentNotFound, Subscription, Bill -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword - -from .browser import Leclercmobile - - -__all__ = ['LeclercMobileModule'] - - -class LeclercMobileModule(Module, CapDocument): - NAME = 'leclercmobile' - MAINTAINER = u'Florent Fourcot' - EMAIL = 'weboob@flo.fourcot.fr' - VERSION = '1.4' - LICENSE = 'AGPLv3+' - DESCRIPTION = 'Leclerc Mobile website' - CONFIG = BackendConfig(ValueBackendPassword('login', - label='Account ID', - masked=False, - regexp='^(\d{10}|)$'), - ValueBackendPassword('password', - label='Password') - ) - BROWSER = Leclercmobile - - def create_default_browser(self): - return self.create_browser(self.config['login'].get(), - self.config['password'].get()) - - def iter_subscription(self): - for subscription in self.browser.get_subscription_list(): - yield subscription - - def get_subscription(self, _id): - if not _id.isdigit(): - raise SubscriptionNotFound() - with self.browser: - subscription = self.browser.get_subscription(_id) - if subscription: - return subscription - else: - raise SubscriptionNotFound() - - def iter_documents_history(self, subscription): - with self.browser: - for history in self.browser.get_history(): - if history.label != "Votre solde": - yield history - - def get_document(self, id): - with self.browser: - bill = self.browser.get_document(id) - if bill: - return bill - else: - raise DocumentNotFound() - - def iter_documents(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - - with self.browser: - for bill in self.browser.iter_documents(subscription.id): - yield bill - - # The subscription is actually useless, but maybe for the futur... - def get_details(self, subscription): - with self.browser: - for detail in self.browser.get_details(): - yield detail - - def download_document(self, bill): - if not isinstance(bill, Bill): - bill = self.get_document(bill) - - with self.browser: - return self.browser.readurl(bill.url) - - def get_balance(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - with self.browser: - balance = self.browser.get_balance() - balance.label = u"Balance %s" % subscription.id - balance.id = "%s-balance" % subscription.id - balance.currency = u'EUR' - return balance diff --git a/modules/leclercmobile/pages/__init__.py b/modules/leclercmobile/pages/__init__.py deleted file mode 100644 index 05e6c00e302cafe739bc396e5fbafa73fe34f08c..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/pages/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 .homepage import HomePage -from .history import HistoryPage, PdfPage -from .login import LoginPage - -__all__ = ['LoginPage', 'HomePage', 'HistoryPage', 'PdfPage'] diff --git a/modules/leclercmobile/pages/history.py b/modules/leclercmobile/pages/history.py deleted file mode 100644 index c824b77441cbbaafc33fef021ead20a855370fc2..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/pages/history.py +++ /dev/null @@ -1,181 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 re -import os -import subprocess -import tempfile -import shutil - -from datetime import datetime, date, time -from decimal import Decimal - -from weboob.deprecated.browser import Page -from weboob.capabilities.bill import Detail, Bill - - -def _get_date(detail): - return detail.datetime - - -class PdfPage(): - def __init__(self, file): - self.pdf = file - - def _parse_pdf(self): - pdffile = tempfile.NamedTemporaryFile(bufsize=100000, mode='w', suffix='.pdf') - temptxt = pdffile.name.replace('.pdf', '.txt') - cmd = "ebook-convert" - stdout = open("/dev/null", "w") - shutil.copyfileobj(self.pdf, pdffile) - pdffile.flush() - subprocess.call([cmd, pdffile.name, temptxt], stdout=stdout) - pdffile.close() - txtfile = open(temptxt, 'r') - txt = txtfile.read() - txtfile.close() - os.remove(temptxt) - return txt - - def get_details(self): - txt = self._parse_pdf() - page = txt.split('CONSOMMATION')[2].split('ACTIVITE DETAILLEE')[0] - lines = page.split('\n') - lines = [x for x in lines if len(x) > 0] # Remove empty lines - details = [] - detail = None - lines.pop(-1) # Line to describes pictures - twolines = False - for line in lines: - if "Votre consommation" in line: - line = line.split(": ", 1)[1] - if twolines: - twolines = False - detail.infos = unicode(line, encoding='utf-8') - elif re.match('[A-Za-z]', line[0]): - # We have a new element, return the other one - if detail is not None: - details.append(detail) - detail = Detail() - split = re.split("(\d)", line, maxsplit=1) - detail.price = Decimal(0) - if len(split) > 2: - detail.infos = unicode(split[1] + split[2], encoding='utf-8') - else: - twolines = True - if '€' in line: - specialprice = split[1] + split[2] - detail.price = Decimal(specialprice.replace('€', '')) - detail.label = unicode(split[0], encoding='utf-8') - elif '€' in line: - detail.price = Decimal(line.replace('€', '')) - else: - detail.infos = unicode(line, encoding='utf-8') - details.append(detail) - return details - - # Standard pdf text extractor take text line by line - # But the position in the file is not always the "real" position to display... - # It produce some unsorted and unparsable data - # Example of bad software: pdfminer and others python tools - # This is why we have to use "ebook-convert" from calibre software, - # it is the only one to 'reflow" text and give some relevant results - # The bad new is that ebook-convert doesn't support simple use with stdin/stdout - def get_calls(self): - txt = self._parse_pdf() - pages = txt.split("DEBIT") - pages.pop(0) # remove headers - details = [] - for page in pages: - page = page.split('RÉGLO MOBILE')[0].split('N.B. Prévoir')[0] # remove footers - lines = page.split('\n') - lines = [x for x in lines if len(x) > 0] # Remove empty lines - numitems = (len(lines) + 1) / 4 # Each line has five columns - lines.pop(0) # remove the extra € symbol - modif = 0 - i = 0 - while i < numitems: - if modif != 0: - numitems = ((len(lines) + 1 + modif) / 4) - base = i * 4 - modif - dateop = base - corres = base + 1 - duree = base + 2 - price = base + 3 - if "Changement vers le Forfait" in lines[base]: - modif += 1 - i += 1 - continue - # Special case with 5 columns, the operation date is not in the first one - if len(re.split("(\d+\/\d+\/\d+)", lines[dateop])) < 2: - lines[base + 1] = lines[base] + " " + lines[base + 1] - dateop = base + 1 - corres = base + 2 - duree = base + 3 - price = base + 4 - modif -= 1 - detail = Detail() - splits = re.split("(\d+\/\d+\/\d+)", lines[dateop]) - mydate = date(*reversed([int(x) for x in splits[1].split("/")])) - mytime = time(*[int(x) for x in splits[2].split(":")]) - detail.datetime = datetime.combine(mydate, mytime) - if lines[corres] == '-': - lines[corres] = "" - if lines[duree] == '-': - lines[duree] = '' - detail.label = unicode(splits[0], encoding='utf-8', errors='replace') + u" " + lines[corres] + u" " + lines[duree] - # Special case with only 3 columns, we insert a price - if "Activation de votre ligne" in detail.label or u"Résiliation" in detail.label: - lines.insert(price, '0') - try: - detail.price = Decimal(lines[price].replace(',', '.')) - except: - # In some special cases, there are no price column. Try to detect it - if "Inclus" not in lines[price]: - modif += 1 - detail.price = Decimal(0) - - details.append(detail) - i += 1 - return sorted(details, key=_get_date, reverse=True) - - -class HistoryPage(Page): - def on_loaded(self): - pass - - def getmaxid(self): - max = 1 - while len(self.document.xpath('//li[@id="liMois%s"]' % max)) > 0: - max += 1 - return max - 1 - - def date_bills(self, parentid): - max = 1 - while len(self.document.xpath('//li[@id="liMois%s"]' % max)) > 0: - li = self.document.xpath('//li[@id="liMois%s"]' % max)[0] - max += 1 - link = li.xpath('a')[0] - bill = Bill() - bill.url = unicode(link.attrib['href']) - bill.label = unicode(link.text) - bill.format = u"pdf" - bill.type = u"bill" - bill.id = parentid + bill.label.replace(' ', '') - yield bill diff --git a/modules/leclercmobile/pages/homepage.py b/modules/leclercmobile/pages/homepage.py deleted file mode 100644 index c3002a5ac28a10cc9be764e46a0a8a9ed874c579..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/pages/homepage.py +++ /dev/null @@ -1,40 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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.bill import Subscription -from weboob.deprecated.browser import Page - - -class HomePage(Page): - def on_loaded(self): - pass - - def get_list(self): - l = [] - phone = unicode(self.document.xpath('//span[@id="ctl00_ctl00_cMain_cEspCli_lblMsIsdn"]')[0].text.replace(' ', '')) - self.browser.logger.debug('Found ' + phone + ' has phone number') - phoneplan = unicode(self.document.xpath('//span[@id="ctl00_ctl00_cMain_cEspCli_aoaOffreActuelle_aooOffreEtOptions"]/dl/dd/span')[0].text) - self.browser.logger.debug('Found ' + phoneplan + ' has subscription type') - - subscription = Subscription(phone) - subscription.label = phone + ' - ' + phoneplan - - l.append(subscription) - - return l diff --git a/modules/leclercmobile/pages/login.py b/modules/leclercmobile/pages/login.py deleted file mode 100644 index 4f60ba05c579d5dd602a201bd7ab09a5d6ff209b..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/pages/login.py +++ /dev/null @@ -1,71 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 StringIO - -from mechanize import TextControl - -from weboob.deprecated.browser import Page - - -class LoginPage(Page): - def on_loaded(self): - pass - - def login(self, login, password): - form = list(self.browser.forms())[0] - self.browser.select_form("aspnetForm") - self.browser.set_all_readonly(False) - self.browser.controls.append(TextControl('text', '__ASYNCPOST', {'value': "true"})) - self.browser['__EVENTTARGET'] = "ctl00$cMain$lnkValider" - self.browser['ctl00$cMain$ascSaisieMsIsdn$txtMsIsdn'] = login.encode('iso-8859-1') - self.browser['ctl00$cMain$txtMdp'] = password.encode('iso-8859-1') - self.browser.submit(nologin=True) - return form - - def iswait(self): - spanwait = self.document.xpath('//span[@id="ctl00_ascAttente_timerAttente"]') - return len(spanwait) > 0 - - def iserror(self): - error = self.document.xpath('//span[@id="ctl00_cMain_ascLibErreur_lblErreur"]') - return len(error) > 0 - - def getredirect(self): - string = StringIO.StringIO() - self.document.write(string) - try: - redirect = string.getvalue().split('pageRedirect')[1].split('|')[2] - except: - redirect = '' - return redirect - - def next(self, login, form): - self.browser.form = form - string = StringIO.StringIO() - self.document.write(string) - controlvalue = string.getvalue().split('__EVENTVALIDATION')[1].split('|')[1] - state = string.getvalue().split('__VIEWSTATE')[1].split('|')[1] - self.browser.controls.append(TextControl('text', 'ctl00$objScriptManager', {'value': "ctl00$ascAttente$panelAttente|ctl00$ascAttente$timerAttente"})) - self.browser['__VIEWSTATE'] = state - self.browser['__EVENTTARGET'] = "ctl00$ascAttente$timerAttente" - self.browser['__EVENTVALIDATION'] = controlvalue - self.browser['ctl00$cMain$ascSaisieMsIsdn$txtMsIsdn'] = login.encode('iso-8859-1') - self.browser['ctl00$cMain$txtMdp'] = "" - self.browser.submit(nologin=True) diff --git a/modules/leclercmobile/test.py b/modules/leclercmobile/test.py deleted file mode 100644 index c9276354bacad4f0dff4cf892246b9eadab3c649..0000000000000000000000000000000000000000 --- a/modules/leclercmobile/test.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012-2013 Fourcot Florent -# -# 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 - - -class LeclercMobileTest(BackendTest): - MODULE = 'leclercmobile' - - def test_list(self): - """ - Test listing of subscriptions . - No support of multi-account on the website, we could assume to - have only one subscription. - Check the balance if the subscription is ok. - """ - subscriptions = list(self.backend.iter_subscription()) - self.assertTrue(len(subscriptions) == 1, msg="Account listing failed") - self.assertTrue(self.backend.get_balance(subscriptions[0]) > 0, - msg="Get balance failed") - - def test_downloadbills(self): - """ - Iter all bills and try to download it. - """ - for subscription in self.backend.iter_subscription(): - for bill in self.backend.iter_documents(subscription.id): - self.backend.download_document(bill.id) - - def test_history(self): - for subscription in self.backend.iter_subscription(): - self.assertTrue(len(list(self.backend.iter_documents_history(subscription))) > 0) - - def test_details(self): - for subscription in self.backend.iter_subscription(): - details = list(self.backend.get_details(subscription)) - self.assertTrue(len(details) > 5, msg="Not enough details") - total = 0 - for d in details: - total += d.price - self.assertTrue(total > 0, msg="Parsing of price failed") diff --git a/modules/nettokom/__init__.py b/modules/nettokom/__init__.py deleted file mode 100644 index c994d9617b5dd4205e0df3192ea8ec87a0e919e1..0000000000000000000000000000000000000000 --- a/modules/nettokom/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 .module import NettoKomModule - -__all__ = ['NettoKomModule'] diff --git a/modules/nettokom/browser.py b/modules/nettokom/browser.py deleted file mode 100644 index 1eded0f01dd653373971056399618ff3c786ffda..0000000000000000000000000000000000000000 --- a/modules/nettokom/browser.py +++ /dev/null @@ -1,109 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Fourcot Florent -# -# 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.deprecated.browser import Browser, BrowserIncorrectPassword -from .pages import HomePage, LoginPage, HistoryPage, DetailsPage, BillsPage - -__all__ = ['Nettokom'] - - -class Nettokom(Browser): - DOMAIN = 'konto.nettokom.de' - PROTOCOL = 'https' - ENCODING = None # refer to the HTML encoding - PAGES = {'.*login.html.*': LoginPage, - '.*start.html': HomePage, - '.*guthabenverbrauch.html': DetailsPage, - '.*/verbindungsnachweis/.*': HistoryPage, - '.*verbindungsnachweis.html': BillsPage - } - - def __init__(self, *args, **kwargs): - Browser.__init__(self, *args, **kwargs) - - def home(self): - self.location('/start.html') - - def is_logged(self): - return not self.is_on_page(LoginPage) - - def login(self): - assert isinstance(self.username, basestring) - assert isinstance(self.password, basestring) - assert self.username.isdigit() - - if not self.is_on_page(LoginPage): - self.location('/login.html') - - self.page.login(self.username, self.password) - - if self.is_on_page(LoginPage): - raise BrowserIncorrectPassword() - - def get_subscription_list(self): - if not self.is_on_page(HomePage): - self.location('/start.html') - - return self.page.get_list() - - def get_subscription(self, id): - assert isinstance(id, basestring) - - if not self.is_on_page(HomePage): - self.location('/start.html') - - l = self.page.get_list() - for a in l: - if a.id == id: - return a - - return None - - def get_history(self): - if not self.is_on_page(HistoryPage): - self.location('/verbindungsnachweis/alle-verbindungen.html') - return self.page.get_calls() - - def get_details(self): - if not self.is_on_page(DetailsPage): - self.location('/guthabenverbrauch.html') - return self.page.get_details() - - def iter_documents(self, parentid): - if not self.is_on_page(BillsPage): - self.location('/verbindungsnachweis.html') - return self.page.date_bills() - - def get_document(self, id): - assert isinstance(id, basestring) - - if not self.is_on_page(BillsPage): - self.location('/verbindungsnachweis.html') - l = self.page.date_bills() - for a in l: - if a.id == id: - return a - -# Todo : url depends of file format -# def download_document(self, id): -# assert isinstance(id, basestring) -# date = id.split('.')[1] -# -# return self.readurl('/moncompte/ajax.php?page=facture&mode=html&date=' + date) diff --git a/modules/nettokom/favicon.png b/modules/nettokom/favicon.png deleted file mode 100644 index 55bfe52a7f9a341d9809ad520ad207fd683db7c4..0000000000000000000000000000000000000000 Binary files a/modules/nettokom/favicon.png and /dev/null differ diff --git a/modules/nettokom/module.py b/modules/nettokom/module.py deleted file mode 100644 index 38b2bd14e0e741d93889e04f531d7eee94ba5832..0000000000000000000000000000000000000000 --- a/modules/nettokom/module.py +++ /dev/null @@ -1,82 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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.bill import CapDocument, Subscription, SubscriptionNotFound, Detail -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword - -from .browser import Nettokom - - -__all__ = ['NettoKomModule'] - - -class NettoKomModule(Module, CapDocument): - NAME = 'nettokom' - MAINTAINER = u'Florent Fourcot' - EMAIL = 'weboob@flo.fourcot.fr' - VERSION = '1.4' - LICENSE = 'AGPLv3+' - DESCRIPTION = 'Nettokom website' - CONFIG = BackendConfig(ValueBackendPassword('login', - label='Account ID (phone number)', - masked=False, - regexp='^(\d{8,13})$'), - ValueBackendPassword('password', - label='Password') - ) - BROWSER = Nettokom - - def create_default_browser(self): - return self.create_browser(self.config['login'].get(), - self.config['password'].get()) - - def iter_subscription(self): - for subscription in self.browser.get_subscription_list(): - yield subscription - - def get_subscription(self, _id): - with self.browser: - subscription = self.browser.get_subscription(_id) - if subscription: - return subscription - else: - raise SubscriptionNotFound() - - def iter_documents_history(self, subscription): - with self.browser: - for history in self.browser.get_history(): - yield history - - # The subscription is actually useless, but maybe for the futur... - def get_details(self, subscription): - with self.browser: - for detail in self.browser.get_details(): - yield detail - - def get_balance(self, subscription): - if not isinstance(subscription, Subscription): - subscription = self.get_subscription(subscription) - balance = Detail() - balance.id = "%s-balance" % subscription.id - balance.price = subscription._balance - balance.label = u"Balance %s" % subscription.id - balance.currency = u'EUR' - return balance diff --git a/modules/nettokom/pages/__init__.py b/modules/nettokom/pages/__init__.py deleted file mode 100644 index 996912ad066ae617e7c4b2d6b53944a978eae1a1..0000000000000000000000000000000000000000 --- a/modules/nettokom/pages/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 .homepage import HomePage -from .history import HistoryPage, DetailsPage, BillsPage -from .login import LoginPage - -__all__ = ['LoginPage', 'HomePage', 'HistoryPage', 'DetailsPage', 'BillsPage'] diff --git a/modules/nettokom/pages/history.py b/modules/nettokom/pages/history.py deleted file mode 100644 index dc25b9f38680e9f87caced3dbb382613d57b7649..0000000000000000000000000000000000000000 --- a/modules/nettokom/pages/history.py +++ /dev/null @@ -1,89 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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 datetime import datetime, date, time -from decimal import Decimal - -from weboob.deprecated.browser import Page -from weboob.capabilities.bill import Detail - - -class DetailsPage(Page): - - def on_loaded(self): - self.details = [] - table = self.document.xpath('//table[@id="reportTable"]') - - if len(table) > 0: - for tr in table[0].xpath('tbody/tr'): - detail = Detail() - # Skip global category - if tr.find('td/a') is not None: - continue - if tr.attrib["class"] == "totalAmount": - continue - tds = tr.xpath('td') - detail.label = unicode(tds[0].text.strip()) - detail.infos = unicode(tds[1].text.strip()) - detail.price = Decimal(tds[2].text.split(' ')[0].replace(',', '.')) - - self.details.append(detail) - - def get_details(self): - return self.details - - -def _get_date(detail): - return detail.datetime - - -class BillsPage(Page): - def on_loaded(self): - pass - - -class HistoryPage(Page): - - def on_loaded(self): - self.calls = [] - for tr in self.document.xpath('//tr'): - try: - attrib = tr.attrib["class"] - except: - continue - if attrib == "even" or attrib == "odd": - label = u'' - tddate = tr.find('td[@class="middle nowrap"]') - for td in tr.xpath('td[@class="long"]'): - label += unicode(td.text.strip()) + u' ' - tdprice = tr.xpath('td[@class="price"]') - label += u'(' + unicode(tdprice[0].text.strip()) + u')' - price = Decimal(tdprice[1].text.strip().replace(',', '.')) - detail = Detail() - mydate = date(*reversed([int(x) for x in tddate.text.strip().split(' ')[0].split(".")])) - mytime = time(*[int(x) for x in tddate.text.strip().split(' ')[1].split(":")]) - detail.datetime = datetime.combine(mydate, mytime) - detail.label = label - detail.price = price - - self.calls.append(detail) - - def get_calls(self): - return sorted(self.calls, key=_get_date, reverse=True) diff --git a/modules/nettokom/pages/homepage.py b/modules/nettokom/pages/homepage.py deleted file mode 100644 index 0851c73971f36b9416a4f4486deb2d5a624ae1b7..0000000000000000000000000000000000000000 --- a/modules/nettokom/pages/homepage.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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.bill import Subscription -from weboob.tools.capabilities.bank.transactions import FrenchTransaction -from weboob.deprecated.browser import Page -from datetime import date -from decimal import Decimal - - -class HomePage(Page): - def on_loaded(self): - pass - - def get_list(self): - l = [] - divabo = self.document.xpath('//div[@id="accountSummary"]')[0] - owner = divabo.xpath('a/h3')[0].text - phone = divabo.xpath('dl/dd')[0].text - credit = divabo.xpath('dl/dd')[1].text - expiredate = divabo.xpath('dl/dd')[2].text - phoneplan = divabo.xpath('dl/dd')[3].text - self.browser.logger.debug('Found ' + owner + ' as subscriber') - self.browser.logger.debug('Found ' + phone + ' as phone number') - self.browser.logger.debug('Found ' + credit + ' as available credit') - self.browser.logger.debug('Found ' + expiredate + ' as expire date ') - self.browser.logger.debug('Found %s as subscription type', phoneplan) - - subscription = Subscription(phone) - subscription.label = unicode(u'%s - %s - %s - %s' % - (phone, credit, phoneplan, expiredate)) - subscription.subscriber = unicode(owner) - expiredate = date(*reversed([int(x) for x in expiredate.split(".")])) - subscription.validity = expiredate - subscription._balance = Decimal(FrenchTransaction.clean_amount(credit)) - - l.append(subscription) - - return l diff --git a/modules/nettokom/pages/login.py b/modules/nettokom/pages/login.py deleted file mode 100644 index f4a9218c099ec2cf7de536a4b919f7435db70bf5..0000000000000000000000000000000000000000 --- a/modules/nettokom/pages/login.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2012 Florent Fourcot -# -# 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.deprecated.browser import Page - - -class LoginPage(Page): - def on_loaded(self): - pass - - def login(self, login, password): - self.browser.select_form(nr=0) - self.browser.set_all_readonly(False) - self.browser['number'] = login.encode('iso-8859-1') - self.browser['password'] = password.encode('iso-8859-1') - self.browser.submit(nologin=True) diff --git a/modules/nettokom/test.py b/modules/nettokom/test.py deleted file mode 100644 index 8b962c21b819b1d888c48452c4dfdb6ffea96c78..0000000000000000000000000000000000000000 --- a/modules/nettokom/test.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013-2014 Florent Fourcot -# -# 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 - - -class NettokomTest(BackendTest): - MODULE = 'nettokom' - - def test_details(self): - for subscription in self.backend.iter_subscription(): - details = list(self.backend.get_details(subscription)) - self.assertTrue(len(details) > 1, msg="Not enough details") - - def test_history(self): - for subscription in self.backend.iter_subscription(): - self.assertTrue(len(list(self.backend.iter_documents_history(subscription))) > 0) - - def test_list(self): - """ - Test listing of subscriptions. - """ - subscriptions = list(self.backend.iter_subscription()) - self.assertTrue(len(subscriptions) > 0, msg="Account listing failed") diff --git a/modules/nihonnooto/__init__.py b/modules/nihonnooto/__init__.py deleted file mode 100644 index 9da0a9089d3ef442e31145873bbb9bcc24008ec3..0000000000000000000000000000000000000000 --- a/modules/nihonnooto/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import NihonNoOtoModule - -__all__ = ['NihonNoOtoModule'] diff --git a/modules/nihonnooto/browser.py b/modules/nihonnooto/browser.py deleted file mode 100644 index 9baa089aec68a8f9d57a43985616ad3afd0842b2..0000000000000000000000000000000000000000 --- a/modules/nihonnooto/browser.py +++ /dev/null @@ -1,50 +0,0 @@ -# * -*- coding: utf-8 -*- - -# Copyright(C) 2013 Thomas Lecavelier -# -# 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.deprecated.browser import Browser -from .pages import LivePage, ProgramPage - -__all__ = ['NihonNoOtoBrowser'] - - -class NihonNoOtoBrowser(Browser): - DOMAIN = 'www.nihon-no-oto.com' - PROTOCOL = 'http' - ENCODING = 'utf-8' - USER_AGENT = Browser.USER_AGENTS['desktop_firefox'] - PAGES = { - 'http://www\.nihon-no-oto\.com/': LivePage, - 'http://www\.nihon-no-oto\.com/app/playlist.php': ProgramPage, - } - - def home(self): - self.location('/') - - assert self.is_on_page(LivePage) - - def iter_radios_list(self): - self.location('/') - - assert self.is_on_page(LivePage) - return self.page.iter_radios_list() - - def get_current_emission(self): - self.location('/app/playlist.php') - assert self.is_on_page(ProgramPage) - return self.page.get_current_emission() diff --git a/modules/nihonnooto/favicon.png b/modules/nihonnooto/favicon.png deleted file mode 100644 index 312fff79f60601900d2f0ba6d34ab06d6c7b26de..0000000000000000000000000000000000000000 Binary files a/modules/nihonnooto/favicon.png and /dev/null differ diff --git a/modules/nihonnooto/module.py b/modules/nihonnooto/module.py deleted file mode 100644 index 81223e2d2fdb06375bb07c0602df8888bfcc7c4b..0000000000000000000000000000000000000000 --- a/modules/nihonnooto/module.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- -# Copyright(C) 2013 Thomas Lecavelier -# -# 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.radio import CapRadio, Radio -from weboob.capabilities.collection import CapCollection -from weboob.tools.backend import Module -from .browser import NihonNoOtoBrowser - -__all__ = ['NihonNoOtoModule'] - - -class NihonNoOtoModule(Module, CapRadio, CapCollection): - NAME = 'nihonnooto' - MAINTAINER = u'Thomas Lecavelier' - EMAIL = 'thomas-weboob@lecavelier.name' - VERSION = '1.4' - DESCRIPTION = u'« Le son du Japon » french operated web radio, diffusing japanese music' - # License of your module - LICENSE = 'AGPLv3+' - - BROWSER = NihonNoOtoBrowser - _RADIOS = {'nihonnooto': (u'Nihon no OTO', True) } - - def iter_resources(self, objs, split_path): - if Radio in objs: - self._restrict_level(split_path) - for radio in self.browser.iter_radios_list(): - self.browser.get_current_emission() - radio.current = self.browser.get_current_emission() - yield radio - - def iter_radios_search(self, pattern): - for radio in self.browser.iter_radios_list(): - if pattern.lower() in radio.title.lower() or pattern.lower() in radio.description.lower(): - self.browser.get_current_emission() - radio.current = self.browser.get_current_emission() - - yield radio - - def get_radio(self, radio): - if not isinstance(radio, Radio): - for rad in self.browser.iter_radios_list(): - if rad.id == radio: - return rad - return None - - def fill_radio(self, radio, fields): - if 'current' in fields: - return self.get_radio(radio.id) - return radio - - OBJECTS = {Radio: fill_radio} diff --git a/modules/nihonnooto/pages.py b/modules/nihonnooto/pages.py deleted file mode 100644 index 06b6e58c8c795e3579121501263e3cdc2f0d03cd..0000000000000000000000000000000000000000 --- a/modules/nihonnooto/pages.py +++ /dev/null @@ -1,62 +0,0 @@ -# * -*- coding: utf-8 -*- - -# Copyright(C) 2013 Thomas Lecavelier -# -# 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.deprecated.browser import Page -from weboob.capabilities.radio import Radio -from weboob.capabilities.audiostream import BaseAudioStream -from weboob.tools.capabilities.streaminfo import StreamInfo - - -class LivePage(Page): - def iter_radios_list(self): - radio = Radio('nihon') - radio.title = u'Nihon no Oto' - radio.description = u'Nihon no Oto: le son du Japon' - radio.streams = [] - - index = -1 - - for el in self.document.xpath('//source'): - index += 1 - mime_type = unicode(el.attrib['type']) - stream_url = unicode(el.attrib['src']) - stream = BaseAudioStream(index) - stream.bitrate = 128 - if (mime_type == u'audio/mpeg'): - stream.format = u'mp3' - elif (mime_type == u'audio/ogg'): - stream.format = u'vorbis' - stream.title = radio.title + ' ' + mime_type - stream.url = stream_url - radio.streams.append(stream) - - yield radio - - -class ProgramPage(Page): - def get_current_emission(self): - current = StreamInfo(0) - two_or_more = unicode(self.document.xpath('//p')[0].text).split('/////')[0].split(' - ') - # Consider that if String(' - ') appears it'll be in title rather in the artist name - if len(two_or_more) > 2: - current.who = two_or_more.pop(0) - current.what = ' - '.join(two_or_more) - else: - current.who, current.what = two_or_more - return current diff --git a/modules/nihonnooto/test.py b/modules/nihonnooto/test.py deleted file mode 100644 index 93d3e6b5246facba5ea0aca80603a6cad520c713..0000000000000000000000000000000000000000 --- a/modules/nihonnooto/test.py +++ /dev/null @@ -1,29 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2013 Thomas Lecavelier -# -# 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 - - -class NihonNoOtoTest(BackendTest): - MODULE = 'nihonnooto' - - def test_nihonnooto(self): - l = list(self.backend.iter_radios_search('')) - self.assertTrue(len(l) > 0) diff --git a/modules/opacwebaloes/__init__.py b/modules/opacwebaloes/__init__.py deleted file mode 100644 index 4994110be06a12164757b55ba0bbfb88dbe1fbfb..0000000000000000000000000000000000000000 --- a/modules/opacwebaloes/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Jeremy Monnet -# -# 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 .module import AloesModule - -__all__ = ['AloesModule'] diff --git a/modules/opacwebaloes/browser.py b/modules/opacwebaloes/browser.py deleted file mode 100644 index fc2ed81c6c5e78fbcf3f2bfdc6dd7766a81011f2..0000000000000000000000000000000000000000 --- a/modules/opacwebaloes/browser.py +++ /dev/null @@ -1,77 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2012 Jeremy Monnet -# -# 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.deprecated.browser import Browser, BrowserIncorrectPassword - -from .pages import LoginPage, HomePage, RentedPage, HistoryPage, BookedPage - - -__all__ = ['AloesBrowser'] - - -# Browser -class AloesBrowser(Browser): - PROTOCOL = 'http' - ENCODING = 'utf-8' - USER_AGENT = Browser.USER_AGENTS['desktop_firefox'] - #DEBUG_HTTP = True - DEBUG_HTTP = False - PAGES = { - 'http://.*/index.aspx': LoginPage, - 'http://.*/index.aspx\?IdPage=1': HomePage, - 'http://.*/index.aspx\?IdPage=45': RentedPage, - 'http://.*/index.aspx\?IdPage=429': HistoryPage, - 'http://.*/index.aspx\?IdPage=44': BookedPage - } - - def __init__(self, baseurl, *args, **kwargs): - self.BASEURL = baseurl - Browser.__init__(self, *args, **kwargs) - - def is_logged(self): - - return self.page \ - and not self.page.document.getroot().xpath('//input[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_ctl00_TextSaisie")]') - #return True - - def login(self): - assert isinstance(self.username, basestring) - assert isinstance(self.password, basestring) - if not self.is_on_page(HomePage): - self.location('%s://%s/index.aspx' - % (self.PROTOCOL, self.BASEURL), - no_login=True) - if not self.page.login(self.username, self.password) or \ - not self.is_logged() or \ - (self.is_on_page(LoginPage) and self.page.is_error()): - raise BrowserIncorrectPassword() - - def get_rented_books_list(self): - if not self.is_on_page(RentedPage): - self.location('%s://%s/index.aspx?IdPage=45' - % (self.PROTOCOL, self.BASEURL) - ) - return self.page.get_list() - - def get_booked_books_list(self): - if not self.is_on_page(BookedPage): - self.location('%s://%s/index.aspx?IdPage=44' - % (self.PROTOCOL, self.BASEURL)) - return self.page.get_list() diff --git a/modules/opacwebaloes/favicon.png b/modules/opacwebaloes/favicon.png deleted file mode 100644 index beb49765fedb9f26637f9ee95ec30d7b77b1fdc5..0000000000000000000000000000000000000000 Binary files a/modules/opacwebaloes/favicon.png and /dev/null differ diff --git a/modules/opacwebaloes/module.py b/modules/opacwebaloes/module.py deleted file mode 100644 index 5f1571e937e6ad333a66d4431d3267a71aecf711..0000000000000000000000000000000000000000 --- a/modules/opacwebaloes/module.py +++ /dev/null @@ -1,67 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2012 Jeremy Monnet -# -# 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.library import CapBook -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import ValueBackendPassword, Value - -from .browser import AloesBrowser - - -__all__ = ['AloesModule'] - - -class AloesModule(Module, CapBook): - NAME = 'opacwebaloes' - MAINTAINER = u'Jeremy Monnet' - EMAIL = 'jmonnet@gmail.com' - VERSION = '1.4' - DESCRIPTION = 'Aloes Library software' - LICENSE = 'AGPLv3+' - CONFIG = BackendConfig(Value('login', label='Account ID', regexp='^\d{1,8}\w$'), - ValueBackendPassword('password', label='Password of account'), - Value('baseurl', label='Base URL') - ) - BROWSER = AloesBrowser - - def create_default_browser(self): - return self.create_browser(self.config['baseurl'].get(), - self.config['login'].get(), - self.config['password'].get()) - - def iter_rented(self): - for book in self.browser.get_rented_books_list(): - yield book - - def iter_booked(self): - for book in self.browser.get_booked_books_list(): - yield book - - def iter_books(self): - for book in self.iter_booked(): - yield book - for book in self.iter_rented(): - yield book - - def get_book(self, _id): - raise NotImplementedError() - - def search_books(self, _string): - raise NotImplementedError() diff --git a/modules/opacwebaloes/pages.py b/modules/opacwebaloes/pages.py deleted file mode 100644 index f05b6226dce4a1eec8ddb47bf74f9ee971766166..0000000000000000000000000000000000000000 --- a/modules/opacwebaloes/pages.py +++ /dev/null @@ -1,117 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2012 Jeremy Monnet -# -# 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 datetime import date - -from mechanize import TextControl - -from weboob.capabilities.library import Book -from weboob.deprecated.browser import BrowserUnavailable, Page - - -class SkipPage(Page): - pass - - -class HomePage(Page): - pass - - -def txt2date(s): - return date(*reversed([int(x) for x in s.split(' ')[-1].split('/')])) - - -class RentedPage(Page): - # TODO, table limited to 20 items, need to use pagination - def get_list(self): - for book in self.iter_books('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl07_COMPTE_PRET_1_1_GrillePrets_ctl00__")]', 1): - book.late = False - yield book - - for book in self.iter_books('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl08_COMPTE_RETARD_0_1_GrilleRetards_ctl00__")]', 0): - book.late = True - yield book - - def iter_books(self, el, start): - for tr in self.document.getroot().xpath(el): - book = Book(tr[start].text) - book.name = tr[start+3].text - book.author = tr[start+4].text - book.date = txt2date(tr[start+5].text) - yield book - - -class HistoryPage(Page): - pass - - -class BookedPage(Page): - # TODO, table limited to 20 items, need to use pagination - def get_list(self): - for tr in self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl09_COMPTE_INFOS_0_GrilleInfos_ctl00__0")]'): - username=tr[1].text+"_"+tr[0].text - - for i, tr in enumerate(self.document.getroot().xpath('//tr[contains(@id, "ctl00_ContentPlaceHolder1_ctl00_ctl10_COMPTE_RESA_1_1_GrilleResas_ctl00__")]')): - book = Book('%s%d' % (username, i)) - # if all the books booked are available, there are only 7 columns. - # if (at least ?) one book is still not available, yous can cancel, and the first column does contain the checkbox. So 8 columns. - if (len(tr) == 7): - start = 2 - if (len(tr) == 8): - start = 3 - book.name = tr[start].text - book.author = tr[start+1].text - book.date = txt2date(tr[start+3].text) - book.late = False - yield book - - -class LoginPage(Page): - def login(self, login, passwd): - self.browser.select_form(predicate=lambda x: x.attrs.get('id','')=='aspnetForm') - self.browser.form.set_all_readonly(False) - self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextSaisie'] = login - self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$TextPass'] = passwd - self.browser['ctl00_ScriptManager1_TSM']="%3B%3BSystem.Web.Extensions%2C%20Version%3D1.0.61025.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D31bf3856ad364e35%3Afr-FR%3A1f0f78f9-0731-4ae9-b308-56936732ccb8%3Aea597d4b%3Ab25378d2%3BTelerik.Web.UI%2C%20Version%3D2009.3.1314.20%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3D121fae78165ba3d4%3Afr-FR%3Aec1048f9-7413-49ac-913a-b3b534cde186%3A16e4e7cd%3Aed16cbdc%3Af7645509%3A24ee1bba%3A19620875%3A874f8ea2%3A33108d14%3Abd8f85e4" - self.browser.controls.append(TextControl('text', 'RadAJAXControlID', {'value': ''})) - self.browser['RadAJAXControlID']="ctl00_ContentPlaceHolder1_ctl00_ctl04_ctl00_RadAjaxPanelConnexion" - self.browser.controls.append(TextControl('text', 'ctl00$ScriptManager1', {'value': ''})) - self.browser['ctl00$ScriptManager1']="ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$RadAjaxPanelConnexionPanel|" - self.browser.controls.append(TextControl('text', '__EVENTTARGET', {'value': ''})) - self.browser.controls.append(TextControl('text', '__EVENTARGUMENT', {'value': ''})) - self.browser.controls.append(TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x', {'value': ''})) - self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.x']="76" - self.browser.controls.append(TextControl('text', 'ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y', {'value': ''})) - self.browser['ctl00$ContentPlaceHolder1$ctl00$ctl04$ctl00$btnImgConnexion.y']="10" - - try: - self.browser.submit() - except BrowserUnavailable: - # Login is not valid - return False - return True - - def is_error(self): - for text in self.document.find('body').itertext(): - text=text.strip() - # Login seems valid, but password does not - needle='Echec lors de l\'authentification' - if text.startswith(needle.decode('utf-8')): - return True - return False diff --git a/modules/sfr/__init__.py b/modules/sfr/__init__.py deleted file mode 100644 index 1b5ffb1af9bfbbf37e7ee7e3b5b6ad5b486d8e09..0000000000000000000000000000000000000000 --- a/modules/sfr/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import SfrModule - -__all__ = ['SfrModule'] diff --git a/modules/sfr/browser.py b/modules/sfr/browser.py deleted file mode 100644 index bfc21ffd25fabc56cf2f1d8c306225a82e37d880..0000000000000000000000000000000000000000 --- a/modules/sfr/browser.py +++ /dev/null @@ -1,66 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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.compat import quote_plus - -from .pages.compose import ClosePage, ComposePage, ConfirmPage, SentPage -from .pages.login import LoginPage - -from weboob.deprecated.browser import Browser, BrowserIncorrectPassword - - -__all__ = ['SfrBrowser'] - - -class SfrBrowser(Browser): - DOMAIN = 'www.sfr.fr' - PAGES = { - 'http://messagerie-.+.sfr.fr/webmail/close_xms_tab.html': ClosePage, - 'http://www.sfr.fr/xmscomposer/index.html\?todo=compose': ComposePage, - 'http://www.sfr.fr/xmscomposer/mc/envoyer-texto-mms/confirm.html': ConfirmPage, - 'https://www.sfr.fr/cas/login\?service=.*': LoginPage, - 'http://www.sfr.fr/xmscomposer/mc/envoyer-texto-mms/send.html': SentPage, - } - - def get_nb_remaining_free_sms(self): - if not self.is_on_page(ComposePage): - self.home() - return self.page.get_nb_remaining_free_sms() - - def home(self): - self.location('http://www.sfr.fr/xmscomposer/index.html?todo=compose') - - def is_logged(self): - return 'loginForm' not in [form.name for form in self.forms()] - - def login(self): - service_url = 'http://www.sfr.fr/xmscomposer/j_spring_cas_security_check' - self.location('https://www.sfr.fr/cas/login?service=%s' % quote_plus(service_url), no_login=True) - self.page.login(self.username, self.password) - if not self.is_logged(): - raise BrowserIncorrectPassword() - - def post_message(self, message): - if not self.is_on_page(ComposePage): - self.home() - self.page.post_message(message) - if self.is_on_page(ConfirmPage): - self.page.confirm() - assert self.is_on_page(ClosePage) or self.is_on_page(SentPage) diff --git a/modules/sfr/favicon.png b/modules/sfr/favicon.png deleted file mode 100644 index a1ef62f8b3078a07b3f13a780be1f94f6ad0d2a3..0000000000000000000000000000000000000000 Binary files a/modules/sfr/favicon.png and /dev/null differ diff --git a/modules/sfr/module.py b/modules/sfr/module.py deleted file mode 100644 index c85af633d092efc9876e12924d2fbbaa70321649..0000000000000000000000000000000000000000 --- a/modules/sfr/module.py +++ /dev/null @@ -1,58 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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.messages import CantSendMessage, CapMessages, CapMessagesPost -from weboob.capabilities.account import CapAccount, StatusField -from weboob.tools.backend import Module, BackendConfig -from weboob.tools.value import Value, ValueBackendPassword - -from .browser import SfrBrowser - - -__all__ = ['SfrModule'] - - -class SfrModule(Module, CapAccount, CapMessages, CapMessagesPost): - NAME = 'sfr' - MAINTAINER = u'Christophe Benz' - EMAIL = 'christophe.benz@gmail.com' - VERSION = '1.4' - DESCRIPTION = 'SFR French mobile phone provider' - LICENSE = 'AGPLv3+' - CONFIG = BackendConfig(Value('login', label='Login'), - ValueBackendPassword('password', label='Password')) - BROWSER = SfrBrowser - ACCOUNT_REGISTER_PROPERTIES = None - - def create_default_browser(self): - return self.create_browser(self.config['login'].get(), self.config['password'].get()) - - # CapMessagesPost methods - - def get_account_status(self): - with self.browser: - return (StatusField('nb_remaining_free_sms', 'Number of remaining free SMS', - self.browser.get_nb_remaining_free_sms()),) - - def post_message(self, message): - if not message.content.strip(): - raise CantSendMessage(u'Message content is empty.') - with self.browser: - self.browser.post_message(message) diff --git a/modules/sfr/pages/__init__.py b/modules/sfr/pages/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/modules/sfr/pages/compose.py b/modules/sfr/pages/compose.py deleted file mode 100644 index 6e089111591f74fc019d97d9684995cda44112d2..0000000000000000000000000000000000000000 --- a/modules/sfr/pages/compose.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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 re - -from weboob.capabilities.messages import CantSendMessage -from weboob.deprecated.browser import Page - - -class ClosePage(Page): - pass - - -class ComposePage(Page): - phone_regex = re.compile('^(\+33|0033|0)(6|7)(\d{8})$') - - def get_nb_remaining_free_sms(self): - nbSms = self.parser.select(self.document.getroot(), '#freeSms',1).text.strip() - return nbSms - - def post_message(self, message): - receiver = message.thread.id - if self.phone_regex.match(receiver) is None: - raise CantSendMessage(u'Invalid receiver: %s' % receiver) - self.browser.select_form(nr=0) - self.browser['msisdns'] = receiver - self.browser['textMessage'] = message.content.encode('utf-8') - self.browser.submit() - - -class ConfirmPage(Page): - def confirm(self): - self.browser.select_form(nr=0) - self.browser.submit() - - -class SentPage(Page): - pass diff --git a/modules/sfr/pages/login.py b/modules/sfr/pages/login.py deleted file mode 100644 index dd868562dea98114abc51559240de10fb9dd1f76..0000000000000000000000000000000000000000 --- a/modules/sfr/pages/login.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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.deprecated.browser import Page - - -class LoginPage(Page): - def login(self, login, password): - self.browser.select_form(nr=0) - self.browser['username'] = login - self.browser['password'] = password - self.browser['remember-me'] = ['on'] - self.browser.submit() diff --git a/modules/sfr/test.py b/modules/sfr/test.py deleted file mode 100644 index 39685024ee6bead21360db98c77700cc7d628317..0000000000000000000000000000000000000000 --- a/modules/sfr/test.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2010-2011 Christophe Benz -# -# 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 - - -class SFRTest(BackendTest): - MODULE = 'sfr' - - def test_sfr(self): - pass - - def test_create_default_browser(self): - connect = self.backend.create_default_browser() - assert connect - - def test_get_account_status(self): - nbSms = self.backend.get_account_status() - assert nbSms - assert isinstance(nbSms[0].value, str) diff --git a/modules/trictractv/__init__.py b/modules/trictractv/__init__.py deleted file mode 100644 index 35008fa3a8d6ecf068a63858715afb81befd37ee..0000000000000000000000000000000000000000 --- a/modules/trictractv/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .module import TricTracTVModule - -__all__ = ['TricTracTVModule'] diff --git a/modules/trictractv/browser.py b/modules/trictractv/browser.py deleted file mode 100644 index 900b4641bbb9bac65c5777633fd8f4ff24073bf7..0000000000000000000000000000000000000000 --- a/modules/trictractv/browser.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2011-2012 Romain Bignon, Laurent Bachelier, Benjamin Drieu -# -# 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 re - -from weboob.deprecated.browser import Browser -from weboob.deprecated.browser.decorators import id2url - -from .pages import IndexPage, VideoPage -from .video import TricTracTVVideo - - -__all__ = ['TricTracTVBrowser'] - - -class TricTracTVBrowser(Browser): - DOMAIN = 'trictrac.tv' - ENCODING = 'ISO-8859-1' - PAGES = {r'http://[w\.]*trictrac.tv/': IndexPage, - r'http://[w\.]*trictrac.tv/home/listing.php.*': IndexPage, - r'http://[w\.]*trictrac.tv/video-(.+)': VideoPage, - } - - @id2url(TricTracTVVideo.id2url) - def get_video(self, url, video=None): - self.location(url) - assert self.is_on_page(VideoPage) - - _id = self.page.get_id() - if video is None: - video = TricTracTVVideo(_id) - - infourl = self.page.get_info_url() - if infourl is not None: - self.parse_info(self.openurl(infourl).read(), video) - - return video - - def home(self): - self.location(self.buildurl('http://www.trictrac.tv/home/listing.php', mot='%')) - - def search_videos(self, pattern): - if not pattern: - self.home() - else: - self.location(self.buildurl('http://www.trictrac.tv/home/listing.php', mot=pattern.encode('utf-8'))) - - assert self.is_on_page(IndexPage) - return self.page.iter_videos() - - def parse_info(self, data, video): - m = re.match ( '.*fichier=(.*?)&', data ) - video.url = unicode ( r'http://src.povcon.net/videos/%s' % m.group ( 1 ) ) - - video.description = self.page.get_descriptif() - video.duration = self.page.get_duration() - video.title = self.page.get_title() - video.date = self.page.get_date() - video.rating = self.page.get_rating() - video.rating_max = 5 - - return video diff --git a/modules/trictractv/favicon.png b/modules/trictractv/favicon.png deleted file mode 100644 index c7cae5f497436f242b9413efae9f2d2c43886687..0000000000000000000000000000000000000000 Binary files a/modules/trictractv/favicon.png and /dev/null differ diff --git a/modules/trictractv/module.py b/modules/trictractv/module.py deleted file mode 100644 index 611abc384843a3dcb43133fa0365a525d70004d7..0000000000000000000000000000000000000000 --- a/modules/trictractv/module.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2011 Romain Bignon -# Copyright(C) 2012 Benjamin Drieu -# -# This file is *not yet* 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 CapVideo -from weboob.tools.backend import Module - -from .browser import TricTracTVBrowser -from .video import TricTracTVVideo - - -__all__ = ['TricTracTVModule'] - - -class TricTracTVModule(Module, CapVideo): - NAME = 'trictractv' - MAINTAINER = u'Benjamin Drieu' - EMAIL = 'benjamin@drieu.org' - VERSION = '1.4' - DESCRIPTION = u'TricTrac.tv video website' - LICENSE = 'AGPLv3+' - BROWSER = TricTracTVBrowser - - def get_video(self, _id): - with self.browser: - return self.browser.get_video(_id) - - def search_videos(self, pattern=None, sortby=CapVideo.SEARCH_RELEVANCE, nsfw=False): - 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(TricTracTVVideo.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 = {TricTracTVVideo: fill_video} diff --git a/modules/trictractv/pages.py b/modules/trictractv/pages.py deleted file mode 100644 index c5f4db6108ea648d6946f24d6f76e0b636579e89..0000000000000000000000000000000000000000 --- a/modules/trictractv/pages.py +++ /dev/null @@ -1,128 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2011-2012 Romain Bignon, Laurent Bachelier -# -# 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 datetime -import re - -from weboob.capabilities.image import Thumbnail -from weboob.deprecated.browser import Page, BrokenPageError - - -from .video import TricTracTVVideo - - -class IndexPage(Page): - def iter_videos(self): - for div in self.parser.select(self.document.getroot(), 'li#contentsearch'): - title = self.parser.select(div, '#titlesearch span', 1) - - a = self.parser.select(div, 'a', 1) - url = a.attrib['href'] - m = re.match('/video-(.*)', url) - if not m: - self.logger.debug('url %s does not match' % url) - continue - _id = m.group(1) - video = TricTracTVVideo(_id) - video.title = unicode(title.text) - - url = self.parser.select(div, 'img', 1).attrib['src'] - stars = self.parser.select(div, '.etoile_on') - video.rating = len(stars) - video.rating_max = 5 - - video.thumbnail = Thumbnail('http://www.trictrac.tv/%s' % url) - video.thumbnail.url = video.thumbnail.id - - yield video - - -class VideoPage(Page): - def on_loaded(self): - p = self.parser.select(self.document.getroot(), 'p.alert') - if len(p) > 0: - raise Exception(p[0].text) - - def get_info_url(self): - try: - div = self.parser.select(self.document.getroot(), '#Content_Video object', 1) - except BrokenPageError: - return None - else: - for param in self.parser.select(div, 'param', None): - if param.get('name') == 'flashvars': - m = re.match('varplaymedia=([0-9]*)', param.attrib['value']) - if m: - return r'http://www.trictrac.tv/swf/listelement.php?idfile=%s' % m.group(1) - - def get_title(self): - try: - title = self.parser.select(self.document.getroot(), 'title', 1) - except BrokenPageError: - return None - else: - return title.text - - def get_descriptif(self): - try: - descriptif = self.parser.select(self.document.getroot(), '.video_descriptif p', 1) - except BrokenPageError: - return None - else: - return descriptif.text - - def get_duration(self): - try: - details = self.parser.select(self.document.getroot(), 'div#video_detail div') - except BrokenPageError: - return None - else: - duration = details[2] - duration_string = duration.text [ duration.text.rfind ( ' ' ) + 1 : ] - tokens = duration_string.split(':') - if len(tokens) > 2: - return datetime.timedelta(hours=int(tokens[0]), minutes=int(tokens[1]), seconds=int(tokens[2])) - else: - return datetime.timedelta(minutes=int(tokens[0]), seconds=int(tokens[1])) - - def get_date(self): - try: - date = self.parser.select(self.document.getroot(), 'div#video_detail div.date', 1) - except BrokenPageError: - return None - else: - string = date.text - string = string [ string.rfind('le ') + 3 : ] - months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ] - words = string.split ( ' ' ) - month_no = months.index ( words [ 1 ] ) + 1 - return datetime.datetime.strptime ( ( '%s %s %s %s' % - ( words [ 0 ], month_no, words [ 2 ], words [ 3 ] ) ), - '%d %m %Y, %H:%M:%S') - - def get_rating(self): - try: - stars = self.parser.select(self.document.getroot(), '#video_info .etoile_on') - except BrokenPageError: - return None - else: - return len(stars) - - def get_id(self): - return self.groups[0] diff --git a/modules/trictractv/test.py b/modules/trictractv/test.py deleted file mode 100644 index cda4bae2c788df882c875707d29f8e2eb573eaed..0000000000000000000000000000000000000000 --- a/modules/trictractv/test.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2011-2012 Romain Bignon, Laurent Bachelier -# -# 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 - - -class TricTracTVTest(BackendTest): - MODULE = 'trictractv' - - def test_trictractv(self): - l = list(self.backend.search_videos('TricTrac')) - 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/trictractv/video.py b/modules/trictractv/video.py deleted file mode 100644 index 1a38c257b19d5cfbf0330dc0e1272e08c032bb75..0000000000000000000000000000000000000000 --- a/modules/trictractv/video.py +++ /dev/null @@ -1,31 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 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 . - - -from weboob.capabilities.video import BaseVideo - - -class TricTracTVVideo(BaseVideo): - def __init__(self, *args, **kwargs): - BaseVideo.__init__(self, *args, **kwargs) - self.ext = u'flv' - - @classmethod - def id2url(cls, _id): - return 'http://www.trictrac.tv/video-%s' % _id diff --git a/modules/unsee/__init__.py b/modules/unsee/__init__.py deleted file mode 100644 index d3aa6c4f2c63ca175d22da1bf22084a7514d1782..0000000000000000000000000000000000000000 --- a/modules/unsee/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2014 Vincent A -# -# This file is part of weboob. -# -# weboob is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# weboob is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with weboob. If not, see . - - -from .module import UnseeModule - - -__all__ = ['UnseeModule'] diff --git a/modules/unsee/browser.py b/modules/unsee/browser.py deleted file mode 100644 index a3c265361a8fef2833f30033cb4b42e37eab6682..0000000000000000000000000000000000000000 --- a/modules/unsee/browser.py +++ /dev/null @@ -1,94 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2014 Vincent A -# -# This file is part of weboob. -# -# weboob is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# weboob is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with weboob. If not, see . - - -from weboob.deprecated.browser import Browser -import os -from uuid import uuid4 -from urllib2 import Request -from weboob.tools.compat import urljoin -from weboob.tools.json import json -from weboob.deprecated.browser.parsers.lxmlparser import LxmlHtmlParser - - -__all__ = ['UnseeBrowser'] - - -def to_bytes(s): - if isinstance(s, unicode): - return s.encode('utf-8') - else: - return s - - -class FileField(object): - def __init__(self, filename, contents=None, headers=None): - self.filename = to_bytes(os.path.basename(filename)) - self.headers = headers or {} - if contents is not None: - self.contents = contents - else: - self.contents = open(filename).read() - - -class UnseeBrowser(Browser): - PROTOCOL = 'https' - DOMAIN = 'unsee.cc' - ENCODING = 'utf-8' - - def _make_boundary(self): - return '==%s==' % uuid4() - - def _make_multipart(self, pairs, boundary): - s = [] - for k, v in pairs: - s.append('--%s' % boundary) - if isinstance(v, FileField): - s.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (k, v.filename)) - for hk, hv in v.headers.items(): - s.append('%s: %s' % (hk, hv)) - v = v.contents - else: - s.append('Content-Disposition: form-data; name="%s"' % k) - s.append('') - s.append(to_bytes(v)) - s.append('--%s--' % boundary) - s.append('') - return '\r\n'.join(s) - - def _multipart(self, url, fields): - b = self._make_boundary() - data = self._make_multipart(fields, b) - headers = {'Content-type': 'multipart/form-data; boundary=%s' % b, 'Content-length': len(data)} - return Request(url, data=self._make_multipart(fields, b), headers=headers) - - def post_image(self, name, contents, time): - # time='first' for one-shot view - - params = [('time', time), ('image[]', FileField(name or '-', contents))] - request = self._multipart('https://unsee.cc/upload/', params) - - d = json.loads(self.readurl(request)) - return {'id': d['hash']} - - def get_image(self, id): - doc = self.get_document(self.openurl('https://unsee.cc/%s/' % id)) - images = LxmlHtmlParser.select(doc, '//img/@src[starts-with(., "/image/")]', method='xpath') - url = urljoin('https://unsee.cc', images[0]) - return self.readurl(url) diff --git a/modules/unsee/favicon.png b/modules/unsee/favicon.png deleted file mode 100644 index 454f0b014a3fcd49fa40f6a64d0b12e85072e3dc..0000000000000000000000000000000000000000 Binary files a/modules/unsee/favicon.png and /dev/null differ diff --git a/modules/unsee/module.py b/modules/unsee/module.py deleted file mode 100644 index 5ca71add5d60af6a0123400735eb2fd41ed56638..0000000000000000000000000000000000000000 --- a/modules/unsee/module.py +++ /dev/null @@ -1,78 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2014 Vincent A -# -# This file is part of weboob. -# -# weboob is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# weboob is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with weboob. If not, see . - - -from weboob.tools.backend import Module -from weboob.capabilities.paste import BasePaste -from weboob.tools.capabilities.paste import BasePasteModule -from weboob.tools.capabilities.paste import image_mime -from weboob.deprecated.browser.decorators import check_url -import re - -from .browser import UnseeBrowser - - -__all__ = ['UnseeModule'] - - -class UnPaste(BasePaste): - @classmethod - def id2url(cls, id): - return 'https://unsee.cc/%s' % id - - -class UnseeModule(Module, BasePasteModule): - NAME = 'unsee' - DESCRIPTION = u'unsee.cc expiring image hosting' - MAINTAINER = u'Vincent A' - EMAIL = 'dev@indigo.re' - LICENSE = 'AGPLv3+' - VERSION = '1.4' - - BROWSER = UnseeBrowser - - EXPIRATIONS = {3600: 'hour', 86400: 'day', 86400 * 7: 'week'} - - def can_post(self, contents, title=None, public=None, max_age=None): - if re.search(r'[^a-zA-Z0-9=+/\s]', contents): - return 0 - elif max_age is not None and not self.get_closest_expiration(max_age): - return 0 - else: - mime = image_mime(contents, ('gif', 'jpeg', 'png')) - return 20 * int(mime is not None) - - @check_url('https?://unsee.cc/.+') - def get_paste(self, id): - paste = UnPaste(id) - paste.contents = self.browser.get_image(id).encode('base64') - return paste - - def new_paste(self, *a, **kw): - return UnPaste(*a, **kw) - - def post_paste(self, paste, max_age=None): - if max_age is None: - max_code = 'week' - else: - max_code = self.EXPIRATIONS[self.get_closest_expiration(max_age)] - - d = self.browser.post_image(paste.title, paste.contents.decode('base64'), max_code) - paste.id = d['id'] - return paste diff --git a/modules/unsee/test.py b/modules/unsee/test.py deleted file mode 100644 index 08a44ae420f967ad64880d5aba0eadb35efef1de..0000000000000000000000000000000000000000 --- a/modules/unsee/test.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright(C) 2014 Vincent A -# -# This file is part of weboob. -# -# weboob is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# weboob is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with weboob. If not, see . - - -from weboob.tools.test import BackendTest - - -class UnseeTest(BackendTest): - MODULE = 'unsee' - - # small gif file - DATA = 'R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==\n' - - def test_unsee(self): - assert self.backend.can_post(self.DATA, max_age=3600) - - post = self.backend.new_paste(None) - post.contents = self.DATA - post = self.backend.post_paste(post, max_age=3600) - assert post.id - - got = self.backend.get_paste(post.id) - assert got - assert got.contents.decode('base64').startswith('GIF89a') - # we can't check the exact data, unsee.cc modifies the images... diff --git a/modules/ups/__init__.py b/modules/ups/__init__.py deleted file mode 100644 index aac6131314c120e93aeadac907defedc6176db20..0000000000000000000000000000000000000000 --- a/modules/ups/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- 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 .module import UpsModule - - -__all__ = ['UpsModule'] diff --git a/modules/ups/browser.py b/modules/ups/browser.py deleted file mode 100644 index be6f533180064cc8efc41392b169936da5275296..0000000000000000000000000000000000000000 --- a/modules/ups/browser.py +++ /dev/null @@ -1,48 +0,0 @@ -# -*- 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 weboob.deprecated.browser import Browser -from weboob.tools.compat import urlencode - -from .pages import TrackPage - - -__all__ = ['UpsBrowser'] - - -class UpsBrowser(Browser): - PROTOCOL = 'https' - DOMAIN = 'wwwapps.ups.com' - ENCODING = None - - PAGES = { - 'https://wwwapps.ups.com/WebTracking/track': TrackPage, - } - - def get_tracking_info(self, _id): - data = {'HTMLVersion': '5.0', - 'USER_HISTORY_LIST': '', - 'loc': 'en_US', - 'track.x': 'Track', - 'trackNums': _id.encode('utf-8'), - } - self.location('https://wwwapps.ups.com/WebTracking/track', urlencode(data)) - assert self.is_on_page(TrackPage) - - return self.page.get_info(_id) diff --git a/modules/ups/favicon.png b/modules/ups/favicon.png deleted file mode 100644 index 17e6a4064115fe9c5d36947ad03ed5bdeaf20b7b..0000000000000000000000000000000000000000 Binary files a/modules/ups/favicon.png and /dev/null differ diff --git a/modules/ups/module.py b/modules/ups/module.py deleted file mode 100644 index 4ca9bc432ec12745779b2abb55699aaad493563e..0000000000000000000000000000000000000000 --- a/modules/ups/module.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- 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 weboob.capabilities.parcel import CapParcel -from weboob.tools.backend import Module - -from .browser import UpsBrowser - - -__all__ = ['UpsModule'] - - -class UpsModule(Module, CapParcel): - NAME = 'ups' - DESCRIPTION = u'UPS website' - MAINTAINER = u'Romain Bignon' - EMAIL = 'romain@weboob.org' - VERSION = '1.4' - - BROWSER = UpsBrowser - - def get_parcel_tracking(self, id): - with self.browser: - return self.browser.get_tracking_info(id) diff --git a/modules/ups/pages.py b/modules/ups/pages.py deleted file mode 100644 index 907b4dab2630dfef57c41bf21fcd19a2cae880f2..0000000000000000000000000000000000000000 --- a/modules/ups/pages.py +++ /dev/null @@ -1,65 +0,0 @@ -# -*- 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 . - - -import re -from dateutil.parser import parse as parse_date - -from weboob.capabilities.parcel import Parcel, Event -from weboob.deprecated.browser import Page - - -class TrackPage(Page): - def get_info(self, id): - if len(self.parser.tocleanstring(self.document.xpath('//p[@class="error"]')[0])) > 0: - return None - - p = Parcel(id) - for dl in self.document.xpath('//dl'): - dt = dl.find('dt') - dd = dl.find('dd') - if dt is None or dd is None: - continue - label = self.parser.tocleanstring(dt) - if label == 'Scheduled Delivery:': - p.status = p.STATUS_IN_TRANSIT - elif label == u'Delivered On:': - p.status = p.STATUS_ARRIVED - else: - continue - - m = re.search('(\d+/\d+/\d+)', dd.text) - if m: - p.arrival = parse_date(m.group(1)) - - p.history = [] - for i, tr in enumerate(self.document.xpath('//table[@class="dataTable"]//tr')): - tds = tr.findall('td') - if len(tds) < 4: - continue - - ev = Event(i) - ev.location = self.parser.tocleanstring(tds[0]) - ev.activity = self.parser.tocleanstring(tds[-1]) - ev.date = parse_date('%s %s' % (tds[1].text, tds[2].text)) - p.history.append(ev) - - p.info = self.document.xpath('//a[@id="tt_spStatus"]')[0].text.strip() - - return p