Beispiel #1
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()
Beispiel #2
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))