RandomPersonRR commited on
Commit
6eeced8
·
verified ·
1 Parent(s): 267d0b1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +92 -123
app.py CHANGED
@@ -9,7 +9,7 @@ import gradio as gr
9
  os.system("chmod +x fdkaac") # Ensure fdkaac is executable
10
 
11
  accel = 'auto'
12
- video_base_opts = ['-crf', '63', '-c:v', 'libx264', '-tune', 'zerolatency', '-movflags', '+faststart']
13
 
14
  UPLOAD_FOLDER = 'uploads'
15
  CONVERTED_FOLDER = 'converted'
@@ -20,7 +20,6 @@ async def run_subprocess(cmd, use_fdkaac=False):
20
  env = os.environ.copy()
21
  if use_fdkaac:
22
  env["LD_LIBRARY_PATH"] = os.path.abspath("./") + ":" + env.get("LD_LIBRARY_PATH", "")
23
- print(f"[DEBUG] Running command:\n{' '.join(cmd)}\n")
24
  process = await asyncio.create_subprocess_exec(
25
  *cmd,
26
  stdout=asyncio.subprocess.PIPE,
@@ -29,170 +28,140 @@ async def run_subprocess(cmd, use_fdkaac=False):
29
  )
30
  stdout, stderr = await process.communicate()
31
  if process.returncode != 0:
32
- print(f"[ERROR] Command failed:\n{stderr.decode()}\n")
33
  raise subprocess.CalledProcessError(process.returncode, cmd, stderr.decode())
34
- print(f"[DEBUG] Command succeeded:\n{stdout.decode()}\n")
35
  return stdout.decode(), stderr.decode()
36
 
37
  async def convert_video_task(input_path, downscale, faster, use_mp3, audio_only, custom_bitrate, video_bitrate, progress):
38
  if use_mp3:
 
39
  output_audio = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp3")
40
- await progress(0.1, desc="Converting audio to MP3...")
41
- ffmpeg_audio_cmd = [
42
  'ffmpeg', '-y', '-i', input_path, '-vn',
43
  '-c:a', 'libmp3lame', '-b:a', '8k', '-ar', '24000', '-ac', '1',
44
  output_audio
45
  ]
 
46
  if audio_only:
47
- await run_subprocess(ffmpeg_audio_cmd)
48
  return output_audio, None
 
 
 
 
 
 
49
  else:
50
- output_video = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
51
- await progress(0.3, desc="Making the video quality lower...")
52
- ffmpeg_video_cmd = [
53
- 'ffmpeg', '-y', '-hwaccel', accel, '-i', input_path
54
- ]
55
- if custom_bitrate:
56
- ffmpeg_video_cmd += ['-b:v', f"{int(video_bitrate)}k"]
57
- else:
58
- ffmpeg_video_cmd += video_base_opts
59
- if faster:
60
- ffmpeg_video_cmd.extend(['-preset', 'ultrafast'])
61
-
62
- ffmpeg_video_cmd += [
63
- '-c:a', 'libmp3lame', '-b:a', '8k', '-ar', '24000', '-ac', '1',
64
- output_video
65
- ]
66
- await run_subprocess(ffmpeg_video_cmd)
67
- return None, output_video
68
-
69
- # AAC (fdkaac) path
70
- await progress(0.1, desc="Splitting Audio and Video...")
71
  audio_wav = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.wav")
72
- audio_output = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.m4a")
73
- video_output = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
74
-
75
- await run_subprocess([
76
- 'ffmpeg', '-y', '-i', input_path, '-ac', '1', '-ar', '8000', audio_wav
77
- ])
78
 
79
- await progress(0.3, desc="Converting audio to AAC which is lower quality...")
80
- await run_subprocess([
81
- './fdkaac', '-b', '1k', '-C', '-f', '2', '-G', '1', '-w', '8000',
82
- '-o', audio_output, audio_wav
83
- ], use_fdkaac=True)
84
 
85
- await progress(0.6, desc="Making the video quality lower...")
86
- video_cmd = [
87
- 'ffmpeg', '-y', '-hwaccel', accel, '-i', input_path
88
- ]
89
  if downscale:
90
- video_cmd += ['-vf', 'scale=-2:144']
91
  if custom_bitrate:
92
- video_cmd += ['-b:v', f"{int(video_bitrate)}k"]
93
  else:
94
- video_cmd += video_base_opts
95
  if faster:
96
- video_cmd.extend(['-preset', 'ultrafast'])
97
- video_cmd += ['-an', video_output]
98
- await run_subprocess(video_cmd)
99
 
100
  if audio_only:
101
  return audio_output, None
102
 
103
- await progress(0.9, desc="Mixing audio and video together...")
104
- merged_output = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
105
- await run_subprocess([
106
- 'ffmpeg', '-y', '-i', video_output, '-i', audio_output, '-c', 'copy', merged_output
107
- ])
108
 
109
- for f in [audio_wav, audio_output, video_output]:
110
- try:
111
- os.remove(f)
112
- except FileNotFoundError:
113
- pass
114
 
115
- await progress(1.0)
116
- return None, merged_output
117
 
118
- async def process_conversion(use_youtube, youtube_url, video_file, downscale, faster, use_mp3, audio_only, custom_bitrate, video_bitrate, progress=gr.Progress()):
119
- try:
 
 
 
120
  if use_youtube:
121
- if not youtube_url:
122
- return "Error: YouTube URL required.", None
123
- yt_uuid = str(uuid.uuid4())
124
- yt_out = os.path.join(UPLOAD_FOLDER, yt_uuid + ".%(ext)s")
125
- await progress(0, desc="Downloading from YouTube...")
126
- yt_cmd = ['yt-dlp', '-o', yt_out, '-f', 'b', youtube_url]
127
- await run_subprocess(yt_cmd)
128
- pattern = os.path.join(UPLOAD_FOLDER, yt_uuid + ".*")
129
- files = glob.glob(pattern)
130
- if not files:
131
- return "Download failed.", None
132
  input_path = files[0]
133
  else:
134
- if not video_file:
135
- return "No video provided.", None
136
- ext = os.path.splitext(video_file.name)[1]
137
- input_path = os.path.join(UPLOAD_FOLDER, f"{uuid.uuid4()}{ext}")
138
- shutil.copy2(video_file.name, input_path)
139
-
 
 
 
 
 
140
  audio_out, video_out = await convert_video_task(
141
- input_path, downscale, faster, use_mp3, audio_only, custom_bitrate, video_bitrate, progress
 
142
  )
143
 
 
 
 
144
  if audio_only:
145
  return audio_out, audio_out
146
  return video_out, video_out
147
- except Exception as e:
148
- return f"Error: {str(e)}", None
149
 
150
- # Gradio Interface
151
  with gr.Blocks(theme=gr.themes.Default(primary_hue="rose")) as demo:
152
- gr.Markdown("""
153
- # **Low Quality Video Inator**
154
- Upload a video or paste a YouTube URL below, then tweak the settings to your liking.
155
- """)
156
-
157
- with gr.Group():
158
- with gr.Row():
159
- use_youtube = gr.Checkbox(label="🔗 Use YouTube URL (If ran locally, then it works.)", value=False)
160
- youtube_url = gr.Textbox(label="YouTube URL", placeholder="Paste YouTube URL here")
161
- video_file = gr.File(label="📁 Upload Video File")
162
-
163
- gr.Markdown("### ⚙️ **Conversion Settings**")
164
- with gr.Group():
165
- with gr.Row():
166
- downscale = gr.Checkbox(label="Downscale Video to 144p", value=False)
167
- faster = gr.Checkbox(label="Faster Video Compression (will result in pixelated artifacts)", value=False)
168
- with gr.Row():
169
- use_mp3 = gr.Checkbox(label="Use MP3 Audio (however AAC sounds lower quality)", value=False)
170
- audio_only = gr.Checkbox(label="Audio Only", value=False)
171
- with gr.Row():
172
- custom_bitrate = gr.Checkbox(label="Custom Video Bitrate", value=False)
173
- video_bitrate = gr.Number(label="Bitrate (kbps)", visible=False)
174
-
175
- custom_bitrate.change(
176
- lambda checked: gr.update(visible=checked),
177
- inputs=[custom_bitrate],
178
- outputs=[video_bitrate]
179
- )
180
 
181
  convert_button = gr.Button("Convert Now", variant="primary")
182
-
183
- gr.Markdown("### **Conversion Preview**")
184
- video_preview = gr.Video(label="Preview Output")
185
-
186
- gr.Markdown("### **Download Your Masterpiece**")
187
- file_download = gr.File(label="Download Result")
188
 
189
  convert_button.click(
190
  process_conversion,
191
- inputs=[
192
- use_youtube, youtube_url, video_file,
193
- downscale, faster, use_mp3, audio_only,
194
- custom_bitrate, video_bitrate
195
- ],
196
  outputs=[video_preview, file_download]
197
  )
198
 
 
9
  os.system("chmod +x fdkaac") # Ensure fdkaac is executable
10
 
11
  accel = 'auto'
12
+ video_base_opts = ['-crf', '63', '-c:v', 'libx264', '-tune', 'zerolatency']
13
 
14
  UPLOAD_FOLDER = 'uploads'
15
  CONVERTED_FOLDER = 'converted'
 
20
  env = os.environ.copy()
21
  if use_fdkaac:
22
  env["LD_LIBRARY_PATH"] = os.path.abspath("./") + ":" + env.get("LD_LIBRARY_PATH", "")
 
23
  process = await asyncio.create_subprocess_exec(
24
  *cmd,
25
  stdout=asyncio.subprocess.PIPE,
 
28
  )
29
  stdout, stderr = await process.communicate()
30
  if process.returncode != 0:
 
31
  raise subprocess.CalledProcessError(process.returncode, cmd, stderr.decode())
 
32
  return stdout.decode(), stderr.decode()
33
 
34
  async def convert_video_task(input_path, downscale, faster, use_mp3, audio_only, custom_bitrate, video_bitrate, progress):
35
  if use_mp3:
36
+ progress.update(1, desc="Converting audio to MP3...")
37
  output_audio = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp3")
38
+ cmd = [
 
39
  'ffmpeg', '-y', '-i', input_path, '-vn',
40
  '-c:a', 'libmp3lame', '-b:a', '8k', '-ar', '24000', '-ac', '1',
41
  output_audio
42
  ]
43
+ await run_subprocess(cmd)
44
  if audio_only:
 
45
  return output_audio, None
46
+ # embed into video
47
+ progress.update(1, desc="Making the video quality lower...")
48
+ output_video = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
49
+ cmd = ['ffmpeg', '-y', '-hwaccel', accel, '-i', input_path]
50
+ if custom_bitrate:
51
+ cmd += ['-b:v', f"{int(video_bitrate)}k"]
52
  else:
53
+ cmd += video_base_opts
54
+ if faster:
55
+ cmd += ['-preset', 'ultrafast']
56
+ cmd += ['-c:a', 'libmp3lame', '-b:a', '8k', '-ar', '24000', '-ac', '1', output_video]
57
+ await run_subprocess(cmd)
58
+ return None, output_video
59
+
60
+ # split
61
+ progress.update(1, desc="Splitting Audio and Video...")
 
 
 
 
 
 
 
 
 
 
 
 
62
  audio_wav = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.wav")
63
+ await run_subprocess(['ffmpeg','-y','-i',input_path,'-ac','1','-ar','8000',audio_wav])
 
 
 
 
 
64
 
65
+ # AAC encode
66
+ progress.update(1, desc="Converting audio to AAC which is lower quality...")
67
+ audio_output = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.m4a")
68
+ await run_subprocess([ './fdkaac','-b','1k','-C','-f','2','-G','1','-w','8000','-o',audio_output,audio_wav ], use_fdkaac=True)
 
69
 
70
+ # video
71
+ progress.update(1, desc="Making the video quality lower...")
72
+ video_output = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
73
+ cmd = ['ffmpeg','-y','-hwaccel',accel,'-i',input_path]
74
  if downscale:
75
+ cmd += ['-vf','scale=-2:144']
76
  if custom_bitrate:
77
+ cmd += ['-b:v',f"{int(video_bitrate)}k"]
78
  else:
79
+ cmd += video_base_opts
80
  if faster:
81
+ cmd += ['-preset','ultrafast']
82
+ cmd += ['-an',video_output]
83
+ await run_subprocess(cmd)
84
 
85
  if audio_only:
86
  return audio_output, None
87
 
88
+ # merge
89
+ progress.update(1, desc="Mixing audio and video together...")
90
+ merged = os.path.join(CONVERTED_FOLDER, f"{uuid.uuid4()}.mp4")
91
+ await run_subprocess(['ffmpeg','-y','-i',video_output,'-i',audio_output,'-c','copy',merged])
 
92
 
93
+ # cleanup
94
+ for f in (audio_wav, audio_output, video_output):
95
+ try: os.remove(f)
96
+ except: pass
 
97
 
98
+ return None, merged
 
99
 
100
+ async def process_conversion(use_youtube, youtube_url, video_file, downscale, faster,
101
+ use_mp3, audio_only, custom_bitrate, video_bitrate,
102
+ progress=gr.Progress()):
103
+ with progress.tqdm(total=5) as pbar:
104
+ # Step 1: fetch
105
  if use_youtube:
106
+ pbar.update(1, desc="Downloading video...")
107
+ yt_uuid = uuid.uuid4().hex
108
+ out = os.path.join(UPLOAD_FOLDER, yt_uuid + ".%(ext)s")
109
+ await run_subprocess(['yt-dlp','-o',out,'-f','b',youtube_url])
110
+ files = glob.glob(os.path.join(UPLOAD_FOLDER, yt_uuid + ".*"))
111
+ if not files: return "Download failed.", None
 
 
 
 
 
112
  input_path = files[0]
113
  else:
114
+ pbar.update(1, desc="Preparing input video...")
115
+ fname = video_file.name
116
+ ext = os.path.splitext(fname)[1]
117
+ input_path = os.path.join(UPLOAD_FOLDER, uuid.uuid4().hex + ext)
118
+ shutil.copy2(fname, input_path)
119
+
120
+ # Step 2–5: convert
121
+ if use_mp3:
122
+ pbar.update(1, desc="Converting audio to MP3...")
123
+ else:
124
+ pbar.update(1, desc="Converting audio to AAC which is lower quality...")
125
  audio_out, video_out = await convert_video_task(
126
+ input_path, downscale, faster, use_mp3, audio_only,
127
+ custom_bitrate, video_bitrate, pbar
128
  )
129
 
130
+ # final update
131
+ pbar.update(1, desc="Finalizing...")
132
+
133
  if audio_only:
134
  return audio_out, audio_out
135
  return video_out, video_out
 
 
136
 
137
+ # Build UI
138
  with gr.Blocks(theme=gr.themes.Default(primary_hue="rose")) as demo:
139
+ gr.Markdown("# Low Quality Video Inator")
140
+ with gr.Row():
141
+ use_youtube = gr.Checkbox(label="Use YouTube URL", value=False)
142
+ youtube_url = gr.Textbox(label="YouTube URL")
143
+ video_file = gr.File(label="Upload Video")
144
+
145
+ with gr.Row():
146
+ downscale = gr.Checkbox("Downscale Video to 144p", value=False)
147
+ faster = gr.Checkbox("Faster Compression", value=False)
148
+ with gr.Row():
149
+ use_mp3 = gr.Checkbox("Use MP3 Audio", value=False)
150
+ audio_only = gr.Checkbox("Audio Only", value=False)
151
+ with gr.Row():
152
+ custom_bitrate = gr.Checkbox("Custom Video Bitrate", value=False)
153
+ video_bitrate = gr.Number(label="Bitrate (kbps)", visible=False)
154
+ custom_bitrate.change(lambda x: gr.update(visible=x), custom_bitrate, video_bitrate)
 
 
 
 
 
 
 
 
 
 
 
 
155
 
156
  convert_button = gr.Button("Convert Now", variant="primary")
157
+ video_preview = gr.Video()
158
+ file_download = gr.File()
 
 
 
 
159
 
160
  convert_button.click(
161
  process_conversion,
162
+ inputs=[use_youtube, youtube_url, video_file,
163
+ downscale, faster, use_mp3, audio_only,
164
+ custom_bitrate, video_bitrate],
 
 
165
  outputs=[video_preview, file_download]
166
  )
167