freevo recordserver start
Traceback (most recent call last):
File "/var/lib/python-support/python2.5/freevo/helpers/recordserver.py", line 51, in <module>
from twisted.internet.app import Application
ImportError: No module named app
recordserver.py
#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------
# record_server.py - A network aware TV recording server.
# -----------------------------------------------------------------------
# $Id: recordserver.py 9401 2007-03-27 20:14:37Z duncan $
#
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002 Krister Lagerstrom, et al.
# 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
#
# -----------------------------------------------------------------------
import sys, string, random, time, os, re, pwd, stat, threading, pickle, md5, datetime, copy
import config
from util import vfs
appname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
appconf = appname.upper()
# change uid
if __name__ == '__main__':
uid='config.'+appconf+'_UID'
gid='config.'+appconf+'_GID'
try:
if eval(uid) and os.getuid() == 0:
os.setgid(eval(gid))
os.setuid(eval(uid))
os.environ['USER'] = pwd.getpwuid(os.getuid())[0]
os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
except Exception, e:
print e
from twisted.web import xmlrpc, server
from twisted.internet.app import Application
from twisted.internet import reactor
from twisted.python import log
from util.marmalade import jellyToXML, unjellyFromXML
from video.commdetectclient import initCommDetectJob
from video.commdetectclient import queueIt
from video.commdetectclient import listJobs
from video.commdetectclient import connectionTest
import rc
rc_object = rc.get_singleton(use_pylirc=0, use_netremote=0)
from tv.record_types import TYPES_VERSION
from tv.record_types import ScheduledRecordings
import tv.record_types
import tv.epg_xmltv
import util.tv_util as tv_util
import plugin
import util.popen3
from tv.channels import FreevoChannels
from util.videothumb import snapshot
from event import *
DEBUG = hasattr(config, appconf+'_DEBUG') and eval('config.'+appconf+'_DEBUG') or config.DEBUG
logfile = '%s/%s-%s.log' % (config.LOGDIR, appname, os.getuid())
log.startLogging(open(logfile, 'a'))
def _debug_(text, level=1):
if DEBUG >= level:
try:
log.debug(String(text))
except:
print String(text)
_debug_('PLUGIN_RECORD: %s' % config.plugin_record)
plugin.init_special_plugin(config.plugin_record)
def print_plugin_warning():
print '*************************************************'
print '** Warning: No recording plugin registered. **'
print '** Check your local_conf.py for a **'
print '** bad "plugin_record =" line or **'
print '** this log for a plugin failure. **'
print '** Recordings will fail! **'
print '*************************************************'
if not plugin.getbyname('RECORD'):
print_plugin_warning()
class RecordServer(xmlrpc.XMLRPC):
def __init__(self):
self.lock = threading.Lock()
self.fc = FreevoChannels()
# XXX: In the future we should have one lock per VideoGroup.
self.tv_lock_file = None
self.vg = None
self.previouslyRecordedShows = None
def isRecording(self):
_debug_('in isRecording', 3)
return glob.glob(config.FREEVO_CACHEDIR + '/record.*') and TRUE or FALSE
def progsTimeCompare(self, first, second):
t1 = first.split(':')[-1]
t2 = second.split(':')[-1]
try:
return int(float(t1)) - int(float(t2))
except ArithmeticError:
pass
return 0
def findOverlaps(self, scheduledRecordings):
_debug_('in findOverlaps', 3)
progs = scheduledRecordings.getProgramList()
proglist = list(progs)
proglist.sort(self.progsTimeCompare)
for progitem in proglist:
progs[progitem].overlap = 0
for i in range(0, len(proglist)-1):
thisprog = progs[proglist[i]]
nextprog = progs[proglist[i+1]]
if thisprog.stop > nextprog.start:
thisprog.overlap = 1
nextprog.overlap = 1
_debug_('Overlap:\n%s\n%s' % (thisprog, nextprog), 3)
def findNextProgram(self):
_debug_('in findNextProgram', 3)
next_program = None
progs = self.getScheduledRecordings().getProgramList()
proglist = list(progs)
proglist.sort(self.progsTimeCompare)
now = time.time()
timenow = time.localtime(now)
for progitem in proglist:
prog = progs[progitem]
_debug_('%s' % (prog), 2)
try:
recording = prog.isRecording
except:
recording = FALSE
_debug_('%s: recording=%s' % (prog.title, recording), 2)
endtime = time.localtime(prog.stop+config.TV_RECORD_PADDING_POST)
if now > prog.stop + config.TV_RECORD_PADDING_POST:
_debug_('%s: prog.stop=%s, now=%s' % (prog.title, endtime, timenow), 2)
continue
_debug_('%s: endtime=%s' % (prog.title, endtime), 2)
if not recording:
next_program = prog
break
self.next_program = next_program
if next_program == None:
_debug_('No program scheduled to record', 3)
return None
_debug_('%s' % (next_program), 3)
return next_program
def isPlayerRunning(self):
'''
returns the state of a player, mplayer, xine, etc.
TODO:
real player running test, check /dev/videoX.
this could go into the upsoon client
'''
_debug_('in isPlayerRunning', 3)
return (os.path.exists(config.FREEVO_CACHEDIR + '/playing'))
# note: add locking and r/rw options to get/save funs
def getScheduledRecordings(self):
file_ver = None
scheduledRecordings = None
if os.path.isfile(config.TV_RECORD_SCHEDULE):
_debug_('GET: reading cached file (%s)' % config.TV_RECORD_SCHEDULE, 5)
if hasattr(self, 'scheduledRecordings_cache'):
mod_time, scheduledRecordings = self.scheduledRecordings_cache
try:
if os.stat(config.TV_RECORD_SCHEDULE)[stat.ST_MTIME] == mod_time:
_debug_('Return cached data', 5)
return scheduledRecordings
except OSError:
pass
f = open(config.TV_RECORD_SCHEDULE, 'r')
scheduledRecordings = unjellyFromXML(f)
f.close()
try:
file_ver = scheduledRecordings.TYPES_VERSION
except AttributeError:
_debug_('The cache does not have a version and must be recreated.', 1)
if file_ver != TYPES_VERSION:
_debug_(('ScheduledRecordings version number %s is stale (new is %s), must ' +
'be reloaded') % (file_ver, TYPES_VERSION), 1)
scheduledRecordings = None
else:
_debug_('Got ScheduledRecordings (version %s).' % file_ver, 5)
if not scheduledRecordings:
_debug_('GET: making a new ScheduledRecordings', 2)
scheduledRecordings = ScheduledRecordings()
self.saveScheduledRecordings(scheduledRecordings)
_debug_('ScheduledRecordings has %s items.' % \
len(scheduledRecordings.programList), 1)
try:
mod_time = os.stat(config.TV_RECORD_SCHEDULE)[stat.ST_MTIME]
self.scheduledRecordings_cache = mod_time, scheduledRecordings
except OSError:
pass
return scheduledRecordings
#
# function to save the schedule to disk
#
def saveScheduledRecordings(self, scheduledRecordings=None):
if not scheduledRecordings:
_debug_('SAVE: making a new ScheduledRecordings', 2)
scheduledRecordings = ScheduledRecordings()
self.findOverlaps(scheduledRecordings)
_debug_('SAVE: saving cached file (%s)' % config.TV_RECORD_SCHEDULE, 2)
_debug_("SAVE: ScheduledRecordings has %s items." % len(scheduledRecordings.programList), 2)
try:
f = open(config.TV_RECORD_SCHEDULE, 'w')
except IOError:
os.unlink(config.TV_RECORD_SCHEDULE)
f = open(config.TV_RECORD_SCHEDULE, 'w')
jellyToXML(scheduledRecordings, f)
f.close()
try:
mod_time = os.stat(config.TV_RECORD_SCHEDULE)[stat.ST_MTIME]
self.scheduledRecordings_cache = mod_time, scheduledRecordings
except OSError:
pass
return TRUE
#
# Load the saved set of recorded shows
#
def loadPreviouslyRecordedShows(self):
if self.previouslyRecordedShows:
return
cacheFile = config.FREEVO_CACHEDIR + "/previouslyRecorded.pickle"
try:
self.previouslyRecordedShows = pickle.load(open(cacheFile, "r"))
except IOError:
self.previouslyRecordedShows = {}
pass
#
# Save the set of recorded shows
#
def savePreviouslyRecordedShows(self):
if not self.previouslyRecordedShows:
return
cacheFile=config.FREEVO_CACHEDIR+"/previouslyRecorded.pickle"
pickle.dump(self.previouslyRecordedShows, open(cacheFile,"w"))
#
# Return true if this is a new episode of 'prog'
#
def newEpisode(self, prog=None):
todayStr = datetime.date.today().strftime('%Y%m%d')
progStr = str(prog.date)
_debug_('Program Date: "%s"' % progStr, 5)
_debug_('Todays Date : "%s"' % todayStr, 5)
if (len(progStr)==8):
_debug_('Good date format', 5)
#Year
todaysYear=(todayStr[0:4])
progYear=(progStr[0:4])
#Month
todaysMonth=(todayStr[4:2])
progMonth=(progStr[4:2])
#Day
todaysDay=(todayStr[6:2])
progDay=(progStr[6:2])
if todaysYear > progYear:
#program from a previous year
return FALSE
elif progYear > todaysYear:
#program in the future
return TRUE
else:
_debug_('Same year', 5)
#program in the same year
if todaysMonth > progMonth:
#program in a previous month
return FALSE
elif progMonth > todaysMonth:
#program in the future
return TRUE
else:
_debug_('Same month', 5)
#program in the same month
if todaysDay > progDay:
#program was previous aired this month
return FALSE
else:
_debug_('Same day or in the upcoming month', 5)
#program is today or in the upcoming days
return TRUE
else:
_debug_('No good date format, assuming new Episode to be on the safe side', 3)
return TRUE
#
# Shrink a string by removing all spaces and making it
# lower case and then returning the MD5 digest of it.
#
def shrink(self, text):
if text:
text = md5.new(text.lower().replace(' ', '')).hexdigest()
else:
text = ''
return text
def getPreviousRecordingKey(self, prog):
'''Return the key to be used for a given prog in the
previouslyRecordedShows hashtable.'''
shrunkTitle = self.shrink(prog.title)
shrunkSub = self.shrink(prog.sub_title)
shrunkDesc = self.shrink(prog.desc);
return ('%s-%s-%s' % (shrunkTitle, shrunkSub, shrunkDesc), \
'%s-%s-' % (shrunkTitle, shrunkSub), \
'%s--%s' % (shrunkTitle, shrunkDesc))
def getPreviousRecording(self, prog):
'''Get a previous recording, or None if none.'''
try:
return self.previouslyRecordedShows[self.getPreviousRecordingKey(prog)]
except KeyError:
return None
def removeDuplicate(self, prog=None):
'''Remove a duplicate recording'''
self.loadPreviouslyRecordedShows()
previous = self.getPreviousRecording(prog)
if previous:
_debug_('Found duplicate, removing', 5)
del self.previouslyRecordedShows[self.getPreviousRecordingKey(previous)]
self.savePreviouslyRecordedShows()
def addDuplicate(self, prog=None):
'''Add program to duplicates hash'''
_debug_('No previous recordings for "%s", "%s", "%s", adding to hash and saving' % \
(prog.title, prog.sub_title, prog.desc), 5)
self.loadPreviouslyRecordedShows()
self.previouslyRecordedShows[self.getPreviousRecordingKey(prog)] = prog
for key in self.getPreviousRecordingKey(prog):
self.previouslyRecordedShows[key] = prog.start
self.savePreviouslyRecordedShows()
def duplicate(self, prog=None):
'''Identify if the given programme is a duplicate. If not,
record it as previously recorded.'''
self.loadPreviouslyRecordedShows()
previous = self.getPreviousRecording(prog)
if previous:
_debug_('Found duplicate for "%s", "%s", "%s", not adding' % \
(prog.title, prog.sub_title, prog.desc), 5)
return TRUE
return FALSE
def addRecordingToSchedule(self, prog=None, inputSchedule=None):
if inputSchedule:
scheduledRecordings=inputSchedule
else:
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.addProgram(prog, tv_util.getKey(prog))
if not inputSchedule:
if config.DUPLICATE_DETECTION:
self.addDuplicate(prog)
self.saveScheduledRecordings(scheduledRecordings)
def removeRecordingFromSchedule(self, prog=None, inputSchedule=None):
if inputSchedule:
scheduledRecordings=inputSchedule
else:
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.removeProgram(prog, tv_util.getKey(prog))
if not inputSchedule:
if config.DUPLICATE_DETECTION:
self.removeDuplicate(prog)
self.saveScheduledRecordings(scheduledRecordings)
def conflictResolution(self, prog):
def exactMatch(self, prog):
if prog.desc:
descResult=FALSE
descMatches=None
(descResult, descMatches)=self.findMatches(prog.desc)
if descResult:
_debug_('Exact Matches %s' % (len(descMatches)), 5)
return descMatches
if prog.sub_title:
sub_titleResult=FALSE
sub_titleMatches=None
(sub_titleResult, sub_titleMatches)=self.findMatches(prog.sub_title)
if sub_titleResult:
_debug_('Exact Matches %s' % (len(sub_titleMatches)), 5)
return sub_titleMatches
return None
def getConflicts(self, prog, myScheduledRecordings):
_debug_('Before mySched recordings; ignore all addProgram lines', 5)
self.addRecordingToSchedule(prog, myScheduledRecordings)
progs = myScheduledRecordings.getProgramList()
proglist = list(progs)
proglist.sort(self.progsTimeCompare)
conflictRating=0
conflicts=[]
for i in range(0, len(proglist)-1):
thisprog = progs[proglist[i]]
nextprog = progs[proglist[i+1]]
if thisprog.stop > nextprog.start:
conflictRating=conflictRating+1
if thisprog==prog:
conflicts.append(nextprog)
elif nextprog==prog:
conflicts.append(thisprog)
self.removeRecordingFromSchedule(prog, myScheduledRecordings)
_debug_('After mySched recordings; stop ignoring all addProgram lines', 5)
return (conflictRating,conflicts)
def getRatedConflicts(self,prog,myScheduledRecordings):
ratedConflicts=[]
occurances = exactMatch(self,prog)
if not occurances:
#program no longer exists
return (FALSE,None,None)
#Search through all occurances of looking for a non-conflicted occurance
for oneOccurance in occurances:
(rating, conflictedProgs)=getConflicts(self,oneOccurance,myScheduledRecordings)
if rating==0:
_debug_('No Conflict', 5)
programsToChange=[]
programsToChange.append(('add',oneOccurance))
return(TRUE,ratedConflicts,programsToChange)
_debug_('Conflict Found', 5)
ratedConflicts.append((rating,conflictedProgs,oneOccurance))
return (FALSE,ratedConflicts,None)
if config.CONFLICT_RESOLUTION:
_debug_('Conflict resolution enabled', 5)
ratedConflicts=[]
myScheduledRecordings = copy.deepcopy(self.getScheduledRecordings())
#Try to record it at its listed time
(rating, conflictedProg)=getConflicts(self,prog,myScheduledRecordings)
if rating==0:
#No need to do anything fancy; this will work at its defaul time
progsToChange=[]
progsToChange.append(('add',prog))
return (TRUE, 'No conflicts, using default time', progsToChange)
#Default time didn't work, let's try all times known
(result, ratedConflicts, progsToChange)=getRatedConflicts(self,prog,myScheduledRecordings)
if result:
#No conflicts
return (TRUE, 'No conflicts if new program is added', progsToChange)
if not ratedConflicts:
#Program no longer exists, should never hit this unless schedule changes
return (FALSE, 'Cannot schedule, new prog no longer exists', None)
_debug_('Going into conflict resolution via scheduled program re-scheduling', 5)
# No viable time to schedule the program without a conflict
# Try and reschedule the already scheduled program
atleastOneSingleConflict=FALSE
for (scheduledConflictRating,scheduledConflictPrograms,conflictProgram) in ratedConflicts:
#Only handle one conflict at the moment
if scheduledConflictRating==1:
atleastOneSingleConflict=TRUE
scheduledConflictProgram=scheduledConflictPrograms[0]
#remove already scheduled program and try to reschedule it with the new program
self.removeRecordingFromSchedule(scheduledConflictProgram,myScheduledRecordings)
self.addRecordingToSchedule(conflictProgram,myScheduledRecordings)
(result, ratedConflicts, progsToChange)=getRatedConflicts(self, \
scheduledConflictProgram, myScheduledRecordings)
if result:
#No conflicts
progsToChange.append(('del',scheduledConflictProgram))
progsToChange.append(('add',conflictProgram))
return (TRUE, 'No conflicts if scheduled program is rescheduled', progsToChange)
if not ratedConflicts:
#Program no longer exists, should never hit this unless schedule changes
progsToChange.append(('del',scheduledConflictProgram))
progsToChange.append(('add',conflictProgram))
return (TRUE, 'Cannot find conflicted program, adding new', progsToChange)
#Return this to original state
self.addRecordingToSchedule(scheduledConflictProgram,myScheduledRecordings)
self.removeRecordingFromSchedule(conflictProgram,myScheduledRecordings)
if not atleastOneSingleConflict:
#Dirty way to (not) handle multiple conflicts
return (FALSE, 'Cannot handle multiple conflicts: %s not scheduled' % (prog.title), None)
_debug_('Going into conflict resolution via priority', 5)
# No viable option to reschedule the original program
# Time to resolve the conflict via priority
tempRating=1000
tempConflicted=None
tempProg=None
#Find least conflicted
for (conflictedRating, conflictedPrograms, tempProgram) in ratedConflicts:
#Cannot handle multiple conflicts
conflictedProgram=conflictedPrograms[0]
if conflictedRating < tempRating:
tempRating=conflictedRating
tempConflicted=conflictedProgram
tempProg=tempProgram
conflictedProgram=tempConflicted
prog=tempProgram
#Here is where it gets ugly
(isProgFav, progFav) = self.getFavoriteObject(prog)
(isConfFav, confFav) = self.getFavoriteObject(conflictedProgram)
if not isProgFav and isConfFav:
#Regular recording has higher priority then favorite
progsToChange=[]
progsToChange.append(('del', conflictedProgram))
progsToChange.append(('add', prog))
reason='New program is a regular recording(added), scheduled is a Favorite(removed)'
return (TRUE, reason, progsToChange)
elif isProgFav and not isConfFav:
#Regular recording has higher priority then favorite
progsToChange=[]
progsToChange.append(('del', prog))
progsToChange.append(('add', conflictedProgram))
reason='Scheduled program is a regular recording(added), new is a Favorite(removed)'
return (TRUE, reason, progsToChange)
elif not isProgFav and not isConfFav:
return (FALSE, 'Both are regular programs, not adding new recording', None)
elif isProgFav and isConfFav:
#Both are favorites, go by priority (lower is better)
if progFav.priority < confFav.priority:
progsToChange=[]
progsToChange.append(('del', conflictedProgram))
progsToChange.append(('add', prog))
reason='New program is higher rated(added), Scheduled is lower(removed)'
return (TRUE, reason, progsToChange)
elif confFav.priority < progFav.priority:
progsToChange=[]
progsToChange.append(('del', prog))
progsToChange.append(('add', conflictedProgram))
reason='Scheduled program is higher rated(added), New is lower(removed)'
return (TRUE, reason, progsToChange)
else:
#Equal priority, not adding new program
return (FALSE, 'Both are regular programs, not adding new recording', None)
else:
return (FALSE, 'No viable way to schedule', None)
else:
progsToChange=[]
progsToChange.append(('add', prog))
return (TRUE, 'Conflict resolution disabled', progsToChange)
def checkOnlyNewDetection(self, prog=None):
if config.ONLY_NEW_DETECTION:
_debug_('Only new episode detection enabled', 5)
if not self.doesFavoriteRecordOnlyNewEpisodes(prog):
return (TRUE, 'Favorite records all episodes, record')
if self.newEpisode(prog):
return (TRUE, 'New episode, record')
else:
return (FALSE, 'Old episode, do not record')
else:
return (TRUE, 'Only new episode detection disabled, record')
def checkDuplicateDetection(self, prog=None):
if config.DUPLICATE_DETECTION:
_debug_('Duplicate detection enabled', 5)
if self.doesFavoriteAllowDuplicates(prog):
return (TRUE, 'Favorite allows duplicates, record')
if not self.duplicate(prog):
return (TRUE, 'Not a duplicate, record')
else:
return (FALSE, 'Duplicate recording, do not record')
else:
return (TRUE, 'Duplicate detection is disabled, record')
def setTunerid(self, prog):
for chan in guide.chan_list:
if prog.channel_id == chan.id:
_debug_('scheduleRecording: "%s"' % (prog), 3)
prog.tunerid = chan.tunerid
return prog
def scheduleRecording(self, prog=None):
global guide
if not prog:
return (FALSE, 'no prog')
now = time.time()
if now > prog.stop:
return (FALSE, 'cannot record it if it is over')
self.updateGuide()
(isFav, favorite) = self.isProgAFavorite(prog)
if isFav:
(onlyNewBool, onlyNewReason) = self.checkOnlyNewDetection(prog)
_debug_('Only new episode detection result: %s reason %s' % (onlyNewBool,onlyNewReason), 3)
if not onlyNewBool:
#failed only new episode check (old episode, etc)
return (FALSE, onlyNewReason)
(duplicateBool, duplicateReason) = self.checkDuplicateDetection(prog)
_debug_('Duplicate detection result: %s reason %s' % (duplicateBool,duplicateReason), 3)
if not duplicateBool:
#failed duplicate check (duplicate, etc)
return (FALSE, duplicateReason)
(ableToResolveBool, resolutionReason, progsToChange) = self.conflictResolution(prog)
_debug_('Conflict resolution result: %s reason %s' % (ableToResolveBool,resolutionReason), 3)
if not ableToResolveBool:
#No viable solution was found
return (FALSE, resolutionReason)
if progsToChange:
for (cmd, prog) in progsToChange:
prog=self.setTunerid(prog)
if cmd=='add':
_debug_('SCHEDULER: adding %s' % (prog.title), 3)
self.addRecordingToSchedule(prog)
elif cmd=='del':
_debug_('SCHEDULER: removing %s' % (prog.title), 3)
self.removeRecordingFromSchedule(prog)
else:
prog=self.setTunerid(prog)
_debug_('SCHEDULER: adding %s' % (prog.title), 3)
self.addRecordingToSchedule(prog)
# check, maybe we need to start right now
self.checkToRecord()
return (TRUE, 'recording scheduled')
def removeScheduledRecording(self, prog=None):
if not prog:
return (FALSE, 'no prog')
# get our version of 'prog'
# It's a bad hack, but we can use isRecording than
sr = self.getScheduledRecordings()
progs = sr.getProgramList()
for saved_prog in progs.values():
if String(saved_prog) == String(prog):
prog = saved_prog
break
try:
recording = prog.isRecording
except Exception, e:
print 'prog.isRecording:', e
recording = FALSE
self.removeRecordingFromSchedule(prog)
now = time.time()
# if now >= prog.start and now <= prog.stop and recording:
if recording:
print 'stopping current recording %s' % (prog)
rec_plugin = plugin.getbyname('RECORD')
if rec_plugin:
rec_plugin.Stop()
return (TRUE, 'recording removed')
def isProgScheduled(self, prog, schedule=None):
if schedule == {}:
return (FALSE, 'prog not scheduled')
if not schedule:
schedule = self.getScheduledRecordings().getProgramList()
for me in schedule.values():
if me.start == prog.start and me.channel_id == prog.channel_id:
return (TRUE, 'prog is scheduled')
return (FALSE, 'prog not scheduled')
def findProg(self, chan=None, start=None):
global guide
_debug_('findProg: %s, %s' % (chan, start), 3)
if not chan or not start:
return (FALSE, 'no chan or no start')
self.updateGuide()
for ch in guide.chan_list:
if chan == ch.id:
_debug_('CHANNEL MATCH: %s' % ch.id, 5)
for prog in ch.programs:
if start == '%s' % prog.start:
_debug_('PROGRAM MATCH 1: %s' % prog, 5)
return (TRUE, prog.utf2str())
return (FALSE, 'prog not found')
def findMatches(self, find=None, movies_only=None):
global guide
_debug_('findMatches: %s' % find, 3)
matches = []
max_results = 500
if not find and not movies_only:
_debug_('nothing to find', 5)
return (FALSE, 'no search string')
self.updateGuide()
pattern = '.*' + find + '\ *'
regex = re.compile(pattern, re.IGNORECASE)
now = time.time()
for ch in guide.chan_list:
for prog in ch.programs:
if now >= prog.stop:
continue
if not find or regex.match(prog.title) or regex.match(prog.desc) \
or regex.match(prog.sub_title):
if movies_only:
# We can do better here than just look for the MPAA
# rating. Suggestions are welcome.
if 'MPAA' in prog.utf2str().getattr('ratings').keys():
matches.append(prog.utf2str())
_debug_('PROGRAM MATCH 2: %s' % prog, 5)
else:
# We should never get here if not find and not
# movies_only.
matches.append(prog.utf2str())
_debug_('PROGRAM MATCH 3: %s' % prog, 5)
if len(matches) >= max_results:
break
_debug_('Found %d matches.' % len(matches), 3)
if matches:
return (TRUE, matches)
return (FALSE, 'no matches')
def updateGuide(self):
global guide
guide = tv.epg_xmltv.get_guide()
def checkToRecord(self):
rec_cmd = None
rec_prog = None
cleaned = None
delay_recording = FALSE
sr = self.getScheduledRecordings()
progs = sr.getProgramList()
currently_recording = None
for prog in progs.values():
try:
recording = prog.isRecording
except:
recording = FALSE
if recording:
currently_recording = prog
now = time.time()
for prog in progs.values():
_debug_('checkToRecord: progloop=%s' % prog, 5)
try:
recording = prog.isRecording
except:
recording = FALSE
if not recording \
and now >= (prog.start - config.TV_RECORD_PADDING_PRE) \
and now < (prog.stop + config.TV_RECORD_PADDING_POST):
# just add to the 'we want to record this' list
# then end the loop, and figure out which has priority,
# remember to take into account the full length of the shows
# and how much they overlap, or chop one short
duration = int((prog.stop + config.TV_RECORD_PADDING_POST) - now)
if duration < 10:
return
if currently_recording:
# Hey, something is already recording!
if prog.start - 10 <= now:
# our new recording should start no later than now!
# check if the new prog is a favorite and the current running is
# not. If so, the user manually added something, we guess it
# has a higher priority.
if self.isProgAFavorite(prog)[0] \
and not self.isProgAFavorite(currently_recording)[0] \
and now < (prog.stop + config.TV_RECORD_PADDING_POST):
_debug_('Ignoring %s' % prog, 3)
continue
sr.removeProgram(currently_recording,
tv_util.getKey(currently_recording))
plugin.getbyname('RECORD').Stop()
time.sleep(5)
_debug_('CALLED RECORD STOP 1: %s' % currently_recording, 3)
else:
# at this moment we must be in the pre-record padding
if currently_recording.stop - 10 <= now:
# The only reason we are still recording is because of
# the post-record padding.
# Therefore we have overlapping paddings but not
# real stop / start times.
overlap = (currently_recording.stop + \
config.TV_RECORD_PADDING_POST) - \
(prog.start - config.TV_RECORD_PADDING_PRE)
if overlap <= ((config.TV_RECORD_PADDING_PRE +
config.TV_RECORD_PADDING_POST)/4):
sr.removeProgram(currently_recording,
tv_util.getKey(currently_recording))
plugin.getbyname('RECORD').Stop()
time.sleep(5)
_debug_('CALLED RECORD STOP 2: %s' % currently_recording, 3)
else:
delay_recording = TRUE
else:
delay_recording = TRUE
if delay_recording:
_debug_('delaying: %s' % prog, 3)
else:
_debug_('going to record: %s' % prog, 3)
prog.isRecording = TRUE
prog.rec_duration = duration
prog.filename = tv_util.getProgFilename(prog)
rec_prog = prog
for prog in progs.values():
# If the program is over remove the entry.
if now > (prog.stop + config.TV_RECORD_PADDING_POST):
_debug_('found a program to clean: %s' % prog, 3)
cleaned = TRUE
del progs[tv_util.getKey(prog)]
if rec_prog or cleaned:
sr.setProgramList(progs)
self.saveScheduledRecordings(sr)
if rec_prog:
_debug_('start recording: %s' % rec_prog, 1)
self.record_app = plugin.getbyname('RECORD')
if not self.record_app:
print_plugin_warning()
_debug_('ERROR: Recording %s failed.' % rec_prog.title, 0)
self.removeScheduledRecording(rec_prog)
return
self.vg = self.fc.getVideoGroup(rec_prog.channel_id, FALSE)
suffix=self.vg.vdev.split('/')[-1]
self.tv_lock_file = config.FREEVO_CACHEDIR + '/record.'+suffix
self.record_app.Record(rec_prog)
# Cleanup old recordings (if enabled)
if config.RECORDSERVER_CLEANUP_THRESHOLD > 0:
space_threshold = config.RECORDSERVER_CLEANUP_THRESHOLD * 1024 * 1024 * 1024
path = config.TV_RECORD_DIR
freespace = util.freespace(path)
if freespace < space_threshold:
files = os.listdir(path)
files = util.find_matches(files, config.VIDEO_SUFFIX)
files = [(f, os.stat(os.path.join(path,f)).st_mtime) for f in files]
files.sort(lambda x,y: cmp(x[1], y[1]))
i = 0
while freespace < space_threshold and i < len(files):
oldestrec = files[i][0]
oldestfxd = oldestrec[:oldestrec.rfind('.')] + '.fxd'
print 'Low on disk space - delete oldest recording: %s' % oldestrec
os.remove(os.path.join(path,oldestrec))
os.remove(os.path.join(path,oldestfxd))
freespace = util.freespace(path)
i = i + 1
def addFavorite(self, name, prog, exactchan=FALSE, exactdow=FALSE, exacttod=FALSE):
if not name:
return (FALSE, 'no name')
(status, favs) = self.getFavorites()
priority = len(favs) + 1
fav = tv.record_types.Favorite(name, prog, exactchan, exactdow, exacttod, priority, allowDuplicates, onlyNew)
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.addFavorite(fav)
self.saveScheduledRecordings(scheduledRecordings)
self.addFavoriteToSchedule(fav)
return (TRUE, 'favorite added')
def addEditedFavorite(self, name, title, chan, dow, mod, priority, allowDuplicates, onlyNew):
fav = tv.record_types.Favorite()
fav.name = name
fav.title = title
fav.channel = chan
fav.dow = dow
fav.mod = mod
fav.priority = priority
fav.allowDuplicates = allowDuplicates
fav.onlyNew = onlyNew
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.addFavorite(fav)
self.saveScheduledRecordings(scheduledRecordings)
self.addFavoriteToSchedule(fav)
return (TRUE, 'favorite added')
def removeFavorite(self, name=None):
if not name:
return (FALSE, 'no name')
(status, fav) = self.getFavorite(name)
self.removeFavoriteFromSchedule(fav)
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.removeFavorite(name)
self.saveScheduledRecordings(scheduledRecordings)
return (TRUE, 'favorite removed')
def clearFavorites(self):
scheduledRecordings = self.getScheduledRecordings()
scheduledRecordings.clearFavorites()
self.saveScheduledRecordings(scheduledRecordings)
return (TRUE, 'favorites cleared')
def getFavorites(self):
return (TRUE, self.getScheduledRecordings().getFavorites())
def getFavorite(self, name):
(status, favs) = self.getFavorites()
if favs.has_key(name):
fav = favs[name]
return (TRUE, fav)
else:
return (FALSE, 'not a favorite')
def adjustPriority(self, favname, mod=0):
save = []
mod = int(mod)
(status, me) = self.getFavorite(favname)
oldprio = int(me.priority)
newprio = oldprio + mod
_debug_('ap: mod=%s' % mod, 3)
sr = self.getScheduledRecordings()
favs = sr.getFavorites().values()
_debug_('adjusting prio of '+favname, 3)
for fav in favs:
fav.priority = int(fav.priority)
if fav.name == me.name:
_debug_('MATCH', 5)
fav.priority = newprio
_debug_('moved prio of %s: %s => %s' % (fav.name, oldprio, newprio), 3)
continue
if mod < 0:
if fav.priority < newprio or fav.priority > oldprio:
_debug_('fp: %s, old: %s, new: %s' % (fav.priority, oldprio, newprio), 3)
_debug_('skipping: %s' % fav.name, 3)
continue
fav.priority = fav.priority + 1
_debug_('moved prio of %s: %s => %s' % (fav.name, fav.priority-1, fav.priority), 3)
if mod > 0:
if fav.priority > newprio or fav.priority < oldprio:
_debug_('skipping: %s' % fav.name, 3)
continue
fav.priority = fav.priority - 1
_debug_('moved prio of %s: %s => %s' % (fav.name, fav.priority+1, fav.priority), 3)
sr.setFavoritesList(favs)
self.saveScheduledRecordings(sr)
return (TRUE, 'priorities adjusted')
def getFavoriteObject(self, prog, favs=None):
#more liberal favorite check that returns an object
if not favs:
(status, favs) = self.getFavorites()
for fav in favs.values():
if Unicode(prog.title).lower().find(Unicode(fav.title).lower()) >= 0:
return (TRUE, fav)
# if we get this far prog is not a favorite
return (FALSE, 'not a favorite')
def isProgAFavorite(self, prog, favs=None):
if not favs:
(status, favs) = self.getFavorites()
lt = time.localtime(prog.start)
dow = '%s' % lt[6]
mod = '%s' % ((lt[3]*60)+(lt[4] / 30 * 30))
mod = '%s' % ((lt[3]*60)+lt[4])
for fav in favs.values():
if Unicode(prog.title).lower().find(Unicode(fav.title).lower()) >= 0:
if fav.channel == tv_util.get_chan_displayname(prog.channel_id) \
or fav.channel == 'ANY':
if Unicode(fav.dow) == Unicode(dow) or Unicode(fav.dow) == u'ANY':
if Unicode(fav.mod) == Unicode(mod) \
or Unicode(fav.mod) == u'ANY':
return (TRUE, fav.name)
# if we get this far prog is not a favorite
return (FALSE, 'not a favorite')
def doesFavoriteRecordOnlyNewEpisodes(self, prog, favs=None):
if not favs:
(status, favs) = self.getFavorites()
for fav in favs.values():
if Unicode(prog.title).lower().find(Unicode(fav.title).lower()) >= 0:
_debug_('NEW: %s'%fav.onlyNew, 5)
if fav.onlyNew == '1':
return TRUE
def doesFavoriteAllowDuplicates(self, prog, favs=None):
if not favs:
(status, favs) = self.getFavorites()
for fav in favs.values():
if Unicode(prog.title).lower().find(Unicode(fav.title).lower()) >= 0:
_debug_('DUP: %s'%fav.allowDuplicates, 5)
if fav.allowDuplicates == '1':
return TRUE
def removeFavoriteFromSchedule(self, fav):
# TODO: make sure the program we remove is not
# covered by another favorite.
tmp = {}
tmp[fav.name] = fav
scheduledRecordings = self.getScheduledRecordings()
progs = scheduledRecordings.getProgramList()
for prog in progs.values():
(isFav, favorite) = self.isProgAFavorite(prog, tmp)
if isFav:
self.removeScheduledRecording(prog)
return (TRUE, 'favorite unscheduled')
def addFavoriteToSchedule(self, fav):
global guide
favs = {}
favs[fav.name] = fav
self.updateGuide()
for ch in guide.chan_list:
for prog in ch.programs:
(isFav, favorite) = self.isProgAFavorite(prog, favs)
if isFav:
prog.isFavorite = favorite
self.scheduleRecording(prog)
return (TRUE, 'favorite scheduled')
def updateFavoritesSchedule(self):
# TODO: do not re-add a prog to record if we have
# previously decided not to record it.
global guide
self.updateGuide()
# First get the timeframe of the guide.
last = 0
for ch in guide.chan_list:
for prog in ch.programs:
if prog.start > last: last = prog.start
scheduledRecordings = self.getScheduledRecordings()
(status, favs) = self.getFavorites()
if not len(favs):
return (FALSE, 'there are no favorites to update')
# Then remove all scheduled favorites in that timeframe to
# make up for schedule changes.
progs = scheduledRecordings.getProgramList()
for prog in progs.values():
# try:
# favorite = prog.isFavorite
# except:
# favorite = FALSE
# if prog.start <= last and favorite:
(isFav, favorite) = self.isProgAFavorite(prog, favs)
if prog.start <= last and isFav:
# do not yet remove programs currently being recorded:
isRec = hasattr(prog, "isRecording") and prog.isRecording
if not isRec:
self.removeScheduledRecording(prog)
for ch in guide.chan_list:
for prog in ch.programs:
(isFav, favorite) = self.isProgAFavorite(prog, favs)
isRec = hasattr(prog, "isRecording") and prog.isRecording
if isFav and not isRec:
prog.isFavorite = favorite
self.scheduleRecording(prog)
return (TRUE, 'favorites schedule updated')
#################################################################
# Start XML-RPC published methods. #
#################################################################
def xmlrpc_isPlayerRunning(self):
(status, message) = (FALSE, 'RecordServer::isPlayerRunning: cannot acquire lock')
self.lock.acquire()
try:
status = self.isPlayerRunning()
message = status and 'player is running' or 'player is not running'
finally:
self.lock.release()
return (status, message)
def xmlrpc_isRecording(self):
(status, message) = (FALSE, 'RecordServer::isRecording: cannot acquire lock')
self.lock.acquire()
try:
status = self.isRecording()
message = status and 'is recording' or 'is not recording'
finally:
self.lock.release()
return (status, message)
def xmlrpc_findNextProgram(self):
(status, message) = (FALSE, 'RecordServer::findNextProgram: cannot acquire lock')
self.lock.acquire()
try:
response = self.findNextProgram()
status = response != None
return (status, jellyToXML(response))
finally:
self.lock.release()
return (status, message)
def xmlrpc_getScheduledRecordings(self):
(status, message) = (FALSE, 'RecordServer::getScheduledRecordings: cannot acquire lock')
self.lock.acquire()
try:
return (TRUE, jellyToXML(self.getScheduledRecordings()))
finally:
self.lock.release()
return (status, message)
def xmlrpc_saveScheduledRecordings(self, scheduledRecordings=None):
(status, message) = (FALSE, 'RecordServer::saveScheduledRecordings: cannot acquire lock')
self.lock.acquire()
try:
status = self.saveScheduledRecordings(scheduledRecordings)
message = status and 'saveScheduledRecordings::success' or 'saveScheduledRecordings::failure'
finally:
self.lock.release()
return (status, message)
def xmlrpc_scheduleRecording(self, prog=None):
if not prog:
return (FALSE, 'RecordServer::scheduleRecording: no prog')
(status, message) = (FALSE, 'RecordServer::scheduleRecording: cannot acquire lock')
self.lock.acquire()
try:
prog = unjellyFromXML(prog)
(status, response) = self.scheduleRecording(prog)
message = 'RecordServer::scheduleRecording: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_removeScheduledRecording(self, prog=None):
if not prog:
return (FALSE, 'RecordServer::removeScheduledRecording: no prog')
(status, message) = (FALSE, 'RecordServer::removeScheduledRecording: cannot acquire lock')
self.lock.acquire()
try:
prog = unjellyFromXML(prog)
(status, response) = self.removeScheduledRecording(prog)
message = 'RecordServer::removeScheduledRecording: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_isProgScheduled(self, prog=None, schedule=None):
if not prog:
return (FALSE, 'removeScheduledRecording::failure: no prog')
(status, message) = (FALSE, 'RecordServer::removeScheduledRecording: cannot acquire lock')
self.lock.acquire()
try:
prog = unjellyFromXML(prog)
if schedule:
schedule = unjellyFromXML(schedule)
(status, response) = self.isProgScheduled(prog, schedule)
message = 'RecordServer::isProgScheduled: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_findProg(self, chan, start):
(status, message) = (FALSE, 'RecordServer::findProg: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.findProg(chan, start)
message = status and jellyToXML(response) or ('RecordServer::findProg: %s' % response)
finally:
self.lock.release()
return (status, message)
def xmlrpc_findMatches(self, find, movies_only):
(status, message) = (FALSE, 'RecordServer::findMatches: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.findMatches(find, movies_only)
message = status and jellyToXML(response) or ('RecordServer::findMatches: %s' % response)
finally:
self.lock.release()
return (status, message)
def xmlrpc_echotest(self, blah):
(status, message) = (FALSE, 'RecordServer::echotest: cannot acquire lock')
self.lock.acquire()
try:
(status, message) = (TRUE, 'RecordServer::echotest: %s' % blah)
finally:
self.lock.release()
return (status, message)
def xmlrpc_addFavorite(self, name, prog, exactchan=FALSE, exactdow=FALSE, exacttod=FALSE):
(status, message) = (FALSE, 'RecordServer::addFavorite: cannot acquire lock')
self.lock.acquire()
try:
prog = unjellyFromXML(prog)
(status, response) = self.addFavorite(name, prog, exactchan, exactdow, exacttod)
message = 'RecordServer::addFavorite: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_addEditedFavorite(self, name, title, chan, dow, mod, priority, allowDuplicates, onlyNew):
(status, message) = (FALSE, 'RecordServer::addEditedFavorite: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.addEditedFavorite(unjellyFromXML(name), \
unjellyFromXML(title), chan, dow, mod, priority, allowDuplicates, onlyNew)
message = 'RecordServer::addEditedFavorite: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_removeFavorite(self, name=None):
(status, message) = (FALSE, 'RecordServer::removeFavorite: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.removeFavorite(name)
message = 'RecordServer::removeFavorite: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_clearFavorites(self):
(status, message) = (FALSE, 'RecordServer::clearFavorites: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.clearFavorites()
message = 'RecordServer::clearFavorites: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_getFavorites(self):
(status, message) = (FALSE, 'RecordServer::getFavorites: cannot acquire lock')
self.lock.acquire()
try:
(status, message) = (TRUE, jellyToXML(self.getScheduledRecordings().getFavorites()))
finally:
self.lock.release()
return (status, message)
def xmlrpc_getFavorite(self, name):
(status, message) = (FALSE, 'RecordServer::getFavorite: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.getFavorite(name)
message = status and jellyToXML(response) or 'RecordServer::getFavorite: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_adjustPriority(self, favname, mod=0):
(status, message) = (FALSE, 'RecordServer::adjustPriority: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.adjustPriority(favname, mod)
message = 'RecordServer::adjustPriority: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_isProgAFavorite(self, prog, favs=None):
(status, message) = (FALSE, 'RecordServer::adjustPriority: cannot acquire lock')
self.lock.acquire()
try:
prog = unjellyFromXML(prog)
if favs:
favs = unjellyFromXML(favs)
(status, response) = self.isProgAFavorite(prog, favs)
message = 'RecordServer::adjustPriority: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_removeFavoriteFromSchedule(self, fav):
(status, message) = (FALSE, 'RecordServer::removeFavoriteFromSchedule: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.removeFavoriteFromSchedule(fav)
message = 'RecordServer::removeFavoriteFromSchedule: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_addFavoriteToSchedule(self, fav):
(status, message) = (FALSE, 'RecordServer::addFavoriteToSchedule: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.addFavoriteToSchedule(fav)
message = 'RecordServer::addFavoriteToSchedule: %s' % response
finally:
self.lock.release()
return (status, message)
def xmlrpc_updateFavoritesSchedule(self):
(status, message) = (FALSE, 'updateFavoritesSchedule: cannot acquire lock')
self.lock.acquire()
try:
(status, response) = self.updateFavoritesSchedule()
message = 'RecordServer::updateFavoritesSchedule: %s' % response
finally:
self.lock.release()
return (status, message)
#################################################################
# End XML-RPC published methods. #
#################################################################
def create_fxd(self, rec_prog):
from util.fxdimdb import FxdImdb, makeVideo
fxd = FxdImdb()
(filebase, fileext) = os.path.splitext(rec_prog.filename)
fxd.setFxdFile(filebase, overwrite=TRUE)
video = makeVideo('file', 'f1', os.path.basename(rec_prog.filename))
fxd.setVideo(video)
fxd.info['tagline'] = fxd.str2XML(rec_prog.sub_title)
fxd.info['plot'] = fxd.str2XML(rec_prog.desc)
fxd.info['runtime'] = None
fxd.info['recording_timestamp'] = str(time.time())
fxd.info['year'] = time.strftime('%m-%d ' + config.TV_TIMEFORMAT,
time.localtime(rec_prog.start))
fxd.title = rec_prog.title
fxd.writeFxd()
def startMinuteCheck(self):
next_minute = (int(time.time()/60) * 60 + 60) - int(time.time())
_debug_('top of the minute in %s seconds' % next_minute, 1)
reactor.callLater(next_minute, self.minuteCheck)
def minuteCheck(self):
next_minute = (int(time.time()/60) * 60 + 60) - int(time.time())
if next_minute != 60:
# Compensate for timer drift
if DEBUG:
log.debug('top of the minute in %s seconds' % next_minute)
reactor.callLater(next_minute, self.minuteCheck)
else:
reactor.callLater(60, self.minuteCheck)
self.checkToRecord()
def eventNotice(self):
#print 'RECORDSERVER GOT EVENT NOTICE'
# Use callLater so that handleEvents will get called the next time
# through the main loop.
reactor.callLater(0, self.handleEvents)
def handleEvents(self):
event = rc_object.get_event()
if event:
if event == OS_EVENT_POPEN2:
print 'popen %s' % event.arg[1]
event.arg[0].child = util.popen3.Popen3(event.arg[1])
elif event == OS_EVENT_WAITPID:
pid = event.arg[0]
print 'waiting on pid %s' % pid
for i in range(20):
try:
wpid = os.waitpid(pid, os.WNOHANG)[0]
except OSError:
# forget it
continue
if wpid == pid:
break
time.sleep(0.1)
elif event == OS_EVENT_KILL:
pid = event.arg[0]
sig = event.arg[1]
print 'killing pid %s with sig %s' % (pid, sig)
try:
os.kill(pid, sig)
except OSError:
pass
for i in range(20):
try:
wpid = os.waitpid(pid, os.WNOHANG)[0]
except OSError:
# forget it
continue
if wpid == pid:
break
time.sleep(0.1)
else:
print 'force killing with signal 9'
try:
os.kill(pid, 9)
except OSError:
pass
for i in range(20):
try:
wpid = os.waitpid(pid, os.WNOHANG)[0]
except OSError:
# forget it
continue
if wpid == pid:
break
time.sleep(0.1)
print 'recorderver: After wait()'
elif event == RECORD_START:
print 'received event RECORD_START'
prog = event.arg
open(self.tv_lock_file, 'w').close()
self.create_fxd(prog)
if config.VCR_PRE_REC:
util.popen3.Popen3(config.VCR_PRE_REC)
elif event == RECORD_STOP:
print 'received event RECORD_STOP'
os.remove(self.tv_lock_file)
prog = event.arg
try:
snapshot(prog.filename)
except:
# If automatic pickling fails, use on-demand caching when
# the file is accessed instead.
os.rename(vfs.getoverlay(prog.filename + '.raw.tmp'),
vfs.getoverlay(os.path.splitext(prog.filename)[0] + '.png'))
pass
if config.VCR_POST_REC:
util.popen3.Popen3(config.VCR_POST_REC)
if config.REMOVE_COMMERCIALS:
(result, response) = connectionTest('connection test')
if result:
(status, idnr) = initCommDetectJob(prog.filename)
(status, output) = listJobs()
_debug_(output, 5)
(status, output) = queueIt(idnr, True)
_debug_(output, 5)
else:
_debug_('commdetect server not running', 1)
else:
print 'not handling event %s' % str(event)
return
else:
print 'no event to get'
def main():
app = Application("RecordServer")
rs = RecordServer()
if (DEBUG == 0):
app.listenTCP(config.RECORDSERVER_PORT, server.Site(rs, logPath='/dev/null'))
else:
app.listenTCP(config.RECORDSERVER_PORT, server.Site(rs))
rs.startMinuteCheck()
rc_object.subscribe(rs.eventNotice)
app.run(save=0)
if __name__ == '__main__':
import traceback
import time
import glob
locks = glob.glob(config.FREEVO_CACHEDIR + '/record.*')
for f in locks:
print 'Removed old record lock \"%s\"' % f
os.remove(f)
while 1:
try:
start = time.time()
main()
break
except:
traceback.print_exc()
if start + 10 > time.time():
print 'server problem, sleeping 1 min'
time.sleep(60)
freevo webserver start
Traceback (most recent call last):
File "/var/lib/python-support/python2.5/freevo/helpers/webserver.py", line 52, in <module>
from twisted.internet import app
ImportError: cannot import name app
import sys, os
import config
appname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
appconf = appname.upper()
# change uid
if __name__ == '__main__':
uid='config.'+appconf+'_UID'
gid='config.'+appconf+'_GID'
try:
if eval(uid) and os.getuid() == 0:
os.setgid(eval(gid))
os.setuid(eval(uid))
os.environ['USER'] = pwd.getpwuid(os.getuid())[0]
os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
except Exception, e:
print e
from twisted.internet import app
#from twisted.internet import reactor
from twisted.web import static, server, vhost, script
from twisted.python import log
import twisted.web.rewrite as rewrite
if len(sys.argv)>1 and sys.argv[1] == '--help':
print 'start or stop the internal webserver'
print 'usage freevo webserver [ start | stop ]'
sys.exit(0)
# No debugging in this module
DEBUG = hasattr(config, appconf+'_DEBUG') and eval('config.'+appconf+'_DEBUG') or config.DEBUG
def _debug_(text, level=1):
if DEBUG >= level:
try:
log.debug(String(text))
except:
print String(text)
def helpimagesrewrite(request):
if request.postpath and request.postpath[0]=='help' and request.postpath[1]=='images':
request.postpath.pop(0)
request.path = '/'+'/'.join(request.prepath+request.postpath)
if request.postpath and request.postpath[0]=='help' and request.postpath[1]=='styles':
request.postpath.pop(0)
request.path = '/'+'/'.join(request.prepath+request.postpath)
def main():
# the start and stop stuff will be handled from the freevo script
logfile = '%s/%s-%s.log' % (config.LOGDIR, appname, os.getuid())
log.startLogging(open(logfile, 'a'))
if os.path.isdir(os.path.join(os.environ['FREEVO_PYTHON'], 'www/htdocs')):
docRoot = os.path.join(os.environ['FREEVO_PYTHON'], 'www/htdocs')
else:
docRoot = os.path.join(config.SHARE_DIR, 'htdocs')
root = static.File(docRoot)
root.processors = { '.rpy': script.ResourceScript, }
child_resources = []
child_resources.extend(config.VIDEO_ITEMS)
child_resources.extend(config.AUDIO_ITEMS)
child_resources.extend(config.IMAGE_ITEMS)
child_resources.extend([('Recorded TV', config.TV_RECORD_DIR)])
child_resources.extend([('Webserver Cache', config.WEBSERVER_CACHEDIR)])
for item in child_resources:
if isinstance(item, tuple) and len(item) == 2:
(title, path) = item
root.putChild(path.replace("/", "_"), static.File(path))
root.putChild('vhost', vhost.VHostMonsterResource())
rewriter = rewrite.RewriterResource(root, helpimagesrewrite)
if (config.DEBUG == 0):
site = server.Site(rewriter, logPath='/dev/null')
else:
site = server.Site(rewriter)
application = app.Application('web')
# reactor.listenTCP(config.WEBSERVER_PORT, site)
application.listenTCP(config.WEBSERVER_PORT, site)
application.run(save=0)
# reactor.run(0)
if __name__ == '__main__':
import traceback
import time
while 1:
try:
start = time.time()
main()
break
except:
traceback.print_exc()
if start + 10 > time.time():
print 'server problem, sleeping 1 min'
time.sleep(60)