#!/usr/bin/env python # coding=utf8 import sys, os, traceback, tempfile from Tkinter import * #try: # from ttk import * #except: # pass import tkMessageBox as tkm import tkSimpleDialog as tkd import PIL, StringIO from PIL import ImageTk, Image import requests, urllib2, tempfile from ContentSources import ContentSources from sources.SourceBase import stream_type import util cunicode = lambda s: s.decode("utf8") if isinstance(s, str) else s cstr = lambda s: s.encode("utf8") if isinstance(s, unicode) else s class Main(Frame): def __init__(self, sources, cfg_file="streams.cfg"): self.root = Tk() self.root.geometry("1050x600+100+0") Frame.__init__(self, self.root) img = PhotoImage(file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'icon.gif')) #img = PhotoImage(file= 'icon.gif') self.root.tk.call('wm', 'iconphoto', self.root._w, img) self.pack(fill=BOTH, expand=1) self.initUI() items = ["item %s" % i for i in range(20)] if sources: self.sources = sources else: self.sources = ContentSources("sources", cfg_file) self.picons_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "picons") #self.tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp") self.tmp_path = os.path.join(tempfile.gettempdir(), "playstream") if not os.path.exists(self.tmp_path): os.mkdir(self.tmp_path) self.history = [] self.cur_index = 0 self.cur = ("Home", "config::home", "", "PlayStream home") def initUI(self): self.master.title("PlayStream") self.txt1 = Label(self) self.txt1.pack(side=TOP, fill=X, padx=15) self.txt1.configure(font=("Tahoma", 14, "bold")) self.txt1.config(text="") self.txt2 = Label(self) self.txt2.pack(side=TOP, fill=X, padx=15) self.txt2.config(text="") self.txt2.configure(font=("Tahoma", 12)) frame1 = Frame(self) frame1.pack(side=TOP, fill=X, padx=15) scrollbar = Scrollbar(frame1, orient=VERTICAL) self.listbox = Listbox(frame1, width=80, height=30, yscrollcommand=scrollbar.set) scrollbar.config(command=self.listbox.yview) #self.listbox.config(yscrollcommand=scrollbar.set) self.listbox.pack(side=LEFT) scrollbar.pack(side=LEFT, fill=Y) self.listbox.focus_set() self.listbox.bind('<>', lambda evt: self.list_action(evt, "Changed")) self.listbox.bind(' ', lambda evt:self.list_action(None, "Return")) self.listbox.bind(' ', self.list_action) self.pic = Canvas(frame1, width=400, height=250) self.pic.pack(side=TOP, expand=1) frame2 = Frame(frame1, height=250, width=400) frame2.pack(side=TOP) scrollbar2 = Scrollbar(frame2) self.desc = Text(frame2, height=15, width=70, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0) scrollbar2.config(command=self.desc.yview) scrollbar2.pack(side="right", fill="y") self.desc.configure(font=("Tahoma", 10)) self.desc.pack(anchor=N) frame3 = Frame(self, height=40) frame3.pack(side=TOP, fill=X, padx=15) self.b_select = Button(frame3, text="Select", command=lambda :self.list_action(None, "Return"), width=10) self.b_select.pack(side=LEFT, anchor=S) self.b_back = Button(frame3, text="Back", command=lambda :self.list_action(None, "Escape"), width=10) self.b_back.pack(side=LEFT, anchor=S) self.b_options = Button(frame3, text="Options", command=lambda :self.list_action(None, "Options"), width=10) self.b_options.pack(side=LEFT, anchor=S) self.b_config = Button(frame3, text="Config", command=lambda :self.list_action(None, "Config"), width=10) self.b_config.pack(side=LEFT, anchor=S) self.b_exit = Button(frame3, text="Exit", command=self.quit, width=10) self.b_exit.pack(side=LEFT, anchor=S) def list_action(self, evt=None, key=None): try: cs = int(self.listbox.curselection()[0]) except Exception as e: cs = 0 self.cur_index = cs if (not key) and evt: w = evt.widget value = w.get(cs) key = evt.keysym #print 'Key: %s' % (key) data = self.content[cs][1] cur2 = self.content[cs] if key == "Changed": self.show_desc() self.show_pic() elif key == "Return" and data <> "back": if not self.sources.is_video(data): if "{0}" in data: a = tkd.askstring("Search", "Search for") cur2 = (cur2[0],cur2[1].format(a.encode("utf8")),cur2[2],cur2[3]) self.history.append((self.cur, cs)) self.cur = self.content[cs] self.cur_index = 0 try: self.show_content(cur2) except Exception as e: print unicode(e) traceback.print_exc() tkm.showerror("Error getting content", unicode(e)) prev = self.history.pop() self.cur = prev[0] self.cur_index = prev[1] self.show_content(self.cur, self.cur_index) return else: self.play_video(self.content[cs], select=0, show_info=True) self.listbox.selection_set(self.cur_index) self.listbox.activate(self.cur_index) self.listbox.focus_set() elif key == "BackSpace" or key == "Escape" or (key == "Return" and data == "back"): if self.history: prev = self.history.pop() self.cur = prev[0] self.cur_index = prev[1] self.show_content(self.cur, self.cur_index) elif key == "Right": index2 = self.cur_index + 20 index2 = min(index2, self.listbox.index(END) - 1) self.set_list_item(index2) elif key == "Left": index2 = self.cur_index - 20 index2 = max(index2, 0) self.set_list_item(index2) elif key in ("i", "I"): if self.sources.is_video(data): self.play_video(self.content[cs], select=0, show_info=True) else: a = VideoInfo(self.content[cs]).result self.listbox.selection_set(self.cur_index) self.listbox.activate(self.cur_index) self.listbox.focus_set() def set_list_item(self, index): self.cur_index = index self.listbox.selection_clear(0, END) self.listbox.selection_set(index) self.listbox.activate(index) self.listbox.focus_set() self.update() def show_content(self, cur2, cur_index=0): data = cur2[1] self.txt1.config(text=cur2[0]) self.content = self.sources.get_content(data) self.listbox.delete(0, END) for item in self.content: self.listbox.insert(END, item[0]) self.listbox.selection_set(cur_index) self.listbox.activate(cur_index) self.listbox.focus_set() self.show_desc() self.show_pic() def show_desc(self): cs = self.listbox.curselection()[0] self.txt2.config(text=self.content[cs][0]) self.desc.config(state=NORMAL) self.desc.delete("1.0", END) self.desc.insert(END, self.content[cs][3]) self.desc.insert(END, "\n\n"+self.content[cs][1]) self.desc.insert(END, "\n"+self.content[cs][2]) self.desc.config(state=DISABLED) def show_pic(self): cs = self.listbox.curselection()[0] img = self.content[cs][2] self.pic.delete(ALL) if not img: return if not img.startswith("http"): img_path = os.path.join(self.picons_path, img) if img and os.path.exists(img_path): im = Image.open(img_path) else: im = None print "No image found ", img_path elif img: fcache = img.replace(":", "_").replace("/", "-").replace(":", "_") fcache = os.path.join(self.tmp_path, fcache) if os.path.exists(fcache): im = Image.open(fcache) else: r = requests.get(img) if r.status_code == 200: img_data = r.content im = Image.open(StringIO.StringIO(r.content)) with open(fcache, "wb") as f: f.write(r.content) else: im = None if im: try: im.thumbnail((400, 250)) except Exception as e: print "Image convert error" image = ImageTk.PhotoImage(im) imagesprite = self.pic.create_image(200, 125,image=image) self.pic.image = image def play_video(self, cur2, select=None, show_info=False): if self.sources.stream_type(cur2[1]): stream = util.item() stream["url"] = cur2[1] stream["name"] = cur2[0] stream["desc"] = cur2[3] stream["img"] = cur2[2] streams = [stream] select = 0 else: try: streams = self.sources.get_streams(cur2[1]) except Exception as e: print unicode(e) traceback.print_exc() tkm.showerror("Error getting streams", unicode(e)) return if not streams: tkm.showerror("Error getting streams", "No streams found") return if show_info: # Izsauc pilno Info logu a = VideoInfo(cur2, streams).result if a is None: return else: select = a else: # izvelās strimu no saraksta if select is None: if len(streams) > 1: lst = [] for i,s in enumerate(streams): s = {k:v.decode("utf8") if v and isinstance(v, str) else v for k,v in zip(s.keys(), s.values())} lst.append(("[%s,%s] %s"%(s["lang"],s["quality"],s["name"]),i)) a = ChoiceBox("ChoiceBox test", "Select stream", lst, parent=self, width=120).result if a is not None: select = a else: return else: select = 0 stream = streams[select] play_stream(stream, self.tmp_path) def start(self): self.root.mainloop() class ChoiceBox(tkd.Dialog): #a = ChoiceBox("ChoiceBox test", "Select stream", items, parent=self).result def __init__(self, title, prompt, items, width=40, height=20, initialvalue=0, parent = None): if not parent: import Tkinter parent = Tkinter._default_root self.prompt = prompt self.items = items self.lwidth = width self.lheight = height self.result = None self.initialvalue = initialvalue tkd.Dialog.__init__(self, parent, title) def body(self, master): #self.width = 100 #self.height = 100 w = Label(self, text=self.prompt, justify=LEFT) w.pack(side=TOP) frame1 = Frame(self) frame1.pack(side=TOP, fill=X, expand=1, padx=5) scrollbar = Scrollbar(frame1, orient=VERTICAL) self.listbox = Listbox(frame1, yscrollcommand=scrollbar.set, width=self.lwidth, height=self.lheight) scrollbar.config(command=self.listbox.yview) #self.listbox.config(yscrollcommand=scrollbar.set) self.listbox.pack(side=LEFT, fill=BOTH, expand=1) scrollbar.pack(side=LEFT, fill=Y) for item in self.items: if isinstance(item, list) or isinstance(item, tuple): item = item[0] self.listbox.insert(END, item) self.listbox.selection_set(self.initialvalue) self.listbox.activate(self.initialvalue) self.listbox.bind(' ', self.list_select) self.listbox.bind(' ', self.list_key) self.update() self.geometry("+%d+%d"%(self.parent.winfo_rootx()+100, self.parent.winfo_rooty()+100 )) return self.listbox def list_key(self, evt): key = evt.keysym #print 'Key %s' % (key) if key == "Return": self.ok() elif key == "Escape": self.cancel() def list_select(self, evt): self.ok() def apply(self): self.result = self.listbox.curselection()[0] class VideoInfo(tkd.Dialog): #a = ChoiceBox("ChoiceBox test", "Select stream", items, parent=self).result def __init__(self, cur=None, streams=[], select=0, parent = None): if not parent: import Tkinter parent = Tkinter._default_root self.streams = streams self.subs = streams[0]["subs"] if len(streams) > 0 and "subs" in streams[0] else [] self.select = select self.select2 = 0 self.cur = cur if not streams: self.name = cur[0] self.data = cur[1] self.img = cur[2] self.desc = cur[3] else: self.name = streams[0]["name"] self.data = cur[1] self.img = streams[0]["img"] self.desc = streams[0]["desc"] self.picons_path = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "picons") self.tmp_path = tempfile.gettempdir() #os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp") self.result = None tkd.Dialog.__init__(self, parent, self.title) def body(self, master): # Virsraksts self.title("Item information") w = Label(self, text=self.name, justify=LEFT, font=("Tahoma", 14, "bold")) w.pack(side=TOP) frame0 = Frame(self, width=820, height=600) #, background="gray", borderwidth=2) frame0.pack(side=TOP) frame_l = Frame(frame0, width=410, height=600) #, background="red", borderwidth=2) frame_l.pack(side=LEFT) frame_r = Frame(frame0, width=410, height=600) #, background="green", borderwidth=2) frame_r.pack(side=LEFT) self.pic = Canvas(frame_l, width=400, height=400) self.pic.pack(side=TOP, expand=1, padx=5, pady=5) img = self.img if img: if not img.startswith("http"): img_path = os.path.join(self.picons_path, img) if img and os.path.exists(img_path): im = Image.open(img_path) else: im = None print "No image found ", img_path elif img: fcache = img.replace(":", "_").replace("/", "-").replace(":", "_") fcache = fcache.split("?")[0] fcache = os.path.join(self.tmp_path, fcache) if os.path.exists(fcache): im = Image.open(fcache) else: r = requests.get(img) if r.status_code == 200: img_data = r.content im = Image.open(StringIO.StringIO(r.content)) with open(fcache, "wb") as f: f.write(r.content) else: im = None if im: try: im.thumbnail((400, 400)) except: print "Image convert error" image = ImageTk.PhotoImage(im) imagesprite = self.pic.create_image(200, 200,image=image) self.pic.image = image if self.streams or self.subs: Label(frame_l, text="Streams (%s)" % len(self.streams), justify=LEFT).pack(side=TOP) frame2 = Frame(frame_l, width=400, height=100) frame2.pack(side=TOP, fill=X, expand=1, padx=5, pady=5) scrollbar = Scrollbar(frame2, orient=VERTICAL) self.listbox = Listbox(frame2, yscrollcommand=scrollbar.set, height=6) #, width=40, height=10) scrollbar.config(command=self.listbox.yview) #self.listbox.config(yscrollcommand=scrollbar.set) self.listbox.pack(side=LEFT, fill=BOTH, expand=1) scrollbar.pack(side=LEFT, fill=Y) lst = [] for i,s in enumerate(self.streams): s = {k:v.decode("utf8") if v and isinstance(v, str) else v for k,v in zip(s.keys(), s.values())} item = "[%s,%s] %s"%(s["lang"],s["quality"],s["name"]) self.listbox.insert(END, item) self.listbox.selection_set(self.select) self.listbox.activate(self.select) self.listbox.bind(' ', self.list_select) self.listbox.bind(' ', self.list_key) #self.listbox.bind('<>', lambda evt: self.list_action(evt, "Changed")) self.listbox.bind('<>', lambda evt: self.list_changed(evt, "Changed")) self.url_stream = Text(frame_l, height=1, width=10, font=("Tahoma", 10)) self.url_stream.pack(fill=X, expand=1, padx=5, pady=5) self.url_stream.config(state=NORMAL) self.url_stream.insert(END, self.streams[self.select]["url"]) self.url_stream.config(state=DISABLED) frame_desc = Frame(frame_r, height=400, width=400) frame_desc.pack(side=TOP, fill=X, expand=1, padx=5, pady=5) scrollbar2 = Scrollbar(frame_desc) desc = Text(frame_desc, height=25, width=55, wrap="word", yscrollcommand=scrollbar2.set) #, borderwidth=0, highlightthickness=0) scrollbar2.config(command=desc.yview) scrollbar2.pack(side="right", fill="y") desc.configure(font=("Tahoma", 10)) desc.pack(side=TOP) desc.insert(END, self.desc) desc.insert(END, "\n\n"+self.cur[1]) desc.insert(END, "\n"+self.cur[2]) desc.config(state=DISABLED) if self.streams or self.subs: Label(frame_r, text="Subtitles (%s)" % len(self.subs), justify=LEFT).pack(side=TOP) frame_sub = Frame(frame_r, width=400, height=100) frame_sub.pack(side=TOP, fill=X, expand=1, padx=5, pady=5) scrollbar3 = Scrollbar(frame_sub, orient=VERTICAL) self.listbox2 = Listbox(frame_sub, yscrollcommand=scrollbar3.set, height=6) #, width=40, height=10) scrollbar.config(command=self.listbox2.yview) #self.listbox.config(yscrollcommand=scrollbar.set) self.listbox2.pack(side=LEFT, fill=BOTH, expand=1) scrollbar3.pack(side=LEFT, fill=Y) for i,s in enumerate(self.subs): if not len(s):continue item = ("%s - %s"%(s["lang"],s["name"])).encode("utf8") self.listbox2.insert(END, item) #self.listbox2.bind(' ', self.list_select) #self.listbox2.bind(' ', self.list_key) #self.listbox2.selection_set(self.select) self.listbox2.bind('<>', lambda evt: self.list_changed2(evt, "Changed")) self.url_sub = Text(frame_r, height=1, width=10, font=("Tahoma", 10)) self.url_sub.pack(fill=X, expand=1, padx=5, pady=5) if self.subs: self.url_sub.config(state=NORMAL) self.url_sub.insert(END, self.subs[self.select]["url"]) self.url_sub.config(state=DISABLED) #self.update() #self.geometry("+%d+%d"%(self.parent.winfo_rootx()+0, self.parent.winfo_rooty()+0 )) #self. geometry('+10+10') return self.listbox if "listbox" in dir(self) else None def buttonbox(self): box = Frame(self) w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE) w.pack(side=LEFT, padx=5, pady=5) w = Button(box, text="Cancel", width=10, command=self.cancel) w.pack(side=LEFT, padx=5, pady=5) self.bind("", self.ok) self.bind("", self.cancel) box.pack() def list_key(self, evt): key = evt.keysym #print 'Key %s' % (key) if key == "Return": self.ok() elif key == "Escape": self.cancel() def list_changed(self, evt, key): self.select = evt.widget.curselection()[0] self.url_stream.config(state=NORMAL) self.url_stream.delete("1.0", END) self.url_stream.insert(END, self.streams[self.select]["url"]) self.url_stream.config(state=DISABLED) def list_changed2(self, evt, key): self.select2 = evt.widget.curselection()[0] self.url_sub.config(state=NORMAL) self.url_sub.delete("1.0", END) self.url_sub.insert(END, self.streams[self.select2]["url"]) self.url_sub.config(state=DISABLED) def list_select(self, evt): self.ok() def apply(self): self.result = self.listbox.curselection()[0] def run(sources=None, data="config::home", title="Home", cfg_file="streams.cfg"): app = Main(sources, cfg_file=cfg_file) app.show_content((title, data, "", "")) app.start() def run_cli(sources, data="config::home", title="Home", cfg_file="streams.cfg"): #options = sources.options_read("ltc") #print options history = [] cur = ("Home",data,None,None) content = sources.get_content(cur[1]) exit_loop = False while True: print for i,item in enumerate(content): s = "%i: %s - %s %s"%(i,item[0],item[1],item[2]) print s #.encode(sys.stdout.encoding,"replace") while True: a = raw_input("Enter number, (-) for download, q for exit: ") if a in ("q","Q","x","X"): exit_loop = True print "Exiting" break try: n = int(a) break except: print "Not number!" if exit_loop: break download = False if n<0: n = abs(n) download = True cur2 = content[n] data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1] if not data0: pass elif cur2[1] == "back": cur = history.pop() elif sources.is_video(cur2[1]): if sources.stream_type(cur2[1]): stream = util.item() stream["url"] = cur2[1] stream["name"] = cur2[0] streams = [stream] else: try: if not download: streams = sources.get_streams(cur2[1]) else: stream = util.item() stream["url"] = cur2[1] stream["name"] = cur2[0] stream["url"] = util.streamproxy_encode2(stream["url"]) print stream["url"] streams = [stream] except Exception as e: print unicode(e) traceback.print_exc() streams = [] if streams: if not download: play_video(streams) else: #urlp = util.streamproxy_encode2(streams[0]["url"]) #print urlp #util.player(urlp) #Downloader.download_video(streams) pass else: print "**No stream to play - %s "%( cur2[1]) raw_input("Press any key") #import os #os.system('"c:\Program Files (x86)\VideoLAN\VLC\vlc.exe" "%s"'%cur2[1]) else: if "{0}" in cur2[1]: a = raw_input("Enter value:") cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3]) history.append(cur) cur = cur2 try: content = sources.get_content(cur[1]) except Exception as e: print unicode(e) traceback.print_exc() raw_input("Continue?") def play_video(streams, select=None): if select is None: if len(streams)>1: for i,s in enumerate(streams): print "%s: [%s,%s,%s] %s"%(i,s["quality"],s["lang"],s["type"],s["name"]) a = raw_input("Select stram to play: ") try: select = int(a) if select>=len(streams): select = len(streams) - 1 except: select = None else: select = 0 if select is not None: play_stream(streams[select]) def play_stream(stream, tmp_path=""): if not tmp_path: tmp_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "tmp") stream = util.stream_change(stream) title = stream["name"] if not "nfo" in stream or not stream["nfo"] else util.nfo2title(stream["nfo"]) desc = stream["desc"] if not "nfo" in stream or not stream["nfo"] else util.nfo2desc(stream["nfo"]) img = stream["img"] url = stream["url"] suburl = "" subfile = "" print url if "subs" in stream and len(stream["subs"]) > 0 and stream["subs"][0]: suburl = stream["subs"][0]["url"] subfile = "" print "\n**Download subtitles %s - %s"%(title,suburl) try: subs = urllib2.urlopen(suburl).read() except: subs = None if subs: fname0 = re.sub("[/\n\r\t,:\?\|'~\.]","_",title) if ".xml" in suburl: subs = util.ttaf2srt(subs) subext = ".srt" elif ".vtt" in suburl: subext = ".vtt" elif ".srt" in suburl: subext = ".srt" else: subext = "" if subext: subfile = cunicode(os.path.join(tmp_path,fname0+subext)) with open(subfile,"w") as f: f.write(subs) else: print "\n Error downloading subtitle %s"%suburl print "\n**Play stream %s\n%s" % (title, url.encode("utf8")) player(url,title,subfile,stream["headers"]) def player(url, title = "", subfile = "",headers={}, player="ffplay"): from subprocess import call title = cunicode(title).encode(sys.getfilesystemencoding()) url = cunicode(url).encode(sys.getfilesystemencoding()) # encode(sys.getfilesystemencoding()) subfile = unicode(subfile).encode(sys.getfilesystemencoding()) cmd1 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url, "--meta-title",title, "--http-user-agent","Enigma2" ] # 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 cmd2 = [ r"C:\gstreamer\1.0\x86_64\bin\gst-launch-1.0", #"-v", "playbin", 'uri="%s"'%url, #"souphttpsrc", "ssl-strict=false", #"proxy=127.0.0.1:8888", #'location="%s"'%url, #'!decodebin!autovideosink' ] vf = r"drawtext=text='%{pts\:hms}':box=1:x=w-tw-10:y=h-th-10:boxcolor=black@0.5:fontsize=20:fontcolor=white" if subfile and os.path.exists(subfile): subfile = subfile.replace("\\", "\\\\\\\\") subfile = re.sub("\w:", "", subfile) vf = 'subtitles=%s,' % subfile + vf cmd3 = ["c:\\Util\\ffplay.exe",url, "-window_title", title, "-vf", vf] if headers: cmd3.append("-headers") hd = [] for k in headers: hd.append("%s:%s" % (k, headers[k])) hd = "\n".join(hd) cmd3.append(hd) if not player: cmd = cmd3 if url.startswith("https") else cmd2 else: cmd = cmd3 if player == "ffplay" else cmd2 #cmd = cmd2 # visu spēlē ar gst ret = call(cmd) #if ret: #a = raw_input("*** Error, continue") return if __name__ == "__main__": show_hidden = False data= sys.argv[1] if len(sys.argv) > 1 else "config::home" cfg_file = sys.argv[2] if len(sys.argv) > 2 else "streams.cfg" #sources = ContentSources("sources") sources = None run(sources, data, cfg_file=cfg_file)