Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added a spanish subtitle provider subtitulamos.tv #7518

Merged
merged 7 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions medusa/init/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ def _configure_subliminal():
# Register
for name in ('napiprojekt = subliminal.providers.napiprojekt:NapiProjektProvider',
'itasa = {basename}.subtitle_providers.itasa:ItaSAProvider'.format(basename=basename),
'subtitulamos = {basename}.subtitle_providers.subtitulamos:SubtitulamosProvider'.format(basename=basename),
'wizdom = {basename}.subtitle_providers.wizdom:WizdomProvider'.format(basename=basename)):
provider_manager.register(name)

Expand Down
237 changes: 237 additions & 0 deletions medusa/subtitle_providers/subtitulamos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import json
import logging
import re

from babelfish import Language, LanguageReverseConverter, language_converters

from guessit import guessit

from requests import Session

from subliminal import __short_version__
from subliminal.cache import EPISODE_EXPIRATION_TIME, region
from subliminal.exceptions import ProviderError
from subliminal.providers import ParserBeautifulSoup, Provider
from subliminal.score import get_equivalent_release_groups
from subliminal.subtitle import Subtitle, fix_line_ending, guess_matches
from subliminal.utils import sanitize, sanitize_release_group
from subliminal.video import Episode

logger = logging.getLogger(__name__)
basename = __name__.split('.')[0]


class SubtitulamosConverter(LanguageReverseConverter):
def __init__(self):
self.name_converter = language_converters['name']
self.from_subtitulamos = {u'Español': ('spa',), u'Español (España)': ('spa',), u'Español (Latinoamérica)': ('spa', 'MX'),
u'Català': ('cat',), 'English': ('eng',), 'Galego': ('glg',), 'Portuguese': ('por',),
'English (US)': ('eng', 'US'), 'English (UK)': ('eng', 'GB'), 'Brazilian': ('por', 'BR')}

self.to_subtitulamos = {('cat',): u'Català', ('glg',): 'Galego', ('por', 'BR'): 'Brazilian'}

self.codes = set(self.from_subtitulamos.keys())

def convert(self, alpha3, country=None, script=None):
if (alpha3, country, script) in self.to_subtitulamos:
return self.to_subtitulamos[[alpha3, country, script]]
if (alpha3, country) in self.to_subtitulamos:
return self.to_subtitulamos[(alpha3, country)]
if (alpha3,) in self.to_subtitulamos:
return self.to_subtitulamos[(alpha3,)]

return self.name_converter.convert(alpha3, country, script)

def reverse(self, subtitulamos):
if subtitulamos in self.from_subtitulamos:
return self.from_subtitulamos[subtitulamos]

return self.name_converter.reverse(subtitulamos)


language_converters.register('subtitulamos = {basename}.subtitle_providers.subtitulamos:SubtitulamosConverter'.format(basename=basename))


class SubtitulamosSubtitle(Subtitle):
"""Subtitulamos Subtitle."""

provider_name = 'subtitulamos'

def __init__(self, language, hearing_impaired, page_link, series, season, episode, title, year, version,
download_link):
super(SubtitulamosSubtitle, self).__init__(language, hearing_impaired, page_link)
self.page_link = page_link
self.series = series
self.season = season
self.episode = episode
self.title = title
self.year = year
self.version = version
self.download_link = download_link

@property
def id(self):
return self.download_link

def get_matches(self, video):
matches = set()

# series name
if video.series and sanitize(self.series) == sanitize(video.series):
matches.add('series')
# season
if video.season and self.season == video.season:
matches.add('season')
# episode
if video.episode and self.episode == video.episode:
matches.add('episode')
# title of the episode
if video.title and sanitize(self.title) == sanitize(video.title):
matches.add('title')
# year
if video.original_series and self.year is None or video.year and video.year == self.year:
matches.add('year')
# release_group
if (video.release_group and self.version and
any(r in sanitize_release_group(self.version)
for r in get_equivalent_release_groups(sanitize_release_group(video.release_group)))):
matches.add('release_group')
# resolution
if video.resolution and self.version and video.resolution in self.version.lower():
matches.add('resolution')
# other properties
matches |= guess_matches(video, guessit(self.version), partial=True)

return matches


class SubtitulamosProvider(Provider):
"""Subtitulamos Provider."""

languages = {Language('por', 'BR')} | {Language(l) for l in [
'cat', 'eng', 'glg', 'por', 'spa'
]}
video_types = (Episode,)
server_url = 'https://www.subtitulamos.tv/'
search_url = server_url + 'search/query'

def initialize(self):
self.session = Session()
self.session.headers['User-Agent'] = 'Subliminal/%s' % __short_version__

def terminate(self):
self.session.close()

@region.cache_on_arguments(expiration_time=EPISODE_EXPIRATION_TIME)
def _search_url_titles(self, series, season, episode, year=None):
"""Search the URL titles by kind for the given `title`, `season` and `episode`.

:param str series: series to search for.
:param int season: season to search for.
:param int episode: episode to search for.
:param int year: year to search for.
:return: the episode URL.
:rtype: str

"""
# make the search
logger.info('Searching episode url for %s, season %d, episode %d', series, season, episode)
episode_url = None

search = '{} {}x{}'.format(series, season, episode)
r = self.session.get(self.search_url, headers={'Referer': self.server_url}, params={'q': search}, timeout=10)
r.raise_for_status()

if r.status_code != 200:
logger.warning('Error getting episode url')
raise ProviderError('%s: Error getting episode url', self.__class__.__name__.upper())

results = json.loads(r.text)

for result in results:
title = sanitize(result['name'])

# attempt series with year
if sanitize('{} ({})'.format(series, year)) in title:
for episode_data in result['episodes']:
if season == episode_data['season'] and episode == episode_data['number']:
episode_url = self.server_url + 'episodes/{}'.format(episode_data['id'])
logger.info('Episode url found with year %s', episode_url)
return episode_url
# attempt series without year
elif sanitize(series) in title:
for episode_data in result['episodes']:
if season == episode_data['season'] and episode == episode_data['number']:
episode_url = self.server_url + 'episodes/{}'.format(episode_data['id'])
logger.info('Episode url found without year %s', episode_url)
return episode_url

return episode_url

def query(self, series, season, episode, year=None):
# get the episode url
episode_url = self._search_url_titles(series, season, episode, year)
if episode_url is None:
logger.info('No episode url found for %s, season %d, episode %d', series, season, episode)
return []

r = self.session.get(episode_url, headers={'Referer': self.server_url}, timeout=10)
r.raise_for_status()
soup = ParserBeautifulSoup(r.content, ['lxml', 'html.parser'])

# get episode title
logger.debug('Getting episode title')

title_pattern = re.compile('{}x{:02d} - (.+)'.format(season, episode))
title = title_pattern.search(soup.select('.episode-name')[0].get_text(strip=True).lower()).group(1)

logger.debug('Episode title found: "%s"', title.upper())

subtitles = []
for sub in soup.find_all('div', attrs={'id': 'progress_buttons_row'}):
# read the language
language = Language.fromsubtitulamos(sub.find_previous('div', class_='subtitle_language').get_text(strip=True))
hearing_impaired = False

# modify spanish latino subtitle language to only spanish and set hearing_impaired = True
# because if exists spanish and spanish latino subtitle for the same episode, the score will be
# higher with spanish subtitle. Spanish subtitle takes priority.
if language == Language('spa', 'MX'):
language = Language('spa')
hearing_impaired = True

# read the release subtitle
release = sub.find_next('div', class_='version_name').get_text(strip=True)

# ignore incomplete subtitles
status = sub.find_next('div', class_='subtitle_buttons').contents[1]
# if there isn't <a> tag, subtitle not finished and no link available to download it
if status.name != 'a':
logger.info('Ignoring subtitle in [%s] because it is not finished', language)
continue

# read the subtitle url
subtitle_url = self.server_url + status['href'][1:]
subtitle = SubtitulamosSubtitle(language, hearing_impaired, episode_url, series, season, episode, title,
year, release, subtitle_url)
logger.info('Found subtitle %r', subtitle)
subtitles.append(subtitle)

return subtitles

def list_subtitles(self, video, languages):
return [s for s in self.query(video.series, video.season, video.episode,
video.year)
if s.language in languages]

def download_subtitle(self, subtitle):
# download the subtitle
logger.info('Downloading subtitle %s', subtitle.download_link)
r = self.session.get(subtitle.download_link, headers={'Referer': subtitle.page_link},
timeout=10)
r.raise_for_status()

subtitle.content = fix_line_ending(r.content)
1 change: 1 addition & 0 deletions medusa/subtitles.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
'opensubtitles': 'http://www.opensubtitles.org',
'podnapisi': 'https://www.podnapisi.net',
'shooter': 'http://www.shooter.cn',
'subtitulamos': 'https://www.subtitulamos.tv',
'thesubdb': 'http://www.thesubdb.com',
'tvsubtitles': 'http://www.tvsubtitles.net',
'wizdom': 'http://wizdom.xyz'
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ flake8-ignore =
medusa/subtitle_providers/__init__.py D104
medusa/subtitle_providers/legendastv.py D100 D102 D103 D105 D204
medusa/subtitle_providers/itasa.py D100 D101 D102 D105 D400 N813
medusa/subtitle_providers/subtitulamos.py D100 D101 D102
medusa/subtitle_providers/wizdom.py D100 D102 D204
medusa/system/__init__.py D104
medusa/system/restart.py D100 D101 D102
Expand Down
1 change: 1 addition & 0 deletions tests/test_subtitles.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ def test_sorted_service_list(monkeypatch):
{'name': 'napiprojekt', 'enabled': False},
{'name': 'opensubtitles', 'enabled': False},
{'name': 'podnapisi', 'enabled': False},
{'name': 'subtitulamos', 'enabled': False},
{'name': 'tvsubtitles', 'enabled': False},
{'name': 'wizdom', 'enabled': False},
]
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added themes/dark/assets/img/subtitles/subtitulamos.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added themes/light/assets/img/subtitles/subtitulamos.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.