diff --git a/README.md b/README.md
index 03fe24a62..077eeecbf 100644
--- a/README.md
+++ b/README.md
@@ -45,8 +45,10 @@ If you need something that is not already part of Bazarr, feel free to create a
* Argenteam
* Assrt
* BetaSeries
+* BSPlayer
* GreekSubtitles
* Hosszupuska
+* LegendasDivx
* LegendasTV
* Napiprojekt
* Napisy24
diff --git a/bazarr.py b/bazarr.py
index ae5d88f13..f9228e2be 100644
--- a/bazarr.py
+++ b/bazarr.py
@@ -11,6 +11,7 @@ import os
import sys
import platform
import re
+import signal
from bazarr.get_args import args
@@ -39,15 +40,97 @@ check_python_version()
dir_name = os.path.dirname(__file__)
-def start_bazarr():
+class ProcessRegistry:
+
+ def register(self, process):
+ pass
+
+ def unregister(self, process):
+ pass
+
+
+class DaemonStatus(ProcessRegistry):
+
+ def __init__(self):
+ self.__should_stop = False
+ self.__processes = set()
+
+ def register(self, process):
+ self.__processes.add(process)
+
+ def unregister(self, process):
+ self.__processes.remove(process)
+
+ '''
+ Waits all the provided processes for the specified amount of time in seconds.
+ '''
+ @staticmethod
+ def __wait_for_processes(processes, timeout):
+ reference_ts = time.time()
+ elapsed = 0
+ remaining_processes = list(processes)
+ while elapsed < timeout and len(remaining_processes) > 0:
+ remaining_time = timeout - elapsed
+ for ep in list(remaining_processes):
+ if ep.poll() is not None:
+ remaining_processes.remove(ep)
+ else:
+ if remaining_time > 0:
+ if PY3:
+ try:
+ ep.wait(remaining_time)
+ remaining_processes.remove(ep)
+ except sp.TimeoutExpired:
+ pass
+ else:
+ '''
+ In python 2 there is no such thing as some mechanism to wait with a timeout.
+ '''
+ time.sleep(1)
+ elapsed = time.time() - reference_ts
+ remaining_time = timeout - elapsed
+ return remaining_processes
+
+ '''
+ Sends to every single of the specified processes the given signal and (if live_processes is not None) append to it processes which are still alive.
+ '''
+ @staticmethod
+ def __send_signal(processes, signal_no, live_processes=None):
+ for ep in processes:
+ if ep.poll() is None:
+ if live_processes is not None:
+ live_processes.append(ep)
+ try:
+ ep.send_signal(signal_no)
+ except Exception as e:
+ print('Failed sending signal %s to process %s because of an unexpected error: %s' % (signal_no, ep.pid, e))
+ return live_processes
+
+ '''
+ Flags this instance as should stop and terminates as smoothly as possible children processes.
+ '''
+ def stop(self):
+ self.__should_stop = True
+ live_processes = DaemonStatus.__send_signal(self.__processes, signal.SIGINT, list())
+ live_processes = DaemonStatus.__wait_for_processes(live_processes, 120)
+ DaemonStatus.__send_signal(live_processes, signal.SIGTERM)
+
+ def should_stop(self):
+ return self.__should_stop
+
+
+def start_bazarr(process_registry=ProcessRegistry()):
script = [sys.executable, "-u", os.path.normcase(os.path.join(dir_name, 'bazarr', 'main.py'))] + sys.argv[1:]
ep = sp.Popen(script, stdout=sp.PIPE, stderr=sp.STDOUT, stdin=sp.PIPE)
+ process_registry.register(ep)
print("Bazarr starting...")
try:
while True:
line = ep.stdout.readline()
if line == '' or not line:
+ # Process ended so let's unregister it
+ process_registry.unregister(ep)
break
if PY3:
sys.stdout.buffer.write(line)
@@ -73,7 +156,7 @@ if __name__ == '__main__':
pass
- def daemon():
+ def daemon(bazarr_runner = lambda: start_bazarr()):
if os.path.exists(stopfile):
try:
os.remove(stopfile)
@@ -89,12 +172,30 @@ if __name__ == '__main__':
except:
print('Unable to delete restart file.')
else:
- start_bazarr()
+ bazarr_runner()
- start_bazarr()
+ bazarr_runner = lambda: start_bazarr()
- # Keep the script running forever.
- while True:
- daemon()
+ should_stop = lambda: False
+
+ if PY3:
+ daemonStatus = DaemonStatus()
+
+ def shutdown():
+ # indicates that everything should stop
+ daemonStatus.stop()
+ # emulate a Ctrl C command on itself (bypasses the signal thing but, then, emulates the "Ctrl+C break")
+ os.kill(os.getpid(), signal.SIGINT)
+
+ signal.signal(signal.SIGTERM, lambda signal_no, frame: shutdown())
+
+ should_stop = lambda: daemonStatus.should_stop()
+ bazarr_runner = lambda: start_bazarr(daemonStatus)
+
+ bazarr_runner()
+
+ # Keep the script running forever until stop is requested through term or keyboard interrupt
+ while not should_stop():
+ daemon(bazarr_runner)
time.sleep(1)
diff --git a/bazarr/config.py b/bazarr/config.py
index ca61871e0..b64040ebf 100644
--- a/bazarr/config.py
+++ b/bazarr/config.py
@@ -102,6 +102,10 @@ defaults = {
'password': '',
'random_agents': 'True'
},
+ 'legendasdivx': {
+ 'username': '',
+ 'password': ''
+ },
'legendastv': {
'username': '',
'password': ''
diff --git a/bazarr/get_providers.py b/bazarr/get_providers.py
index 3e1507138..90f28a1f8 100644
--- a/bazarr/get_providers.py
+++ b/bazarr/get_providers.py
@@ -38,7 +38,7 @@ PROVIDER_THROTTLE_MAP = {
}
}
-PROVIDERS_FORCED_OFF = ["addic7ed", "tvsubtitles", "legendastv", "napiprojekt", "shooter", "hosszupuska",
+PROVIDERS_FORCED_OFF = ["addic7ed", "tvsubtitles", "legendasdivx", "legendastv", "napiprojekt", "shooter", "hosszupuska",
"supersubtitles", "titlovi", "titrari", "argenteam", "assrt", "subscene"]
throttle_count = {}
@@ -114,6 +114,9 @@ def get_providers_auth():
'password': settings.subscene.password,
'only_foreign': False, # fixme
},
+ 'legendasdivx': {'username': settings.legendasdivx.username,
+ 'password': settings.legendasdivx.password,
+ },
'legendastv': {'username': settings.legendastv.username,
'password': settings.legendastv.password,
},
diff --git a/bazarr/get_series.py b/bazarr/get_series.py
index c909dda09..d34a509b5 100644
--- a/bazarr/get_series.py
+++ b/bazarr/get_series.py
@@ -62,19 +62,21 @@ def update_series():
seriesListLength = len(r.json())
for i, show in enumerate(r.json(), 1):
notifications.write(msg="Getting series data from Sonarr...", queue='get_series', item=i, length=seriesListLength)
- try:
- overview = six.text_type(show['overview'])
- except:
- overview = ""
- try:
- poster_big = show['images'][2]['url'].split('?')[0]
- poster = os.path.splitext(poster_big)[0] + '-250' + os.path.splitext(poster_big)[1]
- except:
- poster = ""
- try:
- fanart = show['images'][0]['url'].split('?')[0]
- except:
- fanart = ""
+
+ if 'overview' in show:
+ overview = show['overview']
+ else:
+ overview = ''
+
+ poster = ''
+ fanart = ''
+ for image in show['images']:
+ if image['coverType'] == 'poster':
+ poster_big = image['url'].split('?')[0]
+ poster = os.path.splitext(poster_big)[0] + '-250' + os.path.splitext(poster_big)[1]
+
+ if image['coverType'] == 'fanart':
+ fanart = image['url'].split('?')[0]
if show['alternateTitles'] != None:
alternateTitles = str([item['title'] for item in show['alternateTitles']])
@@ -84,18 +86,18 @@ def update_series():
# Add shows in Sonarr to current shows list
current_shows_sonarr.append(show['id'])
- if show['tvdbId'] in current_shows_db_list:
- series_to_update.append({'title': six.text_type(show["title"]),
- 'path': six.text_type(show["path"]),
+ if show['id'] in current_shows_db_list:
+ series_to_update.append({'title': show["title"],
+ 'path': show["path"],
'tvdbId': int(show["tvdbId"]),
'sonarrSeriesId': int(show["id"]),
- 'overview': six.text_type(overview),
- 'poster': six.text_type(poster),
- 'fanart': six.text_type(fanart),
- 'audio_language': six.text_type(profile_id_to_language((show['qualityProfileId'] if get_sonarr_version().startswith('2') else show['languageProfileId']), audio_profiles)),
- 'sortTitle': six.text_type(show['sortTitle']),
- 'year': six.text_type(show['year']),
- 'alternateTitles': six.text_type(alternateTitles)})
+ 'overview': overview,
+ 'poster': poster,
+ 'fanart': fanart,
+ 'audio_language': profile_id_to_language((show['qualityProfileId'] if get_sonarr_version().startswith('2') else show['languageProfileId']), audio_profiles),
+ 'sortTitle': show['sortTitle'],
+ 'year': show['year'],
+ 'alternateTitles': alternateTitles})
else:
if serie_default_enabled is True:
series_to_add.append({'title': show["title"],
diff --git a/bazarr/get_subtitle.py b/bazarr/get_subtitle.py
index 81d2e8a6e..698afd853 100644
--- a/bazarr/get_subtitle.py
+++ b/bazarr/get_subtitle.py
@@ -40,6 +40,7 @@ from analytics import track_event
import six
from six.moves import range
from functools import reduce
+from locale import getpreferredencoding
def get_video(path, title, sceneName, use_scenename, providers=None, media_type="movie"):
@@ -234,34 +235,7 @@ def download_subtitle(path, language, hi, forced, providers, providers_auth, sce
command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language,
downloaded_language_code2, downloaded_language_code3,
subtitle.language.forced)
- try:
- if os.name == 'nt':
- codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- # wait for the process to terminate
- out_codepage, err_codepage = codepage.communicate()
- encoding = out_codepage.split(':')[-1].strip()
-
- process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- # wait for the process to terminate
- out, err = process.communicate()
-
- if os.name == 'nt':
- out = out.decode(encoding)
-
- except:
- if out == "":
- logging.error(
- 'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
- else:
- logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
- else:
- if out == "":
- logging.info(
- 'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
- else:
- logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)
+ postprocessing(command, path)
# fixme: support multiple languages at once
if media_type == 'series':
@@ -459,34 +433,7 @@ def manual_download_subtitle(path, language, hi, forced, subtitle, provider, pro
command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language,
downloaded_language_code2, downloaded_language_code3,
subtitle.language.forced)
- try:
- if os.name == 'nt':
- codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- # wait for the process to terminate
- out_codepage, err_codepage = codepage.communicate()
- encoding = out_codepage.split(':')[-1].strip()
-
- process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- # wait for the process to terminate
- out, err = process.communicate()
-
- if os.name == 'nt':
- out = out.decode(encoding)
-
- except:
- if out == "":
- logging.error(
- 'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
- else:
- logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
- else:
- if out == "":
- logging.info(
- 'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
- else:
- logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)
+ postprocessing(command, path)
if media_type == 'series':
reversed_path = path_replace_reverse(path)
@@ -1173,3 +1120,41 @@ def upgrade_subtitles():
store_subtitles_movie(movie['video_path'], path_replace_movie(movie['video_path']))
history_log_movie(3, movie['radarrId'], message, path, language_code, provider, score)
send_notifications_movie(movie['radarrId'], message)
+
+
+def postprocessing(command, path):
+ try:
+ encoding = getpreferredencoding()
+ if os.name == 'nt':
+ if six.PY3:
+ codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, encoding=getpreferredencoding())
+ else:
+ codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ # wait for the process to terminate
+ out_codepage, err_codepage = codepage.communicate()
+ encoding = out_codepage.split(':')[-1].strip()
+
+ if six.PY3:
+ process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, encoding=encoding)
+ else:
+ process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ # wait for the process to terminate
+ out, err = process.communicate()
+
+ if six.PY2:
+ out = out.decode(encoding)
+
+ out = out.replace('\n', ' ').replace('\r', ' ')
+
+ except Exception as e:
+ logging.error('BAZARR Post-processing failed for file ' + path + ' : ' + repr(e))
+ else:
+ if out == "":
+ logging.info(
+ 'BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
+ else:
+ logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)
diff --git a/bazarr/main.py b/bazarr/main.py
index 696bc6f68..2115e2976 100644
--- a/bazarr/main.py
+++ b/bazarr/main.py
@@ -1,6 +1,6 @@
# coding=utf-8
-bazarr_version = '0.8.4'
+bazarr_version = '0.8.4.1'
import os
os.environ["SZ_USER_AGENT"] = "Bazarr/1"
@@ -398,6 +398,8 @@ def save_wizard():
settings.addic7ed.password = request.forms.get('settings_addic7ed_password')
settings.addic7ed.random_agents = text_type(settings_addic7ed_random_agents)
settings.assrt.token = request.forms.get('settings_assrt_token')
+ settings.legendasdivx.username = request.forms.get('settings_legendasdivx_username')
+ settings.legendasdivx.password = request.forms.get('settings_legendasdivx_password')
settings.legendastv.username = request.forms.get('settings_legendastv_username')
settings.legendastv.password = request.forms.get('settings_legendastv_password')
settings.opensubtitles.username = request.forms.get('settings_opensubtitles_username')
@@ -1527,6 +1529,8 @@ def save_settings():
settings.addic7ed.password = request.forms.get('settings_addic7ed_password')
settings.addic7ed.random_agents = text_type(settings_addic7ed_random_agents)
settings.assrt.token = request.forms.get('settings_assrt_token')
+ settings.legendasdivx.username = request.forms.get('settings_legendasdivx_username')
+ settings.legendasdivx.password = request.forms.get('settings_legendasdivx_password')
settings.legendastv.username = request.forms.get('settings_legendastv_username')
settings.legendastv.password = request.forms.get('settings_legendastv_password')
settings.opensubtitles.username = request.forms.get('settings_opensubtitles_username')
@@ -1749,9 +1753,9 @@ def execute_task(taskid):
@custom_auth_basic(check_credentials)
def remove_subtitles():
authorize()
- episodePath = request.forms.get('episodePath')
+ episodePath = request.forms.episodePath
language = request.forms.get('language')
- subtitlesPath = request.forms.get('subtitlesPath')
+ subtitlesPath = request.forms.subtitlesPath
sonarrSeriesId = request.forms.get('sonarrSeriesId')
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
@@ -1768,9 +1772,9 @@ def remove_subtitles():
@custom_auth_basic(check_credentials)
def remove_subtitles_movie():
authorize()
- moviePath = request.forms.get('moviePath')
+ moviePath = request.forms.moviePath
language = request.forms.get('language')
- subtitlesPath = request.forms.get('subtitlesPath')
+ subtitlesPath = request.forms.subtitlesPath
radarrId = request.forms.get('radarrId')
try:
@@ -1788,14 +1792,14 @@ def get_subtitle():
authorize()
ref = request.environ['HTTP_REFERER']
- episodePath = request.forms.get('episodePath')
- sceneName = request.forms.get('sceneName')
+ episodePath = request.forms.episodePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
sonarrSeriesId = request.forms.get('sonarrSeriesId')
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
- title = request.forms.get('title')
+ title = request.forms.title
providers_list = get_providers()
providers_auth = get_providers_auth()
@@ -1823,12 +1827,12 @@ def get_subtitle():
def manual_search_json():
authorize()
- episodePath = request.forms.get('episodePath')
- sceneName = request.forms.get('sceneName')
+ episodePath = request.forms.episodePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
- title = request.forms.get('title')
+ title = request.forms.title
providers_list = get_providers()
providers_auth = get_providers_auth()
@@ -1843,16 +1847,16 @@ def manual_get_subtitle():
authorize()
ref = request.environ['HTTP_REFERER']
- episodePath = request.forms.get('episodePath')
- sceneName = request.forms.get('sceneName')
+ episodePath = request.forms.episodePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
selected_provider = request.forms.get('provider')
- subtitle = request.forms.get('subtitle')
+ subtitle = request.forms.subtitle
sonarrSeriesId = request.forms.get('sonarrSeriesId')
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
- title = request.forms.get('title')
+ title = request.forms.title
providers_auth = get_providers_auth()
@@ -1881,14 +1885,14 @@ def perform_manual_upload_subtitle():
authorize()
ref = request.environ['HTTP_REFERER']
- episodePath = request.forms.get('episodePath')
- sceneName = request.forms.get('sceneName')
+ episodePath = request.forms.episodePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
forced = True if request.forms.get('forced') == '1' else False
upload = request.files.get('upload')
sonarrSeriesId = request.forms.get('sonarrSeriesId')
sonarrEpisodeId = request.forms.get('sonarrEpisodeId')
- title = request.forms.get('title')
+ title = request.forms.title
_, ext = os.path.splitext(upload.filename)
@@ -1925,13 +1929,13 @@ def get_subtitle_movie():
authorize()
ref = request.environ['HTTP_REFERER']
- moviePath = request.forms.get('moviePath')
- sceneName = request.forms.get('sceneName')
+ moviePath = request.forms.moviePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
radarrId = request.forms.get('radarrId')
- title = request.forms.get('title')
+ title = request.forms.title
providers_list = get_providers()
providers_auth = get_providers_auth()
@@ -1959,12 +1963,12 @@ def get_subtitle_movie():
def manual_search_movie_json():
authorize()
- moviePath = request.forms.get('moviePath')
- sceneName = request.forms.get('sceneName')
+ moviePath = request.forms.moviePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
- title = request.forms.get('title')
+ title = request.forms.title
providers_list = get_providers()
providers_auth = get_providers_auth()
@@ -1979,15 +1983,15 @@ def manual_get_subtitle_movie():
authorize()
ref = request.environ['HTTP_REFERER']
- moviePath = request.forms.get('moviePath')
- sceneName = request.forms.get('sceneName')
+ moviePath = request.forms.moviePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
hi = request.forms.get('hi')
forced = request.forms.get('forced')
- selected_provider = request.forms.get('provider')
- subtitle = request.forms.get('subtitle')
+ selected_provider = request.forms.provider
+ subtitle = request.forms.subtitle
radarrId = request.forms.get('radarrId')
- title = request.forms.get('title')
+ title = request.forms.title
providers_auth = get_providers_auth()
@@ -2015,13 +2019,13 @@ def perform_manual_upload_subtitle_movie():
authorize()
ref = request.environ['HTTP_REFERER']
- moviePath = request.forms.get('moviePath')
- sceneName = request.forms.get('sceneName')
+ moviePath = request.forms.moviePath
+ sceneName = request.forms.sceneName
language = request.forms.get('language')
forced = True if request.forms.get('forced') == '1' else False
upload = request.files.get('upload')
radarrId = request.forms.get('radarrId')
- title = request.forms.get('title')
+ title = request.forms.title
_, ext = os.path.splitext(upload.filename)
diff --git a/libs/subliminal_patch/core.py b/libs/subliminal_patch/core.py
index d4685c289..38a603eed 100644
--- a/libs/subliminal_patch/core.py
+++ b/libs/subliminal_patch/core.py
@@ -543,6 +543,10 @@ def scan_video(path, dont_use_actual_file=False, hints=None, providers=None, ski
if video.size > 10485760:
logger.debug('Size is %d', video.size)
osub_hash = None
+
+ if "bsplayer" in providers:
+ video.hashes['bsplayer'] = osub_hash = hash_opensubtitles(hash_path)
+
if "opensubtitles" in providers:
video.hashes['opensubtitles'] = osub_hash = hash_opensubtitles(hash_path)
diff --git a/libs/subliminal_patch/providers/bsplayer.py b/libs/subliminal_patch/providers/bsplayer.py
new file mode 100644
index 000000000..9839a0331
--- /dev/null
+++ b/libs/subliminal_patch/providers/bsplayer.py
@@ -0,0 +1,235 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import logging
+import io
+import os
+
+from requests import Session
+from guessit import guessit
+from subliminal_patch.providers import Provider
+from subliminal_patch.subtitle import Subtitle
+from subliminal.utils import sanitize_release_group
+from subliminal.subtitle import guess_matches
+from subzero.language import Language
+
+import gzip
+import random
+from time import sleep
+from xml.etree import ElementTree
+
+logger = logging.getLogger(__name__)
+
+class BSPlayerSubtitle(Subtitle):
+ """BSPlayer Subtitle."""
+ provider_name = 'bsplayer'
+
+ def __init__(self, language, filename, subtype, video, link):
+ super(BSPlayerSubtitle, self).__init__(language)
+ self.language = language
+ self.filename = filename
+ self.page_link = link
+ self.subtype = subtype
+ self.video = video
+
+ @property
+ def id(self):
+ return self.page_link
+
+ @property
+ def release_info(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)
+
+
+ matches |= guess_matches(video, guessit(self.filename))
+
+ matches.add(id(self))
+ matches.add('hash')
+
+ return matches
+
+
+
+class BSPlayerProvider(Provider):
+ """BSPlayer Provider."""
+ languages = {Language('por', 'BR')} | {Language(l) for l in [
+ 'ara', 'bul', 'ces', 'dan', 'deu', 'ell', 'eng', 'fin', 'fra', 'hun', 'ita', 'jpn', 'kor', 'nld', 'pol', 'por',
+ 'ron', 'rus', 'spa', 'swe', 'tur', 'ukr', 'zho'
+ ]}
+ SEARCH_THROTTLE = 8
+
+ # batantly based on kodi's bsplayer plugin
+ # also took from BSPlayer-Subtitles-Downloader
+ def __init__(self):
+ self.initialize()
+
+ def initialize(self):
+ self.session = Session()
+ self.search_url = self.get_sub_domain()
+ self.token = None
+ self.login()
+
+ def terminate(self):
+ self.session.close()
+ self.logout()
+
+ def api_request(self, func_name='logIn', params='', tries=5):
+ headers = {
+ 'User-Agent': 'BSPlayer/2.x (1022.12360)',
+ 'Content-Type': 'text/xml; charset=utf-8',
+ 'Connection': 'close',
+ 'SOAPAction': '"http://api.bsplayer-subtitles.com/v1.php#{func_name}"'.format(func_name=func_name)
+ }
+ data = (
+ '\n'
+ '