# -*- coding: UTF-8 -*- ''' Videoremote plugin for SVPlayer (c) 2011-2015 Jan ONDREJ (SAL) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ''' from sgtk import GObject, Gtk, keysyms import os, re, sys, locale, string, math, time, glob, traceback from sdict import sdict import httpfs, iptv2, urllib, urllib2 import players import config COLUMN_SHOW = 0 COLUMN_CNTR = 1 files_menu = 1 dirname = os.path.dirname(sys.argv[0]) win = None class globals: command_line = [] menutype = None stored_values = [] lastpath = '' path = '' player_vlc = None player_mplayer = None player_gst = None subtitles = [] @staticmethod def reinit(): globals.command_line = [] globals.stored_values = [] globals.subtitles = [] def ls(path): if path.startswith('http://'): l=httpfs.listdir(path) else: l=os.listdir(path) l.sort() l.append('../') for i in ['.x','.mplayer.conf']: try: l.remove(i) except: pass return l def recode(s, charset=None): if charset==None: charset = locale.getlocale()[1] try: return urllib.unquote_plus(unicode(s, charset)) except UnicodeError: print "UnicodeError:",s except TypeError: pass return s shlist = [] class seen: def __init__(self): self.log_file = config.last_seen_filename # load last seen file try: self.files = dict([x.strip().split('\t', 1) for x in open(self.log_file).readlines()]) except IOError: self.files = {} def save(self): # store it back f = open(self.log_file+'.tmp','w') f.write('\n'.join(["%s\t%s" % (x, self.files[x]) for x in sorted(self.files)])) f.close() os.rename(self.log_file+'.tmp', self.log_file) def count(self, name): try: name = os.path.realpath(name) except OSError: return 0 c = [x[:-4] for x in self.files.values()].count(name.rstrip('\r\n')[:-4]) if c>9: return 9 else: return c def inc(self, name): name = os.path.normpath(name) if not name.startswith('http://'): name = os.path.realpath(name.rstrip('\r\n')) t = time.strftime("%Y-%m-%d %H:%M:%S.%%s") % str(time.time()%1)[2:5] self.files[t] = name def last_idx(self, path): path = os.path.realpath(os.path.normpath(path)) paths = [(os.path.join(path, x), id) for x, id in zip(shlist, range(len(shlist))) if os.path.isdir(os.path.join(path, x))] for key in sorted(self.files.keys(), reverse=True): value = self.files[key] for p, id in paths: if p in value: #print "Last idx:", id, key, p, value #print "Last seen row:", sorted(self.files.keys()).index(key) return id raise ValueError, 'Not found' seen = seen() def set_model(store, list, path=""): global sw, shlist shlist=list sw.get_vadjustment().set_value(0) sw.get_hadjustment().set_value(0) store.clear() store.d = {} cursor, cursor_line = -1, 0 if path=="": for item in list.keys(): store_iter = store.append() store.d[recode(item)] = list.get(item) store.set(store_iter, COLUMN_SHOW, recode(item), COLUMN_CNTR, '') else: for item in list: store_iter = store.append() if os.path.isdir(path+"/"+item) and (not item.endswith('/')): item2=item+"/" else: item2=item store.d[recode(item2)]=[item] cntr = seen.count(path.rstrip('/')+"/"+item) if (cursor<0) and (cntr==0): cursor=cursor_line store.set(store_iter, COLUMN_SHOW, recode(item2), COLUMN_CNTR, str(cntr or '')) cursor_line += 1 #traceback.print_stack() return cursor class base: ''' base class ''' def __add__(self,second): x=base() x.ADD_A=self x.ADD_B=second return x def main(self, row, treeview, model): self.ADD_A.main(row, treeview, model) self.ADD_B.main(row, treeview, model) class set_menu(base): def __init__(self, menutype, store_value=None): self.menutype = menutype self.store_value = store_value def main(self, row, treeview, model): globals.stored_values.append(self.store_value) globals.menutype = self.menutype set_model(model, globals.menutype) treeview.set_cursor(0) class film(base): def main(self, row, treeview, model): globals.path = config.file_browser_path globals.lastpath = globals.path globals.menutype = files_menu set_model(model, ls(globals.path), globals.path) treeview.set_cursor(0) class nextfilm(base): def main(self, row, treeview, model): globals.path = globals.lastpath globals.menutype = files_menu set_model(model, ls(globals.path), globals.path) if treeview.cursor_pos.has_key(globals.path): treeview.set_cursor(treeview.cursor_pos[globals.path]) class media_exts(object): exts = ['avi', 'mpg', 'mkv', 'flv', 'vob', 'wmv', 'webm', 'mp4', 'mp3'] def __init__(self): self.point_exts = ["."+x for x in self.exts] #def pattern(self, prefix="*."): # sl = self.exts + [x.upper() for x in self.exts] # u = [''.join(x) for x in zip(*sl)] # return prefix + '[' + ']['.join(u) + ']' def known_ext(self, fn): for ext in self.point_exts: if fn.endswith(ext): return True return False def folder(self, path): return [ os.path.join(path, x) for x in os.listdir(path) if self.known_ext(x) ] #return glob.glob(self.pattern(path)) def recursive(self, path): ret = self.folder(path) for root, dirs, files in os.walk(path): for dirname in dirs: ret.extend(self.folder(os.path.join(root, dirname))) return ret class all_in_folder(base): def main(self, row, treeview, model): globals.path = globals.lastpath # remove last added entry, already added in this folder globals.command_line.pop() globals.command_line.extend(sorted(media_exts().folder(globals.path))) print globals.path treeview.set_cursor(0) class all_in_folder_recursive(all_in_folder): def main(self, row, treeview, model): globals.path = globals.lastpath globals.command_line.extend(sorted(media_exts().recursive(globals.path))) treeview.set_cursor(0) class myexec(base): def __init__(self,*args): self.args = args def main(self, row, treeview, model): print self.args os.execvp(self.args[0], self.args) class system(base): def __init__(self,arg): self.arg=arg def main(self, row, treeview, model): os.system(self.arg) class run(base): def __init__(self,*args): self.arg=args def auto_add_subtitles(self, fn): fn = fn[0] dir, filename = os.path.split(fn) fn_no_ext = fn.rsplit(".", 1)[0] for file in os.listdir(dir): f = os.path.join(dir, file) if os.path.isfile(f): for ext in ['sub', 'srt']: if f==fn_no_ext+"."+ext: if not f in globals.subtitles: print "Auto adding subtitle:", file globals.subtitles.append(f) def main(self, row, treeview, model): print [self.arg[0]]+globals.command_line seen.save() os.execvp(self.arg[0], [self.arg[0]]+globals.command_line) class run_svplayer_vlc(run): def main(self, row, treeview, model): seen.save() fn = globals.command_line self.auto_add_subtitles(fn) globals.player(fn, fn, globals.subtitles, player=players.VLCWidget) class run_svplayer_gst(run): def main(self, row, treeview, model): seen.save() fn = globals.command_line self.auto_add_subtitles(fn) globals.player(fn, fn, globals.subtitles, player=players.GSTWidget) class run_svplayer_mplayer(run): def main(self, row, treeview, model): seen.save() fn = globals.command_line self.auto_add_subtitles(fn) globals.player(fn, fn, globals.subtitles, player=players.MPlayerWidget) class run_mplayer(run): def main(self, row, treeview, model): if os.path.exists(os.path.join(globals.lastpath, '.mplayer.conf')): globals.command_line.insert(0, '-include') globals.command_line.insert(1, os.path.join(globals.lastpath, '.mplayer.conf')) run.main(self, row, treeview, model) class fork_run(run): def main(self, row, treeview, model): if os.fork()==0: os.execvp(self.arg[0],[self.arg[0]]+globals.command_line) else: globals.path = globals.lastpath globals.menutype = files_menu set_model(model, ls(globals.path), globals.path) globals.command_line=[] if treeview.cursor_pos.has_key(globals.path): treeview.set_cursor(treeview.cursor_pos[globals.path]) class fork_run_mplayer(fork_run): def main(self, row, treeview, model): if os.path.exists(os.path.join(globals.lastpath, '.mplayer.conf')): globals.command_line.extend([ '-include',os.path.join(globals.lastpath, '.mplayer.conf')]) fork_run.main(self, row, treeview, model) class arg(base): def __init__(self,*args): self.args=args def main(self, row, treeview, model): globals.command_line.extend(self.args) treeview.set_cursor(0) class antik_archive(base): def __init__(self, date=None): self.date = date globals.alias_list = [] def main(self, row, treeview, model): self.prog = globals.stored_values.pop(-1) globals.menutype = 'ALIAS' globals.alias_list = iptv2.parse_prog(self.prog, self.date) set_model(model, [' '.join(x[1:]) for x in globals.alias_list], 'TV') treeview.set_cursor(0) class exit(base): def main(self, row, treeview, model): Gtk.main_quit() play_menu = sdict([ {'PLAY: internal gstreamer': run_svplayer_gst()}, {'PLAY: internal vlc': run_svplayer_vlc()}, {'PLAY: internal mplayer': run_svplayer_mplayer()}, {'PLAY: external mplayer': run_mplayer('mplayer')}, {'All in this folder': all_in_folder()}, {'Recursive all files': all_in_folder_recursive()}, {'NEXTFILE': nextfilm()}, #{'PLAY without exit': fork_run_mplayer('mplayer')}, #{'seek 00:30:00': arg('-ss','00:30:00')}, #{'seek 01:00:00': arg('-ss','01:00:00')}, #{'aspect 16:10': arg('-aspect','16:10')}, #{'crop 16:10': arg('-vf','crop=720:480:0:48','-vo','sdl')}, #{'aspect 4:3': arg('-aspect','4:3')}, #{'crop 16:9': arg('-vf','crop=720:428:0:74')}, #{'Video out: VDPAU': arg('-vo','vdpau')}, #{'Video out: SDL': arg('-vo','sdl')}, #{'broken': arg('-ni','-nocache','-mc','0','-forceidx','-nobps','-vf-del','0')}, #{'no index': arg('-noidx')}, #{'channels1': arg('-channels','1')}, #{'deinterlace': arg('-vf', 'kerndeint,yadif,pp=l5/lowpass5')}, #{'framedrop': arg('-framedrop')}, #{'forced index': arg('-forceidx')}, #{'demuxer=lavf (ANTIK archiv)': arg('-demuxer', 'lavf')}, #{'subfuzziness': arg('-sub-fuzziness', '2')}, ]) # change order if SVPLAYER_GST is set if os.environ.get('SVPLAYER_GST'): pm0 = play_menu[0] play_menu[0] = play_menu[1] play_menu[1] = pm0 help_menu = sdict([ {'HELP PANASONIC': myexec(dirname+'/showrem.py','--remote','PANASONIC')}, {'HELP JVC': myexec(dirname+'/showrem.py','--remote','JVCs')}, {'HELP NEC': myexec(dirname+'/showrem.py','--remote','NEC')} ]) ADAY=24*60*60 TODAY=time.time() // ADAY * ADAY iptv_date_menu = sdict([ {time.strftime("%c", time.localtime(TODAY-x*ADAY)): antik_archive(TODAY-x*ADAY)} for x in range(60) ]) download_prog_old=['xterm','-e', '(date;wget -T 10 -U mozilla -O - "http://www.salstar.sk/wap/tv/mar.php?channel=all" )>/tmp/tv.html; sleep 2s'] download_prog=['xterm','-e', '(date;wget -T 10 -U mozilla -O - "http://www.salstar.sk/wap/tv/?channel=all" )>/tmp/tv.html; sleep 2s'] record_menu = sdict([ {'RECORD MOVIE': run(dirname+'/tvrec')}, {'PLAY IT': arg('--play')}, {'SNAPSHOT': myexec(dirname+'/tvrec','--snapshot')}, {'STEREO': arg('-tv','amode=1')}, {'LANG1': arg('-tv','amode=2')}, {'TIME 00:30:00': arg('--mins','30')}, {'TIME 01:00:00': arg('--mins','60')}, {'TIME 01:30:00': arg('--mins','90')}, {'TIME 02:00:00': arg('--mins','120')}, {'TIME 03:00:00': arg('--mins','180')}, {'POWEROFF': arg('--poweroff')}, {'TIME 00:01:00': arg('--mins','1')} ]) system_menu = sdict([ {'RestartIR': system('killall irxevent; irxevent &')+exit()}, {'VIDEO': system('amixer sset Line mute')}, {'TV': system('amixer sset Line unmute')}, {'NO MIC': system('amixer sset Mic mute')}, {'MONITOR OFF': system('xset dpms force standby')}, {'MOUNT /mnt/o': system('mount /mnt/o')} ]) programs_menu = sdict([ {'FILM': film()}, {'RECORD': set_menu(record_menu)}, {'MP3': myexec('xmms')}, {'SYSTEM': set_menu(system_menu)}, {'CLOCK': myexec(dirname+'/clock.py')}, #{'PICTURES': myexec(sys.argv[0],'--path',os.environ['HOME']+'/sal/pictures')}, {'HELP': set_menu(help_menu)} ]) # Various settings class change_fullscreen(run): def main(self, row, treeview, model): player = globals.stored_values[0] player.hide_browser() player.change_fullscreen(1) class change_subtitles(run): def main(self, row, treeview, model): player = globals.stored_values[0] player.hide_browser() player.change_subtitle() class change_audio(run): def main(self, row, treeview, model): player = globals.stored_values[0] player.hide_browser() player.change_track(1) # +1 class change_source(run): def main(self, row, treeview, model): player = globals.stored_values[0] player.hide_browser() player.source += 1 player.change_channel() class change_engine(run): def main(self, row, treeview, model): player = globals.stored_values[0] player.hide_browser() player.change_engine() settings_menu = sdict([ {'Fullscreen': change_fullscreen()}, {'Subtitles': change_subtitles()}, {'Audio track': change_audio()}, {'Signal source': change_source()}, {'Player engine': change_engine()} ]) CSS_DATA = """\ GtkTreeView row:nth-child(even) { background-color: #ffffff; } GtkTreeView row:nth-child(odd) { background-color: #f0f0f0; } GtkTreeView row:selected { background-color: #4a90d9; } """ css_provider = Gtk.CssProvider() css_provider.load_from_data(CSS_DATA) class file_browser: def __init__(self, parent, path=None, player=None, menu=None, fullscreen=False): global sw globals.reinit() if path: globals.path = path globals.menutype = files_menu globals.player = player self.mainbox = Gtk.VBox(False, 8) sw = Gtk.ScrolledWindow() sw.set_shadow_type(Gtk.SHADOW_ETCHED_IN) sw.set_policy(Gtk.POLICY_AUTOMATIC, Gtk.POLICY_AUTOMATIC) self.mainbox.pack_start(sw) self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING) if globals.menutype==files_menu: set_model(self.model, ls(globals.path), globals.path) else: set_model(self.model, globals.menutype) self.treeview = Gtk.TreeView(self.model) self.treeview.exit = True self.treeview.cursor_pos = {} self.treeview.set_rules_hint(True) self.treeview.set_search_column(COLUMN_SHOW) self.treeview.connect('row-activated', self.row_activated) sw.add(self.treeview) sw.get_style_context().add_provider( css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) self.treeview.get_style_context().add_provider( css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) # column for fixed toggles renderer = Gtk.CellRendererToggle() self.cell = Gtk.CellRendererText() self.fullscreen(fullscreen) column0 = Gtk.TreeViewColumn('Filename', self.cell, text=COLUMN_SHOW) column1 = Gtk.TreeViewColumn('#', self.cell, text=COLUMN_CNTR) #column0.set_sizing(Gtk.TREE_VIEW_COLUMN_FIXED) self.treeview.append_column(column1) self.treeview.append_column(column0) self.treeview.set_cursor(0) parent.add(self.mainbox) self.mainbox.show_all() self.treeview.grab_focus() # set menu if menu: menu.main(0, self.treeview, self.model) def fullscreen(self, state): if state: self.cell.set_property('font', 'Sans 40') else: self.cell.set_property('font', 'Sans 12') def pushkey(self, keyval): model = self.treeview.get_model() column = self.treeview.get_column(2) if keyval == keysyms.Escape: return False print "BROWSER KEY:", keyval direction = { # Keyboard keys are controlled by treeview widget 'Up': (0,-1), 'Down': (0,1), 'Right': (200,0), 'Left': (-200,0), 'Page_Up': (0,-10), 'Page_Down': (0,10), # LIRC keys 'FF_m': (0,-1), 'REW_m': (0,1), 'FF_s': (200,0), 'REW_s': (-200,0), 'VOL_UP': (200,0), 'VOL_DOWN': (-200,0) } if keyval=='F8' or keyval=='p': npath=os.path.join(globals.path,'.x') if os.path.isdir(npath): globals.lastpath = globals.path globals.path = npath set_model(model, ls(globals.path), globals.path) self.treeview.set_cursor(0) return True elif keyval=='Return': self.say(None) # stop saying model, store_iter = self.treeview.get_selection().get_selected() row = model.get_path(store_iter) column = self.treeview.get_column(COLUMN_SHOW) self.treeview.emit('row-activated', row, column) return True elif keyval in direction.keys(): x,y = direction[keyval] if y!=0: line = self.treeview.get_cursor()[0].get_indices()[0] if (line+y)<0: self.treeview.set_cursor(0) elif (line+y)=0: try: self.treeview.set_cursor((seen.last_idx(globals.path),)) except ValueError: self.treeview.set_cursor(c) self.say(self.get_row()) else: if re.search('\.(txt|sub|srt|ssa|utf|smi|rt|aqt|jss)$', globals.path,re.IGNORECASE): #if '-sub' in globals.command_line: # globals.command_line[globals.command_line.index('-sub')+1] \ # +=','+globals.path #else: # globals.command_line.extend(['-vo', 'sdl', '-sub', globals.path]) globals.subtitles.append(globals.path) globals.path = globals.oldpath set_model(model, ls(globals.path), globals.path) if self.treeview.cursor_pos.has_key(globals.path) & (val=='..'): self.treeview.set_cursor(self.treeview.cursor_pos[globals.path]) elif (re.search('.(gif|jpg|png|bmp)$', globals.path, re.IGNORECASE)): cl = ['geeqie', '-f', globals.path] if os.fork()==0: os.execvp(cl[0], cl) else: globals.path=os.path.dirname(globals.oldpath) set_model(model,ls(globals.path),globals.path) if self.treeview.cursor_pos.has_key(globals.path): self.treeview.set_cursor(self.treeview.cursor_pos[globals.path]) else: globals.command_line.append(globals.path) globals.menutype = play_menu print globals.path seen.inc(globals.path) set_model(model, play_menu) elif globals.menutype=="ALIAS": line = self.treeview.get_cursor()[0].get_indices()[0] # cursor position key = globals.alias_list[line][0] print 'ALIAS', globals.alias_list[line] globals.player( [globals.alias_list[line][2]], [key], media=config.antik_archive_ftp, player=players.GSTWidget #player=players.MPlayerWidget ) else: val.main(row, self.treeview, model) self.treeview.grab_focus() def main(): global win win = Gtk.Window() win.connect('destroy', lambda win: Gtk.main_quit()) win.set_title('VideoRemote') win.set_border_width(8) win.maximize() file_browser(win, menutype=globals.menutype) win.show_all() Gtk.main() if __name__ == '__main__': locale.setlocale(locale.LC_ALL,os.environ['LANG']) globals.path = config.file_browser_path globals.menutype = programs_menu line = 0 n=1 while n