diff --git a/README.md b/README.md index eff518f..ae98641 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The `TwoPass()` Class showcases a 2-pass encoding methodology for the `ffmpeg-py ## Installation -This package works with Python >= 3.8. For Windows users, ensure that Python is added to your system's PATH. +This package works with Python >= 3.8. For Windows users, ensure that Python is added to your system's PATH. I highly recommend that you use the [python.org](https://python.org) Python installation. Install this package with the following command. @@ -65,7 +65,10 @@ You can edit the name of your video file if you need to trim it to a specific se - From the top-left of your video, this example goes 255 pixels to the right, 0 pixels down, and it carves out a 1410x1080 section of the video. - [FFmpeg crop documentation](https://ffmpeg.org/ffmpeg-filters.html#Examples-61) - `--web` - - A Boolean flag. No value is needed after the flag. See [Web UI](#web-ui) for more information on the Web UI. + - Launch the Web UI for this job. A Boolean flag. No value is needed after the flag. See [Web UI](#web-ui) for more information on the Web UI. +- `-p`, `--port` + - Example: `5333` + - Run the Web UI on a specifc port. - `--config` - Example: `custom_run_config.json` - Path to a json file containing the configuration for the above parameters. This config file takes precedence over all of the other flags. diff --git a/ffmpeg4discord/app.py b/ffmpeg4discord/__main__.py similarity index 77% rename from ffmpeg4discord/app.py rename to ffmpeg4discord/__main__.py index 9b5b16c..27afb37 100644 --- a/ffmpeg4discord/app.py +++ b/ffmpeg4discord/__main__.py @@ -11,18 +11,8 @@ from ffmpeg4discord import arguments from ffmpeg4discord.twopass import TwoPass -# get args from the command line -args = arguments.get_args() -web = args.pop("web") -port = args.pop("port") -path = Path(args["filename"]).resolve() -args["filename"] = path -# instantiate the TwoPass class -twopass = TwoPass(**args) - - -def twopass_loop(target_filesize: float) -> str: +def twopass_loop(twopass: TwoPass, target_filesize: float) -> None: while twopass.run() >= target_filesize: print( f"\nThe output file size ({round(twopass.output_filesize, 2)}MB) is still above the target of {target_filesize}MB.\nRestarting...\n" @@ -32,10 +22,7 @@ def twopass_loop(target_filesize: float) -> str: # adjust the class's target file size to set a lower bitrate for the next run twopass.target_filesize -= 0.2 - success_message = f"Your compressed video file ({round(twopass.output_filesize, 2)}MB) is located at {Path(twopass.output_filename).resolve()}" - print(success_message) - - return success_message + twopass.message = f"Your compressed video file ({round(twopass.output_filesize, 2)}MB) is located at {Path(twopass.output_filename).resolve()}" def seconds_to_timestamp(seconds: int) -> str: @@ -48,12 +35,25 @@ def seconds_to_timestamp(seconds: int) -> str: return timestamp -def open_browser() -> None: +def open_browser(port: int) -> None: time.sleep(0.5) webbrowser.open(f"http://localhost:{port}") def main() -> None: + # get args from the command line + args = arguments.get_args() + web = args.pop("web") + + if web: + port = args.pop("port") + + path = Path(args["filename"]).resolve() + args["filename"] = path + + # instantiate the TwoPass class + twopass = TwoPass(**args) + if web: app = Flask(__name__, static_folder=path.parent) @@ -79,7 +79,7 @@ def form_twopass(): twopass.crop = request.form.get("crop") twopass.output_dir = request.form.get("output_dir") - success_message = twopass_loop(target_filesize) + twopass_loop(twopass=twopass, target_filesize=target_filesize) for file in glob("ffmpeg2pass*"): os.remove(file) @@ -88,13 +88,13 @@ def form_twopass(): "web.html", file_url=url_for("static", filename=path.name), twopass=twopass, - alert=success_message, ) - threading.Thread(target=open_browser, name="Open Browser").start() + threading.Thread(target=open_browser, args=[port], name="Open Browser").start() app.run("0.0.0.0", port=port) else: - twopass_loop(twopass.target_filesize) + twopass_loop(twopass=twopass, target_filesize=twopass.target_filesize) + print(twopass.message) if __name__ == "__main__": diff --git a/ffmpeg4discord/arguments.py b/ffmpeg4discord/arguments.py index 01f7e78..f1c4b29 100644 --- a/ffmpeg4discord/arguments.py +++ b/ffmpeg4discord/arguments.py @@ -1,4 +1,12 @@ from argparse import ArgumentParser, Namespace, BooleanOptionalAction +import socket +import logging +from random import randint + + +def is_port_in_use(port: int) -> bool: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + return s.connect_ex(("localhost", port)) == 0 def get_args() -> Namespace: @@ -32,6 +40,24 @@ def get_args() -> Namespace: # web parser.add_argument("--web", action=BooleanOptionalAction, help="Launch ffmpeg4discord's Web UI in your browser.") - parser.add_argument("-p", "--port", type=int, default=5333, help="Local port for the Flask application.") + parser.add_argument("-p", "--port", type=int, help="Local port for the Flask application.") + + args = vars(parser.parse_args()) + + # do some work regarding the port + if args["web"]: + port = args.pop("port") + port = port if port else randint(5000, 6000) + + while True: + if not is_port_in_use(port): + break + logging.warning(f"Port {port} is already in use. Retrying with a new port.") + port = randint(5000, 6000) + + args["port"] = port + + else: + del args["port"] - return vars(parser.parse_args()) + return args diff --git a/ffmpeg4discord/templates/web.html b/ffmpeg4discord/templates/web.html index fa00f73..1cd4b82 100644 --- a/ffmpeg4discord/templates/web.html +++ b/ffmpeg4discord/templates/web.html @@ -11,8 +11,8 @@
{{ alert }}
- Remember to terminate this server before starting another job. +{{ twopass.message }}
+ The server is still running. Do not forget to terminate it.