Merge remote-tracking branch 'origin/development' into halali

# Conflicts:
#	bazarr/get_subtitle.py
pull/489/head
Halali 5 years ago
commit eef8e33554

@ -58,22 +58,23 @@ def get_video(path, title, sceneName, use_scenename, providers=None, media_type=
# use the sceneName but keep the folder structure for better guessing # use the sceneName but keep the folder structure for better guessing
path = os.path.join(os.path.dirname(path), sceneName + os.path.splitext(path)[1]) path = os.path.join(os.path.dirname(path), sceneName + os.path.splitext(path)[1])
dont_use_actual_file = True dont_use_actual_file = True
if providers:
try: try:
if providers:
video = parse_video(path, hints=hints, providers=providers, dry_run=dont_use_actual_file) video = parse_video(path, hints=hints, providers=providers, dry_run=dont_use_actual_file)
video.used_scene_name = dont_use_actual_file video.used_scene_name = dont_use_actual_file
video.original_name = original_name video.original_name = original_name
video.original_path = original_path video.original_path = original_path
refine_video(video) try:
refine_video(video)
except Exception as e:
logging.debug('BAZARR Error trying to refine this file: ' + path)
pass
return video return video
else: except:
logging.info("BAZARR All providers are throttled") logging.exception("BAZARR Error trying to get video information for this file: " + path)
return None else:
logging.info("BAZARR All providers are throttled")
return None
except:
logging.exception("BAZARR Error trying to get video information for this file: " + path)
def get_scores(video, media_type, min_score_movie_perc=60 * 100 / 120.0, min_score_series_perc=240 * 100 / 360.0, def get_scores(video, media_type, min_score_movie_perc=60 * 100 / 120.0, min_score_series_perc=240 * 100 / 360.0,

@ -9,6 +9,7 @@ import rarfile
from cork import Cork from cork import Cork
from ConfigParser2 import ConfigParser from ConfigParser2 import ConfigParser
from whichcraft import which
from config import settings from config import settings
from check_update import check_releases from check_update import check_releases
from get_args import args from get_args import args
@ -153,9 +154,10 @@ def init_binaries():
unrar_exe = None unrar_exe = None
exe = None exe = None
installed_unrar = which('unrar')
if os.path.isfile("unrar"): if installed_unrar and os.path.isfile(installed_unrar):
unrar_exe = "unrar" unrar_exe = installed_unrar
else: else:
if platform.system() == "Windows": # Windows if platform.system() == "Windows": # Windows
unrar_exe = os.path.abspath(os.path.join(binaries_dir, "Windows", "i386", "UnRAR", "UnRAR.exe")) unrar_exe = os.path.abspath(os.path.join(binaries_dir, "Windows", "i386", "UnRAR", "UnRAR.exe"))

@ -63,4 +63,3 @@ subliminal.refiner_manager.register('drone = subliminal_patch.refiners.drone:ref
subliminal.refiner_manager.register('filebot = subliminal_patch.refiners.filebot:refine') subliminal.refiner_manager.register('filebot = subliminal_patch.refiners.filebot:refine')
subliminal.refiner_manager.register('file_info_file = subliminal_patch.refiners.file_info_file:refine') subliminal.refiner_manager.register('file_info_file = subliminal_patch.refiners.file_info_file:refine')
subliminal.refiner_manager.register('symlinks = subliminal_patch.refiners.symlinks:refine') subliminal.refiner_manager.register('symlinks = subliminal_patch.refiners.symlinks:refine')

@ -0,0 +1,159 @@
# -*- coding: utf-8 -*-
import logging
import re
import io
import os
from random import randint
from bs4 import BeautifulSoup
from zipfile import ZipFile, is_zipfile
from rarfile import RarFile, is_rarfile
from requests import Session
from guessit import guessit
from subliminal_patch.providers import Provider
from subliminal_patch.subtitle import Subtitle
from subliminal_patch.utils import sanitize
from subliminal.exceptions import ProviderError
from subliminal.utils import sanitize_release_group
from subliminal.subtitle import guess_matches
from subliminal.video import Episode, Movie
from subliminal.subtitle import fix_line_ending
from subzero.language import Language
from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST
logger = logging.getLogger(__name__)
class SubsSabBzSubtitle(Subtitle):
"""SubsSabBz Subtitle."""
provider_name = 'subssabbz'
def __init__(self, langauge, filename, type):
super(SubsSabBzSubtitle, self).__init__(langauge)
self.langauge = langauge
self.filename = filename
self.type = type
@property
def id(self):
return self.filename
def get_matches(self, video):
matches = set()
video_filename = video.name
video_filename = os.path.basename(video_filename)
video_filename, _ = os.path.splitext(video_filename)
video_filename = sanitize_release_group(video_filename)
subtitle_filename = self.filename
subtitle_filename = os.path.basename(subtitle_filename)
subtitle_filename, _ = os.path.splitext(subtitle_filename)
subtitle_filename = sanitize_release_group(subtitle_filename)
if video_filename == subtitle_filename:
matches.add('hash')
matches |= guess_matches(video, guessit(self.filename, {'type': self.type}))
matches.add(id(self))
return matches
class SubsSabBzProvider(Provider):
"""SubsSabBz Provider."""
languages = {Language('por', 'BR')} | {Language(l) for l in [
'bul', 'eng'
]}
def initialize(self):
self.session = Session()
self.session.headers['User-Agent'] = AGENT_LIST[randint(0, len(AGENT_LIST) - 1)]
self.session.headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
self.session.headers["Accept-Language"] = "en-US,en;q=0.5"
self.session.headers["Accept-Encoding"] = "gzip, deflate, br"
self.session.headers["DNT"] = "1"
self.session.headers["Connection"] = "keep-alive"
self.session.headers["Upgrade-Insecure-Requests"] = "1"
self.session.headers["Cache-Control"] = "max-age=0"
def terminate(self):
self.session.close()
def query(self, language, video):
subtitles = []
isEpisode = isinstance(video, Episode)
params = {
'act': 'search',
'movie': '',
'select-language': '2',
'upldr': '',
'yr': '',
'release': ''
}
if isEpisode:
params['movie'] = "%s %02d %02d" % (sanitize(video.series), video.season, video.episode)
else:
params['yr'] = video.year
params['movie'] = (video.title)
if language == 'en' or language == 'eng':
params['select-language'] = 1
logger.info('Searching subtitle %r', params)
response = self.session.post('http://subs.sab.bz/index.php?', params=params, allow_redirects=False, timeout=10, headers={
'Referer': 'http://subs.sab.bz/',
})
response.raise_for_status()
if response.status_code != 200:
logger.debug('No subtitles found')
return subtitles
soup = BeautifulSoup(response.content, 'html.parser')
rows = soup.findAll('tr', {'class': 'subs-row'})
# Search on first 10 rows only
for row in rows[:10]:
a_element_wrapper = row.find('td', { 'class': 'c2field' })
if a_element_wrapper:
element = row.find('a')
if element:
link = element.get('href')
logger.info('Found subtitle link %r', link)
subtitles = subtitles + self.download_archive_and_add_subtitle_files(link, language, video)
return subtitles
def list_subtitles(self, video, languages):
return [s for l in languages for s in self.query(l, video)]
def download_subtitle(self, subtitle):
pass
def process_archive_subtitle_files(self, archiveStream, language, video):
subtitles = []
type = 'episode' if isinstance(video, Episode) else 'movie'
for file_name in archiveStream.namelist():
if file_name.lower().endswith(('.srt', '.sub')):
logger.info('Found subtitle file %r', file_name)
subtitle = SubsSabBzSubtitle(language, file_name, type)
subtitle.content = archiveStream.read(file_name)
subtitles.append(subtitle)
return subtitles
def download_archive_and_add_subtitle_files(self, link, language, video ):
logger.info('Downloading subtitle %r', link)
request = self.session.get(link, headers={
'Referer': 'http://subs.sab.bz/index.php?'
})
request.raise_for_status()
archive_stream = io.BytesIO(request.content)
if is_rarfile(archive_stream):
return self.process_archive_subtitle_files( RarFile(archive_stream), language, video )
elif is_zipfile(archive_stream):
return self.process_archive_subtitle_files( ZipFile(archive_stream), language, video )
else:
raise ValueError('Not a valid archive')

@ -0,0 +1,161 @@
# -*- coding: utf-8 -*-
import logging
import re
import io
import os
from random import randint
from bs4 import BeautifulSoup
from zipfile import ZipFile, is_zipfile
from rarfile import RarFile, is_rarfile
from requests import Session
from guessit import guessit
from subliminal_patch.providers import Provider
from subliminal_patch.subtitle import Subtitle
from subliminal_patch.utils import sanitize
from subliminal.exceptions import ProviderError
from subliminal.utils import sanitize_release_group
from subliminal.subtitle import guess_matches
from subliminal.video import Episode, Movie
from subliminal.subtitle import fix_line_ending
from subzero.language import Language
from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST
logger = logging.getLogger(__name__)
class SubsUnacsSubtitle(Subtitle):
"""SubsUnacs Subtitle."""
provider_name = 'subsunacs'
def __init__(self, langauge, filename, type):
super(SubsUnacsSubtitle, self).__init__(langauge)
self.langauge = langauge
self.filename = filename
self.type = type
@property
def id(self):
return self.filename
def get_matches(self, video):
matches = set()
video_filename = video.name
video_filename = os.path.basename(video_filename)
video_filename, _ = os.path.splitext(video_filename)
video_filename = sanitize_release_group(video_filename)
subtitle_filename = self.filename
subtitle_filename = os.path.basename(subtitle_filename)
subtitle_filename, _ = os.path.splitext(subtitle_filename)
subtitle_filename = sanitize_release_group(subtitle_filename)
if video_filename == subtitle_filename:
matches.add('hash')
matches |= guess_matches(video, guessit(self.filename, {'type': self.type}))
matches.add(id(self))
return matches
class SubsUnacsProvider(Provider):
"""SubsUnacs Provider."""
languages = {Language('por', 'BR')} | {Language(l) for l in [
'bul', 'eng'
]}
def initialize(self):
self.session = Session()
self.session.headers['User-Agent'] = AGENT_LIST[randint(0, len(AGENT_LIST) - 1)]
self.session.headers["Accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
self.session.headers["Accept-Language"] = "en-US,en;q=0.5"
self.session.headers["Accept-Encoding"] = "gzip, deflate, br"
self.session.headers["DNT"] = "1"
self.session.headers["Connection"] = "keep-alive"
self.session.headers["Upgrade-Insecure-Requests"] = "1"
self.session.headers["Cache-Control"] = "max-age=0"
def terminate(self):
self.session.close()
def query(self, language, video):
subtitles = []
isEpisode = isinstance(video, Episode)
params = {
'm': '',
'l': 0,
'c': '',
'y': '',
'action': " Търси ",
'a': '',
'd': '',
'u': '',
'g': '',
't': '',
'imdbcheck': 1}
if isEpisode:
params['m'] = "%s %02d %02d" % (sanitize(video.series), video.season, video.episode)
else:
params['y'] = video.year
params['m'] = (video.title)
if language == 'en' or language == 'eng':
params['l'] = 1
logger.info('Searching subtitle %r', params)
response = self.session.post('https://subsunacs.net/search.php', params=params, allow_redirects=False, timeout=10, headers={
'Referer': 'https://subsunacs.net/index.php',
})
response.raise_for_status()
if response.status_code != 200:
logger.debug('No subtitles found')
return subtitles
soup = BeautifulSoup(response.content, 'html.parser')
rows = soup.findAll('td', {'class': 'tdMovie'})
# Search on first 10 rows only
for row in rows[:10]:
element = row.find('a', {'class': 'tooltip'})
if element:
link = element.get('href')
logger.info('Found subtitle link %r', link)
subtitles = subtitles + self.download_archive_and_add_subtitle_files('https://subsunacs.net' + link, language, video)
return subtitles
def list_subtitles(self, video, languages):
return [s for l in languages for s in self.query(l, video)]
def download_subtitle(self, subtitle):
pass
def process_archive_subtitle_files(self, archiveStream, language, video):
subtitles = []
type = 'episode' if isinstance(video, Episode) else 'movie'
for file_name in archiveStream.namelist():
if file_name.lower().endswith(('.srt', '.sub')):
logger.info('Found subtitle file %r', file_name)
subtitle = SubsUnacsSubtitle(language, file_name, type)
subtitle.content = archiveStream.read(file_name)
subtitles.append(subtitle)
return subtitles
def download_archive_and_add_subtitle_files(self, link, language, video ):
logger.info('Downloading subtitle %r', link)
request = self.session.get(link, headers={
'Referer': 'https://subsunacs.net/search.php'
})
request.raise_for_status()
archive_stream = io.BytesIO(request.content)
if is_rarfile(archive_stream):
return self.process_archive_subtitle_files( RarFile(archive_stream), language, video )
elif is_zipfile(archive_stream):
return self.process_archive_subtitle_files( ZipFile(archive_stream), language, video )
else:
raise ValueError('Not a valid archive')

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
__author__ = "Daniel Roy Greenfeld"
__email__ = "pydanny@gmail.com"
__version__ = "0.5.2"
import os
import sys
try: # Forced testing
from shutil import which
except ImportError: # Forced testing
# Versions prior to Python 3.3 don't have shutil.which
def which(cmd, mode=os.F_OK | os.X_OK, path=None):
"""Given a command, mode, and a PATH string, return the path which
conforms to the given mode on the PATH, or None if there is no such
file.
`mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result
of os.environ.get("PATH"), or can be overridden with a custom search
path.
Note: This function was backported from the Python 3 source code.
"""
# Check that a given file can be accessed with the correct mode.
# Additionally check that `file` is not a directory, as on Windows
# directories pass the os.access check.
def _access_check(fn, mode):
return os.path.exists(fn) and os.access(fn, mode) and not os.path.isdir(fn)
# If we're given a path with a directory part, look it up directly
# rather than referring to PATH directories. This includes checking
# relative to the current directory, e.g. ./script
if os.path.dirname(cmd):
if _access_check(cmd, mode):
return cmd
return None
if path is None:
path = os.environ.get("PATH", os.defpath)
if not path:
return None
path = path.split(os.pathsep)
if sys.platform == "win32":
# The current directory takes precedence on Windows.
if os.curdir not in path:
path.insert(0, os.curdir)
# PATHEXT is necessary to check on Windows.
pathext = os.environ.get("PATHEXT", "").split(os.pathsep)
# See if the given file matches any of the expected path
# extensions. This will allow us to short circuit when given
# "python.exe". If it does match, only test that one, otherwise we
# have to try others.
if any(cmd.lower().endswith(ext.lower()) for ext in pathext):
files = [cmd]
else:
files = [cmd + ext for ext in pathext]
else:
# On other platforms you don't have things like PATHEXT to tell you
# what file suffixes are executable, so just pass on cmd as-is.
files = [cmd]
seen = set()
for dir in path:
normdir = os.path.normcase(dir)
if normdir not in seen:
seen.add(normdir)
for thefile in files:
name = os.path.join(dir, thefile)
if _access_check(name, mode):
return name
return None

@ -399,7 +399,7 @@
hi: $(this).attr("data-hi"), hi: $(this).attr("data-hi"),
sonarrSeriesId: $(this).attr('data-sonarrSeriesId'), sonarrSeriesId: $(this).attr('data-sonarrSeriesId'),
sonarrEpisodeId: $(this).attr('data-sonarrEpisodeId'), sonarrEpisodeId: $(this).attr('data-sonarrEpisodeId'),
title: '{{!details[0].replace("'", "\\'")}}' title: "{{!details[0].replace("'", "\\'")}}"
}; };
$('#loader_text').text("Downloading subtitle to disk..."); $('#loader_text').text("Downloading subtitle to disk...");

@ -349,7 +349,7 @@
hi: $(this).attr("data-hi"), hi: $(this).attr("data-hi"),
radarrId: $(this).attr("data-radarrId"), radarrId: $(this).attr("data-radarrId"),
tmdbid: {{tmdbid}}, tmdbid: {{tmdbid}},
title: '{{!details[0].replace("'", "\\'")}}' title: "{{!details[0].replace("'", "\\'")}}"
}; };
$('#loader_text').text("Downloading subtitle to disk..."); $('#loader_text').text("Downloading subtitle to disk...");
@ -417,7 +417,7 @@
language: language, language: language,
hi: hi, hi: hi,
radarrId: radarrId, radarrId: radarrId,
title: '{{!details[0].replace("'", "\'")}}' title: "{{!details[0].replace("'", "\'")}}"
}; };
$('#search_result').DataTable( { $('#search_result').DataTable( {
@ -501,7 +501,7 @@
language: $(button).attr("data-language"), language: $(button).attr("data-language"),
hi: hi, hi: hi,
radarrId: radarrId, radarrId: radarrId,
title: '{{!details[0].replace("'", "\\'")}}' title: "{{!details[0].replace("'", "\\'")}}"
}; };
$('#loader_text').text("Downloading subtitle to disk..."); $('#loader_text').text("Downloading subtitle to disk...");

@ -1461,6 +1461,28 @@
</div> </div>
<div class="middle aligned row">
<div class="right aligned four wide column">
<label>Subs.sab.bz</label>
</div>
<div class="one wide column">
<div id="subssabbz" class="ui toggle checkbox provider">
<input type="checkbox">
<label></label>
</div>
</div>
<div class="collapsed column">
<div class="collapsed center aligned column">
<div class="ui basic icon" data-tooltip="Bulgarian mostly subtitle provider." data-inverted="">
<i class="help circle large icon"></i>
</div>
</div>
</div>
</div>
<div id="subssabbz_option" class="ui grid container">
</div>
<div class="middle aligned row"> <div class="middle aligned row">
<div class="right aligned four wide column"> <div class="right aligned four wide column">
<label>Subscene</label> <label>Subscene</label>
@ -1491,6 +1513,28 @@
</div> </div>
<div class="middle aligned row">
<div class="right aligned four wide column">
<label>Subsunacs.net</label>
</div>
<div class="one wide column">
<div id="subsunacs" class="ui toggle checkbox provider">
<input type="checkbox">
<label></label>
</div>
</div>
<div class="collapsed column">
<div class="collapsed center aligned column">
<div class="ui basic icon" data-tooltip="Bulgarian mostly subtitle provider." data-inverted="">
<i class="help circle large icon"></i>
</div>
</div>
</div>
</div>
<div id="subsunacs_option" class="ui grid container">
</div>
<div class="middle aligned row"> <div class="middle aligned row">
<div class="right aligned four wide column"> <div class="right aligned four wide column">
<label>Supersubtitles</label> <label>Supersubtitles</label>

Loading…
Cancel
Save