2014-05-19 13:25:58 +02:00
# coding: utf-8
from __future__ import unicode_literals
import re
2016-08-28 17:43:15 +02:00
from . turner import TurnerBaseIE
2016-08-29 17:40:35 +02:00
from . . utils import (
int_or_none ,
2017-05-08 16:01:10 +02:00
strip_or_none ,
2016-08-29 17:40:35 +02:00
)
2014-05-19 13:25:58 +02:00
2014-11-23 20:41:03 +01:00
2016-08-28 17:43:15 +02:00
class AdultSwimIE ( TurnerBaseIE ) :
2017-05-08 16:01:10 +02:00
_VALID_URL = r ' https?://(?:www \ .)?adultswim \ .com/videos/(?P<show_path>[^/?#]+)(?:/(?P<episode_path>[^/?#]+))? '
2014-12-06 06:49:41 +01:00
_TESTS = [ {
' url ' : ' http://adultswim.com/videos/rick-and-morty/pilot ' ,
' info_dict ' : {
2015-02-18 00:49:10 +01:00
' id ' : ' rQxZvXQ4ROaSOqq-or2Mow ' ,
2017-05-08 16:01:10 +02:00
' ext ' : ' mp4 ' ,
2014-12-06 06:49:41 +01:00
' title ' : ' Rick and Morty - Pilot ' ,
2017-05-08 16:01:10 +02:00
' description ' : ' Rick moves in with his daughter \' s family and establishes himself as a bad influence on his grandson, Morty. ' ,
' timestamp ' : 1493267400 ,
' upload_date ' : ' 20170427 ' ,
2015-10-10 13:28:12 +02:00
} ,
2017-05-08 16:01:10 +02:00
' params ' : {
# m3u8 download
' skip_download ' : True ,
2014-12-06 06:49:41 +01:00
} ,
2017-05-08 16:01:10 +02:00
' expected_warnings ' : [ ' Unable to download f4m manifest ' ] ,
2015-03-08 20:32:42 +01:00
} , {
' url ' : ' http://www.adultswim.com/videos/tim-and-eric-awesome-show-great-job/dr-steve-brule-for-your-wine/ ' ,
' info_dict ' : {
' id ' : ' sY3cMUR_TbuE4YmdjzbIcQ ' ,
2017-05-08 16:01:10 +02:00
' ext ' : ' mp4 ' ,
2015-03-08 20:32:42 +01:00
' title ' : ' Tim and Eric Awesome Show Great Job! - Dr. Steve Brule, For Your Wine ' ,
2017-05-08 16:01:10 +02:00
' description ' : ' Dr. Brule reports live from Wine Country with a special report on wines. \n Watch Tim and Eric Awesome Show Great Job! episode #20, " Embarrassed " on Adult Swim. ' ,
' upload_date ' : ' 20080124 ' ,
' timestamp ' : 1201150800 ,
2015-03-08 20:32:42 +01:00
} ,
2015-12-21 17:07:19 +01:00
' params ' : {
# m3u8 download
' skip_download ' : True ,
2017-05-08 16:01:10 +02:00
} ,
2016-08-05 19:00:05 +02:00
} , {
' url ' : ' http://www.adultswim.com/videos/decker/inside-decker-a-new-hero/ ' ,
' info_dict ' : {
' id ' : ' I0LQFQkaSUaFp8PnAWHhoQ ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Decker - Inside Decker: A New Hero ' ,
2017-05-08 16:01:10 +02:00
' description ' : ' The guys recap the conclusion of the season. They announce a new hero, take a peek into the Victorville Film Archive and welcome back the talented James Dean. ' ,
' timestamp ' : 1469480460 ,
' upload_date ' : ' 20160725 ' ,
2016-08-05 19:00:05 +02:00
} ,
' params ' : {
# m3u8 download
' skip_download ' : True ,
2016-08-28 17:43:15 +02:00
} ,
' expected_warnings ' : [ ' Unable to download f4m manifest ' ] ,
2016-10-26 20:16:48 +02:00
} , {
2017-05-08 16:01:10 +02:00
' url ' : ' http://www.adultswim.com/videos/attack-on-titan ' ,
' info_dict ' : {
' id ' : ' b7A69dzfRzuaXIECdxW8XQ ' ,
' title ' : ' Attack on Titan ' ,
' description ' : ' md5:6c8e003ea0777b47013e894767f5e114 ' ,
} ,
' playlist_mincount ' : 12 ,
} , {
' url ' : ' http://www.adultswim.com/videos/streams/williams-stream ' ,
2016-10-26 20:16:48 +02:00
' info_dict ' : {
2017-05-08 16:01:10 +02:00
' id ' : ' d8DEBj7QRfetLsRgFnGEyg ' ,
' ext ' : ' mp4 ' ,
' title ' : r ' re:^Williams Stream \ d {4} - \ d {2} - \ d {2} \ d {2} : \ d {2} $ ' ,
' description ' : ' original programming ' ,
2016-10-26 20:16:48 +02:00
} ,
' params ' : {
# m3u8 download
' skip_download ' : True ,
} ,
2014-12-06 06:49:41 +01:00
} ]
2014-05-19 13:25:58 +02:00
def _real_extract ( self , url ) :
2017-05-08 16:01:10 +02:00
show_path , episode_path = re . match ( self . _VALID_URL , url ) . groups ( )
display_id = episode_path or show_path
webpage = self . _download_webpage ( url , display_id )
initial_data = self . _parse_json ( self . _search_regex (
r ' AS_INITIAL_DATA(?:__)? \ s*= \ s*( { .+?}); ' ,
webpage , ' initial data ' ) , display_id )
is_stream = show_path == ' streams '
if is_stream :
if not episode_path :
episode_path = ' live-stream '
video_data = next ( stream for stream_path , stream in initial_data [ ' streams ' ] . items ( ) if stream_path == episode_path )
video_id = video_data . get ( ' stream ' )
if not video_id :
entries = [ ]
for episode in video_data . get ( ' archiveEpisodes ' , [ ] ) :
episode_url = episode . get ( ' url ' )
if not episode_url :
continue
entries . append ( self . url_result (
episode_url , ' AdultSwim ' , episode . get ( ' id ' ) ) )
return self . playlist_result (
entries , video_data . get ( ' id ' ) , video_data . get ( ' title ' ) ,
strip_or_none ( video_data . get ( ' description ' ) ) )
2014-12-06 06:49:41 +01:00
else :
2017-05-08 16:01:10 +02:00
show_data = initial_data [ ' show ' ]
if not episode_path :
entries = [ ]
for video in show_data . get ( ' videos ' , [ ] ) :
slug = video . get ( ' slug ' )
if not slug :
continue
entries . append ( self . url_result (
' http://adultswim.com/videos/ %s / %s ' % ( show_path , slug ) ,
' AdultSwim ' , video . get ( ' id ' ) ) )
return self . playlist_result (
entries , show_data . get ( ' id ' ) , show_data . get ( ' title ' ) ,
strip_or_none ( show_data . get ( ' metadata ' , { } ) . get ( ' description ' ) ) )
video_data = show_data [ ' sluggedVideo ' ]
video_id = video_data [ ' id ' ]
info = self . _extract_cvp_info (
2017-05-10 09:50:30 +02:00
' http://www.adultswim.com/videos/api/v0/assets?platform=desktop&id= ' + video_id ,
2017-05-08 16:01:10 +02:00
video_id , {
' secure ' : {
' media_src ' : ' http://androidhls-secure.cdn.turner.com/adultswim/big ' ,
' tokenizer_src ' : ' http://www.adultswim.com/astv/mvpd/processors/services/token_ipadAdobe.do ' ,
} ,
} , {
' url ' : url ,
' site_name ' : ' AdultSwim ' ,
' auth_required ' : video_data . get ( ' auth ' ) ,
} )
2014-05-19 13:25:58 +02:00
2017-05-08 16:01:10 +02:00
info . update ( {
' id ' : video_id ,
' display_id ' : display_id ,
' description ' : info . get ( ' description ' ) or strip_or_none ( video_data . get ( ' description ' ) ) ,
} )
if not is_stream :
info . update ( {
' duration ' : info . get ( ' duration ' ) or int_or_none ( video_data . get ( ' duration ' ) ) ,
' timestamp ' : info . get ( ' timestamp ' ) or int_or_none ( video_data . get ( ' launch_date ' ) ) ,
' season_number ' : info . get ( ' season_number ' ) or int_or_none ( video_data . get ( ' season_number ' ) ) ,
' episode ' : info [ ' title ' ] ,
' episode_number ' : info . get ( ' episode_number ' ) or int_or_none ( video_data . get ( ' episode_number ' ) ) ,
2014-05-19 13:25:58 +02:00
} )
2017-05-08 16:01:10 +02:00
info [ ' series ' ] = video_data . get ( ' collection_title ' ) or info . get ( ' series ' )
if info [ ' series ' ] and info [ ' series ' ] != info [ ' title ' ] :
info [ ' title ' ] = ' %s - %s ' % ( info [ ' series ' ] , info [ ' title ' ] )
return info