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

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