import logging import shutil from pathlib import Path from moviepy.editor import VideoFileClip import gradio as gr import requests from urllib.parse import urlparse import subprocess import atexit from flask import Flask, send_from_directory from threading import Thread # Initialize a Flask application app = Flask(__name__) @app.route('/files/') def serve_file(path): return send_from_directory(Path.cwd(), path) # Start the Flask server in a new thread Thread(target=app.run, kwargs={'host': '0.0.0.0', 'port': 5000}).start() logging.basicConfig(level=logging.INFO) def download_file(url, destination): """Downloads a file from a url to a destination.""" response = requests.get(url) response.raise_for_status() with open(destination, 'wb') as f: f.write(response.content) def get_input_path(video_file, video_url): """Returns the path to the video file, downloading it if necessary.""" if video_file is not None: return Path(video_file.name) elif video_url: url_path = urlparse(video_url).path file_name = Path(url_path).name destination = Path.cwd() / file_name download_file(video_url, destination) return destination else: raise ValueError("No input was provided.") def get_output_path(input_path, res): """Returns the path to the output file, creating it if necessary.""" output_path = Path.cwd() / (Path(input_path).stem + f"_{res}.m3u8") return output_path def get_aspect_ratio(input_path, aspect_ratio): """Returns the aspect ratio of the video, calculating it if necessary.""" if aspect_ratio is not None: return aspect_ratio video = VideoFileClip(str(input_path)) return f"{video.size[0]}:{video.size[1]}" def create_master_playlist(output_paths): """Creates a master playlist .m3u8 file that includes all other .m3u8 files.""" master_playlist_path = Path.cwd() / "master_playlist.m3u8" with open(master_playlist_path, 'w') as f: f.write("#EXTM3U\n") for path in output_paths: f.write(f"#EXT-X-STREAM-INF:BANDWIDTH={1000*1000},RESOLUTION={path.stem.split('_')[-1]}\n") f.write(f"{path.name}\n") return master_playlist_path # make sure this is a single Path object def convert_video(video_file, quality, aspect_ratio, video_url): input_path = get_input_path(video_file, video_url) aspect_ratio = get_aspect_ratio(input_path, aspect_ratio) video = VideoFileClip(str(input_path)) original_height = video.size[1] output_paths = [] for res in standard_resolutions: # Skip if resolution is higher than original if res > original_height: continue scale = "-1:" + str(res) # we scale the height to res and keep aspect ratio output_path = get_output_path(input_path, str(res) + 'p') # pass the resolution to create a unique output file ffmpeg_command = [ "ffmpeg", "-i", str(input_path), "-c:v", "libx264", "-crf", str(quality), "-vf", f"scale={scale}:force_original_aspect_ratio=decrease,pad=ceil(iw/2)*2:ceil(ih/2)*2", "-hls_time", "10", "-hls_playlist_type", "vod", "-hls_segment_filename", str(Path.cwd() / f"{output_path.stem}_%03d.ts"), str(output_path) ] logging.info("Running ffmpeg command: " + ' '.join(ffmpeg_command)) subprocess.run(ffmpeg_command, check=True) output_paths.append(output_path) master_playlist_path = create_master_playlist(output_paths) output_paths.append(master_playlist_path) html_components = [] for path in output_paths: # Create a video player and a download link for each video file if path.suffix in ['.mp4', '.webm', '.ogg']: video_path = f"http://localhost:5000/files/{path.name}" video_component = f"" download_link = f"

Download this video

" html_components.append(f"{video_component}{download_link}") return html_components, # add more return values as needed outputs = [ gr.outputs.HTML(label="Video Players"), # add more outputs as needed ] video_file = gr.inputs.File(label="Video File") quality = gr.inputs.Dropdown( choices=["18", "23", "27", "28", "32"], default="27", label="Quality" ) aspect_ratio = gr.inputs.Dropdown( choices=["16:9", "1:1", "4:3", "3:2", "5:4", "21:9", "1.85:1", "2.35:1", "3:1", "360", "9:16", "2:1", "1:2", "9:1"], default="16:9", label="Aspect ratio (width:height)" ) standard_resolutions = [4320, 2160, 1440, 1080, 720, 480, 360, 240, 144] # 8K, 4K, 2K, Full HD, HD, SD in pixels video_url = gr.inputs.Textbox(label="Or enter video URL") outputs = [ gr.outputs.HTML(label="Download Links"), gr.outputs.Video(label="Video Player"), gr.outputs.Textbox(label="Text Files", type="text") ] interface = gr.Interface( fn=convert_video, inputs=[video_file, quality, aspect_ratio, video_url], outputs=outputs, title="Video Converter", description="A simple video converter app", allow_flagging=False, server_name="0.0.0.0", server_port=7860, ) interface.launch()