Merge branch 'morpheus65535:master' into napiprojekt_enhancement

pull/2825/head
destpstrzy 3 months ago committed by GitHub
commit 3bcf904d62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -90,7 +90,7 @@ def provider_throttle_map():
},
"opensubtitlescom": {
TooManyRequests: (datetime.timedelta(minutes=1), "1 minute"),
DownloadLimitExceeded: (datetime.timedelta(hours=24), "24 hours"),
DownloadLimitExceeded: (datetime.timedelta(hours=6), "6 hours"),
},
"addic7ed": {
DownloadLimitExceeded: (datetime.timedelta(hours=3), "3 hours"),
@ -100,6 +100,9 @@ def provider_throttle_map():
"titlovi": {
TooManyRequests: (datetime.timedelta(minutes=5), "5 minutes"),
},
"titrari": {
TooManyRequests: (datetime.timedelta(minutes=10), "10 minutes"),
},
"titulky": {
DownloadLimitExceeded: (
titulky_limit_reset_timedelta(),

@ -49,12 +49,12 @@ class Server:
threads=100)
self.connected = True
except OSError as error:
if error.errno == 49:
if error.errno == errno.EADDRNOTAVAIL:
logging.exception("BAZARR cannot bind to specified IP, trying with 0.0.0.0")
self.address = '0.0.0.0'
self.connected = False
super(Server, self).__init__()
elif error.errno == 48:
elif error.errno == errno.EADDRINUSE:
if self.port != '6767':
logging.exception("BAZARR cannot bind to specified TCP port, trying with default (6767)")
self.port = '6767'
@ -64,7 +64,7 @@ class Server:
logging.exception("BAZARR cannot bind to default TCP port (6767) because it's already in use, "
"exiting...")
self.shutdown(EXIT_PORT_ALREADY_IN_USE_ERROR)
elif error.errno == 97:
elif error.errno == errno.ENOLINK:
logging.exception("BAZARR cannot bind to IPv6 (*), trying with 0.0.0.0")
self.address = '0.0.0.0'
self.connected = False

@ -53,7 +53,7 @@ def update_movie(updated_movie, send_event):
updated_movie['updated_at_timestamp'] = datetime.now()
database.execute(
update(TableMovies).values(updated_movie)
.where(TableMovies.tmdbId == updated_movie['tmdbId']))
.where(TableMovies.radarrId == updated_movie['radarrId']))
except IntegrityError as e:
logging.error(f"BAZARR cannot update movie {updated_movie['path']} because of {e}")
else:
@ -66,7 +66,7 @@ def update_movie(updated_movie, send_event):
def get_movie_monitored_status(movie_id):
existing_movie_monitored = database.execute(
select(TableMovies.monitored)
.where(TableMovies.tmdbId == str(movie_id)))\
.where(TableMovies.radarrId == str(movie_id)))\
.first()
if existing_movie_monitored is None:
return True
@ -124,16 +124,16 @@ def update_movies(send_event=True):
return
else:
# Get current movies in DB
current_movies_id_db = [x.tmdbId for x in
current_movies_id_db = [x.radarrId for x in
database.execute(
select(TableMovies.tmdbId))
select(TableMovies.radarrId))
.all()]
current_movies_db_kv = [x.items() for x in [y._asdict()['TableMovies'].__dict__ for y in
database.execute(
select(TableMovies))
.all()]]
current_movies_radarr = [str(movie['tmdbId']) for movie in movies if movie['hasFile'] and
current_movies_radarr = [movie['id'] for movie in movies if movie['hasFile'] and
'movieFile' in movie and
(movie['movieFile']['size'] > MINIMUM_VIDEO_SIZE or
get_movie_file_size_from_db(movie['movieFile']['path']) > MINIMUM_VIDEO_SIZE)]
@ -143,7 +143,7 @@ def update_movies(send_event=True):
movies_deleted = []
if len(movies_to_delete):
try:
database.execute(delete(TableMovies).where(TableMovies.tmdbId.in_(movies_to_delete)))
database.execute(delete(TableMovies).where(TableMovies.radarrId.in_(movies_to_delete)))
except IntegrityError as e:
logging.error(f"BAZARR cannot delete movies because of {e}")
else:
@ -172,7 +172,7 @@ def update_movies(send_event=True):
if movie['hasFile'] is True:
if 'movieFile' in movie:
if sync_monitored:
if get_movie_monitored_status(movie['tmdbId']) != movie['monitored']:
if get_movie_monitored_status(movie['id']) != movie['monitored']:
# monitored status is not the same as our DB
trace(f"{i}: (Monitor Status Mismatch) {movie['title']}")
elif not movie['monitored']:
@ -184,7 +184,7 @@ def update_movies(send_event=True):
get_movie_file_size_from_db(movie['movieFile']['path']) > MINIMUM_VIDEO_SIZE):
# Add/update movies from Radarr that have a movie file to current movies list
trace(f"{i}: (Processing) {movie['title']}")
if str(movie['tmdbId']) in current_movies_id_db:
if movie['id'] in current_movies_id_db:
parsed_movie = movieParser(movie, action='update',
tags_dict=tagsDict,
language_profiles=language_profiles,

@ -34,7 +34,7 @@ def get_language_profiles():
def get_series_monitored_table():
series_monitored = database.execute(
select(TableShows.tvdbId, TableShows.monitored))\
select(TableShows.sonarrSeriesId, TableShows.monitored))\
.all()
series_dict = dict((x, y) for x, y in series_monitored)
return series_dict
@ -95,7 +95,7 @@ def update_series(send_event=True):
if sync_monitored:
try:
monitored_status_db = bool_map[series_monitored[show['tvdbId']]]
monitored_status_db = bool_map[series_monitored[show['id']]]
except KeyError:
monitored_status_db = None
if monitored_status_db is None:

@ -2,8 +2,11 @@
import json
from sqlalchemy import func
from app.config import settings
from app.database import TableShowsRootfolder, TableMoviesRootfolder, TableLanguagesProfiles, database, select
from app.database import (TableShowsRootfolder, TableMoviesRootfolder, TableLanguagesProfiles, database, select,
TableShows, TableMovies)
from app.event_handler import event_stream
from .path_mappings import path_mappings
from sonarr.rootfolder import check_sonarr_rootfolder
@ -66,4 +69,21 @@ def get_health_issues():
else:
languages_profile_ids.append(items['id'])
# check if there's at least one languages profile created
languages_profiles_count = database.execute(select(func.count(TableLanguagesProfiles.profileId))).scalar()
series_with_profile = database.execute(select(func.count(TableShows.sonarrSeriesId))
.where(TableShows.profileId.is_not(None))).scalar()
movies_with_profile = database.execute(select(func.count(TableMovies.radarrId))
.where(TableMovies.profileId.is_not(None))).scalar()
default_series_profile_empty = settings.general.serie_default_enabled and settings.general.serie_default_profile == ''
default_movies_profile_empty = settings.general.movie_default_enabled and settings.general.movie_default_profile == ''
if languages_profiles_count == 0:
health_issues.append({'object': 'Missing languages profile',
'issue': 'You must create at least one languages profile and assign it to your content.'})
elif languages_profiles_count > 0 and ((settings.general.use_sonarr and series_with_profile == 0 and default_series_profile_empty) or
(settings.general.use_radarr and movies_with_profile == 0 and default_movies_profile_empty)):
health_issues.append({'object': 'No assigned languages profile',
'issue': 'Although you have created at least one languages profile, you must assign it '
'to your content.'})
return health_issues

@ -9,4 +9,4 @@ From newest to oldest:
{{#each commits}}
- {{subject}}{{#if href}} [{{shorthash}}]({{href}}){{/if}}
{{/each}}
{{/each}}
{{/each}}

@ -9,4 +9,4 @@ From newest to oldest:
{{#each commits}}
- {{subject}}{{#if href}} [{{shorthash}}]({{href}}){{/if}}
{{/each}}
{{/each}}
{{/each}}

@ -3,7 +3,6 @@ from __future__ import absolute_import
import base64
import logging
import os
import traceback
import re
import zlib
import time
@ -411,6 +410,8 @@ def checked(fn, raise_api_limit=False):
except requests.RequestException as e:
status_code = e.response.status_code
if status_code == 503 and "Server under maintenance" in e.response.text:
status_code = 506
else:
status_code = int(response['status'][:3])
except:
@ -437,6 +438,8 @@ def checked(fn, raise_api_limit=False):
raise APIThrottled
if status_code == 503:
raise ServiceUnavailable(str(status_code))
if status_code == 506:
raise ServiceUnavailable("Server under maintenance")
if status_code != 200:
if response and "status" in response:
raise OpenSubtitlesError(response['status'])

@ -290,6 +290,10 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider):
if not title_id:
logger.debug(f'No match found for {title}')
@staticmethod
def is_real_forced(attributes):
return attributes['foreign_parts_only'] and not attributes['hearing_impaired']
def query(self, languages, video):
self.video = video
if self.use_hash:
@ -363,11 +367,11 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider):
# filter out forced subtitles or not depending on the required languages
if all([lang.forced for lang in languages]): # only forced
result['data'] = [x for x in result['data'] if x['attributes']['foreign_parts_only']]
result['data'] = [x for x in result['data'] if self.is_real_forced(x['attributes'])]
elif any([lang.forced for lang in languages]): # also forced
pass
else: # not forced
result['data'] = [x for x in result['data'] if not x['attributes']['foreign_parts_only']]
result['data'] = [x for x in result['data'] if not self.is_real_forced(x['attributes'])]
logger.debug(f"Query returned {len(result['data'])} subtitles")
@ -407,7 +411,7 @@ class OpenSubtitlesComProvider(ProviderRetryMixin, Provider):
if len(item['attributes']['files']):
subtitle = OpenSubtitlesComSubtitle(
language=Language.fromietf(from_opensubtitlescom(item['attributes']['language'])),
forced=item['attributes']['foreign_parts_only'],
forced=self.is_real_forced(item['attributes']),
hearing_impaired=item['attributes']['hearing_impaired'],
page_link=item['attributes']['url'],
file_id=item['attributes']['files'][0]['file_id'],

@ -5,18 +5,18 @@ import os
import io
import logging
import re
import rarfile
from random import randint
from zipfile import ZipFile, is_zipfile
from rarfile import RarFile, is_rarfile
from guessit import guessit
from time import sleep
from subliminal_patch.providers import Provider
from subliminal_patch.providers.mixins import ProviderSubtitleArchiveMixin
from subliminal_patch.subtitle import Subtitle, guess_matches
from subliminal_patch.utils import sanitize, fix_inconsistent_naming as _fix_inconsistent_naming
from .utils import FIRST_THOUSAND_OR_SO_USER_AGENTS as AGENT_LIST
from subliminal.exceptions import ProviderError
from subliminal_patch.exceptions import TooManyRequests
from subliminal.providers import ParserBeautifulSoup
from subliminal.video import Episode, Movie
from subliminal.subtitle import SUBTITLE_EXTENSIONS
@ -147,6 +147,10 @@ class TitrariProvider(Provider, ProviderSubtitleArchiveMixin):
params = self.getQueryParams(imdb_id, title, language)
search_response = self.session.get(self.api_url, params=params, timeout=15)
if search_response.status_code == 404 and 'Too many requests' in search_response.content:
raise TooManyRequests(search_response.content)
search_response.raise_for_status()
if not search_response.content:
@ -215,6 +219,8 @@ class TitrariProvider(Provider, ProviderSubtitleArchiveMixin):
ordered_subs = self.order(subtitles)
sleep(5) # prevent being blocked for too many requests
return ordered_subs
@staticmethod

@ -167,6 +167,7 @@ const SeriesEpisodesView: FunctionComponent = () => {
series.profileId === null ||
!available
}
loading={hasTask}
>
Search
</Toolbox.Button>
@ -195,7 +196,8 @@ const SeriesEpisodesView: FunctionComponent = () => {
series === undefined ||
series.episodeFileCount === 0 ||
series.profileId === null ||
!available
!available ||
hasTask
}
icon={faCloudUploadAlt}
onClick={() => openDropzone.current?.()}

@ -141,6 +141,7 @@ const MovieDetailView: FunctionComponent = () => {
<Toolbox.Button
icon={faSearch}
disabled={!isNumber(movie?.profileId)}
loading={hasTask}
onClick={() => {
if (movie) {
task.create(movie.title, TaskGroup.SearchSubtitle, action, {

Loading…
Cancel
Save