mirror of https://github.com/morpheus65535/bazarr
Merge development into master
This commit is contained in:
commit
87bc9ecd29
|
@ -23,6 +23,6 @@ done
|
|||
cp VERSION $to_dist
|
||||
|
||||
pushd __builds__/bazarr
|
||||
zip -r ../bazarr.zip . -x '*.map' -b $(mktemp -d)
|
||||
zip -r ../bazarr.zip . -b $(mktemp -d)
|
||||
popd
|
||||
rm -rf $to_dist
|
|
@ -12,10 +12,10 @@ from pyga.entities import CustomVariable
|
|||
|
||||
from get_args import args
|
||||
from config import settings
|
||||
from utils import get_sonarr_version, get_radarr_version
|
||||
from utils import get_sonarr_info, get_radarr_info
|
||||
|
||||
sonarr_version = get_sonarr_version()
|
||||
radarr_version = get_radarr_version()
|
||||
sonarr_version = get_sonarr_info.version()
|
||||
radarr_version = get_radarr_info.version()
|
||||
|
||||
|
||||
def track_event(category=None, action=None, label=None):
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# coding=utf-8
|
||||
|
||||
import sys
|
||||
import os
|
||||
import ast
|
||||
from datetime import timedelta
|
||||
from dateutil import rrule
|
||||
|
@ -15,6 +17,8 @@ import hashlib
|
|||
import apprise
|
||||
import gc
|
||||
from peewee import fn, Value
|
||||
import requests
|
||||
from bs4 import BeautifulSoup as bso
|
||||
|
||||
from get_args import args
|
||||
from config import settings, base_url, save_settings, get_settings
|
||||
|
@ -35,7 +39,7 @@ from notifier import send_notifications, send_notifications_movie
|
|||
from list_subtitles import store_subtitles, store_subtitles_movie, series_scan_subtitles, movies_scan_subtitles, \
|
||||
list_missing_subtitles, list_missing_subtitles_movies
|
||||
from utils import history_log, history_log_movie, blacklist_log, blacklist_delete, blacklist_delete_all, \
|
||||
blacklist_log_movie, blacklist_delete_movie, blacklist_delete_all_movie, get_sonarr_version, get_radarr_version, \
|
||||
blacklist_log_movie, blacklist_delete_movie, blacklist_delete_all_movie, get_sonarr_info, get_radarr_info, \
|
||||
delete_subtitles, subtitles_apply_mods, translate_subtitles_file, check_credentials, get_health_issues
|
||||
from get_providers import get_providers, get_providers_auth, list_throttled_providers, reset_throttled_providers, \
|
||||
get_throttled_providers, set_throttled_providers
|
||||
|
@ -596,8 +600,8 @@ class SystemStatus(Resource):
|
|||
def get(self):
|
||||
system_status = {}
|
||||
system_status.update({'bazarr_version': os.environ["BAZARR_VERSION"]})
|
||||
system_status.update({'sonarr_version': get_sonarr_version()})
|
||||
system_status.update({'radarr_version': get_radarr_version()})
|
||||
system_status.update({'sonarr_version': get_sonarr_info.version()})
|
||||
system_status.update({'radarr_version': get_radarr_info.version()})
|
||||
system_status.update({'operating_system': platform.platform()})
|
||||
system_status.update({'python_version': platform.python_version()})
|
||||
system_status.update({'bazarr_directory': os.path.dirname(os.path.dirname(__file__))})
|
||||
|
@ -716,6 +720,15 @@ class Series(Resource):
|
|||
list_missing_subtitles(no=seriesId, send_event=False)
|
||||
|
||||
event_stream(type='series', payload=seriesId)
|
||||
|
||||
episode_id_list = TableEpisodes\
|
||||
.select(TableEpisodes.sonarrEpisodeId)\
|
||||
.where(TableEpisodes.sonarrSeriesId == seriesId)\
|
||||
.dicts()
|
||||
|
||||
for item in episode_id_list:
|
||||
event_stream(type='episode-wanted', payload=item['sonarrEpisodeId'])
|
||||
|
||||
event_stream(type='badges')
|
||||
|
||||
return '', 204
|
||||
|
@ -963,6 +976,7 @@ class Movies(Resource):
|
|||
list_missing_subtitles_movies(no=radarrId, send_event=False)
|
||||
|
||||
event_stream(type='movie', payload=radarrId)
|
||||
event_stream(type='movie-wanted', payload=radarrId)
|
||||
event_stream(type='badges')
|
||||
|
||||
return '', 204
|
||||
|
@ -1516,7 +1530,7 @@ class MoviesHistory(Resource):
|
|||
if int(upgradable_movie['score']) < 120:
|
||||
upgradable_movies_not_perfect.append(upgradable_movie)
|
||||
|
||||
query_conditions = [(TableMovies is not None)]
|
||||
query_conditions = [(TableMovies.title is not None)]
|
||||
if radarrid:
|
||||
query_conditions.append((TableMovies.radarrId == radarrid))
|
||||
query_condition = reduce(operator.and_, query_conditions)
|
||||
|
@ -1696,6 +1710,7 @@ class EpisodesWanted(Resource):
|
|||
TableShows.seriesType)\
|
||||
.join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\
|
||||
.where(wanted_condition)\
|
||||
.order_by(TableEpisodes.rowid.desc())\
|
||||
.limit(length)\
|
||||
.offset(start)\
|
||||
.dicts()
|
||||
|
@ -1749,7 +1764,7 @@ class MoviesWanted(Resource):
|
|||
TableMovies.tags,
|
||||
TableMovies.monitored)\
|
||||
.where(wanted_condition)\
|
||||
.order_by(TableMovies.radarrId.desc())\
|
||||
.order_by(TableMovies.rowid.desc())\
|
||||
.limit(length)\
|
||||
.offset(start)\
|
||||
.dicts()
|
||||
|
@ -1966,6 +1981,12 @@ class Subtitles(Resource):
|
|||
else:
|
||||
subtitles_apply_mods(language, subtitles_path, [action])
|
||||
|
||||
# apply chmod if required
|
||||
chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
|
||||
'win') and settings.general.getboolean('chmod_enabled') else None
|
||||
if chmod:
|
||||
os.chmod(subtitles_path, chmod)
|
||||
|
||||
return '', 204
|
||||
|
||||
|
||||
|
@ -2045,6 +2066,68 @@ class BrowseRadarrFS(Resource):
|
|||
return jsonify(data)
|
||||
|
||||
|
||||
class WebHooksPlex(Resource):
|
||||
@authenticate
|
||||
def post(self):
|
||||
json_webhook = request.form.get('payload')
|
||||
parsed_json_webhook = json.loads(json_webhook)
|
||||
|
||||
event = parsed_json_webhook['event']
|
||||
if event not in ['media.play']:
|
||||
return '', 204
|
||||
|
||||
media_type = parsed_json_webhook['Metadata']['type']
|
||||
|
||||
if media_type == 'episode':
|
||||
season = parsed_json_webhook['Metadata']['parentIndex']
|
||||
episode = parsed_json_webhook['Metadata']['index']
|
||||
else:
|
||||
season = episode = None
|
||||
|
||||
ids = []
|
||||
for item in parsed_json_webhook['Metadata']['Guid']:
|
||||
splitted_id = item['id'].split('://')
|
||||
if len(splitted_id) == 2:
|
||||
ids.append({splitted_id[0]: splitted_id[1]})
|
||||
if not ids:
|
||||
return '', 404
|
||||
|
||||
if media_type == 'episode':
|
||||
try:
|
||||
episode_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0]
|
||||
r = requests.get('https://imdb.com/title/{}'.format(episode_imdb_id),
|
||||
headers={"User-Agent": os.environ["SZ_USER_AGENT"]})
|
||||
soup = bso(r.content, "html.parser")
|
||||
series_imdb_id = soup.find('a', {'class': re.compile(r'SeriesParentLink__ParentTextLink')})['href'].split('/')[2]
|
||||
except:
|
||||
return '', 404
|
||||
else:
|
||||
sonarrEpisodeId = TableEpisodes.select(TableEpisodes.sonarrEpisodeId) \
|
||||
.join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId)) \
|
||||
.where(TableShows.imdbId == series_imdb_id,
|
||||
TableEpisodes.season == season,
|
||||
TableEpisodes.episode == episode) \
|
||||
.dicts() \
|
||||
.get()
|
||||
|
||||
if sonarrEpisodeId:
|
||||
episode_download_subtitles(no=sonarrEpisodeId['sonarrEpisodeId'], send_progress=True)
|
||||
else:
|
||||
try:
|
||||
movie_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0]
|
||||
except:
|
||||
return '', 404
|
||||
else:
|
||||
radarrId = TableMovies.select(TableMovies.radarrId)\
|
||||
.where(TableMovies.imdbId == movie_imdb_id)\
|
||||
.dicts()\
|
||||
.get()
|
||||
if radarrId:
|
||||
movies_download_subtitles(no=radarrId['radarrId'])
|
||||
|
||||
return '', 200
|
||||
|
||||
|
||||
api.add_resource(Badges, '/badges')
|
||||
|
||||
api.add_resource(Providers, '/providers')
|
||||
|
@ -2086,3 +2169,5 @@ api.add_resource(HistoryStats, '/history/stats')
|
|||
api.add_resource(BrowseBazarrFS, '/files')
|
||||
api.add_resource(BrowseSonarrFS, '/files/sonarr')
|
||||
api.add_resource(BrowseRadarrFS, '/files/radarr')
|
||||
|
||||
api.add_resource(WebHooksPlex, '/webhooks/plex')
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# coding=utf-8
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import re
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
|
@ -19,13 +21,13 @@ def check_releases():
|
|||
logging.debug('BAZARR getting releases from Github: {}'.format(url_releases))
|
||||
r = requests.get(url_releases, allow_redirects=True)
|
||||
r.raise_for_status()
|
||||
except requests.exceptions.HTTPError as errh:
|
||||
except requests.exceptions.HTTPError:
|
||||
logging.exception("Error trying to get releases from Github. Http error.")
|
||||
except requests.exceptions.ConnectionError as errc:
|
||||
except requests.exceptions.ConnectionError:
|
||||
logging.exception("Error trying to get releases from Github. Connection Error.")
|
||||
except requests.exceptions.Timeout as errt:
|
||||
except requests.exceptions.Timeout:
|
||||
logging.exception("Error trying to get releases from Github. Timeout Error.")
|
||||
except requests.exceptions.RequestException as err:
|
||||
except requests.exceptions.RequestException:
|
||||
logging.exception("Error trying to get releases from Github.")
|
||||
else:
|
||||
for release in r.json():
|
||||
|
@ -151,6 +153,14 @@ def apply_update():
|
|||
logging.exception('BAZARR unable to unzip release')
|
||||
else:
|
||||
is_updated = True
|
||||
try:
|
||||
logging.debug('BAZARR successfully unzipped new release and will now try to delete the leftover '
|
||||
'files.')
|
||||
update_cleaner(zipfile=bazarr_zip, bazarr_dir=bazarr_dir, config_dir=args.config_dir)
|
||||
except:
|
||||
logging.exception('BAZARR unable to cleanup leftover files after upgrade.')
|
||||
else:
|
||||
logging.debug('BAZARR successfully deleted leftover files.')
|
||||
finally:
|
||||
logging.debug('BAZARR now deleting release archive')
|
||||
os.remove(bazarr_zip)
|
||||
|
@ -161,3 +171,76 @@ def apply_update():
|
|||
logging.debug('BAZARR new release have been installed, now we restart')
|
||||
from server import webserver
|
||||
webserver.restart()
|
||||
|
||||
|
||||
def update_cleaner(zipfile, bazarr_dir, config_dir):
|
||||
with ZipFile(zipfile, 'r') as archive:
|
||||
file_in_zip = archive.namelist()
|
||||
logging.debug('BAZARR zip file contain {} directories and files'.format(len(file_in_zip)))
|
||||
separator = os.path.sep
|
||||
if os.path.sep == '\\':
|
||||
logging.debug('BAZARR upgrade leftover cleaner is running on Windows. We\'ll fix the zip file separator '
|
||||
'accordingly.')
|
||||
for i, item in enumerate(file_in_zip):
|
||||
file_in_zip[i] = item.replace('/', '\\')
|
||||
separator += os.path.sep
|
||||
else:
|
||||
logging.debug('BAZARR upgrade leftover cleaner is running on something else than Windows. The zip file '
|
||||
'separator are fine.')
|
||||
|
||||
dir_to_ignore = ['^.' + separator,
|
||||
'^bin' + separator,
|
||||
'^venv' + separator,
|
||||
'^WinPython' + separator,
|
||||
separator + '__pycache__' + separator + '$']
|
||||
if os.path.abspath(bazarr_dir) in os.path.abspath(config_dir):
|
||||
dir_to_ignore.append('^' + os.path.relpath(config_dir, bazarr_dir) + os.path.sep)
|
||||
dir_to_ignore_regex = re.compile('(?:% s)' % '|'.join(dir_to_ignore))
|
||||
logging.debug('BAZARR upgrade leftover cleaner will ignore directories matching this regex: '
|
||||
'{}'.format(dir_to_ignore_regex))
|
||||
|
||||
file_to_ignore = ['nssm.exe', '7za.exe']
|
||||
logging.debug('BAZARR upgrade leftover cleaner will ignore those files: {}'.format(', '.join(file_to_ignore)))
|
||||
extension_to_ignore = ['.pyc']
|
||||
logging.debug('BAZARR upgrade leftover cleaner will ignore files with those extensions: '
|
||||
'{}'.format(', '.join(extension_to_ignore)))
|
||||
|
||||
file_on_disk = []
|
||||
folder_list = []
|
||||
for foldername, subfolders, filenames in os.walk(bazarr_dir):
|
||||
relative_foldername = os.path.relpath(foldername, bazarr_dir) + os.path.sep
|
||||
|
||||
if not dir_to_ignore_regex.findall(relative_foldername):
|
||||
if relative_foldername not in folder_list:
|
||||
folder_list.append(relative_foldername)
|
||||
|
||||
for file in filenames:
|
||||
if file in file_to_ignore:
|
||||
continue
|
||||
elif os.path.splitext(file)[1] in extension_to_ignore:
|
||||
continue
|
||||
elif foldername == bazarr_dir:
|
||||
file_on_disk.append(file)
|
||||
else:
|
||||
current_dir = relative_foldername
|
||||
filepath = os.path.join(current_dir, file)
|
||||
if not dir_to_ignore_regex.findall(filepath):
|
||||
file_on_disk.append(filepath)
|
||||
logging.debug('BAZARR directory contain {} files'.format(len(file_on_disk)))
|
||||
logging.debug('BAZARR directory contain {} directories'.format(len(folder_list)))
|
||||
file_on_disk += folder_list
|
||||
logging.debug('BAZARR directory contain {} directories and files'.format(len(file_on_disk)))
|
||||
|
||||
file_to_remove = list(set(file_on_disk) - set(file_in_zip))
|
||||
logging.debug('BAZARR will delete {} directories and files'.format(len(file_to_remove)))
|
||||
logging.debug('BAZARR will delete this: {}'.format(', '.join(file_to_remove)))
|
||||
|
||||
for file in file_to_remove:
|
||||
filepath = os.path.join(bazarr_dir, file)
|
||||
try:
|
||||
if os.path.isdir(filepath):
|
||||
rmtree(filepath, ignore_errors=True)
|
||||
else:
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
logging.debug('BAZARR upgrade leftover cleaner cannot delete {}'.format(filepath))
|
||||
|
|
|
@ -139,7 +139,8 @@ defaults = {
|
|||
},
|
||||
'legendastv': {
|
||||
'username': '',
|
||||
'password': ''
|
||||
'password': '',
|
||||
'featured_only': 'False'
|
||||
},
|
||||
'xsubs': {
|
||||
'username': '',
|
||||
|
@ -317,7 +318,7 @@ def save_settings(settings_items):
|
|||
# Make sure that text based form values aren't pass as list
|
||||
if isinstance(value, list) and len(value) == 1 and settings_keys[-1] not in array_keys:
|
||||
value = value[0]
|
||||
if value in empty_values:
|
||||
if value in empty_values and value != '':
|
||||
value = None
|
||||
|
||||
# Make sure empty language list are stored correctly
|
||||
|
@ -442,11 +443,17 @@ def save_settings(settings_items):
|
|||
|
||||
if sonarr_changed:
|
||||
from signalr_client import sonarr_signalr_client
|
||||
sonarr_signalr_client.restart()
|
||||
try:
|
||||
sonarr_signalr_client.restart()
|
||||
except:
|
||||
pass
|
||||
|
||||
if radarr_changed:
|
||||
from signalr_client import radarr_signalr_client
|
||||
radarr_signalr_client.restart()
|
||||
try:
|
||||
radarr_signalr_client.restart()
|
||||
except:
|
||||
pass
|
||||
|
||||
if update_path_map:
|
||||
from helper import path_mappings
|
||||
|
|
|
@ -8,6 +8,7 @@ from peewee import *
|
|||
from playhouse.sqliteq import SqliteQueueDatabase
|
||||
from playhouse.shortcuts import model_to_dict
|
||||
from playhouse.migrate import *
|
||||
from playhouse.sqlite_ext import RowIDField
|
||||
|
||||
from helper import path_mappings
|
||||
from config import settings, get_array_from
|
||||
|
@ -69,6 +70,7 @@ class TableBlacklistMovie(BaseModel):
|
|||
|
||||
|
||||
class TableEpisodes(BaseModel):
|
||||
rowid = RowIDField()
|
||||
audio_codec = TextField(null=True)
|
||||
audio_language = TextField(null=True)
|
||||
episode = IntegerField()
|
||||
|
@ -140,6 +142,7 @@ class TableLanguagesProfiles(BaseModel):
|
|||
|
||||
|
||||
class TableMovies(BaseModel):
|
||||
rowid = RowIDField()
|
||||
alternativeTitles = TextField(null=True)
|
||||
audio_codec = TextField(null=True)
|
||||
audio_language = TextField(null=True)
|
||||
|
@ -163,7 +166,7 @@ class TableMovies(BaseModel):
|
|||
subtitles = TextField(null=True)
|
||||
tags = TextField(null=True)
|
||||
title = TextField()
|
||||
tmdbId = TextField(primary_key=True)
|
||||
tmdbId = TextField(unique=True)
|
||||
video_codec = TextField(null=True)
|
||||
year = TextField(null=True)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import logging
|
|||
import string
|
||||
|
||||
from config import settings, url_sonarr, url_radarr
|
||||
from utils import get_sonarr_version, get_radarr_version
|
||||
from utils import get_sonarr_info, get_radarr_info
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -46,10 +46,9 @@ def browse_bazarr_filesystem(path='#'):
|
|||
|
||||
|
||||
def browse_sonarr_filesystem(path='#'):
|
||||
sonarr_version = get_sonarr_version()
|
||||
if path == '#':
|
||||
path = ''
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url_sonarr_api_filesystem = url_sonarr() + "/api/filesystem?path=" + path + \
|
||||
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
|
||||
settings.sonarr.apikey
|
||||
|
@ -77,11 +76,10 @@ def browse_sonarr_filesystem(path='#'):
|
|||
|
||||
|
||||
def browse_radarr_filesystem(path='#'):
|
||||
radarr_version = get_radarr_version()
|
||||
if path == '#':
|
||||
path = ''
|
||||
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_radarr_api_filesystem = url_radarr() + "/api/filesystem?path=" + path + \
|
||||
"&allowFoldersWithoutTrailingSlashes=true&includeFiles=false&apikey=" + \
|
||||
settings.radarr.apikey
|
||||
|
|
|
@ -12,7 +12,7 @@ from helper import path_mappings
|
|||
from list_subtitles import store_subtitles, series_full_scan_subtitles
|
||||
from get_subtitle import episode_download_subtitles
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
from utils import get_sonarr_version
|
||||
from utils import get_sonarr_info
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -25,7 +25,6 @@ def update_all_episodes():
|
|||
def sync_episodes(series_id=None, send_event=True):
|
||||
logging.debug('BAZARR Starting episodes sync from Sonarr.')
|
||||
apikey_sonarr = settings.sonarr.apikey
|
||||
sonarr_version = get_sonarr_version()
|
||||
|
||||
# Get current episodes id in DB
|
||||
current_episodes_db = TableEpisodes.select(TableEpisodes.sonarrEpisodeId,
|
||||
|
@ -42,8 +41,7 @@ def sync_episodes(series_id=None, send_event=True):
|
|||
altered_episodes = []
|
||||
|
||||
# Get sonarrId for each series from database
|
||||
seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr,
|
||||
sonarr_version=sonarr_version)
|
||||
seriesIdList = get_series_from_sonarr_api(series_id=series_id, url=url_sonarr(), apikey_sonarr=apikey_sonarr,)
|
||||
|
||||
series_count = len(seriesIdList)
|
||||
for i, seriesId in enumerate(seriesIdList, 1):
|
||||
|
@ -57,13 +55,12 @@ def sync_episodes(series_id=None, send_event=True):
|
|||
|
||||
# Get episodes data for a series from Sonarr
|
||||
episodes = get_episodes_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
|
||||
series_id=seriesId['sonarrSeriesId'],
|
||||
sonarr_version=sonarr_version)
|
||||
series_id=seriesId['sonarrSeriesId'])
|
||||
if not episodes:
|
||||
continue
|
||||
else:
|
||||
# For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results
|
||||
if sonarr_version.startswith('3'):
|
||||
if not get_sonarr_info.is_legacy():
|
||||
episodeFiles = get_episodesFiles_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
|
||||
series_id=seriesId['sonarrSeriesId'])
|
||||
for episode in episodes:
|
||||
|
@ -166,7 +163,6 @@ def sync_one_episode(episode_id):
|
|||
logging.debug('BAZARR syncing this specific episode from Sonarr: {}'.format(episode_id))
|
||||
url = url_sonarr()
|
||||
apikey_sonarr = settings.sonarr.apikey
|
||||
sonarr_version = get_sonarr_version()
|
||||
|
||||
# Check if there's a row in database for this episode ID
|
||||
try:
|
||||
|
@ -181,13 +177,13 @@ def sync_one_episode(episode_id):
|
|||
# Get episode data from sonarr api
|
||||
episode = None
|
||||
episode_data = get_episodes_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr,
|
||||
episode_id=episode_id, sonarr_version=sonarr_version)
|
||||
episode_id=episode_id)
|
||||
if not episode_data:
|
||||
return
|
||||
|
||||
else:
|
||||
# For Sonarr v3, we need to update episodes to integrate the episodeFile API endpoint results
|
||||
if sonarr_version.startswith('3'):
|
||||
if not get_sonarr_info.is_legacy():
|
||||
episodeFile = get_episodesFiles_from_sonarr_api(url=url, apikey_sonarr=apikey_sonarr,
|
||||
episode_file_id=existing_episode['episode_file_id'])
|
||||
if episode_data['hasFile']:
|
||||
|
@ -292,7 +288,7 @@ def episodeParser(episode):
|
|||
if 'name' in item:
|
||||
audio_language.append(item['name'])
|
||||
else:
|
||||
audio_language = TableShows.get(TableShows == episode['seriesId']).audio_language
|
||||
audio_language = TableShows.get(TableShows.sonarrSeriesId == episode['seriesId']).audio_language
|
||||
|
||||
if 'mediaInfo' in episode['episodeFile']:
|
||||
if 'videoCodec' in episode['episodeFile']['mediaInfo']:
|
||||
|
@ -336,13 +332,13 @@ def episodeParser(episode):
|
|||
'file_size': episode['episodeFile']['size']}
|
||||
|
||||
|
||||
def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version):
|
||||
def get_series_from_sonarr_api(series_id, url, apikey_sonarr):
|
||||
if series_id:
|
||||
url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format(
|
||||
'' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr)
|
||||
'' if get_sonarr_info.is_legacy() else 'v3/', series_id, apikey_sonarr)
|
||||
else:
|
||||
url_sonarr_api_series = url + "/api/{0}series?apikey={1}".format(
|
||||
'' if sonarr_version.startswith('2') else 'v3/', apikey_sonarr)
|
||||
'' if get_sonarr_info.is_legacy() else 'v3/', apikey_sonarr)
|
||||
try:
|
||||
r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers)
|
||||
r.raise_for_status()
|
||||
|
@ -372,13 +368,13 @@ def get_series_from_sonarr_api(series_id, url, apikey_sonarr, sonarr_version):
|
|||
return series_list
|
||||
|
||||
|
||||
def get_episodes_from_sonarr_api(url, apikey_sonarr, sonarr_version, series_id=None, episode_id=None):
|
||||
def get_episodes_from_sonarr_api(url, apikey_sonarr, series_id=None, episode_id=None):
|
||||
if series_id:
|
||||
url_sonarr_api_episode = url + "/api/{0}episode?seriesId={1}&apikey={2}".format(
|
||||
'' if sonarr_version.startswith('2') else 'v3/', series_id, apikey_sonarr)
|
||||
'' if get_sonarr_info.is_legacy() else 'v3/', series_id, apikey_sonarr)
|
||||
elif episode_id:
|
||||
url_sonarr_api_episode = url + "/api/{0}episode/{1}?apikey={2}".format(
|
||||
'' if sonarr_version.startswith('2') else 'v3/', episode_id, apikey_sonarr)
|
||||
'' if get_sonarr_info.is_legacy() else 'v3/', episode_id, apikey_sonarr)
|
||||
else:
|
||||
return
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ from peewee import DoesNotExist
|
|||
|
||||
from config import settings, url_radarr
|
||||
from helper import path_mappings
|
||||
from utils import get_radarr_version
|
||||
from utils import get_radarr_info
|
||||
from list_subtitles import store_subtitles_movie, movies_full_scan_subtitles
|
||||
from get_rootfolder import check_radarr_rootfolder
|
||||
|
||||
|
@ -31,7 +31,6 @@ def update_movies(send_event=True):
|
|||
logging.debug('BAZARR Starting movie sync from Radarr.')
|
||||
apikey_radarr = settings.radarr.apikey
|
||||
|
||||
radarr_version = get_radarr_version()
|
||||
movie_default_enabled = settings.general.getboolean('movie_default_enabled')
|
||||
|
||||
if movie_default_enabled is True:
|
||||
|
@ -45,11 +44,10 @@ def update_movies(send_event=True):
|
|||
pass
|
||||
else:
|
||||
audio_profiles = get_profile_list()
|
||||
tagsDict = get_tags(radarr_version=radarr_version)
|
||||
tagsDict = get_tags()
|
||||
|
||||
# Get movies data from radarr
|
||||
movies = get_movies_from_radarr_api(radarr_version=radarr_version, url=url_radarr(),
|
||||
apikey_radarr=apikey_radarr)
|
||||
movies = get_movies_from_radarr_api(url=url_radarr(), apikey_radarr=apikey_radarr)
|
||||
if not movies:
|
||||
return
|
||||
else:
|
||||
|
@ -82,13 +80,11 @@ def update_movies(send_event=True):
|
|||
|
||||
if str(movie['tmdbId']) in current_movies_db_list:
|
||||
movies_to_update.append(movieParser(movie, action='update',
|
||||
radarr_version=radarr_version,
|
||||
tags_dict=tagsDict,
|
||||
movie_default_profile=movie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
else:
|
||||
movies_to_add.append(movieParser(movie, action='insert',
|
||||
radarr_version=radarr_version,
|
||||
tags_dict=tagsDict,
|
||||
movie_default_profile=movie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
|
@ -190,7 +186,6 @@ def update_one_movie(movie_id, action):
|
|||
existing_movie['path'])))
|
||||
return
|
||||
|
||||
radarr_version = get_radarr_version()
|
||||
movie_default_enabled = settings.general.getboolean('movie_default_enabled')
|
||||
|
||||
if movie_default_enabled is True:
|
||||
|
@ -201,24 +196,22 @@ def update_one_movie(movie_id, action):
|
|||
movie_default_profile = None
|
||||
|
||||
audio_profiles = get_profile_list()
|
||||
tagsDict = get_tags(radarr_version=radarr_version)
|
||||
tagsDict = get_tags()
|
||||
|
||||
try:
|
||||
# Get movie data from radarr api
|
||||
movie = None
|
||||
movie_data = get_movies_from_radarr_api(radarr_version=radarr_version, url=url_radarr(),
|
||||
apikey_radarr=settings.radarr.apikey, radarr_id=movie_id)
|
||||
movie_data = get_movies_from_radarr_api(url=url_radarr(), apikey_radarr=settings.radarr.apikey,
|
||||
radarr_id=movie_id)
|
||||
if not movie_data:
|
||||
return
|
||||
else:
|
||||
if action == 'updated' and existing_movie:
|
||||
movie = movieParser(movie_data, action='update', radarr_version=radarr_version,
|
||||
tags_dict=tagsDict, movie_default_profile=movie_default_profile,
|
||||
audio_profiles=audio_profiles)
|
||||
movie = movieParser(movie_data, action='update', tags_dict=tagsDict,
|
||||
movie_default_profile=movie_default_profile, audio_profiles=audio_profiles)
|
||||
elif action == 'updated' and not existing_movie:
|
||||
movie = movieParser(movie_data, action='insert', radarr_version=radarr_version,
|
||||
tags_dict=tagsDict, movie_default_profile=movie_default_profile,
|
||||
audio_profiles=audio_profiles)
|
||||
movie = movieParser(movie_data, action='insert', tags_dict=tagsDict,
|
||||
movie_default_profile=movie_default_profile, audio_profiles=audio_profiles)
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot get movie returned by SignalR feed from Radarr API.')
|
||||
return
|
||||
|
@ -262,10 +255,9 @@ def update_one_movie(movie_id, action):
|
|||
|
||||
def get_profile_list():
|
||||
apikey_radarr = settings.radarr.apikey
|
||||
radarr_version = get_radarr_version()
|
||||
profiles_list = []
|
||||
# Get profiles data from radarr
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_radarr_api_movies = url_radarr() + "/api/profile?apikey=" + apikey_radarr
|
||||
else:
|
||||
url_radarr_api_movies = url_radarr() + "/api/v3/qualityprofile?apikey=" + apikey_radarr
|
||||
|
@ -280,7 +272,7 @@ def get_profile_list():
|
|||
logging.exception("BAZARR Error trying to get profiles from Radarr.")
|
||||
else:
|
||||
# Parsing data returned from radarr
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
for profile in profiles_json.json():
|
||||
profiles_list.append([profile['id'], profile['language'].capitalize()])
|
||||
else:
|
||||
|
@ -346,12 +338,12 @@ def RadarrFormatVideoCodec(videoFormat, videoCodecID, videoCodecLibrary):
|
|||
return videoFormat
|
||||
|
||||
|
||||
def get_tags(radarr_version):
|
||||
def get_tags():
|
||||
apikey_radarr = settings.radarr.apikey
|
||||
tagsDict = []
|
||||
|
||||
# Get tags data from Radarr
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_radarr_api_series = url_radarr() + "/api/tag?apikey=" + apikey_radarr
|
||||
else:
|
||||
url_radarr_api_series = url_radarr() + "/api/v3/tag?apikey=" + apikey_radarr
|
||||
|
@ -371,7 +363,7 @@ def get_tags(radarr_version):
|
|||
return tagsDict.json()
|
||||
|
||||
|
||||
def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile, audio_profiles):
|
||||
def movieParser(movie, action, tags_dict, movie_default_profile, audio_profiles):
|
||||
if 'movieFile' in movie:
|
||||
# Detect file separator
|
||||
if movie['path'][0] == "/":
|
||||
|
@ -399,7 +391,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile,
|
|||
sceneName = None
|
||||
|
||||
alternativeTitles = None
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
if 'alternativeTitles' in movie:
|
||||
alternativeTitles = str([item['title'] for item in movie['alternativeTitles']])
|
||||
else:
|
||||
|
@ -422,7 +414,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile,
|
|||
|
||||
if 'mediaInfo' in movie['movieFile']:
|
||||
videoFormat = videoCodecID = videoProfile = videoCodecLibrary = None
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
if 'videoFormat' in movie['movieFile']['mediaInfo']: videoFormat = \
|
||||
movie['movieFile']['mediaInfo']['videoFormat']
|
||||
else:
|
||||
|
@ -437,7 +429,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile,
|
|||
videoCodec = RadarrFormatVideoCodec(videoFormat, videoCodecID, videoCodecLibrary)
|
||||
|
||||
audioFormat = audioCodecID = audioProfile = audioAdditionalFeatures = None
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
if 'audioFormat' in movie['movieFile']['mediaInfo']: audioFormat = \
|
||||
movie['movieFile']['mediaInfo']['audioFormat']
|
||||
else:
|
||||
|
@ -456,7 +448,7 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile,
|
|||
audioCodec = None
|
||||
|
||||
audio_language = []
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
if 'mediaInfo' in movie['movieFile']:
|
||||
if 'audioLanguages' in movie['movieFile']['mediaInfo']:
|
||||
audio_languages_list = movie['movieFile']['mediaInfo']['audioLanguages'].split('/')
|
||||
|
@ -522,8 +514,8 @@ def movieParser(movie, action, radarr_version, tags_dict, movie_default_profile,
|
|||
'file_size': movie['movieFile']['size']}
|
||||
|
||||
|
||||
def get_movies_from_radarr_api(radarr_version, url, apikey_radarr, radarr_id=None):
|
||||
if radarr_version.startswith('0'):
|
||||
def get_movies_from_radarr_api(url, apikey_radarr, radarr_id=None):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_radarr_api_movies = url + "/api/movie" + ("/{}".format(radarr_id) if radarr_id else "") + "?apikey=" + \
|
||||
apikey_radarr
|
||||
else:
|
||||
|
|
|
@ -164,6 +164,9 @@ def get_providers_auth():
|
|||
'legendastv' : {
|
||||
'username': settings.legendastv.username,
|
||||
'password': settings.legendastv.password,
|
||||
'featured_only': settings.legendastv.getboolean(
|
||||
'featured_only'
|
||||
),
|
||||
},
|
||||
'xsubs' : {
|
||||
'username': settings.xsubs.username,
|
||||
|
|
|
@ -7,7 +7,7 @@ import logging
|
|||
from config import settings, url_sonarr, url_radarr
|
||||
from helper import path_mappings
|
||||
from database import TableShowsRootfolder, TableMoviesRootfolder, TableShows, TableMovies
|
||||
from utils import get_sonarr_version, get_radarr_version
|
||||
from utils import get_sonarr_info, get_radarr_info
|
||||
|
||||
headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
||||
|
||||
|
@ -15,10 +15,9 @@ headers = {"User-Agent": os.environ["SZ_USER_AGENT"]}
|
|||
def get_sonarr_rootfolder():
|
||||
apikey_sonarr = settings.sonarr.apikey
|
||||
sonarr_rootfolder = []
|
||||
sonarr_version = get_sonarr_version()
|
||||
|
||||
# Get root folder data from Sonarr
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url_sonarr_api_rootfolder = url_sonarr() + "/api/rootfolder?apikey=" + apikey_sonarr
|
||||
else:
|
||||
url_sonarr_api_rootfolder = url_sonarr() + "/api/v3/rootfolder?apikey=" + apikey_sonarr
|
||||
|
@ -63,8 +62,11 @@ def check_sonarr_rootfolder():
|
|||
rootfolder = TableShowsRootfolder.select(TableShowsRootfolder.id, TableShowsRootfolder.path).dicts()
|
||||
for item in rootfolder:
|
||||
root_path = item['path']
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path += os.path.sep
|
||||
if not root_path.endswith(('/', '\\')):
|
||||
if root_path.startswith('/'):
|
||||
root_path += '/'
|
||||
else:
|
||||
root_path += '\\'
|
||||
if not os.path.isdir(path_mappings.path_replace(root_path)):
|
||||
TableShowsRootfolder.update({TableShowsRootfolder.accessible: 0,
|
||||
TableShowsRootfolder.error: 'This Sonarr root directory does not seems to '
|
||||
|
@ -87,10 +89,9 @@ def check_sonarr_rootfolder():
|
|||
def get_radarr_rootfolder():
|
||||
apikey_radarr = settings.radarr.apikey
|
||||
radarr_rootfolder = []
|
||||
radarr_version = get_radarr_version()
|
||||
|
||||
# Get root folder data from Radarr
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_radarr_api_rootfolder = url_radarr() + "/api/rootfolder?apikey=" + apikey_radarr
|
||||
else:
|
||||
url_radarr_api_rootfolder = url_radarr() + "/api/v3/rootfolder?apikey=" + apikey_radarr
|
||||
|
@ -134,8 +135,11 @@ def check_radarr_rootfolder():
|
|||
rootfolder = TableMoviesRootfolder.select(TableMoviesRootfolder.id, TableMoviesRootfolder.path).dicts()
|
||||
for item in rootfolder:
|
||||
root_path = item['path']
|
||||
if not root_path.endswith(os.path.sep):
|
||||
root_path += os.path.sep
|
||||
if not root_path.endswith(('/', '\\')):
|
||||
if root_path.startswith('/'):
|
||||
root_path += '/'
|
||||
else:
|
||||
root_path += '\\'
|
||||
if not os.path.isdir(path_mappings.path_replace_movie(root_path)):
|
||||
TableMoviesRootfolder.update({TableMoviesRootfolder.accessible: 0,
|
||||
TableMoviesRootfolder.error: 'This Radarr root directory does not seems to '
|
||||
|
|
|
@ -11,7 +11,7 @@ from list_subtitles import list_missing_subtitles
|
|||
from get_rootfolder import check_sonarr_rootfolder
|
||||
from database import TableShows, TableEpisodes
|
||||
from get_episodes import sync_episodes
|
||||
from utils import get_sonarr_version
|
||||
from utils import get_sonarr_info
|
||||
from helper import path_mappings
|
||||
from event_handler import event_stream, show_progress, hide_progress
|
||||
|
||||
|
@ -24,7 +24,6 @@ def update_series(send_event=True):
|
|||
if apikey_sonarr is None:
|
||||
return
|
||||
|
||||
sonarr_version = get_sonarr_version()
|
||||
serie_default_enabled = settings.general.getboolean('serie_default_enabled')
|
||||
|
||||
if serie_default_enabled is True:
|
||||
|
@ -38,8 +37,7 @@ def update_series(send_event=True):
|
|||
tagsDict = get_tags()
|
||||
|
||||
# Get shows data from Sonarr
|
||||
series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr,
|
||||
sonarr_version=sonarr_version)
|
||||
series = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=apikey_sonarr)
|
||||
if not series:
|
||||
return
|
||||
else:
|
||||
|
@ -65,12 +63,12 @@ def update_series(send_event=True):
|
|||
current_shows_sonarr.append(show['id'])
|
||||
|
||||
if show['id'] in current_shows_db_list:
|
||||
series_to_update.append(seriesParser(show, action='update', sonarr_version=sonarr_version,
|
||||
tags_dict=tagsDict, serie_default_profile=serie_default_profile,
|
||||
series_to_update.append(seriesParser(show, action='update', tags_dict=tagsDict,
|
||||
serie_default_profile=serie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
else:
|
||||
series_to_add.append(seriesParser(show, action='insert', sonarr_version=sonarr_version,
|
||||
tags_dict=tagsDict, serie_default_profile=serie_default_profile,
|
||||
series_to_add.append(seriesParser(show, action='insert', tags_dict=tagsDict,
|
||||
serie_default_profile=serie_default_profile,
|
||||
audio_profiles=audio_profiles))
|
||||
|
||||
if send_event:
|
||||
|
@ -137,7 +135,7 @@ def update_series(send_event=True):
|
|||
|
||||
|
||||
def update_one_series(series_id, action):
|
||||
logging.debug('BAZARR syncing this specific series from RSonarr: {}'.format(series_id))
|
||||
logging.debug('BAZARR syncing this specific series from Sonarr: {}'.format(series_id))
|
||||
|
||||
# Check if there's a row in database for this series ID
|
||||
try:
|
||||
|
@ -155,7 +153,6 @@ def update_one_series(series_id, action):
|
|||
event_stream(type='series', action='delete', payload=int(series_id))
|
||||
return
|
||||
|
||||
sonarr_version = get_sonarr_version()
|
||||
serie_default_enabled = settings.general.getboolean('serie_default_enabled')
|
||||
|
||||
if serie_default_enabled is True:
|
||||
|
@ -173,18 +170,19 @@ def update_one_series(series_id, action):
|
|||
series = None
|
||||
|
||||
series_data = get_series_from_sonarr_api(url=url_sonarr(), apikey_sonarr=settings.sonarr.apikey,
|
||||
sonarr_series_id=int(series_id), sonarr_version=get_sonarr_version())
|
||||
sonarr_series_id=int(series_id),
|
||||
sonarr_version=get_sonarr_info.version())
|
||||
|
||||
if not series_data:
|
||||
return
|
||||
else:
|
||||
if action == 'updated' and existing_series:
|
||||
series = seriesParser(series_data, action='update', sonarr_version=sonarr_version,
|
||||
tags_dict=tagsDict, serie_default_profile=serie_default_profile,
|
||||
series = seriesParser(series_data, action='update', tags_dict=tagsDict,
|
||||
serie_default_profile=serie_default_profile,
|
||||
audio_profiles=audio_profiles)
|
||||
elif action == 'updated' and not existing_series:
|
||||
series = seriesParser(series_data, action='insert', sonarr_version=sonarr_version,
|
||||
tags_dict=tagsDict, serie_default_profile=serie_default_profile,
|
||||
series = seriesParser(series_data, action='insert', tags_dict=tagsDict,
|
||||
serie_default_profile=serie_default_profile,
|
||||
audio_profiles=audio_profiles)
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot parse series returned by SignalR feed.')
|
||||
|
@ -208,11 +206,10 @@ def update_one_series(series_id, action):
|
|||
|
||||
def get_profile_list():
|
||||
apikey_sonarr = settings.sonarr.apikey
|
||||
sonarr_version = get_sonarr_version()
|
||||
profiles_list = []
|
||||
|
||||
# Get profiles data from Sonarr
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url_sonarr_api_series = url_sonarr() + "/api/profile?apikey=" + apikey_sonarr
|
||||
else:
|
||||
url_sonarr_api_series = url_sonarr() + "/api/v3/languageprofile?apikey=" + apikey_sonarr
|
||||
|
@ -230,7 +227,7 @@ def get_profile_list():
|
|||
return None
|
||||
|
||||
# Parsing data returned from Sonarr
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
for profile in profiles_json.json():
|
||||
profiles_list.append([profile['id'], profile['language'].capitalize()])
|
||||
else:
|
||||
|
@ -253,7 +250,7 @@ def get_tags():
|
|||
tagsDict = []
|
||||
|
||||
# Get tags data from Sonarr
|
||||
if get_sonarr_version().startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url_sonarr_api_series = url_sonarr() + "/api/tag?apikey=" + apikey_sonarr
|
||||
else:
|
||||
url_sonarr_api_series = url_sonarr() + "/api/v3/tag?apikey=" + apikey_sonarr
|
||||
|
@ -273,7 +270,7 @@ def get_tags():
|
|||
return tagsDict.json()
|
||||
|
||||
|
||||
def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile, audio_profiles):
|
||||
def seriesParser(show, action, tags_dict, serie_default_profile, audio_profiles):
|
||||
overview = show['overview'] if 'overview' in show else ''
|
||||
poster = ''
|
||||
fanart = ''
|
||||
|
@ -290,7 +287,7 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile,
|
|||
alternate_titles = str([item['title'] for item in show['alternateTitles']])
|
||||
|
||||
audio_language = []
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
audio_language = profile_id_to_language(show['qualityProfileId'], audio_profiles)
|
||||
else:
|
||||
audio_language = profile_id_to_language(show['languageProfileId'], audio_profiles)
|
||||
|
@ -332,9 +329,9 @@ def seriesParser(show, action, sonarr_version, tags_dict, serie_default_profile,
|
|||
'profileId': serie_default_profile}
|
||||
|
||||
|
||||
def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_version, sonarr_series_id=None):
|
||||
def get_series_from_sonarr_api(url, apikey_sonarr, sonarr_series_id=None):
|
||||
url_sonarr_api_series = url + "/api/{0}series/{1}?apikey={2}".format(
|
||||
'' if sonarr_version.startswith('2') else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr)
|
||||
'' if get_sonarr_info.is_legacy() else 'v3/', sonarr_series_id if sonarr_series_id else "", apikey_sonarr)
|
||||
try:
|
||||
r = requests.get(url_sonarr_api_series, timeout=60, verify=False, headers=headers)
|
||||
r.raise_for_status()
|
||||
|
|
|
@ -806,7 +806,7 @@ def series_download_subtitles(no):
|
|||
hide_progress(id='series_search_progress_{}'.format(no))
|
||||
|
||||
|
||||
def episode_download_subtitles(no):
|
||||
def episode_download_subtitles(no, send_progress=False):
|
||||
conditions = [(TableEpisodes.sonarrEpisodeId == no)]
|
||||
conditions += get_exclusion_clause('series')
|
||||
episodes_details = TableEpisodes.select(TableEpisodes.path,
|
||||
|
@ -818,7 +818,10 @@ def episode_download_subtitles(no):
|
|||
TableShows.title,
|
||||
TableShows.sonarrSeriesId,
|
||||
TableEpisodes.audio_language,
|
||||
TableShows.seriesType)\
|
||||
TableShows.seriesType,
|
||||
TableEpisodes.title.alias('episodeTitle'),
|
||||
TableEpisodes.season,
|
||||
TableEpisodes.episode)\
|
||||
.join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\
|
||||
.where(reduce(operator.and_, conditions))\
|
||||
.dicts()
|
||||
|
@ -831,6 +834,15 @@ def episode_download_subtitles(no):
|
|||
|
||||
for episode in episodes_details:
|
||||
if providers_list:
|
||||
if send_progress:
|
||||
show_progress(id='episode_search_progress_{}'.format(no),
|
||||
header='Searching missing subtitles...',
|
||||
name='{0} - S{1:02d}E{2:02d} - {3}'.format(episode['title'],
|
||||
episode['season'],
|
||||
episode['episode'],
|
||||
episode['episodeTitle']),
|
||||
value=1,
|
||||
count=1)
|
||||
for language in ast.literal_eval(episode['missing_subtitles']):
|
||||
# confirm if language is still missing or if cutoff have been reached
|
||||
confirmed_missing_subs = TableEpisodes.select(TableEpisodes.missing_subtitles) \
|
||||
|
@ -875,6 +887,8 @@ def episode_download_subtitles(no):
|
|||
history_log(1, episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message, path,
|
||||
language_code, provider, score, subs_id, subs_path)
|
||||
send_notifications(episode['sonarrSeriesId'], episode['sonarrEpisodeId'], message)
|
||||
if send_progress:
|
||||
hide_progress(id='episode_search_progress_{}'.format(no))
|
||||
else:
|
||||
logging.info("BAZARR All providers are throttled")
|
||||
break
|
||||
|
|
|
@ -16,7 +16,7 @@ import subliminal
|
|||
import datetime
|
||||
|
||||
# set subliminal_patch user agent
|
||||
os.environ["SZ_USER_AGENT"] = "Bazarr/1"
|
||||
os.environ["SZ_USER_AGENT"] = "Bazarr/{}".format(os.environ["BAZARR_VERSION"])
|
||||
|
||||
# set anti-captcha provider and key
|
||||
configure_captcha_func()
|
||||
|
@ -42,6 +42,13 @@ if not os.path.exists(os.path.join(args.config_dir, 'cache')):
|
|||
configure_logging(settings.general.getboolean('debug') or args.debug)
|
||||
import logging
|
||||
|
||||
|
||||
def is_virtualenv():
|
||||
# return True if Bazarr have been start from within a virtualenv or venv
|
||||
base_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
|
||||
return base_prefix != sys.prefix
|
||||
|
||||
|
||||
# deploy requirements.txt
|
||||
if not args.no_update:
|
||||
try:
|
||||
|
@ -57,10 +64,12 @@ if not args.no_update:
|
|||
else:
|
||||
logging.info('BAZARR installing requirements...')
|
||||
try:
|
||||
subprocess.check_output([sys.executable, '-m', 'pip', 'install', '--user', '-qq',
|
||||
'--disable-pip-version-check', '--no-color', '-r',
|
||||
os.path.join(os.path.dirname(__file__), '..', 'requirements.txt')],
|
||||
stderr=subprocess.STDOUT)
|
||||
pip_command = [sys.executable, '-m', 'pip', 'install', '-qq', '--disable-pip-version-check',
|
||||
'-r', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'requirements.txt')]
|
||||
if not is_virtualenv():
|
||||
# --user only make sense if not running under venv
|
||||
pip_command.insert(4, '--user')
|
||||
subprocess.check_output(pip_command, stderr=subprocess.STDOUT)
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.exception('BAZARR requirements.txt installation result: {}'.format(e.stdout))
|
||||
os._exit(1)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Gevent monkey patch if gevent available. If not, it will be installed on during the init process.
|
||||
try:
|
||||
from gevent import monkey, Greenlet
|
||||
from gevent import monkey, Greenlet, joinall
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
|
@ -43,7 +43,7 @@ from signalr_client import sonarr_signalr_client, radarr_signalr_client
|
|||
from check_update import apply_update, check_if_new_update, check_releases
|
||||
from server import app, webserver
|
||||
from functools import wraps
|
||||
from utils import check_credentials, get_sonarr_version, get_radarr_version
|
||||
from utils import check_credentials, get_sonarr_info, get_radarr_info
|
||||
|
||||
# Install downloaded update
|
||||
if bazarr_version != '':
|
||||
|
@ -131,8 +131,7 @@ def series_images(url):
|
|||
url = url.strip("/")
|
||||
apikey = settings.sonarr.apikey
|
||||
baseUrl = settings.sonarr.base_url
|
||||
sonarr_version = get_sonarr_version()
|
||||
if sonarr_version.startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url_image = (url_sonarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' +
|
||||
apikey).replace('poster-250', 'poster-500')
|
||||
else:
|
||||
|
@ -151,8 +150,7 @@ def series_images(url):
|
|||
def movies_images(url):
|
||||
apikey = settings.radarr.apikey
|
||||
baseUrl = settings.radarr.base_url
|
||||
radarr_version = get_radarr_version()
|
||||
if radarr_version.startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url_image = url_radarr() + '/api/' + url.lstrip(baseUrl) + '?apikey=' + apikey
|
||||
else:
|
||||
url_image = url_radarr() + '/api/v3/' + url.lstrip(baseUrl) + '?apikey=' + apikey
|
||||
|
@ -204,10 +202,12 @@ def proxy(protocol, url):
|
|||
return dict(status=False, error=result.raise_for_status())
|
||||
|
||||
|
||||
greenlets = []
|
||||
if settings.general.getboolean('use_sonarr'):
|
||||
Greenlet.spawn(sonarr_signalr_client.start)
|
||||
greenlets.append(Greenlet.spawn(sonarr_signalr_client.start))
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
Greenlet.spawn(radarr_signalr_client.start)
|
||||
greenlets.append(Greenlet.spawn(radarr_signalr_client.start))
|
||||
joinall(greenlets)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -15,7 +15,7 @@ from get_episodes import sync_episodes, sync_one_episode
|
|||
from get_series import update_series, update_one_series
|
||||
from get_movies import update_movies, update_one_movie
|
||||
from scheduler import scheduler
|
||||
from utils import get_sonarr_version
|
||||
from utils import get_sonarr_info
|
||||
from get_args import args
|
||||
|
||||
|
||||
|
@ -33,26 +33,31 @@ class SonarrSignalrClient:
|
|||
self.connection = None
|
||||
|
||||
def start(self):
|
||||
if get_sonarr_version().startswith('2.'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
logging.warning('BAZARR can only sync from Sonarr v3 SignalR feed to get real-time update. You should '
|
||||
'consider upgrading.')
|
||||
return
|
||||
|
||||
logging.info('BAZARR trying to connect to Sonarr SignalR feed...')
|
||||
self.configure()
|
||||
while not self.connection.started:
|
||||
try:
|
||||
self.connection.start()
|
||||
except ConnectionError:
|
||||
gevent.sleep(5)
|
||||
except json.decoder.JSONDecodeError:
|
||||
logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is a known issue when Sonarr "
|
||||
"doesn't have write permission to it's /config/xdg directory.")
|
||||
self.stop()
|
||||
logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.')
|
||||
if not args.dev:
|
||||
scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1)
|
||||
scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1)
|
||||
'consider upgrading your version({}).'.format(get_sonarr_info.version()))
|
||||
raise gevent.GreenletExit
|
||||
else:
|
||||
logging.info('BAZARR trying to connect to Sonarr SignalR feed...')
|
||||
self.configure()
|
||||
while not self.connection.started:
|
||||
try:
|
||||
self.connection.start()
|
||||
except ConnectionError:
|
||||
gevent.sleep(5)
|
||||
except json.decoder.JSONDecodeError:
|
||||
logging.error("BAZARR cannot parse JSON returned by SignalR feed. This is caused by a permissions "
|
||||
"issue when Sonarr try to access its /config/.config directory. You should fix "
|
||||
"permissions on that directory and restart Sonarr. Also, if you're a Docker image "
|
||||
"user, you should make sure you properly defined PUID/PGID environment variables. "
|
||||
"Otherwise, please contact Sonarr support.")
|
||||
raise gevent.GreenletExit
|
||||
else:
|
||||
logging.info('BAZARR SignalR client for Sonarr is connected and waiting for events.')
|
||||
finally:
|
||||
if not args.dev:
|
||||
scheduler.add_job(update_series, kwargs={'send_event': True}, max_instances=1)
|
||||
scheduler.add_job(sync_episodes, kwargs={'send_event': True}, max_instances=1)
|
||||
|
||||
def stop(self, log=True):
|
||||
try:
|
||||
|
|
|
@ -58,6 +58,8 @@ class SubSyncer:
|
|||
logging.exception('BAZARR an exception occurs during the synchronization process for this subtitles: '
|
||||
'{0}'.format(self.srtin))
|
||||
else:
|
||||
if settings.subsync.getboolean('debug'):
|
||||
return result
|
||||
if os.path.isfile(self.srtout):
|
||||
if not settings.subsync.getboolean('debug'):
|
||||
os.remove(self.srtin)
|
||||
|
|
154
bazarr/utils.py
154
bazarr/utils.py
|
@ -236,44 +236,53 @@ def cache_maintenance():
|
|||
remove_expired(fn, pack_cache_validity)
|
||||
|
||||
|
||||
def get_sonarr_version():
|
||||
sonarr_version = ''
|
||||
if settings.general.getboolean('use_sonarr'):
|
||||
try:
|
||||
sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey
|
||||
sonarr_json = requests.get(sv, timeout=60, verify=False, headers=headers).json()
|
||||
if 'version' in sonarr_json:
|
||||
sonarr_version = sonarr_json['version']
|
||||
else:
|
||||
sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey
|
||||
sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version']
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot get Sonarr version')
|
||||
sonarr_version = 'unknown'
|
||||
return sonarr_version
|
||||
|
||||
|
||||
def get_sonarr_platform():
|
||||
sonarr_platform = ''
|
||||
if settings.general.getboolean('use_sonarr'):
|
||||
try:
|
||||
if get_sonarr_version().startswith('2'):
|
||||
class GetSonarrInfo:
|
||||
@staticmethod
|
||||
def version():
|
||||
"""
|
||||
Call system/status API endpoint and get the Sonarr version
|
||||
@return: str
|
||||
"""
|
||||
sonarr_version = region.get("sonarr_version", expiration_time=datetime.timedelta(seconds=60).total_seconds())
|
||||
if sonarr_version:
|
||||
region.set("sonarr_version", sonarr_version)
|
||||
return sonarr_version
|
||||
else:
|
||||
sonarr_version = ''
|
||||
if settings.general.getboolean('use_sonarr'):
|
||||
try:
|
||||
sv = url_sonarr() + "/api/system/status?apikey=" + settings.sonarr.apikey
|
||||
else:
|
||||
sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey
|
||||
response = requests.get(sv, timeout=60, verify=False, headers=headers).json()
|
||||
if response['isLinux'] or response['isOsx']:
|
||||
sonarr_platform = 'posix'
|
||||
elif response['isWindows']:
|
||||
sonarr_platform = 'nt'
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot get Sonarr platform')
|
||||
return sonarr_platform
|
||||
sonarr_json = requests.get(sv, timeout=60, verify=False, headers=headers).json()
|
||||
if 'version' in sonarr_json:
|
||||
sonarr_version = sonarr_json['version']
|
||||
else:
|
||||
sv = url_sonarr() + "/api/v3/system/status?apikey=" + settings.sonarr.apikey
|
||||
sonarr_version = requests.get(sv, timeout=60, verify=False, headers=headers).json()['version']
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot get Sonarr version')
|
||||
sonarr_version = 'unknown'
|
||||
logging.debug('BAZARR got this Sonarr version from its API: {}'.format(sonarr_version))
|
||||
region.set("sonarr_version", sonarr_version)
|
||||
return sonarr_version
|
||||
|
||||
def is_legacy(self):
|
||||
"""
|
||||
Call self.version() and parse the result to determine if it's a legacy version of Sonarr API
|
||||
@return: bool
|
||||
"""
|
||||
sonarr_version = self.version()
|
||||
if sonarr_version.startswith(('0.', '2.')):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
get_sonarr_info = GetSonarrInfo()
|
||||
|
||||
|
||||
def notify_sonarr(sonarr_series_id):
|
||||
try:
|
||||
if get_sonarr_version().startswith('2'):
|
||||
if get_sonarr_info.is_legacy():
|
||||
url = url_sonarr() + "/api/command?apikey=" + settings.sonarr.apikey
|
||||
else:
|
||||
url = url_sonarr() + "/api/v3/command?apikey=" + settings.sonarr.apikey
|
||||
|
@ -283,47 +292,56 @@ def notify_sonarr(sonarr_series_id):
|
|||
}
|
||||
requests.post(url, json=data, timeout=60, verify=False, headers=headers)
|
||||
except Exception as e:
|
||||
logging.debug('BAZARR notify Sonarr')
|
||||
logging.exception('BAZARR cannot notify Sonarr')
|
||||
|
||||
|
||||
def get_radarr_version():
|
||||
radarr_version = ''
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
try:
|
||||
rv = url_radarr() + "/api/system/status?apikey=" + settings.radarr.apikey
|
||||
radarr_json = requests.get(rv, timeout=60, verify=False, headers=headers).json()
|
||||
if 'version' in radarr_json:
|
||||
radarr_version = radarr_json['version']
|
||||
else:
|
||||
rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey
|
||||
radarr_version = requests.get(rv, timeout=60, verify=False, headers=headers).json()['version']
|
||||
except Exception as e:
|
||||
logging.debug('BAZARR cannot get Radarr version')
|
||||
radarr_version = 'unknown'
|
||||
return radarr_version
|
||||
|
||||
|
||||
def get_radarr_platform():
|
||||
radarr_platform = ''
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
try:
|
||||
if get_radarr_version().startswith('0'):
|
||||
class GetRadarrInfo:
|
||||
@staticmethod
|
||||
def version():
|
||||
"""
|
||||
Call system/status API endpoint and get the Radarr version
|
||||
@return: str
|
||||
"""
|
||||
radarr_version = region.get("radarr_version", expiration_time=datetime.timedelta(seconds=60).total_seconds())
|
||||
if radarr_version:
|
||||
region.set("radarr_version", radarr_version)
|
||||
return radarr_version
|
||||
else:
|
||||
radarr_version = ''
|
||||
if settings.general.getboolean('use_radarr'):
|
||||
try:
|
||||
rv = url_radarr() + "/api/system/status?apikey=" + settings.radarr.apikey
|
||||
else:
|
||||
rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey
|
||||
response = requests.get(rv, timeout=60, verify=False, headers=headers).json()
|
||||
if response['isLinux'] or response['isOsx']:
|
||||
radarr_platform = 'posix'
|
||||
elif response['isWindows']:
|
||||
radarr_platform = 'nt'
|
||||
except Exception:
|
||||
logging.debug('BAZARR cannot get Radarr platform')
|
||||
return radarr_platform
|
||||
radarr_json = requests.get(rv, timeout=60, verify=False, headers=headers).json()
|
||||
if 'version' in radarr_json:
|
||||
radarr_version = radarr_json['version']
|
||||
else:
|
||||
rv = url_radarr() + "/api/v3/system/status?apikey=" + settings.radarr.apikey
|
||||
radarr_version = requests.get(rv, timeout=60, verify=False, headers=headers).json()['version']
|
||||
except Exception as e:
|
||||
logging.debug('BAZARR cannot get Radarr version')
|
||||
radarr_version = 'unknown'
|
||||
logging.debug('BAZARR got this Radarr version from its API: {}'.format(radarr_version))
|
||||
region.set("radarr_version", radarr_version)
|
||||
return radarr_version
|
||||
|
||||
def is_legacy(self):
|
||||
"""
|
||||
Call self.version() and parse the result to determine if it's a legacy version of Radarr
|
||||
@return: bool
|
||||
"""
|
||||
radarr_version = self.version()
|
||||
if radarr_version.startswith('0.'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
get_radarr_info = GetRadarrInfo()
|
||||
|
||||
|
||||
def notify_radarr(radarr_id):
|
||||
try:
|
||||
if get_radarr_version().startswith('0'):
|
||||
if get_radarr_info.is_legacy():
|
||||
url = url_radarr() + "/api/command?apikey=" + settings.radarr.apikey
|
||||
else:
|
||||
url = url_radarr() + "/api/v3/command?apikey=" + settings.radarr.apikey
|
||||
|
@ -333,7 +351,7 @@ def notify_radarr(radarr_id):
|
|||
}
|
||||
requests.post(url, json=data, timeout=60, verify=False, headers=headers)
|
||||
except Exception as e:
|
||||
logging.debug('BAZARR notify Radarr')
|
||||
logging.exception('BAZARR cannot notify Radarr')
|
||||
|
||||
|
||||
def delete_subtitles(media_type, language, forced, hi, media_path, subtitles_path, sonarr_series_id=None,
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "bazarr",
|
||||
"version": "1",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "bazarr",
|
||||
"version": "1",
|
||||
"version": "1.0.0",
|
||||
"license": "GPL-3",
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^4.2.2",
|
||||
|
@ -19,9 +19,8 @@
|
|||
"@types/lodash": "^4",
|
||||
"@types/node": "^15",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"@types/react-dom": "^17",
|
||||
"@types/react-helmet": "^6.1",
|
||||
"@types/react-redux": "^7",
|
||||
"@types/react-router-dom": "^5",
|
||||
"@types/react-select": "^4.0.3",
|
||||
"@types/react-table": "^7",
|
||||
|
@ -33,9 +32,9 @@
|
|||
"http-proxy-middleware": "^0.19",
|
||||
"lodash": "^4",
|
||||
"rc-slider": "^9.7",
|
||||
"react": "^16",
|
||||
"react": "^17",
|
||||
"react-bootstrap": "^1",
|
||||
"react-dom": "^16",
|
||||
"react-dom": "^17",
|
||||
"react-helmet": "^6.1",
|
||||
"react-redux": "^7.2",
|
||||
"react-router-dom": "^5.2",
|
||||
|
@ -2969,11 +2968,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "16.9.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.12.tgz",
|
||||
"integrity": "sha512-i7NPZZpPte3jtVOoW+eLB7G/jsX5OM6GqQnH+lC0nq0rqwlK0x8WcMEvYDgFWqWhWMlTltTimzdMax6wYfZssA==",
|
||||
"version": "17.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
|
||||
"integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
|
||||
"dependencies": {
|
||||
"@types/react": "^16"
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-helmet": {
|
||||
|
@ -2985,9 +2984,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/react-redux": {
|
||||
"version": "7.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
|
||||
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
|
||||
"version": "7.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz",
|
||||
"integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==",
|
||||
"dependencies": {
|
||||
"@types/hoist-non-react-statics": "^3.3.0",
|
||||
"@types/react": "*",
|
||||
|
@ -7071,9 +7070,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.0.1.tgz",
|
||||
"integrity": "sha512-CQtGN3YwfvbxVwpPugcsHe5rHT4KgT49CEcQppNtu9N7WxbPN0MAG27lGaem7bvtCFtGNLSL+GEqXsFSz36jTg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz",
|
||||
"integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==",
|
||||
"dependencies": {
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
"component-emitter": "~1.3.0",
|
||||
|
@ -15776,13 +15775,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
"object-assign": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
@ -16037,17 +16035,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
|
||||
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
"scheduler": "^0.20.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.14.0"
|
||||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-error-overlay": {
|
||||
|
@ -17711,9 +17708,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
|
@ -18223,15 +18220,15 @@
|
|||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.0.1.tgz",
|
||||
"integrity": "sha512-6AkaEG5zrVuSVW294cH1chioag9i1OqnCYjKwTc3EBGXbnyb98Lw7yMa40ifLjFj3y6fsFKsd0llbUZUCRf3Qw==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz",
|
||||
"integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==",
|
||||
"dependencies": {
|
||||
"@types/component-emitter": "^1.2.10",
|
||||
"backo2": "~1.0.2",
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-client": "~5.0.0",
|
||||
"engine.io-client": "~5.1.2",
|
||||
"parseuri": "0.0.6",
|
||||
"socket.io-parser": "~4.0.4"
|
||||
},
|
||||
|
@ -24411,11 +24408,11 @@
|
|||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "16.9.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.12.tgz",
|
||||
"integrity": "sha512-i7NPZZpPte3jtVOoW+eLB7G/jsX5OM6GqQnH+lC0nq0rqwlK0x8WcMEvYDgFWqWhWMlTltTimzdMax6wYfZssA==",
|
||||
"version": "17.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz",
|
||||
"integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==",
|
||||
"requires": {
|
||||
"@types/react": "^16"
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-helmet": {
|
||||
|
@ -24427,9 +24424,9 @@
|
|||
}
|
||||
},
|
||||
"@types/react-redux": {
|
||||
"version": "7.1.16",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
|
||||
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
|
||||
"version": "7.1.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz",
|
||||
"integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==",
|
||||
"requires": {
|
||||
"@types/hoist-non-react-statics": "^3.3.0",
|
||||
"@types/react": "*",
|
||||
|
@ -27764,9 +27761,9 @@
|
|||
}
|
||||
},
|
||||
"engine.io-client": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.0.1.tgz",
|
||||
"integrity": "sha512-CQtGN3YwfvbxVwpPugcsHe5rHT4KgT49CEcQppNtu9N7WxbPN0MAG27lGaem7bvtCFtGNLSL+GEqXsFSz36jTg==",
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-5.1.2.tgz",
|
||||
"integrity": "sha512-blRrgXIE0A/eurWXRzvfCLG7uUFJqfTGFsyJzXSK71srMMGJ2VraBLg8Mdw28uUxSpVicepBN9X7asqpD1mZcQ==",
|
||||
"requires": {
|
||||
"base64-arraybuffer": "0.1.4",
|
||||
"component-emitter": "~1.3.0",
|
||||
|
@ -34534,13 +34531,12 @@
|
|||
}
|
||||
},
|
||||
"react": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
"object-assign": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"react-app-polyfill": {
|
||||
|
@ -34742,14 +34738,13 @@
|
|||
}
|
||||
},
|
||||
"react-dom": {
|
||||
"version": "16.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
|
||||
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"scheduler": "^0.19.1"
|
||||
"scheduler": "^0.20.2"
|
||||
}
|
||||
},
|
||||
"react-error-overlay": {
|
||||
|
@ -36048,9 +36043,9 @@
|
|||
}
|
||||
},
|
||||
"scheduler": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz",
|
||||
"integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==",
|
||||
"version": "0.20.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
|
||||
"integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
|
@ -36477,15 +36472,15 @@
|
|||
}
|
||||
},
|
||||
"socket.io-client": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.0.1.tgz",
|
||||
"integrity": "sha512-6AkaEG5zrVuSVW294cH1chioag9i1OqnCYjKwTc3EBGXbnyb98Lw7yMa40ifLjFj3y6fsFKsd0llbUZUCRf3Qw==",
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.1.3.tgz",
|
||||
"integrity": "sha512-hISFn6PDpgDifVUiNklLHVPTMv1LAk8poHArfIUdXa+gKgbr0MZbAlquDFqCqsF30yBqa+jg42wgos2FK50BHA==",
|
||||
"requires": {
|
||||
"@types/component-emitter": "^1.2.10",
|
||||
"backo2": "~1.0.2",
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-client": "~5.0.0",
|
||||
"engine.io-client": "~5.1.2",
|
||||
"parseuri": "0.0.6",
|
||||
"socket.io-parser": "~4.0.4"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bazarr",
|
||||
"version": "1",
|
||||
"version": "1.0.0",
|
||||
"description": "Bazarr is a companion application to Sonarr and Radarr. It manages and downloads subtitles based on your requirements. You define your preferences by TV show or movie and Bazarr takes care of everything for you.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -23,9 +23,8 @@
|
|||
"@types/lodash": "^4",
|
||||
"@types/node": "^15",
|
||||
"@types/react": "^16",
|
||||
"@types/react-dom": "^16",
|
||||
"@types/react-dom": "^17",
|
||||
"@types/react-helmet": "^6.1",
|
||||
"@types/react-redux": "^7",
|
||||
"@types/react-router-dom": "^5",
|
||||
"@types/react-select": "^4.0.3",
|
||||
"@types/react-table": "^7",
|
||||
|
@ -37,9 +36,9 @@
|
|||
"http-proxy-middleware": "^0.19",
|
||||
"lodash": "^4",
|
||||
"rc-slider": "^9.7",
|
||||
"react": "^16",
|
||||
"react": "^17",
|
||||
"react-bootstrap": "^1",
|
||||
"react-dom": "^16",
|
||||
"react-dom": "^17",
|
||||
"react-helmet": "^6.1",
|
||||
"react-redux": "^7.2",
|
||||
"react-router-dom": "^5.2",
|
||||
|
|
|
@ -5,13 +5,11 @@ import {
|
|||
episodeDeleteItems,
|
||||
episodeUpdateBy,
|
||||
episodeUpdateById,
|
||||
movieDeleteWantedItems,
|
||||
movieUpdateBlacklist,
|
||||
movieUpdateHistoryList,
|
||||
movieUpdateList,
|
||||
movieUpdateWantedList,
|
||||
providerUpdateList,
|
||||
seriesDeleteWantedItems,
|
||||
seriesUpdateBlacklist,
|
||||
seriesUpdateHistoryList,
|
||||
seriesUpdateList,
|
||||
|
@ -324,18 +322,6 @@ export function useWantedSeries() {
|
|||
const update = useReduxAction(seriesUpdateWantedList);
|
||||
const items = useReduxStore((d) => d.series.wantedEpisodesList);
|
||||
|
||||
const updateAction = useWrapToOptionalId(update);
|
||||
const deleteAction = useReduxAction(seriesDeleteWantedItems);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({
|
||||
key: "episode-wanted",
|
||||
update: updateAction,
|
||||
delete: deleteAction,
|
||||
}),
|
||||
[updateAction, deleteAction]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
return stateBuilder(items, update);
|
||||
}
|
||||
|
||||
|
@ -343,18 +329,6 @@ export function useWantedMovies() {
|
|||
const update = useReduxAction(movieUpdateWantedList);
|
||||
const items = useReduxStore((d) => d.movie.wantedMovieList);
|
||||
|
||||
const updateAction = useWrapToOptionalId(update);
|
||||
const deleteAction = useReduxAction(movieDeleteWantedItems);
|
||||
const reducer = useMemo<SocketIO.Reducer>(
|
||||
() => ({
|
||||
key: "movie-wanted",
|
||||
update: updateAction,
|
||||
delete: deleteAction,
|
||||
}),
|
||||
[updateAction, deleteAction]
|
||||
);
|
||||
useSocketIOReducer(reducer);
|
||||
|
||||
return stateBuilder(items, update);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ export function defaultAOS(): AsyncOrderState<any> {
|
|||
data: {
|
||||
items: [],
|
||||
order: [],
|
||||
fetched: false,
|
||||
dirty: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ export function updateOrderIdState<T extends LooseObject>(
|
|||
return {
|
||||
data: {
|
||||
...state.data,
|
||||
fetched: true,
|
||||
dirty: true,
|
||||
},
|
||||
updating: true,
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ export function updateOrderIdState<T extends LooseObject>(
|
|||
return {
|
||||
data: {
|
||||
...state.data,
|
||||
fetched: true,
|
||||
dirty: true,
|
||||
},
|
||||
updating: false,
|
||||
error: action.payload.item as Error,
|
||||
|
@ -107,7 +107,7 @@ export function updateOrderIdState<T extends LooseObject>(
|
|||
return {
|
||||
updating: false,
|
||||
data: {
|
||||
fetched: true,
|
||||
dirty: true,
|
||||
items: newItems,
|
||||
order: newOrder,
|
||||
},
|
||||
|
@ -131,7 +131,7 @@ export function deleteOrderListItemBy<T extends LooseObject>(
|
|||
return {
|
||||
...state,
|
||||
data: {
|
||||
fetched: true,
|
||||
dirty: true,
|
||||
items: newItems,
|
||||
order: newOrder,
|
||||
},
|
||||
|
|
|
@ -3,9 +3,13 @@ import {
|
|||
badgeUpdateAll,
|
||||
bootstrap,
|
||||
movieDeleteItems,
|
||||
movieDeleteWantedItems,
|
||||
movieUpdateList,
|
||||
movieUpdateWantedList,
|
||||
seriesDeleteItems,
|
||||
seriesDeleteWantedItems,
|
||||
seriesUpdateList,
|
||||
seriesUpdateWantedList,
|
||||
siteAddNotifications,
|
||||
siteAddProgress,
|
||||
siteInitializationFailed,
|
||||
|
@ -91,6 +95,24 @@ export function createDefaultReducer(): SocketIO.Reducer[] {
|
|||
update: bindToReduxStore(movieUpdateList),
|
||||
delete: bindToReduxStore(movieDeleteItems),
|
||||
},
|
||||
{
|
||||
key: "episode-wanted",
|
||||
update: (ids: number[] | undefined) => {
|
||||
if (ids) {
|
||||
reduxStore.dispatch(seriesUpdateWantedList(ids) as any);
|
||||
}
|
||||
},
|
||||
delete: bindToReduxStore(seriesDeleteWantedItems),
|
||||
},
|
||||
{
|
||||
key: "movie-wanted",
|
||||
update: (ids: number[] | undefined) => {
|
||||
if (ids) {
|
||||
reduxStore.dispatch(movieUpdateWantedList(ids) as any);
|
||||
}
|
||||
},
|
||||
delete: bindToReduxStore(movieDeleteWantedItems),
|
||||
},
|
||||
{
|
||||
key: "settings",
|
||||
any: bindToReduxStore(systemUpdateSettings),
|
||||
|
|
|
@ -14,7 +14,7 @@ type StorageType = string | null;
|
|||
interface OrderIdState<T> {
|
||||
items: IdState<T>;
|
||||
order: (number | null)[];
|
||||
fetched: boolean;
|
||||
dirty: boolean;
|
||||
}
|
||||
|
||||
interface AsyncState<T> {
|
||||
|
|
|
@ -181,7 +181,9 @@ namespace Settings {
|
|||
skip_wrong_fps: boolean;
|
||||
}
|
||||
|
||||
interface Legendastv extends BaseProvider {}
|
||||
interface Legendastv extends BaseProvider {
|
||||
featured_only: boolean;
|
||||
}
|
||||
|
||||
interface XSubs extends BaseProvider {}
|
||||
|
||||
|
|
|
@ -77,6 +77,10 @@ export const ProviderList: Readonly<ProviderInfo[]> = [
|
|||
defaultKey: {
|
||||
username: "",
|
||||
password: "",
|
||||
featured_only: false,
|
||||
},
|
||||
keyNameOverride: {
|
||||
featured_only: "Only Download Featured",
|
||||
},
|
||||
},
|
||||
{ key: "napiprojekt", description: "Polish Subtitles Provider" },
|
||||
|
|
|
@ -21,7 +21,7 @@ export default function AsyncPageTable<T extends object>(props: Props<T>) {
|
|||
|
||||
const {
|
||||
updating,
|
||||
data: { order, items, fetched },
|
||||
data: { order, items, dirty },
|
||||
} = aos;
|
||||
|
||||
const allPlugins: PluginHook<T>[] = [useDefaultSettings];
|
||||
|
@ -85,12 +85,12 @@ export default function AsyncPageTable<T extends object>(props: Props<T>) {
|
|||
}, [pageIndex]);
|
||||
|
||||
useEffect(() => {
|
||||
const needInit = visibleItemIds.length === 0 && fetched === false;
|
||||
const needFetch = visibleItemIds.length === 0 && dirty === false;
|
||||
const needRefresh = !visibleItemIds.every(isNonNullable);
|
||||
if (needInit || needRefresh) {
|
||||
if (needFetch || needRefresh) {
|
||||
loader(pageStart, pageSize);
|
||||
}
|
||||
}, [visibleItemIds, pageStart, pageSize, loader, fetched]);
|
||||
}, [visibleItemIds, pageStart, pageSize, loader, dirty]);
|
||||
|
||||
const showLoading = useMemo(
|
||||
() =>
|
||||
|
|
|
@ -75,12 +75,12 @@ class GreekSubsProvider(Provider):
|
|||
r = self.session.get(search_link, timeout=30)
|
||||
|
||||
# 404 is returned if the imdb_id was not found
|
||||
if r.status_code != 404:
|
||||
r.raise_for_status()
|
||||
if r.status_code == 404:
|
||||
logger.debug('IMDB id {} not found on greeksubs'.format(imdb_id))
|
||||
return subtitles
|
||||
|
||||
if r.status_code != 200:
|
||||
logger.debug('No subtitles found')
|
||||
return subtitles
|
||||
r.raise_for_status()
|
||||
|
||||
soup_page = ParserBeautifulSoup(r.content.decode('utf-8', 'ignore'), ['html.parser'])
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ class LegendasTVProvider(_LegendasTVProvider):
|
|||
languages = {Language(*l) for l in language_converters['legendastv'].to_legendastv.keys()}
|
||||
subtitle_class = LegendasTVSubtitle
|
||||
|
||||
def __init__(self, username=None, password=None):
|
||||
def __init__(self, username=None, password=None, featured_only=False):
|
||||
|
||||
# Provider needs UNRAR installed. If not available raise ConfigurationError
|
||||
try:
|
||||
|
@ -85,6 +85,7 @@ class LegendasTVProvider(_LegendasTVProvider):
|
|||
self.password = password
|
||||
self.logged_in = False
|
||||
self.session = None
|
||||
self.featured_only = featured_only
|
||||
|
||||
@staticmethod
|
||||
def is_valid_title(title, title_id, sanitized_title, season, year, imdb_id):
|
||||
|
@ -209,6 +210,11 @@ class LegendasTVProvider(_LegendasTVProvider):
|
|||
# iterate over title's archives
|
||||
for a in archives:
|
||||
|
||||
# Check if featured
|
||||
if self.featured_only and a.featured == False:
|
||||
logger.info('Subtitle is not featured, skipping')
|
||||
continue
|
||||
|
||||
# compute an expiration time based on the archive timestamp
|
||||
expiration_time = (datetime.utcnow().replace(tzinfo=pytz.utc) - a.timestamp).total_seconds()
|
||||
|
||||
|
|
|
@ -124,6 +124,9 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider):
|
|||
languages.update(set(Language.rebuild(l, forced=True) for l in languages))
|
||||
|
||||
def __init__(self, username=None, password=None, use_hash=True, api_key=None):
|
||||
if not all((username, password)):
|
||||
raise ConfigurationError('Username and password must be specified')
|
||||
|
||||
if not api_key:
|
||||
raise ConfigurationError('Api_key must be specified')
|
||||
|
||||
|
|
|
@ -152,12 +152,12 @@ class TitulkyProvider(Provider):
|
|||
"""Titulky Provider."""
|
||||
languages = {Language(l) for l in ['ces', 'slk']}
|
||||
|
||||
server_url = 'https://premium.titulky.com'
|
||||
server_url = 'https://oldpremium.titulky.com'
|
||||
sign_out_url = '?Logoff=true'
|
||||
search_url_series = '?Fulltext={}'
|
||||
search_url_movies = '?Searching=AdvancedResult&ARelease={}'
|
||||
dn_url = 'https://premium.titulky.com'
|
||||
download_url = 'https://premium.titulky.com/idown.php?titulky='
|
||||
dn_url = 'https://oldpremium.titulky.com'
|
||||
download_url = 'https://oldpremium.titulky.com/idown.php?titulky='
|
||||
|
||||
UserAgent = 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Trident/6.0)'
|
||||
|
||||
|
|
Loading…
Reference in New Issue