|
@@ -1,4 +1,5 @@
|
1
|
1
|
#!/usr/bin/python
|
|
2
|
+# -*- coding: utf-8 -*-
|
2
|
3
|
"""
|
3
|
4
|
StreamProxy daemon (based on Livestream daemon)
|
4
|
5
|
Ensures persistent cookies, User-Agents and others tricks to play protected HLS/DASH streams
|
|
@@ -18,6 +19,7 @@ from urllib import unquote, quote
|
18
|
19
|
import urllib,urlparse
|
19
|
20
|
#import cookielib,urllib2
|
20
|
21
|
import requests
|
|
22
|
+
|
21
|
23
|
try:
|
22
|
24
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
23
|
25
|
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
|
@@ -25,7 +27,7 @@ except:
|
25
|
27
|
pass
|
26
|
28
|
|
27
|
29
|
HOST_NAME = ""
|
28
|
|
-PORT_NUMBER = 88
|
|
30
|
+PORT_NUMBER = 8880
|
29
|
31
|
DEBUG = True
|
30
|
32
|
DEBUG2 = False
|
31
|
33
|
|
|
@@ -36,17 +38,18 @@ COL_CODE = "%3A"
|
36
|
38
|
headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
|
37
|
39
|
headers0 = headers2dict("""
|
38
|
40
|
icy-metadata: 1
|
39
|
|
-Cache-Control: max-age=0
|
40
|
|
-Accept-Encoding: gzip, deflate
|
41
|
41
|
User-Agent: GStreamer souphttpsrc libsoup/2.52.2
|
42
|
|
-Connection: Keep-Alive
|
43
|
42
|
""")
|
44
|
43
|
sessions = {}
|
|
44
|
+cur_directory = os.path.dirname(os.path.realpath(__file__))
|
|
45
|
+sources = None
|
|
46
|
+slinks = {}
|
|
47
|
+
|
45
|
48
|
|
46
|
49
|
class StreamHandler(BaseHTTPRequestHandler):
|
47
|
50
|
|
48
|
51
|
def do_HEAD(self):
|
49
|
|
- print "**head"
|
|
52
|
+ print "**get_head"
|
50
|
53
|
self.send_response(200)
|
51
|
54
|
self.send_header("Server", "playstreamproxy")
|
52
|
55
|
if ".m3u8" in self.path.lower():
|
|
@@ -62,14 +65,14 @@ class StreamHandler(BaseHTTPRequestHandler):
|
62
|
65
|
|
63
|
66
|
def do_GET(self):
|
64
|
67
|
"""Respond to a GET request"""
|
65
|
|
- self.log_message("\n\n"+40*"#"+"\nget_url: \n%s", self.path)
|
|
68
|
+ print "\n\n"+40*"#"+"\nget_url: \n%s", self.path
|
66
|
69
|
p = self.path.split("~")
|
67
|
|
- #url = urllib.unquote(p[0][1:])
|
68
|
|
- url = p[0][1:]
|
69
|
|
- url = url.replace(COL_CODE, ":")
|
70
|
|
- headers = self.headers.dict
|
71
|
|
- headers = {} # TODO
|
72
|
|
- headers["host"] = urlparse.urlparse(url).hostname
|
|
70
|
+ #url = urllib.unquote(p[0][1:]) # TODO - vajag nocekot vai visi urli strādā
|
|
71
|
+ urlp = p[0][1:]
|
|
72
|
+ url = urlp.replace(COL_CODE, ":")
|
|
73
|
+ #headers = self.headers.dict
|
|
74
|
+ headers = {} # TODO izmanto saņemtos headerus, var aizvietot ar defaultajiem
|
|
75
|
+ #headers["host"] = urlparse.urlparse(url).hostname
|
73
|
76
|
if len(p)>1:
|
74
|
77
|
for h in p[1:]:
|
75
|
78
|
k = h.split("=")[0].lower()
|
|
@@ -78,18 +81,18 @@ class StreamHandler(BaseHTTPRequestHandler):
|
78
|
81
|
if DEBUG:
|
79
|
82
|
print "url=%s"%url
|
80
|
83
|
print "Original request headers + url headers:"
|
81
|
|
- print_headers(headers)
|
82
|
|
-
|
|
84
|
+ print_headers(self.headers.dict)
|
83
|
85
|
self.protocol_version = 'HTTP/1.1'
|
84
|
86
|
|
85
|
|
- # TODO fetch selection
|
86
|
87
|
try:
|
87
|
|
- if ".lattelecom.tv/" in url: # lattelecom.tv hack
|
88
|
|
- self.fetch_ltc(self.wfile, url, headers)
|
|
88
|
+ if "::" in url: # encoded source link
|
|
89
|
+ self.fetch_source(urlp, headers)
|
|
90
|
+ elif ".lattelecom.tv/" in url: # lattelecom.tv hack
|
|
91
|
+ self.fetch_ltc( url, headers)
|
89
|
92
|
elif "filmas.lv" in url or "viaplay" in url: # HLS session/decode filmas.lv in url:
|
90
|
|
- self.fetch_url2(self.wfile, url, headers)
|
|
93
|
+ self.fetch_url2(url, headers)
|
91
|
94
|
else: # plain fetch
|
92
|
|
- self.fetch_url(self.wfile, url, headers)
|
|
95
|
+ self.fetch_url( url, headers)
|
93
|
96
|
except Exception as e:
|
94
|
97
|
print "Got Exception: ", str(e)
|
95
|
98
|
import traceback
|
|
@@ -97,7 +100,7 @@ class StreamHandler(BaseHTTPRequestHandler):
|
97
|
100
|
|
98
|
101
|
### Remote server request procedures ###
|
99
|
102
|
|
100
|
|
- def fetch_offline(self,wfile):
|
|
103
|
+ def fetch_offline(self):
|
101
|
104
|
print "** Fetch offline"
|
102
|
105
|
self.send_response(200)
|
103
|
106
|
self.send_header("Server", "playstreamproxy")
|
|
@@ -106,172 +109,189 @@ class StreamHandler(BaseHTTPRequestHandler):
|
106
|
109
|
self.wfile.write(open("offline.mp4", "rb").read())
|
107
|
110
|
#self.wfile.close()
|
108
|
111
|
|
109
|
|
- def fetch_url(self,wfile,url,headers):
|
|
112
|
+ def fetch_source(self, urlp, headers):
|
110
|
113
|
if DEBUG:
|
111
|
114
|
print "\n***********************************************************"
|
112
|
|
- print "fetch_url: \n%s"%url
|
113
|
|
- print "**Server request headers: "
|
114
|
|
- print_headers(headers)
|
115
|
|
- #if ".lattelecom.tv/" in url and EQ_CODE in url:
|
116
|
|
- # url = url.replace(EQ_CODE,"=")
|
117
|
|
- r = requests.get(url,headers = headers)
|
|
115
|
+ print "fetch_source: \n%s"%urlp
|
|
116
|
+ base_data = hls_base(urlp)
|
|
117
|
+ data = urllib.unquote_plus(base_data)[:-1]
|
|
118
|
+ if DEBUG: print "base_data=", base_data
|
|
119
|
+ if DEBUG: print "data=", data
|
|
120
|
+ if not base_data in slinks :
|
|
121
|
+ streams = sources.get_streams(data)
|
|
122
|
+ if not streams:
|
|
123
|
+ self.write_error(500) # TODO
|
|
124
|
+ return
|
|
125
|
+ url = streams[0]["url"]
|
|
126
|
+ base_url = hls_base(url)
|
|
127
|
+ if DEBUG: print "New link, base_url=",base_url
|
|
128
|
+ ses = requests.Session()
|
|
129
|
+ ses.trust_env = False
|
|
130
|
+ slinks[base_data] = {"data": data, "urlp":urlp,"url": url, "base_url": base_url,"session":ses}
|
|
131
|
+ else:
|
|
132
|
+ ses = slinks[base_data]["session"]
|
|
133
|
+ if urlp == slinks[base_data]["urlp"]:
|
|
134
|
+ url = slinks[base_data]["url"]
|
|
135
|
+ if DEBUG: print "Existing base link", url
|
|
136
|
+ else:
|
|
137
|
+ url = urlp.replace(base_data, slinks[base_data]["base_url"])
|
|
138
|
+ if DEBUG: print "Existing new link", url
|
|
139
|
+ r = self.get_page_ses(url,ses,True,headers = headers)
|
118
|
140
|
code = r.status_code
|
|
141
|
+ if not code in (200,206): # TODO mēģina vēlreiz get_streams
|
|
142
|
+ self.write_error(code)
|
|
143
|
+ return
|
|
144
|
+ self.send_response(code)
|
|
145
|
+ self.send_headers(r.headers)
|
|
146
|
+ CHUNK_SIZE = 1024 *4
|
|
147
|
+ for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
|
|
148
|
+ try:
|
|
149
|
+ self.wfile.write(chunk)
|
|
150
|
+ except Exception as e:
|
|
151
|
+ print "Exception: ", str(e)
|
|
152
|
+ self.wfile.close()
|
|
153
|
+ return
|
|
154
|
+ if DEBUG: print "**File downloaded"
|
|
155
|
+ if "connection" in r.headers and r.headers["connection"] <> "keep-alive":
|
|
156
|
+ self.wfile.close()
|
|
157
|
+ return
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+ def fetch_url(self, url,headers):
|
119
|
161
|
if DEBUG:
|
120
|
|
- print "** Server/proxy response, code = %s"%code
|
121
|
|
- print_headers(r.headers)
|
|
162
|
+ print "\n***********************************************************"
|
|
163
|
+ print "fetch_url: \n%s"%url
|
|
164
|
+ r = self.get_page(url,headers = headers)
|
|
165
|
+ code = r.status_code
|
122
|
166
|
if not code in (200,206):
|
123
|
|
- print "***Error, code=%s",code
|
124
|
|
- self.send_response(code)
|
125
|
|
- self.send_headers(r.headers)
|
126
|
|
- wfile.close()
|
|
167
|
+ self.write_error(code)
|
127
|
168
|
return
|
128
|
169
|
self.send_response(code)
|
129
|
170
|
self.send_headers(r.headers)
|
130
|
171
|
CHUNK_SIZE = 1024*4
|
131
|
|
- for chunk in r.iter_content(CHUNK_SIZE):
|
|
172
|
+ for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
|
132
|
173
|
try:
|
133
|
|
- wfile.write(chunk)
|
|
174
|
+ self.wfile.write(chunk)
|
134
|
175
|
except Exception as e:
|
135
|
176
|
print "Exception: ", str(e)
|
136
|
|
- wfile.close()
|
|
177
|
+ self.wfile.close()
|
137
|
178
|
return
|
138
|
179
|
if DEBUG: print "**File downloaded"
|
139
|
|
- wfile.close()
|
140
|
|
- # time.sleep(1)
|
|
180
|
+ if "connection" in r.headers and r.headers["connection"] <> "keep-alive":
|
|
181
|
+ self.wfile.close()
|
141
|
182
|
return
|
142
|
183
|
|
143
|
|
- def fetch_ltc(self, wfile, url, headers):
|
|
184
|
+ def fetch_ltc(self, url, headers):
|
|
185
|
+ "lattelecom.tv hack (have to update chunklist after each 6 min"
|
144
|
186
|
if DEBUG:
|
145
|
|
- print "\n***********************************************************"
|
146
|
|
- print "fetch_url2: \n%s"%url
|
147
|
|
- #self.log_message("fetch_filmas: \n%s", url)
|
148
|
|
- #self.log_message("headers: %s", headers)
|
|
187
|
+ print "\n\n***********************************************************"
|
|
188
|
+ print "fetch_ltc: \n%s"%url
|
149
|
189
|
base_url = hls_base(url)
|
150
|
190
|
if DEBUG: print "base_url=",base_url
|
151
|
191
|
if base_url not in sessions:
|
152
|
192
|
if DEBUG: print "New session"
|
153
|
193
|
sessions[base_url] = {}
|
154
|
194
|
sessions[base_url]["session"] = requests.Session()
|
155
|
|
- #sessions[base_url]["session"].headers = {}
|
156
|
|
- sessions[base_url]["key"] = binascii.a2b_hex(headers["key"]) if "key" in headers and headers["key"] else None
|
|
195
|
+ sessions[base_url]["session"].trust_env = False
|
|
196
|
+ sessions[base_url]["session"].headers.update(headers0)
|
|
197
|
+ sessions[base_url]["playlist"] = ""
|
|
198
|
+ sessions[base_url]["chunklist"] = []
|
|
199
|
+
|
|
200
|
+ # change ts file to valid one media_w215689190_33.ts?
|
|
201
|
+ tsfile = re.search("media_\w+_(\d+)\.ts", url, re.IGNORECASE)
|
|
202
|
+ if tsfile and sessions[base_url]["chunklist"]:
|
|
203
|
+ tnum = int(tsfile.group(1))
|
|
204
|
+ url2 = sessions[base_url]["chunklist"][tnum]
|
|
205
|
+ if not url2.startswith("http"):
|
|
206
|
+ url2 = base_url + url2
|
|
207
|
+ url = url2
|
|
208
|
+ if DEBUG: print "[playstreamproxy] url changed to ", url
|
|
209
|
+
|
|
210
|
+ ### get_page ###
|
157
|
211
|
ses = sessions[base_url]["session"]
|
158
|
|
- key = sessions[base_url]["key"]
|
159
|
|
- ses.headers.clear()
|
160
|
|
- ses.headers.update(headers0)
|
|
212
|
+ #ses.headers.update(headers0)
|
161
|
213
|
ses.headers.update(headers)
|
162
|
|
- ses.headers["Connection"]="Keep-Alive"
|
163
|
|
- if DEBUG:
|
164
|
|
- print "**Server request headers: "
|
165
|
|
- print_headers(ses.headers)
|
166
|
|
- for t in range(3):
|
167
|
|
- r = ses.get(url, stream=True, verify=False)
|
168
|
|
- code = r.status_code #r.status_code
|
169
|
|
- if DEBUG:
|
170
|
|
- print "\n\n=====================================\n**Server response:", code #r.status_code
|
171
|
|
- print "**Server response headers: "
|
172
|
|
- print_headers(r.headers)
|
173
|
|
- if code in (200,2016): break
|
174
|
|
- if not (code in (200,206)):
|
175
|
|
- print "***Error, code=%s"%code
|
176
|
|
- self.send_response(code)
|
177
|
|
- self.send_headers(r.headers)
|
178
|
|
- wfile.close()
|
179
|
|
- #self.fetch_offline(wfile)
|
|
214
|
+ # ses.headers["Connection"]="Keep-Alive"
|
|
215
|
+ r = self.get_page_ses(url,ses)
|
|
216
|
+ code = r.status_code #r.status_code
|
|
217
|
+
|
|
218
|
+ if not (code in (200,206)) and tsfile:
|
|
219
|
+ # update chunklist
|
|
220
|
+ r2 = self.get_page(sessions[base_url]["playlist"])
|
|
221
|
+ streams = re.findall(r"#EXT-X-STREAM-INF:.*?BANDWIDTH=(\d+).*?\n(.+?)$", r2.content, re.IGNORECASE | re.MULTILINE)
|
|
222
|
+ if streams:
|
|
223
|
+ sorted(streams, key=lambda item: int(item[0]), reverse=True)
|
|
224
|
+ chunklist = streams[0][1]
|
|
225
|
+ if not chunklist.startswith("http"):
|
|
226
|
+ chunklist = base_url + chunklist
|
|
227
|
+ else:
|
|
228
|
+ self.write_error(r.status_code)
|
|
229
|
+ return
|
|
230
|
+ print "[playstreamproxy] trying to update chunklist", chunklist
|
|
231
|
+ r3 = self.get_page_ses(chunklist,ses,True)
|
|
232
|
+ ts_list = re.findall(r"#EXTINF:.*?\n(.+?)$", r3.content, re.IGNORECASE | re.MULTILINE)
|
|
233
|
+ sessions[base_url]["chunklist"]= ts_list
|
|
234
|
+ tnum = int(tsfile.group(1))
|
|
235
|
+ url2 = sessions[base_url]["chunklist"][tnum]
|
|
236
|
+ if not url2.startswith("http"):
|
|
237
|
+ url2 = base_url + url2
|
|
238
|
+ r = self.get_page_ses(url2,ses,True)
|
|
239
|
+ if not r.status_code in (200,206):
|
|
240
|
+ self.write_error(r.status_code)
|
|
241
|
+ return
|
|
242
|
+ elif not r.status_code in (200,206):
|
|
243
|
+ self.write_error(r.status_code)
|
180
|
244
|
return
|
181
|
245
|
|
|
246
|
+ if "playlist.m3u8" in url:
|
|
247
|
+ sessions[base_url]["playlist"] = url
|
|
248
|
+
|
182
|
249
|
### Start of return formin and sending
|
183
|
250
|
self.send_response(200)
|
184
|
251
|
#headers2 = del_headers(r.headers,["Content-Encoding",'Transfer-Encoding',"Connection",'content-range',"range"])
|
185
|
252
|
headers2 = {"server":"playstreamproxy", "content-type":"text/html"}
|
186
|
253
|
|
187
|
|
- # Content-Type: application/vnd.apple.mpegurl (encrypted)
|
188
|
|
- if r.headers["content-type"] == "application/vnd.apple.mpegurl":
|
189
|
|
- content = r.content
|
190
|
|
- content = r.content.replace(base_url,"")
|
191
|
|
- content = re.sub("#EXT-X-KEY:METHOD=AES-128.+\n", "", content, 0, re.IGNORECASE | re.MULTILINE)
|
192
|
|
- headers2["content-type"] = "application/vnd.apple.mpegurl"
|
193
|
|
- headers2["content-length"] = "%s"%len(content)
|
194
|
|
- r.headers["content-length"] = "%s"%len(content)
|
195
|
|
- #headers2['content-range'] = 'bytes 0-%s/%s'%(len(content)-1,len(content))
|
196
|
|
- #self.send_headers(headers2)
|
197
|
|
- self.send_headers(r.headers)
|
198
|
|
- wfile.write(content)
|
199
|
|
- wfile.close()
|
200
|
|
-
|
201
|
|
- # Content-Type: video/MP2T (encrypted)
|
202
|
|
- elif r.headers["content-type"] == "video/MP2T" and key:
|
203
|
|
- print "Decode video/MP2T"
|
204
|
|
- content = r.content
|
205
|
|
- from Crypto.Cipher import AES
|
206
|
|
- iv = content[:16]
|
207
|
|
- d = AES.new(key, AES.MODE_CBC, iv)
|
208
|
|
- content = d.decrypt(content[16:])
|
209
|
|
- headers2["content-type"] = "video/MP2T"
|
210
|
|
- headers2["content-length"] = "%s"% (len(content))
|
211
|
|
- #headers2['content-range'] = 'bytes 0-%s/%s' % (len(content) - 1, len(content))
|
212
|
|
- print content[0:16]
|
213
|
|
- print "Finish decode"
|
214
|
|
- self.send_headers(headers2)
|
215
|
|
- wfile.write(content)
|
216
|
|
- wfile.close()
|
217
|
|
-
|
218
|
|
- else:
|
219
|
|
- print "Return regular content"
|
220
|
|
- headers2["content-type"] = r.headers["content-type"]
|
221
|
|
- if "content-length" in r.headers:
|
222
|
|
- headers2["content-length"] = r.headers["content-length"]
|
223
|
|
- self.send_headers(r.headers)
|
224
|
|
- CHUNK_SIZE = 4 * 1024
|
225
|
|
- for chunk in r.iter_content(CHUNK_SIZE):
|
226
|
|
- try:
|
227
|
|
- #print "#",
|
228
|
|
- wfile.write(chunk)
|
229
|
|
- except Exception as e:
|
230
|
|
- print "Exception: ", str(e)
|
231
|
|
- return
|
232
|
|
- if DEBUG: print "File downloaded = "
|
233
|
|
- wfile.close()
|
234
|
|
- #time.sleep(1)
|
235
|
|
- return
|
|
254
|
+ if DEBUG: print "\n** Return content"
|
|
255
|
+ headers2["content-type"] = r.headers["content-type"]
|
|
256
|
+ if "content-length" in r.headers:
|
|
257
|
+ headers2["content-length"] = r.headers["content-length"]
|
|
258
|
+ self.send_headers(r.headers)
|
|
259
|
+ CHUNK_SIZE = 4 * 1024
|
|
260
|
+ for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
|
|
261
|
+ try:
|
|
262
|
+ #print "#",
|
|
263
|
+ self.wfile.write(chunk)
|
|
264
|
+ except Exception as e:
|
|
265
|
+ print "Exception: ", str(e)
|
|
266
|
+ return
|
|
267
|
+ if DEBUG: print "File downloaded = "
|
|
268
|
+ self.wfile.close()
|
|
269
|
+ #time.sleep(1)
|
|
270
|
+ return
|
236
|
271
|
|
237
|
272
|
|
238
|
|
- def fetch_url2(self, wfile, url, headers):
|
|
273
|
+ def fetch_url2(self, url, headers):
|
239
|
274
|
if DEBUG:
|
240
|
275
|
print "\n***********************************************************"
|
241
|
276
|
print "fetch_url2: \n%s"%url
|
242
|
|
- #self.log_message("fetch_filmas: \n%s", url)
|
243
|
|
- #self.log_message("headers: %s", headers)
|
244
|
277
|
base_url = hls_base(url)
|
245
|
278
|
if DEBUG: print "base_url=",base_url
|
246
|
279
|
if base_url not in sessions:
|
247
|
280
|
if DEBUG: print "New session"
|
248
|
281
|
sessions[base_url] = {}
|
249
|
282
|
sessions[base_url]["session"] = requests.Session()
|
250
|
|
- #sessions[base_url]["session"].headers = {}
|
|
283
|
+ sessions[base_url]["session"].trust_env = False
|
|
284
|
+ sessions[base_url]["session"].headers.update(headers0)
|
251
|
285
|
sessions[base_url]["key"] = binascii.a2b_hex(headers["key"]) if "key" in headers and headers["key"] else None
|
252
|
286
|
ses = sessions[base_url]["session"]
|
|
287
|
+ ses.trust_env = False
|
253
|
288
|
key = sessions[base_url]["key"]
|
254
|
|
- ses.headers.clear()
|
255
|
|
- ses.headers.update(headers0)
|
|
289
|
+ #ses.headers.clear()
|
256
|
290
|
ses.headers.update(headers)
|
257
|
|
- ses.headers["Connection"]="Keep-Alive"
|
258
|
|
- if DEBUG:
|
259
|
|
- print "**Server request headers: "
|
260
|
|
- print_headers(ses.headers)
|
261
|
|
- for t in range(3):
|
262
|
|
- r = ses.get(url, stream=True, verify=False)
|
263
|
|
- code = r.status_code #r.status_code
|
264
|
|
- if DEBUG:
|
265
|
|
- print "\n\n=====================================\n**Server response:", code #r.status_code
|
266
|
|
- print "**Server response headers: "
|
267
|
|
- print_headers(r.headers)
|
268
|
|
- if code in (200,2016): break
|
|
291
|
+ r = self.get_page_ses(url, ses,stream=False)
|
|
292
|
+ code = r.status_code #r.status_code
|
269
|
293
|
if not (code in (200,206)):
|
270
|
|
- print "***Error, code=%s"%code
|
271
|
|
- self.send_response(code)
|
272
|
|
- self.send_headers(r.headers)
|
273
|
|
- wfile.close()
|
274
|
|
- #self.fetch_offline(wfile)
|
|
294
|
+ self.write_error(r.status_code)
|
275
|
295
|
return
|
276
|
296
|
|
277
|
297
|
### Start of return formin and sending
|
|
@@ -280,7 +300,7 @@ class StreamHandler(BaseHTTPRequestHandler):
|
280
|
300
|
headers2 = {"server":"playstreamproxy", "content-type":"text/html"}
|
281
|
301
|
|
282
|
302
|
# Content-Type: application/vnd.apple.mpegurl (encrypted)
|
283
|
|
- if r.headers["content-type"] == "application/vnd.apple.mpegurl":
|
|
303
|
+ if r.headers["content-type"] == "application/vnd.apple.mpegurl" and key:
|
284
|
304
|
content = r.content
|
285
|
305
|
content = r.content.replace(base_url,"")
|
286
|
306
|
content = re.sub("#EXT-X-KEY:METHOD=AES-128.+\n", "", content, 0, re.IGNORECASE | re.MULTILINE)
|
|
@@ -288,10 +308,10 @@ class StreamHandler(BaseHTTPRequestHandler):
|
288
|
308
|
headers2["content-length"] = "%s"%len(content)
|
289
|
309
|
r.headers["content-length"] = "%s"%len(content)
|
290
|
310
|
#headers2['content-range'] = 'bytes 0-%s/%s'%(len(content)-1,len(content))
|
291
|
|
- #self.send_headers(headers2)
|
292
|
|
- self.send_headers(r.headers)
|
293
|
|
- wfile.write(content)
|
294
|
|
- wfile.close()
|
|
311
|
+ self.send_headers(headers2)
|
|
312
|
+ #self.send_headers(r.headers)
|
|
313
|
+ self.wfile.write(content)
|
|
314
|
+ self.wfile.close()
|
295
|
315
|
|
296
|
316
|
# Content-Type: video/MP2T (encrypted)
|
297
|
317
|
elif r.headers["content-type"] == "video/MP2T" and key:
|
|
@@ -307,25 +327,27 @@ class StreamHandler(BaseHTTPRequestHandler):
|
307
|
327
|
print content[0:16]
|
308
|
328
|
print "Finish decode"
|
309
|
329
|
self.send_headers(headers2)
|
310
|
|
- wfile.write(content)
|
311
|
|
- wfile.close()
|
|
330
|
+ self.wfile.write(content)
|
|
331
|
+ self.wfile.close()
|
312
|
332
|
|
313
|
333
|
else:
|
314
|
|
- print "Return regular content"
|
|
334
|
+ if DEBUG: print "Return regular content"
|
315
|
335
|
headers2["content-type"] = r.headers["content-type"]
|
316
|
336
|
if "content-length" in r.headers:
|
317
|
337
|
headers2["content-length"] = r.headers["content-length"]
|
318
|
338
|
self.send_headers(r.headers)
|
|
339
|
+ #self.send_headers(headers2)
|
319
|
340
|
CHUNK_SIZE = 4 * 1024
|
320
|
|
- for chunk in r.iter_content(CHUNK_SIZE):
|
|
341
|
+ for chunk in r.iter_content(chunk_size=CHUNK_SIZE):
|
321
|
342
|
try:
|
322
|
343
|
#print "#",
|
323
|
|
- wfile.write(chunk)
|
|
344
|
+ self.wfile.write(chunk)
|
324
|
345
|
except Exception as e:
|
325
|
346
|
print "Exception: ", str(e)
|
326
|
347
|
return
|
327
|
348
|
if DEBUG: print "File downloaded = "
|
328
|
|
- wfile.close()
|
|
349
|
+ if "connection" in r.headers and r.headers["connection"]<>"keep-alive":
|
|
350
|
+ self.wfile.close()
|
329
|
351
|
#time.sleep(1)
|
330
|
352
|
return
|
331
|
353
|
|
|
@@ -337,11 +359,48 @@ class StreamHandler(BaseHTTPRequestHandler):
|
337
|
359
|
self.send_header(h, headers[h])
|
338
|
360
|
self.end_headers()
|
339
|
361
|
|
|
362
|
+ def write_error(self,code):
|
|
363
|
+ print "***Error, code=%s" % code
|
|
364
|
+ self.send_response(code)
|
|
365
|
+ #self.send_headers(r.headers)
|
|
366
|
+ self.wfile.close() # TODO?
|
|
367
|
+ # self.fetch_offline()
|
|
368
|
+
|
|
369
|
+ def get_page_ses(self,url,ses,stream=True, headers=None):
|
|
370
|
+ headers= headers if headers else headers0
|
|
371
|
+ ses.headers.update(headers)
|
|
372
|
+ if DEBUG:
|
|
373
|
+ print "\n\n====================================================\n**get_page_ses\n%s"%url
|
|
374
|
+ print "**Server request headers: "
|
|
375
|
+ print_headers(ses.headers)
|
|
376
|
+ r = ses.get(url, stream=stream, verify=False)
|
|
377
|
+ if DEBUG:
|
|
378
|
+ print "**Server response:", r.status_code
|
|
379
|
+ print "**Server response headers: "
|
|
380
|
+ print_headers(r.headers)
|
|
381
|
+ return r
|
|
382
|
+
|
|
383
|
+ def get_page(self,url,headers=None):
|
|
384
|
+ if not headers:
|
|
385
|
+ headers = headers0
|
|
386
|
+ if DEBUG:
|
|
387
|
+ print "\n\n====================================================\n**get_page\n%s"%url
|
|
388
|
+ print "**Server request headers: "
|
|
389
|
+ print_headers(headers)
|
|
390
|
+ r = requests.get(url, headers=headers,stream=True)
|
|
391
|
+ if DEBUG:
|
|
392
|
+ print "**Server response:", r.status_code
|
|
393
|
+ print "**Server response headers: "
|
|
394
|
+ print_headers(r.headers)
|
|
395
|
+ return r
|
340
|
396
|
|
341
|
397
|
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
|
342
|
398
|
"""Handle requests in a separate thread."""
|
343
|
399
|
|
344
|
400
|
def start(host = HOST_NAME, port = PORT_NUMBER):
|
|
401
|
+ import ContentSources, util
|
|
402
|
+ global sources
|
|
403
|
+ sources = ContentSources.ContentSources(os.path.join(cur_directory, "sources"))
|
345
|
404
|
httpd = ThreadedHTTPServer((host, port), StreamHandler)
|
346
|
405
|
print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER)
|
347
|
406
|
try:
|