@ -4,58 +4,110 @@ from __future__ import unicode_literals
import re
import re
from . turner import TurnerBaseIE
from . turner import TurnerBaseIE
from . . utils import extract_attributes
from . . utils import (
float_or_none ,
int_or_none ,
strip_or_none ,
)
class TBSIE ( TurnerBaseIE ) :
class TBSIE ( TurnerBaseIE ) :
# https://github.com/rg3/youtube-dl/issues/13658
_VALID_URL = r ' https?://(?:www \ .)?(?P<site>tbs|tntdrama) \ .com/(?:movies|shows/[^/]+/(?:clips|season- \ d+/episode- \ d+))/(?P<id>[^/?#]+) '
_WORKING = False
_VALID_URL = r ' https?://(?:www \ .)?(?P<site>tbs|tntdrama) \ .com/videos/(?:[^/]+/)+(?P<id>[^/?#]+) \ .html '
_TESTS = [ {
_TESTS = [ {
' url ' : ' http://www.tbs.com/videos/people-of-earth/season-1/extras/2007318/theatrical-trailer.html ' ,
' url ' : ' http://www.tntdrama.com/shows/the-alienist/clips/monster ' ,
' md5 ' : ' 9e61d680e2285066ade7199e6408b2ee ' ,
' info_dict ' : {
' info_dict ' : {
' id ' : ' 2007318 ' ,
' id ' : ' 8d384cde33b89f3a43ce5329de42903ed5099887 ' ,
' ext ' : ' mp4 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Theatrical Trailer ' ,
' title ' : ' Monster ' ,
' description ' : ' Catch the latest comedy from TBS, People of Earth, premiering Halloween night--Monday, October 31, at 9/8c. ' ,
' description ' : ' Get a first look at the theatrical trailer for TNT’ s highly anticipated new psychological thriller The Alienist, which premieres January 22 on TNT. ' ,
' timestamp ' : 1508175329 ,
' upload_date ' : ' 20171016 ' ,
} ,
} ,
' skip ' : ' TBS videos are deleted after a while ' ,
' params ' : {
# m3u8 download
' skip_download ' : True ,
}
} , {
} , {
' url ' : ' http://www.tntdrama.com/videos/good-behavior/season-1/extras/1538823/you-better-run.html ' ,
' url ' : ' http://www.tbs.com/shows/search-party/season-1/episode-1/explicit-the-mysterious-disappearance-of-the-girl-no-one-knew ' ,
' md5 ' : ' ce53c6ead5e9f3280b4ad2031a6fab56 ' ,
' only_matching ' : True ,
' info_dict ' : {
} , {
' id ' : ' 1538823 ' ,
' url ' : ' http://www.tntdrama.com/movies/star-wars-a-new-hope ' ,
' ext ' : ' mp4 ' ,
' only_matching ' : True ,
' title ' : ' You Better Run ' ,
' description ' : ' Letty Raines must figure out what she \' s running toward while running away from her past. Good Behavior premieres November 15 at 9/8c. ' ,
} ,
' skip ' : ' TBS videos are deleted after a while ' ,
} ]
} ]
def _real_extract ( self , url ) :
def _real_extract ( self , url ) :
domain , display_id = re . match ( self . _VALID_URL , url ) . groups ( )
domain , display_id = re . match ( self . _VALID_URL , url ) . groups ( )
site = domain [ : 3 ]
site = domain [ : 3 ]
webpage = self . _download_webpage ( url , display_id )
webpage = self . _download_webpage ( url , display_id )
video_params = extract_attributes ( self . _search_regex ( r ' (<[^>]+id= " page-video " [^>]*>) ' , webpage , ' video params ' ) )
video_data = self . _parse_json ( self . _search_regex (
query = None
r ' <script[^>]+?data-drupal-selector= " drupal-settings-json " [^>]*?>( { .+?})</script> ' ,
clip_id = video_params . get ( ' clipid ' )
webpage , ' drupal setting ' ) , display_id ) [ ' turner_playlist ' ] [ 0 ]
if clip_id :
query = ' id= ' + clip_id
media_id = video_data [ ' mediaID ' ]
else :
title = video_data [ ' title ' ]
query = ' titleId= ' + video_params [ ' titleid ' ]
return self . _extract_cvp_info (
streams_data = self . _download_json (
' http://www. %s .com/service/cvpXml? %s ' % ( domain , query ) , display_id , {
' http://medium.ngtv.io/media/ %s /tv ' % media_id ,
' default ' : {
media_id ) [ ' media ' ] [ ' tv ' ]
' media_src ' : ' http://ht.cdn.turner.com/ %s /big ' % site ,
duration = None
} ,
chapters = [ ]
' secure ' : {
formats = [ ]
' media_src ' : ' http://androidhls-secure.cdn.turner.com/ %s /big ' % site ,
for supported_type in ( ' unprotected ' , ' bulkaes ' ) :
' tokenizer_src ' : ' http://www. %s .com/video/processors/services/token_ipadAdobe.do ' % domain ,
stream_data = streams_data . get ( supported_type , { } )
} ,
m3u8_url = stream_data . get ( ' secureUrl ' ) or stream_data . get ( ' url ' )
} , {
if not m3u8_url :
continue
if stream_data . get ( ' playlistProtection ' ) == ' spe ' :
m3u8_url = self . _add_akamai_spe_token (
' http://www. %s .com/service/token_spe ' % site ,
m3u8_url , media_id , {
' url ' : url ,
' url ' : url ,
' site_name ' : site . upper ( ) ,
' site_name ' : site . upper ( ) ,
' auth_required ' : video_params . get ( ' isAuthRequired ' ) != ' false ' ,
' auth_required ' : video_data . get ( ' authRequired ' ) == ' 1 ' ,
} )
formats . extend ( self . _extract_m3u8_formats (
m3u8_url , media_id , ' mp4 ' , m3u8_id = ' hls ' , fatal = False ) )
duration = float_or_none ( stream_data . get ( ' totalRuntime ' ) or video_data . get ( ' duration ' ) )
if not chapters :
for chapter in stream_data . get ( ' contentSegments ' , [ ] ) :
start_time = float_or_none ( chapter . get ( ' start ' ) )
duration = float_or_none ( chapter . get ( ' duration ' ) )
if start_time is None or duration is None :
continue
chapters . append ( {
' start_time ' : start_time ,
' end_time ' : start_time + duration ,
} )
self . _sort_formats ( formats )
thumbnails = [ ]
for image_id , image in video_data . get ( ' images ' , { } ) . items ( ) :
image_url = image . get ( ' url ' )
if not image_url or image . get ( ' type ' ) != ' video ' :
continue
i = {
' id ' : image_id ,
' url ' : image_url ,
}
mobj = re . search ( r ' ( \ d+)x( \ d+) ' , image_url )
if mobj :
i . update ( {
' width ' : int ( mobj . group ( 1 ) ) ,
' height ' : int ( mobj . group ( 2 ) ) ,
} )
} )
thumbnails . append ( i )
return {
' id ' : media_id ,
' title ' : title ,
' description ' : strip_or_none ( video_data . get ( ' descriptionNoTags ' ) or video_data . get ( ' shortDescriptionNoTags ' ) ) ,
' duration ' : duration ,
' timestamp ' : int_or_none ( video_data . get ( ' created ' ) ) ,
' season_number ' : int_or_none ( video_data . get ( ' season ' ) ) ,
' episode_number ' : int_or_none ( video_data . get ( ' episode ' ) ) ,
' cahpters ' : chapters ,
' thumbnails ' : thumbnails ,
' formats ' : formats ,
}