forked from LBRYCommunity/lbry-sdk
Fixed check_video.py on Windows
using a cross-platform workaround fixed proactor use in the SDK fixed linter
This commit is contained in:
parent
47e8f74da9
commit
a90b60799a
4 changed files with 44 additions and 20 deletions
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import platform
|
||||||
import sys
|
import sys
|
||||||
import typing
|
import typing
|
||||||
import logging
|
import logging
|
||||||
|
@ -461,6 +462,13 @@ class BaseConfig:
|
||||||
if self.persisted.upgrade():
|
if self.persisted.upgrade():
|
||||||
self.persisted.save()
|
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):
|
class TranscodeConfig(BaseConfig):
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,8 @@ def setup_logging(logger: logging.Logger, args: argparse.Namespace, conf: Config
|
||||||
|
|
||||||
|
|
||||||
def run_daemon(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()
|
loop = asyncio.get_event_loop()
|
||||||
if args.verbose is not None:
|
if args.verbose is not None:
|
||||||
loop.set_debug(True)
|
loop.set_debug(True)
|
||||||
|
|
|
@ -21,7 +21,8 @@ class VideoFileAnalyzer:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
async def _execute(self, command, arguments):
|
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=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE)
|
||||||
stdout, stderr = await process.communicate() # returns when the streams are closed
|
stdout, stderr = await process.communicate() # returns when the streams are closed
|
||||||
return stdout.decode() + stderr.decode(), process.returncode
|
return stdout.decode() + stderr.decode(), process.returncode
|
||||||
|
@ -34,7 +35,7 @@ class VideoFileAnalyzer:
|
||||||
code = -1
|
code = -1
|
||||||
version = ""
|
version = ""
|
||||||
if code != 0 or not version.startswith(name):
|
if code != 0 or not version.startswith(name):
|
||||||
raise Exception(f"Unable to locate or run {name}. Please install FFmpeg "
|
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")
|
f"and ensure that it is callable via PATH or conf.ffmpeg_folder")
|
||||||
return version
|
return version
|
||||||
|
|
||||||
|
@ -54,7 +55,7 @@ class VideoFileAnalyzer:
|
||||||
|
|
||||||
def _verify_container(self, scan_data: json):
|
def _verify_container(self, scan_data: json):
|
||||||
container = scan_data["format"]["format_name"]
|
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"]):
|
if not self._matches(container.split(","), ["webm", "mp4", "3gp", "ogg"]):
|
||||||
return "Container format is not in the approved list of WebM, MP4. " \
|
return "Container format is not in the approved list of WebM, MP4. " \
|
||||||
f"Actual: {container} [{scan_data['format']['format_long_name']}]"
|
f"Actual: {container} [{scan_data['format']['format_long_name']}]"
|
||||||
|
@ -65,7 +66,7 @@ class VideoFileAnalyzer:
|
||||||
if stream["codec_type"] != "video":
|
if stream["codec_type"] != "video":
|
||||||
continue
|
continue
|
||||||
codec = stream["codec_name"]
|
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"]):
|
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. " \
|
return "Video codec is not in the approved list of H264, VP8, VP9, AV1, Theora. " \
|
||||||
f"Actual: {codec} [{stream['codec_long_name']}]"
|
f"Actual: {codec} [{stream['codec_long_name']}]"
|
||||||
|
@ -82,7 +83,7 @@ class VideoFileAnalyzer:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
bit_rate = float(scan_data["format"]["bit_rate"])
|
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
|
pixels = -1.0
|
||||||
for stream in scan_data["streams"]:
|
for stream in scan_data["streams"]:
|
||||||
if stream["codec_type"] == "video":
|
if stream["codec_type"] == "video":
|
||||||
|
@ -114,7 +115,7 @@ class VideoFileAnalyzer:
|
||||||
if stream["codec_type"] != "audio":
|
if stream["codec_type"] != "audio":
|
||||||
continue
|
continue
|
||||||
codec = stream["codec_name"]
|
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"]):
|
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. " \
|
return "Audio codec is not in the approved list of AAC, FLAC, MP3, Vorbis, and Opus. " \
|
||||||
f"Actual: {codec} [{stream['codec_long_name']}]"
|
f"Actual: {codec} [{stream['codec_long_name']}]"
|
||||||
|
@ -143,7 +144,7 @@ class VideoFileAnalyzer:
|
||||||
return "Audio is at least five dB lower than prime. " \
|
return "Audio is at least five dB lower than prime. " \
|
||||||
f"Actual max: {max_volume}, mean: {mean_volume}"
|
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 ""
|
return ""
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import sys
|
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.conf import TranscodeConfig
|
||||||
from lbry.file_analysis import VideoFileAnalyzer
|
from lbry.file_analysis import VideoFileAnalyzer
|
||||||
|
|
||||||
|
@ -19,21 +21,15 @@ def enable_logging():
|
||||||
root.addHandler(handler)
|
root.addHandler(handler)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def process_video(analyzer, video_file):
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Usage: <path to video file>", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
video_file = sys.argv[1]
|
|
||||||
|
|
||||||
enable_logging()
|
|
||||||
conf = TranscodeConfig()
|
|
||||||
analyzer = VideoFileAnalyzer(conf)
|
|
||||||
try:
|
try:
|
||||||
await analyzer.verify_or_repair(True, False, video_file)
|
await analyzer.verify_or_repair(True, False, video_file)
|
||||||
print("No concerns. Ship it!")
|
print("No concerns. Ship it!")
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
print(str(e))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(str(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":
|
if transcode == "y":
|
||||||
try:
|
try:
|
||||||
new_video_file = await analyzer.verify_or_repair(True, True, video_file)
|
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))
|
print("Unable to complete the transcode. Message: ", str(e))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print("Usage: check_video.py <path to video file>", 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__':
|
if __name__ == '__main__':
|
||||||
asyncio.run(main())
|
main()
|
||||||
|
|
Loading…
Reference in a new issue