neonwatty commited on
Commit
5667416
·
verified ·
1 Parent(s): e8145e9

Upload 4 files

Browse files
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ yt-dlp
2
+ gradio==4.38.1
youtube_downloader/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import os
2
+
3
+ base_dir = os.path.dirname(os.path.abspath(__file__))
4
+ main_dir = os.path.dirname(base_dir)
youtube_downloader/app.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+ import tempfile
3
+ from youtube_downloader.yt_download import download_video
4
+ import gradio as gr
5
+
6
+ video_choices = ["best", "1080", "720", "360"]
7
+
8
+
9
+ print("Setting up Gradio interface...")
10
+ with gr.Blocks(theme=gr.themes.Soft(), title=" youtube downloader") as demo:
11
+ with gr.Tabs():
12
+ with gr.TabItem("youtube downloader"):
13
+ with tempfile.TemporaryDirectory() as tmpdirname:
14
+ with gr.Row():
15
+ with gr.Column(scale=4):
16
+ url_input = gr.Textbox(
17
+ value="https://www.youtube.com/shorts/43BhDHYBG0o",
18
+ label="🔗 Paste YouTube / Shorts URL here",
19
+ placeholder="e.g., https://www.youtube.com/watch?v=.",
20
+ max_lines=1,
21
+ )
22
+ with gr.Column(scale=3):
23
+ resolution_dropdown = gr.Dropdown(
24
+ choices=video_choices, value="best", label="video resolution", info="choose video resolution", interactive=True
25
+ )
26
+
27
+ with gr.Column(scale=2):
28
+ download_button = gr.Button("download", variant="primary")
29
+
30
+ with gr.Row():
31
+ og_video = gr.Video(
32
+ visible=True,
33
+ show_download_button=True,
34
+ show_label=True,
35
+ label="your video",
36
+ format="mp4",
37
+ width="50vw",
38
+ height="50vw",
39
+ )
40
+
41
+ @download_button.click(inputs=[url_input, resolution_dropdown], outputs=[og_video])
42
+ def download_this(url_input, resolution_dropdown):
43
+ temporary_video_location = download_video(url_input, tmpdirname, resolution_dropdown)
44
+
45
+ filename = open(temporary_video_location, "rb")
46
+ byte_file = io.BytesIO(filename.read())
47
+ with open(temporary_video_location, "wb") as out:
48
+ out.write(byte_file.read())
49
+
50
+ new_og_video = gr.Video(
51
+ value=temporary_video_location,
52
+ visible=True,
53
+ show_download_button=True,
54
+ show_label=True,
55
+ label="your video",
56
+ format="mp4",
57
+ width="50vw",
58
+ height="50vw",
59
+ )
60
+
61
+ return new_og_video
62
+
63
+ with gr.TabItem("💡 About"):
64
+ with gr.Blocks() as about:
65
+ gr.Markdown(
66
+ (
67
+ "### About \n"
68
+ "Some notes on how this works: \n\n"
69
+ "1. **youtube / google login**: you do **not** need to be logged into a google account to use the app, with one exception: age restricted videos"
70
+ "2. **age restricted videos**: this app cannot fetch age restricted videos yet, which requires a user login to google / youtube - this feature is not yet available"
71
+ "3. **video resolution**: not all videos have all possible resolutions, so you may not be able to fetch the resolution you want for some videos (as they don't exist) \n"
72
+ "4. **recommended hardware**: this is a very light weight app, so minimum specs should work fine"
73
+ "5. **proxies**: there is an option in the yt_download module to enter proxy server ips"
74
+ )
75
+ )
76
+
77
+
78
+ if __name__ == "__main__":
79
+ print("Launching Gradio interface...")
80
+ demo.launch() # allow_flagging="never"
youtube_downloader/yt_download.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yt_dlp
2
+ from yt_dlp import YoutubeDL
3
+ import re
4
+
5
+
6
+ def is_valid_youtube_url(url: str) -> bool:
7
+ if not isinstance(url, str):
8
+ return False
9
+ pattern = r"^https://www\.youtube\.com/watch\?v=[A-Za-z0-9_-]{11}$" # youtube vido ids are always 11 chars long
10
+ if "shorts" in url:
11
+ pattern = r"^https://www\.youtube\.com/shorts/[A-Za-z0-9_-]{11}$" # youtube vido ids are always 11 chars long
12
+ return re.match(pattern, url) is not None
13
+
14
+
15
+ def download_video(url: str, savedir: str, resolution_dropdown: str, my_proxies: dict = {}) -> str:
16
+ try:
17
+ print("Downloading video from youtube...")
18
+ if is_valid_youtube_url(url):
19
+ with YoutubeDL() as ydl:
20
+ info_dict = ydl.extract_info(url, download=False)
21
+ video_url = info_dict.get("url", None)
22
+ video_id = info_dict.get("id", None)
23
+ video_title = info_dict.get("title", None)
24
+ if video_title is None:
25
+ savepath = savedir + "/" + video_id + ".mp4"
26
+ else:
27
+ savepath = savedir + "/" + video_title + ".mp4"
28
+
29
+ ydl_opts = {
30
+ "format": "bestvideo+bestaudio/best",
31
+ "merge_output_format": "mp4",
32
+ "outtmpl": savepath,
33
+ }
34
+ if resolution_dropdown == "1080":
35
+ ydl_opts = {
36
+ "format": "bestvideo[height<=1080]+bestaudio/best",
37
+ "merge_output_format": "mp4",
38
+ "outtmpl": savepath,
39
+ }
40
+
41
+ if resolution_dropdown == "720":
42
+ ydl_opts = {
43
+ "format": "bestvideo[height<=720]+bestaudio/best",
44
+ "merge_output_format": "mp4",
45
+ "outtmpl": savepath,
46
+ }
47
+
48
+ if resolution_dropdown == "360":
49
+ ydl_opts = {
50
+ "format": "bestvideo[height<=360]+bestaudio/best",
51
+ "merge_output_format": "mp4",
52
+ "outtmpl": savepath,
53
+ }
54
+
55
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
56
+ ydl.download([url])
57
+
58
+ print("...done!")
59
+ return savepath
60
+ else:
61
+ raise ValueError(f"invalid input url: {url}")
62
+ except Exception as e:
63
+ raise ValueError(f"yt_download failed with exception {e}")