mirror of
https://github.com/clinton-hall/nzbToMedia.git
synced 2025-01-08 04:00:03 -08:00
1214 lines
58 KiB
Python
1214 lines
58 KiB
Python
# pylint: disable=too-many-lines
|
|
from __future__ import annotations
|
|
|
|
import errno
|
|
import json
|
|
import logging
|
|
import os
|
|
import pathlib
|
|
import platform
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
from subprocess import DEVNULL
|
|
from subprocess import PIPE
|
|
|
|
from babelfish import Language
|
|
|
|
import nzb2media
|
|
from nzb2media.utils.files import list_media_files
|
|
from nzb2media.utils.paths import make_dir
|
|
|
|
log = logging.getLogger(__name__)
|
|
log.addHandler(logging.NullHandler())
|
|
|
|
MOUNTED = None
|
|
GETSUBS = False
|
|
TRANSCODE = None
|
|
CONCAT = None
|
|
DUPLICATE = None
|
|
IGNOREEXTENSIONS = []
|
|
VEXTENSION = None
|
|
OUTPUTVIDEOPATH = None
|
|
PROCESSOUTPUT = False
|
|
GENERALOPTS: list[str] = []
|
|
OTHEROPTS: list[str] = []
|
|
ALANGUAGE = None
|
|
AINCLUDE = False
|
|
SLANGUAGES: list[str] = []
|
|
SINCLUDE = False
|
|
SUBSDIR = None
|
|
ALLOWSUBS = False
|
|
SEXTRACT = False
|
|
SEMBED = False
|
|
BURN = False
|
|
DEFAULTS = None
|
|
VCODEC = None
|
|
VCODEC_ALLOW = []
|
|
VPRESET = None
|
|
VFRAMERATE = None
|
|
VBITRATE = None
|
|
VLEVEL = None
|
|
VCRF = None
|
|
VRESOLUTION = None
|
|
ACODEC = None
|
|
ACODEC_ALLOW = []
|
|
ACHANNELS = None
|
|
ABITRATE = None
|
|
ACODEC2 = None
|
|
ACODEC2_ALLOW: list[str] = []
|
|
ACHANNELS2 = None
|
|
ABITRATE2 = None
|
|
ACODEC3 = None
|
|
ACODEC3_ALLOW = []
|
|
ACHANNELS3 = None
|
|
ABITRATE3 = None
|
|
SCODEC = None
|
|
OUTPUTFASTSTART = None
|
|
OUTPUTQUALITYPERCENT = None
|
|
HWACCEL = False
|
|
|
|
|
|
def is_video_good(video: pathlib.Path, status, require_lan=None):
|
|
file_ext = video.suffix
|
|
disable = False
|
|
if file_ext not in nzb2media.MEDIA_CONTAINER or not nzb2media.tool.FFPROBE or not nzb2media.CHECK_MEDIA or file_ext in {'.iso'} or (status > 0 and nzb2media.NOEXTRACTFAILED):
|
|
disable = True
|
|
else:
|
|
test_details, res = get_video_details(nzb2media.TEST_FILE)
|
|
if res or test_details.get('error'):
|
|
disable = True
|
|
log.info('DISABLED: ffprobe failed to analyse test file. Stopping corruption check.')
|
|
if test_details.get('streams'):
|
|
vid_streams = [item for item in test_details['streams'] if 'codec_type' in item and item['codec_type'] == 'video']
|
|
aud_streams = [item for item in test_details['streams'] if 'codec_type' in item and item['codec_type'] == 'audio']
|
|
if not (len(vid_streams) > 0 and len(aud_streams) > 0):
|
|
disable = True
|
|
log.info('DISABLED: ffprobe failed to analyse streams from test file. Stopping corruption check.')
|
|
if disable:
|
|
if status:
|
|
# if the download was 'failed', assume bad.
|
|
# If it was successful, assume good.
|
|
return False
|
|
return True
|
|
log.info(f'Checking [{video.name}] for corruption, please stand by ...')
|
|
video_details, result = get_video_details(video)
|
|
if result:
|
|
log.error(f'FAILED: [{video.name}] is corrupted!')
|
|
return False
|
|
if video_details.get('error'):
|
|
error_details = video_details.get('error')
|
|
log.info(f'FAILED: [{video.name}] returned error [{error_details}].')
|
|
return False
|
|
if video_details.get('streams'):
|
|
video_streams = [item for item in video_details['streams'] if item['codec_type'] == 'video']
|
|
audio_streams = [item for item in video_details['streams'] if item['codec_type'] == 'audio']
|
|
if require_lan:
|
|
valid_audio = [item for item in audio_streams if 'tags' in item and 'language' in item['tags'] and item['tags']['language'] in require_lan]
|
|
else:
|
|
valid_audio = audio_streams
|
|
if len(video_streams) > 0 and len(valid_audio) > 0:
|
|
log.info(f'SUCCESS: [{video.name}] has no corruption.')
|
|
return True
|
|
log.info(f'FAILED: [{video.name}] has {len(video_streams)} video streams and {len(audio_streams)} audio streams. Assume corruption.')
|
|
return False
|
|
|
|
|
|
def zip_out(file, img):
|
|
if os.path.isfile(file):
|
|
cmd = ['cat', file]
|
|
else:
|
|
cmd = [os.fspath(nzb2media.tool.SEVENZIP), '-so', 'e', img, file]
|
|
try:
|
|
with subprocess.Popen(cmd, stdout=PIPE, stderr=DEVNULL) as proc:
|
|
return proc
|
|
except Exception:
|
|
log.error(f'Extracting [{file}] has failed')
|
|
return None
|
|
|
|
|
|
def get_video_details(videofile, img=None):
|
|
video_details = {}
|
|
result = 1
|
|
file = videofile
|
|
if not nzb2media.tool.FFPROBE:
|
|
return video_details, result
|
|
print_format = '-of' if 'avprobe' in nzb2media.tool.FFPROBE.name else '-print_format'
|
|
try:
|
|
if img:
|
|
videofile = '-'
|
|
command = [os.fspath(nzb2media.tool.FFPROBE), '-v', 'quiet', print_format, 'json', '-show_format', '-show_streams', '-show_error', videofile]
|
|
print_cmd(command)
|
|
if img:
|
|
procin = zip_out(file, img)
|
|
with subprocess.Popen(command, stdout=PIPE, stdin=procin.stdout) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
result = proc.returncode
|
|
procin.stdout.close()
|
|
else:
|
|
with subprocess.Popen(command, stdout=PIPE) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
result = proc.returncode
|
|
video_details = json.loads(proc_out.decode())
|
|
except Exception:
|
|
try: # try this again without -show error in case of ffmpeg limitation
|
|
command = [os.fspath(nzb2media.tool.FFPROBE), '-v', 'quiet', print_format, 'json', '-show_format', '-show_streams', videofile]
|
|
print_cmd(command)
|
|
if img:
|
|
procin = zip_out(file, img)
|
|
with subprocess.Popen(command, stdout=PIPE, stdin=procin.stdout) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
result = proc.returncode
|
|
procin.stdout.close()
|
|
else:
|
|
with subprocess.Popen(command, stdout=PIPE) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
result = proc.returncode
|
|
video_details = json.loads(proc_out.decode())
|
|
except Exception:
|
|
log.error(f'Checking [{file}] has failed')
|
|
return video_details, result
|
|
|
|
|
|
def check_vid_file(video_details, result):
|
|
if result:
|
|
return False
|
|
if video_details.get('error'):
|
|
return False
|
|
if not video_details.get('streams'):
|
|
return False
|
|
video_streams = [item for item in video_details['streams'] if item['codec_type'] == 'video']
|
|
audio_streams = [item for item in video_details['streams'] if item['codec_type'] == 'audio']
|
|
if len(video_streams) > 0 and len(audio_streams) > 0:
|
|
return True
|
|
return False
|
|
|
|
|
|
def build_commands(file, new_dir, movie_name):
|
|
global VEXTENSION
|
|
if isinstance(file, str):
|
|
input_file = file
|
|
if 'concat:' in file:
|
|
file = file.split('|')[0].replace('concat:', '')
|
|
video_details, result = get_video_details(file)
|
|
directory, name = os.path.split(file)
|
|
name, ext = os.path.splitext(name)
|
|
check = re.match('VTS_([0-9][0-9])_[0-9]+', name)
|
|
if check and CONCAT:
|
|
name = movie_name
|
|
elif check:
|
|
name = f'{movie_name}.cd{check.groups()[0]}'
|
|
elif CONCAT and re.match('(.+)[cC][dD][0-9]', name):
|
|
name = re.sub('([ ._=:-]+[cC][dD][0-9])', '', name)
|
|
if ext == VEXTENSION and new_dir == directory: # we need to change the name to prevent overwriting itself.
|
|
VEXTENSION = f'-transcoded{VEXTENSION}' # adds '-transcoded.ext'
|
|
new_file = file
|
|
else:
|
|
img, data = next(file.items())
|
|
name = data['name']
|
|
new_file = []
|
|
rem_vid = []
|
|
for vid in data['files']:
|
|
video_details, result = get_video_details(vid, img)
|
|
if not check_vid_file(video_details, result):
|
|
# lets not transcode menu or other clips that don't have audio and video.
|
|
rem_vid.append(vid)
|
|
data['files'] = [f for f in data['files'] if f not in rem_vid]
|
|
new_file = {img: {'name': data['name'], 'files': data['files']}}
|
|
video_details, result = get_video_details(data['files'][0], img)
|
|
input_file = '-'
|
|
file = '-'
|
|
newfile_path = os.path.normpath(os.path.join(new_dir, name) + VEXTENSION)
|
|
map_cmd = []
|
|
video_cmd = []
|
|
audio_cmd = []
|
|
audio_cmd2 = []
|
|
sub_cmd = []
|
|
meta_cmd = []
|
|
other_cmd = []
|
|
if not video_details or not video_details.get('streams'):
|
|
# we couldn't read streams with ffprobe. Set defaults to try transcoding.
|
|
video_streams = []
|
|
audio_streams = []
|
|
sub_streams = []
|
|
map_cmd.extend(['-map', '0'])
|
|
if VCODEC:
|
|
video_cmd.extend(['-c:v', VCODEC])
|
|
if VCODEC == 'libx264' and VPRESET:
|
|
video_cmd.extend(['-pre', VPRESET])
|
|
else:
|
|
video_cmd.extend(['-c:v', 'copy'])
|
|
if VFRAMERATE:
|
|
video_cmd.extend(['-r', str(VFRAMERATE)])
|
|
if VBITRATE:
|
|
video_cmd.extend(['-b:v', str(VBITRATE)])
|
|
if VRESOLUTION:
|
|
video_cmd.extend(['-vf', f'scale={VRESOLUTION}'])
|
|
if VPRESET:
|
|
video_cmd.extend(['-preset', VPRESET])
|
|
if VCRF:
|
|
video_cmd.extend(['-crf', str(VCRF)])
|
|
if VLEVEL:
|
|
video_cmd.extend(['-level', str(VLEVEL)])
|
|
if ACODEC:
|
|
audio_cmd.extend(['-c:a', ACODEC])
|
|
if ACODEC in {'aac', 'dts'}:
|
|
# Allow users to use the experimental AAC codec that's built into recent versions of ffmpeg
|
|
audio_cmd.extend(['-strict', '-2'])
|
|
else:
|
|
audio_cmd.extend(['-c:a', 'copy'])
|
|
if ACHANNELS:
|
|
audio_cmd.extend(['-ac', str(ACHANNELS)])
|
|
if ABITRATE:
|
|
audio_cmd.extend(['-b:a', str(ABITRATE)])
|
|
if OUTPUTQUALITYPERCENT:
|
|
audio_cmd.extend(['-q:a', str(OUTPUTQUALITYPERCENT)])
|
|
if SCODEC and ALLOWSUBS:
|
|
sub_cmd.extend(['-c:s', SCODEC])
|
|
elif ALLOWSUBS: # Not every subtitle codec can be used for every video container format!
|
|
sub_cmd.extend(['-c:s', 'copy'])
|
|
else: # http://en.wikibooks.org/wiki/FFMPEG_An_Intermediate_Guide/subtitle_options
|
|
sub_cmd.extend(['-sn']) # Don't copy the subtitles over
|
|
if OUTPUTFASTSTART:
|
|
other_cmd.extend(['-movflags', '+faststart'])
|
|
else:
|
|
video_streams = [item for item in video_details['streams'] if item['codec_type'] == 'video']
|
|
audio_streams = [item for item in video_details['streams'] if item['codec_type'] == 'audio']
|
|
sub_streams = [item for item in video_details['streams'] if item['codec_type'] == 'subtitle']
|
|
if VEXTENSION not in ['.mkv', '.mpegts']:
|
|
sub_streams = [item for item in video_details['streams'] if item['codec_type'] == 'subtitle' and item['codec_name'] != 'hdmv_pgs_subtitle' and item['codec_name'] != 'pgssub']
|
|
for video in video_streams:
|
|
codec = video['codec_name']
|
|
frame_rate = video.get('avg_frame_rate', 0)
|
|
width = video.get('width', 0)
|
|
height = video.get('height', 0)
|
|
scale = VRESOLUTION
|
|
if codec in VCODEC_ALLOW or not VCODEC:
|
|
video_cmd.extend(['-c:v', 'copy'])
|
|
else:
|
|
video_cmd.extend(['-c:v', VCODEC])
|
|
if VFRAMERATE and not VFRAMERATE * 0.999 <= frame_rate <= VFRAMERATE * 1.001:
|
|
video_cmd.extend(['-r', str(VFRAMERATE)])
|
|
if scale:
|
|
w_scale = width / float(scale.split(':')[0])
|
|
h_scale = height / float(scale.split(':')[1])
|
|
if w_scale > h_scale: # widescreen, Scale by width only.
|
|
_width = scale.split(':')[0]
|
|
_height = int((height / w_scale) / 2) * 2
|
|
scale = f'{_width}:{_height}'
|
|
if w_scale > 1:
|
|
video_cmd.extend(['-vf', f'scale={scale}'])
|
|
else: # lower or matching ratio, scale by height only.
|
|
_width = int((width / h_scale) / 2) * 2
|
|
_height = scale.split(':')[1]
|
|
scale = f'{_width}:{_height}'
|
|
if h_scale > 1:
|
|
video_cmd.extend(['-vf', f'scale={scale}'])
|
|
if VBITRATE:
|
|
video_cmd.extend(['-b:v', str(VBITRATE)])
|
|
if VPRESET:
|
|
video_cmd.extend(['-preset', VPRESET])
|
|
if VCRF:
|
|
video_cmd.extend(['-crf', str(VCRF)])
|
|
if VLEVEL:
|
|
video_cmd.extend(['-level', str(VLEVEL)])
|
|
no_copy = ['-vf', '-r', '-crf', '-level', '-preset', '-b:v']
|
|
if video_cmd[1] == 'copy' and any(i in video_cmd for i in no_copy):
|
|
video_cmd[1] = VCODEC
|
|
if VCODEC == 'copy': # force copy. therefore ignore all other video transcoding.
|
|
video_cmd = ['-c:v', 'copy']
|
|
_index = video['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
break # Only one video needed
|
|
used_audio = 0
|
|
a_mapped = []
|
|
commentary = []
|
|
if audio_streams:
|
|
for i, val in reversed(list(enumerate(audio_streams))):
|
|
try:
|
|
if 'Commentary' in val.get('tags').get('title'):
|
|
# Split out commentry tracks.
|
|
commentary.append(val)
|
|
del audio_streams[i]
|
|
except Exception:
|
|
continue
|
|
try:
|
|
audio1 = [item for item in audio_streams if item['tags']['language'] == ALANGUAGE]
|
|
except Exception: # no language tags. Assume only 1 language.
|
|
audio1 = audio_streams
|
|
try:
|
|
audio2 = [item for item in audio1 if item['codec_name'] in ACODEC_ALLOW]
|
|
except Exception:
|
|
audio2 = []
|
|
try:
|
|
audio3 = [item for item in audio_streams if item['tags']['language'] != ALANGUAGE]
|
|
except Exception:
|
|
audio3 = []
|
|
try:
|
|
audio4 = [item for item in audio3 if item['codec_name'] in ACODEC_ALLOW]
|
|
except Exception:
|
|
audio4 = []
|
|
if audio2: # right (or only) language and codec...
|
|
_index = audio2[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio2[0]['index']])
|
|
bitrate = int(float(audio2[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio2[0].get('channels', 0)))
|
|
audio_cmd.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif audio1: # right (or only) language, wrong codec.
|
|
_index = audio1[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio1[0]['index']])
|
|
bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio1[0].get('channels', 0)))
|
|
audio_cmd.extend([f'-c:a:{used_audio}', ACODEC if ACODEC else 'copy'])
|
|
elif audio4:
|
|
# wrong language, right codec.
|
|
_index = audio4[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio4[0]['index']])
|
|
bitrate = int(float(audio4[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio4[0].get('channels', 0)))
|
|
audio_cmd.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif audio3:
|
|
# wrong language, wrong codec. just pick the default audio track
|
|
_index = audio3[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio3[0]['index']])
|
|
bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio3[0].get('channels', 0)))
|
|
audio_cmd.extend([f'-c:a:{used_audio}', ACODEC if ACODEC else 'copy'])
|
|
if ACHANNELS and channels and channels > ACHANNELS:
|
|
audio_cmd.extend([f'-ac:a:{used_audio}', str(ACHANNELS)])
|
|
if audio_cmd[1] == 'copy':
|
|
audio_cmd[1] = ACODEC
|
|
if ABITRATE and not ABITRATE * 0.9 < bitrate < ABITRATE * 1.1:
|
|
audio_cmd.extend([f'-b:a:{used_audio}', str(ABITRATE)])
|
|
if audio_cmd[1] == 'copy':
|
|
audio_cmd[1] = ACODEC
|
|
if OUTPUTQUALITYPERCENT:
|
|
audio_cmd.extend([f'-q:a:{used_audio}', str(OUTPUTQUALITYPERCENT)])
|
|
if audio_cmd[1] == 'copy':
|
|
audio_cmd[1] = ACODEC
|
|
if audio_cmd[1] in {'aac', 'dts'}:
|
|
audio_cmd[2:2] = ['-strict', '-2']
|
|
if ACODEC2_ALLOW:
|
|
used_audio += 1
|
|
try:
|
|
audio5 = [item for item in audio1 if item['codec_name'] in ACODEC2_ALLOW]
|
|
except Exception:
|
|
audio5 = []
|
|
try:
|
|
audio6 = [item for item in audio3 if item['codec_name'] in ACODEC2_ALLOW]
|
|
except Exception:
|
|
audio6 = []
|
|
if audio5: # right language and codec.
|
|
_index = audio5[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio5[0]['index']])
|
|
bitrate = int(float(audio5[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio5[0].get('channels', 0)))
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif audio1: # right language wrong codec.
|
|
_index = audio1[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio1[0]['index']])
|
|
bitrate = int(float(audio1[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio1[0].get('channels', 0)))
|
|
if ACODEC2:
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', ACODEC2])
|
|
else:
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif audio6: # wrong language, right codec
|
|
_index = audio6[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio6[0]['index']])
|
|
bitrate = int(float(audio6[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio6[0].get('channels', 0)))
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif audio3:
|
|
# wrong language, wrong codec just pick the default audio track
|
|
_index = audio3[0]['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
a_mapped.extend([audio3[0]['index']])
|
|
bitrate = int(float(audio3[0].get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio3[0].get('channels', 0)))
|
|
if ACODEC2:
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', ACODEC2])
|
|
else:
|
|
audio_cmd2.extend([f'-c:a:{used_audio}', 'copy'])
|
|
if ACHANNELS2 and channels and channels > ACHANNELS2:
|
|
audio_cmd2.extend([f'-ac:a:{used_audio}', str(ACHANNELS2)])
|
|
if audio_cmd2[1] == 'copy':
|
|
audio_cmd2[1] = ACODEC2
|
|
if ABITRATE2 and not ABITRATE2 * 0.9 < bitrate < ABITRATE2 * 1.1:
|
|
audio_cmd2.extend([f'-b:a:{used_audio}', str(ABITRATE2)])
|
|
if audio_cmd2[1] == 'copy':
|
|
audio_cmd2[1] = ACODEC2
|
|
if OUTPUTQUALITYPERCENT:
|
|
audio_cmd2.extend([f'-q:a:{used_audio}', str(OUTPUTQUALITYPERCENT)])
|
|
if audio_cmd2[1] == 'copy':
|
|
audio_cmd2[1] = ACODEC2
|
|
if audio_cmd2[1] in {'aac', 'dts'}:
|
|
audio_cmd2[2:2] = ['-strict', '-2']
|
|
if a_mapped[1] == a_mapped[0] and audio_cmd2[1:] == audio_cmd[1:]:
|
|
# check for duplicate output track.
|
|
del map_cmd[-2:]
|
|
else:
|
|
audio_cmd.extend(audio_cmd2)
|
|
if AINCLUDE and ACODEC3:
|
|
# add commentary tracks back here.
|
|
audio_streams.extend(commentary)
|
|
for audio in audio_streams:
|
|
if audio['index'] in a_mapped:
|
|
continue
|
|
used_audio += 1
|
|
_index = audio['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
audio_cmd3 = []
|
|
bitrate = int(float(audio.get('bit_rate', 0))) / 1000
|
|
channels = int(float(audio.get('channels', 0)))
|
|
if audio['codec_name'] in ACODEC3_ALLOW:
|
|
audio_cmd3.extend([f'-c:a:{used_audio}', 'copy'])
|
|
elif ACODEC3:
|
|
audio_cmd3.extend([f'-c:a:{used_audio}', ACODEC3])
|
|
else:
|
|
audio_cmd3.extend([f'-c:a:{used_audio}', 'copy'])
|
|
if ACHANNELS3 and channels and channels > ACHANNELS3:
|
|
audio_cmd3.extend([f'-ac:a:{used_audio}', str(ACHANNELS3)])
|
|
if audio_cmd3[1] == 'copy':
|
|
audio_cmd3[1] = ACODEC3
|
|
if ABITRATE3 and not ABITRATE3 * 0.9 < bitrate < ABITRATE3 * 1.1:
|
|
audio_cmd3.extend([f'-b:a:{used_audio}', str(ABITRATE3)])
|
|
if audio_cmd3[1] == 'copy':
|
|
audio_cmd3[1] = ACODEC3
|
|
if OUTPUTQUALITYPERCENT > 0:
|
|
audio_cmd3.extend([f'-q:a:{used_audio}', str(OUTPUTQUALITYPERCENT)])
|
|
if audio_cmd3[1] == 'copy':
|
|
audio_cmd3[1] = ACODEC3
|
|
if audio_cmd3[1] in {'aac', 'dts'}:
|
|
audio_cmd3[2:2] = ['-strict', '-2']
|
|
audio_cmd.extend(audio_cmd3)
|
|
s_mapped = []
|
|
burnt = 0
|
|
num = 0
|
|
for lan in SLANGUAGES:
|
|
try:
|
|
subs1 = [item for item in sub_streams if item['tags']['language'] == lan]
|
|
except Exception:
|
|
subs1 = []
|
|
if BURN and not subs1 and not burnt and os.path.isfile(file):
|
|
for subfile in get_subs(file):
|
|
if lan in os.path.split(subfile)[1]:
|
|
video_cmd.extend(['-vf', f'subtitles={subfile}'])
|
|
burnt = 1
|
|
for sub in subs1:
|
|
if BURN and not burnt and os.path.isfile(input_file):
|
|
subloc = 0
|
|
for index, sub_stream in enumerate(sub_streams):
|
|
if sub_stream['index'] == sub['index']:
|
|
subloc = index
|
|
break
|
|
video_cmd.extend(['-vf', f'subtitles={input_file}:si={subloc}'])
|
|
burnt = 1
|
|
if not ALLOWSUBS:
|
|
break
|
|
if sub['codec_name'] in {'dvd_subtitle', 'VobSub'} and SCODEC == 'mov_text':
|
|
continue # We can't convert these.
|
|
_index = sub['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
s_mapped.extend([sub['index']])
|
|
if SINCLUDE:
|
|
for sub in sub_streams:
|
|
if not ALLOWSUBS:
|
|
break
|
|
if sub['index'] in s_mapped:
|
|
continue
|
|
if sub['codec_name'] in {'dvd_subtitle', 'VobSub'} and SCODEC == 'mov_text': # We can't convert these.
|
|
continue
|
|
_index = sub['index']
|
|
map_cmd.extend(['-map', f'0:{_index}'])
|
|
s_mapped.extend([sub['index']])
|
|
if OUTPUTFASTSTART:
|
|
other_cmd.extend(['-movflags', '+faststart'])
|
|
if OTHEROPTS:
|
|
other_cmd.extend(OTHEROPTS)
|
|
command = [nzb2media.tool.FFMPEG, '-loglevel', 'warning']
|
|
if HWACCEL:
|
|
command.extend(['-hwaccel', 'auto'])
|
|
if GENERALOPTS:
|
|
command.extend(GENERALOPTS)
|
|
command.extend(['-i', input_file])
|
|
if SEMBED and os.path.isfile(file):
|
|
for subfile in get_subs(file):
|
|
sub_details, result = get_video_details(subfile)
|
|
if not sub_details or not sub_details.get('streams'):
|
|
continue
|
|
if SCODEC == 'mov_text':
|
|
subcode = [stream['codec_name'] for stream in sub_details['streams']]
|
|
if set(subcode).intersection(['dvd_subtitle', 'VobSub']):
|
|
# We can't convert these.
|
|
continue
|
|
command.extend(['-i', subfile])
|
|
lan = os.path.splitext(os.path.splitext(subfile)[0])[1][1:].split('-')[0]
|
|
metlan = None
|
|
try:
|
|
if len(lan) == 3:
|
|
metlan = Language(lan)
|
|
if len(lan) == 2:
|
|
metlan = Language.fromalpha2(lan)
|
|
except Exception:
|
|
pass
|
|
if metlan:
|
|
meta_cmd.extend([f'-metadata:s:s:{len(s_mapped) + num}', f'language={metlan.alpha3}'])
|
|
num += 1
|
|
map_cmd.extend(['-map', f'{num}:0'])
|
|
if not ALLOWSUBS or (not s_mapped and not num):
|
|
sub_cmd.extend(['-sn'])
|
|
elif SCODEC:
|
|
sub_cmd.extend(['-c:s', SCODEC])
|
|
else:
|
|
sub_cmd.extend(['-c:s', 'copy'])
|
|
command.extend(map_cmd)
|
|
command.extend(video_cmd)
|
|
command.extend(audio_cmd)
|
|
command.extend(sub_cmd)
|
|
command.extend(meta_cmd)
|
|
command.extend(other_cmd)
|
|
command.append(newfile_path)
|
|
if platform.system() != 'Windows':
|
|
command = nzb2media.tool.NICENESS + command
|
|
return command, new_file
|
|
|
|
|
|
def get_subs(file):
|
|
filepaths = []
|
|
sub_ext = ['.srt', '.sub', '.idx']
|
|
name = os.path.splitext(os.path.split(file)[1])[0]
|
|
path = os.path.split(file)[0]
|
|
for directory, _, filenames in os.walk(path):
|
|
for filename in filenames:
|
|
filepaths.extend([os.path.join(directory, filename)])
|
|
subfiles = [item for item in filepaths if os.path.splitext(item)[1] in sub_ext and name in item]
|
|
return subfiles
|
|
|
|
|
|
def extract_subs(file, newfile_path):
|
|
video_details, result = get_video_details(file)
|
|
if not video_details:
|
|
return
|
|
if SUBSDIR:
|
|
subdir = SUBSDIR
|
|
else:
|
|
subdir = os.path.split(newfile_path)[0]
|
|
name = os.path.splitext(os.path.split(newfile_path)[1])[0]
|
|
try:
|
|
sub_streams = [item for item in video_details['streams'] if item['codec_type'] == 'subtitle' and item['tags']['language'] in SLANGUAGES and item['codec_name'] != 'hdmv_pgs_subtitle' and item['codec_name'] != 'pgssub']
|
|
except Exception:
|
|
sub_streams = [item for item in video_details['streams'] if item['codec_type'] == 'subtitle' and item['codec_name'] != 'hdmv_pgs_subtitle' and item['codec_name'] != 'pgssub']
|
|
num = len(sub_streams)
|
|
for ea_num in range(num):
|
|
sub = sub_streams[ea_num]
|
|
idx = sub['index']
|
|
lan = sub.get('tags', {}).get('language', 'unk')
|
|
if num == 1:
|
|
output_file = os.path.join(subdir, f'{name}.srt')
|
|
if os.path.isfile(output_file):
|
|
output_file = os.path.join(subdir, f'{name}.{ea_num}.srt')
|
|
else:
|
|
output_file = os.path.join(subdir, f'{name}.{lan}.srt')
|
|
if os.path.isfile(output_file):
|
|
output_file = os.path.join(subdir, f'{name}.{lan}.{ea_num}.srt')
|
|
command = [nzb2media.tool.FFMPEG, '-loglevel', 'warning', '-i', file, '-vn', '-an', f'-codec:{idx}', 'srt', output_file]
|
|
if platform.system() != 'Windows':
|
|
command = nzb2media.tool.NICENESS + command
|
|
log.info(f'Extracting {lan} subtitle from: {file}')
|
|
print_cmd(command)
|
|
result = 1 # set result to failed in case call fails.
|
|
try:
|
|
with subprocess.Popen(command, stdout=DEVNULL, stderr=DEVNULL) as proc:
|
|
proc_out, proc_error = proc.communicate()
|
|
result = proc.returncode
|
|
except Exception:
|
|
log.error('Extracting subtitle has failed')
|
|
if not result:
|
|
try:
|
|
shutil.copymode(file, output_file)
|
|
except Exception:
|
|
pass
|
|
log.info(f'Extracting {lan} subtitle from {file} has succeeded')
|
|
else:
|
|
log.error('Extracting subtitles has failed')
|
|
|
|
|
|
def process_list(iterable):
|
|
rem_list = []
|
|
new_list = []
|
|
combine = []
|
|
vts_path = None
|
|
mts_path = None
|
|
success = True
|
|
for item in iterable:
|
|
ext = os.path.splitext(item)[1].lower()
|
|
if ext in {'.iso', '.bin', '.img'} and ext not in IGNOREEXTENSIONS:
|
|
log.debug(f'Attempting to rip disk image: {item}')
|
|
new_list.extend(rip_iso(item))
|
|
rem_list.append(item)
|
|
elif re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', item) and '.vob' not in IGNOREEXTENSIONS:
|
|
log.debug(f'Found VIDEO_TS image file: {item}')
|
|
if not vts_path:
|
|
try:
|
|
vts_path = re.match('(.+VIDEO_TS)', item).groups()[0]
|
|
except Exception:
|
|
vts_path = os.path.split(item)[0]
|
|
rem_list.append(item)
|
|
elif re.match('.+BDMV[/\\]SOURCE[/\\][0-9]+[0-9].[Mm][Tt][Ss]', item) and '.mts' not in IGNOREEXTENSIONS:
|
|
log.debug(f'Found MTS image file: {item}')
|
|
if not mts_path:
|
|
try:
|
|
mts_path = re.match('(.+BDMV[/\\]SOURCE)', item).groups()[0]
|
|
except Exception:
|
|
mts_path = os.path.split(item)[0]
|
|
rem_list.append(item)
|
|
elif re.match('.+VIDEO_TS.', item) or re.match('.+VTS_[0-9][0-9]_[0-9].', item):
|
|
rem_list.append(item)
|
|
elif CONCAT and re.match('.+[cC][dD][0-9].', item):
|
|
rem_list.append(item)
|
|
combine.append(item)
|
|
else:
|
|
continue
|
|
if vts_path:
|
|
new_list.extend(combine_vts(vts_path))
|
|
if mts_path:
|
|
new_list.extend(combine_mts(mts_path))
|
|
if combine:
|
|
new_list.extend(combine_cd(combine))
|
|
for file in new_list:
|
|
if isinstance(file, str) and 'concat:' not in file and not os.path.isfile(file):
|
|
success = False
|
|
break
|
|
if success and new_list:
|
|
iterable.extend(new_list)
|
|
for item in rem_list:
|
|
iterable.remove(item)
|
|
log.debug(f'Successfully extracted .vob file {new_list[0]} from disk image')
|
|
elif new_list and not success:
|
|
new_list = []
|
|
rem_list = []
|
|
log.error('Failed extracting .vob files from disk image. Stopping transcoding.')
|
|
return iterable, rem_list, new_list, success
|
|
|
|
|
|
def mount_iso(item): # Currently only supports Linux Mount when permissions allow.
|
|
global MOUNTED
|
|
if platform.system() == 'Windows':
|
|
log.error(f'No mounting options available under Windows for image file {item}')
|
|
return []
|
|
mount_point = os.path.join(os.path.dirname(os.path.abspath(item)), 'temp')
|
|
make_dir(mount_point)
|
|
cmd = ['mount', '-o', 'loop', item, mount_point]
|
|
print_cmd(cmd)
|
|
with subprocess.Popen(cmd, stdout=PIPE, stderr=DEVNULL) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
MOUNTED = mount_point # Allows us to verify this has been done and then cleanup.
|
|
for root, _dirs, files in os.walk(mount_point):
|
|
for file in files:
|
|
full_path = os.path.join(root, file)
|
|
if re.match('.+VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb]', full_path) and '.vob' not in IGNOREEXTENSIONS:
|
|
log.debug(f'Found VIDEO_TS image file: {full_path}')
|
|
try:
|
|
vts_path = re.match('(.+VIDEO_TS)', full_path).groups()[0]
|
|
except Exception:
|
|
vts_path = os.path.split(full_path)[0]
|
|
return combine_vts(vts_path)
|
|
if re.match('.+BDMV[/\\]STREAM[/\\][0-9]+[0-9].[Mm]', full_path) and '.mts' not in IGNOREEXTENSIONS:
|
|
log.debug(f'Found MTS image file: {full_path}')
|
|
try:
|
|
mts_path = re.match('(.+BDMV[/\\]STREAM)', full_path).groups()[0]
|
|
except Exception:
|
|
mts_path = os.path.split(full_path)[0]
|
|
return combine_mts(mts_path)
|
|
log.error(f'No VIDEO_TS or BDMV/SOURCE folder found in image file {mount_point}')
|
|
return ['failure'] # If we got here, nothing matched our criteria
|
|
|
|
|
|
def rip_iso(item):
|
|
new_files = []
|
|
failure_dir = 'failure'
|
|
# Mount the ISO in your OS and call combineVTS.
|
|
if not nzb2media.tool.SEVENZIP:
|
|
log.debug(f'No 7zip installed. Attempting to mount image file {item}')
|
|
try:
|
|
# Currently only works for Linux.
|
|
new_files = mount_iso(item)
|
|
except Exception:
|
|
log.error(f'Failed to mount and extract from image file {item}')
|
|
new_files = [failure_dir]
|
|
return new_files
|
|
cmd = [nzb2media.tool.SEVENZIP, 'l', item]
|
|
try:
|
|
log.debug(f'Attempting to extract .vob or .mts from image file {item}')
|
|
print_cmd(cmd)
|
|
with subprocess.Popen(cmd, stdout=PIPE, stderr=DEVNULL) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
file_match_gen = (re.match(r'.+(VIDEO_TS[/\\]VTS_[0-9][0-9]_[0-9].[Vv][Oo][Bb])', line) for line in proc_out.decode().splitlines())
|
|
file_list = [file_match.groups()[0] for file_match in file_match_gen if file_match]
|
|
combined = []
|
|
if file_list: # handle DVD
|
|
for title_set in range(99):
|
|
concat = []
|
|
part = 1
|
|
while True:
|
|
vts_name = f'VIDEO_TS{os.sep}VTS_{title_set + 1:02d}_{part:d}.VOB'
|
|
if vts_name in file_list:
|
|
concat.append(vts_name)
|
|
part += 1
|
|
else:
|
|
break
|
|
if not concat:
|
|
break
|
|
if CONCAT:
|
|
combined.extend(concat)
|
|
continue
|
|
name = f'{os.path.splitext(os.path.split(item)[1])[0]}.cd{title_set + 1}'
|
|
new_files.append({item: {'name': name, 'files': concat}})
|
|
else:
|
|
# check BlueRay for BDMV/STREAM/XXXX.MTS
|
|
mts_list_gen = (re.match(r'.+(BDMV[/\\]STREAM[/\\][0-9]+[0-9].[Mm]).', line) for line in proc_out.decode().splitlines())
|
|
mts_list = [file_match.groups()[0] for file_match in mts_list_gen if file_match]
|
|
mts_list.sort(key=lambda f: int(''.join(filter(str.isdigit, f))))
|
|
title_set = 0
|
|
for mts_name in mts_list:
|
|
concat = []
|
|
title_set += 1
|
|
concat.append(mts_name)
|
|
if CONCAT:
|
|
combined.extend(concat)
|
|
continue
|
|
name = f'{os.path.splitext(os.path.split(item)[1])[0]}.cd{title_set}'
|
|
new_files.append({item: {'name': name, 'files': concat}})
|
|
if CONCAT and combined:
|
|
name = os.path.splitext(os.path.split(item)[1])[0]
|
|
new_files.append({item: {'name': name, 'files': combined}})
|
|
if not new_files:
|
|
log.error(f'No VIDEO_TS or BDMV/SOURCE folder found in image file. Attempting to mount and scan {item}')
|
|
new_files = mount_iso(item)
|
|
except Exception:
|
|
log.error(f'Failed to extract from image file {item}')
|
|
new_files = [failure_dir]
|
|
return new_files
|
|
|
|
|
|
def combine_vts(vts_path):
|
|
new_files = []
|
|
combined = []
|
|
name = re.match(r'(.+)[/\\]VIDEO_TS', vts_path).groups()[0]
|
|
if os.path.basename(name) == 'temp':
|
|
name = os.path.basename(os.path.dirname(name))
|
|
else:
|
|
name = os.path.basename(name)
|
|
for title_set in range(99):
|
|
concat = []
|
|
part = 1
|
|
while True:
|
|
vts_name = f'VTS_{title_set + 1:02d}_{part:d}.VOB'
|
|
if os.path.isfile(os.path.join(vts_path, vts_name)):
|
|
concat.append(os.path.join(vts_path, vts_name))
|
|
part += 1
|
|
else:
|
|
break
|
|
if not concat:
|
|
break
|
|
if CONCAT:
|
|
combined.extend(concat)
|
|
continue
|
|
name = f'{name}.cd{title_set + 1}'
|
|
new_files.append({vts_path: {'name': name, 'files': concat}})
|
|
if CONCAT:
|
|
new_files.append({vts_path: {'name': name, 'files': combined}})
|
|
return new_files
|
|
|
|
|
|
def combine_mts(mts_path):
|
|
new_files = []
|
|
combined = []
|
|
name = re.match(r'(.+)[/\\]BDMV[/\\]STREAM', mts_path).groups()[0]
|
|
if os.path.basename(name) == 'temp':
|
|
name = os.path.basename(os.path.dirname(name))
|
|
else:
|
|
name = os.path.basename(name)
|
|
num = 0
|
|
mts_list = [f for f in os.listdir(mts_path) if os.path.isfile(os.path.join(mts_path, f))]
|
|
if sys.version_info[0] == 2: # Python2 sorting
|
|
mts_list.sort(key=lambda f: int(filter(str.isdigit, f)))
|
|
else: # Python3 sorting
|
|
mts_list.sort(key=lambda f: int(''.join(filter(str.isdigit, f))))
|
|
for mts_name in mts_list: # need to sort all files [1 - 998].mts in order
|
|
concat = []
|
|
concat.append(os.path.join(mts_path, mts_name))
|
|
if CONCAT:
|
|
combined.extend(concat)
|
|
continue
|
|
name = f'{name}.cd{num + 1}'
|
|
new_files.append({mts_path: {'name': name, 'files': concat}})
|
|
num += 1
|
|
if CONCAT:
|
|
new_files.append({mts_path: {'name': name, 'files': combined}})
|
|
return new_files
|
|
|
|
|
|
def combine_cd(combine):
|
|
new_files = []
|
|
for item in {re.match('(.+)[cC][dD][0-9].', ea_item).groups()[0] for ea_item in combine}:
|
|
concat = ''
|
|
for num in range(99):
|
|
files = [file for file in combine if num + 1 == int(re.match('.+[cC][dD]([0-9]+).', file).groups()[0]) and item in file]
|
|
if files:
|
|
concat += f'{files[0]}|'
|
|
else:
|
|
break
|
|
if concat:
|
|
new_files.append(f'concat:{concat[:-1]}')
|
|
return new_files
|
|
|
|
|
|
def print_cmd(command):
|
|
cmd = ''
|
|
for item in command:
|
|
cmd = f'{cmd} {item}'
|
|
log.debug(f'calling command:{cmd}')
|
|
|
|
|
|
def transcode_directory(dir_name):
|
|
global MOUNTED
|
|
if not nzb2media.tool.FFMPEG:
|
|
return 1, dir_name
|
|
log.info('Checking for files to be transcoded')
|
|
final_result = 0 # initialize as successful
|
|
if OUTPUTVIDEOPATH:
|
|
new_dir = OUTPUTVIDEOPATH
|
|
make_dir(new_dir)
|
|
name = os.path.splitext(os.path.split(dir_name)[1])[0]
|
|
new_dir = os.path.join(new_dir, name)
|
|
make_dir(new_dir)
|
|
else:
|
|
new_dir = dir_name
|
|
movie_name = os.path.splitext(os.path.split(dir_name)[1])[0]
|
|
file_list = list_media_files(dir_name, media=True, audio=False, meta=False, archives=False)
|
|
file_list, rem_list, new_list, success = process_list(file_list)
|
|
if not success:
|
|
return 1, dir_name
|
|
for file in file_list:
|
|
if isinstance(file, str) and os.path.splitext(file)[1] in IGNOREEXTENSIONS:
|
|
continue
|
|
command, file = build_commands(file, new_dir, movie_name)
|
|
newfile_path = command[-1]
|
|
# transcoding files may remove the original file, so make sure to extract subtitles first
|
|
if SEXTRACT and isinstance(file, str):
|
|
extract_subs(file, newfile_path)
|
|
try: # Try to remove the file that we're transcoding to just in case. (ffmpeg will return an error if it already exists for some reason)
|
|
os.remove(newfile_path)
|
|
except OSError as error:
|
|
if error.errno != errno.ENOENT: # Ignore the error if it's just telling us that the file doesn't exist
|
|
log.debug(f'Error when removing transcoding target: {error}')
|
|
except Exception as error:
|
|
log.debug(f'Error when removing transcoding target: {error}')
|
|
log.info(f'Transcoding video: {newfile_path}')
|
|
print_cmd(command)
|
|
result = 1 # set result to failed in case call fails.
|
|
try:
|
|
if isinstance(file, str):
|
|
with subprocess.Popen(command, stdout=DEVNULL, stderr=PIPE) as proc:
|
|
out, err = proc.communicate()
|
|
else:
|
|
img, data = next(file.items())
|
|
with subprocess.Popen(command, stdout=DEVNULL, stderr=PIPE, stdin=PIPE) as proc:
|
|
for vob in data['files']:
|
|
procin = zip_out(vob, img)
|
|
if procin:
|
|
log.debug(f'Feeding in file: {vob} to Transcoder')
|
|
shutil.copyfileobj(procin.stdout, proc.stdin)
|
|
procin.stdout.close()
|
|
out, err = proc.communicate()
|
|
if err:
|
|
log.error(f'Transcoder returned:{err} has failed')
|
|
result = proc.returncode
|
|
except Exception:
|
|
log.error(f'Transcoding of video {newfile_path} has failed')
|
|
if SUBSDIR and not result and isinstance(file, str):
|
|
for sub in get_subs(file):
|
|
name = os.path.splitext(os.path.split(file)[1])[0]
|
|
subname = os.path.split(sub)[1]
|
|
newname = os.path.splitext(os.path.split(newfile_path)[1])[0]
|
|
newpath = os.path.join(SUBSDIR, subname.replace(name, newname))
|
|
if not os.path.isfile(newpath):
|
|
os.rename(sub, newpath)
|
|
if not result:
|
|
try:
|
|
shutil.copymode(file, newfile_path)
|
|
except Exception:
|
|
pass
|
|
log.info(f'Transcoding of video to {newfile_path} succeeded')
|
|
if os.path.isfile(newfile_path) and (file in new_list or not DUPLICATE):
|
|
try:
|
|
os.unlink(file)
|
|
except Exception:
|
|
pass
|
|
else:
|
|
log.error(f'Transcoding of video to {newfile_path} failed with result {result}')
|
|
# this will be 0 (successful) it all are successful, else will return a positive integer for failure.
|
|
final_result = final_result + result
|
|
if MOUNTED: # In case we mounted an .iso file, unmount here.
|
|
time.sleep(5) # play it safe and avoid failing to unmount.
|
|
cmd = ['umount', '-l', MOUNTED]
|
|
print_cmd(cmd)
|
|
with subprocess.Popen(cmd, stdout=PIPE, stderr=DEVNULL) as proc:
|
|
proc_out, proc_err = proc.communicate()
|
|
time.sleep(5)
|
|
os.rmdir(MOUNTED)
|
|
MOUNTED = None
|
|
if not final_result and not DUPLICATE:
|
|
for file in rem_list:
|
|
try:
|
|
os.unlink(file)
|
|
except Exception:
|
|
pass
|
|
if not os.listdir(new_dir):
|
|
# this is an empty directory and we didn't transcode into it.
|
|
os.rmdir(new_dir)
|
|
new_dir = dir_name
|
|
if not PROCESSOUTPUT and DUPLICATE:
|
|
# We postprocess the original files to CP/SB
|
|
new_dir = dir_name
|
|
return final_result, new_dir
|
|
|
|
|
|
def configure_transcoder():
|
|
global MOUNTED
|
|
global GETSUBS
|
|
global TRANSCODE
|
|
global DUPLICATE
|
|
global CONCAT
|
|
global IGNOREEXTENSIONS
|
|
global OUTPUTFASTSTART
|
|
global GENERALOPTS
|
|
global OTHEROPTS
|
|
global OUTPUTQUALITYPERCENT
|
|
global OUTPUTVIDEOPATH
|
|
global PROCESSOUTPUT
|
|
global ALANGUAGE
|
|
global AINCLUDE
|
|
global SLANGUAGES
|
|
global SINCLUDE
|
|
global SEXTRACT
|
|
global SEMBED
|
|
global SUBSDIR
|
|
global VEXTENSION
|
|
global VCODEC
|
|
global VPRESET
|
|
global VFRAMERATE
|
|
global VBITRATE
|
|
global VRESOLUTION
|
|
global VCRF
|
|
global VLEVEL
|
|
global VCODEC_ALLOW
|
|
global ACODEC
|
|
global ACODEC_ALLOW
|
|
global ACHANNELS
|
|
global ABITRATE
|
|
global ACODEC2
|
|
global ACODEC2_ALLOW
|
|
global ACHANNELS2
|
|
global ABITRATE2
|
|
global ACODEC3
|
|
global ACODEC3_ALLOW
|
|
global ACHANNELS3
|
|
global ABITRATE3
|
|
global SCODEC
|
|
global BURN
|
|
global HWACCEL
|
|
global ALLOWSUBS
|
|
global DEFAULTS
|
|
MOUNTED = None
|
|
GETSUBS = int(nzb2media.CFG['Transcoder']['getSubs'])
|
|
TRANSCODE = int(nzb2media.CFG['Transcoder']['transcode'])
|
|
DUPLICATE = int(nzb2media.CFG['Transcoder']['duplicate'])
|
|
CONCAT = int(nzb2media.CFG['Transcoder']['concat'])
|
|
IGNOREEXTENSIONS = nzb2media.CFG['Transcoder']['ignoreExtensions']
|
|
if isinstance(IGNOREEXTENSIONS, str):
|
|
IGNOREEXTENSIONS = IGNOREEXTENSIONS.split(',')
|
|
OUTPUTFASTSTART = int(nzb2media.CFG['Transcoder']['outputFastStart'])
|
|
GENERALOPTS = nzb2media.CFG['Transcoder']['generalOptions']
|
|
if isinstance(GENERALOPTS, str):
|
|
GENERALOPTS = GENERALOPTS.split(',')
|
|
if GENERALOPTS == ['']:
|
|
GENERALOPTS = []
|
|
if '-fflags' not in GENERALOPTS:
|
|
GENERALOPTS.append('-fflags')
|
|
if '+genpts' not in GENERALOPTS:
|
|
GENERALOPTS.append('+genpts')
|
|
OTHEROPTS = nzb2media.CFG['Transcoder']['otherOptions']
|
|
if isinstance(OTHEROPTS, str):
|
|
OTHEROPTS = OTHEROPTS.split(',')
|
|
if OTHEROPTS == ['']:
|
|
OTHEROPTS = []
|
|
try:
|
|
OUTPUTQUALITYPERCENT = int(nzb2media.CFG['Transcoder']['outputQualityPercent'])
|
|
except Exception:
|
|
pass
|
|
OUTPUTVIDEOPATH = nzb2media.CFG['Transcoder']['outputVideoPath']
|
|
PROCESSOUTPUT = int(nzb2media.CFG['Transcoder']['processOutput'])
|
|
ALANGUAGE = nzb2media.CFG['Transcoder']['audioLanguage']
|
|
AINCLUDE = int(nzb2media.CFG['Transcoder']['allAudioLanguages'])
|
|
SLANGUAGES = nzb2media.CFG['Transcoder']['subLanguages']
|
|
if isinstance(SLANGUAGES, str):
|
|
SLANGUAGES = SLANGUAGES.split(',')
|
|
if SLANGUAGES == ['']:
|
|
SLANGUAGES = []
|
|
SINCLUDE = int(nzb2media.CFG['Transcoder']['allSubLanguages'])
|
|
SEXTRACT = int(nzb2media.CFG['Transcoder']['extractSubs'])
|
|
SEMBED = int(nzb2media.CFG['Transcoder']['embedSubs'])
|
|
SUBSDIR = nzb2media.CFG['Transcoder']['externalSubDir']
|
|
VEXTENSION = nzb2media.CFG['Transcoder']['outputVideoExtension'].strip()
|
|
VCODEC = nzb2media.CFG['Transcoder']['outputVideoCodec'].strip()
|
|
VCODEC_ALLOW = nzb2media.CFG['Transcoder']['VideoCodecAllow'].strip()
|
|
if isinstance(VCODEC_ALLOW, str):
|
|
VCODEC_ALLOW = VCODEC_ALLOW.split(',')
|
|
if VCODEC_ALLOW == ['']:
|
|
VCODEC_ALLOW = []
|
|
VPRESET = nzb2media.CFG['Transcoder']['outputVideoPreset'].strip()
|
|
try:
|
|
VFRAMERATE = float(nzb2media.CFG['Transcoder']['outputVideoFramerate'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VCRF = int(nzb2media.CFG['Transcoder']['outputVideoCRF'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VLEVEL = nzb2media.CFG['Transcoder']['outputVideoLevel'].strip()
|
|
except Exception:
|
|
pass
|
|
try:
|
|
VBITRATE = int((nzb2media.CFG['Transcoder']['outputVideoBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
VRESOLUTION = nzb2media.CFG['Transcoder']['outputVideoResolution']
|
|
ACODEC = nzb2media.CFG['Transcoder']['outputAudioCodec'].strip()
|
|
ACODEC_ALLOW = nzb2media.CFG['Transcoder']['AudioCodecAllow'].strip()
|
|
if isinstance(ACODEC_ALLOW, str):
|
|
ACODEC_ALLOW = ACODEC_ALLOW.split(',')
|
|
if ACODEC_ALLOW == ['']:
|
|
ACODEC_ALLOW = []
|
|
try:
|
|
ACHANNELS = int(nzb2media.CFG['Transcoder']['outputAudioChannels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE = int((nzb2media.CFG['Transcoder']['outputAudioBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
ACODEC2 = nzb2media.CFG['Transcoder']['outputAudioTrack2Codec'].strip()
|
|
ACODEC2_ALLOW = nzb2media.CFG['Transcoder']['AudioCodec2Allow'].strip()
|
|
if isinstance(ACODEC2_ALLOW, str):
|
|
ACODEC2_ALLOW = ACODEC2_ALLOW.split(',')
|
|
if ACODEC2_ALLOW == ['']:
|
|
ACODEC2_ALLOW = []
|
|
try:
|
|
ACHANNELS2 = int(nzb2media.CFG['Transcoder']['outputAudioTrack2Channels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE2 = int((nzb2media.CFG['Transcoder']['outputAudioTrack2Bitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
ACODEC3 = nzb2media.CFG['Transcoder']['outputAudioOtherCodec'].strip()
|
|
ACODEC3_ALLOW = nzb2media.CFG['Transcoder']['AudioOtherCodecAllow'].strip()
|
|
if isinstance(ACODEC3_ALLOW, str):
|
|
ACODEC3_ALLOW = ACODEC3_ALLOW.split(',')
|
|
if ACODEC3_ALLOW == ['']:
|
|
ACODEC3_ALLOW = []
|
|
try:
|
|
ACHANNELS3 = int(nzb2media.CFG['Transcoder']['outputAudioOtherChannels'].strip())
|
|
except Exception:
|
|
pass
|
|
try:
|
|
ABITRATE3 = int((nzb2media.CFG['Transcoder']['outputAudioOtherBitrate'].strip()).replace('k', '000'))
|
|
except Exception:
|
|
pass
|
|
SCODEC = nzb2media.CFG['Transcoder']['outputSubtitleCodec'].strip()
|
|
BURN = int(nzb2media.CFG['Transcoder']['burnInSubtitle'].strip())
|
|
DEFAULTS = nzb2media.CFG['Transcoder']['outputDefault'].strip()
|
|
HWACCEL = int(nzb2media.CFG['Transcoder']['hwAccel'])
|
|
allow_subs = ['.mkv', '.mp4', '.m4v', 'asf', 'wma', 'wmv']
|
|
codec_alias = {'libx264': ['libx264', 'h264', 'h.264', 'AVC', 'MPEG-4'], 'libmp3lame': ['libmp3lame', 'mp3'], 'libfaac': ['libfaac', 'aac', 'faac']}
|
|
transcode_defaults = {
|
|
'iPad': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'iPad-1080p': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '1920:1080', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'iPad-720p': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': None, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'Apple-TV': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6, 'ACODEC2': 'aac', 'ACODEC2_ALLOW': ['libfaac'], 'ABITRATE2': None, 'ACHANNELS2': 2, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'iPod': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '1280:720', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'iPhone': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '460:320', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'PS3': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6, 'ACODEC2': 'aac', 'ACODEC2_ALLOW': ['libfaac'], 'ABITRATE2': None, 'ACHANNELS2': 2, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'xbox': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'ac3', 'ACODEC_ALLOW': ['ac3'], 'ABITRATE': None, 'ACHANNELS': 6, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'Roku-480p': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'Roku-720p': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'Roku-1080p': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 160000, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
'mkv': {'VEXTENSION': '.mkv', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], 'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8, 'SCODEC': 'mov_text'},
|
|
'mkv-bluray': {'VEXTENSION': '.mkv', 'VCODEC': 'libx265', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'hevc', 'h265', 'libx265', 'h.265', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], 'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8, 'SCODEC': 'mov_text'},
|
|
'mp4-scene-release': {'VEXTENSION': '.mp4', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': None, 'VCRF': 19, 'VLEVEL': '3.1', 'VRESOLUTION': None, 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4', 'mpeg2video'], 'ACODEC': 'dts', 'ACODEC_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE': None, 'ACHANNELS': 8, 'ACODEC2': None, 'ACODEC2_ALLOW': [], 'ABITRATE2': None, 'ACHANNELS2': None, 'ACODEC3': 'ac3', 'ACODEC3_ALLOW': ['libfaac', 'dts', 'ac3', 'mp2', 'mp3'], 'ABITRATE3': None, 'ACHANNELS3': 8, 'SCODEC': 'mov_text'},
|
|
'MKV-SD': {'VEXTENSION': '.mkv', 'VCODEC': 'libx264', 'VPRESET': None, 'VFRAMERATE': None, 'VBITRATE': '1200k', 'VCRF': None, 'VLEVEL': None, 'VRESOLUTION': '720: -1', 'VCODEC_ALLOW': ['libx264', 'h264', 'h.264', 'AVC', 'avc', 'mpeg4', 'msmpeg4', 'MPEG-4'], 'ACODEC': 'aac', 'ACODEC_ALLOW': ['libfaac'], 'ABITRATE': 128000, 'ACHANNELS': 2, 'ACODEC2': 'ac3', 'ACODEC2_ALLOW': ['ac3'], 'ABITRATE2': None, 'ACHANNELS2': 6, 'ACODEC3': None, 'ACODEC3_ALLOW': [], 'ABITRATE3': None, 'ACHANNELS3': None, 'SCODEC': 'mov_text'},
|
|
}
|
|
if DEFAULTS and DEFAULTS in transcode_defaults:
|
|
VEXTENSION = transcode_defaults[DEFAULTS]['VEXTENSION']
|
|
VCODEC = transcode_defaults[DEFAULTS]['VCODEC']
|
|
VPRESET = transcode_defaults[DEFAULTS]['VPRESET']
|
|
VFRAMERATE = transcode_defaults[DEFAULTS]['VFRAMERATE']
|
|
VBITRATE = transcode_defaults[DEFAULTS]['VBITRATE']
|
|
VRESOLUTION = transcode_defaults[DEFAULTS]['VRESOLUTION']
|
|
VCRF = transcode_defaults[DEFAULTS]['VCRF']
|
|
VLEVEL = transcode_defaults[DEFAULTS]['VLEVEL']
|
|
VCODEC_ALLOW = transcode_defaults[DEFAULTS]['VCODEC_ALLOW']
|
|
ACODEC = transcode_defaults[DEFAULTS]['ACODEC']
|
|
ACODEC_ALLOW = transcode_defaults[DEFAULTS]['ACODEC_ALLOW']
|
|
ACHANNELS = transcode_defaults[DEFAULTS]['ACHANNELS']
|
|
ABITRATE = transcode_defaults[DEFAULTS]['ABITRATE']
|
|
ACODEC2 = transcode_defaults[DEFAULTS]['ACODEC2']
|
|
ACODEC2_ALLOW = transcode_defaults[DEFAULTS]['ACODEC2_ALLOW']
|
|
ACHANNELS2 = transcode_defaults[DEFAULTS]['ACHANNELS2']
|
|
ABITRATE2 = transcode_defaults[DEFAULTS]['ABITRATE2']
|
|
ACODEC3 = transcode_defaults[DEFAULTS]['ACODEC3']
|
|
ACODEC3_ALLOW = transcode_defaults[DEFAULTS]['ACODEC3_ALLOW']
|
|
ACHANNELS3 = transcode_defaults[DEFAULTS]['ACHANNELS3']
|
|
ABITRATE3 = transcode_defaults[DEFAULTS]['ABITRATE3']
|
|
SCODEC = transcode_defaults[DEFAULTS]['SCODEC']
|
|
del transcode_defaults
|
|
if VEXTENSION in allow_subs:
|
|
ALLOWSUBS = 1
|
|
if not VCODEC_ALLOW and VCODEC:
|
|
VCODEC_ALLOW.extend([VCODEC])
|
|
for codec in VCODEC_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in VCODEC_ALLOW]
|
|
VCODEC_ALLOW.extend(extra)
|
|
if not ACODEC_ALLOW and ACODEC:
|
|
ACODEC_ALLOW.extend([ACODEC])
|
|
for codec in ACODEC_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC_ALLOW]
|
|
ACODEC_ALLOW.extend(extra)
|
|
if not ACODEC2_ALLOW and ACODEC2:
|
|
ACODEC2_ALLOW.extend([ACODEC2])
|
|
for codec in ACODEC2_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC2_ALLOW]
|
|
ACODEC2_ALLOW.extend(extra)
|
|
if not ACODEC3_ALLOW and ACODEC3:
|
|
ACODEC3_ALLOW.extend([ACODEC3])
|
|
for codec in ACODEC3_ALLOW:
|
|
if codec in codec_alias:
|
|
extra = [item for item in codec_alias[codec] if item not in ACODEC3_ALLOW]
|
|
ACODEC3_ALLOW.extend(extra)
|