pwsh-download-songs.psm1
#--------------------------------------------------------------------------------------------- # Copyright (c) nt4f04und. All rights reserved. # Licensed under the BSD-style license. See LICENSE in the project root for license information. #--------------------------------------------------------------------------------------------- <# .Synopsis Downloads audio/video files from popular sites like youtube, and treats them, so they look nice. .Description Downloads audio/video files from popular sites like youtube, and treats them so they look nice. Inserts metadata to files and embeds squared album arts (if there are so and source file is one of the followings: .mp3, .m4a, .m4b, .m4p, .m4v, .mp4). For its work this function requires some dependencies See https://github.com/nt4f04und/pwsh-download-songs for installation instructions. For full list of available sites see youtube-dl supported sites https://ytdl-org.github.io/youtube-dl/supportedsites.html .LINK youtube-dl docs - https://ytdl-org.github.io/youtube-dl github repo with installation instructions - https://github.com/nt4f04und/pwsh-download-songs .Parameter url The url to save songs from. Mandatory. .Parameter format The requested format. Use -seeFormats paramater to check what formats are available. Passed to youtube-dl, so check its -f parameter and [its doc](https://github.com/ytdl-org/youtube-dl/blob/master/README.md#format-selection). "m4a/mp3/bestaudio" by defalt. .Parameter noPlaylist Whether to download only the song/video, if the URL refers to a song/video and a playlist. False by default. See youtube-dl --no-playlist param. .Parameter saveThumbs Whether to erase the song thumb image files after the download process. False by default. .Parameter seeFormats If true, the the songs/videos won't be downloaded, but the command will output the available formats. False by default. .Example Download single song "Yxngxr1 - Falling 4 U" in default .m4a format from the YouTube Music playlist download-songs -noPlaylist "https://music.youtube.com/watch?v=jCcGMtGRw5s&list=PLv5tSVP9eg2nkbqapepgxXYGCESsfLcu9" .Example Check all available formats for a single song "Psycho" from the YouTube Music album "Yxngxr1 - I Don't Suit Hats" download-songs -seeFormats -noPlaylist "https://www.youtube.com/watch?v=3ITW3pWaoWQ&list=OLAK5uy_mmO6QLOUTnk7GWFp_CVKH7B0gDgpGJI1A&index=2" .Example Download the whole playlist "Yxngxr1" from YouTube Music (despite the url points on a track) and save its thumbs download-songs -saveThumbs "https://music.youtube.com/watch?v=jCcGMtGRw5s&list=PLv5tSVP9eg2nkbqapepgxXYGCESsfLcu9" #> function download-songs { Param ( [Parameter(Mandatory)] [string[]]$url, [string[]]$format = "m4a/mp3/bestaudio", [switch]$noPlaylist, [switch]$saveThumbs, [switch]$seeFormats ) $ERROR_MESSAGE = "- command doesn't exist. See https://github.com/nt4f04und/pwsh-download-songs to install needed dependencies." # Checks if command exists function _check-command($cmdname) { return [bool](Get-Command -Name $cmdname -ErrorAction SilentlyContinue) } if (!$(_check-command -cmdname 'ffmpeg')) { throw "ffmpeg $ERROR_MESSAGE" } if (!$(_check-command -cmdname 'youtube-dl')) { throw "youtube-dl $ERROR_MESSAGE" } if (!$(_check-command -cmdname 'magick')) { throw "magick $ERROR_MESSAGE" } if (!$(_check-command -cmdname 'AtomicParsley')){ throw "AtomicParsley $ERROR_MESSAGE" } $PREFIX = "[ STAGE ]" if ($seeFormats) { Write-Output "$PREFIX Checking the available formats..." `n } else { Write-Output "$PREFIX Downloading songs and album arts..." `n } if ($seeFormats) { if ($noPlaylist) { youtube-dl -F "$url" --console-title --no-playlist } else { youtube-dl -F "$url" --console-title } return } else { #lowercase letters/numbers only id $BASE_FOLDER = "songs_load_" + -join ((48..57) + (97..122) | Get-Random -Count 20 | ForEach-Object { [char]$_ }) mkdir $BASE_FOLDER if ($noPlaylist) { youtube-dl -f "$format" "$url" --console-title -o "$BASE_FOLDER\%(creator)s - %(title)s.%(ext)s" --write-thumbnail --add-metadata --no-playlist } else { youtube-dl -f "$format" "$url" --console-title -o "$BASE_FOLDER\%(creator)s - %(title)s.%(ext)s" --write-thumbnail --add-metadata } } # Autimatically removes NA from song and image names Get-ChildItem $BASE_FOLDER\*.* | Move-Item -Force -Path { "$BASE_FOLDER\$($_.Name)" } -Destination { "$BASE_FOLDER\$($_.Name -replace 'NA - ', '')" } Write-Output `n"$PREFIX Inserting album arts into songs... (only for .mp3, .m4a, .m4b, .m4p, .m4v and .mp4 files)" `n Get-ChildItem ".\$BASE_FOLDER\*" -Include ` *.mp3, *.m4a, *.m4b, *.m4p, *.m4v, *.mp4 ` | Foreach-Object { $name = [io.path]::GetFileNameWithoutExtension($_.Name) $ext = [io.path]::GetExtension($_.Name) write-output $ext # Convert any image format to png if([System.IO.File]::Exists("$BASE_FOLDER\$name.jpg")){ magick convert "$BASE_FOLDER\$name.jpg" "$BASE_FOLDER\$name.png" } elseif([System.IO.File]::Exists("$BASE_FOLDER\$name.png")) {} elseif([System.IO.File]::Exists("$BASE_FOLDER\$name.jpeg")) { magick convert "$BASE_FOLDER\$name.jpeg" "$BASE_FOLDER\$name.png" } elseif([System.IO.File]::Exists("$BASE_FOLDER\$name.webp")) { magick convert "$BASE_FOLDER\$name.webp" "$BASE_FOLDER\$name.png" } elseif([System.IO.File]::Exists("$BASE_FOLDER\$name.bmp")) { magick convert "$BASE_FOLDER\$name.bmp" "$BASE_FOLDER\$name.png" } elseif([System.IO.File]::Exists("$BASE_FOLDER\$name.gif")) { magick convert "$BASE_FOLDER\$name.gif" "$BASE_FOLDER\$name.png" } $img = @(Get-ChildItem -LiteralPath "$BASE_FOLDER\$name.png") if ($img.length -eq 0) { Write-Error "Album art asset not found for '$($_.Name)'.`n" return } magick mogrify -quality 100 -set option:distort:viewport "%[fx:w>h?h:w]x%[fx:w>h?h:w]+%[fx:w>h?(w-h)/2:0]+%[fx:w>h?0:(h-w)/2]" -filter point -distort SRT 0 +repage "$BASE_FOLDER\*.png" if ($ext -eq ".mp3") { ffmpeg -y -i "$BASE_FOLDER\$($_.Name)" -i "$BASE_FOLDER\$($img[0].Name)" -map 0 -map 1 -c copy -id3v2_version 3 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" "$BASE_FOLDER\$($name)_temp$ext" # ffmpeg can't write to the same file, so rename the output Get-ChildItem -LiteralPath "$BASE_FOLDER\$($name)_temp$ext" | Move-Item -Force -Path { "$BASE_FOLDER\$($_.Name)" } -Destination { "$BASE_FOLDER\$($_.Name -replace '_temp', '')" } } else { AtomicParsley "$BASE_FOLDER\$($_.Name)" --artwork "$BASE_FOLDER\$($img[0].Name)" --overWrite } } Remove-Item $BASE_FOLDER\*.jpg Remove-Item $BASE_FOLDER\*.jpeg Remove-Item $BASE_FOLDER\*.webp Remove-Item $BASE_FOLDER\*.bmp Remove-Item $BASE_FOLDER\*.gif if (!$saveThumbs) { Remove-Item $BASE_FOLDER\*.png } } Export-ModuleMember -Function download-songs # SIG # Begin signature block # MIIUTQYJKoZIhvcNAQcCoIIUPjCCFDoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDkHaHb72M0PnB8 # 1A0i8KAnPzf6p3RgvweRIWkb/bD4I6CCDf8wggQUMIIC/KADAgECAgsEAAAAAAEv # TuFS1zANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xv # YmFsU2lnbiBudi1zYTEQMA4GA1UECxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFs # U2lnbiBSb290IENBMB4XDTExMDQxMzEwMDAwMFoXDTI4MDEyODEyMDAwMFowUjEL # MAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExKDAmBgNVBAMT # H0dsb2JhbFNpZ24gVGltZXN0YW1waW5nIENBIC0gRzIwggEiMA0GCSqGSIb3DQEB # AQUAA4IBDwAwggEKAoIBAQCU72X4tVefoFMNNAbrCR+3Rxhqy/Bb5P8npTTR94ka # v56xzRJBbmbUgaCFi2RaRi+ZoI13seK8XN0i12pn0LvoynTei08NsFLlkFvrRw7x # 55+cC5BlPheWMEVybTmhFzbKuaCMG08IGfaBMa1hFqRi5rRAnsP8+5X2+7UulYGY # 4O/F69gCWXh396rjUmtQkSnF/PfNk2XSYGEi8gb7Mt0WUfoO/Yow8BcJp7vzBK6r # kOds33qp9O/EYidfb5ltOHSqEYva38cUTOmFsuzCfUomj+dWuqbgz5JTgHT0A+xo # smC8hCAAgxuh7rR0BcEpjmLQR7H68FPMGPkuO/lwfrQlAgMBAAGjgeUwgeIwDgYD # VR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEbYPv/c # 477/g+b0hZuw3WrWFKnBMEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB # FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAzBgNVHR8E # LDAqMCigJqAkhiJodHRwOi8vY3JsLmdsb2JhbHNpZ24ubmV0L3Jvb3QuY3JsMB8G # A1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA0GCSqGSIb3DQEBBQUAA4IB # AQBOXlaQHka02Ukx87sXOSgbwhbd/UHcCQUEm2+yoprWmS5AmQBVteo/pSB204Y0 # 1BfMVTrHgu7vqLq82AafFVDfzRZ7UjoC1xka/a/weFzgS8UY3zokHtqsuKlYBAIH # MNuwEl7+Mb7wBEj08HD4Ol5Wg889+w289MXtl5251NulJ4TjOJuLpzWGRCCkO22k # aguhg/0o69rvKPbMiF37CjsAq+Ah6+IvNWwPjjRFl+ui95kzNX7Lmoq7RU3nP5/C # 2Yr6ZbJux35l/+iS4SwxovewJzZIjyZvO+5Ndh95w+V/ljW8LQ7MAbCOf/9RgICn # ktSzREZkjIdPFmMHMUtjsN/zMIIEnzCCA4egAwIBAgISESHWmadklz7x+EJ+6RnM # U0EUMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i # YWxTaWduIG52LXNhMSgwJgYDVQQDEx9HbG9iYWxTaWduIFRpbWVzdGFtcGluZyBD # QSAtIEcyMB4XDTE2MDUyNDAwMDAwMFoXDTI3MDYyNDAwMDAwMFowYDELMAkGA1UE # BhMCU0cxHzAdBgNVBAoTFkdNTyBHbG9iYWxTaWduIFB0ZSBMdGQxMDAuBgNVBAMT # J0dsb2JhbFNpZ24gVFNBIGZvciBNUyBBdXRoZW50aWNvZGUgLSBHMjCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBALAXrqLTtgQwVh5YD7HtVaTWVMvY9nM6 # 7F1eqyX9NqX6hMNhQMVGtVlSO0KiLl8TYhCpW+Zz1pIlsX0j4wazhzoOQ/DXAIlT # ohExUihuXUByPPIJd6dJkpfUbJCgdqf9uNyznfIHYCxPWJgAa9MVVOD63f+ALF8Y # ppj/1KvsoUVZsi5vYl3g2Rmsi1ecqCYr2RelENJHCBpwLDOLf2iAKrWhXWvdjQIC # KQOqfDe7uylOPVOTs6b6j9JYkxVMuS2rgKOjJfuv9whksHpED1wQ119hN6pOa9PS # UyWdgnP6LPlysKkZOSpQ+qnQPDrK6Fvv9V9R9PkK2Zc13mqF5iMEQq8CAwEAAaOC # AV8wggFbMA4GA1UdDwEB/wQEAwIHgDBMBgNVHSAERTBDMEEGCSsGAQQBoDIBHjA0 # MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0 # b3J5LzAJBgNVHRMEAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMEIGA1UdHwQ7 # MDkwN6A1oDOGMWh0dHA6Ly9jcmwuZ2xvYmFsc2lnbi5jb20vZ3MvZ3N0aW1lc3Rh # bXBpbmdnMi5jcmwwVAYIKwYBBQUHAQEESDBGMEQGCCsGAQUFBzAChjhodHRwOi8v # c2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC9nc3RpbWVzdGFtcGluZ2cyLmNy # dDAdBgNVHQ4EFgQU1KKESjhaGH+6TzBQvZ3VeofWCfcwHwYDVR0jBBgwFoAURtg+ # /9zjvv+D5vSFm7DdatYUqcEwDQYJKoZIhvcNAQEFBQADggEBAI+pGpFtBKY3IA6D # lt4j02tuH27dZD1oISK1+Ec2aY7hpUXHJKIitykJzFRarsa8zWOOsz1QSOW0zK7N # ko2eKIsTShGqvaPv07I2/LShcr9tl2N5jES8cC9+87zdglOrGvbr+hyXvLY3nKQc # MLyrvC1HNt+SIAPoccZY9nUFmjTwC1lagkQ0qoDkL4T2R12WybbKyp23prrkUNPU # N7i6IA7Q05IqW8RZu6Ft2zzORJ3BOCqt4429zQl3GhC+ZwoCNmSIubMbJu7nnmDE # Rqi8YTNsz065nLlq8J83/rU9T5rTTf/eII5Ol6b9nwm8TcoYdsmwTYVQ8oDSHQb1 # WAQHsRgwggVAMIIDKKADAgECAhBrPtF6EkS3sEgQtchsbRn4MA0GCSqGSIb3DQEB # CwUAMDgxEjAQBgNVBAMMCW50NGYwNHVOZDEiMCAGCSqGSIb3DQEJARYTbnQ0ZjA0 # dW5kQGdtYWlsLmNvbTAeFw0yMDA1MDExNjMwNDRaFw0yNTA1MDExNjQwNDJaMDgx # EjAQBgNVBAMMCW50NGYwNHVOZDEiMCAGCSqGSIb3DQEJARYTbnQ0ZjA0dW5kQGdt # YWlsLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALg95/MUewLb # PglnVtNCBXE3aW6O07rSCiAWD9hsYBlR3jtninrVtX2ICiEnMb4kaqATsBR18gOo # dW04VUT/VtucMG8ivw7QQK6mS4YumQchscW2T4BwOzbWEc+SlSwGp5iVWFEL4teZ # hJCrbTf3bnj1CoxV2HJbtLOiHDrkOpX9geOUjtfsvaYcVR0rI1lQx0URxcA6uaQD # +nj3oD2JS2sVhKq211r9NY5pQWWiJFZgftzugMlrCnOyOLyLOmsBZI4t8IIP69I2 # EQ2Ot6kUzdb/+khRh4M8qbHXF0ABhVT9qeAQ9zYoxa27IlNnBfOGhFzNi7esJDU7 # eM4YI7V0OLRAyY6Ja8cvl045IRs/gKowhXdbh0T0LMli+6HGToGD64i6MA1H+oHX # X+Y0Oxhi/IoJpctLuAOPQaRNE4ZwYug105fbu6/K+XFso/LOBFSk3x3i1JZBBUN7 # SK4RJ58c4Fi0hsiwejc5S4HkDDTSrjeKoZEIrExVrcYl5Xjr9jzHzj/L7DEFjQzk # 6VrMdaj4K7eaxLmB+tL6B8MeNs3J57JOisysrJWrdI64lYy6+xo4TQKmrsoqfUxU # WGQCij9J1iQaA6RQG+a5DfXstOtOvBP69PQAPTY0DnMNHkka5IUHT6T91FXVfxjd # wzJhR25sUeWTEe426DpdI9yS4DdnoX0hAgMBAAGjRjBEMA4GA1UdDwEB/wQEAwIH # gDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUTb3vtrm0+qP6ocdBdvPD # qyn6ry0wDQYJKoZIhvcNAQELBQADggIBAC9/YvCnzW9j2lggujyNY8+21StYnRSd # Vi/gkg5ZaG/czAa0kF63Loxs5gtpPuZyGBOVRasBaLQ1JrPU4AGkDzKsXLDTAkWf # +WKdM+PDzJPyAxpv9DOjlgurTa8jgsLFAs/Xxgj9vrYgFGgg4f5zENzlFkL8fTDz # ANQmzNZC80CLCrFAZnYrLJhoe1GraJrkaIMLCVtwUldQ9Di2RyBvshRG02od7vks # +viN30b80To0tvTsETXlTZcixo+8w0Ym8bU6ZHtREQ+F/4x4p+P0POLRb9iai/Bo # QNB+lEcRJkz//+IXp9/85D0mvp5Gt8u0QvW4ub7WS2bEgHedCOSxoCIezPSV8KQN # jPJurBu5o0I3+3tWPBYVn4Qga/u+jDoeJCPELlGzY+tKdR9huWG4hHpBhD6fjIqJ # tMzfwJ8UOn9IegzgpY3x/xqrBesT1D/I7q9H5RcmfhqQOXH2m1wjNFOGlY7C5v1a # XSAhrcjcRg/V71rRd/HUrFqddb62TPf19Hcg/t7lms0jbx4/aOjIQnPz6CYmu4b/ # i2HtHxIjOFNWgWmuH7Gn8iIkgNo0jSLeX8KuH5tb+vnsbFCejZCassacD5VKy8OP # DuHB836S9GtA72yOH3uzSV0x/mMVgJXQhezAtJnVH6snLrAWhMsyjunYxIfB1qnI # yQ4HsbxUEM8aMYIFpDCCBaACAQEwTDA4MRIwEAYDVQQDDAludDRmMDR1TmQxIjAg # BgkqhkiG9w0BCQEWE250NGYwNHVuZEBnbWFpbC5jb20CEGs+0XoSRLewSBC1yGxt # GfgwDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZ # BgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYB # BAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgIlftavTn811qh2rrlsg1BNajYTW4EfYI # VRMcyjh0SOswDQYJKoZIhvcNAQEBBQAEggIAR1qarN5KVmC6spsHN/mhdxRuLFUl # u20LFUcqTA2xNlrFCyZy8eWlEWbhgajwpBcDzb7Iji9bKigiR80z3UWo3hPIKwWP # WO6uJJ7cLmgua7m8a+434GysCgp16RvAMBfnVP14jVVBOuP7QLM8fIPQVJwjN1DV # PZK18ihtOLNA3J6qisjI9jrOUx7M4hPq4kNnOJ0NVCgX13kVmePuEGHN+9nledkP # n6FPTm/Xf3Fwpx2MciseZig29uttt3aOn49xA44M52HbOWEeKJK9GT5qsXU6R9uT # 3K6Uh8lEWpl2guw6KbYKQhipGlJZuTnq0gpxS+xSTrZvfIy7rvUZ12nHFgZsaYm6 # ZGZu0YeDAKJVzfAZAjl0TQrOoY/CsSx74jZdcNVcSyHsMlaOtX3hdsWVcDlQCKU8 # G0z42DZDEHjlOJRwqyLEgIJRfKesSA5c/oc1B+NAY0nw/8TSj3AL1rM/iCMIuaOm # kDwDxwmtRzjncudxzsEvHVHZumHymdI2NnJnV3qtPMM3MPJXNhYX7vp+U7it6fOF # 3XZG4rPN41z1bd2YvVotCCs2wmBi1SpM0lCoq/2sR+2jrhLzOEs7Fvqk+IUIA6gb # fFWu68nPmnzs+6MeRiDH6Q4fAUSouCE0C3LlgKCptT0rdsAVB8HyqGhka7pJDqfY # pS0Ai7uqr8ZmwNahggKiMIICngYJKoZIhvcNAQkGMYICjzCCAosCAQEwaDBSMQsw # CQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMf # R2xvYmFsU2lnbiBUaW1lc3RhbXBpbmcgQ0EgLSBHMgISESHWmadklz7x+EJ+6RnM # U0EUMAkGBSsOAwIaBQCggf0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq # hkiG9w0BCQUxDxcNMjAwNTAxMTcwNzQ1WjAjBgkqhkiG9w0BCQQxFgQUDuJEGDak # FUy+hSD9uKGcMiWD/nYwgZ0GCyqGSIb3DQEJEAIMMYGNMIGKMIGHMIGEBBRjuC+r # YfWDkJaVBQsAJJxQKTPseTBsMFakVDBSMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQ # R2xvYmFsU2lnbiBudi1zYTEoMCYGA1UEAxMfR2xvYmFsU2lnbiBUaW1lc3RhbXBp # bmcgQ0EgLSBHMgISESHWmadklz7x+EJ+6RnMU0EUMA0GCSqGSIb3DQEBAQUABIIB # AA+K04MhAvO3WXNH2r2oh/JouKaDfg2MyQbXupPqA2Dx21EN883gLRevrQxT2lW7 # foU4t8T5OHG5B0gkNo0Xy4lmPk4f2bVNtVl1F/IITt0IWqcqSInr4OAydWinx2WH # SEsAR3bpevxhKuN+EHZOUJioz1JG1NjDHNSjgKqv1QKsWEqN8t6rBcEbaXpp2Y3T # VpchPp3vuYikJo38Cx+HU8jcE5jNHWfiVfsSGKgCpqO105T9VgvchTq+2ci8Hv+x # hapAsn+eqa6pqHKZXdtl1ex9f0Em5CSiQQWxPqvrn+sgvF/yue4iz2TOw8v7HQuT # ayttfQ1ug+22C7ry4P2HXfQ= # SIG # End signature block |