fix crash when showing movielist
[enigma2-plugins.git] / movielistpreview / src / plugin.py
1 ##
2 ## Movielist Preview
3 ## by AliAbdul
4 ##
5 from Components.ActionMap import ActionMap
6 from Components.AVSwitch import AVSwitch
7 from Components.config import config, ConfigInteger, ConfigSelection, ConfigSubsection, ConfigYesNo, getConfigListEntry\r
8 from Components.ConfigList import ConfigListScreen
9 from Components.Console import Console
10 from Components.Label import Label
11 from Components.Language import language
12 from Components.MenuList import MenuList
13 from Components.MovieList import MovieList
14 from Components.Pixmap import Pixmap
15 from Components.ServiceEventTracker import InfoBarBase
16 from Components.VideoWindow import VideoWindow
17 from enigma import ePicLoad, ePoint, eServiceReference, eSize, eTimer, getDesktop
18 from os import environ, listdir
19 from Plugins.Plugin import PluginDescriptor
20 from Screens.InfoBarGenerics import InfoBarSeek, InfoBarCueSheetSupport
21 from Screens.MessageBox import MessageBox
22 from Screens.MovieSelection import MovieSelection
23 from Screens.Screen import Screen
24 from Tools.Directories import fileExists, resolveFilename, SCOPE_LANGUAGE, SCOPE_PLUGINS
25 import gettext, random
26
27 ##############################################################################
28
29 config.plugins.MovielistPreview = ConfigSubsection()
30 config.plugins.MovielistPreview.enabled = ConfigYesNo(default=True)
31 config.plugins.MovielistPreview.position_x = ConfigInteger(default=100)
32 config.plugins.MovielistPreview.position_y = ConfigInteger(default=100)
33 config.plugins.MovielistPreview.size = ConfigSelection(choices=["250x200", "200x160", "150x120", "100x80"], default="250x200")
34
35 ##############################################################################
36
37 def localeInit():
38         lang = language.getLanguage()
39         environ["LANGUAGE"] = lang[:2]
40         gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
41         gettext.textdomain("enigma2")
42         gettext.bindtextdomain("MovielistPreview", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/MovielistPreview/locale/"))
43
44 def _(txt):
45         t = gettext.dgettext("MovielistPreview", txt)
46         if t == txt:
47                 t = gettext.gettext(txt)
48         return t
49
50 localeInit()
51 language.addCallback(localeInit)
52
53 ##############################################################################
54
55 SKIN = """
56         <screen position="0,0" size="250,200" zPosition="10" flags="wfNoBorder" backgroundColor="#FF000000" >
57                 <widget name="background" position="0,0" size="250,200" zPosition="1" backgroundColor="#00000000" />
58                 <widget name="preview" position="0,0" size="250,200" zPosition="2" />
59         </screen>"""
60
61 ##############################################################################
62
63 class MovielistPreviewScreen(Screen):
64         def __init__(self, session):
65                 Screen.__init__(self, session)
66                 self.skin = SKIN
67                 self["background"] = Label("")
68                 self["preview"] = Pixmap()
69                 self.onShow.append(self.movePosition)
70
71         def movePosition(self):
72                 if self.instance:
73                         self.instance.move(ePoint(config.plugins.MovielistPreview.position_x.value, config.plugins.MovielistPreview.position_y.value))
74                         size = config.plugins.MovielistPreview.size.value.split("x")
75                         self.instance.resize(eSize(int(size[0]), int(size[1])))
76                         self["background"].instance.resize(eSize(int(size[0]), int(size[1])))
77                         self["preview"].instance.resize(eSize(int(size[0]), int(size[1])))
78
79 ##############################################################################
80
81 class MovielistPreview():
82         def __init__(self):
83                 self.dialog = None
84                 self.mayShow = True
85                 self.working = False
86
87         def gotSession(self, session):
88                 if not self.dialog:
89                         self.dialog = session.instantiateDialog(MovielistPreviewScreen)
90
91         def changeVisibility(self):
92                 if config.plugins.MovielistPreview.enabled.value:
93                         config.plugins.MovielistPreview.enabled.value = False
94                 else:
95                         config.plugins.MovielistPreview.enabled.value = True
96                 config.plugins.MovielistPreview.enabled.save()
97
98         def showPreview(self, movie):
99                 if self.working == False:
100                         self.dialog.hide()
101                         if movie and self.mayShow and config.plugins.MovielistPreview.enabled.value:
102                                 png = movie + "_mp.jpg"
103                                 if fileExists(png):
104                                         self.working = True
105                                         sc = AVSwitch().getFramebufferScale()
106                                         self.picload = ePicLoad()
107                                         self.picload.PictureData.get().append(self.showPreviewCallback)
108                                         size = config.plugins.MovielistPreview.size.value.split("x")
109                                         self.picload.setPara((int(size[0]), int(size[1]), sc[0], sc[1], False, 1, "#00000000"))
110                                         self.picload.startDecode(png)
111
112         def showPreviewCallback(self, picInfo=None):
113                 if picInfo:
114                         ptr = self.picload.getData()
115                         if ptr != None:
116                                 self.dialog["preview"].instance.setPixmap(ptr)
117                                 self.dialog.show()
118                 self.working = False
119
120         def hideDialog(self):
121                 self.mayShow = False
122                 self.dialog.hide()
123
124         def showDialog(self):
125                 self.mayShow = True
126                 self.dialog.show()
127 movielistpreview = MovielistPreview()
128
129 ##############################################################################
130
131 class MovielistPreviewPositionerCoordinateEdit(ConfigListScreen, Screen):\r
132         skin = """\r
133                 <screen position="center,center" size="560,110" title="%s">\r
134                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />\r
135                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />\r
136                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />\r
137                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />\r
138                         <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />\r
139                         <widget name="config" position="0,45" size="560,60" scrollbarMode="showOnDemand" />\r
140                 </screen>""" % _("Movielist Preview")
141
142         def __init__(self, session, x, y, w, h):\r
143                 Screen.__init__(self, session)
144                 \r
145                 self["key_green"] = Label(_("OK"))
146                 
147                 self.xEntry = ConfigInteger(default=x, limits=(0, w))
148                 self.yEntry = ConfigInteger(default=y, limits=(0, h))\r
149                 ConfigListScreen.__init__(self, [
150                         getConfigListEntry("x position:", self.xEntry),
151                         getConfigListEntry("y position:", self.yEntry)])
152                 \r
153                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
154                         {
155                                 "green": self.ok,
156                                  "cancel": self.close
157                         }, -1)
158
159         def ok(self):
160                 self.close([self.xEntry.value, self.yEntry.value])
161
162 ##############################################################################
163
164 class MovielistPreviewPositioner(Screen):
165         def __init__(self, session):
166                 Screen.__init__(self, session)
167                 self.skin = SKIN
168                 self["background"] = Label("")
169                 self["preview"] = Pixmap()
170                 
171                 self["actions"] = ActionMap(["EPGSelectActions", "MenuActions", "WizardActions"],
172                 {
173                         "left": self.left,
174                         "up": self.up,
175                         "right": self.right,
176                         "down": self.down,
177                         "ok": self.ok,
178                         "back": self.exit,
179                         "menu": self.editCoordinates,
180                         "nextBouquet": self.bigger,
181                         "prevBouquet": self.smaller
182                 }, -1)
183                 
184                 desktop = getDesktop(0)
185                 self.desktopWidth = desktop.size().width()
186                 self.desktopHeight = desktop.size().height()
187                 
188                 self.moveTimer = eTimer()
189                 self.moveTimer.callback.append(self.movePosition)
190                 self.moveTimer.start(50, 1)
191                 
192                 self.onShow.append(self.__onShow)
193
194         def __onShow(self):
195                 if self.instance:
196                         size = config.plugins.MovielistPreview.size.value.split("x")
197                         self.instance.resize(eSize(int(size[0]), int(size[1])))
198                         self["background"].instance.resize(eSize(int(size[0]), int(size[1])))
199                         self["preview"].instance.resize(eSize(int(size[0]), int(size[1])))
200
201         def movePosition(self):
202                 self.instance.move(ePoint(config.plugins.MovielistPreview.position_x.value, config.plugins.MovielistPreview.position_y.value))
203                 self.moveTimer.start(50, 1)
204
205         def left(self):
206                 value = config.plugins.MovielistPreview.position_x.value
207                 value -= 1
208                 if value < 0:
209                         value = 0
210                 config.plugins.MovielistPreview.position_x.value = value
211
212         def up(self):
213                 value = config.plugins.MovielistPreview.position_y.value
214                 value -= 1
215                 if value < 0:
216                         value = 0
217                 config.plugins.MovielistPreview.position_y.value = value
218
219         def right(self):
220                 value = config.plugins.MovielistPreview.position_x.value
221                 value += 1
222                 if value > self.desktopWidth:
223                         value = self.desktopWidth
224                 config.plugins.MovielistPreview.position_x.value = value
225
226         def down(self):
227                 value = config.plugins.MovielistPreview.position_y.value
228                 value += 1
229                 if value > self.desktopHeight:
230                         value = self.desktopHeight
231                 config.plugins.MovielistPreview.position_y.value = value
232
233         def ok(self):
234                 config.plugins.MovielistPreview.position_x.save()
235                 config.plugins.MovielistPreview.position_y.save()
236                 self.close()
237
238         def exit(self):
239                 config.plugins.MovielistPreview.position_x.cancel()
240                 config.plugins.MovielistPreview.position_y.cancel()
241                 self.close()
242
243         def editCoordinates(self):
244                 self.session.openWithCallback(self.editCoordinatesCallback, MovielistPreviewPositionerCoordinateEdit, config.plugins.MovielistPreview.position_x.value, config.plugins.MovielistPreview.position_y.value, self.desktopWidth, self.desktopHeight)
245
246         def editCoordinatesCallback(self, callback=None):
247                 if callback:
248                         config.plugins.MovielistPreview.position_x.value = callback[0]
249                         config.plugins.MovielistPreview.position_y.value = callback[1]
250
251         def bigger(self):
252                 if config.plugins.MovielistPreview.size.value == "200x160":
253                         config.plugins.MovielistPreview.size.value = "250x200"
254                 elif config.plugins.MovielistPreview.size.value == "150x120":
255                         config.plugins.MovielistPreview.size.value = "200x160"
256                 elif config.plugins.MovielistPreview.size.value == "100x80":
257                         config.plugins.MovielistPreview.size.value = "150x120"
258                 config.plugins.MovielistPreview.size.save()
259                 self.__onShow()
260
261         def smaller(self):
262                 if config.plugins.MovielistPreview.size.value == "150x120":
263                         config.plugins.MovielistPreview.size.value = "100x80"
264                 elif config.plugins.MovielistPreview.size.value == "200x160":
265                         config.plugins.MovielistPreview.size.value = "150x120"
266                 elif config.plugins.MovielistPreview.size.value == "250x200":
267                         config.plugins.MovielistPreview.size.value = "200x160"
268                 config.plugins.MovielistPreview.size.save()
269                 self.__onShow()
270
271 ##############################################################################
272
273 class PreviewCreator:
274         def __init__(self):
275                 self.callback = None
276                 self.Console = Console()
277
278         def grab(self, file):
279                 if not self.Console:
280                         self.Console = Console()
281                 self.Console.ePopen('/usr/bin/grab -v -r 250 -l -j 100 "%s"'%file, self.grabDone)
282
283         def grabDone(self, result, retval, extra_args):
284                 if retval != 0:
285                         print result
286                 if self.callback:
287                         self.callback()
288 previewcreator = PreviewCreator()
289
290 ##############################################################################
291
292 class MovielistPreviewManualCreator(Screen, InfoBarBase, InfoBarSeek, InfoBarCueSheetSupport):
293         skin = """
294                 <screen position="center,center" size="560,380" title="%s">
295                         <widget name="video" position="100,20" size="360,288" backgroundColor="transparent" />
296                         <widget source="session.CurrentService" render="PositionGauge" position="145,330" size="270,10" pointer="skin_default/position_pointer.png:540,0" transparent="1" foregroundColor="#20224f">
297                                 <convert type="ServicePosition">Gauge</convert>
298                         </widget>
299                         <widget name="seekState" position="40,320" size="60,25" halign="right" font="Regular;18" valign="center" />
300                         <ePixmap pixmap="skin_default/icons/mp_buttons.png" position="225,350" size="109,13" alphatest="on" />
301                 </screen>""" % _("Movielist Preview")
302
303         def __init__(self, session, service):
304                 Screen.__init__(self, session)
305                 InfoBarSeek.__init__(self)
306                 InfoBarCueSheetSupport.__init__(self)
307                 InfoBarBase.__init__(self, steal_current_service=True)
308                 
309                 self.session = session
310                 self.service = service
311                 self.working = False
312                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
313                 self.session.nav.playService(service)
314                 previewcreator.callback = self.grabDone
315                 
316                 desktopSize = getDesktop(0).size()
317                 self["video"] = VideoWindow(decoder=0, fb_width=desktopSize.width(), fb_height=desktopSize.height())
318                 self["seekState"] = Label()
319                 
320                 self.onPlayStateChanged.append(self.updateStateLabel)
321                 self.updateStateLabel(self.seekstate)
322                 
323                 self["actions"] = ActionMap(["OkCancelActions"],
324                         {
325                                 "ok": self.grab,
326                                 "cancel": self.exit
327                         }, -2)
328
329         def checkSkipShowHideLock(self):
330                 pass
331
332         def updateStateLabel(self, state):
333                 self["seekState"].setText(state[3].strip())
334
335         def grab(self):
336                 if not self.working:
337                         self.working = True
338                         png = self.service.getPath() + "_mp.jpg"
339                         previewcreator.grab(png)
340
341         def grabDone(self):
342                 self.working = False
343                 self.session.open(MessageBox,_("Preview created."), MessageBox.TYPE_INFO, timeout=5)
344
345         def exit(self):
346                 if not self.working:
347                         self.session.nav.playService(self.oldService)
348                         self.close()
349
350 ##############################################################################
351
352 class MovielistPreviewAutoCreator(Screen):
353         skin = """
354                 <screen position="center,center" size="420,105" title="%s">
355                         <widget name="label" position="10,10" size="400,85" transparent="1" font="Regular;20" halign="center" valign="center" />
356                 </screen>""" % _("Movielist Preview")
357
358         def __init__(self, session):
359                 Screen.__init__(self, session)
360                 
361                 self.session = session
362                 self.files = []
363                 self.filescount = 0
364                 self.current = 1
365                 self.working = True
366                 self.abort = False
367                 self.dir = config.movielist.last_videodir.value
368                 previewcreator.callback = self.grabDone
369                 self.playable = ["avi", "dat", "divx", "m2ts", "m4a", "mkv", "mp4", "mov", "mpg", "ts", "vob"]
370                 self.oldService = self.session.nav.getCurrentlyPlayingServiceReference()
371                 
372                 self["label"] = Label()
373                 
374                 self.timer = eTimer()
375                 self.timer.callback.append(self.seekAndCreatePreview)
376                 
377                 self["actions"] = ActionMap(["OkCancelActions"], {"cancel": self.exit}, -1)
378                 
379                 self.onLayoutFinish.append(self.createPreviews)
380
381         def exit(self):
382                 if self.working == False:
383                         self.session.nav.playService(self.oldService)
384                         self.close()
385                 else:
386                         self.abort = True
387
388         def getExtension(self, name):
389                 ext = None
390                 if name.__contains__("."):
391                         tmp = name.split(".")
392                         ext = tmp[-1]
393                 return ext
394
395         def createPreviews(self):
396                 try:
397                         files = listdir(self.dir)
398                 except:
399                         files = []
400                 for file in files:
401                         ext = self.getExtension(file)
402                         if ext and (ext.lower() in self.playable):
403                                 self.files.append(file)
404                 self.filescount = len(self.files)
405                 if self.filescount == 0:
406                         self["label"].setText(_("Could not find any movie!"))
407                 else:
408                         self.createNextPreview()
409
410         def createNextPreview(self):
411                 if len(self.files):
412                         file = self.files[0]
413                         movie = ("%s/%s" % (self.dir, file)).replace("//", "/")
414                         png = movie + "_mp.jpg"
415                         if fileExists(png):
416                                 self.grabDone()
417                         else:
418                                 counter = "%d / %d" % (self.current, self.filescount)
419                                 self["label"].setText(_("%s - creating preview for movie %s") % (counter, movie))
420                                 if movie.endswith(".ts"):
421                                         ref = eServiceReference(1, 0, movie)
422                                 else:
423                                         ref = eServiceReference(4097, 0, movie)
424                                 self.session.nav.playService(ref)
425                                 self.png = png
426                                 self.timer.start(5000, 1)
427                 else:
428                         self["label"].setText(_("Everything done ;)"))
429                         self.working = False
430
431         def seekAndCreatePreview(self):
432                 service = self.session.nav.getCurrentService()
433                 if service:
434                         cue = service and service.cueSheet()
435                         if cue is not None:
436                                 cue.setCutListEnable(0)
437                         seek = service.seek()
438                         if seek:
439                                 length = int(seek.getLength()[1])
440                                 seek.seekTo(random.randint(0, length))
441                         previewcreator.grab(self.png)
442                 else:
443                         self.grabDone()
444
445         def grabDone(self):
446                 del self.files[0]
447                 self.current += 1
448                 if self.abort:
449                         self["label"].setText(_("Autocreate of previews aborted due user!"))
450                         self.working = False
451                 else:
452                         self.createNextPreview()
453
454 ##############################################################################
455
456 class MovielistPreviewMenu(Screen):
457         skin = """
458                 <screen position="center,center" size="420,105" title="%s">
459                         <widget name="list" position="5,5" size="410,100" />
460                 </screen>""" % _("Movielist Preview")
461
462         def __init__(self, session, service):
463                 Screen.__init__(self, session)
464                 self.session = session
465                 self.service = service
466                 self["list"] = MenuList([])
467                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.okClicked, "cancel": self.close}, -1)
468                 self.onLayoutFinish.append(self.showMenu)
469
470         def showMenu(self):
471                 list = []
472                 if config.plugins.MovielistPreview.enabled.value:
473                         list.append(_("Deactivate Movielist Preview"))
474                 else:
475                         list.append(_("Activate Movielist Preview"))
476                 list.append(_("Create preview"))
477                 list.append(_("Autocreate of missing previews"))
478                 list.append(_("Change Movielist Preview position"))
479                 self["list"].setList(list)
480
481         def okClicked(self):
482                 idx = self["list"].getSelectionIndex()
483                 if movielistpreview.dialog is None:
484                         movielistpreview.gotSession(self.session)
485                 if idx == 0:
486                         movielistpreview.changeVisibility()
487                         self.showMenu()
488                 elif idx == 1:
489                         movielistpreview.dialog.hide()
490                         self.session.open(MovielistPreviewManualCreator, self.service)
491                 elif idx == 2:
492                         movielistpreview.dialog.hide()
493                         self.session.open(MovielistPreviewAutoCreator)
494                 else:
495                         movielistpreview.dialog.hide()
496                         self.session.open(MovielistPreviewPositioner)
497
498 ##############################################################################
499
500 SelectionChanged = MovieList.selectionChanged
501 def selectionChanged(instance):
502         SelectionChanged(instance)
503         curr = instance.getCurrent()
504         if curr and isinstance(curr, eServiceReference):
505                 movielistpreview.showPreview(curr.getPath())
506 MovieList.selectionChanged = selectionChanged
507
508 Hide = MovieSelection.hide
509 def hideMovieSelection(instance):
510         Hide(instance)
511         movielistpreview.hideDialog()
512 MovieSelection.hide = hideMovieSelection
513
514 Show = MovieSelection.show
515 def showMovieSelection(instance):
516         Show(instance)
517         movielistpreview.showDialog()
518 MovieSelection.show = showMovieSelection
519
520 ##############################################################################
521
522 def selectionChanged2(instance):
523         SelectionChanged2(instance)
524         curr = instance.getCurrent()
525         if curr and isinstance(curr, eServiceReference):
526                 movielistpreview.showPreview(curr.getPath())
527
528 def hideMovieSelection2(instance):
529         Hide2(instance)
530         movielistpreview.hideDialog()
531
532 def showMovieSelection2(instance):
533         Show2(instance)
534         movielistpreview.showDialog()
535
536 try:
537         from Plugins.Extensions.Suomipoeka.MovieList import MovieList as MovieList2
538         from Plugins.Extensions.Suomipoeka.MovieSelection import MovieSelectionSP
539         SelectionChanged2 = MovieList2.selectionChanged
540         MovieList2.selectionChanged = selectionChanged2
541         Hide2 = MovieSelectionSP.hide
542         MovieSelectionSP.hide = hideMovieSelection2
543         Show2 = MovieSelectionSP.show
544         MovieSelectionSP.show = showMovieSelection2
545 except ImportError:
546         print "[Movielist Preview] Could not import Suomipoeka Plugin, maybe not installed or too old version?"
547
548 ##############################################################################
549
550 def sessionstart(reason, **kwargs):
551         if reason == 0:
552                 movielistpreview.gotSession(kwargs["session"])
553
554 def main(session, service):
555         session.open(MovielistPreviewMenu, service)
556
557 ##############################################################################
558
559 def Plugins(**kwargs):
560         return [
561                 PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART], fnc=sessionstart),
562                 PluginDescriptor(name=_("Movielist Preview"), description=_("Movielist Preview"), where=PluginDescriptor.WHERE_MOVIELIST, fnc=main)]