Spaces:
Sleeping
Sleeping
import gradio as gr | |
import os | |
from pathlib import Path | |
from datetime import datetime | |
from converter_fw import VideoConverter | |
import tempfile | |
import shutil | |
class VideoConverterGUI: | |
def __init__(self): | |
self.converter = VideoConverter() | |
self.current_progress = 0 | |
self.status_message = "" | |
self.output_dir = os.path.join(os.getcwd(), "converted_videos") | |
os.makedirs(self.output_dir, exist_ok=True) | |
# Define video extensions | |
self.video_extensions = [ | |
".mp4", ".avi", ".mkv", ".mov", ".wmv", ".flv", ".mpeg", | |
".MP4", ".AVI", ".MKV", ".MOV", ".WMV", ".FLV", ".MPEG" | |
] | |
def generate_output_filename(self, input_filename, output_format): | |
name = Path(input_filename).stem | |
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | |
return f"{name}_{timestamp}.{output_format.lower()}" | |
def update_video_display(self, files): | |
"""Update the video preview""" | |
if not files or len(files) == 0: | |
return None | |
return files[0] | |
def create_temp_copy(self, file_path): | |
"""Create a temporary copy of the input file""" | |
file_ext = os.path.splitext(file_path)[1] | |
temp_file = tempfile.NamedTemporaryFile(suffix=file_ext, delete=False) | |
temp_path = temp_file.name | |
temp_file.close() | |
shutil.copy2(file_path, temp_path) | |
return temp_path | |
def is_valid_video(self, file_path): | |
"""Check if file has a valid video extension""" | |
return any(file_path.lower().endswith(ext.lower()) for ext in self.video_extensions) | |
def convert_videos(self, files, output_format, codec, resolution, bitrate, bitrate_unit, fps, progress=gr.Progress()): | |
if not files: | |
return "Please upload video files.", [] | |
results = [] | |
output_files = [] | |
temp_files = [] | |
# Filter valid video files | |
valid_files = [f for f in files if self.is_valid_video(f.name)] | |
if not valid_files: | |
return "No valid video files found. Please upload video files.", [] | |
total_files = len(valid_files) | |
file_weight = 1.0 / total_files | |
# Process bitrate input | |
if bitrate.strip().lower() != "auto" and bitrate.strip() != "": | |
try: | |
bitrate_value = float(bitrate) | |
if bitrate_unit == "kbps": | |
bitrate_value = f"{bitrate_value}k" | |
elif bitrate_unit == "Mbps": | |
bitrate_value = f"{bitrate_value}M" | |
else: | |
return "Invalid bitrate unit selected.", [] | |
except ValueError: | |
return f"Invalid bitrate value: {bitrate}. Please enter a numeric value.", [] | |
else: | |
bitrate_value = "auto" | |
try: | |
for i, file in enumerate(valid_files): | |
try: | |
base_progress = i * file_weight | |
# Create a temporary copy of the input file | |
temp_input_path = self.create_temp_copy(file.name) | |
temp_files.append(temp_input_path) | |
original_filename = os.path.basename(file.name) | |
progress(base_progress, desc=f"Converting {original_filename}") | |
def progress_callback(file_progress): | |
total_progress = base_progress + (file_progress * file_weight) | |
progress(total_progress) | |
output_filename = self.generate_output_filename(original_filename, output_format) | |
print(f"Converting {temp_input_path} to {output_filename}") # Debug print | |
success, message = self.converter.convert_video( | |
temp_input_path, | |
output_format, | |
codec, | |
self.output_dir, | |
progress_callback, | |
output_filename, | |
resolution, | |
bitrate_value, | |
fps | |
) | |
if success: | |
output_path = os.path.join(self.output_dir, output_filename) | |
if os.path.exists(output_path): | |
output_files.append(output_path) | |
results.append(message) | |
except Exception as e: | |
print(f"Detailed error for {file.name}: {str(e)}") # Debug print | |
results.append(f"Error processing {os.path.basename(file.name)}: {str(e)}") | |
finally: | |
# Clean up temporary files | |
for temp_file in temp_files: | |
try: | |
if os.path.exists(temp_file): | |
os.remove(temp_file) | |
except Exception as e: | |
print(f"Error cleaning up {temp_file}: {str(e)}") | |
success_count = sum(1 for msg in results if "Successfully" in msg) | |
report = f"Conversion completed: {success_count}/{total_files} files converted successfully\n\n" | |
report += "\n".join(results) | |
return report, output_files if output_files else None | |
def create_ui(self): | |
with gr.Blocks() as app: | |
gr.Markdown(f""" | |
# Batch Video Converter | |
GPU Acceleration: {"Available" if self.converter.gpu_available else "Not Available"} | |
""") | |
with gr.Column(): | |
# Input Settings Section | |
gr.Markdown("### Input Settings") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
input_videos = gr.Files( | |
label="Upload Videos", | |
file_count="multiple", | |
file_types=["video"], | |
type="filepath" | |
) | |
with gr.Row(): | |
preview = gr.Video( | |
label="Video Preview", | |
format="mp4", | |
visible=True, | |
interactive=False | |
) | |
# Conversion Settings Section | |
gr.Markdown("### Conversion Settings") | |
with gr.Row(): | |
format_dropdown = gr.Dropdown( | |
choices=self.converter.formats, | |
value="MP4", | |
label="Output Format" | |
) | |
codec_dropdown = gr.Dropdown( | |
choices=self.converter.codecs, | |
value="H.264", | |
label="Codec" | |
) | |
# Add output resolution, bitrate, and fps options | |
with gr.Row(): | |
resolution_dropdown = gr.Dropdown( | |
choices=[ | |
"Same as input", | |
"3840x2160 (4K)", | |
"2560x1440 (1440p)", | |
"1920x1080 (1080p)", | |
"1280x720 (720p)", | |
"854x480 (480p)" | |
], | |
value="Same as input", | |
label="Output Resolution" | |
) | |
with gr.Row(): | |
bitrate_input = gr.Textbox( | |
label="Output Bitrate", | |
placeholder="Enter value or leave blank for auto", | |
value="" | |
) | |
bitrate_unit = gr.Dropdown( | |
choices=["kbps", "Mbps"], | |
value="Mbps", | |
label="Bitrate Unit" | |
) | |
with gr.Row(): | |
fps_dropdown = gr.Dropdown( | |
choices=[ | |
"Same as input", | |
"23.97", | |
"24", | |
"25", | |
"29.97", | |
"30", | |
"60" | |
], | |
value="Same as input", | |
label="Output FPS" | |
) | |
# Conversion Button and Progress Section | |
convert_btn = gr.Button( | |
"Convert Videos", | |
variant="primary", | |
size="lg" | |
) | |
gr.Markdown("### Conversion Progress") | |
output_text = gr.Textbox( | |
label="Status", | |
lines=10, | |
show_copy_button=True | |
) | |
# Download Section | |
gr.Markdown("### Download Converted Videos") | |
output_files = gr.Files( | |
label="Converted Videos (Click to download)", | |
interactive=False | |
) | |
# Event handlers | |
input_videos.change( | |
fn=self.update_video_display, | |
inputs=[input_videos], | |
outputs=[preview] | |
) | |
convert_btn.click( | |
fn=self.convert_videos, | |
inputs=[ | |
input_videos, | |
format_dropdown, | |
codec_dropdown, | |
resolution_dropdown, | |
bitrate_input, | |
bitrate_unit, | |
fps_dropdown | |
], | |
outputs=[ | |
output_text, | |
output_files | |
] | |
) | |
return app | |
def main(self): | |
gui = VideoConverterGUI() | |
app = gui.create_ui() | |
app.launch() | |
if __name__ == "__main__": | |
VideoConverterGUI().main() | |