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

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