From a6298871f2ddf7f7fca1601863b8d76ed9eb4c44 Mon Sep 17 00:00:00 2001 From: Julien Veyssier Date: Tue, 26 Feb 2013 00:29:45 +0100 Subject: [PATCH] new subtitle backend : tvsubtitles --- modules/opensubtitles/browser.py | 5 -- modules/opensubtitles/pages.py | 1 - modules/tvsubtitles/__init__.py | 3 + modules/tvsubtitles/backend.py | 55 +++++++++++++++ modules/tvsubtitles/browser.py | 66 ++++++++++++++++++ modules/tvsubtitles/favicon.png | Bin 0 -> 6496 bytes modules/tvsubtitles/pages.py | 115 +++++++++++++++++++++++++++++++ modules/tvsubtitles/test.py | 39 +++++++++++ 8 files changed, 278 insertions(+), 6 deletions(-) create mode 100644 modules/tvsubtitles/__init__.py create mode 100644 modules/tvsubtitles/backend.py create mode 100644 modules/tvsubtitles/browser.py create mode 100644 modules/tvsubtitles/favicon.png create mode 100644 modules/tvsubtitles/pages.py create mode 100644 modules/tvsubtitles/test.py diff --git a/modules/opensubtitles/browser.py b/modules/opensubtitles/browser.py index 596e43b7..65d922f5 100644 --- a/modules/opensubtitles/browser.py +++ b/modules/opensubtitles/browser.py @@ -62,11 +62,6 @@ class OpensubtitlesBrowser(BaseBrowser): return self.page.iter_subtitles() def get_subtitle(self, id): - """ the id is formed this way : id_movie|id_file - the id_movie helps to find the page - the id_file help to find the file into the page - if NO id_movie set, using id_file to form the URL - """ self.location('http://www.opensubtitles.org/subtitles/%s' % id) assert self.is_on_page(SubtitlePage) return self.page.get_subtitle() diff --git a/modules/opensubtitles/pages.py b/modules/opensubtitles/pages.py index 4e376714..e765fd84 100644 --- a/modules/opensubtitles/pages.py +++ b/modules/opensubtitles/pages.py @@ -29,7 +29,6 @@ from weboob.capabilities.subtitle import Subtitle from weboob.capabilities.base import NotAvailable from weboob.tools.browser import BasePage from weboob.tools.misc import get_bytes_size -import time __all__ = ['SubtitlesPage','SearchPage'] diff --git a/modules/tvsubtitles/__init__.py b/modules/tvsubtitles/__init__.py new file mode 100644 index 00000000..5ee86610 --- /dev/null +++ b/modules/tvsubtitles/__init__.py @@ -0,0 +1,3 @@ +from .backend import TvsubtitlesBackend + +__all__ = ['TvsubtitlesBackend'] diff --git a/modules/tvsubtitles/backend.py b/modules/tvsubtitles/backend.py new file mode 100644 index 00000000..5fb9508a --- /dev/null +++ b/modules/tvsubtitles/backend.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010-2011 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 ICapSubtitle +from weboob.tools.backend import BaseBackend + +from .browser import TvsubtitlesBrowser,LANGUAGE_CONV + +from urllib import quote_plus + +__all__ = ['TvsubtitlesBackend'] + + +class TvsubtitlesBackend(BaseBackend, ICapSubtitle): + NAME = 'tvsubtitles' + MAINTAINER = u'Julien Veyssier' + EMAIL = 'julien.veyssier@aiur.fr' + VERSION = '0.f' + DESCRIPTION = 'Tvsubtitles subtitle website' + LICENSE = 'AGPLv3+' + BROWSER = TvsubtitlesBrowser + + def create_default_browser(self): + return self.create_browser() + + 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 LANGUAGE_CONV.keys(): + return [] + return self.browser.iter_subtitles(language,quote_plus(pattern.encode('utf-8'))) diff --git a/modules/tvsubtitles/browser.py b/modules/tvsubtitles/browser.py new file mode 100644 index 00000000..4aad8b2a --- /dev/null +++ b/modules/tvsubtitles/browser.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010-2011 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.browser import BaseBrowser + +from .pages import SeriePage, SearchPage, SeasonPage,HomePage + + +__all__ = ['OpensubtitlesBrowser'] + +LANGUAGE_CONV = { +'ar':'ara', 'eo':'epo', 'ga':'', 'ru':'rus', +'af':'' , 'et':'est', 'it':'ita', 'sr':'scc', +'sq':'alb', 'tl':'' , 'ja':'jpn', 'sk':'slo', +'hy':'arm', 'fi':'fin', 'kn':'', 'sl':'slv', +'az':'' , 'fr':'fre', 'ko':'kor', 'es':'spa', +'eu':'baq', 'gl':'glg', 'la':'', 'sw':'swa', +'be':'' , 'ka':'geo', 'lv':'lav', 'sv':'swe', +'bn':'ben', 'de':'ger', 'lt':'lit', 'ta':'', +'bg':'bul', 'gr':'ell', 'mk':'mac', 'te':'tel', +'ca':'cat', 'gu':'' , 'ms':'may', 'th':'tha', +'zh':'chi', 'ht':'' , 'mt':'', 'tr':'tur', +'hr':'hrv', 'iw':'heb', 'no':'nor', 'uk':'ukr', +'cz':'cze', 'hi':'hin', 'fa':'per', 'ur':'urd', +'da':'dan', 'hu':'hun', 'pl':'pol', 'vi':'vie', +'nl':'dut', 'is':'ice', 'pt':'por', 'cy':'', +'en':'eng', 'id':'ind', 'ro':'rum', 'yi':''} + +class TvsubtitlesBrowser(BaseBrowser): + DOMAIN = 'www.tvsubtitles.net' + PROTOCOL = 'http' + ENCODING = 'utf-8' + USER_AGENT = BaseBrowser.USER_AGENTS['wget'] + PAGES = { + 'http://www.tvsubtitles.net': HomePage, + 'http://www.tvsubtitles.net/search.php': SearchPage, + 'http://www.tvsubtitles.net/tvshow-.*.html': SeriePage, + 'http://www.tvsubtitles.net/subtitle-[0-9]*-[0-9]*-.*.html' : SeasonPage + } + + def iter_subtitles(self, language, pattern): + self.location('http://www.tvsubtitles.net') + assert self.is_on_page(HomePage) + return self.page.iter_subtitles(language,pattern) + + def get_subtitle(self, id): + self.location('http://www.tvsubtitles.net/subtitle-%s.html' % id) + assert self.is_on_page(SeasonPage) + return self.page.get_subtitle() diff --git a/modules/tvsubtitles/favicon.png b/modules/tvsubtitles/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..253ee0a96077b597fa79c6d34b6e084834b83498 GIT binary patch literal 6496 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. + + +try: + from urlparse import parse_qs +except ImportError: + from cgi import parse_qs # NOQA + +from urlparse import urlsplit + +from weboob.capabilities.subtitle import Subtitle +from weboob.capabilities.base import NotAvailable +from weboob.tools.browser import BasePage +from weboob.tools.misc import get_bytes_size + + +__all__ = ['HomePage','SearchPage','SeriePage','SeasonPage'] + + +class HomePage(BasePage): + def iter_subtitles(self,language,pattern): + self.browser.select_form(nr=0) + self.browser['q'] = pattern.encode('utf-8') + self.browser.submit() + assert self.browser.is_on_page(SearchPage) + for subtitle in self.browser.page.iter_subtitles(language): + yield subtitle + + +class SearchPage(BasePage): + """ Page which contains results as a list of series + """ + def iter_subtitles(self,language): + list_result = self.parser.select(self.document.getroot(),'div.left_articles ul',1) + li_result = self.parser.select(list_result,'li') + for line in li_result: + if len(self.parser.select(line,'img[alt=%s]'%language)) > 0: + link = self.parser.select(line,'a',1) + href = link.attrib.get('href','') + self.browser.location("http://%s%s"%(self.browser.DOMAIN,href)) + assert self.browser.is_on_page(SeriePage) + for subtitle in self.browser.page.iter_subtitles(language): + yield subtitle + + +class SeriePage(BasePage): + """ Page of all seasons + """ + def iter_subtitles(self,language,only_one_season=False): + # handle the current season + last_table_line = self.parser.select(self.document.getroot(),'table#table5 tr')[-1] + amount = int(self.parser.select(last_table_line,'td')[2].text_content()) + if amount > 0: + my_lang_img = self.parser.select(last_table_line,'img[alt=%s]'%language) + if len(my_lang_img) > 0: + url_current_season = self.browser.geturl().split('/')[-1].replace('tvshow','subtitle').replace('.html','-%s.html'%language) + self.browser.location(url_current_season) + assert self.browser.is_on_page(SeasonPage) + yield self.browser.page.iter_subtitles() + + if not only_one_season: + # handle the other seasons by following top links + other_seasons_links = self.parser.select(self.document.getroot(),'p.description a') + for link in other_seasons_links: + href = link.attrib.get('href','') + self.browser.location("http://%s/%s"%(self.browser.DOMAIN,href)) + assert self.browser.is_on_page(SeriePage) + for subtitle in self.browser.page.iter_subtitles(language,True): + yield subtitle + + +class SeasonPage(BasePage): + """ Page of a season with the right language + """ + def get_subtitle(self): + filename_line = self.parser.select(self.document.getroot(),'img[alt=filename]',1).getparent().getparent() + name = self.parser.select(filename_line,'td')[2].text + id = self.browser.geturl().split('/')[-1].replace('.html','').replace('subtitle-','') + url = "http://%s/download-%s.html"%(self.browser.DOMAIN,id) + amount_line = self.parser.select(self.document.getroot(),'tr[title~=amount]',1) + nb_cd = int(self.parser.select(amount_line,'td')[2].text) + lang = url.split('-')[-1].split('.html')[0] + filenames_line = self.parser.select(self.document.getroot(),'tr[title~=list]',1) + file_names = self.parser.select(filenames_line,'td')[2].text_content().strip().replace('.srt','.srt\n') + desc = u"files :\n" + desc += file_names + fps = 0 + + subtitle = Subtitle(id,name) + subtitle.url = url + subtitle.fps = fps + subtitle.language = lang + subtitle.nb_cd = nb_cd + subtitle.description = desc + return subtitle + + def iter_subtitles(self): + return self.get_subtitle() diff --git a/modules/tvsubtitles/test.py b/modules/tvsubtitles/test.py new file mode 100644 index 00000000..ef14f2ba --- /dev/null +++ b/modules/tvsubtitles/test.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +# Copyright(C) 2010-2011 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 +from weboob.capabilities.base import NotLoaded + +import urllib +from random import choice + +class TvsubtitlesTest(BackendTest): + BACKEND = 'tvsubtitles' + + def test_subtitle(self): + subtitles = list(self.backend.iter_subtitles('fr','sopranos')) + assert (len(subtitles) > 0) + for subtitle in subtitles: + path, qs = urllib.splitquery(subtitle.url) + assert path.endswith('.zip') + + # get the file of a random sub + if len(subtitles): + subtitle = choice(subtitles) + self.backend.get_subtitle_file(subtitle.id)