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

run.py 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. #!/usr/bin/env python
  2. # coding=utf8
  3. import sys, os, traceback, tempfile
  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 = tempfile.gettempdir() #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 = fcache.split("?")[0]
  359. fcache = os.path.join(self.tmp_path, fcache)
  360. if os.path.exists(fcache):
  361. im = Image.open(fcache)
  362. else:
  363. r = requests.get(img)
  364. if r.status_code == 200:
  365. img_data = r.content
  366. im = Image.open(StringIO.StringIO(r.content))
  367. with open(fcache, "wb") as f:
  368. f.write(r.content)
  369. else:
  370. im = None
  371. if im:
  372. try:
  373. im.thumbnail((400, 400))
  374. except:
  375. print "Image convert error"
  376. image = ImageTk.PhotoImage(im)
  377. imagesprite = self.pic.create_image(200, 200,image=image)
  378. self.pic.image = image
  379. if self.streams or self.subs:
  380. Label(frame_l, text="Streams (%s)" % len(self.streams), justify=LEFT).pack(side=TOP)
  381. frame2 = Frame(frame_l, width=400, height=100)
  382. frame2.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  383. scrollbar = Scrollbar(frame2, orient=VERTICAL)
  384. self.listbox = Listbox(frame2, yscrollcommand=scrollbar.set, height=6) #, width=40, height=10)
  385. scrollbar.config(command=self.listbox.yview)
  386. #self.listbox.config(yscrollcommand=scrollbar.set)
  387. self.listbox.pack(side=LEFT, fill=BOTH, expand=1)
  388. scrollbar.pack(side=LEFT, fill=Y)
  389. lst = []
  390. for i,s in enumerate(self.streams):
  391. s = {k:v.decode("utf8") if v and isinstance(v, str) else v for k,v in zip(s.keys(), s.values())}
  392. item = "[%s,%s] %s"%(s["lang"],s["quality"],s["name"])
  393. self.listbox.insert(END, item)
  394. self.listbox.selection_set(self.select)
  395. self.listbox.activate(self.select)
  396. self.listbox.bind('<Double-1> ', self.list_select)
  397. self.listbox.bind('<Key> ', self.list_key)
  398. #self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_action(evt, "Changed"))
  399. self.listbox.bind('<<ListboxSelect>>', lambda evt: self.list_changed(evt, "Changed"))
  400. self.url_stream = Text(frame_l, height=1, width=10, font=("Tahoma", 10))
  401. self.url_stream.pack(fill=X, expand=1, padx=5, pady=5)
  402. self.url_stream.config(state=NORMAL)
  403. self.url_stream.insert(END, self.streams[self.select]["url"])
  404. self.url_stream.config(state=DISABLED)
  405. frame_desc = Frame(frame_r, height=400, width=400)
  406. frame_desc.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  407. scrollbar2 = Scrollbar(frame_desc)
  408. desc = Text(frame_desc, height=25, width=55, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0)
  409. scrollbar2.config(command=desc.yview)
  410. scrollbar2.pack(side="right", fill="y")
  411. desc.configure(font=("Tahoma", 10))
  412. desc.pack(side=TOP)
  413. desc.insert(END, self.desc)
  414. desc.insert(END, "\n\n"+self.cur[1])
  415. desc.insert(END, "\n"+self.cur[2])
  416. desc.config(state=DISABLED)
  417. if self.streams or self.subs:
  418. Label(frame_r, text="Subtitles (%s)" % len(self.subs), justify=LEFT).pack(side=TOP)
  419. frame_sub = Frame(frame_r, width=400, height=100)
  420. frame_sub.pack(side=TOP, fill=X, expand=1, padx=5, pady=5)
  421. scrollbar3 = Scrollbar(frame_sub, orient=VERTICAL)
  422. self.listbox2 = Listbox(frame_sub, yscrollcommand=scrollbar3.set, height=6) #, width=40, height=10)
  423. scrollbar.config(command=self.listbox2.yview)
  424. #self.listbox.config(yscrollcommand=scrollbar.set)
  425. self.listbox2.pack(side=LEFT, fill=BOTH, expand=1)
  426. scrollbar3.pack(side=LEFT, fill=Y)
  427. for i,s in enumerate(self.subs):
  428. if not len(s):continue
  429. item = ("%s - %s"%(s["lang"],s["name"])).encode("utf8")
  430. self.listbox2.insert(END, item)
  431. #self.listbox2.bind('<Double-1> ', self.list_select)
  432. #self.listbox2.bind('<Key> ', self.list_key)
  433. #self.listbox2.selection_set(self.select)
  434. self.listbox2.bind('<<ListboxSelect>>', lambda evt: self.list_changed2(evt, "Changed"))
  435. self.url_sub = Text(frame_r, height=1, width=10, font=("Tahoma", 10))
  436. self.url_sub.pack(fill=X, expand=1, padx=5, pady=5)
  437. if self.subs:
  438. self.url_sub.config(state=NORMAL)
  439. self.url_sub.insert(END, self.subs[self.select]["url"])
  440. self.url_sub.config(state=DISABLED)
  441. #self.update()
  442. #self.geometry("+%d+%d"%(self.parent.winfo_rootx()+0, self.parent.winfo_rooty()+0 ))
  443. #self. geometry('+10+10')
  444. return self.listbox if "listbox" in dir(self) else None
  445. def buttonbox(self):
  446. box = Frame(self)
  447. w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
  448. w.pack(side=LEFT, padx=5, pady=5)
  449. w = Button(box, text="Cancel", width=10, command=self.cancel)
  450. w.pack(side=LEFT, padx=5, pady=5)
  451. self.bind("<Return>", self.ok)
  452. self.bind("<Escape>", self.cancel)
  453. box.pack()
  454. def list_key(self, evt):
  455. key = evt.keysym
  456. #print 'Key %s' % (key)
  457. if key == "Return":
  458. self.ok()
  459. elif key == "Escape":
  460. self.cancel()
  461. def list_changed(self, evt, key):
  462. self.select = evt.widget.curselection()[0]
  463. self.url_stream.config(state=NORMAL)
  464. self.url_stream.delete("1.0", END)
  465. self.url_stream.insert(END, self.streams[self.select]["url"])
  466. self.url_stream.config(state=DISABLED)
  467. def list_changed2(self, evt, key):
  468. self.select2 = evt.widget.curselection()[0]
  469. self.url_sub.config(state=NORMAL)
  470. self.url_sub.delete("1.0", END)
  471. self.url_sub.insert(END, self.streams[self.select2]["url"])
  472. self.url_sub.config(state=DISABLED)
  473. def list_select(self, evt):
  474. self.ok()
  475. def apply(self):
  476. self.result = self.listbox.curselection()[0]
  477. def run(sources=None, data="config::home", title="Home", cfg_file="streams.cfg"):
  478. app = Main(sources, cfg_file=cfg_file)
  479. app.show_content((title, data, "", ""))
  480. app.start()
  481. def run_cli(sources, data="config::home", title="Home", cfg_file="streams.cfg"):
  482. #options = sources.options_read("ltc")
  483. #print options
  484. history = []
  485. cur = ("Home",data,None,None)
  486. content = sources.get_content(cur[1])
  487. exit_loop = False
  488. while True:
  489. print
  490. for i,item in enumerate(content):
  491. s = "%i: %s - %s %s"%(i,item[0],item[1],item[2])
  492. print s #.encode(sys.stdout.encoding,"replace")
  493. while True:
  494. a = raw_input("Enter number, (-) for download, q for exit: ")
  495. if a in ("q","Q","x","X"):
  496. exit_loop = True
  497. print "Exiting"
  498. break
  499. try:
  500. n = int(a)
  501. break
  502. except:
  503. print "Not number!"
  504. if exit_loop: break
  505. download = False
  506. if n<0:
  507. n = abs(n)
  508. download = True
  509. cur2 = content[n]
  510. data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
  511. if not data0:
  512. pass
  513. elif cur2[1] == "back":
  514. cur = history.pop()
  515. elif sources.is_video(cur2[1]):
  516. if sources.stream_type(cur2[1]):
  517. stream = util.item()
  518. stream["url"] = cur2[1]
  519. stream["name"] = cur2[0]
  520. streams = [stream]
  521. else:
  522. try:
  523. if not download:
  524. streams = sources.get_streams(cur2[1])
  525. else:
  526. stream = util.item()
  527. stream["url"] = cur2[1]
  528. stream["name"] = cur2[0]
  529. stream["url"] = util.streamproxy_encode2(stream["url"])
  530. print stream["url"]
  531. streams = [stream]
  532. except Exception as e:
  533. print unicode(e)
  534. traceback.print_exc()
  535. streams = []
  536. if streams:
  537. if not download:
  538. play_video(streams)
  539. else:
  540. #urlp = util.streamproxy_encode2(streams[0]["url"])
  541. #print urlp
  542. #util.player(urlp)
  543. #Downloader.download_video(streams)
  544. pass
  545. else:
  546. print "**No stream to play - %s "%(
  547. cur2[1])
  548. raw_input("Press any key")
  549. #import os
  550. #os.system('"c:\Program Files (x86)\VideoLAN\VLC\vlc.exe" "%s"'%cur2[1])
  551. else:
  552. if "{0}" in cur2[1]:
  553. a = raw_input("Enter value:")
  554. cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3])
  555. history.append(cur)
  556. cur = cur2
  557. try:
  558. content = sources.get_content(cur[1])
  559. except Exception as e:
  560. print unicode(e)
  561. traceback.print_exc()
  562. raw_input("Continue?")
  563. def play_video(streams, select=None):
  564. if select is None:
  565. if len(streams)>1:
  566. for i,s in enumerate(streams):
  567. print "%s: [%s,%s,%s] %s"%(i,s["quality"],s["lang"],s["type"],s["name"])
  568. a = raw_input("Select stram to play: ")
  569. try:
  570. select = int(a)
  571. if select>=len(streams):
  572. select = len(streams) - 1
  573. except:
  574. select = None
  575. else:
  576. select = 0
  577. if select is not None:
  578. play_stream(streams[select])
  579. def play_stream(stream, tmp_path=""):
  580. if not tmp_path:
  581. tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp")
  582. stream = util.stream_change(stream)
  583. title = stream["name"] if not "nfo" in stream or not stream["nfo"] else util.nfo2title(stream["nfo"])
  584. desc = stream["desc"] if not "nfo" in stream or not stream["nfo"] else util.nfo2desc(stream["nfo"])
  585. img = stream["img"]
  586. url = stream["url"]
  587. suburl = ""
  588. subfile = ""
  589. print url
  590. if "subs" in stream and len(stream["subs"]) > 0 and stream["subs"][0]:
  591. suburl = stream["subs"][0]["url"]
  592. subfile = ""
  593. print "\n**Download subtitles %s - %s"%(title,suburl)
  594. try:
  595. subs = urllib2.urlopen(suburl).read()
  596. except:
  597. subs = None
  598. if subs:
  599. fname0 = re.sub("[/\n\r\t,:\?\|'~\.]","_",title)
  600. if ".xml" in suburl:
  601. subs = util.ttaf2srt(subs)
  602. subext = ".srt"
  603. elif ".vtt" in suburl:
  604. subext = ".vtt"
  605. elif ".srt" in suburl:
  606. subext = ".srt"
  607. else:
  608. subext = ""
  609. if subext:
  610. subfile = cunicode(os.path.join(tmp_path,fname0+subext))
  611. with open(subfile,"w") as f:
  612. f.write(subs)
  613. else:
  614. print "\n Error downloading subtitle %s"%suburl
  615. print "\n**Play stream %s\n%s" % (title, url.encode("utf8"))
  616. player(url,title,subfile,stream["headers"])
  617. def player(url, title = "", subfile = "",headers={}, player="ffplay"):
  618. from subprocess import call
  619. title = cunicode(title).encode(sys.getfilesystemencoding())
  620. url = cunicode(url).encode(sys.getfilesystemencoding())
  621. # encode(sys.getfilesystemencoding())
  622. subfile = unicode(subfile).encode(sys.getfilesystemencoding())
  623. cmd1 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url,
  624. "--meta-title",title,
  625. "--http-user-agent","Enigma2"
  626. ]
  627. # 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
  628. cmd2 = [
  629. r"C:\gstreamer\1.0\x86_64\bin\gst-launch-1.0",
  630. #"-v",
  631. "playbin", 'uri="%s"'%url,
  632. #"souphttpsrc", "ssl-strict=false",
  633. #"proxy=127.0.0.1:8888",
  634. #'location="%s"'%url,
  635. #'!decodebin!autovideosink'
  636. ]
  637. vf = r"drawtext=text='%{pts\:hms}':box=1:x=w-tw-10:y=h-th-10:boxcolor=black@0.5:fontsize=20:fontcolor=white"
  638. if subfile and os.path.exists(subfile):
  639. subfile = subfile.replace("\\", "\\\\\\\\")
  640. subfile = re.sub("\w:", "", subfile)
  641. vf = 'subtitles=%s,' % subfile + vf
  642. cmd3 = ["c:\\Util\\ffplay.exe",url, "-window_title", title, "-vf", vf]
  643. if headers:
  644. cmd3.append("-headers")
  645. hd = []
  646. for k in headers:
  647. hd.append("%s:%s" % (k, headers[k]))
  648. hd = "\n".join(hd)
  649. cmd3.append(hd)
  650. if not player:
  651. cmd = cmd3 if url.startswith("https") else cmd2
  652. else:
  653. cmd = cmd3 if player == "ffplay" else cmd2
  654. #cmd = cmd2 # visu spēlē ar gst
  655. ret = call(cmd)
  656. #if ret:
  657. #a = raw_input("*** Error, continue")
  658. return
  659. if __name__ == "__main__":
  660. show_hidden = False
  661. data= sys.argv[1] if len(sys.argv) > 1 else "config::home"
  662. cfg_file = sys.argv[2] if len(sys.argv) > 2 else "streams.cfg"
  663. #sources = ContentSources("sources")
  664. sources = None
  665. run(sources, data, cfg_file=cfg_file)