Skip to content
This repository was archived by the owner on Apr 18, 2023. It is now read-only.

Commit 4730173

Browse files
authoredJan 12, 2022
Merge pull request #5 from FarisR99/release-1.1.2
Release 1.1.2
2 parents 1fc9058 + ea21878 commit 4730173

File tree

6 files changed

+332
-247
lines changed

6 files changed

+332
-247
lines changed
 

‎Anime4K.py

+88-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import argparse
2+
import glob
23
import os
34
import sys
45

6+
from encode import encode_to_hevc
57
from extract_audio import extract_audio
68
from extract_subs import extract_subs
79
from multi import multi
@@ -11,7 +13,7 @@
1113
from utils import __current_version__, is_tool, credz, str2dict
1214

1315
# Constant variables
14-
MODES_SUPPORTING_MULTI_INPUTS = ["shader", "multi"]
16+
MODES_SUPPORTING_MULTI_INPUTS = ["shader", "multi", "encode"]
1517

1618
# Print credits
1719
credz()
@@ -43,6 +45,7 @@
4345
subs - Extract subtitles from a media file
4446
mux - Mux/compile a media file with audio files and subtitle files
4547
multi - Apply shader with -ss and -sa, audio, subs and mux mode in order
48+
encode - Encode media files using X265 with predefined settings
4649
split - Split a media file into parts''')
4750
parser.add_argument("-ew", "--width", required=False, type=int, default=3840,
4851
help="Desired width when applying shader")
@@ -69,10 +72,14 @@
6972
default=False,
7073
help="Set this flag if you want to manually mux audio when using mode shader")
7174
parser.add_argument("-sm", "--skip_menus", required=False, type=str2dict,
72-
help='''Skip shader/encoding choice menus when using mode shader
73-
Example:
75+
help='''Skip choice menus
76+
Examples for mode shader:
7477
--skip_menus="shader=4,encoder=cpu,codec=h264,preset=fast,crf=23"
75-
--skip_menus="shader=4,encoder=nvenc,codec=hevc,preset=fast,qp=24"''')
78+
--skip_menus="shader=4,encoder=nvenc,codec=hevc,preset=fast,qp=24"
79+
Example for mode audio:
80+
--skip_menus="convert=0"
81+
Example for mode encode:
82+
--skip_menus="encode=0"''')
7683
parser.add_argument("-al", "--audio_language", required=False, type=str,
7784
help=
7885
'''Set this to the audio track language for the output video.
@@ -82,6 +89,8 @@
8289
action='store_true',
8390
default=False,
8491
help="Set this flag to delete output files that have failed to compile when using mode multi")
92+
parser.add_argument("-si", "--skip_input", required=False, action='append',
93+
help="Input file to skip when using a directory as an input for modes shader and multi")
8594

8695
args = vars(parser.parse_args())
8796
if args['version']:
@@ -97,21 +106,25 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
97106
elif allow_dir is False:
98107
print("error: cannot use a directory ({0}) as an input for this mode"
99108
.format(file_path))
109+
sys.exit(-2)
100110

101111

102-
fn = args['input']
112+
# Validate "mode" argument
103113
mode = str(args['mode']).lower()
114+
if mode == "subtitles":
115+
mode = "subs"
104116

105117
# Validate "input" argument
118+
fn = args['input']
106119
if fn is None:
107120
parser.print_help()
108121
print("error: the following arguments are required: -i/--input")
109122
sys.exit(-2)
110123
if type(fn) is list:
111124
if len(fn) != 1:
112-
if mode != "shader":
125+
if mode not in MODES_SUPPORTING_MULTI_INPUTS:
113126
print(
114-
"error: Cannot use multiple inputs with mode={0}".format(mode))
127+
"error: cannot use multiple inputs with mode={0}".format(mode))
115128
sys.exit(-2)
116129
for file in fn:
117130
exit_if_missing(file, mode in MODES_SUPPORTING_MULTI_INPUTS)
@@ -120,9 +133,9 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
120133
exit_if_missing(fn, mode in MODES_SUPPORTING_MULTI_INPUTS)
121134
else:
122135
exit_if_missing(fn, mode in MODES_SUPPORTING_MULTI_INPUTS)
123-
124-
if mode == "subtitles":
125-
mode = "subs"
136+
if mode in MODES_SUPPORTING_MULTI_INPUTS:
137+
if type(fn) is str:
138+
fn = [fn]
126139

127140
# Validate "output" argument
128141
if mode == "audio" or mode == "subs":
@@ -131,36 +144,86 @@ def exit_if_missing(file_path: str, allow_dir: bool = True):
131144
output = ""
132145
if output != "":
133146
if not os.path.isdir(output):
134-
print("Output directory {0} does not exist".format(output))
147+
print("error: output directory {0} does not exist".format(output))
135148
sys.exit(-2)
136149
else:
137150
if not output.endswith("/"):
138151
output = output + "/"
139-
elif mode == "mux" or mode == "shader" or mode == "multi":
152+
elif mode in MODES_SUPPORTING_MULTI_INPUTS:
153+
output = args['output'] or "out.mkv"
154+
if os.path.isdir(output) and not os.path.exists(output):
155+
try:
156+
os.mkdir(output)
157+
except Exception as e:
158+
print(
159+
"error: failed to create output directory={0}:".format(output))
160+
print(e)
161+
sys.exit(-2)
162+
else:
140163
output = args['output'] or "out.mkv"
141-
elif mode == "split":
142-
output = args['output']
143164

165+
# Collect input file paths from the input argument(s)
166+
in_files = []
167+
if mode in MODES_SUPPORTING_MULTI_INPUTS:
168+
skip_inputs = args['skip_input']
169+
if skip_inputs is None:
170+
skip_inputs = []
171+
elif type(skip_inputs) is str:
172+
skip_inputs = [skip_inputs]
173+
174+
for file in fn:
175+
if os.path.isdir(file):
176+
for file_in_dir in glob.glob(
177+
os.path.join(file, "*.mkv")
178+
) + glob.glob(
179+
os.path.join(file, "*.mp4")
180+
):
181+
file_name = os.path.basename(file_in_dir)
182+
if file_name in skip_inputs:
183+
continue
184+
in_files.append(os.path.join(file_in_dir))
185+
else:
186+
# Only here for consistency
187+
# Why would you specify a file input then add that file
188+
# to a list of files to ignore?
189+
if file in skip_inputs:
190+
continue
191+
in_files.append(os.path.join(file))
192+
file_count = len(in_files)
193+
if file_count > 1:
194+
if not os.path.isdir(output):
195+
print(
196+
"error: output path must be a directory when there are more than one input files")
197+
sys.exit(-2)
198+
elif file_count == 0:
199+
print("error: no valid input media files found")
200+
sys.exit(-2)
201+
202+
# Validate "skip_menus" argument
203+
skip_menus = args['skip_menus']
204+
if skip_menus is None:
205+
skip_menus = {}
206+
207+
# Perform action based on mode
144208
if mode == "audio":
145-
extract_audio(fn, output)
209+
extract_audio(fn, output, skip_menus)
146210
elif mode == "subs":
147211
extract_subs(fn, output)
148212
elif mode == "mux":
149213
mux(fn, output)
150214
elif mode == "shader":
151-
if type(fn) is str:
152-
fn = [fn]
153-
shader(fn, args['width'], args['height'], args['shader_dir'], args['bit'],
154-
args['audio_language'], args['softsubs'], args['softaudio'],
155-
args['skip_menus'] or {}, output)
215+
shader(in_files, args['width'], args['height'],
216+
args['shader_dir'], args['bit'], args['audio_language'],
217+
args['softsubs'], args['softaudio'], skip_menus, True, output)
156218
elif mode == "multi":
157-
if type(fn) is str:
158-
fn = [fn]
159-
multi(fn, args['width'], args['height'], args['shader_dir'], args['bit'],
160-
args['skip_menus'], args['delete_failures'], output)
219+
multi(in_files, args['width'], args['height'],
220+
args['shader_dir'], args['bit'], skip_menus,
221+
args['delete_failures'], output)
222+
elif mode == "encode":
223+
encode_to_hevc(in_files, output, skip_menus)
161224
elif mode == "split":
162225
length = get_video_length(fn)
163226
split_by_seconds(filename=fn, split_length=args['split_length'],
164227
video_length=length, split_dir=output)
165228
else:
166-
print("Unknown option: {0}".format(mode))
229+
print("Unknown mode: {0}".format(mode))

‎encode.py

+100-107
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import glob
21
import os
32
import subprocess
43
import sys
@@ -8,134 +7,128 @@
87
from utils import current_date, is_tool, clear
98

109

11-
def encode_to_hevc(fn: str, out: str):
10+
def encode_to_hevc(input_files: "list[str]", out: str,
11+
skip_menus: dict) -> dict:
1212
"""
13-
Encode a media file to HEVC
13+
Encode a media file to HEVC using X265
1414
1515
Args:
16-
fn: media file path
16+
input_files: list of input media file paths
1717
out: output path
18+
skip_menus: menu skipping options passed from command line
19+
Returns:
20+
a mapping of successfully encoded input files to their output paths
1821
"""
1922

2023
param_line = "crf=18.0:limit-sao=1:bframes=8:aq-mode=3:psy-rd=1.0"
2124

22-
detail_menu = TerminalMenu([
23-
"One setting to rule them all (Recommended if you don't know)",
24-
"Flat, slow anime (slice of life, everything is well lit, e.g. Your Name)",
25-
"Some dark scenes, some battle scenes (shonen, historical, etc., e.g. Kimetsu no Yaiba)",
26-
"[TV Series] Movie-tier dark scene, complex grain/detail (Rarely used)",
27-
"[Movie] Movie-tier dark scene, complex grain/detail (Rarely used)",
28-
], title="Choose the encode options")
25+
detail_choice = None
26+
if "encode" in skip_menus:
27+
detail_choice = int(skip_menus["encode"])
28+
if detail_choice < 0 or detail_choice > 4:
29+
detail_choice = None
30+
if detail_choice is None:
31+
detail_menu = TerminalMenu([
32+
"One setting to rule them all (Recommended if you don't know)",
33+
"Flat, slow anime (slice of life, everything is well lit, e.g. Your Name)",
34+
"Some dark scenes, some battle scenes (shonen, historical, etc., e.g. Kimetsu no Yaiba)",
35+
"[TV Series] Movie-tier dark scene, complex grain/detail (Rarely used)",
36+
"[Movie] Movie-tier dark scene, complex grain/detail (Rarely used)",
37+
], title="Choose the encode options")
38+
detail_choice = detail_menu.show()
39+
if detail_choice is None:
40+
print("Cancelled")
41+
sys.exit(-1)
2942

30-
choice = detail_menu.show()
31-
# Flat, slow anime (slice of life, everything is well lit)
32-
if choice == 1:
43+
if detail_choice == 1:
44+
# Flat, slow anime (slice of life, everything is well lit)
3345
param_line = "crf=19.0:bframes=8:aq-mode=3:psy-rd=1:aq-strength=0.8:deblock=1,1"
34-
# Some dark scenes, some battle scenes (shonen, historical, etc.)
35-
elif choice == 2:
46+
elif detail_choice == 2:
47+
# Some dark scenes, some battle scenes (shonen, historical, etc.)
3648
param_line = "crf=18.0:bframes=8:aq-mode=3:psy-rd=1.5:psy-rdoq=2"
37-
# [TV Series] Movie-tier dark scene, complex grain/detail
38-
elif choice == 3:
49+
elif detail_choice == 3:
50+
# [TV Series] Movie-tier dark scene, complex grain/detail
3951
param_line = "crf=18.0:limit-sao=1:bframes=8:aq-mode=3:psy-rd=1.5:psy-rdoq=3.5"
40-
# [Movie] Movie-tier dark scene, complex grain/detail
41-
elif choice == 4:
52+
elif detail_choice == 4:
53+
# [Movie] Movie-tier dark scene, complex grain/detail
4254
param_line = "crf=16.0:limit-sao=1:bframes=8:aq-mode=3:psy-rd=1.5:psy-rdoq=3.5"
4355

4456
if is_tool("ffmpeg-bar"):
4557
binary = "ffmpeg-bar"
4658
else:
4759
binary = "ffmpeg"
4860

49-
files = []
50-
if os.path.isdir(fn):
51-
for file in glob.glob(os.path.join(fn, "*.mkv")):
52-
files.append(os.path.join(file))
53-
if len(files) == 0:
54-
print("Encoding start time: " + current_date())
55-
cmd = [
56-
binary,
57-
"-hide_banner",
58-
"-i",
59-
fn,
60-
"-c:v",
61-
"libx265",
62-
"-profile:v",
63-
"main10",
64-
"-pix_fmt",
65-
"yuv420p10le",
66-
"-preset",
67-
"slow",
68-
"-x265-params",
69-
param_line,
70-
"-map",
71-
"0:v:0",
72-
"-f",
73-
"matroska",
74-
'-vf',
75-
'scale=out_color_matrix=bt709',
76-
'-color_primaries',
77-
'bt709',
78-
'-color_trc',
79-
'bt709',
80-
'-colorspace',
81-
'bt709',
82-
out
83-
]
61+
cmd = [
62+
binary,
63+
"-hide_banner",
64+
"-c:v",
65+
"libx265",
66+
"-profile:v",
67+
"main10",
68+
"-pix_fmt",
69+
"yuv420p10le",
70+
"-preset",
71+
"slow",
72+
"-x265-params",
73+
param_line,
74+
"-map",
75+
"0:v:0",
76+
"-f",
77+
"matroska",
78+
'-vf',
79+
'scale=out_color_matrix=bt709',
80+
'-color_primaries',
81+
'bt709',
82+
'-color_trc',
83+
'bt709',
84+
'-colorspace',
85+
'bt709'
86+
]
87+
88+
encoded_files = {}
89+
90+
file_count = len(input_files)
91+
start_time = current_date()
92+
print("Encoding start time: " + start_time)
93+
i = 0
94+
for f in input_files:
95+
print("Encoding start time for file={0}: {1}".format(
96+
str(i + 1),
97+
current_date()
98+
))
99+
100+
cmd.append("-i")
101+
cmd.append(f)
102+
output_path = None
103+
if file_count == 1 and not os.path.isdir(out):
104+
output_path = os.path.join(out)
105+
else:
106+
name = f.split("/")
107+
name = name[len(name) - 1]
108+
output_path = os.path.join(out, name + "-encoded.mkv")
109+
cmd.append(output_path)
110+
111+
return_code = -1
84112
try:
85-
subprocess.call(cmd)
113+
return_code = subprocess.call(cmd)
86114
except KeyboardInterrupt:
87-
print("Cancelled encoding, exiting program...")
115+
print("Cancelled encoding for file={0}".format(f))
116+
print("Exiting program...")
88117
try:
89118
sys.exit(-1)
90119
except SystemExit:
91120
os._exit(-1)
92-
print("Encoding end time: " + current_date())
93-
else:
94-
print("Encoding start time: " + current_date())
95-
i = 0
96-
for f in files:
97-
clear()
98-
name = f.split("/")
99-
name = name[len(name) - 1]
100-
cmd = [
101-
binary,
102-
"-hide_banner",
103-
"-i",
104-
f,
105-
"-c:v",
106-
"libx265",
107-
"-profile:v",
108-
"main10",
109-
"-pix_fmt",
110-
"yuv420p10le",
111-
"-preset",
112-
"slow",
113-
"-x265-params",
114-
param_line,
115-
"-map",
116-
"0:v:0",
117-
"-f",
118-
"matroska",
119-
'-vf',
120-
'scale=out_color_matrix=bt709',
121-
'-color_primaries',
122-
'bt709',
123-
'-color_trc',
124-
'bt709',
125-
'-colorspace',
126-
'bt709',
127-
os.path.join(out, name)
128-
]
129-
try:
130-
subprocess.call(cmd)
131-
except KeyboardInterrupt:
132-
print("Cancelled encoding for file={0}".format(f))
133-
print("Exiting program...")
134-
try:
135-
sys.exit(-1)
136-
except SystemExit:
137-
os._exit(-1)
138-
print("Encoding end time for file=" + str(
139-
i + 1) + ": " + current_date())
140-
i = i + 1
141-
print("Encoding end time: " + current_date())
121+
if return_code == 0:
122+
encoded_files[f] = output_path
123+
else:
124+
print("error: failed to encode file={0}".format(f))
125+
print("Encoding end time for file={0}: {1}".format(
126+
str(i + 1),
127+
current_date())
128+
)
129+
i = i + 1
130+
clear()
131+
print("Encoding start time: " + start_time)
132+
print("Encoded files: {0}".format(", ".join(encoded_files.keys())))
133+
print("Encoding end time: " + current_date())
134+
return encoded_files

‎extract_audio.py

+41-20
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
from utils import current_date, language_mapping
1111

1212

13-
def extract_audio(fn: str, out_dir: str) -> bool:
13+
def extract_audio(fn: str, out_dir: str, skip_menus: dict) -> bool:
1414
"""
1515
Extract audio from a media file.
1616
1717
Args:
1818
fn: input media file path
1919
out_dir: directory where audio files are extracted to
20+
skip_menus: menu skipping options passed from command line
2021
Returns:
2122
True if the audio tracks were successfully extracted
2223
"""
@@ -44,6 +45,7 @@ def extract_audio(fn: str, out_dir: str) -> bool:
4445
])
4546
except KeyboardInterrupt:
4647
print("Cancelled track extraction.")
48+
print("Please clear the audio files in the current directory.")
4749
print("Exiting program...")
4850
try:
4951
sys.exit(-1)
@@ -58,31 +60,54 @@ def extract_audio(fn: str, out_dir: str) -> bool:
5860
for file in glob.glob(out_dir + "*.FLAC"):
5961
flacs.append(file)
6062
if len(flacs) > 0:
61-
convert_menu = TerminalMenu(
62-
["Yes", "No"],
63-
title="Do you want to convert every FLAC to Opus?"
64-
)
65-
convert_choice = convert_menu.show()
63+
convert_choice = None
64+
if "convert" in skip_menus:
65+
convert_choice = int(skip_menus['convert'])
66+
if convert_choice < 0 or convert_choice > 1:
67+
convert_choice = None
68+
else:
69+
# Flip the value, because "1" in the command line arg means
70+
# "Yes" which is at index 0 in convert_menu choice array
71+
convert_choice = 1 - convert_choice
72+
if convert_choice is None:
73+
convert_menu = TerminalMenu(
74+
["Yes", "No"],
75+
title="Do you want to convert every FLAC to Opus?"
76+
)
77+
convert_choice = convert_menu.show()
78+
if convert_choice is None:
79+
print("Cancelled conversion")
80+
6681
if convert_choice == 0:
6782
print("Conversion start time: " + current_date())
6883
for f in flacs:
69-
br_menu = TerminalMenu(
70-
["192K", "256K", "320K"],
71-
title="What's the format of the file? => {0}".format(f)
72-
)
73-
br_choice = br_menu.show()
84+
bit_rates = ["192K", "256K", "320K"]
85+
br_choice = None
86+
if "bitrate" in skip_menus:
87+
br_choice = bit_rates.index(skip_menus["bitrate"])
88+
if br_choice < 0 or br_choice > 2:
89+
br_choice = None
90+
if br_choice is None:
91+
br_menu = TerminalMenu(
92+
bit_rates,
93+
title="What's the format of the file? => {0}".format(f)
94+
)
95+
br_choice = br_menu.show()
96+
if br_choice is None:
97+
print("Cancelled conversion")
98+
continue
7499
if br_choice == 0:
75100
br = "192K"
76101
elif br_choice == 1:
77102
br = "256K"
78103
elif br_choice == 2:
79104
br = "320K"
80-
else:
81-
br = "192K"
105+
82106
fn_base = f.split(".")[0]
83107
out_audio = fn_base + ".Opus"
108+
return_code = -1
84109
try:
85-
subprocess.call([
110+
return_code = subprocess.call([
86111
"ffmpeg",
87112
"-hide_banner",
88113
"-i",
@@ -98,12 +123,8 @@ def extract_audio(fn: str, out_dir: str) -> bool:
98123
except KeyboardInterrupt:
99124
print("Cancelled conversion.")
100125
os.remove(out_audio)
101-
print("Exiting program...")
102-
try:
103-
sys.exit(-1)
104-
except SystemExit:
105-
os._exit(-1)
106126
time.sleep(1)
107-
os.remove(f)
127+
if return_code == 0:
128+
os.remove(f)
108129
print("Conversion end time: " + current_date())
109130
return success

‎multi.py

+12-9
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
from extract_subs import extract_subs
66
from mux import clean_up, mux
77
from shader import shader
8+
from utils import clear
89

910

10-
def multi(fn: "list[str]", width: int, height: int, shader_path: str,
11+
def multi(input_files: "list[str]", width: int, height: int, shader_path: str,
1112
ten_bit: bool, skip_menus: dict, del_failures: bool, outname: str):
1213
"""
1314
Run mode shader on the input files, then for each file successfully
@@ -16,7 +17,7 @@ def multi(fn: "list[str]", width: int, height: int, shader_path: str,
1617
extracted subs and audio track files.
1718
1819
Args:
19-
fn: list of input files
20+
input_files: list of input media files
2021
width: desired width of video
2122
height: desired height of video
2223
shader_path: path where the shaders are located
@@ -30,15 +31,17 @@ def multi(fn: "list[str]", width: int, height: int, shader_path: str,
3031

3132
if skip_menus is None:
3233
skip_menus = {}
33-
encoded_files = shader(fn=fn, width=width, height=height,
34-
shader_path=shader_path,
35-
ten_bit=ten_bit, language="", softsubs=True,
36-
softaudio=True,
37-
skip_menus=skip_menus, outname=outname)
34+
encoded_files = shader(input_files=input_files, width=width, height=height,
35+
shader_path=shader_path, ten_bit=ten_bit,
36+
language="", softsubs=True,
37+
softaudio=True, skip_menus=skip_menus,
38+
exit_on_cancel=False, outname=outname)
39+
clear()
3840
if len(encoded_files) == 0:
39-
print()
4041
print("error: no files encoded, terminating program early...")
4142
sys.exit(-2)
43+
else:
44+
print("Encoded files: {0}".format(", ".join(encoded_files.keys())))
4245

4346
successful_inputs = {}
4447
failed_inputs = []
@@ -59,7 +62,7 @@ def multi(fn: "list[str]", width: int, height: int, shader_path: str,
5962
continue
6063
print()
6164
print("Starting mode audio for input={0}".format(input_path))
62-
if not extract_audio(input_path, ""):
65+
if not extract_audio(input_path, "", skip_menus):
6366
print(
6467
"Failed to extract audio for file={0}".format(input_path)
6568
)

‎shader.py

+90-85
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import glob
21
import os
32
import subprocess
43
import sys
@@ -24,10 +23,12 @@ def menu_fhd_shaders(shader_path: str, skip_menus: dict) -> str:
2423
"""
2524

2625
mode_choice = None
27-
if "shader" in skip_menus and skip_menus['shader'] is not None:
26+
if "shader" in skip_menus:
2827
mode_choice = int(skip_menus['shader'])
2928
if mode_choice < 0 or mode_choice > 5:
3029
mode_choice = None
30+
elif "recommended" in skip_menus and skip_menus['recommended'] == "1":
31+
mode_choice = 4
3132
if mode_choice is None:
3233
mode_menu = TerminalMenu(
3334
[
@@ -133,14 +134,16 @@ def menu_fhd_shaders(shader_path: str, skip_menus: dict) -> str:
133134

134135
# Core
135136

136-
def remove_audio_and_subs(fn: str, softsubs: bool, softaudio: bool):
137+
def remove_audio_and_subs(fn: str, softsubs: bool, softaudio: bool) -> int:
137138
"""
138139
Remove audio and optionally subtitles from a file.
139140
140141
Args:
141142
fn: media file path
142143
softsubs: true if subtitles should be removed
143144
softaudio: true if audio should be removed
145+
Returns:
146+
return code of the merge process
144147
"""
145148

146149
args = [
@@ -155,7 +158,7 @@ def remove_audio_and_subs(fn: str, softsubs: bool, softaudio: bool):
155158
args.append(fn)
156159

157160
try:
158-
subprocess.call(args)
161+
return subprocess.call(args)
159162
except KeyboardInterrupt:
160163
print("File processing cancelled for file={0}".format(fn))
161164
shader_cleanup()
@@ -174,15 +177,42 @@ def shader_cleanup():
174177
os.remove("temp.mkv")
175178

176179

177-
def shader(fn: "list[str]", width: int, height: int, shader_path: str,
178-
ten_bit: bool,
179-
language: str, softsubs: bool, softaudio: bool, skip_menus: dict,
180-
outname: str) -> dict:
180+
def handle_encoding_cancellation(file_name: str, output_file, start_time: str,
181+
exit: bool):
182+
"""
183+
Handle cancellation during encoding
184+
185+
Args:
186+
file_name: The current file being encoded
187+
output_file: The output file to delete
188+
start_time: The time the first file began encoding
189+
exit: true if the program should terminate
190+
"""
191+
192+
print("Cancelled encoding of file={0}".format(file_name))
193+
print("Start time: {0}".format(start_time))
194+
print("End time: " + current_date())
195+
print()
196+
print("Deleting temporary files...")
197+
shader_cleanup()
198+
if output_file is not None:
199+
os.remove(output_file)
200+
if exit:
201+
print("Exiting program...")
202+
try:
203+
sys.exit(-1)
204+
except SystemExit:
205+
os._exit(-1)
206+
207+
208+
def shader(input_files: "list[str]", width: int, height: int, shader_path: str,
209+
ten_bit: bool, language: str, softsubs: bool, softaudio: bool,
210+
skip_menus: dict, exit_on_cancel: bool, outname: str) -> dict:
181211
"""
182212
Select encoding and start the encoding process.
183213
184214
Args:
185-
fn: list of input media paths
215+
input_files: list of input media paths
186216
width: output width
187217
height: output height
188218
shader_path: path the shaders are located at
@@ -191,6 +221,8 @@ def shader(fn: "list[str]", width: int, height: int, shader_path: str,
191221
softsubs: true if subtitles should be removed
192222
softaudio: true if audio should be removed
193223
skip_menus: menu skipping options passed from command line
224+
exit_on_cancel: true if the program should exit when the user cancels
225+
during encoding, false if the function call should terminate
194226
outname: output path
195227
196228
Returns:
@@ -202,41 +234,33 @@ def shader(fn: "list[str]", width: int, height: int, shader_path: str,
202234
shader_path))
203235
sys.exit(-2)
204236

205-
files = []
206-
for file in fn:
207-
if os.path.isdir(file):
208-
for fileInDir in glob.glob(os.path.join(file, "*.mkv")):
209-
files.append(os.path.join(fileInDir))
210-
for fileInDir in glob.glob(os.path.join(file, "*.mp4")):
211-
files.append(os.path.join(fileInDir))
212-
else:
213-
files.append(os.path.join(file))
214-
file_count = len(files)
215-
if file_count > 1:
216-
if not os.path.isdir(outname):
217-
print(
218-
"error: output path must be a directory when there are more than one input files")
219-
sys.exit(-2)
220-
elif file_count == 0:
221-
print("error: no valid input media files found")
222-
sys.exit(-2)
223-
else:
224-
clear()
225-
if os.path.isdir(outname):
226-
outname = os.path.join(outname, "out.mkv")
227-
remove_audio_and_subs(files[0], softsubs, softaudio)
237+
output_is_dir = os.path.isdir(outname)
238+
if len(input_files) == 1:
239+
if output_is_dir:
240+
new_outname = os.path.join(outname, "out.mkv")
241+
out_name_index = 1
242+
while os.path.exists(new_outname):
243+
new_outname = os.path.join(outname, "out-{0}.mkv"
244+
.format(str(out_name_index)))
245+
out_name_index = out_name_index + 1
246+
outname = new_outname
247+
output_is_dir = False
248+
remove_audio_and_subs(input_files[0], softsubs, softaudio)
228249
clear()
229250

230251
# Select encoder
231252
codec = ""
232253
encoder = ""
233254

234-
if "encoder" in skip_menus and skip_menus['encoder'] is not None:
255+
if "encoder" in skip_menus:
235256
encoder = skip_menus['encoder']
236257
if encoder != 'cpu' and encoder != 'nvenc' and encoder != 'amf':
237258
print("Unsupported encoder: {0}".format(encoder))
238259
sys.exit(-2)
239-
if "codec" in skip_menus and skip_menus['codec'] is not None:
260+
if encoder == "":
261+
if "recommended" in skip_menus and skip_menus["recommended"] == "1":
262+
encoder = "cpu"
263+
if "codec" in skip_menus:
240264
codec = skip_menus['codec']
241265
if codec == 'x264':
242266
codec = 'h264'
@@ -249,6 +273,9 @@ def shader(fn: "list[str]", width: int, height: int, shader_path: str,
249273
if codec != 'h264' and codec != 'hevc':
250274
print("Unsupported codec={0}".format(encoder))
251275
sys.exit(-2)
276+
if codec == "":
277+
if "recommended" in skip_menus and skip_menus["recommended"] == "1":
278+
codec = "h264"
252279
if codec == "" or encoder == "":
253280
cg_menu = TerminalMenu(
254281
[
@@ -286,58 +313,17 @@ def shader(fn: "list[str]", width: int, height: int, shader_path: str,
286313
sys.exit(-2)
287314

288315
return start_encoding(codec, encoder, width, height, shader_path, ten_bit,
289-
language, softsubs, softaudio, skip_menus, outname,
290-
files)
291-
292-
293-
def handle_encoding_cancellation(file_name: str, output_file, start_time: str):
294-
"""
295-
Handle cancellation during encoding
296-
297-
Args:
298-
file_name: The current file being encoded
299-
output_file: The output file to delete
300-
start_time: The time the first file began encoding
301-
"""
302-
303-
print("Cancelled encoding of file={0}".format(file_name))
304-
print("Start time: {0}".format(start_time))
305-
print("End time: " + current_date())
306-
print()
307-
print("Deleting temporary files...")
308-
shader_cleanup()
309-
if output_file is not None:
310-
os.remove(output_file)
311-
print("Exiting program...")
312-
try:
313-
sys.exit(-1)
314-
except SystemExit:
315-
os._exit(-1)
316+
language, softsubs, softaudio, skip_menus,
317+
exit_on_cancel, input_files, outname)
316318

317319

318320
def start_encoding(codec: str, encoder: str, width: int, height: int,
319321
shader_path: str, ten_bit: bool, language: str,
320322
softsubs: bool, softaudio: bool, skip_menus: dict,
321-
outname: str, files: "list[str]") -> dict:
323+
exit_on_cancel: bool, files: "list[str]",
324+
outname: str) -> dict:
322325
"""
323326
Start the encoding of input file(s) to the specified encoding using the CPU.
324-
325-
Args:
326-
codec: h264/hevc
327-
encoder: cpu/nvenc/amf
328-
width: output width
329-
height: output height
330-
shader_path: path the shaders are located at
331-
ten_bit: true if the input media is a 10 bit source
332-
language: optional desired audio track language
333-
softsubs: true if subtitles should be removed
334-
softaudio: true if audio should be removed
335-
skip_menus: menu skipping options passed from command line
336-
outname: output path
337-
files: list of input media file paths
338-
339-
Returns:
340-
mapping of files that were successfully encoded to their output paths
341327
"""
342328

343329
clear()
@@ -365,10 +351,12 @@ def start_encoding(codec: str, encoder: str, width: int, height: int,
365351
elif encoder == "nvenc":
366352
codec_presets = ["fast", "medium", "slow", "lossless"]
367353
codec_preset = None
368-
if "preset" in skip_menus and skip_menus['preset'] is not None:
354+
if "preset" in skip_menus:
369355
codec_preset = skip_menus['preset']
370356
if codec_preset not in codec_presets:
371357
codec_preset = None
358+
elif "recommended" in skip_menus and skip_menus["recommended"] == "1":
359+
codec_preset = "fast"
372360
if codec_preset is None:
373361
selected_codec_preset = TerminalMenu(codec_presets,
374362
title="Choose Encoder Preset:").show()
@@ -380,29 +368,33 @@ def start_encoding(codec: str, encoder: str, width: int, height: int,
380368

381369
comp_level = ""
382370
if encoder == "cpu":
383-
if "crf" in skip_menus and skip_menus['crf'] is not None:
371+
if "crf" in skip_menus:
384372
crf = int(skip_menus['crf'])
385373
if 0 <= crf <= 51:
386374
comp_level = str(crf)
387375
else:
388376
comp_level = "23"
389377
print("Invalid crf provided, using default crf={0}".format(
390378
comp_level))
379+
elif "recommended" in skip_menus and skip_menus["recommended"] == "1":
380+
comp_level = "23"
391381
else:
392382
comp_level = input(
393383
"Insert compression factor (CRF) 0-51\n0 = Lossless | 23 = Default | 51 = Highest compression\n"
394384
)
395385
if comp_level == "" or comp_level is None:
396386
comp_level = "23"
397387
elif encoder == "nvenc" or encoder == "amf":
398-
if "qp" in skip_menus and skip_menus['qp'] is not None:
388+
if "qp" in skip_menus:
399389
qp = int(skip_menus['qp'])
400390
if 0 <= qp <= 51:
401391
comp_level = str(qp)
402392
else:
403393
comp_level = "24"
404394
print("Invalid qp provided, using default qp={0}".format(
405395
comp_level))
396+
elif "recommended" in skip_menus and skip_menus["recommended"] == "1":
397+
comp_level = "24"
406398
else:
407399
comp_level = input(
408400
"Insert Quantization Parameter (QP) 0-51\n0 = Lossless | 24 = Default | 51 = Highest compression\n"
@@ -505,7 +497,9 @@ def start_encoding(codec: str, encoder: str, width: int, height: int,
505497
encoding_args + ['--o=' + outname, "temp.mkv"]
506498
)
507499
except KeyboardInterrupt:
508-
handle_encoding_cancellation(files[0], outname, start_time)
500+
handle_encoding_cancellation(files[0], outname, start_time,
501+
exit_on_cancel)
502+
return successful_encodes
509503
print("End time: " + current_date())
510504
os.remove("temp.mkv")
511505
print()
@@ -524,7 +518,15 @@ def start_encoding(codec: str, encoder: str, width: int, height: int,
524518
name = name[len(name) - 1]
525519
remove_audio_and_subs(f, softsubs, softaudio)
526520
clear()
527-
print("Files: {0}".format(files_string))
521+
print("Encoded files: {0}".format(
522+
", ".join(successful_encodes.keys())))
523+
print("Remaining files: {0}".format(", ".join(
524+
[
525+
item for item in files
526+
if
527+
item not in failed_files and item not in successful_encodes
528+
]
529+
)))
528530
print("Start time: {0}".format(start_time))
529531
print("Start time for file={0}: {1}".format(str(i + 1),
530532
current_date()))
@@ -538,7 +540,10 @@ def start_encoding(codec: str, encoder: str, width: int, height: int,
538540
"temp.mkv"
539541
])
540542
except KeyboardInterrupt:
541-
handle_encoding_cancellation(f, output_path, start_time)
543+
handle_encoding_cancellation(f, output_path, start_time,
544+
exit_on_cancel)
545+
return successful_encodes
546+
542547
if return_code != 0:
543548
failed_files.append(f)
544549
else:

‎utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from datetime import datetime
33
from shutil import which
44

5-
__current_version__ = '1.1.1'
5+
__current_version__ = '1.1.2'
66

77

88
def credz():

0 commit comments

Comments
 (0)
This repository has been archived.