def __init__(self,curseslock,geom,charmap,fifopath=None): gobject.GObject.__init__(self) self._lock = RLock() self._geom = geom self._curseslock = curseslock if fifopath == "": self._fifopath = None else: self._fifopath = fifopath self._window = geom.newwin() self._window.nodelay(1) self._window.keypad(1) self._charmap = charmap self._key = None self._quit = Event() signal.signal(signal.SIGUSR1, lambda signum, stack_frame: None) signal.signal(signal.SIGTERM, lambda signum, stack_frame: exit(0)) self._clear_timer = Timer(1000,self._clear_key,repeat=False) self._buffer = "" self.connect("event",self._on_event) self.update()
def __init__(self,bus,player,directory,conf): """Create a new log handler. Arguments: bus Which gobject to send error events to. player Which object to ask the current position of. directory Directory of the audiobook. conf A configuration object like that from the result of the parser in pstorytime.coreparser. """ gobject.GObject.__gobject_init__(self) self._lock = threading.RLock() self._bus = bus self._player = player self._playlog_file = conf.playlog_file self._autolog_file = conf.playlog_file+".auto" self._playlog = self._load(self._playlog_file) self._pending = "" self._autologtimer = Timer(conf.autolog_interval*1000, self._autolognow, repeat=True) # Merge in old auto save (should only be there if the last session crashed # while playing.) if isfile(self._autolog_file): auto = self._load(self._autolog_file) if len(auto)==1: self._logentry(auto[0]) os.remove(self._autolog_file)
def __init__(self,curseslock,conf,audiobook,geom,interval): """Create the audiobook view. Arguments: conf The parsed program configuration. audiobook The audiobook object to create a view for. geom Geometry of the window. interval How often to show position while playing. """ self._lock = RLock() self._curseslock = curseslock self._audiobook = audiobook self._geom = geom with self._lock: self._audiobook.connect("position",self._on_position) self._audiobook.connect("notify::playing",self._on_playing) self._gst = self._audiobook.gst() self._window = geom.newwin() self._timer = Timer(interval*1000, self._on_timer, repeat=True) self.update()
class Status(object): HEIGHT = 2 def __init__(self,curseslock,conf,audiobook,geom,interval): """Create the audiobook view. Arguments: conf The parsed program configuration. audiobook The audiobook object to create a view for. geom Geometry of the window. interval How often to show position while playing. """ self._lock = RLock() self._curseslock = curseslock self._audiobook = audiobook self._geom = geom with self._lock: self._audiobook.connect("position",self._on_position) self._audiobook.connect("notify::playing",self._on_playing) self._gst = self._audiobook.gst() self._window = geom.newwin() self._timer = Timer(interval*1000, self._on_timer, repeat=True) self.update() def getGeom(self): with self._lock: return self._geom def setGeom(self,geom): with self._lock: with self._curseslock: self._geom = geom if self._geom.is_sane(): self._window.resize(geom.h,geom.w) self._window.mvwin(geom.y,geom.x) self.update() def _on_playing(self,ab,prop): """Playing state updated. Arguments: ab The audiobook that this is a view for. prop The property that was updated. """ with self._lock: if ab.playing and (not self._timer.started()): self._timer.start() if (not ab.playing) and self._timer.started(): self._timer.stop() def _on_position(self,ab): """A hint has been received that it is a good idea to update the position information. Arguments: ab The audiobook that this is a view for. """ with self._lock: self.update() def _on_timer(self): with self._lock: self.update() def update(self): with self._lock: if self._geom.is_sane(): (filename,position,duration) = self._audiobook.position() if filename == None: filename = "" if self._audiobook.playing: state = "Playing" elif self._audiobook.eob: state = "End" else: state = "Paused" with self._curseslock: prefix = "File: " maxchars = self._geom.w - len(prefix) - 1 first = prefix + filename[-maxchars:] second = "{position} / {duration} [{state}]".format( position=ns_to_str(position), duration=ns_to_str(duration), state=state) self._window.erase() if self._geom.h>=1: self._window.addnstr(0,0,first,self._geom.w-1) if self._geom.h>=2: self._window.addnstr(1,0,second,self._geom.w-1) self._window.refresh()
class Reader(gobject.GObject): HEIGHT=1 __gsignals__ = { 'error' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), 'event' : ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN, (gobject.TYPE_STRING,), gobject.signal_accumulator_true_handled) } def __init__(self,curseslock,geom,charmap,fifopath=None): gobject.GObject.__init__(self) self._lock = RLock() self._geom = geom self._curseslock = curseslock if fifopath == "": self._fifopath = None else: self._fifopath = fifopath self._window = geom.newwin() self._window.nodelay(1) self._window.keypad(1) self._charmap = charmap self._key = None self._quit = Event() signal.signal(signal.SIGUSR1, lambda signum, stack_frame: None) signal.signal(signal.SIGTERM, lambda signum, stack_frame: exit(0)) self._clear_timer = Timer(1000,self._clear_key,repeat=False) self._buffer = "" self.connect("event",self._on_event) self.update() def run(self): self._read() #if self._fifopath == None: # self._read() #else: # # Create fifo if it does not exist. # fifopath = expanduser(self._fifopath) # if not exists(fifopath): # os.mkfifo(fifopath,0700) # # self._read(fifohandle) def _read(self): handles = [sys.stdin] try: while not self._quit.is_set(): try: select.select(handles,[],handles) except select.error: pass if self._quit.is_set(): break while True: try: with self._lock: with self._curseslock: ch = self._window.getch() if ch == -1: break key = curses.keyname(ch) self._key = key self.update() self._clear_timer.start() event = self._charmap[key].strip() event_formatted = event.format(b=self._buffer) if not self.emit("event",event_formatted): self.emit('error','Failed to parse: "{0}"'.format(event)) except (KeyError, IndexError): pass finally: self._quit.set() def _on_event(self,obj,event): with self._lock: eventword = event.split() if eventword[0]=="buffer": if eventword[1] == "store": self._buffer += eventword[2] self.update() return True elif eventword[1] == "erase": self._buffer = self._buffer[:-1] self.update() return True elif eventword[1] == "clear": self._buffer = "" self.update() return True return False def _clear_key(self): with self._lock: self._key = None self.update() def quit(self): with self._lock: if not self._quit.is_set(): self._quit.set() os.kill(os.getpid(), signal.SIGUSR1) def getGeom(self): with self._lock: return self._geom def setGeom(self,geom): with self._lock: with self._curseslock: self._geom = geom if self._geom.is_sane(): self._window.resize(geom.h,geom.w) self._window.mvwin(geom.y,geom.x) self.update() def update(self): with self._lock: if self._geom.is_sane(): with self._curseslock: self._window.erase() prefix = "> " if self._key!=None: keystr = " ({0})".format(self._key) else: keystr = "" maxbuf = self._geom.w - len(keystr) - len(prefix) - 1 bufstr = self._buffer[-maxbuf:] spacing = " "*(maxbuf-len(bufstr)) line = prefix+bufstr+spacing+keystr if self._geom.h>=1: self._window.addnstr(0,0,line,self._geom.w-1) self._window.refresh()
class Log(gobject.GObject): @withdoc(gobject.property) def playlog(self): """The current playlog. """ with self._lock: return self._playlog def __init__(self,bus,player,directory,conf): """Create a new log handler. Arguments: bus Which gobject to send error events to. player Which object to ask the current position of. directory Directory of the audiobook. conf A configuration object like that from the result of the parser in pstorytime.coreparser. """ gobject.GObject.__gobject_init__(self) self._lock = threading.RLock() self._bus = bus self._player = player self._playlog_file = conf.playlog_file self._autolog_file = conf.playlog_file+".auto" self._playlog = self._load(self._playlog_file) self._pending = "" self._autologtimer = Timer(conf.autolog_interval*1000, self._autolognow, repeat=True) # Merge in old auto save (should only be there if the last session crashed # while playing.) if isfile(self._autolog_file): auto = self._load(self._autolog_file) if len(auto)==1: self._logentry(auto[0]) os.remove(self._autolog_file) def start(self): """Start autologging (or reset the timer.)""" with self._lock: self._autologtimer.start() self._autolognow() def stop(self): """Stop autologging and remove autolog file.""" with self._lock: self._autologtimer.stop() if isfile(self._autolog_file): os.remove(self._autolog_file) def lognow(self,event): """Log an event with the given event name at the current position and time. Arguments: event The event type to log. """ with self._lock: walltime = time.time() (filename,position,duration) = self._player.position() self._logentry(LogEntry(walltime,event,filename,position,duration)) def _load(self,logfile): """Load log from given file. Arguments: logfile File name to load log from. Return: The loaded log. """ with self._lock: try: with open(logfile,'rb') as f: lines = f.readlines() # Parse lines and remove invalid ones. return filter(lambda e: e!=None, map(LogEntry.parse, lines)) except IOError: return [] def _autolognow(self): """Save current position and such to autolog file now. """ with self._lock: # Retry writing pending entries to the play log. self._writelog() # Make sure the autolog timer is running. The autologging could have been stopped # while we were waiting at the lock. if self._autologtimer.started(): # Update autolog walltime = time.time() (filename,position,duration) = self._player.position() event = LogEntry(walltime, 'auto', filename, position, duration) line = str(event)+"\n" try: _write_file(self._autolog_file,'wb',line) except IOError: self._bus.emit("error","Failed to write to auto log: {0}".format(self._autolog_file)) def _logentry(self,entry): """Log the given entry to the playlog. Arguments: entry The entry to add. """ with self._lock: self._playlog.append(entry) self.notify("playlog") self._pending += str(entry)+"\n" self._writelog() def _writelog(self): """Write all pending log entries to file. """ with self._lock: if self._pending != "": try: _write_file(self._playlog_file,'ab',self._pending) self._pending = "" except IOError as e: self._bus.emit("error","Failed to write to play log, data will be included in next write: {0}".format(self._playlog_file))