Skip to content

Commit

Permalink
Merge development into master
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] authored Feb 4, 2024
2 parents 8282899 + 4029c9f commit 38094e6
Show file tree
Hide file tree
Showing 211 changed files with 7,091 additions and 4,132 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,23 @@ If you need something that is not already part of Bazarr, feel free to create a
## Supported subtitles providers:

- Addic7ed
- Argenteam
- Assrt
- BetaSeries
- BSplayer
- Embedded Subtitles
- Gestdown.info
- GreekSubs
- GreekSubtitles
- HDBits.org
- Hosszupuska
- LegendasDivx
- Karagarga.in
- Ktuvit (Get `hashed_password` using method described [here](https://github.com/XBMCil/service.subtitles.ktuvit))
- LegendasDivx
- Napiprojekt
- Napisy24
- Nekur
- OpenSubtitles.org
- OpenSubtitles.com
- OpenSubtitles.org (VIP users only)
- Podnapisi
- RegieLive
- Sous-Titres.eu
Expand All @@ -79,7 +80,6 @@ If you need something that is not already part of Bazarr, feel free to create a
- Subtitrari-noi.ro
- subtitri.id.lv
- Subtitulamos.tv
- Sucha
- Supersubtitles
- Titlovi
- Titrari.ro
Expand All @@ -100,4 +100,4 @@ If you need something that is not already part of Bazarr, feel free to create a
### License

- [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
- Copyright 2010-2019
- Copyright 2010-2024
23 changes: 14 additions & 9 deletions bazarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

def check_python_version():
python_version = platform.python_version_tuple()
minimum_py3_tuple = (3, 7, 0)
minimum_py3_tuple = (3, 8, 0)
minimum_py3_str = ".".join(str(i) for i in minimum_py3_tuple)

if int(python_version[0]) < minimum_py3_tuple[0]:
Expand Down Expand Up @@ -52,22 +52,27 @@ def get_python_path():

def end_child_process(ep):
try:
ep.kill()
if os.name != 'nt':
try:
ep.send_signal(signal.SIGINT)
except ProcessLookupError:
pass
else:
import win32api
import win32con
try:
win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, ep.pid)
except KeyboardInterrupt:
pass
except:
pass

def terminate_child_process(ep):
try:
ep.terminate()
except:
pass


def start_bazarr():
script = [get_python_path(), "-u", os.path.normcase(os.path.join(dir_name, 'bazarr', 'main.py'))] + sys.argv[1:]
ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL)
atexit.register(end_child_process, ep=ep)
signal.signal(signal.SIGTERM, lambda signal_no, frame: terminate_child_process(ep))
signal.signal(signal.SIGTERM, lambda signal_no, frame: end_child_process(ep))


def check_status():
Expand Down
4 changes: 2 additions & 2 deletions bazarr/api/episodes/blacklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ def post(self):

delete_request_parser = reqparse.RequestParser()
delete_request_parser.add_argument('all', type=str, required=False, help='Empty episodes subtitles blacklist')
delete_request_parser.add_argument('provider', type=str, required=True, help='Provider name')
delete_request_parser.add_argument('subs_id', type=str, required=True, help='Subtitles ID')
delete_request_parser.add_argument('provider', type=str, required=False, help='Provider name')
delete_request_parser.add_argument('subs_id', type=str, required=False, help='Subtitles ID')

@authenticate
@api_ns_episodes_blacklist.doc(parser=delete_request_parser)
Expand Down
4 changes: 2 additions & 2 deletions bazarr/api/movies/blacklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ def post(self):

delete_request_parser = reqparse.RequestParser()
delete_request_parser.add_argument('all', type=str, required=False, help='Empty movies subtitles blacklist')
delete_request_parser.add_argument('provider', type=str, required=True, help='Provider name')
delete_request_parser.add_argument('subs_id', type=str, required=True, help='Subtitles ID')
delete_request_parser.add_argument('provider', type=str, required=False, help='Provider name')
delete_request_parser.add_argument('subs_id', type=str, required=False, help='Subtitles ID')

@authenticate
@api_ns_movies_blacklist.doc(parser=delete_request_parser)
Expand Down
102 changes: 87 additions & 15 deletions bazarr/api/subtitles/subtitles.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
import sys
import gc

from flask_restx import Resource, Namespace, reqparse
from flask_restx import Resource, Namespace, reqparse, fields, marshal

from app.database import TableEpisodes, TableMovies, database, select
from languages.get_languages import alpha3_from_alpha2
from utilities.path_mappings import path_mappings
from utilities.video_analyzer import subtitles_sync_references
from subtitles.tools.subsyncer import SubSyncer
from subtitles.tools.translate import translate_subtitles_file
from subtitles.tools.mods import subtitles_apply_mods
from subtitles.indexer.series import store_subtitles
from subtitles.indexer.movies import store_subtitles_movie
from app.config import settings
from app.config import settings, empty_values
from app.event_handler import event_stream

from ..utils import authenticate
Expand All @@ -25,17 +26,77 @@

@api_ns_subtitles.route('subtitles')
class Subtitles(Resource):
get_request_parser = reqparse.RequestParser()
get_request_parser.add_argument('subtitlesPath', type=str, required=True, help='External subtitles file path')
get_request_parser.add_argument('sonarrEpisodeId', type=int, required=False, help='Sonarr Episode ID')
get_request_parser.add_argument('radarrMovieId', type=int, required=False, help='Radarr Movie ID')

audio_tracks_data_model = api_ns_subtitles.model('audio_tracks_data_model', {
'stream': fields.String(),
'name': fields.String(),
'language': fields.String(),
})

embedded_subtitles_data_model = api_ns_subtitles.model('embedded_subtitles_data_model', {
'stream': fields.String(),
'name': fields.String(),
'language': fields.String(),
'forced': fields.Boolean(),
'hearing_impaired': fields.Boolean(),
})

external_subtitles_data_model = api_ns_subtitles.model('external_subtitles_data_model', {
'name': fields.String(),
'path': fields.String(),
'language': fields.String(),
'forced': fields.Boolean(),
'hearing_impaired': fields.Boolean(),
})

get_response_model = api_ns_subtitles.model('SubtitlesGetResponse', {
'audio_tracks': fields.Nested(audio_tracks_data_model),
'embedded_subtitles_tracks': fields.Nested(embedded_subtitles_data_model),
'external_subtitles_tracks': fields.Nested(external_subtitles_data_model),
})

@authenticate
@api_ns_subtitles.response(200, 'Success')
@api_ns_subtitles.response(401, 'Not Authenticated')
@api_ns_subtitles.doc(parser=get_request_parser)
def get(self):
"""Return available audio and embedded subtitles tracks with external subtitles. Used for manual subsync
modal"""
args = self.get_request_parser.parse_args()
subtitlesPath = args.get('subtitlesPath')
episodeId = args.get('sonarrEpisodeId', None)
movieId = args.get('radarrMovieId', None)

result = subtitles_sync_references(subtitles_path=subtitlesPath, sonarr_episode_id=episodeId,
radarr_movie_id=movieId)

return marshal(result, self.get_response_model, envelope='data')

patch_request_parser = reqparse.RequestParser()
patch_request_parser.add_argument('action', type=str, required=True,
help='Action from ["sync", "translate" or mods name]')
patch_request_parser.add_argument('language', type=str, required=True, help='Language code2')
patch_request_parser.add_argument('path', type=str, required=True, help='Subtitles file path')
patch_request_parser.add_argument('type', type=str, required=True, help='Media type from ["episode", "movie"]')
patch_request_parser.add_argument('id', type=int, required=True, help='Media ID (episodeId, radarrId)')
patch_request_parser.add_argument('forced', type=str, required=False, help='Forced subtitles from ["True", "False"]')
patch_request_parser.add_argument('forced', type=str, required=False,
help='Forced subtitles from ["True", "False"]')
patch_request_parser.add_argument('hi', type=str, required=False, help='HI subtitles from ["True", "False"]')
patch_request_parser.add_argument('original_format', type=str, required=False,
help='Use original subtitles format from ["True", "False"]')
patch_request_parser.add_argument('reference', type=str, required=False,
help='Reference to use for sync from video file track number (a:0) or some '
'subtitles file path')
patch_request_parser.add_argument('max_offset_seconds', type=str, required=False,
help='Maximum offset seconds to allow')
patch_request_parser.add_argument('no_fix_framerate', type=str, required=False,
help='Don\'t try to fix framerate from ["True", "False"]')
patch_request_parser.add_argument('gss', type=str, required=False,
help='Use Golden-Section Search from ["True", "False"]')

@authenticate
@api_ns_subtitles.doc(parser=patch_request_parser)
Expand Down Expand Up @@ -79,19 +140,30 @@ def patch(self):
video_path = path_mappings.path_replace_movie(metadata.path)

if action == 'sync':
sync_kwargs = {
'video_path': video_path,
'srt_path': subtitles_path,
'srt_lang': language,
'reference': args.get('reference') if args.get('reference') not in empty_values else video_path,
'max_offset_seconds': args.get('max_offset_seconds') if args.get('max_offset_seconds') not in
empty_values else str(settings.subsync.max_offset_seconds),
'no_fix_framerate': args.get('no_fix_framerate') == 'True',
'gss': args.get('gss') == 'True',
}

subsync = SubSyncer()
if media_type == 'episode':
subsync.sync(video_path=video_path, srt_path=subtitles_path,
srt_lang=language, media_type='series', sonarr_series_id=metadata.sonarrSeriesId,
sonarr_episode_id=id)
else:
try:
subsync.sync(video_path=video_path, srt_path=subtitles_path,
srt_lang=language, media_type='movies', radarr_id=id)
except OSError:
return 'Unable to edit subtitles file. Check logs.', 409
del subsync
gc.collect()
try:
if media_type == 'episode':
sync_kwargs['sonarr_series_id'] = metadata.sonarrSeriesId
sync_kwargs['sonarr_episode_id'] = id
else:
sync_kwargs['radarr_id'] = id
subsync.sync(**sync_kwargs)
except OSError:
return 'Unable to edit subtitles file. Check logs.', 409
finally:
del subsync
gc.collect()
elif action == 'translate':
from_language = subtitles_lang_from_filename(subtitles_path)
dest_language = language
Expand Down
2 changes: 1 addition & 1 deletion bazarr/app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def create_app():
app.config["DEBUG"] = False

socketio.init_app(app, path=f'{base_url.rstrip("/")}/api/socket.io', cors_allowed_origins='*',
async_mode='threading', allow_upgrades=False, transports='polling')
async_mode='threading', allow_upgrades=False, transports='polling', engineio_logger=False)

@app.errorhandler(404)
def page_not_found(_):
Expand Down
Loading

0 comments on commit 38094e6

Please sign in to comment.