44from datetime import datetime
55import os
66import sys
7+
8+ # Verify script is colocated with ./src/ and import TranscodeSession.py
9+ if not os.path.isdir(os.path.join(sys.path[0], "src")):
10+ sys.exit("FATAL: ./src/ not present in parent diectory.\n")
711sys.path.append(os.path.join(sys.path[0], "src"))
8- from TranscodeSession import Session
12+ try:
13+ from TranscodeSession import Session
14+ except ImportError:
15+ sys.exit("FATAL: failed to import TranscodeSession from src/TranscodeSession.py\n")
916
1017"""
1118
1219TODO:
1320- allow comma-separated string for --preset, e.g. medium,slow,slower, map to list
14- - ~~if presets.json does not exist, download from github~~
15- - need to format source / output filenames: drop resolution suffixes
1621- add check: if working directory == script location, exit with warning to symlink transcode.py onto $PATH, else if different directory but no symlink, prompt to run --install
1722- add --install arg (with optional path to custom $PATH location) to create symlink at /usr/local/bin or custom $PATH location?
23+ - once profiling is complete, only append file decorator if --test is specified
1824
1925"""
2026
21- def main():
22- # Define command-line arguments
23- parser = argparse.ArgumentParser()
24- files_group = parser.add_mutually_exclusive_group(required=True)
25- files_group.add_argument("-f", "--file", help="relative path to movie in source directory")
26- files_group.add_argument("--all", action="store_true", help="transcode all supported movies in source directory")
27- parser.add_argument("-q", "--quality", type=int, help="HandBrake quality slider value (-12,51)")
28- parser.add_argument("--preset", help="override video encoder preset")
29- preset_group = parser.add_mutually_exclusive_group(required=False)
30- preset_group.add_argument("--baseline", action="store_true", help="use baseline encoder options")
31- preset_group.add_argument("--best", action="store_true", help="use highest quality encoder options")
32- parser.add_argument("--small", action="store_true", help="use additional encoder options to minimize filesize at the expense of speed")
33- parser.add_argument("--delete", action="store_true", help="delete output files when complete/interrupted")
34- args = parser.parse_args()
35- valid_arguments = False
27+ def build_source_list(args):
28+ """ Constructs and returns list of source files
29+ """
30+ extensions = [".mp4", ".m4v", ".mov", ".mkv", ".mpg", ".mpeg", ".avi", ".wmv", ".flv", ".webm", ".ts"]
31+ print("\nBuilding source list...")
32+ if args.all:
33+ source_files = ["source/" + file for file in os.listdir("source") if os.path.splitext(file)[1].lower() in extensions]
34+ else:
35+ if os.path.splitext(args.file)[1].lower() in extensions:
36+ source_files = [args.file]
37+ else:
38+ sys.exit("FATAL: " + args.file + " has invalid file extension!\n")
39+
40+ for source_file in source_files:
41+ session = Session(source_file, args)
42+ if os.path.exists(session.path["output"]):
43+ print(" Skipping", source_file)
44+ source_files = [file for file in source_files if file is not source_file]
45+
46+ if len(source_files) == 0:
47+ sys.exit("All supported files in ./source/ have already been transcoded. Exiting.\n")
48+ else:
49+ print(str(source_files) + "\n")
3650
37- # Validate command-line arguments
51+ return source_files
52+
53+ def validate_args(args):
54+ """ Exits with error messages if command-line arguments are invalid
55+ """
56+ valid_arguments = False
3857 if not "source" in os.listdir():
3958 print("FATAL: invalid working directory!")
4059 elif args.file and not os.path.exists(args.file):
@@ -45,6 +64,7 @@ def main():
4564 print("FATAL: quality must be between -12 and 51 (lower is slower + higher quality)")
4665 else:
4766 valid_arguments = True
67+
4868 if not valid_arguments:
4969 sys.exit("Invalid command-line arguments.\n")
5070 elif args.all and args.quality:
@@ -56,46 +76,41 @@ def main():
5676 if reply[0] == "n":
5777 sys.exit("Aborting invocation with --all and --quality options.\n")
5878
59- # Build list of source files and create directories if necessary
60- extensions = [".mp4", ".m4v", ".mov", ".mkv", ".mpg", ".mpeg", ".avi", ".wmv", ".flv", ".webm", ".ts"]
61- print("\nBuilding source list...")
62- if args.all:
63- source_files = ["source/" + file for file in os.listdir("source") if os.path.splitext(file)[1].lower() in extensions]
64- else:
65- source_files = [args.file]
66- for source_file in source_files:
67- session = Session(source_file, args)
68- if os.path.exists(session.path["output"]):
69- print(" Skipping", source_file)
70- source_files = [file for file in source_files if file is not source_file]
71- if len(source_files) == 0:
72- sys.exit("All source files have already been transcoded. Exiting.\n")
73- else:
74- print(str(source_files) + "\n")
75- if not os.path.exists("performance"):
76- os.mkdir("performance")
77- if not os.path.exists("hevc"):
78- os.mkdir("hevc")
79+ if not os.path.isdir("performance"):
80+ try:
81+ os.mkdir("performance")
82+ except FileExistsError:
83+ sys.exit("FATAL: can't create directory \"performance\" because file with same name exists")
84+ if not os.path.isdir("hevc"):
85+ try:
86+ os.mkdir("hevc")
87+ except FileExistsError:
88+ sys.exit("FATAL: can't create directory \"hevc\" because file with same name exists")
89+
90+ def main():
91+ # Define command-line arguments
92+ parser = argparse.ArgumentParser()
93+ files_group = parser.add_mutually_exclusive_group(required=True)
94+ files_group.add_argument("-f", "--file", help="relative path to movie in source directory")
95+ files_group.add_argument("--all", action="store_true", help="transcode all supported movies in source directory")
96+ parser.add_argument("-q", "--quality", type=int, help="HandBrake quality slider value (-12,51)")
97+ parser.add_argument("--preset", help="override video encoder preset")
98+ preset_group = parser.add_mutually_exclusive_group(required=False)
99+ preset_group.add_argument("--baseline", action="store_true", help="use baseline encoder options")
100+ preset_group.add_argument("--best", action="store_true", help="use highest quality encoder options")
101+ parser.add_argument("--small", action="store_true", help="use additional encoder options to minimize filesize at the expense of speed")
102+ parser.add_argument("--delete", action="store_true", help="delete output files when complete/interrupted")
103+ args = parser.parse_args()
104+ validate_args(args)
79105
80106 # Do the thing
107+ source_files = build_source_list(args)
81108 time_script_started = datetime.now()
82109 for file in source_files:
83110 session = Session(file, args)
84- session.summarize()
85- time_session_started = datetime.now()
86111 session.start()
87112 session.job.wait()
88- time_session_finished = datetime.now()
89- time_session_duration = time_session_finished - time_session_started
90- fps = session.source["frames"] / time_session_duration.seconds
91- source_file_size = session.source["filesize"] / 1000000
92- output_file_size = os.path.getsize(session.path["output"]) / 1000000
93- compression_ratio = int(100 - (output_file_size / source_file_size * 100))
94- print("\n{date}: Finished {output_file}".format(date=str(time_session_finished), output_file=session.path["output"]))
95- session.log(time_session_duration, fps, compression_ratio)
96- print("\n\n\n\n\n")
97- if args.delete:
98- session.cleanup()
113+ session.finish()
99114
100115 time_script_finished = datetime.now()
101116 time_script_duration = time_script_finished - time_script_started
0 commit comments