Skip to content

Instantly share code, notes, and snippets.

@LachlanArthur
Last active August 2, 2017 13:06
Show Gist options
  • Save LachlanArthur/ba6f866d3e723dbf3400a1b6e6189dad to your computer and use it in GitHub Desktop.
Save LachlanArthur/ba6f866d3e723dbf3400a1b6e6189dad to your computer and use it in GitHub Desktop.
Adult Swim Downloader (Requires FFMpeg)
$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