File size: 5,999 Bytes
d83b57c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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

# For simplicity, we use 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 = []  # List to keep track of temporary files.

    if use_youtube:
        if not youtube_url:
            return "Error: YouTube URL is required.", None

        if downscale:
            # Download the worst-quality version to disk.
            quality = 'worstaudio' if audio_only else 'worstvideo+worstaudio'
            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)
            ffmpeg_cmd = ['ffmpeg', '-hwaccel', accel, '-y', '-i', yt_input_file] + extra.split()
        else:
            # Pipe best-quality output directly from yt-dlp.
            quality = 'bestaudio' if audio_only else 'best'
            yt_dlp_cmd = ['yt-dlp', '-o', '-', '-f', quality, youtube_url]
            ffmpeg_cmd = ['ffmpeg', '-hwaccel', accel, '-y', '-i', '-'] + 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 (for file uploads and YouTube downloads alike).
    if downscale:
        ffmpeg_cmd.extend(['-vf', 'scale=144:-2'])
    # Apply faster conversion if selected.
    if faster:
        ffmpeg_cmd.extend(['-preset', 'ultrafast'])
    
    # Configure audio options.
    if audio_only:
        ffmpeg_cmd.extend(['-vn'])
        configure_audio(ffmpeg_cmd, use_mp3)
    else:
        configure_audio(ffmpeg_cmd, use_mp3)
    
    ffmpeg_cmd.append(output_path)
    
    # Run FFmpeg.
    if use_youtube and not downscale:
        try:
            yt_proc = subprocess.Popen(yt_dlp_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            subprocess.run(ffmpeg_cmd, stdin=yt_proc.stdout, check=True)
            yt_proc.stdout.close()
            yt_proc.wait()
        except subprocess.CalledProcessError as e:
            return f"An error occurred during conversion: {e}", None
    else:
        try:
            subprocess.run(ffmpeg_cmd, check=True)
        except subprocess.CalledProcessError as e:
            return f"An error occurred during conversion: {e}", None

    # (Optional cleanup could be done here for files in files_to_delete.)
    # Return the output file path for both video preview and file download.
    return output_path, output_path

# Create the Gradio interface using Blocks.
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()