884b5a0773ad1415d748463b12181a2026c3d52f
[vuplus_dvbapp] / lib / python / Plugins / Extensions / DLNABrowser / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2
3 import os
4 from enigma import gFont, eTimer, eConsoleAppContainer, ePicLoad, getDesktop, eServiceReference, iPlayableService, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER, RT_VALIGN_CENTER
5
6 from Screens.Screen import Screen
7 from Screens.ChoiceBox import ChoiceBox
8 from Screens.MessageBox import MessageBox
9 from Screens.InfoBarGenerics import InfoBarNotifications
10
11 from Components.Button import Button
12 from Components.Label import Label
13 from Components.ConfigList import ConfigListScreen
14 from Components.Sources.StaticText import StaticText
15 from Components.ActionMap import NumberActionMap, ActionMap
16 from Components.config import config, ConfigSelection, getConfigListEntry, ConfigText, ConfigDirectory, ConfigYesNo, ConfigSelection
17 from Components.FileList import FileList, FileEntryComponent
18 from Components.MenuList import MenuList
19 from Components.Pixmap import Pixmap, MovingPixmap
20 from Components.AVSwitch import AVSwitch
21 from Components.ServiceEventTracker import ServiceEventTracker
22 from Components.MultiContent import MultiContentEntryText
23
24 from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS
25
26 EXTENSIONS = {
27         ".m4a" : "music",
28         ".mp2" : "music",
29         ".mp3" : "music",
30         ".wav" : "music",
31         ".ogg" : "music",
32         ".flac": "music",
33         ".ts"  : "movie",
34         ".avi" : "movie",
35         ".divx": "movie",
36         ".m4v" : "movie",
37         ".mpg" : "movie",
38         ".mpeg": "movie",
39         ".mkv" : "movie",
40         ".mp4" : "movie",
41         ".mov" : "movie",
42         ".m2ts": "movie",
43         ".wmv" : "movie",
44         ".jpg" : "picture",
45         ".jpeg": "picture",
46         ".png" : "picture",
47         ".bmp" : "picture",
48         ".m3u" : "stream",
49         ".m3u8": "stream",
50 }
51
52 DLNA_CONFIG_SLIDESHOW       = 10000
53 DLNA_CONFIG_DEVICE_REFRESH  = 10000
54 DLNA_CONFIG_ROOT_DIR        = '/media/upnp/'
55 DLNA_CONFIG_CLIENT_CONFNAME = "/etc/djmount.conf"
56
57
58 class DLNAFileList(FileList):
59         def __init__(self, directory):
60                 self.rootDir = directory
61                 inhibitDirs = ["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/usr", "/var"]
62                 matchingPattern = "(?i)^.*\.(m4a|mp2|mp3|wav|ogg|flac|ts|avi|divx|m4v|mpg|mpeg|mkv|mp4|mov|m2ts|jpg|jpeg|png|bmp)"
63                 FileList.__init__(self, directory=directory, matchingPattern=matchingPattern, showDirectories=True, showFiles=True, inhibitMounts=[], inhibitDirs=inhibitDirs, isTop=True)
64
65         def changeTop(self):
66                 parent = ""
67                 directoryItem = self.rootDir[:-1].split('/')
68                 directoryItem.pop()
69                 for di in directoryItem:
70                         parent += di+'/'
71                 self.changeDir(self.rootDir, select=parent)
72
73         def changeParent(self):
74                 i, parent, grandParent = 0, "", ""
75                 currentDir = self.getCurrentDirectory()
76                 if currentDir == self.rootDir:
77                         return False
78                 directoryItem = currentDir[:-1].split('/')
79                 directoryItem.pop()
80                 for di in directoryItem:
81                         parent += di+'/'
82                 if len(directoryItem) > 0:
83                         directoryItem.pop()
84                 for di in directoryItem:
85                         grandParent += di+'/'
86                 if parent == grandParent:
87                         return False
88                 self.changeDir(parent, select=grandParent)
89                 return True
90
91         def getFileType(self):
92                 try:
93                         selectedFileName = self.getSelection()[0]
94                         splitedFileName  = os.path.splitext(selectedFileName)
95                         return EXTENSIONS[splitedFileName[1]]
96                 except: pass
97                 return 'unknown'
98
99 class DLNAFileBrowser(Screen):
100         skin =  """
101                 <screen name="DLNAFileBrowser" position="center,center" size="600,350" title="File Browser">
102                         <ePixmap pixmap="skin_default/buttons/red.png" position="5,0" size="140,40" alphatest="on" />
103                         <ePixmap pixmap="skin_default/buttons/green.png" position="155,0" size="140,40" alphatest="on" />
104                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="305,0" size="140,40" alphatest="on" />
105                         <ePixmap pixmap="skin_default/buttons/blue.png" position="455,0" size="140,40" alphatest="on" />
106
107                         <widget source="key_red" render="Label" position="5,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
108                         <widget source="key_green" render="Label" position="155,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
109                         <widget source="key_yellow" render="Label" position="305,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" foregroundColor="#ffffff" transparent="1" />
110                         <widget source="key_blue" render="Label" position="455,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" foregroundColor="#ffffff" transparent="1" />
111
112                         <widget name="directory" position="10,45" size="600,40" valign="center" font="Regular;20" />
113                         <widget name="filelist" position="0,100" zPosition="1" size="560,250" scrollbarMode="showOnDemand"/>
114                 </screen>
115                 <!--
116                 <screen name="DLNAFileBrowser" position="center,90" size="1000,580" title="File Browser">
117                         <ePixmap pixmap="skin_default/buttons/red.png" position="55,0" size="140,40" alphatest="on" />
118                         <ePixmap pixmap="skin_default/buttons/green.png" position="305,0" size="140,40" alphatest="on" />
119                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="555,0" size="140,40" alphatest="on" />
120                         <ePixmap pixmap="skin_default/buttons/blue.png" position="805,0" size="140,40" alphatest="on" />
121
122                         <widget source="key_red" render="Label" position="55,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
123                         <widget source="key_green" render="Label" position="305,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
124                         <widget source="key_yellow" render="Label" position="555,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" foregroundColor="#ffffff" transparent="1" />
125                         <widget source="key_blue" render="Label" position="805,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" foregroundColor="#ffffff" transparent="1" />
126
127                         <widget name="directory" position="10,60" size="980,22" valign="center" font="Regular;22" />
128                         <widget name="filelist" position="0,100" zPosition="1" size="1000,480" scrollbarMode="showOnDemand"/>
129                 </screen>
130                 -->
131                 """
132         def __init__(self, session, directory):
133                 self.session = session
134                 Screen.__init__(self, session)
135                 
136                 self["actions"]  = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"], {
137                         "back"  : self.keyCancel,
138                         "left"  : self.keyLeft,
139                         "right" : self.keyRight,
140                         "up"    : self.keyUp,
141                         "down"  : self.keyDown,
142                         "ok"    : self.keyOK,
143                         "green" : self.keyGreen,
144                         "red"   : self.keyCancel,
145                         "yellow": self.keyYellow,
146                         "blue"  : self.keyBlue
147                 }, -1)
148
149                 self["directory"]  = Label()
150                 self["key_red"]    = StaticText(_("Show Device"))
151                 self["key_green"]  = StaticText(_(" "))
152                 self["key_yellow"] = StaticText(_("Up"))
153                 self["key_blue"]   = StaticText(_("Top"))
154                 self["filelist"]   = DLNAFileList(directory)
155
156                 self.onLayoutFinish.append(self.layoutFinished)
157
158                 self.showCB = {
159                         'movie'   : self.showMovie,
160                         'music'   : self.showMusic,
161                         'picture' : self.showPicture,
162                         'stream'  : self.showStream,
163                         'unknown' : self.showUnknown,
164                 }
165
166         def layoutFinished(self):
167                 self.updateDirectory()
168
169         def keyCancel(self):
170                 self.close()
171
172         def keyBlue(self):
173                 self["filelist"].changeTop()
174                 self.updateDirectory()
175
176         def keyGreen(self):
177                 print "not implements!!"
178
179         def keyYellow(self):
180                 self["filelist"].changeParent()
181                 self.updateDirectory()
182
183         def keyUp(self):
184                 self["filelist"].up()
185                 self.updateDirectory()
186
187         def keyDown(self):
188                 self["filelist"].down()
189                 self.updateDirectory()
190
191         def keyLeft(self):
192                 self["filelist"].pageUp()
193                 self.updateDirectory()
194
195         def keyRight(self):
196                 self["filelist"].pageDown()
197                 self.updateDirectory()
198
199         def keyOK(self):
200                 try:
201                         if self["filelist"].canDescent():
202                                 self["filelist"].descent()
203                                 self.updateDirectory()
204                                 return
205                 except: return
206                 fileType = self["filelist"].getFileType()
207                 self.showCB[fileType]()
208
209         def updateDirectory(self):
210                 directory = self["filelist"].getSelection()[0]
211                 if directory is None or directory.strip() == '':
212                         directory = "Empty Directory!!"
213                 self["directory"].setText(directory)
214
215         def showMovie(self):
216                 from Plugins.Extensions.MediaPlayer.plugin import MediaPlayer
217                 self.beforeService = self.session.nav.getCurrentlyPlayingServiceReference()
218                 path = self["filelist"].getCurrentDirectory() + self["filelist"].getFilename()
219                 mp = self.session.open(MediaPlayer)
220                 mp.callback = self.cbShowMovie
221                 mp.playlist.clear()
222                 mp.savePlaylistOnExit = False
223                 mp.playlist.addFile(eServiceReference(4097, 0, path))
224                 mp.changeEntry(0)
225                 mp.switchToPlayList()
226                 
227         def showPicture(self):
228                 self.session.openWithCallback(self.cbShowPicture, 
229                                               DLNAImageViewer, 
230                                               self["filelist"].getFileList(), 
231                                               self["filelist"].getSelectionIndex(), 
232                                               self["filelist"].getCurrentDirectory())
233
234         def showMusic(self):
235                 self.showMovie()
236
237         def showStream(self):
238                 path = self["filelist"].getCurrentDirectory() + self["filelist"].getFilename()
239                 self.beforeService = self.session.nav.getCurrentlyPlayingServiceReference()
240                 self.session.openWithCallback(self.cbShowMovie, 
241                                               DLNAStreamPlayer, 
242                                               eServiceReference(4097, 0, path), 
243                                               self.beforeService)
244
245         def showUnknown(self):
246                 message = "Can't play selected file. It is unknown file extension."
247                 self.session.open(MessageBox, message, type=MessageBox.TYPE_INFO)
248
249         def cbShowMovie(self, data=None):
250                 if self.beforeService is not None:
251                         self.session.nav.playService(self.beforeService)
252                         self.beforeService = None
253
254         def cbShowPicture(self, idx=0):
255                 if idx > 0: self["filelist"].moveToIndex(idx)
256
257 class DLNAStreamPlayer(Screen, InfoBarNotifications):
258         skin =  """
259                 <screen name="DLNAStreamPlayer" flags="wfNoBorder" position="center,620" size="455,53" title="DLNAStreamPlayer" backgroundColor="transparent">
260                         <ePixmap pixmap="Vu_HD/mp_wb_background.png" position="0,0" zPosition="-1" size="455,53" />
261                         <ePixmap pixmap="Vu_HD/icons/mp_wb_buttons.png" position="40,23" size="30,13" alphatest="on" />
262
263                         <widget source="session.CurrentService" render="PositionGauge" position="80,25" size="220,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" foregroundColor="#20224f">
264                                 <convert type="ServicePosition">Gauge</convert>
265                         </widget>
266                         
267                         <widget source="session.CurrentService" render="Label" position="310,20" size="50,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" >
268                                 <convert type="ServicePosition">Position</convert>
269                         </widget>
270                         <widget name="sidebar" position="362,20" size="10,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" />
271                         <widget source="session.CurrentService" render="Label" position="374,20" size="50,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" > 
272                                 <convert type="ServicePosition">Length</convert>
273                         </widget>
274                 </screen>
275                 """
276         PLAYER_IDLE     = 0
277         PLAYER_PLAYING  = 1
278         PLAYER_PAUSED   = 2
279
280         def __init__(self, session, service, lastservice):
281                 Screen.__init__(self, session)
282                 InfoBarNotifications.__init__(self)
283
284                 self.session     = session
285                 self.service     = service
286                 self.lastservice = lastservice
287                 self["actions"] = ActionMap(["OkCancelActions", "InfobarSeekActions", "MediaPlayerActions", "MovieSelectionActions"], {
288                         "ok": self.doInfoAction,
289                         "cancel": self.doExit,
290                         "stop": self.doExit,
291                         "playpauseService": self.playpauseService,
292                 }, -2)
293                 self["sidebar"] = Label(_("/"))
294
295                 self.__event_tracker = ServiceEventTracker(screen = self, eventmap = {
296                         iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
297                         iPlayableService.evStart: self.__serviceStarted,
298                         iPlayableService.evEOF: self.__evEOF,
299                 })
300
301                 self.hidetimer = eTimer()
302                 self.hidetimer.timeout.get().append(self.doInfoAction)
303
304                 self.state = self.PLAYER_PLAYING
305                 self.lastseekstate = self.PLAYER_PLAYING
306                 self.__seekableStatusChanged()
307         
308                 self.onClose.append(self.__onClose)
309                 self.doPlay()
310
311         def __onClose(self):
312                 self.session.nav.stopService()
313
314         def __seekableStatusChanged(self):
315                 service = self.session.nav.getCurrentService()
316                 if service is not None:
317                         seek = service.seek()
318                         if seek is None or not seek.isCurrentlySeekable():
319                                 self.setSeekState(self.PLAYER_PLAYING)
320
321         def __serviceStarted(self):
322                 self.state = self.PLAYER_PLAYING
323                 self.__seekableStatusChanged()
324
325         def __evEOF(self):
326                 self.doExit()
327
328         def __setHideTimer(self):
329                 self.hidetimer.start(5000)
330
331         def doExit(self):
332                 list = ((_("Yes"), "y"), (_("No"), "n"),)
333                 self.session.openWithCallback(self.cbDoExit, ChoiceBox, title=_("Stop playing this movie?"), list = list)
334
335         def cbDoExit(self, answer):
336                 answer = answer and answer[1]
337                 if answer == "y":
338                         self.close()
339
340         def setSeekState(self, wantstate):
341                 service = self.session.nav.getCurrentService()
342                 if service is None:
343                         print "No Service found"
344                         return
345
346                 pauseable = service.pause()
347                 if pauseable is not None:
348                         if wantstate == self.PLAYER_PAUSED:
349                                 pauseable.pause()
350                                 self.state = self.PLAYER_PAUSED
351                                 if not self.shown:
352                                         self.hidetimer.stop()
353                                         self.show()
354                         elif wantstate == self.PLAYER_PLAYING:
355                                 pauseable.unpause()
356                                 self.state = self.PLAYER_PLAYING
357                                 if self.shown:
358                                         self.__setHideTimer()
359                 else:
360                         self.state = self.PLAYER_PLAYING
361
362         def doInfoAction(self):
363                 if self.shown:
364                         self.hidetimer.stop()
365                         self.hide()
366                 else:
367                         self.show()
368                         if self.state == self.PLAYER_PLAYING:
369                                 self.__setHideTimer()
370
371         def doPlay(self):
372                 if self.state == self.PLAYER_PAUSED:
373                         if self.shown:
374                                 self.__setHideTimer()   
375                 self.state = self.PLAYER_PLAYING
376                 self.session.nav.playService(self.service)
377                 if self.shown:
378                         self.__setHideTimer()
379
380         def playpauseService(self):
381                 if self.state == self.PLAYER_PLAYING:
382                         self.setSeekState(self.PLAYER_PAUSED)
383                 elif self.state == self.PLAYER_PAUSED:
384                         self.setSeekState(self.PLAYER_PLAYING)
385
386 class DLNAImageViewer(Screen):
387         s, w, h = 30, getDesktop(0).size().width(), getDesktop(0).size().height()
388         skin = """
389                 <screen position="0,0" size="%d,%d" flags="wfNoBorder">
390                         <eLabel position="0,0" zPosition="0" size="%d,%d" backgroundColor="#00000000" />
391                         <widget name="image" position="%d,%d" size="%d,%d" zPosition="1" alphatest="on" />
392                         <widget name="status" position="%d,%d" size="20,20" zPosition="2" pixmap="skin_default/icons/record.png" alphatest="on" />
393                         <widget name="icon" position="%d,%d" size="20,20" zPosition="2" pixmap="skin_default/icons/ico_mp_play.png"  alphatest="on" />
394                         <widget source="message" render="Label" position="%d,%d" size="%d,25" font="Regular;20" halign="left" foregroundColor="#0038FF48" zPosition="2" noWrap="1" transparent="1" />
395                 </screen>
396                 """ % (w, h, w, h, s, s, w-(s*2), h-(s*2), s+5, s+2, s+25, s+2, s+45, s, w-(s*2)-50)
397
398         def __init__(self, session, fileList, index, path):
399                 Screen.__init__(self, session)
400                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions", "MovieSelectionActions"], {
401                         "cancel": self.keyCancel,
402                         "left"  : self.keyLeft,
403                         "right" : self.keyRight,
404                         "blue"  : self.keyBlue,
405                         "yellow": self.keyYellow,
406                 }, -1)
407
408                 self["icon"]    = Pixmap()
409                 self["image"]   = Pixmap()
410                 self["status"]  = Pixmap()
411                 self["message"] = StaticText(_("Please wait, Loading image."))
412
413                 self.fileList     = []
414                 self.currentImage = []
415
416                 self.lsatIndex      = index
417                 self.fileListLen    = 0
418                 self.currentIndex   = 0
419                 self.directoryCount = 0
420
421                 self.displayNow = True
422
423                 self.makeFileList(fileList, path)
424
425                 self.pictureLoad = ePicLoad()
426                 self.pictureLoad.PictureData.get().append(self.finishDecode)
427
428                 self.slideShowTimer = eTimer()
429                 self.slideShowTimer.callback.append(self.cbSlideShow)
430
431                 self.onLayoutFinish.append(self.layoutFinished)
432
433         def layoutFinished(self):
434                 if self.fileListLen >= 0:
435                         self.setPictureLoadPara()
436
437         def keyLeft(self):
438                 self.currentImage = []
439                 self.currentIndex = self.lsatIndex
440                 self.currentIndex -= 1
441                 if self.currentIndex < 0:
442                         self.currentIndex = self.fileListLen
443                 self.startDecode()
444                 self.displayNow = True
445
446         def keyRight(self):
447                 self.displayNow = True
448                 self.showPicture()
449
450         def keyYellow(self):
451                 if self.fileListLen < 0:
452                         return
453                 from Plugins.Extensions.PicturePlayer.plugin import Pic_Exif
454                 self.session.open(Pic_Exif, self.pictureLoad.getInfo(self.fileList[self.lsatIndex]))
455
456         def keyBlue(self):
457                 if self.slideShowTimer.isActive():
458                         self.slideShowTimer.stop()
459                         self["icon"].hide()
460                 else:
461                         global DLNA_CONFIG_SLIDESHOW
462                         self.slideShowTimer.start(DLNA_CONFIG_SLIDESHOW)
463                         self["icon"].show()
464                         self.keyRight()
465
466         def keyCancel(self):
467                 del self.pictureLoad
468                 self.close(self.lsatIndex + self.directoryCount)
469
470         def setPictureLoadPara(self):
471                 sc = AVSwitch().getFramebufferScale()
472                 self.pictureLoad.setPara([self["image"].instance.size().width(), 
473                                           self["image"].instance.size().height(), 
474                                           sc[0],
475                                           sc[1],
476                                           0,
477                                           int(config.pic.resize.value),
478                                           '#00000000'])
479                 self["icon"].hide()
480                 if config.pic.infoline.value == False:
481                         self["message"].setText("")
482                 self.startDecode()
483
484         def makeFileList(self, fileList, path):
485                 for x in fileList:
486                         l = len(fileList[0])
487                         if l == 3:
488                                 if x[0][1] == False:
489                                         self.fileList.append(path + x[0][0])
490                                 else:   self.directoryCount += 1
491                         elif l == 2:
492                                 if x[0][1] == False:
493                                         self.fileList.append(x[0][0])
494                                 else:   self.directoryCount += 1
495                         else:   self.fileList.append(x[4])
496                 
497                 self.currentIndex = self.lsatIndex - self.directoryCount
498                 if self.currentIndex < 0:
499                         self.currentIndex = 0
500                 self.fileListLen = len(self.fileList) - 1
501
502         def showPicture(self):
503                 if self.displayNow and len(self.currentImage):
504                         self.displayNow = False
505                         self["message"].setText(self.currentImage[0])
506                         self.lsatIndex = self.currentImage[1]
507                         self["image"].instance.setPixmap(self.currentImage[2].__deref__())
508                         self.currentImage = []
509
510                         self.currentIndex += 1
511                         if self.currentIndex > self.fileListLen:
512                                 self.currentIndex = 0
513                         self.startDecode()
514
515         def finishDecode(self, picInfo=""):
516                 self["status"].hide()
517                 ptr = self.pictureLoad.getData()
518                 if ptr != None:
519                         text = ""
520                         try:
521                                 text = picInfo.split('\n',1)
522                                 text = "(" + str(self.currentIndex+1) + "/" + str(self.fileListLen+1) + ") " + text[0].split('/')[-1]
523                         except:
524                                 pass
525                         self.currentImage = []
526                         self.currentImage.append(text)
527                         self.currentImage.append(self.currentIndex)
528                         self.currentImage.append(ptr)
529                         self.showPicture()
530
531         def startDecode(self):
532                 self.pictureLoad.startDecode(self.fileList[self.currentIndex])
533                 self["status"].show()
534
535         def cbSlideShow(self):
536                 print "slide to next Picture index=" + str(self.lsatIndex)
537                 if config.pic.loop.value==False and self.lsatIndex == self.fileListLen:
538                         self.PlayPause()
539                 self.displayNow = True
540                 self.showPicture()
541
542 class TaskManager:
543         def __init__(self):
544                 self.taskIdx = 0
545                 self.taskList = []
546                 self.gTaskInstance = None
547                 self.occurError = False
548                 self.cbSetStatusCB = None
549
550         def append(self, command, cbDataFunc, cbCloseFunc):
551                 self.taskList.append([command+'\n', cbDataFunc, cbCloseFunc])
552
553         def dump(self):
554                 print "############### TASK ###############"
555                 print "Current Task Index :", self.taskIdx
556                 print "Current Task Instance :", self.gTaskInstance
557                 print "Occur Error :", self.occurError
558                 print "Task List:\n", self.taskList
559                 print "####################################"
560
561         def error(self):
562                 print "[DLNAClient Plugin] Info >> set task error!!"
563                 self.occurError = True
564
565         def reset(self):
566                 self.taskIdx = 0
567                 self.gTaskInstance = None
568                 self.occurError = False
569
570         def clean(self):
571                 self.reset()
572                 self.taskList = []
573                 self.cbSetStatusCB = None
574                 print "clear task!!"
575
576         def index(self):
577                 self.taskIdx
578
579         def setStatusCB(self, cbfunc):
580                 self.cbSetStatusCB = cbfunc
581                 
582         def next(self):
583                 if self.taskIdx >= len(self.taskList) or self.occurError:
584                         print "[DLNAClient Plugin] Info >> can't run task!!"
585                         return False
586                 command     = self.taskList[self.taskIdx][0]
587                 cbDataFunc  = self.taskList[self.taskIdx][1]
588                 cbCloseFunc = self.taskList[self.taskIdx][2]
589
590                 self.gTaskInstance = eConsoleAppContainer()
591                 if cbDataFunc is not None:
592                         self.gTaskInstance.dataAvail.append(cbDataFunc)
593                 if cbCloseFunc is not None:
594                         self.gTaskInstance.appClosed.append(cbCloseFunc)
595                 if self.cbSetStatusCB is not None:
596                         self.cbSetStatusCB(self.taskIdx)
597
598                 print "[DLNAClient Plugin] Info >> prepared command : %s"%(command)
599                 self.gTaskInstance.execute(command)
600                 self.taskIdx += 1
601                 return True
602
603 class DLNAClientConfig(ConfigListScreen, Screen):
604         skin=   """
605                 <screen position="center,center" size="600,350" title="Mini DLNA Runcher">
606                         <ePixmap pixmap="skin_default/buttons/red.png" position="5,0" size="140,40" alphatest="on" />
607                         <ePixmap pixmap="skin_default/buttons/green.png" position="155,0" size="140,40" alphatest="on" />
608                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="305,0" size="140,40" alphatest="on" />
609                         <ePixmap pixmap="skin_default/buttons/blue.png" position="455,0" size="140,40" alphatest="on" />
610
611                         <widget source="key_red" render="Label" position="5,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
612                         <widget source="key_green" render="Label" position="155,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
613                         <widget source="key_yellow" render="Label" position="305,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" foregroundColor="#ffffff" transparent="1" />
614                         <widget source="key_blue" render="Label" position="455,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" foregroundColor="#ffffff" transparent="1" />
615
616                         <widget name="config" position="0,50" size="600,200" scrollbarMode="showOnDemand" />
617                 </screen>
618                 """
619         def __init__(self, session): 
620                 self.session = session
621                 Screen.__init__(self, session)
622
623                 self.menulist  = []
624                 self.oldConfig = {}
625                 ConfigListScreen.__init__(self, self.menulist)
626
627                 global DLNA_CONFIG_CLIENT_CONFNAME
628                 self.configFileName = DLNA_CONFIG_CLIENT_CONFNAME
629                 self["actions"] = ActionMap(["OkCancelActions", "ShortcutActions", "WizardActions", "ColorActions", "SetupActions", ], {
630                         "red"    : self.keyExit,
631                         "green"  : self.keyOK,
632                         "cancel" : self.keyExit,
633                         "ok"     : self.keyOK,
634                 }, -2)
635                 self["key_red"]     = StaticText(_("Exit"))
636                 self["key_green"]   = StaticText(_("Save"))
637                 self["key_yellow"]  = StaticText(_(" "))
638                 self["key_blue"]    = StaticText(_(" "))
639
640                 self.makeMenuList()
641
642         def keyExit(self):
643                 self.close(None, None, None)
644
645         def keyOK(self):
646                 self.writeConfigFile()
647                 #self.close(self.menuItemRefresh.value, self.menuItemRootDir.value)
648                 self.close(self.menuItemRefresh.value, None, self.menuItemSlideshow.value)
649
650         def makeMenuList(self):
651                 self.readConfigFile()
652                 #self.menuItemRootDir   = ConfigText(default=self.oldConfig.get('rootdir'))
653                 self.menuItemRefresh   = ConfigSelection(default=self.oldConfig.get('refresh'), choices = [("5", _("5")), ("10", _("10")), ("15", _("15"))])
654                 self.menuItemSlideshow = ConfigSelection(default=self.oldConfig.get('slideshow'), choices = [("5", _("5")), ("10", _("10")), ("15", _("15")), ("20", _("20"))])
655
656                 #self.menuEntryRootDir   = getConfigListEntry(_("Mount Point"), self.menuItemRootDir)
657                 self.menuEntryRefresh   = getConfigListEntry(_("DeviceList Refresh Interval"), self.menuItemRefresh)
658                 self.menuEntrySlideshow = getConfigListEntry(_("Slideshow Interval"), self.menuItemSlideshow)
659                 self.resetMenuList()
660
661         def resetMenuList(self):
662                 self.menulist = []
663                 #self.menulist.append(self.menuEntryRootDir)
664                 self.menulist.append(self.menuEntryRefresh)
665                 self.menulist.append(self.menuEntrySlideshow)
666                 self["config"].list = self.menulist
667                 self["config"].l.setList(self.menulist)
668
669         def writeConfigFile(self):
670                 def configDataAppend(origin, key, value):
671                         if key.strip() != '' and value.strip() != '':
672                                 origin += "%s=%s\n" % (key,value)
673                         return origin
674                 configString = ""
675                 #configString = configDataAppend(configString, "rootdir", self.menuItemRootDir.value)
676                 configString = configDataAppend(configString, "refresh", self.menuItemRefresh.value)
677                 configString = configDataAppend(configString, "slideshow", self.menuItemSlideshow.value)
678                 print configString
679                 confFile = file(self.configFileName, 'w')
680                 confFile.write(configString)
681                 confFile.close()
682
683         def readConfigFile(self):
684                 def setDefault(key, default):
685                         try:
686                                 value = self.oldConfig.get(key)
687                                 if value == None or value.strip() == '':
688                                         self.oldConfig[key] = default
689                         except: self.oldConfig[key] = default
690
691                 self.oldConfig = {}
692                 if not os.path.exists(self.configFileName):
693                         #setDefault('rootdir', '/media/upnp/')
694                         setDefault('refresh', '10')
695                         setDefault('slideshow', '10')
696                         return
697                 for line in file(self.configFileName).readlines():
698                         line = line.strip()
699                         if line == '' or line[0] == '#':
700                                 continue
701                         try:
702                                 i   = line.find('=')
703                                 k,v = line[:i],line[i+1:]
704                                 self.oldConfig[k] = v
705                         except : pass
706
707                 #setDefault('rootdir', '/media/upnp/')
708                 setDefault('refresh', '10')
709                 setDefault('slideshow', '10')
710                 print "Current Config : ", self.oldConfig
711
712
713 class DLNADeviceBrowser(Screen):
714         skin =  """
715                 <screen name="DLNADeviceBrowser" position="center,center" size="600,350" title="Device Browser">
716                         <ePixmap pixmap="skin_default/buttons/red.png" position="5,0" size="140,40" alphatest="on" />
717                         <ePixmap pixmap="skin_default/buttons/green.png" position="155,0" size="140,40" alphatest="on" />
718                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="305,0" size="140,40" alphatest="on" />
719                         <ePixmap pixmap="skin_default/buttons/blue.png" position="455,0" size="140,40" alphatest="on" />
720
721                         <widget source="key_red" render="Label" position="5,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" foregroundColor="#ffffff" transparent="1" />
722                         <widget source="key_green" render="Label" position="155,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" foregroundColor="#ffffff" transparent="1" />
723                         <widget source="key_yellow" render="Label" position="305,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" foregroundColor="#ffffff" transparent="1" />
724                         <widget source="key_blue" render="Label" position="455,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" foregroundColor="#ffffff" transparent="1" />
725
726                         <widget name="devicelist" position="0,50" size="600,300" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />
727                 </screen>
728                 """
729         def __init__(self, session):
730                 Screen.__init__(self, session)
731                 self["actions"]  = ActionMap(["OkCancelActions", "ShortcutActions", "WizardActions", "ColorActions", "SetupActions", "NumberActions", "MenuActions"], {
732                         "ok"    : self.keyOK,
733                         "cancel": self.keyCancel,
734                         "red"   : self.keyCancel,
735                         "green" : self.keyGreen,
736                         "yellow": self.keyYellow,
737                         "blue"  : self.keyBlue,
738                 }, -1)
739
740                 global DLNA_CONFIG_CLIENT_CONFNAME
741                 self.configFileName = DLNA_CONFIG_CLIENT_CONFNAME
742                 self["key_red"]    = StaticText(_("Exit"))
743                 self["key_green"]  = StaticText(_("Start"))
744                 self["key_yellow"] = StaticText(_("Setting"))
745                 self["key_blue"]   = StaticText(_("Reload Device"))
746
747                 #self["devicelist"] = MenuList(self.setListOnView())
748                 self["devicelist"] = MenuList([])
749                 self.onLayoutFinish.append(self.layoutFinished)
750
751                 self.initConfig()
752                 self.taskManager = TaskManager()
753
754                 self.toggleGreenButtonTimer = eTimer()
755                 self.toggleGreenButtonTimer.timeout.get().append(self.cbToggleGreenButton)
756
757                 self.deviceListRefreshTimer = eTimer()
758                 self.deviceListRefreshTimer.timeout.get().append(self.cbDeviceListRefresh)
759                 global DLNA_CONFIG_DEVICE_REFRESH
760                 self.deviceListRefreshTimer.start(DLNA_CONFIG_DEVICE_REFRESH)
761
762         def layoutFinished(self):
763                 if not os.path.exists('/media/upnp'):
764                         os.system('mkdir -p /media/upnp')
765                 self.updateGUI()
766                 if self["key_green"].getText() == 'Start':
767                         global DLNA_CONFIG_DEVICE_REFRESH
768                         self.deviceListRefreshTimer.start(DLNA_CONFIG_DEVICE_REFRESH)
769
770         def keyYellow(self):
771                 self.deviceListRefreshTimer.stop()
772                 self.session.openWithCallback(self.cbConfigClose, DLNAClientConfig)
773
774         def keyGreen(self):
775                 global DLNA_CONFIG_ROOT_DIR
776                 if self["key_green"].getText() == 'Stop':
777                         cmd = 'fusermount -u %s'%(DLNA_CONFIG_ROOT_DIR)
778                         self.taskManager.append(cmd, self.cbPrintAvail, self.cbPrintClose)
779                         cmd = 'modprobe -r fuse'
780                         self.taskManager.append(cmd, self.cbPrintAvail, self.cbStopDone)
781                         #cmd = 'killall -9 djmount'
782                         #self.taskManager.append(cmd, self.cbPrintAvail, self.cbTasksDone)
783                         self["devicelist"].setList([])
784                 else:
785                         cmd = 'modprobe fuse'
786                         self.taskManager.append(cmd, self.cbPrintAvail, self.cbPrintClose)
787                         cmd = 'djmount -o allow_other -o iocharset=utf8 %s'%(DLNA_CONFIG_ROOT_DIR)
788                         self.taskManager.append(cmd, self.cbPrintAvail, self.cbStartDone)
789                 self.taskManager.next()
790
791         def keyCancel(self):
792                 self.close()
793
794         def keyOK(self):
795                 global DLNA_CONFIG_ROOT_DIR
796                 selectedItem = self["devicelist"].getCurrent()
797                 if selectedItem is None:
798                         return
799                 selectedFullPaht = '%s%s/'%(DLNA_CONFIG_ROOT_DIR, selectedItem[1])
800                 self.session.openWithCallback(self.cbDeviceListRefresh, DLNAFileBrowser, selectedFullPaht)
801                 self.deviceListRefreshTimer.stop()
802
803         def keyBlue(self):
804                 print "updated device list!!"
805                 self["devicelist"].setList(self.setListOnView())
806
807         def initConfig(self):
808                 global DLNA_CONFIG_ROOT_DIR
809                 global DLNA_CONFIG_SLIDESHOW
810                 global DLNA_CONFIG_DEVICE_REFRESH
811                 if not os.path.exists(self.configFileName):
812                         DLNA_CONFIG_ROOT_DIR = '/media/upnp/'
813                         DLNA_CONFIG_DEVICE_REFRESH = 10000
814                         DLNA_CONFIG_SLIDESHOW = 10000
815                         print "config : [%s][%d][%d]"%(DLNA_CONFIG_ROOT_DIR, DLNA_CONFIG_SLIDESHOW, DLNA_CONFIG_DEVICE_REFRESH)
816                         return
817                 for line in file(self.configFileName).readlines():
818                         line = line.strip()
819                         if line == '' or line[0] == '#':
820                                 continue
821                         try:
822                                 i   = line.find('=')
823                                 k,v = line[:i],line[i+1:]
824                                 if k == 'rootdir':      DLNA_CONFIG_ROOT_DIR = v
825                                 elif k == 'refresh':    DLNA_CONFIG_DEVICE_REFRESH = int(v)*1000
826                                 elif k == 'slideshow':  DLNA_CONFIG_SLIDESHOW = int(v)*1000
827                         except : pass
828                 print "config : [%s][%d][%d]"%(DLNA_CONFIG_ROOT_DIR, DLNA_CONFIG_SLIDESHOW, DLNA_CONFIG_DEVICE_REFRESH)
829
830         def isRunning(self):
831                 ps_str = os.popen('cat /etc/mtab | grep djmount').read()
832                 if ps_str.strip() != '':
833                         return True
834                 return False
835
836         def updateGUI(self):
837                 green_btm_str = 'Start'
838                 if self.isRunning():
839                         green_btm_str = 'Stop'
840                 self["key_green"].setText(green_btm_str)
841                 self.keyBlue()
842
843         def cbConfigClose(self, refresh, rootdir, slideshow):
844                 global DLNA_CONFIG_ROOT_DIR
845                 global DLNA_CONFIG_SLIDESHOW
846                 global DLNA_CONFIG_DEVICE_REFRESH
847                 try:
848                         if refresh is not None:
849                                 newRefresh = int(refresh)*1000
850                                 if DLNA_CONFIG_DEVICE_REFRESH != newRefresh:
851                                         DLNA_CONFIG_DEVICE_REFRESH = newRefresh
852                 except: pass
853                 try:
854                         if rootdir is not None:
855                                 if DLNA_CONFIG_ROOT_DIR != rootdir:
856                                         DLNA_CONFIG_ROOT_DIR = rootdir
857                                         print "need restart!!!"
858                 except: pass
859                 try:
860                         if slideshow is not None:
861                                 newSlideshow = int(slideshow)*1000
862                                 if DLNA_CONFIG_SLIDESHOW != newSlideshow:
863                                         DLNA_CONFIG_SLIDESHOW = newSlideshow
864                 except: pass
865                 self.deviceListRefreshTimer.start(DLNA_CONFIG_DEVICE_REFRESH)
866                 print "config : [%s][%d][%d]"%(DLNA_CONFIG_ROOT_DIR, DLNA_CONFIG_SLIDESHOW, DLNA_CONFIG_DEVICE_REFRESH)
867
868         def cbPrintAvail(self, data):
869                 print data
870
871         def cbPrintClose(self, ret):
872                 self.taskManager.next()
873
874         def cbStopDone(self, ret):
875                 self.taskManager.clean()
876                 self.toggleGreenButtonTimer.start(1000)
877                 self.deviceListRefreshTimer.stop()
878
879         def cbStartDone(self, ret):
880                 global DLNA_CONFIG_DEVICE_REFRESH
881                 self.taskManager.clean()
882                 self.toggleGreenButtonTimer.start(1000)
883                 self.deviceListRefreshTimer.start(DLNA_CONFIG_DEVICE_REFRESH)
884
885         def cbToggleGreenButton(self):
886                 self.toggleGreenButtonTimer.stop()
887                 self.updateGUI()
888
889         def cbDeviceListRefresh(self):
890                 global DLNA_CONFIG_DEVICE_REFRESH
891                 self.deviceListRefreshTimer.start(DLNA_CONFIG_DEVICE_REFRESH)
892                 self.keyBlue()
893
894         def setListOnView(slelf):
895                 global DLNA_CONFIG_ROOT_DIR
896                 items,rootdir = [],DLNA_CONFIG_ROOT_DIR
897                 deviceList = [ name for name in os.listdir(rootdir) if os.path.isdir(os.path.join(rootdir, name)) ]
898                 deviceList.sort()
899                 for d in deviceList:
900                         if d[0] in ('.', '_'): continue
901                         items.append((d,d))
902                 return items
903
904 def main(session, **kwargs):
905         session.open(DLNADeviceBrowser)
906                                                            
907 def Plugins(**kwargs):
908         return PluginDescriptor(name=_("DLNA/uPnP Browser"), description="This is dlna/upnp client using djmount.", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main)