Update of /cvsroot/freevo/freevo/src/record
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30565

Modified Files:
        favorite.py recording.py server.py 
Added Files:
        recorder.py 
Log Message:
first working version of the recordserver

Index: recording.py
===================================================================
RCS file: /cvsroot/freevo/freevo/src/record/recording.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** recording.py        6 Nov 2004 17:56:21 -0000       1.1
--- recording.py        7 Nov 2004 16:38:24 -0000       1.2
***************
*** 32,36 ****
--- 32,38 ----
  
  import time
+ import copy
  
+ import config
  import util.fxdparser as fxdparser
  
***************
*** 38,51 ****
  
  def _int2time(i):
      return time.strftime(_time_format, time.localtime(i))
  
  def _time2int(s):
      return int(time.mktime(time.strptime(s, _time_format)))
  
  
  class Recording:
      def __init__(self, id = -1, name = 'unknown', channel = 'unknown',
!                  priority = 0, start = 0, stop = 0, filename = '/dev/null',
!                  info = {}, status = 'scheduled' ):
          self.id       = id
          self.name     = name
--- 40,63 ----
  
  def _int2time(i):
+     """
+     Helper function to create a time string from an int.
+     """
      return time.strftime(_time_format, time.localtime(i))
  
+ 
  def _time2int(s):
+     """
+     Helper function to create an int from a string created by _int2time
+     """
      return int(time.mktime(time.strptime(s, _time_format)))
  
  
  class Recording:
+     """
+     Base class for a recording.
+     """
      def __init__(self, id = -1, name = 'unknown', channel = 'unknown',
!                  priority = 0, start = 0, stop = 0, info = {},
!                  status = 'scheduled' ):
          self.id       = id
          self.name     = name
***************
*** 54,62 ****
          self.start    = start
          self.stop     = stop
-         self.filename = filename
-         self.info     = info
          self.status   = status
  
      def short_list(self):
          return self.id, self.channel, self.priority, self.start, \
                 self.stop, self.status
--- 66,87 ----
          self.start    = start
          self.stop     = stop
          self.status   = status
+         self.info     = {}
+ 
+         self.subtitle = ''
+         self.url      = ''
+         self.padding  = config.TV_RECORD_PADDING
+         for i in info:
+             if i in ('subtitle', 'url'):
+                 setattr(self, i, info[i])
+             if i == 'padding':
+                 i.padding = int(info[i])
+         self.recorder = None
+ 
  
      def short_list(self):
+         """
+         Return a short list with informations about the recording.
+         """
          return self.id, self.channel, self.priority, self.start, \
                 self.stop, self.status
***************
*** 64,79 ****
  
      def long_list(self):
          return self.id, self.name, self.channel, self.priority, self.start, \
!                self.stop, self.filename, self.status, self.info
  
  
      def parse_fxd(self, parser, node):
          self.id = int(parser.getattr(node, 'id'))
          for child in node.children:
!             for var in ('name', 'channel', 'status'):
                  if child.name == var:
                      setattr(self, var, parser.gettext(child))
!             if child.name == 'priority':
!                 self.priority = int(parser.gettext(child))
              if child.name == 'timer':
                  self.start = _time2int(parser.getattr(child, 'start'))
--- 89,116 ----
  
      def long_list(self):
+         """
+         Return a long list with every information about the recording.
+         """
+         info = copy.copy(self.info)
+         if self.subtitle:
+             info['subtitle'] = self.subtitle
+         if self.url:
+             info['url'] = url
          return self.id, self.name, self.channel, self.priority, self.start, \
!                self.stop, self.status, self.padding, info
  
  
      def parse_fxd(self, parser, node):
+         """
+         Parse informations from a fxd node and set the internal variables.
+         """
          self.id = int(parser.getattr(node, 'id'))
          for child in node.children:
!             for var in ('name', 'channel', 'status', 'subtitle', 'url'):
                  if child.name == var:
                      setattr(self, var, parser.gettext(child))
!             for var in ('priority', 'padding'):
!                 if child.name == var:
!                     setattr(self, var, int(parser.gettext(child)))
              if child.name == 'timer':
                  self.start = _time2int(parser.getattr(child, 'start'))
***************
*** 83,92 ****
  
      def __str__(self):
!         return String(self.short_list())
  
  
      def __fxd__(self, fxd):
          node = fxdparser.XMLnode('recording', [ ('id', self.id ) ] )
!         for var in ('name', 'channel', 'priority', 'filename', 'status'):
              subnode = fxdparser.XMLnode(var, [], getattr(self, var) )
              fxd.add(subnode, node)
--- 120,148 ----
  
      def __str__(self):
!         """
!         A simple string representation for a recording for debugging in the
!         recordserver.
!         """
!         channel = self.channel
!         if len(channel) > 10:
!             channel = channel[:10]
!         diff = (self.stop - self.start) / 60
!         name = self.name
!         if len(name) > 23:
!             name = name[:20] + u'...'
!         name = u'"' + name + u'"'
!         return '%3d %10s %-25s %4d %s-%s %s' % \
!                (self.id, String(channel), String(name),
!                 self.priority, _int2time(self.start)[4:],
!                 _int2time(self.stop)[9:], self.status)
  
  
      def __fxd__(self, fxd):
+         """
+         Dump informations about the recording in a fxd file node.
+         """
          node = fxdparser.XMLnode('recording', [ ('id', self.id ) ] )
!         for var in ('name', 'channel', 'priority', 'url', 'status',
!                     'subtitle', 'padding'):
              subnode = fxdparser.XMLnode(var, [], getattr(self, var) )
              fxd.add(subnode, node)
***************
*** 101,105 ****
--- 157,165 ----
          return node
  
+ 
      def __cmp__(self, obj):
+         """
+         Compare basic informations between Recording objects
+         """
          if not isinstance(obj, Recording):
              return True

Index: favorite.py
===================================================================
RCS file: /cvsroot/freevo/freevo/src/record/favorite.py,v
retrieving revision 1.1
retrieving revision 1.2
diff -C2 -d -r1.1 -r1.2
*** favorite.py 6 Nov 2004 17:56:21 -0000       1.1
--- favorite.py 7 Nov 2004 16:38:24 -0000       1.2
***************
*** 37,51 ****
  import util.fxdparser as fxdparser
  
  _time_re = re.compile('([0-9]*):([0-9]*)-([0-9]*):([0-9]*)')
  
  class Favorite:
      def __init__(self, id = -1, name = 'unknown', channels = [],
!                  priority = 0, days = [], times = []):
!         self.id = id
!         self.name = name
          self.channels = channels
          self.priority = priority
!         self.days = days
!         self.times = []
          for t in times:
              m = _time_re.match(t).groups()
--- 37,56 ----
  import util.fxdparser as fxdparser
  
+ # internal regexp for time format
  _time_re = re.compile('([0-9]*):([0-9]*)-([0-9]*):([0-9]*)')
  
  class Favorite:
+     """
+     Base class for a favorite.
+     """
      def __init__(self, id = -1, name = 'unknown', channels = [],
!                  priority = 0, days = [], times = [], once = False):
!         self.id       = id
!         self.name     = name
          self.channels = channels
          self.priority = priority
!         self.days     = days
!         self.times    = []
!         self.once     = once
          for t in times:
              m = _time_re.match(t).groups()
***************
*** 55,65 ****
  
      def short_list(self):
          return self.id, self.name, self.priority
  
      def long_list(self):
          return self.id, self.name, self.channels, self.priority, self.days, \
!                self.times
  
      def parse_fxd(self, parser, node):
          self.id = int(parser.getattr(node, 'id'))
          for child in node.children:
--- 60,81 ----
  
      def short_list(self):
+         """
+         Return a short list with informations about the favorite.
+         """
          return self.id, self.name, self.priority
  
+ 
      def long_list(self):
+         """
+         Return a long list with every information about the favorite.
+         """
          return self.id, self.name, self.channels, self.priority, self.days, \
!                self.times, self.once
! 
  
      def parse_fxd(self, parser, node):
+         """
+         Parse informations from a fxd node and set the internal variables.
+         """
          self.id = int(parser.getattr(node, 'id'))
          for child in node.children:
***************
*** 67,70 ****
--- 83,88 ----
                  if child.name == var:
                      setattr(self, var, parser.gettext(child))
+             if child.name == 'once':
+                 self.once = True
              if child.name == 'channels':
                  self.channels = []
***************
*** 86,89 ****
--- 104,110 ----
  
      def match(self, name, channel, start):
+         """
+         Return True if name, channel and start match this favorite.
+         """
          if name != self.name:
              return False
***************
*** 106,113 ****
  
      def __str__(self):
!         return String(self.short_list())
  
  
      def __fxd__(self, fxd):
          node = fxdparser.XMLnode('favorite', [ ('id', self.id ) ] )
          for var in ('name', 'priority'):
--- 127,150 ----
  
      def __str__(self):
!         """
!         A simple string representation for a favorite for debugging in the
!         recordserver.
!         """
!         name = self.name
!         if len(name) > 45:
!             name = name[:45] + u'...'
!         name = u'"' + name + u'"'
!         if self.once:
!             once = '(schedule once)'
!         else:
!             once = ''
!         return '%3d %-45s %4d %s' % \
!                (self.id, String(name), self.priority, once)
  
  
      def __fxd__(self, fxd):
+         """
+         Dump informations about the favorite in a fxd file node.
+         """
          node = fxdparser.XMLnode('favorite', [ ('id', self.id ) ] )
          for var in ('name', 'priority'):
***************
*** 126,132 ****
--- 163,175 ----
              subnode = fxdparser.XMLnode('times', [], s[:-1])
              fxd.add(subnode, node)
+         if self.once:
+             subnode = fxdparser.XMLnode('once')
+             fxd.add(subnode, node)
          return node
  
      def __cmp__(self, obj):
+         """
+         Compare basic informations between Favorite objects
+         """
          if not isinstance(obj, Favorite):
              return True

--- NEW FILE: recorder.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# recorder.py - base class for recorder plugins
# -----------------------------------------------------------------------------
# $Id: recorder.py,v 1.1 2004/11/07 16:38:24 dischi Exp $
#
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# 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.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

# python imports
import time
import os
import string

# notifier
import notifier

# freevo imports
import config
import plugin
import childapp

# list of possible plugins
plugins = []

class Childapp(childapp.Instance):
    """
    ChildApp wrapper for use inside a recorder plugin
    """
    def __init__(self, app, control, debugname = None, doeslogging = 0,
                 prio = 0):
        """
        Init the childapp
        """
        childapp.Instance.__init__(self, app, debugname, doeslogging, prio, 0)
        self.control = control


    def finished(self):
        """
        Callback when the child died
        """
        self.control.stopped()
        self.control = None


class Plugin(plugin.Plugin):
    """
    Plugin template for a recorder plugin
    """
    def __init__(self):
        plugin.Plugin.__init__(self)
        self.type = 'recorder'
        # childapp running the external program
        self.app  = None
        # recording item
        self.item = None
        # timer for stop the child when it's all done
        self.timer = None
        # reference to the recordserver
        self.server = None
        plugins.append(self)


    def get_cmd(self, rec):
        """
        Function for the plugin to create the command running the
        external program.
        """
        raise Exception('no record command function defined')


    def create_fxd(self, rec):
        """
        Create fxd file for the recording
        TODO: write this function
        """
        pass


    def record(self, server, rec):
        """
        Record 'rec', called from the recordserver 'server'
        """
        if self.item:
            print 'plugin.record: there is something running, stopping it'
            self.stop()
        # create a filename if it is missing
        if not rec.url:
            filename_array = { 'progname': String(rec.name),
                               'title'   : String(rec.subtitle) }

            filemask = config.TV_RECORDFILE_MASK % filename_array
            filename = ''
            for letter in time.strftime(filemask, time.localtime(rec.start)):
                if letter in string.ascii_letters + string.digits:
                    filename += letter
                elif filename and filename[-1] != '_':
                    filename += '_'
            filename = filename.rstrip(' -_:') + config.TV_RECORDFILE_SUFFIX
            rec.url = 'file:' + os.path.join(config.TV_RECORD_DIR, filename)

        # get the cmd for the childapp
        cmd = self.get_cmd(rec)
        self.server = server
        self.item = rec
        self.app = Childapp(cmd, self)
        rec.recorder = self

        # Set auto stop for stop time + padding + 10 secs
        if self.timer:
            notifier.removeTimer(self.timer)
        timer = max(0, int(rec.stop + rec.padding + 10 - time.time()))
        print 'plugin.record: add stop timer for %s seconds' % (timer)
        self.timer = notifier.addTimer(timer * 1000, self.stop)
        # Create fxd file now, even if we don't know if it is working. It
        # will be deleted later when there is a problem
        self.create_fxd()


    def stop(self):
        """
        Stop the current running recording
        """
        if not self.item:
            return False
        print 'plugin.stop: stop recording'
        notifier.removeTimer(self.timer)
        self.app.stop()
        self.timer = None
        return False


    def stopped(self):
        """
        Callback when the recording has stopped
        """
        if self.timer:
            notifier.removeTimer(self.timer)
        if self.item.url.startswith('file:'):
            filename = self.item.url[5:]
            if os.path.isfile(filename):
                self.item.status = 'saved'
                # TODO: create thumbnail
            else:
                self.item.status = 'failed'
                # TODO: delete fxd
        else:
            self.item.status = 'done'
        print 'plugin.stopped: recording finished, new status'
        print self.item
        if self.server:
            self.server.save()
        self.item.recorder = None
        self.item   = None
        self.app    = None
        self.server = None

Index: server.py
===================================================================
RCS file: /cvsroot/freevo/freevo/src/record/server.py,v
retrieving revision 1.12
retrieving revision 1.13
diff -C2 -d -r1.12 -r1.13
*** server.py   6 Nov 2004 17:56:21 -0000       1.12
--- server.py   7 Nov 2004 16:38:24 -0000       1.13
***************
*** 31,50 ****
--- 31,62 ----
  # 
-----------------------------------------------------------------------------
  
+ 
+ # python imports
  import copy
  import os
  import time
+ import traceback
  
+ # notifier
  import notifier
+ 
+ # pyepg
  import pyepg
  
+ # freevo imports
  import sysconfig
  import config
  import util
+ import plugin
  
+ # mbus support
  from mcomm import RPCServer, RPCError, RPCReturn
  
+ # record imports
+ import recorder
  from recording import Recording
  from favorite import Favorite
  
+ 
  # FIXME: move to config file
  EPGDB = os.path.join(config.FREEVO_CACHEDIR, 'epgdb')
***************
*** 53,71 ****
  CONFLICT  = 'conflict'
  SCHEDULED = 'scheduled'
  MISSED    = 'missed'
  SAVED     = 'saved'
  
  class RecordServer(RPCServer):
      def __init__(self):
          RPCServer.__init__(self, 'recordserver')
          self.epgdb = pyepg.get_epg(EPGDB)
          self.fxdfile = sysconfig.cachefile('recordserver.fxd')
!         self.load()
  
  
      def resolve_conflict(self, recordings):
!         # Sort by priority ans can all except the one with the
!         # lowest priority again if the conflict is now solved.
!         #
          # FIXME:
          # This is a very poor solution, maybe we have more than one card
--- 65,99 ----
  CONFLICT  = 'conflict'
  SCHEDULED = 'scheduled'
+ RECORDING = 'recording'
  MISSED    = 'missed'
  SAVED     = 'saved'
+ DELETED   = 'deleted'
+ 
  
  class RecordServer(RPCServer):
+     """
+     Class for the recordserver. It handles the rpc calls and checks the
+     schedule for recordings and favorites. The recordings itself are
+     done by plugins in record/plugins.
+     """
      def __init__(self):
          RPCServer.__init__(self, 'recordserver')
+         plugin.init(exclusive = [ 'record' ])
+         # db access to match favorites
          self.epgdb = pyepg.get_epg(EPGDB)
+         # file to load / save the recordings and favorites
          self.fxdfile = sysconfig.cachefile('recordserver.fxd')
!         # timer for record callback
!         self.rec_timer = None
!         # load the config file and rebuild index
!         self.load(True)
  
  
      def resolve_conflict(self, recordings):
!         """
!         Resolve a conflict for recordings. A higher priority wins. A
!         conflict doesn't mean they can't be all recorded, maybe a plugin can
!         record two programs at a time or there is more than one plugin.
!         """
          # FIXME:
          # This is a very poor solution, maybe we have more than one card
***************
*** 73,81 ****
          # a plugin can record two items at the same time. So this function
          # needs a huge update!!!
          recordings.sort(lambda l, o: cmp(l.priority,o.priority))
!         self.scan_for_conflicts(recordings[:-1])
  
  
      def scan_for_conflicts(self, recordings):
          # Sort by start time
          recordings.sort(lambda l, o: cmp(l.start,o.start))
--- 101,139 ----
          # a plugin can record two items at the same time. So this function
          # needs a huge update!!!
+         print 'recordserver.resolve_conflict'
+         for r in recordings:
+             print String(r)
          recordings.sort(lambda l, o: cmp(l.priority,o.priority))
!         # check if a conflict is recorded right now
!         for r in recordings:
!             if r.recorder:
!                 # This recording active right now. It wins against all
!                 # priorities, we don't stop a running recording
!                 r.status = RECORDING
!                 
!         for r in recordings:
!             if r.status == RECORDING:
!                 continue
!             for c in filter(lambda l: l.status in (SCHEDULED, RECORDING),
!                             recordings):
!                 if c.start <= r.start <= c.stop or \
!                        r.start <= c.start <= r.stop:
!                     break
!             else:
!                 # no conflict for this recording
!                 r.status = SCHEDULED
!         print 'result:'
!         for r in recordings:
!             print String(r)
!         print
  
  
      def scan_for_conflicts(self, recordings):
+         """
+         Scan the scheudle for conflicts. A conflict is a list of recordings
+         with overlapping times. After scanning the conflicts will be
+         resolved by resolve_conflict.
+         """
+         print 'recordserver.scan_for_conflicts'
          # Sort by start time
          recordings.sort(lambda l, o: cmp(l.start,o.start))
***************
*** 132,135 ****
--- 190,198 ----
  
      def check_recordings(self):
+         """
+         Check the current recordings. This includes checking conflicts,
+         removing old entries. At the end, the timer is set for the next
+         recording.
+         """
          ctime = time.time()
          # remove informations older than one week
***************
*** 145,151 ****
  
          # scan for conflicts
          self.scan_for_conflicts(filter(lambda r: r.stop > ctime and \
!                                        r.status in (CONFLICT, SCHEDULED),
!                                        self.recordings))
  
          # print current schedule
--- 208,214 ----
  
          # scan for conflicts
+         to_check = (CONFLICT, SCHEDULED, RECORDING)
          self.scan_for_conflicts(filter(lambda r: r.stop > ctime and \
!                                        r.status in to_check, self.recordings))
  
          # print current schedule
***************
*** 153,185 ****
          print 'recordings:'
          for r in self.recordings:
!             print ' ',
!             for e in r.short_list():
!                 print String(e),
!             print
          print
          print 'favorites:'
          for f in self.favorites:
!             print ' ',
!             for e in f.short_list():
!                 print String(e),
!             print
          print
!         print 'next record id', self.rec_id
!         print 'next favorite id', self.fav_id
  
          # save status
!         if os.path.isfile(self.fxdfile):
!             os.unlink(self.fxdfile)
!         fxd = util.fxdparser.FXD(self.fxdfile)
          for r in self.recordings:
!             fxd.add(r)
!         for r in self.favorites:
!             fxd.add(r)
!         fxd.save()
  
  
      def check_favorites(self):
!         print 'checking favorites against epg'
!         for f in self.favorites:
              for entry in self.epgdb.search_programs(f.name):
                  dbid, channel, title, subtitle, foo, descr, \
--- 216,248 ----
          print 'recordings:'
          for r in self.recordings:
!             print r
          print
          print 'favorites:'
          for f in self.favorites:
!             print f
          print
!         print 'next ids: record=%s favorite=%s' % (self.rec_id, self.fav_id)
  
          # save status
!         self.save()
! 
!         # set wakeup call
!         if self.rec_timer:
!             notifier.removeTimer(self.rec_timer)
          for r in self.recordings:
!             if r.status == SCHEDULED:
!                 secs = max(0, int(r.start - time.time()))
!                 print 'recordserver.check_recordings: next in %s sec' % timer
!                 self.rec_timer = notifier.addTimer(secs * 1000, self.record)
!                 break
  
  
      def check_favorites(self):
!         """
!         Check favorites against the database and add them to the list of
!         recordings
!         """
!         print 'recordserver.check_favorites'
!         for f in copy.copy(self.favorites):
              for entry in self.epgdb.search_programs(f.name):
                  dbid, channel, title, subtitle, foo, descr, \
***************
*** 189,193 ****
--- 252,260 ----
                  r = Recording(self.rec_id, title, channel, 1000+f.priority,
                                start, stop)
+                 r.favorite = True
                  if r in self.recordings:
+                     # This does not only avoids adding recordings twice, it
+                     # also prevents from added a deleted favorite as active
+                     # again.
                      continue
                  print '  added %s: %s (%s)' % (String(channel),
***************
*** 195,202 ****
--- 262,337 ----
                  self.recordings.append(r)
                  self.rec_id += 1
+                 if f.once:
+                     self.favorites.remove(f)
+                     break
+         # now check the schedule again
          self.check_recordings()
  
  
+     def record(self):
+         """
+         Record a program now using one of the record plugins
+         """
+         # FIXME: handle not conflicting recordings when the padding
+         # has a conflict!
+         for r in self.recordings:
+             if r.status == SCHEDULED:
+                 break
+         else:
+             print 'recordserver.record: unable to find the next recording'
+             # This should never happen
+             self.check_recordings()
+             return False
+         if not recorder.plugins:
+             print 'recordserver.record: no plugins found'
+             return False
+ 
+         # FIXME: find the correct recorder
+         record_plugin = recorder.plugins[0]
+ 
+         # remove timer that called this function
+         notifier.removeTimer(self.rec_timer)
+         self.rec_timer = None
+ 
+         if record_plugin.item and record_plugin.item.stop > time.time():
+             # The recorder is recording something. If we are at this point
+             # it means that the current recording has a padding overlapping
+             # the recording of the last recording. So just wait until the
+             # old recording is done
+             secs = record_plugin.item.stop - time.time()
+             self.rec_timer = notifier.addTimer(secs * 1000, self.record)
+             return False
+         
+         print 'recordserver.record: start recording'
+         print r
+         # set status to recording
+         r.status = RECORDING
+ 
+         # schedule next recording
+         for next in self.recordings:
+             if next.status == SCHEDULED:
+                 secs = max(0, int(next.start - time.time()))
+                 print 'recordserver.record: next in %s sec' % timer
+                 self.rec_timer = notifier.addTimer(secs * 1000, self.record)
+                 break
+ 
+         # FIXME: handle more than one recorder
+         try:
+             record_plugin.record(self, r)
+         except:
+             print 'recordserver.record: plugin failed'
+             traceback.print_exc()
+             r.status = MISSED
+         return False
+ 
+ 
+     #
+     # load / save fxd file with recordings and favorites
+     #
+ 
      def __load_recording(self, parser, node):
+         """
+         callback for <recording> in the fxd file
+         """
          try:
              r = Recording()
***************
*** 205,212 ****
              self.rec_id = max(self.rec_id, r.id + 1)
          except Exception, e:
!             print 'server.load_recording:', e
  
  
      def __load_favorite(self, parser, node):
          try:
              f = Favorite()
--- 340,350 ----
              self.rec_id = max(self.rec_id, r.id + 1)
          except Exception, e:
!             print 'recordserver.load_recording:', e
  
  
      def __load_favorite(self, parser, node):
+         """
+         callback for <favorite> in the fxd file
+         """
          try:
              f = Favorite()
***************
*** 215,222 ****
              self.fav_id = max(self.fav_id, f.id + 1)
          except Exception, e:
!             print 'server.load_favorite:', e
  
  
!     def load(self):
          self.rec_id = 0
          self.fav_id = 0
--- 353,363 ----
              self.fav_id = max(self.fav_id, f.id + 1)
          except Exception, e:
!             print 'recordserver.load_favorite:', e
  
  
!     def load(self, rebuild=False):
!         """
!         load the fxd file
!         """
          self.rec_id = 0
          self.fav_id = 0
***************
*** 229,238 ****
              fxd.parse()
          except Exception, e:
!             print 'FXDFile corrupt:', self.fxdfile
              print e
  
          self.check_favorites()
  
  
  
      #
--- 370,397 ----
              fxd.parse()
          except Exception, e:
!             print 'recordserver.load: %s corrupt:' % self.fxdfile
              print e
  
+         if rebuild:
+             for r in self.recordings:
+                 r.id = self.recordings.index(r)
+             for f in self.favorites:
+                 f.id = self.favorites.index(f)
          self.check_favorites()
  
  
+     def save(self):
+         """
+         save the fxd file
+         """
+         if os.path.isfile(self.fxdfile):
+             os.unlink(self.fxdfile)
+         fxd = util.fxdparser.FXD(self.fxdfile)
+         for r in self.recordings:
+             fxd.add(r)
+         for r in self.favorites:
+             fxd.add(r)
+         fxd.save()
+ 
  
      #
***************
*** 241,244 ****
--- 400,407 ----
  
      def __rpc_recording_list__(self, addr, val):
+         """
+         list the current recordins in a short form.
+         result: [ ( id channel priority start stop status ) (...) ]
+         """
          self.parse_parameter(val, () )
          ret = []
***************
*** 249,252 ****
--- 412,420 ----
  
      def __rpc_recording_describe__(self, addr, val):
+         """
+         send a detailed description about a recording
+         parameter: id
+         result: ( id name channel priority start stop status padding info )
+         """
          id = self.parse_parameter(val, ( int, ))
          print 'recording.describe: %s' % id
***************
*** 258,268 ****
  
      def __rpc_recording_add__(self, addr, val):
!         name, channel, priority, start, stop, filename, info = \
                self.parse_parameter(val, ( unicode, unicode, int, int, int,
!                                           str, dict ) )
          print 'recording.add: %s' % String(name)
          r = Recording(self.rec_id, name, channel, priority, start, stop,
!                       filename, info)
          if r in self.recordings:
              return RPCError('Already scheduled')
          self.recordings.append(r)
--- 426,447 ----
  
      def __rpc_recording_add__(self, addr, val):
!         """
!         add a new recording
!         parameter: name channel priority start stop optionals
!         optionals: subtitle, url, padding, description
!         """
!         name, channel, priority, start, stop, info = \
                self.parse_parameter(val, ( unicode, unicode, int, int, int,
!                                           dict ) )
          print 'recording.add: %s' % String(name)
          r = Recording(self.rec_id, name, channel, priority, start, stop,
!                       info = info)
          if r in self.recordings:
+             r = self.recordings[self.recordings.index(r)]
+             if r.status == DELETED:
+                 r.status   = 'scheduled'
+                 r.favorite = False
+                 self.check_recordings()
+                 return RPCReturn(self.rec_id - 1)
              return RPCError('Already scheduled')
          self.recordings.append(r)
***************
*** 273,281 ****
  
      def __rpc_recording_remove__(self, addr, val):
          id = self.parse_parameter(val, ( int, ))
          print 'recording.remove: %s' % id
          for r in self.recordings:
              if r.id == id:
!                 r.status = 'deleted'
                  self.check_recordings()
                  return RPCReturn()
--- 452,468 ----
  
      def __rpc_recording_remove__(self, addr, val):
+         """
+         remove a recording
+         parameter: id
+         """
          id = self.parse_parameter(val, ( int, ))
          print 'recording.remove: %s' % id
          for r in self.recordings:
              if r.id == id:
!                 if r.status == RECORDING:
!                     r.status = SAVED
!                     r.recorder.stop()
!                 else:
!                     r.status = DELETED
                  self.check_recordings()
                  return RPCReturn()
***************
*** 284,291 ****
--- 471,484 ----
  
      def __rpc_recording_modify__(self, addr, val):
+         """
+         modify a recording
+         parameter: id [ ( var val ) (...) ]
+         """
          id, key_val = self.parse_parameter(val, ( int, dict ))
          print 'recording.modify: %s' % id
          for r in self.recordings:
              if r.id == id:
+                 if r.status == RECORDING:
+                     return RPCError('Currently recording')
                  cp = copy.copy(self.recordings[id])
                  for key in key_val:
***************
*** 301,304 ****
--- 494,500 ----
  
      def __rpc_favorite_update__(self, addr=None, val=[]):
+         """
+         updates favorites with data from the database
+         """
          self.check_favorites()
          return RPCReturn()
***************
*** 306,313 ****
  
      def __rpc_favorite_add__(self, addr, val):
!         name, channel, priority, day, time = \
!               self.parse_parameter(val, ( unicode, list, int, list, list ))
          print 'favorite.add: %s' % String(name)
!         f = Favorite(self.fav_id, name, channel, priority, day, time)
          if f in self.favorites:
              return RPCError('Already scheduled')
--- 502,519 ----
  
      def __rpc_favorite_add__(self, addr, val):
!         """
!         add a favorite
!         parameter: name channels priority days times
!         channels is a list of channels
!         days is a list of days ( 0 = Sunday - 6 = Saturday )
!         times is a list of hh:mm-hh:mm
!         """
!         print val
!         name, channels, priority, days, times, once = \
!               self.parse_parameter(val, ( unicode, list, int, list, list,
!                                           bool ))
!         print once
          print 'favorite.add: %s' % String(name)
!         f = Favorite(self.fav_id, name, channels, priority, days, times, once)
          if f in self.favorites:
              return RPCError('Already scheduled')



-------------------------------------------------------
This SF.Net email is sponsored by:
Sybase ASE Linux Express Edition - download now for FREE
LinuxWorld Reader's Choice Award Winner for best database on Linux.
http://ads.osdn.com/?ad_id=5588&alloc_id=12065&op=click
_______________________________________________
Freevo-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to