|
@@ -0,0 +1,505 @@
|
|
1
|
+#!/usr/bin/env python
|
|
2
|
+# coding=utf8
|
|
3
|
+import sys, os, traceback
|
|
4
|
+from Tkinter import *
|
|
5
|
+try:
|
|
6
|
+ from ttk import *
|
|
7
|
+except:
|
|
8
|
+ pass
|
|
9
|
+import tkMessageBox as tkm
|
|
10
|
+import tkSimpleDialog as tkd
|
|
11
|
+
|
|
12
|
+import PIL, StringIO
|
|
13
|
+from PIL import ImageTk, Image
|
|
14
|
+import requests, urllib2
|
|
15
|
+
|
|
16
|
+from ContentSources import ContentSources
|
|
17
|
+from sources.SourceBase import stream_type
|
|
18
|
+import util
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+class Main(Frame):
|
|
22
|
+
|
|
23
|
+ def __init__(self, sources):
|
|
24
|
+ self.root = Tk()
|
|
25
|
+ self.root.geometry("1050x600")
|
|
26
|
+ Frame.__init__(self, self.root)
|
|
27
|
+ #self.pack()
|
|
28
|
+ self.pack(fill=BOTH, expand=1)
|
|
29
|
+ self.initUI()
|
|
30
|
+ items = ["item %s" % i for i in range(20)]
|
|
31
|
+ if sources:
|
|
32
|
+ self.sources = sources
|
|
33
|
+ else:
|
|
34
|
+ self.sources = ContentSources("sources")
|
|
35
|
+ self.picons_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "picons")
|
|
36
|
+ self.tmp_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), "tmp")
|
|
37
|
+ if not os.path.exists(self.tmp_path):
|
|
38
|
+ os.mkdir(self.tmp_path)
|
|
39
|
+ self.history = []
|
|
40
|
+ self.cur_index = 0
|
|
41
|
+ self.cur = ("Home", "config::home", "", "PlayStream home")
|
|
42
|
+
|
|
43
|
+ def initUI(self):
|
|
44
|
+ self.master.title("PlayStream")
|
|
45
|
+ self.txt1 = Label(self)
|
|
46
|
+ self.txt1.pack(side=TOP, fill=X, padx=15)
|
|
47
|
+ self.txt1.configure(font=("Tahoma", 14, "bold"))
|
|
48
|
+ self.txt1.config(text="")
|
|
49
|
+ self.txt2 = Label(self)
|
|
50
|
+ self.txt2.pack(side=TOP, fill=X, padx=15)
|
|
51
|
+ self.txt2.config(text="")
|
|
52
|
+ self.txt2.configure(font=("Tahoma", 12))
|
|
53
|
+
|
|
54
|
+ frame1 = Frame(self)
|
|
55
|
+ frame1.pack(side=TOP, fill=X, padx=15)
|
|
56
|
+ scrollbar = Scrollbar(frame1, orient=VERTICAL)
|
|
57
|
+ self.listbox = Listbox(frame1, width=80, height=30, yscrollcommand=scrollbar.set)
|
|
58
|
+ scrollbar.config(command=self.listbox.yview)
|
|
59
|
+ #self.listbox.config(yscrollcommand=scrollbar.set)
|
|
60
|
+ self.listbox.pack(side=LEFT)
|
|
61
|
+ scrollbar.pack(side=LEFT, fill=Y)
|
|
62
|
+ self.listbox.focus_set()
|
|
63
|
+ self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_action(evt, "Changed"))
|
|
64
|
+ self.listbox.bind('<Double-1> ', lambda evt:self.list_action(None, "Return"))
|
|
65
|
+ self.listbox.bind('<Key> ', self.list_action)
|
|
66
|
+
|
|
67
|
+ self.pic = Canvas(frame1, width=400, height=250)
|
|
68
|
+ self.pic.pack(side=TOP, expand=1)
|
|
69
|
+
|
|
70
|
+ frame2 = Frame(frame1, height=250, width=400)
|
|
71
|
+ frame2.pack(side=TOP)
|
|
72
|
+ scrollbar2 = Scrollbar(frame2)
|
|
73
|
+ self.desc = Text(frame2, height=15, width=70, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0)
|
|
74
|
+ scrollbar2.config(command=self.desc.yview)
|
|
75
|
+ scrollbar2.pack(side="right", fill="y")
|
|
76
|
+ self.desc.configure(font=("Tahoma", 10))
|
|
77
|
+ self.desc.pack(anchor=N)
|
|
78
|
+
|
|
79
|
+ frame3 = Frame(self, height=40)
|
|
80
|
+ frame3.pack(side=TOP, fill=X, padx=15)
|
|
81
|
+ self.b_select = Button(frame3, text="Select",
|
|
82
|
+ command=lambda :self.list_action(None, "Return"), width=10)
|
|
83
|
+ self.b_select.pack(side=LEFT, anchor=S)
|
|
84
|
+
|
|
85
|
+ self.b_back = Button(frame3, text="Back",
|
|
86
|
+ command=lambda :self.list_action(None, "Escape"), width=10)
|
|
87
|
+ self.b_back.pack(side=LEFT, anchor=S)
|
|
88
|
+
|
|
89
|
+ self.b_options = Button(frame3, text="Options",
|
|
90
|
+ command=lambda :self.list_action(None, "Options"), width=10)
|
|
91
|
+ self.b_options.pack(side=LEFT, anchor=S)
|
|
92
|
+
|
|
93
|
+ self.b_config = Button(frame3, text="Config",
|
|
94
|
+ command=lambda :self.list_action(None, "Config"), width=10)
|
|
95
|
+ self.b_config.pack(side=LEFT, anchor=S)
|
|
96
|
+
|
|
97
|
+ self.b_exit = Button(frame3, text="Exit",
|
|
98
|
+ command=self.quit, width=10)
|
|
99
|
+ self.b_exit.pack(side=LEFT, anchor=S)
|
|
100
|
+
|
|
101
|
+ def list_select(self):
|
|
102
|
+ w = evt.widget
|
|
103
|
+ cs = int(w.curselection()[0])
|
|
104
|
+ value = w.get(cs)
|
|
105
|
+ #print 'You selected item %d: "%s"' % (index, value)
|
|
106
|
+
|
|
107
|
+ def list_key(self, evt):
|
|
108
|
+ w = evt.widget
|
|
109
|
+ cs = int(w.curselection()[0])
|
|
110
|
+ value = w.get(cs)
|
|
111
|
+ key = evt.keysym
|
|
112
|
+ #print 'Key %s' % (key)
|
|
113
|
+ self.cur_index = cs
|
|
114
|
+ self.list_action(key)
|
|
115
|
+
|
|
116
|
+ def list_action(self, evt=None, key=None):
|
|
117
|
+ cs = int(self.listbox.curselection()[0])
|
|
118
|
+ self.cur_index = cs
|
|
119
|
+ if (not key) and evt:
|
|
120
|
+ w = evt.widget
|
|
121
|
+ value = w.get(cs)
|
|
122
|
+ key = evt.keysym
|
|
123
|
+ print 'Key %s' % (key)
|
|
124
|
+ data = self.content[cs][1]
|
|
125
|
+ cur2 = self.content[cs]
|
|
126
|
+
|
|
127
|
+ if key == "Changed":
|
|
128
|
+ self.show_desc()
|
|
129
|
+ self.show_pic()
|
|
130
|
+
|
|
131
|
+ elif key == "Return" and data <> "back":
|
|
132
|
+ if not self.sources.is_video(data):
|
|
133
|
+ if "{0}" in data:
|
|
134
|
+ a = tkd.askstring("Search", "Search for")
|
|
135
|
+ cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3])
|
|
136
|
+ self.history.append((self.cur, cs))
|
|
137
|
+ self.cur = self.content[cs]
|
|
138
|
+ self.cur_index = 0
|
|
139
|
+ try:
|
|
140
|
+ self.show_content(cur2)
|
|
141
|
+ except Exception as e:
|
|
142
|
+ print unicode(e)
|
|
143
|
+ traceback.print_exc()
|
|
144
|
+ tkm.showerror("Error getting content", unicode(e))
|
|
145
|
+ prev = self.history.pop()
|
|
146
|
+ self.cur = prev[0]
|
|
147
|
+ self.cur_index = prev[1]
|
|
148
|
+ self.show_content(self.cur, self.cur_index)
|
|
149
|
+ return
|
|
150
|
+ else:
|
|
151
|
+ self.play_video(self.content[cs])
|
|
152
|
+ self.listbox.selection_set(self.cur_index)
|
|
153
|
+ self.listbox.activate(self.cur_index)
|
|
154
|
+ self.listbox.focus_set()
|
|
155
|
+
|
|
156
|
+ elif key == "BackSpace" or key == "Escape" or (key == "Return" and data == "back"):
|
|
157
|
+ if self.history:
|
|
158
|
+ prev = self.history.pop()
|
|
159
|
+ self.cur = prev[0]
|
|
160
|
+ self.cur_index = prev[1]
|
|
161
|
+ self.show_content(self.cur, self.cur_index)
|
|
162
|
+ elif key == "Right":
|
|
163
|
+ index2 = self.cur_index + 20
|
|
164
|
+ index2 = min(index2, self.listbox.index(END) - 1)
|
|
165
|
+ self.set_list_item(index2)
|
|
166
|
+
|
|
167
|
+ elif key == "Left":
|
|
168
|
+ index2 = self.cur_index - 20
|
|
169
|
+ index2 = max(index2, 0)
|
|
170
|
+ self.set_list_item(index2)
|
|
171
|
+
|
|
172
|
+ def set_list_item(self, index):
|
|
173
|
+ self.cur_index = index
|
|
174
|
+ self.listbox.selection_clear(0, END)
|
|
175
|
+ self.listbox.selection_set(index)
|
|
176
|
+ self.listbox.activate(index)
|
|
177
|
+ self.listbox.focus_set()
|
|
178
|
+ self.update()
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+ def show_content(self, cur2, cur_index=0):
|
|
182
|
+ data = cur2[1]
|
|
183
|
+ self.txt1.config(text=cur2[0])
|
|
184
|
+ self.content = self.sources.get_content(data)
|
|
185
|
+ self.listbox.delete(0, END)
|
|
186
|
+ for item in self.content:
|
|
187
|
+ self.listbox.insert(END, item[0])
|
|
188
|
+ self.listbox.selection_set(cur_index)
|
|
189
|
+ self.listbox.activate(cur_index)
|
|
190
|
+ self.listbox.focus_set()
|
|
191
|
+ self.show_desc()
|
|
192
|
+ self.show_pic()
|
|
193
|
+
|
|
194
|
+ def show_desc(self):
|
|
195
|
+ cs = self.listbox.curselection()[0]
|
|
196
|
+ self.txt2.config(text=self.content[cs][0])
|
|
197
|
+ self.desc.config(state=NORMAL)
|
|
198
|
+ self.desc.delete("1.0", END)
|
|
199
|
+ self.desc.insert(END, self.content[cs][3])
|
|
200
|
+ self.desc.insert(END, "\n\n"+self.content[cs][2])
|
|
201
|
+ self.desc.config(state=DISABLED)
|
|
202
|
+
|
|
203
|
+ def show_pic(self):
|
|
204
|
+ cs = self.listbox.curselection()[0]
|
|
205
|
+ img = self.content[cs][2]
|
|
206
|
+ self.pic.delete(ALL)
|
|
207
|
+ if not img.startswith("http"):
|
|
208
|
+ img_path = os.path.join(self.picons_path, img)
|
|
209
|
+ if img and os.path.exists(img_path):
|
|
210
|
+ im = Image.open(img_path)
|
|
211
|
+ else:
|
|
212
|
+ im = None
|
|
213
|
+ elif img:
|
|
214
|
+ fcache = img.replace(":", "_").replace("/", "-").replace(":", "_")
|
|
215
|
+ fcache = os.path.join(self.tmp_path, fcache)
|
|
216
|
+ if os.path.exists(fcache):
|
|
217
|
+ im = Image.open(fcache)
|
|
218
|
+ else:
|
|
219
|
+ r = requests.get(img)
|
|
220
|
+ if r.status_code == 200:
|
|
221
|
+ img_data = r.content
|
|
222
|
+ im = Image.open(StringIO.StringIO(r.content))
|
|
223
|
+ with open(fcache, "wb") as f:
|
|
224
|
+ f.write(r.content)
|
|
225
|
+ else:
|
|
226
|
+ im = None
|
|
227
|
+ if im:
|
|
228
|
+ im.thumbnail((400, 250))
|
|
229
|
+ image = ImageTk.PhotoImage(im)
|
|
230
|
+ imagesprite = self.pic.create_image(200, 125,image=image)
|
|
231
|
+ self.pic.image = image
|
|
232
|
+
|
|
233
|
+ def play_video(self, cur2):
|
|
234
|
+ if self.sources.stream_type(cur2[1]):
|
|
235
|
+ stream = util.item()
|
|
236
|
+ stream["url"] = cur2[1]
|
|
237
|
+ stream["name"] = cur2[0]
|
|
238
|
+ streams = [stream]
|
|
239
|
+ else:
|
|
240
|
+ try:
|
|
241
|
+ streams = self.sources.get_streams(cur2[1])
|
|
242
|
+ except Exception as e:
|
|
243
|
+ print unicode(e)
|
|
244
|
+ traceback.print_exc()
|
|
245
|
+ tkm.showerror("Error getting streams", unicode(e))
|
|
246
|
+ return
|
|
247
|
+ if not streams:
|
|
248
|
+ tkm.showerror("Error getting streams", "No streams found")
|
|
249
|
+ return
|
|
250
|
+ if len(streams) > 1:
|
|
251
|
+ lst = []
|
|
252
|
+ for i,s in enumerate(streams):
|
|
253
|
+ lst.append(("[%s,%s] %s"%(s["lang"],s["quality"],s["name"]),i))
|
|
254
|
+ a = ChoiceBox("ChoiceBox test", "Select stream", lst, parent=self, width=40).result
|
|
255
|
+ stream = streams[a]
|
|
256
|
+ else:
|
|
257
|
+ stream = streams[0]
|
|
258
|
+ stream = util.stream_change(stream)
|
|
259
|
+ title = stream["name"] if not "nfo" in stream or not stream["nfo"] else util.nfo2title(stream["nfo"])
|
|
260
|
+ desc = stream["desc"] if not "nfo" in stream or not stream["nfo"] else util.nfo2desc(stream["nfo"])
|
|
261
|
+ img = stream["img"]
|
|
262
|
+ url = stream["url"]
|
|
263
|
+ suburl = ""
|
|
264
|
+ print url
|
|
265
|
+ if "subs" in stream and stream["subs"]:
|
|
266
|
+ suburl = stream["subs"][0]["url"]
|
|
267
|
+ print "\n**Download subtitles %s - %s"%(title,suburl)
|
|
268
|
+ subs = urllib2.urlopen(suburl).read()
|
|
269
|
+ if subs:
|
|
270
|
+ fname0 = re.sub("[/\n\r\t,:\?]","_",title)
|
|
271
|
+ subext = ".srt"
|
|
272
|
+ subfile = os.path.join(self.tmp_path,fname0+subext)
|
|
273
|
+ if ".xml" in suburl:
|
|
274
|
+ subs = util.ttaf2srt(subs)
|
|
275
|
+ with open(subfile,"w") as f:
|
|
276
|
+ f.write(subs)
|
|
277
|
+ else:
|
|
278
|
+ print "\n Error downloading subtitle %s"%suburl
|
|
279
|
+ print "\n**Play stream %s\n%s" % (title, url.encode("utf8"))
|
|
280
|
+ player(url,title,suburl,stream["headers"])
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+ def start(self):
|
|
285
|
+ self.root.mainloop()
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+class ChoiceBox(tkd.Dialog):
|
|
289
|
+ #a = ChoiceBox("ChoiceBox test", "Select stream", items, parent=self).result
|
|
290
|
+ def __init__(self, title, prompt, items, width=20, height=15,
|
|
291
|
+ initialvalue=0, parent = None):
|
|
292
|
+ if not parent:
|
|
293
|
+ import Tkinter
|
|
294
|
+ parent = Tkinter._default_root
|
|
295
|
+ self.prompt = prompt
|
|
296
|
+ self.items = items
|
|
297
|
+ self.width = width
|
|
298
|
+ self.height = height
|
|
299
|
+ self.result = None
|
|
300
|
+ self.initialvalue = initialvalue
|
|
301
|
+ tkd.Dialog.__init__(self, parent, title)
|
|
302
|
+
|
|
303
|
+ def body(self, master):
|
|
304
|
+ w = Label(self, text=self.prompt, justify=LEFT)
|
|
305
|
+ w.pack(side=TOP)
|
|
306
|
+ frame1 = Frame(self)
|
|
307
|
+ frame1.pack(side=TOP, fill=X, expand=1, padx=5)
|
|
308
|
+ scrollbar = Scrollbar(frame1, orient=VERTICAL)
|
|
309
|
+ self.listbox = Listbox(frame1, yscrollcommand=scrollbar.set, width=self.width, height=self.height)
|
|
310
|
+ scrollbar.config(command=self.listbox.yview)
|
|
311
|
+ #self.listbox.config(yscrollcommand=scrollbar.set)
|
|
312
|
+ self.listbox.pack(side=LEFT, fill=BOTH, expand=1)
|
|
313
|
+ scrollbar.pack(side=LEFT, fill=Y)
|
|
314
|
+ for item in self.items:
|
|
315
|
+ self.listbox.insert(END, item)
|
|
316
|
+ self.listbox.selection_set(self.initialvalue)
|
|
317
|
+ self.listbox.activate(self.initialvalue)
|
|
318
|
+ self.listbox.bind('<Double-1> ', self.list_select)
|
|
319
|
+ self.listbox.bind('<Key> ', self.list_key)
|
|
320
|
+ self.update()
|
|
321
|
+ self.geometry("+%d+%d"%(self.parent.winfo_rootx()+100, self.parent.winfo_rooty()+100 ))
|
|
322
|
+ return self.listbox
|
|
323
|
+
|
|
324
|
+ def list_key(self, evt):
|
|
325
|
+ key = evt.keysym
|
|
326
|
+ #print 'Key %s' % (key)
|
|
327
|
+ if key == "Return":
|
|
328
|
+ self.ok()
|
|
329
|
+ elif key == "Escape":
|
|
330
|
+ self.cancel()
|
|
331
|
+
|
|
332
|
+ def list_select(self, evt):
|
|
333
|
+ self.ok()
|
|
334
|
+
|
|
335
|
+ def apply(self):
|
|
336
|
+ self.result = self.listbox.curselection()[0]
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+def run(sources=None, data="config::home", title="Home"):
|
|
340
|
+ app = Main(sources)
|
|
341
|
+ app.show_content((title, data, "", ""))
|
|
342
|
+ app.start()
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+def run_cli(sources, data="config::home"):
|
|
347
|
+
|
|
348
|
+ #options = sources.options_read("ltc")
|
|
349
|
+ #print options
|
|
350
|
+ history = []
|
|
351
|
+ cur = ("Home",data,None,None)
|
|
352
|
+ content = sources.get_content(cur[1])
|
|
353
|
+
|
|
354
|
+ exit_loop = False
|
|
355
|
+ while True:
|
|
356
|
+ print
|
|
357
|
+ for i,item in enumerate(content):
|
|
358
|
+ s = "%i: %s - %s %s"%(i,item[0],item[1],item[2])
|
|
359
|
+ print s #.encode(sys.stdout.encoding,"replace")
|
|
360
|
+
|
|
361
|
+ while True:
|
|
362
|
+ a = raw_input("Enter number, (-) for download, q for exit: ")
|
|
363
|
+ if a in ("q","Q","x","X"):
|
|
364
|
+ exit_loop = True
|
|
365
|
+ print "Exiting"
|
|
366
|
+ break
|
|
367
|
+ try:
|
|
368
|
+ n = int(a)
|
|
369
|
+ break
|
|
370
|
+ except:
|
|
371
|
+ print "Not number!"
|
|
372
|
+ if exit_loop: break
|
|
373
|
+ download = False
|
|
374
|
+ if n<0:
|
|
375
|
+ n = abs(n)
|
|
376
|
+ download = True
|
|
377
|
+ cur2 = content[n]
|
|
378
|
+ data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
|
|
379
|
+ if not data0:
|
|
380
|
+ pass
|
|
381
|
+ elif cur2[1] == "back":
|
|
382
|
+ cur = history.pop()
|
|
383
|
+ elif sources.is_video(cur2[1]):
|
|
384
|
+ if sources.stream_type(cur2[1]):
|
|
385
|
+ stream = util.item()
|
|
386
|
+ stream["url"] = cur2[1]
|
|
387
|
+ stream["name"] = cur2[0]
|
|
388
|
+ streams = [stream]
|
|
389
|
+ else:
|
|
390
|
+ try:
|
|
391
|
+ if not download:
|
|
392
|
+ streams = sources.get_streams(cur2[1])
|
|
393
|
+ else:
|
|
394
|
+ stream = util.item()
|
|
395
|
+ stream["url"] = cur2[1]
|
|
396
|
+ stream["name"] = cur2[0]
|
|
397
|
+ stream["url"] = util.streamproxy_encode2(stream["url"])
|
|
398
|
+ print stream["url"]
|
|
399
|
+ streams = [stream]
|
|
400
|
+ except Exception as e:
|
|
401
|
+ print unicode(e)
|
|
402
|
+ traceback.print_exc()
|
|
403
|
+ streams = []
|
|
404
|
+ if streams:
|
|
405
|
+ if not download:
|
|
406
|
+ play_video(streams)
|
|
407
|
+ else:
|
|
408
|
+ #urlp = util.streamproxy_encode2(streams[0]["url"])
|
|
409
|
+ #print urlp
|
|
410
|
+ #util.player(urlp)
|
|
411
|
+ #Downloader.download_video(streams)
|
|
412
|
+ pass
|
|
413
|
+ else:
|
|
414
|
+ print "**No stream to play - %s "%(
|
|
415
|
+ cur2[1])
|
|
416
|
+ raw_input("Press any key")
|
|
417
|
+ #import os
|
|
418
|
+ #os.system('"c:\Program Files (x86)\VideoLAN\VLC\vlc.exe" "%s"'%cur2[1])
|
|
419
|
+
|
|
420
|
+ else:
|
|
421
|
+ if "{0}" in cur2[1]:
|
|
422
|
+ a = raw_input("Enter value:")
|
|
423
|
+ cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3])
|
|
424
|
+ history.append(cur)
|
|
425
|
+ cur = cur2
|
|
426
|
+ try:
|
|
427
|
+ content = sources.get_content(cur[1])
|
|
428
|
+ except Exception as e:
|
|
429
|
+ print unicode(e)
|
|
430
|
+ traceback.print_exc()
|
|
431
|
+ raw_input("Continue?")
|
|
432
|
+
|
|
433
|
+def play_video(streams, select=False):
|
|
434
|
+ if len(streams)>1 and select:
|
|
435
|
+ for i,s in enumerate(streams):
|
|
436
|
+
|
|
437
|
+ print "%s: [%s,%s,%s] %s"%(i,s["quality"],s["lang"],s["type"],s["name"])
|
|
438
|
+ a = raw_input("Select stram to play: ")
|
|
439
|
+ try:
|
|
440
|
+ n = int(a)
|
|
441
|
+ except:
|
|
442
|
+ n = 0
|
|
443
|
+ if n>=len(streams):
|
|
444
|
+ stream = streams[-1]
|
|
445
|
+ else:
|
|
446
|
+ stream = streams[n]
|
|
447
|
+ else:
|
|
448
|
+ stream = streams[0]
|
|
449
|
+
|
|
450
|
+ stream = util.stream_change(stream)
|
|
451
|
+ title = stream["name"] if not "nfo" in stream or not stream["nfo"] else util.nfo2title(stream["nfo"])
|
|
452
|
+ desc = stream["desc"] if not "nfo" in stream or not stream["nfo"] else util.nfo2desc(stream["nfo"])
|
|
453
|
+ img = stream["img"]
|
|
454
|
+ url = stream["url"]
|
|
455
|
+ suburl = ""
|
|
456
|
+ print url
|
|
457
|
+ if "subs" in stream and stream["subs"]:
|
|
458
|
+ suburl = stream["subs"][0]["url"]
|
|
459
|
+ print "\n**Download subtitles %s - %s"%(title,suburl)
|
|
460
|
+ subs = urllib2.urlopen(suburl).read()
|
|
461
|
+ if subs:
|
|
462
|
+ fname0 = re.sub("[/\n\r\t,:\?]","_",title)
|
|
463
|
+ subext = ".srt"
|
|
464
|
+ subfile = os.path.join("",fname0+subext)
|
|
465
|
+ if ".xml" in suburl:
|
|
466
|
+ subs = ttaf2srt(subs)
|
|
467
|
+ with open(subfile,"w") as f:
|
|
468
|
+ f.write(subs)
|
|
469
|
+ else:
|
|
470
|
+ print "\n Error downloading subtitle %s"%suburl
|
|
471
|
+ print "\n**Play stream %s\n%s" % (title, url.encode("utf8"))
|
|
472
|
+ return player(url,title,suburl,stream["headers"])
|
|
473
|
+
|
|
474
|
+def player(url, title = "", suburl= "",headers={}):
|
|
475
|
+ from subprocess import call
|
|
476
|
+ cmd1 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url,
|
|
477
|
+ "--meta-title",title.decode("utf8").encode(sys.getfilesystemencoding()),
|
|
478
|
+ "--http-user-agent","Enigma2"
|
|
479
|
+ ]
|
|
480
|
+ # gst-launch-1.0 -v souphttpsrc ssl-strict=false proxy=127.0.0.1:8888 extra-headers="Origin:adadadasd" location="http://bitdash-a.akamaihd.net/content/sintel/sintel.mpd" ! decodebin! autovideosink
|
|
481
|
+ cmd2 = [
|
|
482
|
+ r"C:\gstreamer\1.0\x86_64\bin\gst-launch-1.0","-v",
|
|
483
|
+ "playbin", 'uri="%s"'%url,
|
|
484
|
+ #"souphttpsrc", "ssl-strict=false",
|
|
485
|
+ #"proxy=127.0.0.1:8888",
|
|
486
|
+ #'location="%s"'%url,
|
|
487
|
+ #'!decodebin!autovideosink'
|
|
488
|
+ ]
|
|
489
|
+ cmd3 = ["ffplay.exe",url]
|
|
490
|
+ cmd = cmd3 if url.startswith("https") else cmd2
|
|
491
|
+ ret = call(cmd)
|
|
492
|
+ #if ret:
|
|
493
|
+ #a = raw_input("*** Error, continue")
|
|
494
|
+ return
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+if __name__ == "__main__":
|
|
498
|
+ show_hidden = False
|
|
499
|
+ if len(sys.argv)>1:
|
|
500
|
+ data= sys.argv[1]
|
|
501
|
+ else:
|
|
502
|
+ data = "config::home"
|
|
503
|
+ #sources = ContentSources("sources")
|
|
504
|
+ sources = None
|
|
505
|
+ run(sources, data)
|