Example #1
0
  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()
Example #2
0
  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)
Example #3
0
 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()
Example #4
0
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()
Example #5
0
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()
Example #6
0
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))