import time
import os
+import bisect
from Components.config import config, currentConfigSelectionElement
class InfoBarDish:
def __init__(self):
self.dishDialog = self.session.instantiateDialog(Dish)
- self.onShown.append(self.dishDialog.show)
+ self.onLayoutFinish.append(self.dishDialog.show)
class InfoBarShowHide:
""" InfoBar show/hide control, accepts toggleShow and hide actions, might start
def __onHide(self):
self.__state = self.STATE_HIDDEN
+ def doShow(self):
+ self.show()
+ self.startHideTimer()
+
def doTimerHide(self):
self.hideTimer.stop()
if self.__state == self.STATE_SHOWN:
# print "You pressed number " + str(number)
if number == 0:
self.servicelist.recallPrevService()
- self.show()
+ self.doShow()
else:
self.session.openWithCallback(self.numberEntered, NumberZap, number)
{
"switchChannelUp": self.switchChannelUp,
"switchChannelDown": self.switchChannelDown,
- "zapUp": (self.zapUp, _("next channel")),
- "zapDown": (self.zapDown, _("previous channel")),
+ "zapUp": (self.zapUp, _("previous channel")),
+ "zapDown": (self.zapDown, _("next channel")),
+ "historyBack": (self.historyBack, _("previous channel in history")),
+ "historyNext": (self.historyNext, _("next channel in history"))
})
+ def historyBack(self):
+ self.servicelist.historyBack()
+
+ def historyNext(self):
+ self.servicelist.historyNext()
+
def switchChannelUp(self):
self.servicelist.moveUp()
self.session.execDialog(self.servicelist)
self.servicelist.moveDown()
self.session.execDialog(self.servicelist)
- def zapUp(self):
+ def zapUp(self):
+ if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes":
+ if self.servicelist.inBouquet() and self.servicelist.atBegin():
+ self.servicelist.prevBouquet()
self.servicelist.moveUp()
self.servicelist.zap()
- self.show()
+ self.doShow()
- def zapDown(self):
- self.servicelist.moveDown()
+ def zapDown(self):
+ if currentConfigSelectionElement(config.usage.quickzap_bouquet_change) == "yes" and self.servicelist.inBouquet() and self.servicelist.atEnd():
+ self.servicelist.nextBouquet()
+ else:
+ self.servicelist.moveDown()
self.servicelist.zap()
- self.show()
+ self.doShow()
class InfoBarMenu:
""" Handles a menu action, to open the (main) menu """
self.servicelist.setCurrentSelection(service) #select the service in servicelist
self.servicelist.zap()
- def openBouquetEPG(self, bouquet):
+ def openBouquetEPG(self, bouquet, withCallback=True):
ptr=eEPGCache.getInstance()
services = [ ]
servicelist = eServiceCenter.getInstance().list(bouquet)
services.append(ServiceReference(service))
if len(services):
self.epg_bouquet = bouquet
- self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
+ if withCallback:
+ self.session.openWithCallback(self.closed, EPGSelection, services, self.zapToService)
+ else:
+ self.session.open(EPGSelection, services, self.zapToService)
def closed(self, ret):
if ret:
self.close(ret)
- def openMultiServiceEPG(self):
+ def openMultiServiceEPG(self, withCallback=True):
bouquets = self.servicelist.getBouquetList()
if bouquets is None:
cnt = 0
else:
cnt = len(bouquets)
if cnt > 1: # show bouquet list
- self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
+ if withCallback:
+ self.session.openWithCallback(self.closed, BouquetSelector, bouquets, self.openBouquetEPG)
+ else:
+ self.session.open(BouquetSelector, bouquets, self.openBouquetEPG)
elif cnt == 1:
- self.openBouquetEPG(bouquets[0][1])
+ self.openBouquetEPG(bouquets[0][1], withCallback)
def openSingleServiceEPG(self):
ref=self.session.nav.getCurrentlyPlayingServiceReference()
self.session.open(EventViewEPGSelect, self.epglist[0], ServiceReference(ref), self.eventViewCallback, self.openSingleServiceEPG, self.openMultiServiceEPG)
else:
print "no epg for the service avail.. so we show multiepg instead of eventinfo"
- self.openMultiServiceEPG()
+ self.openMultiServiceEPG(False)
def eventViewCallback(self, setEvent, setService, val): #used for now/next displaying
if len(self.epglist) > 1:
self["Event_Now"] = EventInfo(self.session.nav, EventInfo.Now)
self["Event_Next"] = EventInfo(self.session.nav, EventInfo.Next)
- self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Duration)
+ self["Event_Now_Duration"] = EventInfo(self.session.nav, EventInfo.Now_Remaining)
self["Event_Next_Duration"] = EventInfo(self.session.nav, EventInfo.Next_Duration)
self["Now_ProgressBar"] = EventInfoProgress(self.session.nav, EventInfo.Now)
SEEK_STATE_FF_64X = (0, 64, 0, ">> 64x")
SEEK_STATE_FF_128X = (0, 128, 0, ">> 128x")
- SEEK_STATE_BACK_4X = (0, -4, 0, "<< 4x")
+ SEEK_STATE_BACK_16X = (0, -16, 0, "<< 16x")
SEEK_STATE_BACK_32X = (0, -32, 0, "<< 32x")
SEEK_STATE_BACK_64X = (0, -64, 0, "<< 64x")
SEEK_STATE_BACK_128X = (0, -128, 0, "<< 128x")
"unPauseService": (self.unPauseService, "continue"),
"seekFwd": (self.seekFwd, "skip forward"),
- "seekFwdUp": (self.seekFwdUp, "skip forward"),
+ "seekFwdDown": self.seekFwdDown,
+ "seekFwdUp": self.seekFwdUp,
"seekBack": (self.seekBack, "skip backward"),
- "seekBackUp": (self.seekBackUp, "skip backward"),
+ "seekBackDown": self.seekBackDown,
+ "seekBackUp": self.seekBackUp,
}, prio=-1)
# give them a little more priority to win over color buttons
del self.fwdKeyTimer
del self.rwdKeyTimer
- def isSeekable(self):
+ def getSeek(self):
service = self.session.nav.getCurrentService()
if service is None:
return False
- if service.seek() is None:
+
+ seek = service.seek()
+
+ if seek is None or not seek.isCurrentlySeekable():
+ return None
+
+ return seek
+
+ def isSeekable(self):
+ if self.getSeek() is None:
return False
- else:
- return True
+ return True
def __seekableStatusChanged(self):
print "seekable status changed!"
if service is None:
return False
- if service.seek() is None:
+ if not self.isSeekable():
if state not in [self.SEEK_STATE_PLAY, self.SEEK_STATE_PAUSE]:
state = self.SEEK_STATE_PLAY
if service is None:
return
- seekable = service.seek()
+ seekable = self.getSeek()
if seekable is None:
return
+
seekable.seekTo(90 * seektime)
- def seekFwd(self):
+ def seekFwdDown(self):
print "start fwd timer"
self.fwdtimer = True
- self.fwdKeyTimer.start(500)
+ self.fwdKeyTimer.start(1000)
- def seekBack(self):
+ def seekBackDown(self):
print "start rewind timer"
self.rwdtimer = True
- self.rwdKeyTimer.start(500)
+ self.rwdKeyTimer.start(1000)
def seekFwdUp(self):
print "seekFwdUp"
if self.fwdtimer:
self.fwdKeyTimer.stop()
self.fwdtimer = False
- lookup = {
- self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
- self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
- self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
- self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
- self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
- self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
- self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
- self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
- self.SEEK_STATE_BACK_4X: self.SEEK_STATE_PLAY,
- self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_4X,
- self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
- self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
- self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
- self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
- self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
- }
- self.setSeekState(lookup[self.seekstate]);
+ self.seekFwd()
+
+ def seekFwd(self):
+ lookup = {
+ self.SEEK_STATE_PLAY: self.SEEK_STATE_FF_2X,
+ self.SEEK_STATE_PAUSE: self.SEEK_STATE_SM_EIGHTH,
+ self.SEEK_STATE_FF_2X: self.SEEK_STATE_FF_4X,
+ self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_8X,
+ self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_32X,
+ self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_64X,
+ self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_128X,
+ self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_128X,
+ self.SEEK_STATE_BACK_16X: self.SEEK_STATE_PLAY,
+ self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_16X,
+ self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_32X,
+ self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_64X,
+ self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_HALF,
+ self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_HALF,
+ self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_SM_QUARTER
+ }
+ self.setSeekState(lookup[self.seekstate])
def seekBackUp(self):
print "seekBackUp"
if self.rwdtimer:
self.rwdKeyTimer.stop()
self.rwdtimer = False
+ self.seekBack()
- lookup = {
- self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_4X,
- self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
- self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
- self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
- self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
- self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
- self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
- self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
- self.SEEK_STATE_BACK_4X: self.SEEK_STATE_BACK_32X,
- self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
- self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
- self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
- self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
- self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
- self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
- }
- self.setSeekState(lookup[self.seekstate]);
-
+ def seekBack(self):
+ lookup = {
+ self.SEEK_STATE_PLAY: self.SEEK_STATE_BACK_16X,
+ self.SEEK_STATE_PAUSE: self.SEEK_STATE_PAUSE,
+ self.SEEK_STATE_FF_2X: self.SEEK_STATE_PLAY,
+ self.SEEK_STATE_FF_4X: self.SEEK_STATE_FF_2X,
+ self.SEEK_STATE_FF_8X: self.SEEK_STATE_FF_4X,
+ self.SEEK_STATE_FF_32X: self.SEEK_STATE_FF_8X,
+ self.SEEK_STATE_FF_64X: self.SEEK_STATE_FF_32X,
+ self.SEEK_STATE_FF_128X: self.SEEK_STATE_FF_64X,
+ self.SEEK_STATE_BACK_16X: self.SEEK_STATE_BACK_32X,
+ self.SEEK_STATE_BACK_32X: self.SEEK_STATE_BACK_64X,
+ self.SEEK_STATE_BACK_64X: self.SEEK_STATE_BACK_128X,
+ self.SEEK_STATE_BACK_128X: self.SEEK_STATE_BACK_128X,
+ self.SEEK_STATE_SM_HALF: self.SEEK_STATE_SM_QUARTER,
+ self.SEEK_STATE_SM_QUARTER: self.SEEK_STATE_SM_EIGHTH,
+ self.SEEK_STATE_SM_EIGHTH: self.SEEK_STATE_PAUSE
+ }
+ self.setSeekState(lookup[self.seekstate])
+
def fwdTimerFire(self):
print "Display seek fwd"
self.fwdKeyTimer.stop()
def fwdSeekTo(self, minutes):
print "Seek", minutes, "minutes forward"
if minutes != 0:
- service = self.session.nav.getCurrentService()
- if service is None:
- return
- seekable = service.seek()
- if seekable is None:
- return
- seekable.seekRelative(1, minutes * 60 * 90000)
+ seekable = self.getSeek()
+ if seekable is not None:
+ seekable.seekRelative(1, minutes * 60 * 90000)
def rwdTimerFire(self):
print "rwdTimerFire"
self.lockedBecauseOfSkipping = True
def __evEOF(self):
- self.setSeekState(self.SEEK_STATE_PAUSE)
+ if self.seekstate != self.SEEK_STATE_PLAY:
+ self.setSeekState(self.SEEK_STATE_PAUSE)
+ # HACK
+ self.getSeek().seekRelative(1, -90000)
+ self.setSeekState(self.SEEK_STATE_PLAY)
+ else:
+ self.setSeekState(self.SEEK_STATE_PAUSE)
def __evSOF(self):
self.setSeekState(self.SEEK_STATE_PLAY)
+ self.doSeek(0)
+
+ def seekRelative(self, diff):
+ seekable = self.getSeek()
+ if seekable is not None:
+ seekable.seekRelative(0, diff)
from Screens.PVRState import PVRState
{
"timeshiftActivateEnd": self.activateTimeshiftEnd, # something like "pause key"
"timeshiftActivateEndAndPause": self.activateTimeshiftEndAndPause # something like "backward key"
- })
+ }, prio=-1) # priority over record
self.timeshift_enabled = 0
self.timeshift_state = 0
return service.timeshift()
def startTimeshift(self):
- # TODO: check for harddisk! (or do this in the interface? would make
- # more sense... for example radio could be timeshifted in memory,
- # and the decision can't be made here)
print "enable timeshift"
ts = self.getTimeshift()
if ts is None:
else:
print "timeshift failed"
- # nyi
def stopTimeshift(self):
+ if not self.timeshift_enabled:
+ return
print "disable timeshift"
ts = self.getTimeshift()
if ts is None:
return
+ self.session.openWithCallback(self.stopTimeshiftConfirmed, MessageBox, _("Stop Timeshift?"), MessageBox.TYPE_YESNO)
+
+ def stopTimeshiftConfirmed(self, confirmed):
+ if not confirmed:
+ return
+
+ ts = self.getTimeshift()
+ if ts is None:
+ return
+
ts.stopTimeshift()
self.timeshift_enabled = 0
else:
self.setSeekState(self.SEEK_STATE_PLAY)
ts.activateTimeshift()
+ self.seekRelative(0)
# same as activateTimeshiftEnd, but pauses afterwards.
def activateTimeshiftEndAndPause(self):
"instantRecord": (self.instantRecord, "Instant Record..."),
})
self.recording = None
-
self["BlinkingPoint"] = BlinkingPixmapConditional()
- self.onShown.append(self["BlinkingPoint"].hideWidget)
+ self["BlinkingPoint"].hide()
self["BlinkingPoint"].setConnect(self.session.nav.RecordTimer.isRecording)
-
+
def stopCurrentRecording(self):
self.session.nav.RecordTimer.removeEntry(self.recording)
self.recording = None
-
+
def startInstantRecording(self):
serviceref = self.session.nav.getCurrentlyPlayingServiceReference()
if event is not None:
data = parseEvent(event)
- begin = data[0]
- if begin < time.time():
- begin = time.time()
-
- end = data[1]
- if end < begin:
- end = begin
-
- end += 3600 * 10
+ begin = time.time()
+ end = begin + 3600 * 10
data = (begin, end, data[2], data[3], data[4])
else:
self["ButtonRed"] = PixmapConditional(withTimer = False)
self["ButtonRed"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
- self.onShown.append(self["ButtonRed"].update)
+ self.onLayoutFinish.append(self["ButtonRed"].update)
self["ButtonRedText"] = LabelConditional(text = _("Record"), withTimer = False)
self["ButtonRedText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
- self.onShown.append(self["ButtonRedText"].update)
+ self.onLayoutFinish.append(self["ButtonRedText"].update)
self["ButtonGreen"] = Pixmap()
self["ButtonGreenText"] = Label(_("Subservices"))
self["ButtonYellow"] = PixmapConditional(withTimer = False)
- self["ButtonYellow"].setConnect(lambda: False)
+ self["ButtonYellow"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+ self["ButtonYellowText"] = LabelConditional(text = _("Timeshifting"), withTimer = False)
+ self["ButtonYellowText"].setConnect(lambda: harddiskmanager.HDDCount() > 0)
+ self.onLayoutFinish.append(self["ButtonYellow"].update)
+ self.onLayoutFinish.append(self["ButtonYellowText"].update)
self["ButtonBlue"] = PixmapConditional(withTimer = False)
self["ButtonBlue"].setConnect(lambda: False)
+ self["ButtonBlueText"] = LabelConditional(text = _("Extensions"), withTimer = False)
+ self["ButtonBlueText"].setConnect(lambda: False)
+ self.onLayoutFinish.append(self["ButtonBlue"].update)
+ self.onLayoutFinish.append(self["ButtonBlueText"].update)
self.session.nav.event.append(self.gotServiceEvent) # we like to get service events
def hideSubServiceIndication(self):
- self["ButtonGreen"].hideWidget()
+ self["ButtonGreen"].hide()
self["ButtonGreenText"].hide()
def showSubServiceIndication(self):
- self["ButtonGreen"].showWidget()
+ self["ButtonGreen"].show()
self["ButtonGreenText"].show()
def checkFormat(self, service):
if info is not None:
aspect = info.getInfo(iServiceInformation.sAspect)
if aspect in [ 3, 4, 7, 8, 0xB, 0xC, 0xF, 0x10 ]:
- self["FormatActive"].showWidget()
+ self["FormatActive"].show()
else:
- self["FormatActive"].hideWidget()
+ self["FormatActive"].hide()
def checkSubservices(self, service):
if service.subServices().getNumberOfSubservices() > 0:
dolby = True
break
if dolby:
- self["DolbyActive"].showWidget()
+ self["DolbyActive"].show()
else:
- self["DolbyActive"].hideWidget()
+ self["DolbyActive"].hide()
def checkCrypted(self, service):
info = service.info()
if info is not None:
if info.getInfo(iServiceInformation.sIsCrypted) > 0:
- self["CryptActive"].showWidget()
+ self["CryptActive"].show()
else:
- self["CryptActive"].hideWidget()
+ self["CryptActive"].hide()
def gotServiceEvent(self, ev):
service = self.session.nav.getCurrentService()
self.checkDolby(service)
elif ev == iPlayableService.evEnd:
self.hideSubServiceIndication()
- self["CryptActive"].hideWidget()
- self["DolbyActive"].hideWidget()
- self["FormatActive"].hideWidget()
+ self["CryptActive"].hide()
+ self["DolbyActive"].hide()
+ self["FormatActive"].hide()
class InfoBarNotifications:
def __init__(self):
self.setSeekState(self.SEEK_STATE_PLAY)
except:
pass
+
+class InfoBarCueSheetSupport:
+ CUT_TYPE_IN = 0
+ CUT_TYPE_OUT = 1
+ CUT_TYPE_MARK = 2
+
+ def __init__(self):
+ self["CueSheetActions"] = HelpableActionMap(self, "InfobarCueSheetActions",
+ {
+ "jumpPreviousMark": (self.jumpPreviousMark, "jump to next marked position"),
+ "jumpNextMark": (self.jumpNextMark, "jump to previous marked position"),
+ "toggleMark": (self.toggleMark, "toggle a cut mark at the current position")
+ }, prio=1)
+
+ self.cut_list = [ ]
+ self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+ {
+ iPlayableService.evStart: self.__serviceStarted,
+ })
+
+ def __serviceStarted(self):
+ print "new service started! trying to download cuts!"
+ self.downloadCuesheet()
+
+ def __getSeekable(self):
+ service = self.session.nav.getCurrentService()
+ if service is None:
+ return None
+ return service.seek()
+
+ def __getCurrentPosition(self):
+ seek = self.__getSeekable()
+ if seek is None:
+ return None
+ r = seek.getPlayPosition()
+ if r[0]:
+ return None
+ return long(r[1])
+
+ def jumpPreviousNextMark(self, cmp, alternative=None):
+ current_pos = self.__getCurrentPosition()
+ if current_pos is None:
+ return
+ mark = self.getNearestCutPoint(current_pos, cmp=cmp)
+ if mark is not None:
+ pts = mark[0]
+ elif alternative is not None:
+ pts = alternative
+ else:
+ return
+
+ seekable = self.__getSeekable()
+ if seekable is not None:
+ seekable.seekTo(pts)
+
+ def jumpPreviousMark(self):
+ print "jumpPreviousMark"
+ # we add 2 seconds, so if the play position is <2s after
+ # the mark, the mark before will be used
+ self.jumpPreviousNextMark(lambda x: -x-5*90000, alternative=0)
+
+ def jumpNextMark(self):
+ print "jumpNextMark"
+ self.jumpPreviousNextMark(lambda x: x)
+
+ def getNearestCutPoint(self, pts, cmp=abs):
+ # can be optimized
+ nearest = None
+ for cp in self.cut_list:
+ diff = cmp(cp[0] - pts)
+ if diff >= 0 and (nearest is None or cmp(nearest[0] - pts) > diff):
+ nearest = cp
+ return nearest
+
+ def toggleMark(self):
+ print "toggleMark"
+ current_pos = self.__getCurrentPosition()
+ if current_pos is None:
+ print "not seekable"
+ return
+
+ print "current position: ", current_pos
+
+ nearest_cutpoint = self.getNearestCutPoint(current_pos)
+ print "nearest_cutpoint: ", nearest_cutpoint
+
+ if nearest_cutpoint is not None and abs(nearest_cutpoint[0] - current_pos) < 5*90000:
+ self.removeMark(self, *nearest_cutpoint)
+ else:
+ self.addMark(self, current_pos, self.CUT_TYPE_MARK)
+
+ def addMark(self, where, type):
+ bisect.insort(self.cut_list, (current_pos, self.CUT_TYPE_MARK))
+ self.uploadCuesheet()
+
+ def removeMark(self, where, type):
+ self.cut_list.remove(nearest_cutpoint)
+ self.uploadCuesheet()
+
+ def __getCuesheet(self):
+ service = self.session.nav.getCurrentService()
+ if service is None:
+ return None
+ return service.cueSheet()
+
+ def uploadCuesheet(self):
+ cue = self.__getCuesheet()
+
+ if cue is None:
+ print "upload failed, no cuesheet interface"
+ return
+ cue.setCutList(self.cut_list)
+
+ def downloadCuesheet(self):
+ cue = self.__getCuesheet()
+
+ if cue is None:
+ print "upload failed, no cuesheet interface"
+ return
+ self.cut_list = cue.getCutList()
+
+ print "cuts:", self.cut_list