gagndeep's picture
Update app.py from anycoder
09133a9 verified
import gradio as gr
import subprocess
import os
from pathlib import Path
import tempfile
import json
# Comprehensive format support
VIDEO_FORMATS = [
"mp4", "avi", "mkv", "mov", "wmv", "flv", "webm", "m4v", "mpg", "mpeg",
"3gp", "ogv", "ts", "vob", "divx", "f4v", "asf", "rm", "rmvb"
]
AUDIO_FORMATS = [
"mp3", "wav", "aac", "flac", "ogg", "m4a", "wma", "opus", "aiff",
"alac", "ape", "ac3", "dts", "amr", "mka", "tta", "wv"
]
IMAGE_FORMATS = [
"jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "webp", "svg",
"ico", "heic", "heif", "raw", "cr2", "nef", "psd", "eps"
]
DOCUMENT_FORMATS = [
"pdf", "txt", "doc", "docx", "rtf", "odt", "html", "md"
]
ALL_FORMATS = sorted(set(VIDEO_FORMATS + AUDIO_FORMATS + IMAGE_FORMATS + DOCUMENT_FORMATS))
def get_file_info(file_path):
"""Get detailed information about the uploaded file."""
if not file_path:
return "πŸ“‹ *Upload a file to see details*"
try:
file_size = os.path.getsize(file_path)
file_ext = Path(file_path).suffix.lower().replace(".", "")
size_mb = file_size / (1024 * 1024)
info = f"""
πŸ“ **File Information**
- **Name:** {Path(file_path).name}
- **Format:** {file_ext.upper()}
- **Size:** {size_mb:.2f} MB
"""
# Try to get media info using ffprobe
try:
result = subprocess.run(
["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", file_path],
capture_output=True,
text=True,
timeout=10
)
if result.returncode == 0:
data = json.loads(result.stdout)
if "format" in data:
duration = data["format"].get("duration", "N/A")
if duration != "N/A":
info += f"\n- **Duration:** {float(duration):.2f} seconds"
if "streams" in data:
for stream in data["streams"]:
if stream["codec_type"] == "video":
info += f"\n- **Video Codec:** {stream.get('codec_name', 'N/A')}"
info += f"\n- **Resolution:** {stream.get('width', 'N/A')}x{stream.get('height', 'N/A')}"
break
for stream in data["streams"]:
if stream["codec_type"] == "audio":
info += f"\n- **Audio Codec:** {stream.get('codec_name', 'N/A')}"
info += f"\n- **Sample Rate:** {stream.get('sample_rate', 'N/A')} Hz"
break
except Exception as e:
info += f"\n\n*Could not retrieve detailed media info*"
return info
except Exception as e:
return f"❌ Error reading file: {str(e)}"
def convert_media(input_file, output_format, quality="high", resolution=None):
"""
Convert media file to specified format.
Args:
input_file: Path to input file
output_format: Desired output format
quality: Quality setting (high, medium, low)
resolution: Optional resolution for video (e.g., "1920x1080")
"""
if not input_file:
raise gr.Error("❌ Please upload a file first!")
if not output_format:
raise gr.Error("❌ Please select an output format!")
# Create temporary output file
output_file = tempfile.NamedTemporaryFile(
delete=False,
suffix=f".{output_format}"
).name
try:
# Build ffmpeg command based on format and quality
cmd = ["ffmpeg", "-i", input_file, "-y"]
# Quality settings
if quality == "high":
if output_format in VIDEO_FORMATS:
cmd.extend(["-crf", "18", "-preset", "slow"])
elif output_format in AUDIO_FORMATS:
cmd.extend(["-b:a", "320k"])
elif quality == "medium":
if output_format in VIDEO_FORMATS:
cmd.extend(["-crf", "23", "-preset", "medium"])
elif output_format in AUDIO_FORMATS:
cmd.extend(["-b:a", "192k"])
else: # low
if output_format in VIDEO_FORMATS:
cmd.extend(["-crf", "28", "-preset", "fast"])
elif output_format in AUDIO_FORMATS:
cmd.extend(["-b:a", "128k"])
# Resolution settings for video
if resolution and output_format in VIDEO_FORMATS:
cmd.extend(["-s", resolution])
# Format-specific settings
if output_format == "mp3":
cmd.extend(["-codec:a", "libmp3lame"])
elif output_format == "aac":
cmd.extend(["-codec:a", "aac"])
elif output_format == "flac":
cmd.extend(["-codec:a", "flac"])
elif output_format == "opus":
cmd.extend(["-codec:a", "libopus"])
elif output_format == "webm":
cmd.extend(["-codec:v", "libvpx-vp9", "-codec:a", "libopus"])
elif output_format == "mp4":
cmd.extend(["-codec:v", "libx264", "-codec:a", "aac"])
elif output_format == "wav":
cmd.extend(["-codec:a", "pcm_s16le"])
elif output_format in IMAGE_FORMATS:
# For image conversion, just specify format
pass
cmd.append(output_file)
# Execute conversion
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300 # 5 minute timeout
)
if result.returncode != 0:
raise Exception(f"Conversion failed: {result.stderr}")
# Verify output file exists and has content
if not os.path.exists(output_file) or os.path.getsize(output_file) == 0:
raise Exception("Conversion produced empty file")
output_size = os.path.getsize(output_file) / (1024 * 1024)
return output_file, f"βœ… **Conversion Successful!**\n\nConverted to **{output_format.upper()}** format with **{quality}** quality.\n\nπŸ“¦ Output size: **{output_size:.2f} MB**"
except subprocess.TimeoutExpired:
if os.path.exists(output_file):
os.unlink(output_file)
raise gr.Error("⏱️ Conversion timed out. File may be too large or complex.")
except Exception as e:
if os.path.exists(output_file):
os.unlink(output_file)
raise gr.Error(f"❌ Conversion failed: {str(e)}")
def update_format_suggestions(input_file):
"""Update suggested formats based on input file type."""
if not input_file:
return gr.Dropdown(choices=ALL_FORMATS, value="mp4")
file_ext = Path(input_file).suffix.lower().replace(".", "")
# Suggest related formats
if file_ext in VIDEO_FORMATS:
suggested = ["mp4", "webm", "avi", "mkv", "mov", "gif"]
elif file_ext in AUDIO_FORMATS:
suggested = ["mp3", "wav", "aac", "flac", "ogg", "m4a"]
elif file_ext in IMAGE_FORMATS:
suggested = ["jpg", "png", "webp", "gif", "bmp", "tiff"]
else:
suggested = ["mp4", "mp3", "jpg", "png"]
# Add all formats but prioritize suggested ones
all_choices = suggested + [f for f in ALL_FORMATS if f not in suggested]
return gr.Dropdown(choices=all_choices, value=suggested[0])
# Custom CSS for better UI/UX
custom_css = """
.main-container {
max-width: 1400px;
margin: 0 auto;
}
.header-section {
text-align: center;
padding: 2rem 1rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 12px;
margin-bottom: 2rem;
color: white;
}
.header-section h1 {
font-size: 2.5rem;
margin-bottom: 0.5rem;
font-weight: 700;
}
.header-section p {
font-size: 1.1rem;
opacity: 0.95;
}
.conversion-panel {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1rem;
}
.info-box {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 8px;
padding: 1rem;
margin: 1rem 0;
}
.status-success {
color: #10b981;
font-weight: 600;
}
.status-error {
color: #ef4444;
font-weight: 600;
}
footer {
text-align: center;
padding: 2rem;
margin-top: 2rem;
opacity: 0.8;
}
.format-badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: #667eea;
color: white;
border-radius: 20px;
font-size: 0.875rem;
margin: 0.25rem;
}
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin: 1rem 0;
}
.feature-item {
background: rgba(102, 126, 234, 0.1);
padding: 1rem;
border-radius: 8px;
text-align: center;
}
"""
# Build the Gradio interface
with gr.Blocks(fill_height=True) as demo:
gr.HTML("""
<div class="header-section">
<h1>🎬 Universal Media Converter</h1>
<p>Convert any media file to any format β€’ Support for 60+ formats β€’ Professional quality</p>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="color: white; text-decoration: none; opacity: 0.9; font-size: 0.9rem;">
✨ Built with anycoder
</a>
</div>
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸ“€ Input Settings")
input_file = gr.File(
label="Upload Media File",
file_types=["video", "audio", "image"],
type="filepath"
)
file_info = gr.Markdown(
value="πŸ“‹ *Upload a file to see details*",
elem_classes="info-box"
)
gr.Markdown("### βš™οΈ Conversion Settings")
output_format = gr.Dropdown(
choices=ALL_FORMATS,
value="mp4",
label="Output Format",
info="Select the desired output format"
)
quality = gr.Radio(
choices=["high", "medium", "low"],
value="high",
label="Quality",
info="Higher quality = larger file size"
)
with gr.Accordion("🎨 Advanced Options", open=False):
resolution = gr.Dropdown(
choices=[
"Original",
"3840x2160 (4K)",
"1920x1080 (Full HD)",
"1280x720 (HD)",
"854x480 (SD)",
"640x360"
],
value="Original",
label="Video Resolution (for video files)",
info="Resize video to specific resolution"
)
convert_btn = gr.Button(
"πŸš€ Convert Media",
variant="primary",
size="lg"
)
clear_btn = gr.ClearButton(
components=[input_file, output_format, quality, file_info],
value="πŸ—‘οΈ Clear All"
)
with gr.Column(scale=1):
gr.Markdown("### πŸ“₯ Output")
status_message = gr.Markdown(
value="*Ready to convert your media*",
elem_classes="info-box"
)
output_file = gr.File(
label="Converted File",
type="filepath"
)
gr.Markdown("""
### πŸ“‹ Supported Formats
**Video:** MP4, AVI, MKV, MOV, WebM, FLV, WMV, and more
**Audio:** MP3, WAV, AAC, FLAC, OGG, M4A, and more
**Image:** JPG, PNG, GIF, WebP, BMP, TIFF, and more
### ✨ Features
- 🎯 60+ format support
- 🎨 Quality control (high/medium/low)
- πŸ“ Resolution options for video
- ⚑ Fast conversion with FFmpeg
- πŸ’Ύ Detailed file info analysis
- πŸ”„ Smart format suggestions
- πŸ“Š Output size reporting
### πŸŽ“ How to Use
1. **Upload** your media file
2. **Select** output format (auto-suggested)
3. **Choose** quality level
4. **Click** Convert Media button
5. **Download** your converted file
""")
# Event handlers
input_file.change(
fn=get_file_info,
inputs=[input_file],
outputs=[file_info]
)
input_file.change(
fn=update_format_suggestions,
inputs=[input_file],
outputs=[output_format]
)
def process_conversion(input_file, output_format, quality, resolution):
res = None if resolution == "Original" else resolution.split(" ")[0]
return convert_media(input_file, output_format, quality, res)
convert_btn.click(
fn=process_conversion,
inputs=[input_file, output_format, quality, resolution],
outputs=[output_file, status_message]
)
if __name__ == "__main__":
demo.launch(
theme=gr.themes.Soft(
primary_hue="indigo",
secondary_hue="purple",
neutral_hue="slate",
font=gr.themes.GoogleFont("Inter"),
text_size="lg",
spacing_size="lg",
radius_size="lg"
).set(
button_primary_background_fill="*primary_600",
button_primary_background_fill_hover="*primary_700",
block_title_text_weight="600",
block_label_text_weight="600",
),
css=custom_css,
footer_links=[
{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}
]
)