from gradio_client import Client import yt_dlp # pip install yt-dlp import subprocess import os from pathlib import Path import gradio as gr import shutil import random from theme import theme VIDEO_DIRECTORY = "videos" client = Client("abidlabs/music-separation") def acapellify(audio_path): result = client.predict(audio_path, api_name="/predict") return result[0] # based on https://github.com/gradio-app/gradio/blob/bebfb72b353a4280155cf7070441fc476ac10172/guides/06_client-libraries/fastapi-app-with-the-gradio-client.md def process_video(video_path): old_audio = os.path.basename(video_path).split(".")[0] + ".m4a" subprocess.run( ["ffmpeg", "-y", "-i", video_path, "-vn", "-acodec", "copy", old_audio] ) new_audio = acapellify(old_audio) new_video_path = f"{VIDEO_DIRECTORY}/{Path(video_path).name}" subprocess.call( [ "ffmpeg", "-y", "-i", video_path, "-i", new_audio, "-map", "0:v", "-map", "1:a", "-c:v", "copy", "-c:a", "aac", "-strict", "experimental", new_video_path, ] ) # remove old audio and video os.remove(old_audio) os.remove(video_path) new_audio_path = f"{VIDEO_DIRECTORY}/{old_audio}" shutil.move(new_audio, new_audio_path) return new_video_path, new_audio_path # filename default value will return name of video on youtube def download_yt_url(url: str, filename: str = "%(title)s", format="mp4"): output_path = f"{filename}.{format}" # restrict video length so one user doesn't take up all our bandwidth def video_filter(info): MAX_DURATION = 10 * 60 duration = info.get("duration") if duration and duration > MAX_DURATION: raise gr.Error( f"The video is too long at {duration}s, choose a video less than {MAX_DURATION}s" ) ydl_opts = { "match_filter": video_filter, "format": f"{format}/bestaudio", "outtmpl": output_path, } with yt_dlp.YoutubeDL(ydl_opts) as ydl: error_code = ydl.download([url]) # info = ydl.extract_info(url, extra_info={"output_path": output_path}) if error_code: raise gr.Error(f"Failed to download video, error code: {error_code}") return output_path def wrap_html(filename): yt_url = f"https://www.youtube.com/watch?v={filename}" return f"""

Original Video

{yt_url}

""" # ideally yt_url should be validated def acapellify_url(yt_url, gr_request: gr.Request): # example filename: https://www.youtube.com/watch?v=TasKo5HHWb4 -> TasKo5HHWb4 filename = yt_url.split("=", 1)[-1].split("=", 1)[0] video_path = download_yt_url(yt_url, filename) new_video_path, new_audio_path = process_video(video_path) return new_video_path, new_audio_path, wrap_html(filename) def load_mystery_video(gr_request: gr.Request): video_paths = list(Path(VIDEO_DIRECTORY).glob("*.mp4")) n_videos = len(video_paths) if not n_videos: raise gr.Error( "No videos archived yet. Enter a Youtube URL to add the first video!" ) selected_video = video_paths[random.randrange(n_videos)] filename = selected_video.name.split(".", 1)[0] selected_audio = Path(VIDEO_DIRECTORY) / f"{filename}.m4a" selected_video = str(selected_video) selected_audio = str(selected_audio) return selected_video, selected_audio, wrap_html(filename) with open("header.md", "r") as markdown_file: markdown_text = markdown_file.read() with gr.Blocks(theme=theme, css="footer {visibility: hidden}") as demo: with gr.Row(): header = gr.Markdown(markdown_text) with gr.Row().style(equal_height=True): with gr.Column(scale=0.4, variant="panel"): input_url = gr.Textbox(label="Youtube URL") process_video_btn = gr.Button("Acapellify", variant="primary") mystery_btn = gr.Button("Mysterious Video") static_path_display = gr.HTML(label="Output File Paths", visible=True) with gr.Column(scale=0.6, variant="panel"): output_video = gr.Video(label="Acapellified Video") output_audio = gr.Audio(label="Acapellified Audio") process_video_btn.click( fn=acapellify_url, inputs=[input_url], outputs=[output_video, output_audio, static_path_display], ) mystery_btn.click( fn=load_mystery_video, inputs=[], outputs=[output_video, output_audio, static_path_display], ) if __name__ == "__main__": os.makedirs(VIDEO_DIRECTORY, exist_ok=True) demo.launch()