Last active
August 2, 2017 13:06
-
-
Save LachlanArthur/ba6f866d3e723dbf3400a1b6e6189dad to your computer and use it in GitHub Desktop.
Adult Swim Downloader (Requires FFMpeg)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$VideoURL = Read-Host -Prompt 'Adult Swim video page URL' | |
$Temp = "temp_" + ( $VideoURL -replace '[<>:"/\\|?*]','_' ) | |
New-Item -ItemType Directory -Path "./$($Temp)" -Force | Out-Null | |
if ( -not ( Test-Path "./$($Temp)/Video_Page.html" ) ) { | |
"Downloading webpage..." | Write-Host | |
Invoke-WebRequest $VideoURL -OutFile "./$($Temp)/Video_Page.html" | |
} | |
$VideoPage = Get-Content "./$($Temp)/Video_Page.html" | |
"Extracting video ID..." | Write-Host | |
$VideoConfigRegex = [regex]::Matches( $VideoPage, '<script>\s*__AS_INITIAL_DATA__ = (.+?);\s*</script>' ) | |
if ( -not $VideoConfigRegex.success ) { throw "Couldn't find video config" } | |
$VideoConfig = $VideoConfigRegex.Captures.Groups[1].Value | ConvertFrom-Json | |
if ( -not ( Test-Path "./$($Temp)/API_Response.json" ) ) { | |
$VideoId = $VideoConfig.show.sluggedVideo.id | |
$APIParams = @{ | |
fields = 'title,type,duration,collection_title,images,stream,segments,title_id' | |
iframe = 'false' | |
} | |
"Downloading episode data from API..." | Write-Host | |
Invoke-WebRequest "http://www.adultswim.com/videos/api/v2/videos/$VideoId" -Body $APIParams -OutFile "./$($Temp)/API_Response.json" | |
} | |
$APIResponse = Get-Content "./$($Temp)/API_Response.json" | ConvertFrom-Json | |
if ( $APIResponse.status -ne 'ok' ) { throw "API Request failed" } | |
$VideoAssets = $APIResponse.data.stream.assets | |
$PlaylistURL = [System.Uri]( $VideoAssets | Where-Object url -like '*_stream_full.m3u8' | Select-Object -ExpandProperty url ) | |
$BaseURL = ( ( $PlaylistURL.Scheme, "://", $PlaylistURL.Host ) + $PlaylistURL.Segments[0..($PlaylistURL.Segments.Length - 2)] ) -join '' | |
if ( -not ( Test-Path "./$($Temp)/Playlist_Full.m3u8" ) ) { | |
"Downloading index of all video resolutions..." | Write-Host | |
Invoke-WebRequest $PlaylistURL.AbsoluteUri -OutFile "./$($Temp)/Playlist_Full.m3u8" | |
} | |
$PlaylistFull = Get-Content "./$($Temp)/Playlist_Full.m3u8" | |
$PlaylistMaxFilename = 'none'; | |
"Finding largest resolution video..." | Write-Host | |
$LargestPlaylistBandwidth = 0 | |
$NextPlaylistBandwidthLarger = 0 | |
$VideoResolution = '' | |
$PlaylistFull | ForEach-Object { | |
if ( $_ -match '^#EXT-X-STREAM-INF:' ) { | |
$_PlaylistBandwidthRegex = [regex]::Matches( $_, 'BANDWIDTH=(\d+)' ) | |
$_ResolutionRegex = [regex]::Matches( $_, 'RESOLUTION=(\d+x\d+)' ) | |
if ( $_PlaylistBandwidthRegex.success ) { | |
$_PlaylistBandwidth = [System.Convert]::ToInt32( $_PlaylistBandwidthRegex.Captures.Groups[1].Value, 10 ) | |
if ( $_PlaylistBandwidth -gt $LargestPlaylistBandwidth ) { | |
$NextPlaylistBandwidthLarger = 1 | |
$VideoResolution = $_ResolutionRegex.Captures.Groups[1].Value | |
} | |
} | |
} elseif ( $_ -match '^[^#]' -and $NextPlaylistBandwidthLarger -eq 1 ) { | |
$PlaylistMaxFilename = $_ | |
$NextPlaylistBandwidthLarger = 0 | |
} | |
} | |
"Selected video resolution: $VideoResolution..." | Write-Host | |
$PlaylistMaxURL = $BaseURL, $PlaylistMaxFilename -join '' | |
if ( -not ( Test-Path "./$($Temp)/Playlist_Max.m3u8" ) ) { | |
Invoke-WebRequest $PlaylistMaxURL -OutFile "./$($Temp)/Playlist_Max.m3u8" | |
} | |
$PlaylistMax = Get-Content "./$($Temp)/Playlist_Max.m3u8" | |
$KeyFiles = @() | |
$PlaylistFiles = @() | |
$PlaylistMax | ForEach-Object { | |
if ( $_ -match '^#EXT-X-KEY:' ) { | |
$_KeyRegex = [regex]::Matches( $_, 'URI="(.+?)"', [System.Text.RegularExpressions.RegexOptions]::IgnoreCase ) | |
if ( $_KeyRegex.success ) { | |
$KeyFiles += $_KeyRegex.Captures.Groups[1].Value | |
} | |
} elseif ( $_ -match '^[^#]' ) { | |
$PlaylistFiles += $_ | |
} | |
} | |
$KeyFiles = $KeyFiles | Get-Unique | |
"Downloading $($KeyFiles.Length) encryption keys..." | Write-Host | |
$KeyIndex = 1 | |
$KeyFiles | ForEach-Object { | |
if ( -not ( Test-Path "./$($Temp)/$_" ) ) { | |
Invoke-WebRequest ( ( $BaseURL, $_ ) -join '' ) -OutFile "./$($Temp)/$($_)" | |
"Key $KeyIndex downloaded" | Write-Host | |
$KeyIndex += 1 | |
} | |
} | |
"Downloading $($PlaylistFiles.Length) video parts..." | Write-Host | |
$VideoPartIndex = 1 | |
$PlaylistFiles | ForEach-Object { | |
if ( -not ( Test-Path "./$($Temp)/$($_)" ) ) { | |
Invoke-WebRequest ( ( $BaseURL, $_ ) -join '' ) -OutFile "./$($Temp)/$($_)" | |
"Part $VideoPartIndex downloaded" | Write-Host | |
$VideoPartIndex += 1 | |
} | |
} | |
$SeasonNumber = ( [System.Convert]::ToInt32( $VideoConfig.show.sluggedVideo.season_number ) ).ToString( '00' ); | |
$EpisodeNumber = ( [System.Convert]::ToInt32( $VideoConfig.show.sluggedVideo.episode_number ) ).ToString( '00' ); | |
$OutputFilename = "$($VideoConfig.show.sluggedVideo.collection_title) - S$($SeasonNumber)E$($EpisodeNumber) - $($VideoConfig.show.sluggedVideo.title)" -replace '[<>:"/\\|?*]','_' | |
"Decrypting and combining video..." | Write-Host | |
if ( -not ( Test-Path "./$($OutputFilename).mp4" ) ) { | |
$FFMpegCommand = "ffmpeg -allowed_extensions ALL -i ./$($Temp)/Playlist_Max.m3u8 -c copy `"$($OutputFilename).mp4`"" | |
Invoke-Expression "& $($FFMpegCommand)" | |
} | |
#"Deleting temporary files" | Write-Host | |
#Remove-Item "./$($Temp)" -Recurse |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment