Python module (submodule repositary), which provides content (video streams) from various online stream sources to corresponding Enigma2, Kodi, Plex plugins

run.py 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  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. import PIL, StringIO
  12. from PIL import ImageTk, Image
  13. import requests, urllib2, tempfile
  14. from ContentSources import ContentSources
  15. from sources.SourceBase import stream_type
  16. import util
  17. cunicode = lambda s: s.decode("utf8") if isinstance(s, str) else s
  18. cstr = lambda s: s.encode("utf8") if isinstance(s, unicode) else s
  19. class Main(Frame):
  20. def __init__(self, sources, cfg_file="streams.cfg"):
  21. self.root = Tk()
  22. self.root.geometry("1050x600+100+0")
  23. Frame.__init__(self, self.root)
  24. img = PhotoImage(file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'icon.gif'))
  25. #img = PhotoImage(file= 'icon.gif')
  26. self.root.tk.call('wm', 'iconphoto', self.root._w, img)
  27. self.pack(fill=BOTH, expand=1)
  28. self.initUI()
  29. items = ["item %s" % i for i in range(20)]
  30. if sources:
  31. self.sources = sources
  32. else:
  33. self.sources = ContentSources("sources", cfg_file)
  34. self.picons_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "picons")
  35. #self.tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp")
  36. self.tmp_path = os.path.join(tempfile.gettempdir(), "playstream")
  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. def initUI(self):
  43. self.master.title("PlayStream")
  44. self.txt1 = Label(self)
  45. self.txt1.pack(side=TOP, fill=X, padx=15)
  46. self.txt1.configure(font=("Tahoma", 14, "bold"))
  47. self.txt1.config(text="")
  48. self.txt2 = Label(self)
  49. self.txt2.pack(side=TOP, fill=X, padx=15)
  50. self.txt2.config(text="")
  51. self.txt2.configure(font=("Tahoma", 12))
  52. frame1 = Frame(self)
  53. frame1.pack(side=TOP, fill=X, padx=15)
  54. scrollbar = Scrollbar(frame1, orient=VERTICAL)
  55. self.listbox = Listbox(frame1, width=80, height=30, yscrollcommand=scrollbar.set)
  56. scrollbar.config(command=self.listbox.yview)
  57. #self.listbox.config(yscrollcommand=scrollbar.set)
  58. self.listbox.pack(side=LEFT)
  59. scrollbar.pack(side=LEFT, fill=Y)
  60. self.listbox.focus_set()
  61. self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_action(evt, "Changed"))
  62. self.listbox.bind('<Double-1> ', lambda evt:self.list_action(None, "Return"))
  63. self.listbox.bind('<Key> ', self.list_action)
  64. self.pic = Canvas(frame1, width=400, height=250)
  65. self.pic.pack(side=TOP, expand=1)
  66. frame2 = Frame(frame1, height=250, width=400)
  67. frame2.pack(side=TOP)
  68. scrollbar2 = Scrollbar(frame2)
  69. self.desc = Text(frame2, height=15, width=70, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0)
  70. scrollbar2.config(command=self.desc.yview)
  71. scrollbar2.pack(side="right", fill="y")
  72. self.desc.configure(font=("Tahoma", 10))
  73. self.desc.pack(anchor=N)
  74. frame3 = Frame(self, height=40)
  75. frame3.pack(side=TOP, fill=X, padx=15)
  76. self.b_select = Button(frame3, text="Select",
  77. command=lambda :self.list_action(None, "Return"), width=10)
  78. self.b_select.pack(side=LEFT, anchor=S)
  79. self.b_back = Button(frame3, text="Back",
  80. command=lambda :self.list_action(None, "Escape"), width=10)
  81. self.b_back.pack(side=LEFT, anchor=S)
  82. self.b_options = Button(frame3, text="Options",
  83. command=lambda :self.list_action(None, "Options"), width=10)
  84. self.b_options.pack(side=LEFT, anchor=S)
  85. self.b_config = Button(frame3, text="Config",
  86. command=lambda :self.list_action(None, "Config"), width=10)
  87. self.b_config.pack(side=LEFT, anchor=S)
  88. self.b_exit = Button(frame3, text="Exit",
  89. command=self.quit, width=10)
  90. self.b_exit.pack(side=LEFT, anchor=S)
  91. def list_action(self, evt=None, key=None):
  92. try:
  93. cs = int(self.listbox.curselection()[0])
  94. except Exception as e:
  95. cs = 0
  96. self.cur_index = cs
  97. if (not key) and evt:
  98. w = evt.widget
  99. value = w.get(cs)
  100. key = evt.keysym
  101. #print 'Key: %s' % (key)
  102. data = self.content[cs][1]
  103. cur2 = self.content[cs]
  104. if key == "Changed":
  105. self.show_desc()
  106. self.show_pic()
  107. elif key == "Return" and data <> "back":
  108. if not self.sources.is_video(data):
  109. if "{0}" in data:
  110. a = tkd.askstring("Search", "Search for")
  111. cur2 = (cur2[0],cur2[1].format(a.encode("utf8")),cur2[2],cur2[3])
  112. self.history.append((self.cur, cs))
  113. self.cur = self.content[cs]
  114. self.cur_index = 0
  115. try:
  116. self.show_content(cur2)
  117. except Exception as e:
  118. print unicode(e)
  119. traceback.print_exc()
  120. tkm.showerror("Error getting content", unicode(e))
  121. prev = self.history.pop()
  122. self.cur = prev[0]
  123. self.cur_index = prev[1]
  124. self.show_content(self.cur, self.cur_index)
  125. return
  126. else:
  127. self.play_video(self.content[cs], select=0, show_info=True)
  128. self.listbox.selection_set(self.cur_index)
  129. self.listbox.activate(self.cur_index)
  130. self.listbox.focus_set()
  131. elif key == "BackSpace" or key == "Escape" or (key == "Return" and data == "back"):
  132. if self.history:
  133. prev = self.history.pop()
  134. self.cur = prev[0]
  135. self.cur_index = prev[1]
  136. self.show_content(self.cur, self.cur_index)
  137. elif key == "Right":
  138. index2 = self.cur_index + 20
  139. index2 = min(index2, self.listbox.index(END) - 1)
  140. self.set_list_item(index2)
  141. elif key == "Left":
  142. index2 = self.cur_index - 20
  143. index2 = max(index2, 0)
  144. self.set_list_item(index2)
  145. elif key in ("i", "I"):
  146. if self.sources.is_video(data):
  147. self.play_video(self.content[cs], select=0, show_info=True)
  148. else:
  149. a = VideoInfo(self.content[cs]).result
  150. self.listbox.selection_set(self.cur_index)
  151. self.listbox.activate(self.cur_index)
  152. self.listbox.focus_set()
  153. def set_list_item(self, index):
  154. self.cur_index = index
  155. self.listbox.selection_clear(0, END)
  156. self.listbox.selection_set(index)
  157. self.listbox.activate(index)
  158. self.listbox.focus_set()
  159. self.update()
  160. def show_content(self, cur2, cur_index=0):
  161. data = cur2[1]
  162. self.txt1.config(text=cur2[0])
  163. self.content = self.sources.get_content(data)
  164. self.listbox.delete(0, END)
  165. for item in self.content:
  166. self.listbox.insert(END, item[0])
  167. self.listbox.selection_set(cur_index)
  168. self.listbox.activate(cur_index)
  169. self.listbox.focus_set()
  170. self.show_desc()
  171. self.show_pic()
  172. def show_desc(self):
  173. cs = self.listbox.curselection()[0]
  174. self.txt2.config(text=self.content[cs][0])
  175. self.desc.config(state=NORMAL)
  176. self.desc.delete("1.0", END)
  177. self.desc.insert(END, self.content[cs][3])
  178. self.desc.insert(END, "\n\n"+self.content[cs][1])
  179. self.desc.insert(END, "\n"+self.content[cs][2])
  180. self.desc.config(state=DISABLED)
  181. def show_pic(self):
  182. cs = self.listbox.curselection()[0]
  183. img = self.content[cs][2]
  184. self.pic.delete(ALL)
  185. if not img:
  186. return
  187. if not img.startswith("http"):
  188. img_path = os.path.join(self.picons_path, img)
  189. if img and os.path.exists(img_path):
  190. im = Image.open(img_path)
  191. else:
  192. im = None
  193. print "No image found ", img_path
  194. elif img:
  195. fcache = img.replace(":", "_").replace("/", "-").replace(":", "_")
  196. fcache = os.path.join(self.tmp_path, fcache)
  197. if os.path.exists(fcache):
  198. im = Image.open(fcache)
  199. else:
  200. r = requests.get(img)
  201. if r.status_code == 200:
  202. img_data = r.content
  203. im = Image.open(StringIO.StringIO(r.content))
  204. with open(fcache, "wb") as f:
  205. f.write(r.content)
  206. else:
  207. im = None
  208. if im:
  209. try:
  210. im.thumbnail((400, 250))
  211. except Exception as e:
  212. print "Image convert error"
  213. image = ImageTk.PhotoImage(im)
  214. imagesprite = self.pic.create_image(200, 125,image=image)
  215. self.pic.image = image
  216. def play_video(self, cur2, select=None, show_info=False):
  217. if self.sources.stream_type(cur2[1]):
  218. stream = util.item()
  219. stream["url"] = cur2[1]
  220. stream["name"] = cur2[0]
  221. stream["desc"] = cur2[3]
  222. stream["img"] = cur2[2]
  223. streams = [stream]
  224. select = 0
  225. else:
  226. try:
  227. streams = self.sources.get_streams(cur2[1])
  228. except Exception as e:
  229. print unicode(e)
  230. traceback.print_exc()
  231. tkm.showerror("Error getting streams", unicode(e))
  232. return
  233. if not streams:
  234. tkm.showerror("Error getting streams", "No streams found")
  235. return
  236. if show_info: # Izsauc pilno Info logu
  237. a = VideoInfo(cur2, streams).result
  238. if a is None:
  239. return
  240. else:
  241. select = a
  242. else: # izvelās strimu no saraksta
  243. if select is None:
  244. if len(streams) > 1:
  245. lst = []
  246. for i,s in enumerate(streams):
  247. s = {k:v.decode("utf8") if v and isinstance(v, str) else v for k,v in zip(s.keys(), s.values())}
  248. lst.append(("[%s,%s] %s"%(s["lang"],s["quality"],s["name"]),i))
  249. a = ChoiceBox("ChoiceBox test", "Select stream", lst, parent=self, width=120).result
  250. if a is not None:
  251. select = a
  252. else:
  253. return
  254. else:
  255. select = 0
  256. stream = streams[select]
  257. play_stream(stream, self.tmp_path)
  258. def start(self):
  259. self.root.mainloop()
  260. class ChoiceBox(tkd.Dialog):
  261. #a = ChoiceBox("ChoiceBox test", "Select stream", items, parent=self).result
  262. def __init__(self, title, prompt, items, width=40, height=20,
  263. initialvalue=0, parent = None):
  264. if not parent:
  265. import Tkinter
  266. parent = Tkinter._default_root
  267. self.prompt = prompt
  268. self.items = items
  269. self.lwidth = width
  270. self.lheight = height
  271. self.result = None
  272. self.initialvalue = initialvalue
  273. tkd.Dialog.__init__(self, parent, title)
  274. def body(self, master):
  275. #self.width = 100
  276. #self.height = 100
  277. w = Label(self, text=self.prompt, justify=LEFT)
  278. w.pack(side=TOP)
  279. frame1 = Frame(self)
  280. frame1.pack(side=TOP, fill=X, expand=1, padx=5)
  281. scrollbar = Scrollbar(frame1, orient=VERTICAL)
  282. self.listbox = Listbox(frame1, yscrollcommand=scrollbar.set, width=self.lwidth, height=self.lheight)
  283. scrollbar.config(command=self.listbox.yview)
  284. #self.listbox.config(yscrollcommand=scrollbar.set)
  285. self.listbox.pack(side=LEFT, fill=BOTH, expand=1)
  286. scrollbar.pack(side=LEFT, fill=Y)
  287. for item in self.items:
  288. if isinstance(item, list) or isinstance(item, tuple):
  289. item = item[0]
  290. self.listbox.insert(END, item)
  291. self.listbox.selection_set(self.initialvalue)
  292. self.listbox.activate(self.initialvalue)
  293. self.listbox.bind('<Double-1> ', self.list_select)
  294. self.listbox.bind('<Key> ', self.list_key)
  295. self.update()
  296. self.geometry("+%d+%d"%(self.parent.winfo_rootx()+100, self.parent.winfo_rooty()+100 ))
  297. return self.listbox
  298. def list_key(self, evt):
  299. key = evt.keysym
  300. #print 'Key %s' % (key)
  301. if key == "Return":
  302. self.ok()
  303. elif key == "Escape":
  304. self.cancel()
  305. def list_select(self, evt):
  306. self.ok()
  307. def apply(self):
  308. self.result = self.listbox.curselection()[0]
  309. class VideoInfo(tkd.Dialog):
  310. #a = ChoiceBox("ChoiceBox test", "Select stream", items, parent=self).result
  311. def __init__(self, cur=None, streams=[], select=0, parent = None):
  312. if not parent:
  313. import Tkinter
  314. parent = Tkinter._default_root
  315. self.streams = streams
  316. self.subs = streams[0]["subs"] if len(streams) > 0 and "subs" in streams[0] else []
  317. self.select = select
  318. self.select2 = 0
  319. self.cur = cur
  320. if not streams:
  321. self.name = cur[0]
  322. self.data = cur[1]
  323. self.img = cur[2]
  324. self.desc = cur[3]
  325. else:
  326. self.name = streams[0]["name"]
  327. self.data = cur[1]
  328. self.img = streams[0]["img"]
  329. self.desc = streams[0]["desc"]
  330. self.picons_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "picons")
  331. self.tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp")
  332. self.result = None
  333. tkd.Dialog.__init__(self, parent, self.title)
  334. def body(self, master):
  335. # Virsraksts
  336. self.title("Item information")
  337. w = Label(self, text=self.name, justify=LEFT, font=("Tahoma", 14, "bold"))
  338. w.pack(side=TOP)
  339. frame0 = Frame(self, width=820, height=600) #, background="gray", borderwidth=2)
  340. frame0.pack(side=TOP)
  341. frame_l = Frame(frame0, width=410, height=600) #, background="red", borderwidth=2)
  342. frame_l.pack(side=LEFT)
  343. frame_r = Frame(frame0, width=410, height=600) #, background="green", borderwidth=2)
  344. frame_r.pack(side=LEFT)
  345. self.pic = Canvas(frame_l, width=400, height=400)
  346. self.pic.pack(side=TOP, expand=1, padx=5, pady=5)
  347. img = self.img
  348. if img:
  349. if not img.startswith("http"):
  350. img_path = os.path.join(self.picons_path, img)
  351. if img and os.path.exists(img_path):
  352. im = Image.open(img_path)
  353. else:
  354. im = None
  355. print "No image found ", img_path
  356. elif img:
  357. fcache = img.replace(":", "_").replace("/", "-").replace(":", "_")
  358. fcache = os.path.join(self.tmp_path, fcache)
  359. if os.path.exists(fcache):
  360. im = Image.open(fcache)
  361. else:
  362. r = requests.get(img)
  363. if r.status_code == 200:
  364. img_data = r.content
  365. im = Image.open(StringIO.StringIO(r.content))
  366. with open(fcache, "wb") as f:
  367. f.write(r.content)
  368. else:
  369. im = None
  370. if im:
  371. try:
  372. im.thumbnail((400, 400))
  373. except:
  374. print "Image convert error"
  375. image = ImageTk.PhotoImage(im)
  376. imagesprite = self.pic.create_image(200, 200,image=image)
  377. self.pic.image = image
  378. if self.streams or self.subs:
  379. Label(frame_l, text="Streams (%s)" % len(self.streams), justify=LEFT).pack(side=TOP)
  380. frame2 = Frame(frame_l, width=400, height=100)
  381. frame2.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  382. scrollbar = Scrollbar(frame2, orient=VERTICAL)
  383. self.listbox = Listbox(frame2, yscrollcommand=scrollbar.set, height=6) #, width=40, height=10)
  384. scrollbar.config(command=self.listbox.yview)
  385. #self.listbox.config(yscrollcommand=scrollbar.set)
  386. self.listbox.pack(side=LEFT, fill=BOTH, expand=1)
  387. scrollbar.pack(side=LEFT, fill=Y)
  388. lst = []
  389. for i,s in enumerate(self.streams):
  390. s = {k:v.decode("utf8") if v and isinstance(v, str) else v for k,v in zip(s.keys(), s.values())}
  391. item = "[%s,%s] %s"%(s["lang"],s["quality"],s["name"])
  392. self.listbox.insert(END, item)
  393. self.listbox.selection_set(self.select)
  394. self.listbox.activate(self.select)
  395. self.listbox.bind('<Double-1> ', self.list_select)
  396. self.listbox.bind('<Key> ', self.list_key)
  397. #self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_action(evt, "Changed"))
  398. self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_changed(evt, "Changed"))
  399. self.url_stream = Text(frame_l, height=1, width=10, font=("Tahoma", 10))
  400. self.url_stream.pack(fill=X, expand=1, padx=5, pady=5)
  401. self.url_stream.config(state=NORMAL)
  402. self.url_stream.insert(END, self.streams[self.select]["url"])
  403. self.url_stream.config(state=DISABLED)
  404. frame_desc = Frame(frame_r, height=400, width=400)
  405. frame_desc.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  406. scrollbar2 = Scrollbar(frame_desc)
  407. desc = Text(frame_desc, height=25, width=55, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0)
  408. scrollbar2.config(command=desc.yview)
  409. scrollbar2.pack(side="right", fill="y")
  410. desc.configure(font=("Tahoma", 10))
  411. desc.pack(side=TOP)
  412. desc.insert(END, self.desc)
  413. desc.insert(END, "\n\n"+self.cur[1])
  414. desc.insert(END, "\n"+self.cur[2])
  415. desc.config(state=DISABLED)
  416. if self.streams or self.subs:
  417. Label(frame_r, text="Subtitles (%s)" % len(self.subs), justify=LEFT).pack(side=TOP)
  418. frame_sub = Frame(frame_r, width=400, height=100)
  419. frame_sub.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  420. scrollbar3 = Scrollbar(frame_sub, orient=VERTICAL)
  421. self.listbox2 = Listbox(frame_sub, yscrollcommand=scrollbar3.set, height=6) #, width=40, height=10)
  422. scrollbar.config(command=self.listbox2.yview)
  423. #self.listbox.config(yscrollcommand=scrollbar.set)
  424. self.listbox2.pack(side=LEFT, fill=BOTH, expand=1)
  425. scrollbar3.pack(side=LEFT, fill=Y)
  426. for i,s in enumerate(self.subs):
  427. if not len(s):continue
  428. item = ("%s - %s"%(s["lang"],s["name"])).encode("utf8")
  429. self.listbox2.insert(END, item)
  430. #self.listbox2.bind('<Double-1> ', self.list_select)
  431. #self.listbox2.bind('<Key> ', self.list_key)
  432. #self.listbox2.selection_set(self.select)
  433. self.listbox2.bind('<<ListboxSelect>>', lambda evt: self.list_changed2(evt, "Changed"))
  434. self.url_sub = Text(frame_r, height=1, width=10, font=("Tahoma", 10))
  435. self.url_sub.pack(fill=X, expand=1, padx=5, pady=5)
  436. if self.subs:
  437. self.url_sub.config(state=NORMAL)
  438. self.url_sub.insert(END, self.subs[self.select]["url"])
  439. self.url_sub.config(state=DISABLED)
  440. #self.update()
  441. #self.geometry("+%d+%d"%(self.parent.winfo_rootx()+0, self.parent.winfo_rooty()+0 ))
  442. #self. geometry('+10+10')
  443. return self.listbox if "listbox" in dir(self) else None
  444. def buttonbox(self):
  445. box = Frame(self)
  446. w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
  447. w.pack(side=LEFT, padx=5, pady=5)
  448. w = Button(box, text="Cancel", width=10, command=self.cancel)
  449. w.pack(side=LEFT, padx=5, pady=5)
  450. self.bind("<Return>", self.ok)
  451. self.bind("<Escape>", self.cancel)
  452. box.pack()
  453. def list_key(self, evt):
  454. key = evt.keysym
  455. #print 'Key %s' % (key)
  456. if key == "Return":
  457. self.ok()
  458. elif key == "Escape":
  459. self.cancel()
  460. def list_changed(self, evt, key):
  461. self.select = evt.widget.curselection()[0]
  462. self.url_stream.config(state=NORMAL)
  463. self.url_stream.delete("1.0", END)
  464. self.url_stream.insert(END, self.streams[self.select]["url"])
  465. self.url_stream.config(state=DISABLED)
  466. def list_changed2(self, evt, key):
  467. self.select2 = evt.widget.curselection()[0]
  468. self.url_sub.config(state=NORMAL)
  469. self.url_sub.delete("1.0", END)
  470. self.url_sub.insert(END, self.streams[self.select2]["url"])
  471. self.url_sub.config(state=DISABLED)
  472. def list_select(self, evt):
  473. self.ok()
  474. def apply(self):
  475. self.result = self.listbox.curselection()[0]
  476. def run(sources=None, data="config::home", title="Home", cfg_file="streams.cfg"):
  477. app = Main(sources, cfg_file=cfg_file)
  478. app.show_content((title, data, "", ""))
  479. app.start()
  480. def run_cli(sources, data="config::home", title="Home", cfg_file="streams.cfg"):
  481. #options = sources.options_read("ltc")
  482. #print options
  483. history = []
  484. cur = ("Home",data,None,None)
  485. content = sources.get_content(cur[1])
  486. exit_loop = False
  487. while True:
  488. print
  489. for i,item in enumerate(content):
  490. s = "%i: %s - %s %s"%(i,item[0],item[1],item[2])
  491. print s #.encode(sys.stdout.encoding,"replace")
  492. while True:
  493. a = raw_input("Enter number, (-) for download, q for exit: ")
  494. if a in ("q","Q","x","X"):
  495. exit_loop = True
  496. print "Exiting"
  497. break
  498. try:
  499. n = int(a)
  500. break
  501. except:
  502. print "Not number!"
  503. if exit_loop: break
  504. download = False
  505. if n<0:
  506. n = abs(n)
  507. download = True
  508. cur2 = content[n]
  509. data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
  510. if not data0:
  511. pass
  512. elif cur2[1] == "back":
  513. cur = history.pop()
  514. elif sources.is_video(cur2[1]):
  515. if sources.stream_type(cur2[1]):
  516. stream = util.item()
  517. stream["url"] = cur2[1]
  518. stream["name"] = cur2[0]
  519. streams = [stream]
  520. else:
  521. try:
  522. if not download:
  523. streams = sources.get_streams(cur2[1])
  524. else:
  525. stream = util.item()
  526. stream["url"] = cur2[1]
  527. stream["name"] = cur2[0]
  528. stream["url"] = util.streamproxy_encode2(stream["url"])
  529. print stream["url"]
  530. streams = [stream]
  531. except Exception as e:
  532. print unicode(e)
  533. traceback.print_exc()
  534. streams = []
  535. if streams:
  536. if not download:
  537. play_video(streams)
  538. else:
  539. #urlp = util.streamproxy_encode2(streams[0]["url"])
  540. #print urlp
  541. #util.player(urlp)
  542. #Downloader.download_video(streams)
  543. pass
  544. else:
  545. print "**No stream to play - %s "%(
  546. cur2[1])
  547. raw_input("Press any key")
  548. #import os
  549. #os.system('"c:\Program Files (x86)\VideoLAN\VLC\vlc.exe" "%s"'%cur2[1])
  550. else:
  551. if "{0}" in cur2[1]:
  552. a = raw_input("Enter value:")
  553. cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3])
  554. history.append(cur)
  555. cur = cur2
  556. try:
  557. content = sources.get_content(cur[1])
  558. except Exception as e:
  559. print unicode(e)
  560. traceback.print_exc()
  561. raw_input("Continue?")
  562. def play_video(streams, select=None):
  563. if select is None:
  564. if len(streams)>1:
  565. for i,s in enumerate(streams):
  566. print "%s: [%s,%s,%s] %s"%(i,s["quality"],s["lang"],s["type"],s["name"])
  567. a = raw_input("Select stram to play: ")
  568. try:
  569. select = int(a)
  570. if select>=len(streams):
  571. select = len(streams) - 1
  572. except:
  573. select = None
  574. else:
  575. select = 0
  576. if select is not None:
  577. play_stream(streams[select])
  578. def play_stream(stream, tmp_path=""):
  579. if not tmp_path:
  580. tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp")
  581. stream = util.stream_change(stream)
  582. title = stream["name"] if not "nfo" in stream or not stream["nfo"] else util.nfo2title(stream["nfo"])
  583. desc = stream["desc"] if not "nfo" in stream or not stream["nfo"] else util.nfo2desc(stream["nfo"])
  584. img = stream["img"]
  585. url = stream["url"]
  586. suburl = ""
  587. subfile = ""
  588. print url
  589. if "subs" in stream and len(stream["subs"]) > 0 and stream["subs"][0]:
  590. suburl = stream["subs"][0]["url"]
  591. subfile = ""
  592. print "\n**Download subtitles %s - %s"%(title,suburl)
  593. try:
  594. subs = urllib2.urlopen(suburl).read()
  595. except:
  596. subs = None
  597. if subs:
  598. fname0 = re.sub("[/\n\r\t,:\?\|'~\.]","_",title)
  599. if ".xml" in suburl:
  600. subs = util.ttaf2srt(subs)
  601. subext = ".srt"
  602. elif ".vtt" in suburl:
  603. subext = ".vtt"
  604. elif ".srt" in suburl:
  605. subext = ".srt"
  606. else:
  607. subext = ""
  608. if subext:
  609. subfile = cunicode(os.path.join(tmp_path,fname0+subext))
  610. with open(subfile,"w") as f:
  611. f.write(subs)
  612. else:
  613. print "\n Error downloading subtitle %s"%suburl
  614. print "\n**Play stream %s\n%s" % (title, url.encode("utf8"))
  615. player(url,title,subfile,stream["headers"])
  616. def player(url, title = "", subfile = "",headers={}, player="ffplay"):
  617. from subprocess import call
  618. title = cunicode(title).encode(sys.getfilesystemencoding())
  619. url = cunicode(url).encode(sys.getfilesystemencoding())
  620. # encode(sys.getfilesystemencoding())
  621. subfile = unicode(subfile).encode(sys.getfilesystemencoding())
  622. cmd1 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url,
  623. "--meta-title",title,
  624. "--http-user-agent","Enigma2"
  625. ]
  626. # 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
  627. cmd2 = [
  628. r"C:\gstreamer\1.0\x86_64\bin\gst-launch-1.0",
  629. #"-v",
  630. "playbin", 'uri="%s"'%url,
  631. #"souphttpsrc", "ssl-strict=false",
  632. #"proxy=127.0.0.1:8888",
  633. #'location="%s"'%url,
  634. #'!decodebin!autovideosink'
  635. ]
  636. vf = r"drawtext=text='%{pts\:hms}':box=1:x=w-tw-10:y=h-th-10:boxcolor=black@0.5:fontsize=20:fontcolor=white"
  637. if subfile and os.path.exists(subfile):
  638. subfile = subfile.replace("\\", "\\\\\\\\")
  639. subfile = re.sub("\w:", "", subfile)
  640. vf = 'subtitles=%s,' % subfile + vf
  641. cmd3 = ["ffplay.exe",url, "-window_title", title, "-vf", vf]
  642. if not player:
  643. cmd = cmd3 if url.startswith("https") else cmd2
  644. else:
  645. cmd = cmd3 if player == "ffplay" else cmd2
  646. #cmd = cmd2 # visu spēlē ar gst
  647. ret = call(cmd)
  648. #if ret:
  649. #a = raw_input("*** Error, continue")
  650. return
  651. if __name__ == "__main__":
  652. show_hidden = False
  653. data= sys.argv[1] if len(sys.argv) > 1 else "config::home"
  654. cfg_file = sys.argv[2] if len(sys.argv) > 2 else "streams.cfg"
  655. #sources = ContentSources("sources")
  656. sources = None
  657. run(sources, data, cfg_file=cfg_file)