Spaces:
Sleeping
Sleeping
import os | |
import subprocess | |
import uuid | |
import glob | |
import gradio as gr | |
# Set default acceleration and extra encoding options. | |
accel = 'auto' | |
extra = '-crf 63 -c:v libx264' # default extra settings | |
# Fixed upload and conversion folders. | |
UPLOAD_FOLDER = 'uploads' | |
CONVERTED_FOLDER = 'converted' | |
os.makedirs(UPLOAD_FOLDER, exist_ok=True) | |
os.makedirs(CONVERTED_FOLDER, exist_ok=True) | |
# Helper function to configure audio options. | |
def configure_audio(cmd_list, use_mp3): | |
if use_mp3: | |
cmd_list.extend(['-c:a', 'libmp3lame', '-b:a', '8k', '-ar', '24k', '-ac', '1']) | |
else: | |
cmd_list.extend(['-c:a', 'aac', '-b:a', '1k', '-ar', '8k', '-ac', '1']) | |
def convert_video(use_youtube, youtube_url, video_file, downscale, faster, use_mp3, audio_only): | |
""" | |
Converts a video either from a YouTube URL or an uploaded file. | |
Returns a tuple (preview_file, download_file) with the output path. | |
""" | |
# Determine output filename based on whether only audio is desired. | |
if audio_only: | |
output_filename = f"{uuid.uuid4()}.mp3" if use_mp3 else f"{uuid.uuid4()}.aac" | |
else: | |
output_filename = f"{uuid.uuid4()}.mp4" | |
output_path = os.path.join(CONVERTED_FOLDER, output_filename) | |
files_to_delete = [] # For temporary file cleanup. | |
if use_youtube: | |
if not youtube_url: | |
return "Error: YouTube URL is required.", None | |
# Determine quality based on whether downscale is ticked. | |
if downscale: | |
quality = 'worstaudio' if audio_only else 'worstvideo+worstaudio' | |
else: | |
quality = 'b' # Use "-f b" for best quality if downscale is not ticked. | |
yt_uuid = str(uuid.uuid4()) | |
yt_input_filename = yt_uuid + ".%(ext)s" | |
yt_input_path = os.path.join(UPLOAD_FOLDER, yt_input_filename) | |
yt_dlp_cmd = ['yt-dlp', '-o', yt_input_path, '-f', quality, youtube_url] | |
try: | |
subprocess.run(yt_dlp_cmd, check=True) | |
except subprocess.CalledProcessError as e: | |
return f"An error occurred during YouTube download: {e}", None | |
# Locate the downloaded file (yt-dlp replaces %(ext)s with the actual extension). | |
pattern = os.path.join(UPLOAD_FOLDER, yt_uuid + ".*") | |
downloaded_files = glob.glob(pattern) | |
if not downloaded_files: | |
return "Failed to download YouTube video.", None | |
yt_input_file = downloaded_files[0] | |
files_to_delete.append(yt_input_file) | |
# Build FFmpeg command using the downloaded file. | |
ffmpeg_cmd = ['ffmpeg', '-hwaccel', accel, '-y', '-i', yt_input_file] + extra.split() | |
else: | |
# File upload branch. | |
if not video_file: | |
return "Error: No video file provided.", None | |
# Gradio passes the file path as a string. | |
ext = os.path.splitext(video_file)[1] | |
input_filename = f"{uuid.uuid4()}{ext}" | |
input_path = os.path.join(UPLOAD_FOLDER, input_filename) | |
# Move the uploaded file to our upload folder. | |
os.rename(video_file, input_path) | |
files_to_delete.append(input_path) | |
ffmpeg_cmd = ['ffmpeg', '-hwaccel', accel, '-y', '-i', input_path] + extra.split() | |
# Apply downscale if requested. | |
if downscale: | |
ffmpeg_cmd.extend(['-vf', 'scale=144:-2']) | |
# Apply faster conversion if selected. | |
if faster: | |
ffmpeg_cmd.extend(['-preset', 'ultrafast']) | |
# Configure audio encoding. | |
if audio_only: | |
ffmpeg_cmd.extend(['-vn']) | |
configure_audio(ffmpeg_cmd, use_mp3) | |
else: | |
configure_audio(ffmpeg_cmd, use_mp3) | |
# Append output file path. | |
ffmpeg_cmd.append(output_path) | |
# Run FFmpeg. | |
try: | |
subprocess.run(ffmpeg_cmd, check=True) | |
except subprocess.CalledProcessError as e: | |
return f"An error occurred during conversion: {e}", None | |
# (Optional: cleanup temporary files here if desired.) | |
# Return output file path for preview and download. | |
return output_path, output_path | |
# Create the Gradio interface. | |
with gr.Blocks() as demo: | |
gr.Markdown("## Low Quality Video Inator") | |
gr.Markdown("Upload a video or use a YouTube URL and adjust the options below.") | |
with gr.Row(): | |
use_youtube = gr.Checkbox(label="Use YouTube URL", value=False) | |
youtube_url = gr.Textbox(label="YouTube URL", placeholder="Enter YouTube URL here") | |
video_file = gr.File(label="Upload Video") | |
with gr.Row(): | |
downscale = gr.Checkbox(label="Downscale Video (144p)", value=False) | |
faster = gr.Checkbox(label="Faster Conversion (more pixelated)", value=False) | |
with gr.Row(): | |
use_mp3 = gr.Checkbox(label="Use MP3 (video audio compression)", value=False) | |
audio_only = gr.Checkbox(label="Only Audio (no video)", value=False) | |
convert_button = gr.Button("Convert Video") | |
gr.Markdown("### Preview Converted Video") | |
video_preview = gr.Video(label="Converted Video") | |
gr.Markdown("### Download Converted Video") | |
file_download = gr.File(label="Download Video") | |
convert_button.click( | |
convert_video, | |
inputs=[use_youtube, youtube_url, video_file, downscale, faster, use_mp3, audio_only], | |
outputs=[video_preview, file_download] | |
) | |
demo.launch() |