Skip to content

Instantly share code, notes, and snippets.

@anonymous1184
Last active August 12, 2024 00:15
Show Gist options
  • Save anonymous1184/e08453e3ba393622d8fef3046764a2a3 to your computer and use it in GitHub Desktop.
Save anonymous1184/e08453e3ba393622d8fef3046764a2a3 to your computer and use it in GitHub Desktop.
YouTube Download Helper

;
; REQUIRED
;
ytdl.Path := "D:\CLI\youtube"
; Path of yt-dlp.exe
;
; OPTIONAL
; The values below represent the defaults
;
; FFmpeg directory
ytdl.FFmpeg := "..\FFmpeg"
; Simple bypass
ytdl.GeoBypass := true
; Via country code
; ytdl.GeoBypass := "US"
; From an IP block (CDIR)
; ytdl.GeoBypass := "35.190.247.0/24"
; Embed metadata?
ytdl.Metadata := true
; Time between downloads
ytdl.SleepInterval := 0
; Audio options
; 'm4a'/'opus' natively
ytdl.Audio.Format := "m4a"
; Others need recoding (like mp3)
; Thumbnail?
ytdl.Audio.Thumbnail := false
; Video options
; mkv
; mp4
; ogg
; webm
ytdl.Video.Container := "mp4"
; 144p = 144
; 240p = 240
; 360p = 360
; 480p = 480
; HD = 720
; FHD = 1080
; QHD = 1440
; 4k = 2160
; 8k = 4320
ytdl.Video.Quality := 1080
; Thumbnail?
ytdl.Video.Thumbnail := true
#NoEnv
EnvGet UserProfile, USERPROFILE
MusicDir := UserProfile "\Music"
VideoDir := UserProfile "\Videos"
GroupAdd Browsers, ahk_exe chrome.exe
GroupAdd Browsers, ahk_exe firefox.exe
GroupAdd Browsers, ahk_exe msedge.exe
GroupAdd Browsers, ahk_exe opera.exe
return ; End of auto-execute
#If WinActive("ahk_group Browsers")
!y::ytdl(MusicDir, 1)
^y::ytdl(VideoDir, 2)
#If

; Version: 2023.10.13.1
/*
# Examples
See the file above.
# Dependencies
## yt-dlp
https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
## FFmpeg
https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-essentials.7z
FFmpeg binaries must be accessible to `yt-dlp` for format conversions.
You can drop them in the folder where yt-dlp.exe resides:
- ffmpeg.exe
- ffplay.exe
- ffprobe.exe
Else, function expects them to be in the same level as yt-dlp binary. Example:
- D:\CLI\FFmpeg
- D:\CLI\yt-dlp
Alternatively, to use an explicit path, set the option:
ytdl.FFmpeg := "D:\Path\to\FFmpeg\bin"
## GetUrl()
https://gist.github.com/anonymous1184/7cce378c9dfdaf733cb3ca6df345b140/raw/GetUrl1.ahk
*/
/**
* Downloads a video from YouTube.
*
* @param {string} Directory Path to save the downloaded file
* @param {integer} Mode 1 = Audio, 2 = Video
*/
ytdl(Directory, Mode) {
if !(FileExist(ytdl.Path) ~= "D") {
throw Exception("Not a directory", -1, ytdl.Path)
}
if (!FileExist(ytdl.Path "\yt-dlp.exe")) {
throw Exception("yt-dlp.exe was not found.", -1, ytdl.Path)
}
if (!FileExist(ytdl.Path "\cache")) {
FileCreateDir % ytdl.Path "\cache"
}
cmd := "yt-dlp.exe"
Directory := RTrim(Directory, "\")
loop files, % Directory, D
Directory := A_LoopFileLongPath "\"
if !(Directory ~= "\\$") {
throw Exception("Invalid directory.", -1, Directory)
}
if !(Mode ~= "^[12]$") {
msg := "'Mode' must be either '1' or '2'" "`n"
. "`n" "1 = Audio"
. "`n" "2 = Video"
throw Exception(msg "`n", -1, Mode)
}
ytdl.Video.Container := Format("{:L}", ytdl.Video.Container)
if !(ytdl.Video.Container ~= "^(mkv|mp4|ogg|webm)$") {
ytdl.Video.Container := "mp4"
}
ytdl.Video.Quality := ytdl.Video.Quality
if !(ytdl.Video.Quality ~= "^(144|240|360|480|720|1080|1440|2160|4320)$") {
ytdl.Video.Quality := 1080
}
if !(url := GetUrl()) {
MsgBox 0x40010, Error, Couldn't retrieve the URL.
return
}
if (!InStr(url, "youtube.com")) {
return
}
regex := "i)(?=.*v=(?<videoId>[^&]+))?(?=.*list=(?<listId>[^&]+))?"
RegExMatch(url, regex, _)
if (!_videoId && !_listId) {
MsgBox 0x40010, Error, No video or playlist found on the URL.
return
}
isPlaylist := false
if (_listId && !_videoId) {
isPlaylist := true
} else if (_listId && _videoId) {
MsgBox 0x40024, Playlist, Download the full playlist?
IfMsgBox Yes
isPlaylist := true
}
if (isPlaylist) {
Directory .= "%(playlist)s\%(playlist_index)s - "
}
Directory .= "%(title)s.%(ext)s"
; Options:
;; yt-dlp.exe --help
; General Options
cmd .= " --ignore-errors"
cmd .= " --ignore-config"
; Network Options
cmd .= " --force-ipv4" ; Avoid leaking for split tunnels
; Geo restriction
if (ytdl.GeoBypass = true) {
cmd .= " --geo-bypass"
} else if (ytdl.GeoBypass ~= "^\w{2}$") {
cmd .= " --geo-bypass-country """ ytdl.GeoBypass """"
} else if (ytdl.GeoBypass ~= "^[\d\.\/]+$") {
cmd .= " --geo-bypass-ip-block """ ytdl.GeoBypass """"
}
; Video Selection
cmd .= " --yes-playlist"
; Download Options
cmd .= " --hls-prefer-ffmpeg"
; Filesystem Options
cmd .= " --output """ Directory """"
cmd .= " --no-overwrites"
cmd .= " --continue"
cmd .= " --no-part"
cmd .= " --cookies """ ytdl.Path "\cache\cookies.txt"""
cmd .= " --cache-dir """ ytdl.Path "\cache"""
; Verbosity
cmd .= " --no-warnings"
cmd .= " --console-title"
cmd .= " --no-call-home"
; Workarounds
cmd .= " --no-check-certificate"
cmd .= " --prefer-insecure"
; User agent:
;; Firefox (2023/10) like when reloading page without cache
cmd .= " --user-agent ""Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0"""
cmd .= " --referer """ url """"
cmd .= " --add-header ""Accept-Encoding: gzip, deflate, br"""
cmd .= " --add-header ""Accept-Language: en-US,en;q=0.5"""
cmd .= " --add-header ""Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"""
cmd .= " --add-header ""Cache-Control: no-cache"""
cmd .= " --add-header ""Connection: keep-alive"""
cmd .= " --add-header ""DNT: 1"""
cmd .= " --add-header ""Pragma: no-cache"""
cmd .= " --add-header ""SEC-FETCH-DEST: document"""
cmd .= " --add-header ""SEC-FETCH-MODE: navigate"""
cmd .= " --add-header ""SEC-FETCH-SITE: same-origin"""
cmd .= " --add-header ""SEC-FETCH-USER: ?1"""
cmd .= " --add-header ""TE: trailers"""
cmd .= " --add-header ""UPGRADE-INSECURE-REQUESTS: 1"""
; Sleep Interval
cmd .= " --sleep-interval """ Format("{:d}", ytdl.SleepInterval) """"
; Video Format Options
cmd .= " --youtube-skip-dash-manifest"
cmd .= " --merge-output-format """ ytdl.Video.Container """"
; Subtitle Options
; -none-
; Authentication Options
; -none-
; Adobe Pass Options
; -none-
; Post-processing Options
;; Format
if (Mode = 1) {
cmd .= " --format "
ext := Format("{:L}", ytdl.Audio.Format)
if (ext ~= "^(m4a|opus)$") {
cmd .= """bestaudio[ext=" ext "]"""
} else {
cmd .= " --extract-audio"
cmd .= " --audio-format """ ext """"
cmd .= " --audio-quality 0"
}
} else {
cmd .= " --format ""bestvideo[height<=" ytdl.Video.Quality "]+bestaudio"""
}
;; Thumbnails
if (Mode = 1 && ytdl.Audio.Thumbnail)
|| (Mode = 2 && ytdl.Video.Thumbnail) {
cmd .= " --embed-thumbnail"
}
;; Metadata
if (ytdl.Metadata) {
cmd .= " --add-metadata"
}
;; FFmpeg
if (!FileExist(ytdl.Path "\ffmpeg.exe")) {
ffmpegPath := ""
if (FileExist(ytdl.FFmpeg "\ffmpeg.exe")) {
loop files, % ytdl.Path, D
ffmpegPath := A_LoopFileLongPath
}
if (FileExist(ytdl.Path "\" ytdl.FFmpeg "\ffmpeg.exe")) {
loop files, % ytdl.Path "\" ytdl.FFmpeg, D
ffmpegPath := A_LoopFileLongPath
}
if (ffmpegPath) {
cmd .= " --ffmpeg-location """ ffmpegPath """"
}
}
; Execute
cmd .= " """ (isPlaylist ? _listId : _videoId) """"
try {
Run % cmd, % ytdl.Path
} catch {
MsgBox 0x40010, Error, There was an error running yt-dlp.
}
}
class ytdl {
static Path := "" ; Path to the binary
; FFmpeg directory
, FFmpeg := "..\FFmpeg"
; Uncensor
, GeoBypass := true
; Embed metadata?
, Metadata := true
; Time between downloads
, SleepInterval := 0
; Audio options
, Audio := {}
; 'm4a'/'opus' natively
, Audio.Format := "m4a"
; Others need recoding (like mp3)
; Thumbnail?
, Audio.Thumbnail := false
; Video options
, Video := {}
; mkv
; mp4
; ogg
; webm
, Video.Container := "mp4"
; 144p = 144
; 240p = 240
; 360p = 360
; 480p = 480
; HD = 720
; FHD = 1080
; QHD = 1440
; 4k = 2160
; 8k = 4320
, Video.Quality := 1080
; Thumbnail?
, Video.Thumbnail := true
}
@Gewerd-Strauss
Copy link

Hey there.

I have not yet tested this - I'm not at home rn, but finally got around to taking some time for it. Last couple weeks were... shit, so this got stashed very thoroughly. So this comment is based fully on a brief read-through of the code above. So excuse my semi-ignorant question now:

(How) can I get a channel's name before downloading? The reason is that I use a system of D:\YTD\%channelName%\%videotitle%.%filetype%, because otherwhise holy hell would this get crammed.


From what I can tell, the example-script is almost all I need - a few changes to iterate over a file of URLs, and an optional way to shutdown PC at script ending, but aside from that I think I can almost use this verbatim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment