Jeffgold's picture
Update app.py
f34662a
raw
history blame
4.76 kB
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
import http.server
import socketserver
import threading
logging.basicConfig(level=logging.INFO)
PORT = 8000
temp_dir = Path(tempfile.mkdtemp()) # Create a temporary directory using mkdtemp() instead of TemporaryDirectory()
class Handler(http.server.SimpleHTTPRequestHandler):
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=str(temp_dir), **kwargs)
def start_server():
with socketserver.TCPServer(("", PORT), Handler) as httpd:
print(f"Serving at port {PORT}")
httpd.serve_forever()
t = threading.Thread(target=start_server)
t.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, 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, res):
"""Returns the path to the output file, creating it if necessary."""
output_path = temp_dir / (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, temp_dir):
"""Creates a master playlist .m3u8 file that includes all other .m3u8 files."""
master_playlist_path = temp_dir / "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
def convert_video(video_file, quality, aspect_ratio, video_url):
# Use the already-created temp_dir instead of creating a new one
# temp_dir = Path(tempfile.mkdtemp())
input_path = get_input_path(video_file, video_url, temp_dir)
aspect_ratio = get_aspect_ratio(input_path, aspect_ratio)
video = VideoFileClip(str(input_path))
original_height = video.size[1]
output_paths = [] # Define output_paths as an empty list
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, temp_dir, 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(temp_dir / 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) # Append each completed output file to the output_paths list
master_playlist_path = create_master_playlist(output_paths, temp_dir)
output_paths.append(master_playlist_path)
return output_paths # Return the list of completed output files
video_file = gr.File(label="Video File")
quality = gr.Dropdown(
choices=["18", "23", "27", "28", "32"], label="Quality", default="27")
aspect_ratio = gr.Textbox(default="16:9", lines=1, label="Aspect ratio (width:height)")
video_url = gr.Textbox(label="Or enter video URL")
interface = gr.Interface(
fn=convert_video,
inputs=[video_file, quality, aspect_ratio, video_url],
outputs=gr.Textbox(label="Output"),
title="Video Converter",
description="A simple video converter app",
allow_flagging=False,
)
interface.launch()