nurjns icon

YouTube Audio Downloader

nurjns | PRO | 10/17/25 05:11:49 PM UTC (Edited) | 0 ⭐ | 6297 👁️ | Never ⏰ | []
PowerShell |

5.02 KB

|

None

|

0 👍

/

0 👎

# ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
# YouTube Audio Downloader
#
# 1. Script als z. B. "download.ps1" mit Kodierung "UTF-8" anlegen.
# 2. yt-dlp hier herunterladen und in den selben Ordner des Scripts kopieren: https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe
# 3. Beim Ausführen des Scripts die Video- oder Kanal-URL angegeben. Das Script lädt alle Videos als MP3 herunter und passt das Datum zum Upload-Datum an. Bereits heruntergeladene Audios werden übersprungen.
# 4. Es werden maximal 50 Videos wegen dem Rate-Limit von YouTube heruntergeladen. Nach Abschluss der Downloads wird das ursprüngliche Upload-Datum auf die Audio-Dateien gesetzt.
#
# Version 1.0.1 - 22.09.2025 - @nurjns
# ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
# Pfade definieren und prüfen
$outputDir = Join-Path $PSScriptRoot 'audios'
$archiveFile = Join-Path $PSScriptRoot 'downloaded.txt'
$ytDlp = Join-Path $PSScriptRoot 'yt-dlp.exe'
 
if (!(Test-Path $ytDlp)) {
    Write-Host "Fehler: yt-dlp.exe wurde im Skriptordner nicht gefunden: $ytDlp" -ForegroundColor Red
    Write-Host "Hier herunterladen: https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp.exe"
    Pause
    return
}
 
# Kanal-Link interaktiv abfragen
$channelUrl = Read-Host "YouTube Video-URL oder Kanal-URL"
 
# Sicherstellen, dass der Ausgabeordner existiert
if (!(Test-Path $outputDir)) {
    New-Item -ItemType Directory -Force -Path $outputDir | Out-Null
}
 
# Download-Befehl mit yt-dlp (max. 50 Videos)
$arguments = @(
    $channelUrl,
    "--download-archive", "`"$archiveFile`"",
    "-o", "`"$outputDir/%(title)s [%(id)s].%(ext)s`"",
    "-x",
    "--audio-format", "mp3",
    "--ffmpeg-location", "`"$PSScriptRoot`"",
    "--max-downloads", "50"
)
 
Write-Host "Starte Download mit yt-dlp..."
& $ytDlp @arguments
 
if ($LASTEXITCODE -eq 101) {
    Write-Host "Limit von 50 Videos erreicht! Fuer weitere Downloads Script neu starten." -ForegroundColor Yellow
}
 
# Hole Liste aller Video-IDs, die im Archiv stehen (also schon geladen wurden)
$downloadedIds = Get-Content $archiveFile | ForEach-Object { $_ -replace '^youtube ', '' }
 
# Schleife durch YouTube-Kanal
foreach ($id in $downloadedIds) {
    try {
        $json = & $ytDlp -j --skip-download -- "$id" 2>$null | ConvertFrom-Json
        if ($null -eq $json) { 
            Write-Warning "Keine Metadaten fuer ID $id gefunden"
            continue 
        }
 
        $uploadDate = $json.upload_date
        $title = $json.title
 
        # ungültige Zeichen durch "_" ersetzen
        $invalidChars = [System.IO.Path]::GetInvalidFileNameChars() -join ''
        $regex = "[{0}]" -f [Regex]::Escape($invalidChars)
        $safeTitle = $title -replace $regex, '_'
 
        $fileName = "$outputDir\$($safeTitle) [$id].mp3"
 
        $fileFound = $false
        $actualFileName = ""
 
        if (Test-Path $fileName) {
            $fileFound = $true
            $actualFileName = $fileName
        }
        else {
            $searchPattern = "*[$id].*"
            $matchingFiles = Get-ChildItem -Path $outputDir -Filter $searchPattern -ErrorAction SilentlyContinue
            if ($matchingFiles.Count -gt 0) {
                $actualFileName = $matchingFiles[0].FullName
                $fileFound = $true
                Write-Host "Datei gefunden als: $($matchingFiles[0].Name)" -ForegroundColor Yellow
            }
        }
 
        if (!$fileFound) { 
            Write-Warning "Datei nicht gefunden fuer ID $id. Gesucht: $fileName"
            continue 
        }
 
        if ($uploadDate -match '^\d{8}$') {
            $year = $uploadDate.Substring(0, 4)
            $month = $uploadDate.Substring(4, 2)
            $day = $uploadDate.Substring(6, 2)
 
            try {
                $dt = Get-Date -Year $year -Month $month -Day $day -Hour 0 -Minute 0 -Second 0
                $file = Get-Item -LiteralPath $actualFileName
                if ($file -is [System.Array]) {
                    $file = $file[0]
                }
 
                if ($file.CreationTime.Date -ne $dt.Date -or $file.LastWriteTime.Date -ne $dt.Date -or $file.LastAccessTime.Date -ne $dt.Date) {
                    Set-ItemProperty -LiteralPath $actualFileName -Name CreationTime -Value $dt
                    Set-ItemProperty -LiteralPath $actualFileName -Name LastWriteTime -Value $dt
                    Set-ItemProperty -LiteralPath $actualFileName -Name LastAccessTime -Value $dt
                    Write-Host "Metadaten gesetzt fuer: $($file.Name)" -ForegroundColor Green
                }
                else {
                    Write-Host "Metadaten bereits korrekt fuer: $($file.Name)" -ForegroundColor DarkGray
                }
            }
            catch {
                Write-Error "Fehler beim Setzen der Zeitstempel fuer $actualFileName : $($_.Exception.Message)"
            }
        }
        else {
            Write-Warning "Ungueltiges Upload-Datum Format fuer $fileName : $uploadDate"
        }
    }
    catch {
        Write-Error "Fehler beim Verarbeiten von ID $id : $($_.Exception.Message)"
    }
}
 
Write-Host "Fertig!" -ForegroundColor Green
pause

Comments