Skip to content

Commit

Permalink
Added a spanish subtitle provider subtitulamos.tv (#7518)
Browse files Browse the repository at this point in the history
* Added support to www.subtitulamos.tv/

* Update subtitulamos.py

Fix syntax

* Update setup.cfg

Added medusa/subtitle_providers/subtitulamos.py.

* Update subtitulamos.py

Fixed the flake issues D204.

* Update subtitulamos.py

Fixed the flake issues W293.

* Update subtitulamos.py

Minor changes made.

* Update subtitulamos.py

Problem with tabs resolved.
  • Loading branch information
porzino authored and medariox committed Jan 5, 2020
1 parent bdd18d4 commit e7c72c6
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 0 deletions.
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.

0 comments on commit e7c72c6

Please sign in to comment.