]>
Raphaël G. Git Repositories - youtubedl/blob - youtube_dl/extractor/soundcloud.py
e22ff9c387ab0e01c1e6fcb1da793af877f37a5c
6 from . common
import InfoExtractor
17 class SoundcloudIE ( InfoExtractor
):
18 """Information extractor for soundcloud.com
19 To access the media, the uid of the song and a stream token
20 must be extracted from the page source and the script must make
21 a request to media.soundcloud.com/crossdomain.xml. Then
22 the media can be grabbed by requesting from an url composed
23 of the stream token and uid
26 _VALID_URL
= r
'''^(?:https?://)?
27 (?:(?:(?:www\.|m\.)?soundcloud\.com/
28 (?P<uploader>[\w\d-]+)/
29 (?!sets/)(?P<title>[\w\d-]+)/?
30 (?P<token>[^?]+?)?(?:[?].*)?$)
31 |(?:api\.soundcloud\.com/tracks/(?P<track_id>\d+))
32 |(?P<widget>w\.soundcloud\.com/player/?.*?url=.*)
35 IE_NAME
= u
'soundcloud'
38 u
'url' : u
'http://soundcloud.com/ethmusic/lostin-powers-she-so-heavy' ,
39 u
'file' : u
'62986583.mp3' ,
40 u
'md5' : u
'ebef0a451b909710ed1d7787dddbf0d7' ,
42 u
"upload_date" : u
"20121011" ,
43 u
"description" : u
"No Downloads untill we record the finished version this weekend, i was too pumped n i had to post it , earl is prolly gonna b hella p.o'd" ,
44 u
"uploader" : u
"E.T. ExTerrestrial Music" ,
45 u
"title" : u
"Lostin Powers - She so Heavy (SneakPreview) Adrian Ackers Blueprint 1"
50 u
'url' : u
'https://soundcloud.com/the-concept-band/goldrushed-mastered?in=the-concept-band/sets/the-royal-concept-ep' ,
54 u
'title' : u
'Goldrushed' ,
55 u
'uploader' : u
'The Royal Concept' ,
56 u
'upload_date' : u
'20120521' ,
60 u
'skip_download' : True ,
65 u
'url' : u
'https://soundcloud.com/jaimemf/youtube-dl-test-video-a-y-baw/s-8Pjrp' ,
66 u
'md5' : u
'aa0dd32bfea9b0c5ef4f02aacd080604' ,
70 u
'title' : u
'Youtube - Dl Test Video \'\' Ä↭' ,
71 u
'uploader' : u
'jaimeMF' ,
72 u
'description' : u
'test chars: \"\' / \\ ä↭' ,
73 u
'upload_date' : u
'20131209' ,
78 u
'url' : u
'https://soundcloud.com/simgretina/just-your-problem-baby-1' ,
79 u
'md5' : u
'56a8b69568acaa967b4c49f9d1d52d19' ,
83 u
'title' : u
'Just Your Problem Baby (Acapella)' ,
84 u
'description' : u
'Vocals' ,
85 u
'uploader' : u
'Sim Gretina' ,
86 u
'upload_date' : u
'20130815' ,
91 _CLIENT_ID
= 'b45b1aa10f1ac2941910a7f0d10f8e28'
92 _IPHONE_CLIENT_ID
= '376f225bf427445fc4bfb6b99b72e0bf'
95 def suitable ( cls
, url
):
96 return re
. match ( cls
._ VALID
_U RL
, url
, flags
= re
. VERBOSE
) is not None
98 def report_resolve ( self
, video_id
):
99 """Report information extraction."""
100 self
. to_screen ( u
' %s : Resolving id' % video_id
)
103 def _resolv_url ( cls
, url
):
104 return 'http://api.soundcloud.com/resolve.json?url=' + url
+ '&client_id=' + cls
._ CLIENT
_ ID
106 def _extract_info_dict ( self
, info
, full_title
= None , quiet
= False , secret_token
= None ):
107 track_id
= compat_str ( info
[ 'id' ])
108 name
= full_title
or track_id
110 self
. report_extraction ( name
)
112 thumbnail
= info
[ 'artwork_url' ]
113 if thumbnail
is not None :
114 thumbnail
= thumbnail
. replace ( '-large' , '-t500x500' )
118 'uploader' : info
[ 'user' ][ 'username' ],
119 'upload_date' : unified_strdate ( info
[ 'created_at' ]),
120 'title' : info
[ 'title' ],
121 'description' : info
[ 'description' ],
122 'thumbnail' : thumbnail
,
124 if info
. get ( 'downloadable' , False ):
125 # We can build a direct link to the song
127 u
'https://api.soundcloud.com/tracks/ {0} /download?client_id= {1} ' . format (
128 track_id
, self
._ CLIENT
_ ID
))
129 result
[ 'formats' ] = [{
130 'format_id' : 'download' ,
131 'ext' : info
. get ( 'original_format' , u
'mp3' ),
136 # We have to retrieve the url
137 streams_url
= ( 'http://api.soundcloud.com/i1/tracks/ {0} /streams?'
138 'client_id= {1} &secret_token= {2} ' . format ( track_id
, self
._ IPHONE
_ CLIENT
_ ID
, secret_token
))
139 stream_json
= self
._ download
_ webpage
(
141 track_id
, u
'Downloading track url' )
144 format_dict
= json
. loads ( stream_json
)
145 for key
, stream_url
in format_dict
. items ():
146 if key
. startswith ( u
'http' ):
153 elif key
. startswith ( u
'rtmp' ):
154 # The url doesn't have an rtmp app, we have to extract the playpath
155 url
, path
= stream_url
. split ( 'mp3:' , 1 )
159 'play_path' : 'mp3:' + path
,
165 # We fallback to the stream_url in the original info, this
166 # cannot be always used, sometimes it can give an HTTP 404 error
168 'format_id' : u
'fallback' ,
169 'url' : info
[ 'stream_url' ] + '?client_id=' + self
._ CLIENT
_ ID
,
175 if f
[ 'format_id' ]. startswith ( 'http' ):
177 if f
[ 'format_id' ]. startswith ( 'rtmp' ):
181 formats
. sort ( key
= format_pref
)
182 result
[ 'formats' ] = formats
186 def _real_extract ( self
, url
):
187 mobj
= re
. match ( self
._ VALID
_U RL
, url
, flags
= re
. VERBOSE
)
189 raise ExtractorError ( u
'Invalid URL: %s ' % url
)
191 track_id
= mobj
. group ( 'track_id' )
193 if track_id
is not None :
194 info_json_url
= 'http://api.soundcloud.com/tracks/' + track_id
+ '.json?client_id=' + self
._ CLIENT
_ ID
195 full_title
= track_id
196 elif mobj
. group ( 'widget' ):
197 query
= compat_urlparse
. parse_qs ( compat_urlparse
. urlparse ( url
). query
)
198 return self
. url_result ( query
[ 'url' ][ 0 ], ie
= 'Soundcloud' )
200 # extract uploader (which is in the url)
201 uploader
= mobj
. group ( 'uploader' )
202 # extract simple title (uploader + slug of song title)
203 slug_title
= mobj
. group ( 'title' )
204 token
= mobj
. group ( 'token' )
205 full_title
= resolve_title
= ' %s / %s ' % ( uploader
, slug_title
)
207 resolve_title
+= '/ %s ' % token
209 self
. report_resolve ( full_title
)
211 url
= 'http://soundcloud.com/ %s ' % resolve_title
212 info_json_url
= self
._ resolv
_u rl
( url
)
213 info_json
= self
._ download
_ webpage
( info_json_url
, full_title
, u
'Downloading info JSON' )
215 info
= json
. loads ( info_json
)
216 return self
._ extract
_ info
_ dict
( info
, full_title
, secret_token
= token
)
218 class SoundcloudSetIE ( SoundcloudIE
):
219 _VALID_URL
= r
'^(?:https?://)?(?:www\.)?soundcloud\.com/([\w\d-]+)/sets/([\w\d-]+)(?:[?].*)?$'
220 IE_NAME
= u
'soundcloud:set'
221 # it's in tests/test_playlists.py
224 def _real_extract ( self
, url
):
225 mobj
= re
. match ( self
._ VALID
_U RL
, url
)
227 raise ExtractorError ( u
'Invalid URL: %s ' % url
)
229 # extract uploader (which is in the url)
230 uploader
= mobj
. group ( 1 )
231 # extract simple title (uploader + slug of song title)
232 slug_title
= mobj
. group ( 2 )
233 full_title
= ' %s /sets/ %s ' % ( uploader
, slug_title
)
235 self
. report_resolve ( full_title
)
237 url
= 'http://soundcloud.com/ %s /sets/ %s ' % ( uploader
, slug_title
)
238 resolv_url
= self
._ resolv
_u rl
( url
)
239 info_json
= self
._ download
_ webpage
( resolv_url
, full_title
)
241 info
= json
. loads ( info_json
)
243 for err
in info
[ 'errors' ]:
244 self
._ downloader
. report_error ( u
'unable to download video webpage: %s ' % compat_str ( err
[ 'error_message' ]))
247 self
. report_extraction ( full_title
)
248 return { '_type' : 'playlist' ,
249 'entries' : [ self
._ extract
_ info
_ dict
( track
) for track
in info
[ 'tracks' ]],
251 'title' : info
[ 'title' ],
255 class SoundcloudUserIE ( SoundcloudIE
):
256 _VALID_URL
= r
'https?://(www\.)?soundcloud\.com/(?P<user>[^/]+)(/?(tracks/)?)?(\?.*)?$'
257 IE_NAME
= u
'soundcloud:user'
259 # it's in tests/test_playlists.py
262 def _real_extract ( self
, url
):
263 mobj
= re
. match ( self
._ VALID
_U RL
, url
)
264 uploader
= mobj
. group ( 'user' )
266 url
= 'http://soundcloud.com/ %s /' % uploader
267 resolv_url
= self
._ resolv
_u rl
( url
)
268 user_json
= self
._ download
_ webpage
( resolv_url
, uploader
,
269 u
'Downloading user info' )
270 user
= json
. loads ( user_json
)
273 for i
in itertools
. count ():
274 data
= compat_urllib_parse
. urlencode ({ 'offset' : i
* 50 ,
275 'client_id' : self
._ CLIENT
_ ID
,
277 tracks_url
= 'http://api.soundcloud.com/users/ %s /tracks.json?' % user
[ 'id' ] + data
278 response
= self
._ download
_ webpage
( tracks_url
, uploader
,
279 u
'Downloading tracks page %s ' % ( i
+ 1 ))
280 new_tracks
= json
. loads ( response
)
281 tracks
. extend ( self
._ extract
_ info
_ dict
( track
, quiet
= True ) for track
in new_tracks
)
282 if len ( new_tracks
) < 50 :
287 'id' : compat_str ( user
[ 'id' ]),
288 'title' : user
[ 'username' ],