初始发布: 21 个 skills (Claude Code / Codex / DSH)
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Download YouTube video(s) at highest quality as merged MP4.
|
||||
.DESCRIPTION
|
||||
Wraps yt-dlp with the settings needed for modern YouTube:
|
||||
- JS runtime (bun preferred; deno auto-downloaded to .\bin if missing)
|
||||
- yt-dlp (auto-downloaded to .\bin if missing)
|
||||
- ffmpeg (must be on PATH, or set -FfmpegDir)
|
||||
- cookies.txt next to this script is used automatically if present
|
||||
.EXAMPLE
|
||||
.\yt-download.ps1 "https://www.youtube.com/watch?v=xxxx"
|
||||
.EXAMPLE
|
||||
.\yt-download.ps1 URL1 URL2 URL3 -OutDir "D:\Videos"
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[Parameter(Mandatory = $true, Position = 0, ValueFromRemainingArguments = $true)]
|
||||
[string[]] $Urls,
|
||||
|
||||
[string] $OutDir = (Join-Path $env:USERPROFILE 'Downloads'),
|
||||
|
||||
# Override format selection if you want (e.g. H.264 only, or <=1080p)
|
||||
[string] $Format = 'bestvideo+bestaudio/best',
|
||||
|
||||
# Path to ffmpeg's bin dir. Auto-detected from PATH if omitted.
|
||||
[string] $FfmpegDir = '',
|
||||
|
||||
# Path to a Netscape cookies.txt. Defaults to cookies.txt beside this script.
|
||||
[string] $Cookies = ''
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$BinDir = Join-Path $ScriptDir 'bin'
|
||||
New-Item -ItemType Directory -Force $BinDir | Out-Null
|
||||
|
||||
function Get-Tool($name, $url, $outFile) {
|
||||
$local = Join-Path $BinDir $outFile
|
||||
if (Test-Path $local) { return $local }
|
||||
$onPath = (Get-Command $name -ErrorAction SilentlyContinue)
|
||||
if ($onPath) { return $onPath.Source }
|
||||
Write-Host "[setup] downloading $name ..." -ForegroundColor Cyan
|
||||
Invoke-WebRequest -Uri $url -OutFile $local
|
||||
return $local
|
||||
}
|
||||
|
||||
# --- yt-dlp ---
|
||||
$ytdlp = Get-Tool 'yt-dlp' 'https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe' 'yt-dlp.exe'
|
||||
|
||||
# --- JS runtime (bun preferred; deno fallback; required by YouTube) ---
|
||||
$jsRuntime = ''
|
||||
$bun = Get-Command 'bun' -ErrorAction SilentlyContinue
|
||||
if ($bun) {
|
||||
$jsRuntime = "bun:$($bun.Source)"
|
||||
} else {
|
||||
$deno = Join-Path $BinDir 'deno.exe'
|
||||
if (-not (Test-Path $deno)) {
|
||||
$onPath = Get-Command 'deno' -ErrorAction SilentlyContinue
|
||||
if ($onPath) {
|
||||
$deno = $onPath.Source
|
||||
} else {
|
||||
Write-Host "[setup] downloading deno ..." -ForegroundColor Cyan
|
||||
$zip = Join-Path $BinDir 'deno.zip'
|
||||
Invoke-WebRequest -Uri 'https://github.com/denoland/deno/releases/latest/download/deno-x86_64-pc-windows-msvc.zip' -OutFile $zip
|
||||
Expand-Archive $zip -DestinationPath $BinDir -Force
|
||||
Remove-Item $zip -Force
|
||||
}
|
||||
}
|
||||
$jsRuntime = "deno:$deno"
|
||||
}
|
||||
|
||||
# --- ffmpeg ---
|
||||
if (-not $FfmpegDir) {
|
||||
$ff = Get-Command 'ffmpeg' -ErrorAction SilentlyContinue
|
||||
if ($ff) {
|
||||
$FfmpegDir = Split-Path -Parent $ff.Source
|
||||
} else {
|
||||
Write-Warning "ffmpeg not found on PATH. Install it (winget install Gyan.FFmpeg) or pass -FfmpegDir. Merging video+audio will fail without it."
|
||||
}
|
||||
}
|
||||
|
||||
# --- cookies ---
|
||||
if (-not $Cookies) {
|
||||
$defaultCookies = Join-Path $ScriptDir 'cookies.txt'
|
||||
if (Test-Path $defaultCookies) { $Cookies = $defaultCookies }
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force $OutDir | Out-Null
|
||||
|
||||
$common = @(
|
||||
'--no-js-runtimes',
|
||||
'--js-runtimes', $jsRuntime,
|
||||
'-f', $Format,
|
||||
'--merge-output-format', 'mp4',
|
||||
'-o', (Join-Path $OutDir '%(title)s [%(height)sp].%(ext)s'),
|
||||
'--no-playlist'
|
||||
)
|
||||
if ($FfmpegDir) { $common += @('--ffmpeg-location', $FfmpegDir) }
|
||||
if ($Cookies) { $common += @('--cookies', $Cookies); Write-Host "[info] using cookies: $Cookies" -ForegroundColor DarkGray }
|
||||
else { Write-Host "[info] no cookies.txt -- public videos only. See SKILL.md if you hit 'Sign in to confirm you're not a bot'." -ForegroundColor DarkGray }
|
||||
|
||||
$fail = 0
|
||||
foreach ($u in $Urls) {
|
||||
Write-Host "`n==== downloading: $u ====" -ForegroundColor Green
|
||||
& $ytdlp @common $u
|
||||
if ($LASTEXITCODE -ne 0) { $fail++; Write-Warning "failed: $u" }
|
||||
}
|
||||
if ($fail) { Write-Warning "$fail download(s) failed."; exit 1 }
|
||||
Write-Host "`nAll done. Saved to: $OutDir" -ForegroundColor Green
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env bash
|
||||
# Download YouTube video(s) at highest quality as merged MP4 (Linux/macOS).
|
||||
#
|
||||
# ./yt-download.sh "https://www.youtube.com/watch?v=xxxx"
|
||||
# ./yt-download.sh URL1 URL2 URL3
|
||||
#
|
||||
# Env overrides:
|
||||
# OUTDIR=/path/to/dir output directory (default: ~/Downloads)
|
||||
# FORMAT="..." yt-dlp -f selector (default: bestvideo+bestaudio/best)
|
||||
# COOKIES=/path/cookies.txt Netscape cookies file (default: cookies.txt beside this script)
|
||||
#
|
||||
# Requirements: yt-dlp, ffmpeg, and a JS runtime (bun/deno/node) must be installed.
|
||||
# pipx install yt-dlp (or: brew install yt-dlp / apt install yt-dlp)
|
||||
# brew install ffmpeg (or: apt install ffmpeg)
|
||||
# bun / deno / node any one (needed for YouTube JS challenges)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -lt 1 ]; then
|
||||
echo "usage: $0 <youtube-url> [more urls...]" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
OUTDIR="${OUTDIR:-$HOME/Downloads}"
|
||||
FORMAT="${FORMAT:-bestvideo+bestaudio/best}"
|
||||
|
||||
# yt-dlp
|
||||
if ! command -v yt-dlp >/dev/null 2>&1; then
|
||||
echo "error: yt-dlp not found. Install it: pipx install yt-dlp" >&2
|
||||
exit 1
|
||||
fi
|
||||
# ffmpeg
|
||||
if ! command -v ffmpeg >/dev/null 2>&1; then
|
||||
echo "warning: ffmpeg not found; merging video+audio will fail. Install ffmpeg." >&2
|
||||
fi
|
||||
|
||||
# JS runtime for YouTube JS challenges. Prefer bun, fall back to deno/node.
|
||||
# Override with JS_RUNTIME=bun|deno|node (must be on PATH).
|
||||
# --no-js-runtimes ensures ONLY the chosen runtime is used (bun won't be
|
||||
# silently shadowed by yt-dlp's built-in deno preference).
|
||||
JS_ARGS=()
|
||||
JS_RUNTIME_NAME=
|
||||
JS_RUNTIME_BIN=
|
||||
if [ -n "${JS_RUNTIME:-}" ] && command -v "$JS_RUNTIME" >/dev/null 2>&1; then
|
||||
JS_RUNTIME_NAME="$JS_RUNTIME"
|
||||
JS_RUNTIME_BIN="$(command -v "$JS_RUNTIME")"
|
||||
elif command -v bun >/dev/null 2>&1; then
|
||||
JS_RUNTIME_NAME="bun"
|
||||
JS_RUNTIME_BIN="$(command -v bun)"
|
||||
elif command -v deno >/dev/null 2>&1; then
|
||||
JS_RUNTIME_NAME="deno"
|
||||
JS_RUNTIME_BIN="$(command -v deno)"
|
||||
elif [ -x "$HOME/.deno/bin/deno" ]; then
|
||||
JS_RUNTIME_NAME="deno"
|
||||
JS_RUNTIME_BIN="$HOME/.deno/bin/deno"
|
||||
elif command -v node >/dev/null 2>&1; then
|
||||
JS_RUNTIME_NAME="node"
|
||||
JS_RUNTIME_BIN="$(command -v node)"
|
||||
fi
|
||||
if [ -n "$JS_RUNTIME_NAME" ]; then
|
||||
JS_ARGS=(--no-js-runtimes --js-runtimes "$JS_RUNTIME_NAME:$JS_RUNTIME_BIN")
|
||||
else
|
||||
echo "warning: no JS runtime (bun/deno/node) found. YouTube may reject the download ('confirm you're not a bot')." >&2
|
||||
fi
|
||||
|
||||
# cookies
|
||||
COOKIES="${COOKIES:-$SCRIPT_DIR/cookies.txt}"
|
||||
COOKIE_ARGS=()
|
||||
if [ -f "$COOKIES" ]; then
|
||||
COOKIE_ARGS=(--cookies "$COOKIES")
|
||||
echo "[info] using cookies: $COOKIES"
|
||||
else
|
||||
echo "[info] no cookies.txt -- public videos only. See SKILL.md for login-required videos."
|
||||
fi
|
||||
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
fail=0
|
||||
for url in "$@"; do
|
||||
echo ""
|
||||
echo "==== downloading: $url ===="
|
||||
if ! yt-dlp "${JS_ARGS[@]}" "${COOKIE_ARGS[@]}" \
|
||||
-f "$FORMAT" \
|
||||
--merge-output-format mp4 \
|
||||
-o "$OUTDIR/%(title)s [%(height)sp].%(ext)s" \
|
||||
--no-playlist \
|
||||
"$url"; then
|
||||
fail=$((fail+1))
|
||||
echo "warning: failed: $url" >&2
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$fail" -gt 0 ]; then
|
||||
echo "warning: $fail download(s) failed." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
echo "All done. Saved to: $OUTDIR"
|
||||
Reference in New Issue
Block a user