Made Mosaic translateable and added german translation
[enigma2-plugins.git] / mosaic / src / plugin.py
1 ##
2 ## Mosaic
3 ## by AliAbdul
4 ## needs the aio-screengrabber by seddi
5 ##
6 from Components.ActionMap import NumberActionMap
7 from Components.AVSwitch import AVSwitch
8 from Components.config import config, ConfigSubsection, ConfigInteger
9 from Components.Label import Label
10 from Components.Language import language
11 from Components.Pixmap import Pixmap
12 from Components.VideoWindow import VideoWindow
13 from enigma import eConsoleAppContainer, eServiceCenter, eServiceReference, eTimer, loadPic, loadPNG
14 from os import environ
15 from Plugins.Plugin import PluginDescriptor
16 from Screens.ChannelSelection import BouquetSelector
17 from Screens.MessageBox import MessageBox
18 from Screens.Screen import Screen
19 from Tools.Directories import fileExists, resolveFilename, SCOPE_SKIN_IMAGE, SCOPE_LANGUAGE
20 import gettext
21
22 ################################################
23
24 grab_binary = "/usr/bin/grab"
25 grab_picture = "/tmp/.mosaic.bmp"
26
27 config_limits = (3, 30)
28 config.plugins.Mosaic = ConfigSubsection()
29 config.plugins.Mosaic.countdown = ConfigInteger(default=5, limits=config_limits)
30
31 playingIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_play.png'))
32 pausedIcon = loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'skin_default/icons/ico_mp_pause.png'))
33
34 ################################################
35
36 lang = language.getLanguage()
37 environ["LANGUAGE"] = lang[:2]\r
38 gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))\r
39 gettext.textdomain("enigma2")\r
40 gettext.bindtextdomain("Mosaic", resolveFilename(SCOPE_LANGUAGE))
41
42 def _(txt):\r
43         t = gettext.dgettext("Mosaic", txt)\r
44         if t == txt:\r
45                 t = gettext.gettext(txt)\r
46         return t
47
48 ################################################
49
50 class Mosaic(Screen):
51         PLAY = 0
52         PAUSE = 1
53
54         skin = """
55         <screen position="0,0" size="720,576" title="Mosaic" flags="wfNoBorder" backgroundColor="#ffffff" >
56                 <widget name="playState" position="55,55" size="16,16" alphatest="on" />
57                 <eLabel position="78,54" size="180,144" />
58                 <eLabel position="274,54" size="180,144" />
59                 <eLabel position="470,54" size="180,144" />
60                 <eLabel position="78,221" size="180,144" />
61                 <eLabel position="274,221" size="180,144" />
62                 <eLabel position="470,221" size="180,144" />
63                 <eLabel position="78,388" size="180,144" />
64                 <eLabel position="274,388" size="180,144" />
65                 <eLabel position="470,388" size="180,144" />
66                 <widget name="channel1" position="80,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
67                 <widget name="channel2" position="276,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
68                 <widget name="channel3" position="472,32" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
69                 <widget name="channel4" position="80,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
70                 <widget name="channel5" position="276,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
71                 <widget name="channel6" position="472,198" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
72                 <widget name="channel7" position="80,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
73                 <widget name="channel8" position="276,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
74                 <widget name="channel9" position="472,366" size="176,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
75                 <widget name="window1" position="78,54" zPosition="1" size="180,144" />
76                 <widget name="window2" position="274,54" zPosition="1" size="180,144" />
77                 <widget name="window3" position="470,54" zPosition="1" size="180,144" />
78                 <widget name="window4" position="78,221" zPosition="1" size="180,144" />
79                 <widget name="window5" position="274,221" zPosition="1" size="180,144" />
80                 <widget name="window6" position="470,221" zPosition="1" size="180,144" />
81                 <widget name="window7" position="78,388" zPosition="1" size="180,144" />
82                 <widget name="window8" position="274,388" zPosition="1" size="180,144" />
83                 <widget name="window9" position="470,388" zPosition="1" size="180,144" />
84                 <widget name="video1" position="78,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
85                 <widget name="video2" position="274,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
86                 <widget name="video3" position="470,54" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
87                 <widget name="video4" position="78,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
88                 <widget name="video5" position="274,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
89                 <widget name="video6" position="470,221" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
90                 <widget name="video7" position="78,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
91                 <widget name="video8" position="274,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
92                 <widget name="video9" position="470,388" zPosition="2" size="180,144" backgroundColor="#ffffffff" />
93                 <widget name="event1" position="78,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
94                 <widget name="event2" position="274,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
95                 <widget name="event3" position="470,54" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
96                 <widget name="event4" position="78,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
97                 <widget name="event5" position="274,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
98                 <widget name="event6" position="470,221" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
99                 <widget name="event7" position="78,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
100                 <widget name="event8" position="274,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
101                 <widget name="event9" position="470,388" size="180,20" zPosition="3" font="Regular;18" backgroundColor="#000000" foregroundColor="#ffffff" />
102                 <widget name="countdown" position="80,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" />
103                 <widget name="count" position="472,535" size="175,20" font="Regular;18" backgroundColor="#ffffff" foregroundColor="#000000" halign="right" />
104         </screen>"""
105
106         def __init__(self, session, services):
107                 Screen.__init__(self, session)
108                 
109                 self.session = session
110                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
111                 self.container = eConsoleAppContainer()
112                 self.aspect = AVSwitch().getAspectRatioSetting()
113                 self.serviceHandler = eServiceCenter.getInstance()
114                 self.ref_list = services
115                 self.window_refs = [None, None, None, None, None, None, None, None, None]
116                 self.current_refidx = 0
117                 self.current_window = 1
118                 self.countdown = config.plugins.Mosaic.countdown.value
119                 self.working = False
120                 self.state = self.PLAY
121                 
122                 self["playState"] = Pixmap()
123                 for i in range(1, 10):
124                         self["window" + str(i)] = Pixmap()
125                         self["video" + str(i)] = VideoWindow(decoder = 0)
126                         self["video" + str(i)].hide()
127                         self["channel" + str(i)] = Label("")
128                         self["event" + str(i)] = Label("")
129                         self["event" + str(i)].hide()
130                 self["video1"].decoder = 0
131                 self["video1"].show()
132                 self["countdown"] = Label()
133                 self.updateCountdownLabel()
134                 self["count"] = Label()
135                 
136                 self["actions"] = NumberActionMap(["MosaicActions"],
137                         {
138                                 "ok": self.close,
139                                 "cancel": self.closeWithOldService,
140                                 "green": self.play,
141                                 "yellow": self.pause,
142                                 "channelup": self.countdownPlus,
143                                 "channeldown": self.countdownMinus,
144                                 "1": self.numberPressed,
145                                 "2": self.numberPressed,
146                                 "3": self.numberPressed,
147                                 "4": self.numberPressed,
148                                 "5": self.numberPressed,
149                                 "6": self.numberPressed,
150                                 "7": self.numberPressed,
151                                 "8": self.numberPressed,
152                                 "9": self.numberPressed
153                         }, prio=-1)
154                 
155                 self.updateTimer = eTimer()
156                 self.updateTimer.timeout.get().append(self.updateCountdown)
157                 self.checkTimer = eTimer()
158                 self.checkTimer.timeout.get().append(self.checkGrab)
159                 
160                 self.container.appClosed.append(self.showNextScreenshot)
161                 self.checkTimer.start(500, 1)
162
163         def checkGrab(self):
164                 if fileExists(grab_binary):
165                         # Start the first service in the bouquet and show the service-name
166                         ref = self.ref_list[0]
167                         self.window_refs[0] = ref
168                         info = self.serviceHandler.info(ref)
169                         name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
170                         event_name = self.getEventName(info, ref)
171                         self["channel1"].setText(name)
172                         self["event1"].setText(event_name)
173                         self.session.nav.playService(ref)
174                         self["count"].setText(_("Channel: ") + "1 / " + str(len(self.ref_list)))
175                         self["playState"].instance.setPixmap(playingIcon)
176                         
177                         # Start updating the video-screenshots
178                         self.updateTimer.start(1, 1)
179                 else:
180                         self.session.openWithCallback(self.exit, MessageBox, _("%s does not exist!") % grab_binary, MessageBox.TYPE_ERROR, timeout=5)
181
182         def exit(self, callback=None):
183                 self.close()
184
185         def closeWithOldService(self):
186                 self.session.nav.playService(self.oldService)
187                 self.close()
188
189         def numberPressed(self, number):
190                 ref = self.window_refs[number-1]
191                 if ref is not None:
192                         self.session.nav.playService(ref)
193                         self.close()
194
195         def play(self):
196                 if self.working == False and self.state == self.PAUSE:
197                         self.state = self.PLAY
198                         self.updateTimer.start(1000, 1)
199                         self["playState"].instance.setPixmap(playingIcon)
200
201         def pause(self):
202                 if self.working == False and self.state == self.PLAY:
203                         self.state = self.PAUSE
204                         self.updateTimer.stop()
205                         self["playState"].instance.setPixmap(pausedIcon)
206
207         def countdownPlus(self):
208                 self.changeCountdown(1)
209
210         def countdownMinus(self):
211                 self.changeCountdown(-1)
212
213         def changeCountdown(self, direction):
214                 if self.working == False:
215                         configNow = config.plugins.Mosaic.countdown.value
216                         configNow += direction
217                         
218                         if configNow < config_limits[0]:
219                                 configNow = config_limits[0]
220                         elif configNow > config_limits[1]:
221                                 configNow = config_limits[1]
222                         
223                         config.plugins.Mosaic.countdown.value = configNow
224                         config.plugins.Mosaic.countdown.save()
225                         
226                         self.updateCountdownLabel()
227
228         def makeNextScreenshot(self):
229                 # Grab video
230                 if self.container.execute("%s -v %s" % (grab_binary, grab_picture)):
231                         self.showNextScreenshot(-1)
232
233         def showNextScreenshot(self, callback):
234                 # Resize screenshot and show in the current window
235                 picture = loadPic(grab_picture, 180, 144, self.aspect, 1, 0, 1)
236                 self["window" + str(self.current_window)].instance.setPixmap(picture)
237                 
238                 # Hide current video-window and show the running event-name
239                 self["video" + str(self.current_window)].hide()
240                 self["event" + str(self.current_window)].show()
241                 
242                 # Get next ref
243                 self.current_refidx += 1
244                 if self.current_refidx > (len(self.ref_list) -1):
245                         self.current_refidx = 0
246                 
247                 # Play next ref
248                 ref = self.ref_list[self.current_refidx]
249                 info = self.serviceHandler.info(ref)
250                 name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
251                 event_name = self.getEventName(info, ref)
252                 self.session.nav.playService(ref)
253                 
254                 # Get next window index
255                 self.current_window += 1
256                 if self.current_window > 9:
257                         self.current_window = 1
258                 
259                 # Save the ref
260                 self.window_refs[self.current_window-1] = ref
261                 
262                 # Save the event-name and hide the label
263                 self["event" + str(self.current_window)].hide()
264                 self["event" + str(self.current_window)].setText(event_name)
265                 
266                 # Show the new video-window
267                 self["video" + str(self.current_window)].show()
268                 self["video" + str(self.current_window)].decoder = 0
269                 
270                 # Show the servicename
271                 self["channel" + str(self.current_window)].setText(name)
272                 self["count"].setText(_("Channel: ") + str(self.current_refidx + 1) + " / " + str(len(self.ref_list)))
273                 
274                 # Restart timer
275                 self.working = False
276                 self.updateTimer.start(1, 1)
277
278         def updateCountdown(self, callback=None):
279                 self.countdown -= 1
280                 self.updateCountdownLabel()
281                 if self.countdown == 0:
282                         self.countdown = config.plugins.Mosaic.countdown.value
283                         self.working = True
284                         self.makeNextScreenshot()
285                 else:
286                         self.updateTimer.start(1000, 1)
287
288         def updateCountdownLabel(self):
289                 self["countdown"].setText("%s %s / %s" % (_("Countdown:"), str(self.countdown), str(config.plugins.Mosaic.countdown.value)))
290
291         def getEventName(self, info, ref):
292                 event = info.getEvent(ref)
293                 if event is not None:
294                         eventName = event.getEventName()
295                         if eventName is None:
296                                 eventName = ""
297                 else:
298                         eventName = ""
299                 return eventName
300
301 ################################################
302 # Most stuff stolen from the GraphMultiEPG
303
304 Session = None
305 Servicelist = None
306 BouquetSelectorScreen = None
307
308 def getBouquetServices(bouquet):
309         services = []
310         Servicelist = eServiceCenter.getInstance().list(bouquet)
311         if Servicelist is not None:
312                 while True:
313                         service = Servicelist.getNext()
314                         if not service.valid():
315                                 break
316                         if service.flags & (eServiceReference.isDirectory | eServiceReference.isMarker):
317                                 continue
318                         services.append(service)
319         return services
320
321 def closeBouquetSelectorScreen(ret=None):
322         if BouquetSelectorScreen is not None:
323                 BouquetSelectorScreen.close()
324
325 def openMosaic(bouquet):
326         if bouquet is not None:
327                 services = getBouquetServices(bouquet)
328                 if len(services):
329                         Session.openWithCallback(closeBouquetSelectorScreen, Mosaic, services)
330
331 def main(session, servicelist, **kwargs):
332         global Session
333         Session = session
334         global Servicelist
335         Servicelist = servicelist
336         global BouquetSelectorScreen
337         
338         bouquets = Servicelist.getBouquetList()
339         if bouquets is not None:
340                 if len(bouquets) == 1:
341                         self.openMosaic(bouquets[0][1])
342                 elif len(bouquets) > 1:
343                         BouquetSelectorScreen = Session.open(BouquetSelector, bouquets, openMosaic, enableWrapAround=True)
344
345 def Plugins(**kwargs):
346         return PluginDescriptor(name=_("Mosaic"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)