Skip to content

Commit

Permalink
Merge d291a84 into 76525cc
Browse files Browse the repository at this point in the history
  • Loading branch information
ofir123 committed May 8, 2019
2 parents 76525cc + d291a84 commit dd5eeb6
Show file tree
Hide file tree
Showing 17 changed files with 2,936 additions and 13 deletions.
5 changes: 5 additions & 0 deletions docs/api/providers.rst
Expand Up @@ -41,3 +41,8 @@ TVsubtitles
-----------
.. automodule:: subliminal.providers.tvsubtitles
:private-members:

Wizdom
------
.. automodule:: subliminal.providers.wizdom
:private-members:
1 change: 1 addition & 0 deletions docs/user/how_it_works.rst
Expand Up @@ -14,6 +14,7 @@ subtitles. Current supported providers are:
* Shooter
* TheSubDB
* TvSubtitles
* Wizdom

Providers all inherit the same :class:`~subliminal.providers.Provider` base class and thus share the same API.
They are registered on the ``subliminal.providers`` entry point and are exposed through the
Expand Down
3 changes: 2 additions & 1 deletion setup.py
Expand Up @@ -74,7 +74,8 @@ def find_version(*file_paths):
'podnapisi = subliminal.providers.podnapisi:PodnapisiProvider',
'shooter = subliminal.providers.shooter:ShooterProvider',
'thesubdb = subliminal.providers.thesubdb:TheSubDBProvider',
'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider'
'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider',
'wizdom = subliminal.providers.wizdom:WizdomProvider'
],
'subliminal.refiners': [
'metadata = subliminal.refiners.metadata:refine',
Expand Down
3 changes: 2 additions & 1 deletion subliminal/extensions.py
Expand Up @@ -96,7 +96,8 @@ def unregister(self, entry_point):
'podnapisi = subliminal.providers.podnapisi:PodnapisiProvider',
'shooter = subliminal.providers.shooter:ShooterProvider',
'thesubdb = subliminal.providers.thesubdb:TheSubDBProvider',
'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider'
'tvsubtitles = subliminal.providers.tvsubtitles:TVsubtitlesProvider',
'wizdom = subliminal.providers.wizdom:WizdomProvider'
])

#: Disabled providers
Expand Down
206 changes: 206 additions & 0 deletions subliminal/providers/wizdom.py
@@ -0,0 +1,206 @@
# -*- coding: utf-8 -*-
import io
import logging
import os
import zipfile

from babelfish import Language
from guessit import guessit
from requests import Session

from . import Provider
from .. import __short_version__
from ..cache import SHOW_EXPIRATION_TIME, region
from ..exceptions import ProviderError
from ..matches import guess_matches
from ..subtitle import Subtitle, fix_line_ending
from ..utils import sanitize
from ..video import Episode, Movie

logger = logging.getLogger(__name__)


class WizdomSubtitle(Subtitle):
"""Wizdom Subtitle."""
provider_name = 'wizdom'

def __init__(self, language, hearing_impaired, page_link, series, season, episode, title, imdb_id, subtitle_id,
release):
super(WizdomSubtitle, self).__init__(language, hearing_impaired, page_link)
self.series = series
self.season = season
self.episode = episode
self.title = title
self.imdb_id = imdb_id
self.subtitle_id = subtitle_id
self.release = release

@property
def id(self):
return str(self.subtitle_id)

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

# episode
if isinstance(video, Episode):
# series
if video.series and (sanitize(self.title) in (
sanitize(name) for name in [video.series] + video.alternative_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')
# imdb_id
if video.series_imdb_id and self.imdb_id == video.series_imdb_id:
matches.add('series_imdb_id')
# guess
matches |= guess_matches(video, guessit(self.release, {'type': 'episode'}), partial=True)
# movie
elif isinstance(video, Movie):
# guess
matches |= guess_matches(video, guessit(self.release, {'type': 'movie'}), partial=True)

# title
if video.title and (sanitize(self.title) in (
sanitize(name) for name in [video.title] + video.alternative_titles)):
matches.add('title')

return matches


class WizdomProvider(Provider):
"""Wizdom Provider."""
languages = {Language.fromalpha2(l) for l in ['he']}
server_url = 'wizdom.xyz'

_tmdb_api_key = 'a51ee051bcd762543373903de296e0a3'

def __init__(self):
self.session = None

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

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

@region.cache_on_arguments(expiration_time=SHOW_EXPIRATION_TIME)
def _search_imdb_id(self, title, year, is_movie):
"""Search the IMDB ID for the given `title` and `year`.
:param str title: title to search for.
:param int year: year to search for (or 0 if not relevant).
:param bool is_movie: If True, IMDB ID will be searched for in TMDB instead of Wizdom.
:return: the IMDB ID for the given title and year (or None if not found).
:rtype: str
"""
# make the search
logger.info('Searching IMDB ID for %r%r', title, '' if not year else ' ({})'.format(year))
category = 'movie' if is_movie else 'tv'
title = title.replace('\'', '')
# get TMDB ID first
r = self.session.get('http://api.tmdb.org/3/search/{}?api_key={}&query={}{}&language=en'.format(
category, self._tmdb_api_key, title, '' if not year else '&year={}'.format(year)))
r.raise_for_status()
tmdb_results = r.json().get('results')
if tmdb_results:
tmdb_id = tmdb_results[0].get('id')
if tmdb_id:
# get actual IMDB ID from TMDB
r = self.session.get('http://api.tmdb.org/3/{}/{}{}?api_key={}&language=en'.format(
category, tmdb_id, '' if is_movie else '/external_ids', self._tmdb_api_key))
r.raise_for_status()
return str(r.json().get('imdb_id', '')) or None
return None

def query(self, title, season=None, episode=None, year=None, filename=None, imdb_id=None):
# search for the IMDB ID if needed.
is_movie = not (season and episode)
imdb_id = imdb_id or self._search_imdb_id(title, year, is_movie)
if not imdb_id:
return {}

# search
logger.debug('Using IMDB ID %r', imdb_id)
url = 'http://json.{}/{}.json'.format(self.server_url, imdb_id)
page_link = 'http://{}/#/{}/{}'.format(self.server_url, 'movies' if is_movie else 'series', imdb_id)

# get the list of subtitles
logger.debug('Getting the list of subtitles')
r = self.session.get(url)
r.raise_for_status()
try:
results = r.json()
except ValueError:
return {}

# filter irrelevant results
if not is_movie:
results = results.get('subs', [])
# there are two formats of result jsons - seasons list and seasons dict
if isinstance(results, list):
results = results[season] if len(results) >= season else {}
else:
results = results.get(str(season), {})
results = results.get(str(episode), [])
else:
results = results.get('subs', [])

# loop over results
subtitles = {}
for result in results:
language = Language.fromalpha2('he')
hearing_impaired = False
subtitle_id = result['id']
release = result['version']

# otherwise create it
subtitle = WizdomSubtitle(language, hearing_impaired, page_link, title, season, episode, title, imdb_id,
subtitle_id, release)
logger.debug('Found subtitle %r', subtitle)
subtitles[subtitle_id] = subtitle

return subtitles.values()

def list_subtitles(self, video, languages):
season = episode = None
year = video.year
filename = video.name
imdb_id = video.imdb_id

if isinstance(video, Episode):
titles = [video.series] + video.alternative_series
season = video.season
episode = video.episode
imdb_id = video.series_imdb_id
else:
titles = [video.title] + video.alternative_titles

for title in titles:
subtitles = [s for s in
self.query(title, season, episode, year, filename, imdb_id) if s.language in languages]
if subtitles:
return subtitles

return []

def download_subtitle(self, subtitle):
# download
url = 'http://zip.{}/{}.zip'.format(self.server_url, subtitle.subtitle_id)
r = self.session.get(url, headers={'Referer': subtitle.page_link}, timeout=10)
r.raise_for_status()

# open the zip
with zipfile.ZipFile(io.BytesIO(r.content)) as zf:
# remove some filenames from the namelist
namelist = [n for n in zf.namelist() if os.path.splitext(n)[1] in ['.srt', '.sub']]
if len(namelist) > 1:
raise ProviderError('More than one file to unzip')

subtitle.content = fix_line_ending(zf.read(namelist[0]))

0 comments on commit dd5eeb6

Please sign in to comment.