import logging import shutil import tempfile import subprocess from pathlib import Path from moviepy.editor import VideoFileClip import gradio as gr import requests from urllib.parse import urlparse from web3.storage import Web3Storage 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, temp_dir): """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 = temp_dir / file_name download_file(video_url, destination) return destination else: raise ValueError("No input was provided.") def get_output_path(input_path, temp_dir): """Returns the path to the output file, creating it if necessary.""" output_path = temp_dir / (Path(input_path).stem + ".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 upload_to_web3_storage(api_key, path): """Uploads a file to web3.storage.""" with open(path, 'rb') as f: storage = Web3Storage.new(token=api_key) cid = storage.put_file(f) return f"https://dweb.link/ipfs/{cid}" def convert_video(video_file, quality, aspect_ratio, video_url, api_key, web3_upload): """Converts a video to HLS format, adjusting the quality and aspect ratio as necessary.""" with tempfile.TemporaryDirectory() as temp_dir: temp_dir = Path(temp_dir) input_path = get_input_path(video_file, video_url, temp_dir) output_path = get_output_path(input_path, temp_dir) aspect_ratio = get_aspect_ratio(input_path, aspect_ratio) ffmpeg_command = [ "ffmpeg", "-i", str(input_path), "-c:v", "libx264", "-crf", str(quality), "-vf", f"scale=-1:720,setsar={aspect_ratio}", "-hls_time", "6", "-hls_playlist_type", "vod", "-f", "hls", str(output_path) ] try: logging.info("Running command: %s", " ".join(ffmpeg_command)) subprocess.run(ffmpeg_command, check=True, timeout=600) except subprocess.CalledProcessError: logging.exception("ffmpeg command failed.") return "ffmpeg command failed." except subprocess.TimeoutExpired: logging.exception("ffmpeg command timed out.") return "ffmpeg command timed out." except FileNotFoundError: logging.exception("ffmpeg is not installed.") return "ffmpeg is not installed." except Exception as e: logging.exception("An error occurred.") return f"An error occurred: {str(e)}" # Copy the output to a new temporary file that won't be deleted when the # TemporaryDirectory context manager exits. output_copy_path = shutil.copy2(output_path, tempfile.gettempdir()) # If the user wants to upload to web3, do that and return the URL. # Otherwise, just return the local path. if web3_upload: return upload_to_web3_storage(api_key, output_copy_path) else: return output_copy_path def main(): video_file = gr.inputs.File(label="Video File", type="file") quality = gr.inputs.Dropdown( choices=["18", "23", "28", "32"], label="Quality", default="23") aspect_ratio = gr.inputs.Dropdown( choices=[None, "1:1", "4:3", "3:2", "5:4", "16:9", "21:9", "1.85:1", "2.35:1", "3:1", "360", "9:16", "16:9", "2:1", "1:2", "9:1"], label="Aspect Ratio", default=None) video_url = gr.inputs.Textbox(label="Video URL") api_key = gr.inputs.Textbox(label="web3.storage API Key") web3_upload = gr.inputs.Checkbox(label="Upload to web3.storage") gr.Interface(convert_video, inputs=[video_file, quality, aspect_ratio, video_url, api_key, web3_upload], outputs='text').launch() if __name__ == "__main__": main()