Skip to content

Instantly share code, notes, and snippets.

@SeidChr
Last active September 19, 2020 18:32
Show Gist options
  • Save SeidChr/b77cec8282bc4afd0ec93e01b1460b5a to your computer and use it in GitHub Desktop.
Save SeidChr/b77cec8282bc4afd0ec93e01b1460b5a to your computer and use it in GitHub Desktop.
param(
[string[]] $videoId,
[switch] $setup,
[double] $trimPercentage = 0.015
)
function Ensure-Path
{
param([string]$Path)
if (!(Test-Path $Path)) {
New-Item -ItemType Directory -Path $Path
}
}
function Expand-PartialArchive
{
param(
[string] $Path,
[string] $DestinationPath,
[string] $like
)
Ensure-Path -Path $DestinationPath
Add-Type -AssemblyName System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($Path)
$zip.Entries `
| Where-Object { $_.FullName -like $like -and $_.Name } `
| ForEach-Object {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile(
$_,
"$DestinationPath\$($_.Name)",
$true
)
}
$zip.Dispose()
}
function Get-Duration
{
param(
[string] $executable,
[string] $mediaFilePath
)
$durationCommand = "$executable -i $mediaFilePath 2>&1"
Write-Host "Duration:" $durationCommand
$durationResult = Invoke-Expression $durationCommand
$match = $durationResult | Select-String -Pattern "Duration:\s+(\d{2}:\d{2}:\d{2}.\d{2}),.*"
[System.TimeSpan]::Parse($match.Matches.Groups[1].Value)
}
function Run-Setup
{
if ($IsWindows)
{
# https://www.gyan.dev/ffmpeg/builds/
$url = (Invoke-WebRequest "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.zip" -ErrorAction Ignore -SkipHttpErrorCheck).Headers.Location[0]
Invoke-WebRequest $url -OutFile ffmpeg.zip
Expand-PartialArchive -Path ffmpeg.zip -DestinationPath $binPath -like "*/bin/*"
Remove-Item .\ffmpeg.zip
# http://ytdl-org.github.io/youtube-dl/download.html
$url = "https://yt-dl.org/downloads/2020.09.14/youtube-dl.exe"
Ensure-Path $binPath
Invoke-WebRequest $url -OutFile $ytdlRuntime
}
if ($IsLinux)
{
# docker run -it --rm -v ".:/project" -w "/project" --entrypoint pwsh mcr.microsoft.com/dotnet/core/sdk
# run ".\script.ps1 -setup" in the container
# commit the container for later use
# or use a dockerfile ...
Add-Content /etc/apt/sources.list -Value "deb http://ftp.de.debian.org/debian sid main"
& apt-get update
# ffmpeg is auto-installed with ytdl
& apt-get install -y youtube-dl
& apt-get remove --purge -y ((& apt-mark showauto) -join " ")
Remove-Item "/var/lib/apt/lists/*" -Force
}
}
function DownloadTo-Mp3
{
param(
[string] $executable,
[string] $videoIdentifier,
[string] $targetFileName = $videoIdentifier,
[string] $targetFolder
)
$downloadFilePath = Join-Path $targetFolder "$targetFileName.mp3"
$outArgument = Join-Path $targetFolder ($targetFileName+'.%(ext)s');
$downloadCommand = "$executable -x -f bestaudio --audio-format mp3 --add-metadata -o `"$outArgument`" $videoIdentifier"
Write-Host "Download:" $downloadCommand
Invoke-Expression $downloadCommand | Write-Host
$downloadFilePath
}
function Trim-Mp3
{
param(
[string] $executable,
[string] $sourceFilePath,
[string] $targetFolderPath,
[double] $trimPercentage,
[switch] $deleteSource
)
$sourceDuration = Get-Duration `
-executable $executable `
-mediaFilePath $sourceFilePath
$trimSeconds = [int]($sourceDuration.TotalSeconds * $trimPercentage)
$ss = [System.TimeSpan]::FromSeconds($trimSeconds)
$to = $sourceDuration.Add([System.TimeSpan]::FromSeconds(-$trimSeconds))
$targetDuration = $to-$ss
$diffDuration = $sourceDuration - $targetDuration
Write-Host "Source Duration:" $sourceDuration
Write-Host "Target Duration:" $targetDuration
Write-Host "Removing $($diffDuration.TotalSeconds) Seconds from the Track"
$targetFilePath = Join-Path $targetFolderPath (Split-Path $sourceFilePath -Leaf)
$trimCommand = "$executable -hide_banner -ss $ss -to $to -i $sourceFilePath -y -c copy $targetFilePath"
Write-Host "Trim:" $trimCommand
Invoke-Expression $trimCommand | Write-Host
if ($deleteSource)
{
Remove-Item $sourceFilePath
}
}
#######################
### ###
### ACTUAL SCRIPT ###
### ###
#######################
$location = Get-Location
$binPath = Join-Path $location "bin"
$tempPath = Join-Path $location "temp"
$outPath = Join-Path $location "out"
Ensure-Path $tempPath
Ensure-Path $outPath
$ytdlRuntime = "youtube-dl"
$ffmpegRuntime = "ffmpeg"
if ($IsWindows)
{
$ffmpegRuntime = Join-Path $binPath "ffmpeg.exe"
$ytdlRuntime = Join-Path $binPath "youtube-dl.exe"
}
if ($setup)
{
Run-Setup
}
# https://stackoverflow.com/questions/46508055/using-ffmpeg-to-cut-audio-from-to-position
# https://superuser.com/questions/23930/how-to-decode-aac-m4a-audio-files-into-wav#:~:text=7%20Answers&text=The%20easiest%20way%20to%20do,this%20to%20them%20in%20bulk.
# https://spapas.github.io/2018/03/06/easy-youtube-mp3-downloading/
# .\youtube-dl.exe -x --audio-format mp3 --audio-quality 9 --postprocessor-args "-ss 600" mcQc3UdkSow
# https://ffmpeg.org/ffmpeg.html
# .\ffmpeg.exe -ss 600 -t 1:00:00 -i $m4aPath $m4aPath+".mp3"
$videoId | Where-Object { $_ } | ForEach-Object {
$downloadedFile = DownloadTo-Mp3 `
-executable $ytdlRuntime `
-targetFolder $tempPath `
-videoIdentifier $_
Trim-Mp3 `
-executable $ffmpegRuntime `
-sourceFilePath $downloadedFile `
-targetFolderPath $outPath `
-trimPercentage $trimPercentage `
-deleteSource
}
# https://github.com/ytdl-org/youtube-dl/blob/master/README.md#readme
# normalize: https://superuser.com/a/323127/1191155
# http://ffmpeg.org/ffmpeg-all.html#loudnorm
# overlaying mulitple files
# https://www.reddit.com/r/ffmpeg/comments/7kpqxa/merging_two_audio_files/drh8dm9/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment