diff --git a/lbry/conf.py b/lbry/conf.py index 09810d6a3..5ab16951f 100644 --- a/lbry/conf.py +++ b/lbry/conf.py @@ -1,5 +1,6 @@ import os import re +import platform import sys import typing import logging @@ -461,6 +462,13 @@ class BaseConfig: if self.persisted.upgrade(): self.persisted.save() + @property + def needs_proactor(self): + major, minor, _ = platform.python_version_tuple() + if int(major) > 3 or (int(major) == 3 and int(minor) > 7): + return False + return platform.system() == "Windows" + class TranscodeConfig(BaseConfig): diff --git a/lbry/extras/cli.py b/lbry/extras/cli.py index acdd1933e..8c3699826 100644 --- a/lbry/extras/cli.py +++ b/lbry/extras/cli.py @@ -262,6 +262,8 @@ def setup_logging(logger: logging.Logger, args: argparse.Namespace, conf: Config def run_daemon(args: argparse.Namespace, conf: Config): + if conf.needs_proactor: + asyncio.set_event_loop(asyncio.ProactorEventLoop()) loop = asyncio.get_event_loop() if args.verbose is not None: loop.set_debug(True) diff --git a/lbry/file_analysis.py b/lbry/file_analysis.py index 135942411..1e94d6da8 100644 --- a/lbry/file_analysis.py +++ b/lbry/file_analysis.py @@ -21,7 +21,8 @@ class VideoFileAnalyzer: return False async def _execute(self, command, arguments): - process = await asyncio.create_subprocess_exec(self._conf.ffmpeg_folder + command, *shlex.split(arguments), + args = shlex.split(arguments) + process = await asyncio.create_subprocess_exec(self._conf.ffmpeg_folder + command, *args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() # returns when the streams are closed return stdout.decode() + stderr.decode(), process.returncode @@ -34,8 +35,8 @@ class VideoFileAnalyzer: code = -1 version = "" if code != 0 or not version.startswith(name): - raise Exception(f"Unable to locate or run {name}. Please install FFmpeg " - f"and ensure that it is callable via PATH or conf.ffmpeg_folder") + raise FileNotFoundError(f"Unable to locate or run {name}. Please install FFmpeg " + f"and ensure that it is callable via PATH or conf.ffmpeg_folder") return version async def _verify_ffmpeg_installed(self): @@ -54,7 +55,7 @@ class VideoFileAnalyzer: def _verify_container(self, scan_data: json): container = scan_data["format"]["format_name"] - log.debug(" Detected container %s", container) + log.debug(" Detected container is %s", container) if not self._matches(container.split(","), ["webm", "mp4", "3gp", "ogg"]): return "Container format is not in the approved list of WebM, MP4. " \ f"Actual: {container} [{scan_data['format']['format_long_name']}]" @@ -65,7 +66,7 @@ class VideoFileAnalyzer: if stream["codec_type"] != "video": continue codec = stream["codec_name"] - log.debug(" Detected video codec %s encoding %s", codec, stream["pix_fmt"]) + log.debug(" Detected video codec is %s, format is %s", codec, stream["pix_fmt"]) if not self._matches(codec.split(","), ["h264", "vp8", "vp9", "av1", "theora"]): return "Video codec is not in the approved list of H264, VP8, VP9, AV1, Theora. " \ f"Actual: {codec} [{stream['codec_long_name']}]" @@ -82,7 +83,7 @@ class VideoFileAnalyzer: return "" bit_rate = float(scan_data["format"]["bit_rate"]) - log.debug(" Detected bitrate %s Mbps", str(bit_rate / 1000000.0)) + log.debug(" Detected bitrate is %s Mbps", str(bit_rate / 1000000.0)) pixels = -1.0 for stream in scan_data["streams"]: if stream["codec_type"] == "video": @@ -114,7 +115,7 @@ class VideoFileAnalyzer: if stream["codec_type"] != "audio": continue codec = stream["codec_name"] - log.debug(" Detected audio codec %s", codec) + log.debug(" Detected audio codec is %s", codec) if not self._matches(codec.split(","), ["aac", "mp3", "flac", "vorbis", "opus"]): return "Audio codec is not in the approved list of AAC, FLAC, MP3, Vorbis, and Opus. " \ f"Actual: {codec} [{stream['codec_long_name']}]" @@ -143,7 +144,7 @@ class VideoFileAnalyzer: return "Audio is at least five dB lower than prime. " \ f"Actual max: {max_volume}, mean: {mean_volume}" - log.debug(" Detected audio volume mean, max as %f dB, %f dB", mean_volume, max_volume) + log.debug(" Detected audio volume has mean, max of %f, %f dB", mean_volume, max_volume) return "" diff --git a/scripts/check_video.py b/scripts/check_video.py index 1a99a7251..f3215060c 100755 --- a/scripts/check_video.py +++ b/scripts/check_video.py @@ -3,7 +3,9 @@ import asyncio import logging import sys -import lbry.wallet # just to make the following line work: + +# noinspection PyUnresolvedReferences +import lbry.wallet # needed to make the following line work (it's a bug): from lbry.conf import TranscodeConfig from lbry.file_analysis import VideoFileAnalyzer @@ -19,21 +21,15 @@ def enable_logging(): root.addHandler(handler) -async def main(): - if len(sys.argv) < 2: - print("Usage: ", file=sys.stderr) - sys.exit(1) - video_file = sys.argv[1] - - enable_logging() - conf = TranscodeConfig() - analyzer = VideoFileAnalyzer(conf) +async def process_video(analyzer, video_file): try: await analyzer.verify_or_repair(True, False, video_file) print("No concerns. Ship it!") + except FileNotFoundError as e: + print(str(e)) except Exception as e: print(str(e)) - transcode = input("Would you like repair this via transcode now? [y/N] ") + transcode = input("Would you like to make a repaired clone now? [y/N] ") if transcode == "y": try: new_video_file = await analyzer.verify_or_repair(True, True, video_file) @@ -42,5 +38,22 @@ async def main(): print("Unable to complete the transcode. Message: ", str(e)) +def main(): + if len(sys.argv) < 2: + print("Usage: check_video.py ", file=sys.stderr) + sys.exit(1) + + enable_logging() + + video_file = sys.argv[1] + conf = TranscodeConfig() + analyzer = VideoFileAnalyzer(conf) + loop = asyncio.ProactorEventLoop() if conf.needs_proactor else asyncio.get_event_loop() + try: + loop.run_until_complete(process_video(analyzer, video_file)) + except KeyboardInterrupt: + pass + + if __name__ == '__main__': - asyncio.run(main()) + main()