@ -1,10 +1,5 @@
from __future__ import unicode_literals
from __future__ import unicode_literals
import re
import json
import random
import string
from . common import InfoExtractor
from . common import InfoExtractor
from . . utils import find_xpath_attr
from . . utils import find_xpath_attr
@ -16,69 +11,64 @@ class HowStuffWorksIE(InfoExtractor):
' url ' : ' http://adventure.howstuffworks.com/5266-cool-jobs-iditarod-musher-video.htm ' ,
' url ' : ' http://adventure.howstuffworks.com/5266-cool-jobs-iditarod-musher-video.htm ' ,
' info_dict ' : {
' info_dict ' : {
' id ' : ' 450221 ' ,
' id ' : ' 450221 ' ,
' display_id ' : ' cool-jobs-iditarod-musher ' ,
' ext ' : ' flv ' ,
' ext ' : ' flv ' ,
' title ' : ' Cool Jobs - Iditarod Musher ' ,
' title ' : ' Cool Jobs - Iditarod Musher ' ,
' description ' : ' md5:82bb58438a88027b8186a1fccb365f90 ' ,
' description ' : ' Cold sleds, freezing temps and warm dog breath... an Iditarod musher\' s dream. Kasey-Dee Gardner jumps on a sled to find out what the big deal is. ' ,
' thumbnail ' : ' re:^https?://.*\ .jpg$ ' ,
' thumbnail ' : ' http://s.hswstatic.com/gif/videos/480x360/5266.jpg ' ,
} ,
} ,
' params ' : {
# md5 is not consistent
' skip_download ' : True
}
} ,
} ,
{
{
' url ' : ' http://adventure.howstuffworks.com/7199-survival-zone-food-and-water-in-the-savanna-video.htm ' ,
' url ' : ' http://adventure.howstuffworks.com/7199-survival-zone-food-and-water-in-the-savanna-video.htm ' ,
' info_dict ' : {
' info_dict ' : {
' id ' : ' 453464 ' ,
' id ' : ' 453464 ' ,
' display_id ' : ' survival-zone-food-and-water-in-the-savanna ' ,
' ext ' : ' mp4 ' ,
' ext ' : ' mp4 ' ,
' title ' : ' Survival Zone: Food and Water In the Savanna ' ,
' title ' : ' Survival Zone: Food and Water In the Savanna ' ,
' description ' : ' md5:7e1c89f6411434970c15fa094170c371 ' ,
' description ' : ' Learn how to find both food and water while trekking in the African savannah. In this video from the Discovery Channel. ' ,
' thumbnail ' : ' re:^https?://.*\ .jpg$ ' ,
' thumbnail ' : ' http://s.hswstatic.com/gif/videos/480x360/7199.jpg ' ,
} ,
} ,
' params ' : {
# md5 is not consistent
' skip_download ' : True
}
} ,
} ,
{
{
' url ' : ' http://entertainment.howstuffworks.com/arts/2706-sword-swallowing-1-by-dan-meyer-video.htm ' ,
' url ' : ' http://entertainment.howstuffworks.com/arts/2706-sword-swallowing-1-by-dan-meyer-video.htm ' ,
' info_dict ' : {
' info_dict ' : {
' id ' : ' 440011 ' ,
' id ' : ' 440011 ' ,
' display_id ' : ' sword-swallowing-1-by-dan-meyer ' ,
' ext ' : ' flv ' ,
' ext ' : ' flv ' ,
' title ' : ' Sword Swallowing #1 by Dan Meyer ' ,
' title ' : ' Sword Swallowing #1 by Dan Meyer ' ,
' description ' : ' md5:b2409e88172913e2e7d3d1159b0ef735 ' ,
' description ' : ' Video footage (1 of 3) used by permission of the owner Dan Meyer through Sword Swallowers Association International <www.swordswallow.org> ' ,
' thumbnail ' : ' re:^https?://.*\ .jpg$ ' ,
' thumbnail ' : ' http://s.hswstatic.com/gif/videos/480x360/118306353233.jpg ' ,
} ,
} ,
' params ' : {
# md5 is not consistent
' skip_download ' : True
}
} ,
} ,
]
]
def _real_extract ( self , url ) :
def _real_extract ( self , url ) :
mobj = re . match ( self . _VALID_URL , url )
display_id = self . _match_id ( url )
display_id = mobj . group ( ' id ' )
webpage = self . _download_webpage ( url , display_id )
webpage = self . _download_webpage ( url , display_id )
clip_info = self . _search_regex ( ' (?s)var clip = { (.*?)}; ' , webpage , ' clip info ' )
content_id = self . _search_regex ( r ' var siteSectionId= " ( \ d+) " ; ' , webpage , ' content id ' )
def extract_clip_info ( key , clip_info , name = None , * * kargs ) :
if name is None :
name = key
return self . _html_search_regex (
r " \ s* %s \ s*: ' ?([^ ' \ n]*[^ ' \ n,]) " % key , clip_info , name , * * kargs )
mp4 = self . _search_regex (
video_id = extract_clip_info ( ' content_id ' , clip_info , ' video id ' )
r ''' (?xs)var \ s+clip \ s*= \ s* { \ s*
formats = [ ]
. + ? \s *
m3u8_url = extract_clip_info ( ' m3u8 ' , clip_info , ' m3u8 url ' , default = None )
content_id \s * : \s * % s \s * , \s *
if m3u8_url is not None :
. + ? \s *
formats + = self . _extract_m3u8_formats ( m3u8_url , video_id , ' mp4 ' )
mp4 \s * : \s * \[ ( . * ? ) , ? \] \s *
mp4 = self . _parse_json (
} ; \s *
extract_clip_info (
videoData \. push \( clip \) ; ''' % c ontent_id,
' mp4 ' , clip_info , ' formats ' ) . replace ( ' },] ' , ' }] ' ) , video_id )
webpage , ' mp4 ' , fatal = False , default = None )
for video in mp4 :
formats . append ( {
' url ' : video [ ' src ' ] ,
' format_id ' : video [ ' bitrate ' ] ,
' vbr ' : int ( video [ ' bitrate ' ] . rstrip ( ' k ' ) ) ,
} )
if not formats :
smil = self . _download_xml (
smil = self . _download_xml (
' http://services.media.howstuffworks.com/videos/ %s /smil-service.smil ' % content_id ,
' http://services.media.howstuffworks.com/videos/ %s /smil-service.smil ' % video _id,
content_id , ' Downloading video SMIL ' )
video _id, ' Downloading video SMIL ' )
http_base = find_xpath_attr (
http_base = find_xpath_attr (
smil ,
smil ,
@ -86,27 +76,10 @@ class HowStuffWorksIE(InfoExtractor):
' name ' ,
' name ' ,
' httpBase ' ) . get ( ' content ' )
' httpBase ' ) . get ( ' content ' )
def random_string ( str_len = 0 ) :
URL_SUFFIX = ' ?v=2.11.3&fp=LNX 11,2,202,356&r=A&g=A '
return ' ' . join ( [ random . choice ( string . ascii_uppercase ) for _ in range ( str_len ) ] )
URL_SUFFIX = ' ?v=2.11.3&fp=LNX 11,2,202,356&r= %s &g= %s ' % ( random_string ( 5 ) , random_string ( 12 ) )
formats = [ ]
if mp4 :
for video in json . loads ( ' [ %s ] ' % mp4 ) :
bitrate = video [ ' bitrate ' ]
fmt = {
' url ' : video [ ' src ' ] . replace ( ' http://pmd.video.howstuffworks.com ' , http_base ) + URL_SUFFIX ,
' format_id ' : bitrate ,
}
m = re . search ( r ' (?P<vbr> \ d+)[Kk] ' , bitrate )
if m :
fmt [ ' vbr ' ] = int ( m . group ( ' vbr ' ) )
formats . append ( fmt )
else :
for video in smil . findall (
for video in smil . findall (
' ./ / {0} body/ {0} switch/ {0} video ' . format ( ' { http://www.w3.org/2001/SMIL20/Language} ' ) ) :
' ./ {0} body/ {0} switch/ {0} video ' . format ( ' { http://www.w3.org/2001/SMIL20/Language} ' ) ) :
vbr = int ( video . attrib [ ' system-bitrate ' ] ) / 1000
vbr = int ( video . attrib [ ' system-bitrate ' ] ) / 1000
formats . append ( {
formats . append ( {
' url ' : ' %s / %s %s ' % ( http_base , video . attrib [ ' src ' ] , URL_SUFFIX ) ,
' url ' : ' %s / %s %s ' % ( http_base , video . attrib [ ' src ' ] , URL_SUFFIX ) ,
@ -116,19 +89,12 @@ class HowStuffWorksIE(InfoExtractor):
self . _sort_formats ( formats )
self . _sort_formats ( formats )
title = self . _og_search_title ( webpage )
TITLE_SUFFIX = ' : HowStuffWorks '
if title . endswith ( TITLE_SUFFIX ) :
title = title [ : - len ( TITLE_SUFFIX ) ]
description = self . _og_search_description ( webpage )
thumbnail = self . _og_search_thumbnail ( webpage )
return {
return {
' id ' : content _id,
' id ' : video_id ,
' display_id ' : display_id ,
' display_id ' : display_id ,
' title ' : title ,
' title ' : extract_clip_info ( ' clip_title ' , clip_info , ' title ' ) ,
' description ' : description ,
' description ' : extract_clip_info ( ' caption ' , clip_info , ' description ' , fatal = False ) ,
' thumbnail ' : thumbnail ,
' thumbnail ' : extract_clip_info ( ' video_still_url ' , clip_info , ' thumbnail ' ) ,
' duration ' : extract_clip_info ( ' duration ' , clip_info ) ,
' formats ' : formats ,
' formats ' : formats ,
}
}