]>
git.frykholm.com Git - svtplaydump.git/blob - svtplaydump.py
0718c308e74c87e0125d84230b98a5b17094a074
2 # -*- coding: utf-8 -*-
4 # (C) Copyright 2010 Mikael Frykholm <mikael@frykholm.com>
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>
20 # 0.3 added apple streaming playlist parsing and decryption
21 # 0.2 added python 2.4 urlparse compatibility
24 from BeautifulSoup
import BeautifulSoup
25 from subprocess
import *
28 from Crypto
.Cipher
import AES
36 import urllib2
.urlparse
as urlparse
45 videoid
= re
.findall("/video/(.*)[/]*",argv
[1])[0]
46 soup
= BeautifulSoup(urllib2
.urlopen("http://www.svtplay.se/video/%s/?type=embed"%videoid
).read())
47 flashvars
= json
.loads(soup
.find("param", {"name":"flashvars",'value':True})['value'][5:])
49 page
= urllib2
.urlopen(argv
[1]).read()
50 videoid
= re
.findall("svt_article_id=(.*)[&]*",page
)[0]
51 flashvars
= json
.loads(urllib2
.urlopen("http://www.svt.se/wd?widgetId=248134§ionId=1024&articleId=%s&position=0&format=json&type=embed&contextSectionId=1024"%videoid
).read())
53 title
= flashvars
['statistics']['title']
56 if 'dynamicStreams' in flashvars
:
57 url
= flashvars
['dynamicStreams'][0].split('url:')[1].split('.mp4,')[0] +'.mp4'
58 filename
= title
+".mp4"
59 print Popen(["rtmpdump",u
"-o"+filename
,"-r", url
], stdout
=PIPE
).communicate()[0]
60 if 'pathflv' in flashvars
:
61 rtmp
= flashvars
['pathflv'][0]
62 filename
= title
+".flv"
63 print Popen(["mplayer","-dumpstream","-dumpfile",filename
, rtmp
], stdout
=PIPE
).communicate()[0]
64 if 'video' in flashvars
:
65 for reference
in flashvars
['video']['videoReferences']:
66 if reference
['url'].endswith("m3u8"):
68 download_from_playlist(url
, title
+'.ts')
70 print "Could not find any streams"
73 def download_from_playlist(url
, title
):
74 playlist
= parse_playlist(urllib2
.urlopen(url
).read())
75 videourl
= sorted(playlist
, key
=lambda k
: int(k
['BANDWIDTH']))[-1]['url']
76 segments
, metadata
= parse_segment_playlist(urllib2
.urlopen(videourl
).read())
77 if "EXT-X-KEY" in metadata
:
78 key
= urllib2
.urlopen(metadata
["EXT-X-KEY"]['URI'].strip('"')).read()
82 with
open("%s"%title
,"w") as ofile
:
85 print "Downloading: %s"%(url)
86 ufile
= urllib2
.urlopen(url
)
88 iv
=struct
.pack("IIII",segment
,0,0,0)
89 decryptor
= AES
.new(key
, AES
.MODE_CBC
, iv
)
91 buf
= ufile
.read(1024)
94 buf
= decryptor
.decrypt(buf
)
101 def parse_playlist(playlist
):
102 assert playlist
.startswith("#EXTM3U")
103 playlist
= playlist
.splitlines()[1:]
105 for (metadata_string
,url
) in zip(playlist
[0::2], playlist
[1::2]):
107 assert 'EXT-X-STREAM-INF' in metadata_string
.split(':')[0]
108 for item
in metadata_string
.split(':')[1].split(','):
110 md
.update([item
.split('='),])
115 def parse_segment_playlist(playlist
):
116 assert playlist
.startswith("#EXTM3U")
117 PATTERN
= re
.compile(r
'''((?:[^,"']|"[^"]*"|'[^']*')+)''')
121 for row
in playlist
.splitlines():
128 if "EXT-X-KEY" in row
:
129 row
= row
.split(':',1)[1] #skip first part
130 parts
= PATTERN
.split(row
)[1:-1] #do magic re split and keep quoting
131 metadata
["EXT-X-KEY"] = dict([part
.split('=',1) for part
in parts
if '=' in part
]) #throw away the commas and make dict of the pairs
132 return(segments
, metadata
)
134 if __name__
== "__main__":