mosaic/plugin.py

Mon, 16 Jan 2012 23:08:14 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Mon, 16 Jan 2012 23:08:14 +0100
changeset 23
d783b433388d
parent 21
6bb708a2265f
permissions
-rw-r--r--

Inconclusively complete possibly missing fields. This change introduces
inconsistencies difficult to correct given incomplete documentation of
IPKG and OPKG packaging standards.

     1 # -*- coding: UTF-8 -*-
     2 # Mosaic by AliAbdul
     3 from Components.ActionMap import NumberActionMap
     4 from Components.config import config, ConfigSubsection, ConfigInteger
     5 from Components.Console import Console
     6 from Components.Label import Label
     7 from Components.Language import language
     8 from Components.Pixmap import Pixmap
     9 from Components.VideoWindow import VideoWindow
    10 from enigma import eServiceCenter, eServiceReference, eTimer, getDesktop, loadPNG
    11 from os import environ
    12 from Plugins.Plugin import PluginDescriptor
    13 from Screens.ChannelSelection import BouquetSelector
    14 from Screens.MessageBox import MessageBox
    15 from Screens.Screen import Screen
    16 from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE, SCOPE_PLUGINS
    17 from Tools.LoadPixmap import LoadPixmap
    18 import gettext
    20 ################################################
    22 grab_binary = "/usr/bin/grab"
    23 grab_picture = "/tmp/mosaic.jpg"
    24 grab_errorlog = "/tmp/mosaic.log"
    26 config_limits = (3, 30)
    27 config.plugins.Mosaic = ConfigSubsection()
    28 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
    30 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
    31 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
    33 ################################################
    35 lang = language.getLanguage()
    36 environ["LANGUAGE"] = lang[:2]
    37 gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
    38 gettext.textdomain("enigma2")
    39 gettext.bindtextdomain("Mosaic", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/Mosaic/locale/"))
    41 def _(txt):
    42 	t = gettext.dgettext("Mosaic", txt)
    43 	if t == txt:
    44 		t = gettext.gettext(txt)
    45 	return t
    47 ################################################
    49 class Mosaic(Screen):
    50 	PLAY = 0
    51 	PAUSE = 1
    53 	desktop = getDesktop(0)
    54 	size = desktop.size()
    55 	width = size.width()
    56 	height = size.height()
    57 	windowWidth = width / 4
    58 	windowHeight = height / 4
    60 	positions = []
    61 	x = 80
    62 	y = 40
    63 	for i in range(1, 10):
    64 		positions.append([x, y])
    65 		x += windowWidth
    66 		x += ((width - 160) - (windowWidth * 3)) / 2
    67 		if (i == 3) or (i == 6):
    68 			y = y + windowHeight + 40
    69 			x = 80
    71 	skin = ""
    72 	skin += """<screen position="0,0" size="%d,%d" title="Mosaic" flags="wfNoBorder" backgroundColor="#000000" >""" % (width, height)
    73 	skin += """<widget name="playState" position="55,55" size="16,16" alphatest="on" />"""
    74 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]+1, windowWidth, windowHeight)
    75 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]+1, windowWidth, windowHeight)
    76 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]+1, windowWidth, windowHeight)
    77 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]+1, windowWidth, windowHeight)
    78 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]+1, windowWidth, windowHeight)
    79 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]+1, windowWidth, windowHeight)
    80 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]+1, windowWidth, windowHeight)
    81 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]+1, windowWidth, windowHeight)
    82 	skin += """<eLabel position="%d,%d" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]+1, windowWidth, windowHeight)
    84 	skin += """<widget name="channel1" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[0][0]-2, positions[0][1]-18, windowWidth-4)
    85 	skin += """<widget name="channel2" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[1][0]-2, positions[1][1]-18, windowWidth-4)
    86 	skin += """<widget name="channel3" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[2][0]-2, positions[2][1]-18, windowWidth-4)
    87 	skin += """<widget name="channel4" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[3][0]-2, positions[3][1]-18, windowWidth-4)
    88 	skin += """<widget name="channel5" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[4][0]-2, positions[4][1]-18, windowWidth-4)
    89 	skin += """<widget name="channel6" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[5][0]-2, positions[5][1]-18, windowWidth-4)
    90 	skin += """<widget name="channel7" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[6][0]-2, positions[6][1]-18, windowWidth-4)
    91 	skin += """<widget name="channel8" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[7][0]-2, positions[7][1]-18, windowWidth-4)
    92 	skin += """<widget name="channel9" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#88aacc" />""" % (positions[8][0]-2, positions[8][1]-18, windowWidth-4)
    94 	skin += """<widget name="window1" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[0][0]-2, positions[0][1]+1, windowWidth, windowHeight)
    95 	skin += """<widget name="window2" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[1][0]-2, positions[1][1]+1, windowWidth, windowHeight)
    96 	skin += """<widget name="window3" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[2][0]-2, positions[2][1]+1, windowWidth, windowHeight)
    97 	skin += """<widget name="window4" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[3][0]-2, positions[3][1]+1, windowWidth, windowHeight)
    98 	skin += """<widget name="window5" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[4][0]-2, positions[4][1]+1, windowWidth, windowHeight)
    99 	skin += """<widget name="window6" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[5][0]-2, positions[5][1]+1, windowWidth, windowHeight)
   100 	skin += """<widget name="window7" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[6][0]-2, positions[6][1]+1, windowWidth, windowHeight)
   101 	skin += """<widget name="window8" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[7][0]-2, positions[7][1]+1, windowWidth, windowHeight)
   102 	skin += """<widget name="window9" position="%d,%d" zPosition="1" size="%d,%d" />""" % (positions[8][0]-2, positions[8][1]+1, windowWidth, windowHeight)
   104         # Playing video moving pictures
   105 	skin += """<widget name="video1" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[0][0]-2, positions[0][1]+1, windowWidth, windowHeight)
   106 	skin += """<widget name="video2" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[1][0]-2, positions[1][1]+1, windowWidth, windowHeight)
   107 	skin += """<widget name="video3" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[2][0]-2, positions[2][1]+1, windowWidth, windowHeight)
   108 	skin += """<widget name="video4" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[3][0]-2, positions[3][1]+1, windowWidth, windowHeight)
   109 	skin += """<widget name="video5" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[4][0]-2, positions[4][1]+1, windowWidth, windowHeight)
   110 	skin += """<widget name="video6" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[5][0]-2, positions[5][1]+1, windowWidth, windowHeight)
   111 	skin += """<widget name="video7" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[6][0]-2, positions[6][1]+1, windowWidth, windowHeight)
   112 	skin += """<widget name="video8" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[7][0]-2, positions[7][1]+1, windowWidth, windowHeight)
   113 	skin += """<widget name="video9" position="%d,%d" zPosition="2" size="%d,%d" backgroundColor="#ffffffff" />""" % (positions[8][0]-2, positions[8][1]+1, windowWidth, windowHeight)
   115         # Zweite Zeile Sendung
   116 	skin += """<widget name="event1" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[0][0]-2, positions[0][1]-1, windowWidth)
   117 	skin += """<widget name="event2" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[1][0]-2, positions[1][1]-1, windowWidth)
   118 	skin += """<widget name="event3" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[2][0]-2, positions[2][1]-1, windowWidth)
   119 	skin += """<widget name="event4" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[3][0]-2, positions[3][1]-1, windowWidth)
   120 	skin += """<widget name="event5" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[4][0]-2, positions[4][1]-1, windowWidth)
   121 	skin += """<widget name="event6" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[5][0]-2, positions[5][1]-1, windowWidth)
   122 	skin += """<widget name="event7" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[6][0]-2, positions[6][1]-1, windowWidth)
   123 	skin += """<widget name="event8" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[7][0]-2, positions[7][1]-1, windowWidth)
   124 	skin += """<widget name="event9" position="%d,%d" size="%d,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#446688" />""" % (positions[8][0]-2, positions[8][1]-1, windowWidth)
   126 	skin += """<widget name="countdown" position="80,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#448866" />""" % (height-40, windowWidth)
   127 	skin += """<widget name="count" position="%d,%d" size="%d,20" font="Regular;18" backgroundColor="#000000" foregroundColor="#886644" halign="right" />
   128 	</screen>""" % (positions[2][0] ,height-40, windowWidth)
   130 	def __init__(self, session, services):
   131 		Screen.__init__(self, session)
   133 		self.session = session
   134 		self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
   135 		self.consoleCmd = ""
   136 		self.Console = Console()
   137 		self.serviceHandler = eServiceCenter.getInstance()
   138 		self.ref_list = services
   139 		self.window_refs = [None, None, None, None, None, None, None, None, None]
   140 		self.current_refidx = 0
   141 		self.current_window = 1
   142 		self.countdown = config.plugins.Mosaic.countdown.value
   143 		self.working = False
   144 		self.state = self.PLAY
   146 		self["playState"] = Pixmap()
   147 		for i in range(1, 10):
   148 			self["window" + str(i)] = Pixmap()
   149 			self["video" + str(i)] = VideoWindow(decoder=0, fb_width=self.width, fb_height=self.height)
   150 			self["video" + str(i)].hide()
   151 			self["channel" + str(i)] = Label("")
   152 			self["event" + str(i)] = Label("")
   153 			self["event" + str(i)].hide()
   154 		self["video1"].decoder = 0
   155 		self["video1"].show()
   156 		self["countdown"] = Label()
   157 		self.updateCountdownLabel()
   158 		self["count"] = Label()
   160 		self["actions"] = NumberActionMap(["MosaicActions"],
   161 			{
   162 				"ok": self.exit,
   163 				"cancel": self.closeWithOldService,
   164 				"green": self.play,
   165 				"yellow": self.pause,
   166 				"channelup": self.countdownPlus,
   167 				"channeldown": self.countdownMinus,
   168 				"1": self.numberPressed,
   169 				"2": self.numberPressed,
   170 				"3": self.numberPressed,
   171 				"4": self.numberPressed,
   172 				"5": self.numberPressed,
   173 				"6": self.numberPressed,
   174 				"7": self.numberPressed,
   175 				"8": self.numberPressed,
   176 				"9": self.numberPressed
   177 			}, prio=-1)
   179 		self.updateTimer = eTimer()
   180 		self.updateTimer.callback.append(self.updateCountdown)
   181 		self.checkTimer = eTimer()
   182 		self.checkTimer.callback.append(self.checkGrab)
   183 		self.checkTimer.start(500, 1)
   185 	def checkGrab(self):
   186 		# Start the first service in the bouquet and show the service-name
   187 		ref = self.ref_list[0]
   188 		self.window_refs[0] = ref
   189 		info = self.serviceHandler.info(ref)
   190 		name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
   191 		event_name = self.getEventName(info, ref)
   192 		self["channel1"].setText(name)
   193 		self["event1"].setText(event_name)
   194 		self.session.nav.playService(ref)
   195 		self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
   196 		self["playState"].instance.setPixmap(playingIcon)
   197 		# Start updating the video-screenshots
   198 		self.updateTimer.start(1, 1)
   200 	def exit(self, callback=None):
   201 		self.deleteConsoleCallbacks()
   202 		self.close()
   204 	def deleteConsoleCallbacks(self):
   205 		if self.Console.appContainers.has_key(self.consoleCmd):
   206 			del self.Console.appContainers[self.consoleCmd].dataAvail[:]
   207 			del self.Console.appContainers[self.consoleCmd].appClosed[:]
   208 			del self.Console.appContainers[self.consoleCmd]
   209 			del self.Console.extra_args[self.consoleCmd]
   210 			del self.Console.callbacks[self.consoleCmd]
   212 	def closeWithOldService(self):
   213 		self.session.nav.playService(self.oldService)
   214 		self.deleteConsoleCallbacks()
   215 		self.close()
   217 	def numberPressed(self, number):
   218 		ref = self.window_refs[number-1]
   219 		if ref is not None:
   220 			self.session.nav.playService(ref)
   221 			self.deleteConsoleCallbacks()
   222 			self.close()
   224 	def play(self):
   225 		if self.working == False and self.state == self.PAUSE:
   226 			self.state = self.PLAY
   227 			self.updateTimer.start(1000, 1)
   228 			self["playState"].instance.setPixmap(playingIcon)
   230 	def pause(self):
   231 		if self.working == False and self.state == self.PLAY:
   232 			self.state = self.PAUSE
   233 			self.updateTimer.stop()
   234 			self["playState"].instance.setPixmap(pausedIcon)
   236 	def countdownPlus(self):
   237 		self.changeCountdown(1)
   239 	def countdownMinus(self):
   240 		self.changeCountdown(-1)
   242 	def changeCountdown(self, direction):
   243 		if self.working == False:
   244 			configNow = config.plugins.Mosaic.countdown.value
   245 			configNow += direction
   247 			if configNow < config_limits[0]:
   248 				configNow = config_limits[0]
   249 			elif configNow > config_limits[1]:
   250 				configNow = config_limits[1]
   252 			config.plugins.Mosaic.countdown.value = configNow
   253 			config.plugins.Mosaic.countdown.save()
   255 			self.updateCountdownLabel()
   257 	def makeNextScreenshot(self):
   258 		# Grab video
   259 		if not self.Console:
   260 			self.Console = Console()
   261 		self.consoleCmd = "%s -v -r %d -j 100 %s" % (grab_binary, self.windowWidth, grab_picture)
   262 		self.Console.ePopen(self.consoleCmd, self.showNextScreenshot)
   264 	def showNextScreenshot(self, result, retval, extra_args):
   265 		if retval == 0:
   266 			# Show screenshot in the current window
   267 			pic = LoadPixmap(grab_picture)
   268 			self["window" + str(self.current_window)].instance.setPixmap(pic)
   270 			# Hide current video-window and show the running event-name
   271 			self["video" + str(self.current_window)].hide()
   272 			self["event" + str(self.current_window)].show()
   274 			# Get next ref
   275 			self.current_refidx += 1
   276 			if self.current_refidx > (len(self.ref_list) -1):
   277 				self.current_refidx = 0
   279 			# Play next ref
   280 			ref = self.ref_list[self.current_refidx]
   281 			info = self.serviceHandler.info(ref)
   282 			name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
   283 			event_name = self.getEventName(info, ref)
   284 			self.session.nav.playService(ref)
   286 			# Get next window index
   287 			self.current_window += 1
   288 			if self.current_window > 9:
   289 				self.current_window = 1
   291 			# Save the ref
   292 			self.window_refs[self.current_window-1] = ref
   294 			# Save the event-name and hide the label
   295 			self["event" + str(self.current_window)].hide()
   296 			self["event" + str(self.current_window)].setText(event_name)
   298 			# Show the new video-window
   299 			self["video" + str(self.current_window)].show()
   300 			self["video" + str(self.current_window)].decoder = 0
   302 			# Show the servicename
   303 			self["channel" + str(self.current_window)].setText(name)
   304 			self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
   306 			# Restart timer
   307 			self.working = False
   308 			self.updateTimer.start(1, 1)
   309 		else:
   310 			print "[Mosaic] retval: %d result: %s" % (retval, result)
   312 			try:
   313 				f = open(grab_errorlog, "w")
   314 				f.write("retval: %d\nresult: %s" % (retval, result))
   315 				f.close()
   316 			except:
   317 				pass
   319 			self.session.openWithCallback(self.exit, MessageBox, _("Error while creating screenshot. You need grab version 0.8 or higher!"), MessageBox.TYPE_ERROR, timeout=5)
   321 	def updateCountdown(self, callback=None):
   322 		self.countdown -= 1
   323 		self.updateCountdownLabel()
   324 		if self.countdown == 0:
   325 			self.countdown = config.plugins.Mosaic.countdown.value
   326 			self.working = True
   327 			self.makeNextScreenshot()
   328 		else:
   329 			self.updateTimer.start(1000, 1)
   331 	def updateCountdownLabel(self):
   332 		self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
   334 	def getEventName(self, info, ref):
   335 		event = info.getEvent(ref)
   336 		if event is not None:
   337 			eventName = event.getEventName()
   338 			if eventName is None:
   339 				eventName = ""
   340 		else:
   341 			eventName = ""
   342 		return eventName
   344 ################################################
   345 # Most stuff stolen from the GraphMultiEPG
   347 Session = None
   348 Servicelist = None
   349 BouquetSelectorScreen = None
   351 def getBouquetServices(bouquet):
   352 	services = []
   353 	Servicelist = eServiceCenter.getInstance().list(bouquet)
   354 	if Servicelist is not None:
   355 		while True:
   356 			service = Servicelist.getNext()
   357 			if not service.valid():
   358 				break
   359 			if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
   360 				continue
   361 			services.append(service)
   362 	return services
   364 def closeBouquetSelectorScreen(ret=None):
   365 	if BouquetSelectorScreen is not None:
   366 		BouquetSelectorScreen.close()
   368 def openMosaic(bouquet):
   369 	if bouquet is not None:
   370 		services = getBouquetServices(bouquet)
   371 		if len(services):
   372 			Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
   374 def main(session, servicelist, **kwargs):
   375 	global Session
   376 	Session = session
   377 	global Servicelist
   378 	Servicelist = servicelist
   379 	global BouquetSelectorScreen
   381 	bouquets = Servicelist.getBouquetList()
   382 	if bouquets is not None:
   383 		if len(bouquets) == 1:
   384 			openMosaic(bouquets[0][1])
   385 		elif len(bouquets) > 1:
   386 			BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
   388 def Plugins(**kwargs):
   389 	return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)

mercurial