Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
morpheus65535 committed May 21, 2020
2 parents fa903e4 + 56f3eb3 commit 20c3a3c
Show file tree
Hide file tree
Showing 30 changed files with 804 additions and 521 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ cachefile.dbm
bazarr.pid
/venv
/data
/.vscode

# Allow
!*.dll
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ If you need something that is not already part of Bazarr, feel free to create a
* TVSubtitles
* Wizdom
* XSubs
* Yavka.net
* Zimuku

## Screenshot
Expand Down
191 changes: 45 additions & 146 deletions bazarr.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,26 @@

import os
import platform
import signal
import subprocess
import sys
import time
import atexit

from bazarr.get_args import args
from libs.six import PY3


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

if (int(python_version[0]) == minimum_py3_tuple[0] and int(python_version[1]) < minimum_py3_tuple[1]) or \
(int(python_version[0]) != minimum_py3_tuple[0] and int(python_version[0]) != minimum_py2_tuple[0]):
if int(python_version[0]) < minimum_py3_tuple[0]:
print("Python " + minimum_py3_str + " or greater required. "
"Current version is " + platform.python_version() + ". Please upgrade Python.")
sys.exit(1)
elif int(python_version[0]) == minimum_py2_tuple[0] and int(python_version[1]) < minimum_py2_tuple[1]:
print("Python " + minimum_py2_str + " or greater required. "
elif (int(python_version[0]) == minimum_py3_tuple[0] and int(python_version[1]) < minimum_py3_tuple[1]) or \
(int(python_version[0]) != minimum_py3_tuple[0]):
print("Python " + minimum_py3_str + " or greater required. "
"Current version is " + platform.python_version() + ". Please upgrade Python.")
sys.exit(1)

Expand All @@ -34,156 +31,58 @@ def check_python_version():
dir_name = os.path.dirname(__file__)


class ProcessRegistry:

def register(self, process):
pass

def unregister(self, process):
pass


class DaemonStatus(ProcessRegistry):

def __init__(self):
self.__should_stop = False
self.__processes = set()

def register(self, process):
self.__processes.add(process)

def unregister(self, process):
self.__processes.remove(process)

@staticmethod
def __wait_for_processes(processes, timeout):
"""
Waits all the provided processes for the specified amount of time in seconds.
"""
reference_ts = time.time()
elapsed = 0
remaining_processes = list(processes)
while elapsed < timeout and len(remaining_processes) > 0:
remaining_time = timeout - elapsed
for ep in list(remaining_processes):
if ep.poll() is not None:
remaining_processes.remove(ep)
else:
if remaining_time > 0:
if PY3:
try:
ep.wait(remaining_time)
remaining_processes.remove(ep)
except subprocess.TimeoutExpired:
pass
else:
# In python 2 there is no such thing as some mechanism to wait with a timeout
time.sleep(1)
elapsed = time.time() - reference_ts
remaining_time = timeout - elapsed
return remaining_processes

@staticmethod
def __send_signal(processes, signal_no, live_processes=None):
"""
Sends to every single of the specified processes the given signal and (if live_processes is not None) append to
it processes which are still alive.
"""
for ep in processes:
if ep.poll() is None:
if live_processes is not None:
live_processes.append(ep)
try:
ep.send_signal(signal_no)
except Exception as e:
print('Failed sending signal %s to process %s because of an unexpected error: %s' % (
signal_no, ep.pid, e))
return live_processes

def stop(self):
"""
Flags this instance as should stop and terminates as smoothly as possible children processes.
"""
self.__should_stop = True
live_processes = DaemonStatus.__send_signal(self.__processes, signal.SIGINT, list())
live_processes = DaemonStatus.__wait_for_processes(live_processes, 120)
DaemonStatus.__send_signal(live_processes, signal.SIGTERM)

def should_stop(self):
return self.__should_stop


def start_bazarr(process_registry=ProcessRegistry()):
def start_bazarr():
script = [sys.executable, "-u", os.path.normcase(os.path.join(dir_name, 'bazarr', 'main.py'))] + sys.argv[1:]

print("Bazarr starting...")
if PY3:
ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL)
else:
ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=None)
process_registry.register(ep)
try:
ep.wait()
process_registry.unregister(ep)
except KeyboardInterrupt:
pass
ep = subprocess.Popen(script, stdout=None, stderr=None, stdin=subprocess.DEVNULL)
atexit.register(lambda: ep.kill())


def check_status():
if os.path.exists(stopfile):
try:
os.remove(stopfile)
except Exception:
print('Unable to delete stop file.')
finally:
print('Bazarr exited.')
sys.exit(0)

if os.path.exists(restartfile):
try:
os.remove(restartfile)
except Exception:
print('Unable to delete restart file.')
else:
print("Bazarr is restarting...")
start_bazarr()


if __name__ == '__main__':
restartfile = os.path.normcase(os.path.join(args.config_dir, 'bazarr.restart'))
stopfile = os.path.normcase(os.path.join(args.config_dir, 'bazarr.stop'))
restartfile = os.path.join(args.config_dir, 'bazarr.restart')
stopfile = os.path.join(args.config_dir, 'bazarr.stop')

# Cleanup leftover files
try:
os.remove(restartfile)
except Exception:
except FileNotFoundError:
pass

try:
os.remove(stopfile)
except Exception:
except FileNotFoundError:
pass


def daemon(bazarr_runner=lambda: start_bazarr()):
if os.path.exists(stopfile):
try:
os.remove(stopfile)
except Exception:
print('Unable to delete stop file.')
else:
print('Bazarr exited.')
sys.exit(0)

if os.path.exists(restartfile):
try:
os.remove(restartfile)
except Exception:
print('Unable to delete restart file.')
else:
bazarr_runner()


bazarr_runner = lambda: start_bazarr()

should_stop = lambda: False

if PY3:
daemonStatus = DaemonStatus()

def shutdown():
# indicates that everything should stop
daemonStatus.stop()
# emulate a Ctrl C command on itself (bypasses the signal thing but, then, emulates the "Ctrl+C break")
os.kill(os.getpid(), signal.SIGINT)

signal.signal(signal.SIGTERM, lambda signal_no, frame: shutdown())

should_stop = lambda: daemonStatus.should_stop()
bazarr_runner = lambda: start_bazarr(daemonStatus)

bazarr_runner()
# Initial start of main bazarr process
print("Bazarr starting...")
start_bazarr()

# Keep the script running forever until stop is requested through term or keyboard interrupt
while not should_stop():
daemon(bazarr_runner)
time.sleep(1)
while True:
check_status()
try:
if sys.platform.startswith('win'):
time.sleep(5)
else:
os.wait()
except (KeyboardInterrupt, SystemExit):
pass
2 changes: 2 additions & 0 deletions bazarr/check_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def gitconfig():
logging.debug('BAZARR Settings git email')
config_write.set_value("user", "email", "[email protected]")

config_write.release()


def check_and_apply_update():
check_releases()
Expand Down
4 changes: 3 additions & 1 deletion bazarr/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@
},
'legendasdivx': {
'username': '',
'password': ''
'password': '',
'skip_wrong_fps': 'False'
},
'legendastv': {
'username': '',
Expand Down Expand Up @@ -150,6 +151,7 @@
settings = simpleconfigparser(defaults=defaults)
settings.read(os.path.join(args.config_dir, 'config', 'config.ini'))

settings.general.base_url = settings.general.base_url if settings.general.base_url else '/'
base_url = settings.general.base_url


Expand Down
24 changes: 22 additions & 2 deletions bazarr/get_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,24 @@

from get_args import args
from config import settings
from subliminal_patch.exceptions import TooManyRequests, APIThrottled, ParseResponseError
from subliminal_patch.exceptions import TooManyRequests, APIThrottled, ParseResponseError, IPAddressBlocked
from subliminal.exceptions import DownloadLimitExceeded, ServiceUnavailable
from subliminal import region as subliminal_cache_region

def time_until_end_of_day(dt=None):
# type: (datetime.datetime) -> datetime.timedelta
"""
Get timedelta until end of day on the datetime passed, or current time.
"""
if dt is None:
dt = datetime.datetime.now()
tomorrow = dt + datetime.timedelta(days=1)
return datetime.datetime.combine(tomorrow, datetime.time.min) - dt

hours_until_end_of_day = time_until_end_of_day().seconds // 3600 + 1

VALID_THROTTLE_EXCEPTIONS = (TooManyRequests, DownloadLimitExceeded, ServiceUnavailable, APIThrottled,
ParseResponseError)
ParseResponseError, IPAddressBlocked)
VALID_COUNT_EXCEPTIONS = ('TooManyRequests', 'ServiceUnavailable', 'APIThrottled')

PROVIDER_THROTTLE_MAP = {
Expand All @@ -32,9 +44,16 @@
"addic7ed": {
DownloadLimitExceeded: (datetime.timedelta(hours=3), "3 hours"),
TooManyRequests: (datetime.timedelta(minutes=5), "5 minutes"),
IPAddressBlocked: (datetime.timedelta(hours=1), "1 hours"),

},
"titulky": {
DownloadLimitExceeded: (datetime.timedelta(hours=3), "3 hours")
},
"legendasdivx": {
TooManyRequests: (datetime.timedelta(hours=3), "3 hours"),
DownloadLimitExceeded: (datetime.timedelta(hours=hours_until_end_of_day), "{} hours".format(str(hours_until_end_of_day))),
IPAddressBlocked: (datetime.timedelta(hours=hours_until_end_of_day), "{} hours".format(str(hours_until_end_of_day))),
}
}

Expand Down Expand Up @@ -116,6 +135,7 @@ def get_providers_auth():
},
'legendasdivx': {'username': settings.legendasdivx.username,
'password': settings.legendasdivx.password,
'skip_wrong_fps': settings.legendasdivx.getboolean('skip_wrong_fps'),
},
'legendastv': {'username': settings.legendastv.username,
'password': settings.legendastv.password,
Expand Down
26 changes: 23 additions & 3 deletions bazarr/get_subtitle.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ def download_subtitle(path, language, audio_language, hi, forced, providers, pro
path_decoder=force_unicode
)
except Exception as e:
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path + ': ' + repr(e))
pass
else:
saved_any = True
Expand Down Expand Up @@ -473,11 +473,14 @@ def manual_download_subtitle(path, language, audio_language, hi, forced, subtitl
logging.debug('BAZARR Ended manually downloading Subtitles for file: ' + path)


def manual_upload_subtitle(path, language, forced, title, scene_name, media_type, subtitle):
def manual_upload_subtitle(path, language, forced, title, scene_name, media_type, subtitle, audio_language):
logging.debug('BAZARR Manually uploading subtitles for this file: ' + path)

single = settings.general.getboolean('single_language')

use_postprocessing = settings.general.getboolean('use_postprocessing')
postprocessing_cmd = settings.general.postprocessing_cmd

chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
'win') and settings.general.getboolean('chmod_enabled') else None

Expand Down Expand Up @@ -540,6 +543,20 @@ def manual_upload_subtitle(path, language, forced, title, scene_name, media_type
os.chmod(subtitle_path, chmod)

message = language_from_alpha3(language) + (" forced" if forced else "") + " Subtitles manually uploaded."

uploaded_language_code3 = language
uploaded_language = language_from_alpha3(uploaded_language_code3)
uploaded_language_code2 = alpha2_from_alpha3(uploaded_language_code3)
audio_language_code2 = alpha2_from_language(audio_language)
audio_language_code3 = alpha3_from_language(audio_language)


if use_postprocessing is True:
command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language,
uploaded_language_code2, uploaded_language_code3, audio_language,
audio_language_code2, audio_language_code3, forced)
postprocessing(command, path)


if media_type == 'series':
reversed_path = path_replace_reverse(path)
Expand Down Expand Up @@ -973,7 +990,10 @@ def refine_from_ffprobe(path, video):
video.video_codec = data['video'][0]['codec']
if 'frame_rate' in data['video'][0]:
if not video.fps:
video.fps = data['video'][0]['frame_rate']
if isinstance(data['video'][0]['frame_rate'], float):
video.fps = data['video'][0]['frame_rate']
else:
video.fps = data['video'][0]['frame_rate'].magnitude

if 'audio' not in data:
logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!')
Expand Down
Loading

0 comments on commit 20c3a3c

Please sign in to comment.