forked from OpenPLi/enigma2
/
MovieSelection.py
2147 lines (1907 loc) · 72.7 KB
/
MovieSelection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
from Screen import Screen
from Components.Button import Button
from Components.ActionMap import HelpableActionMap, ActionMap, NumberActionMap
from Components.ChoiceList import ChoiceList, ChoiceEntryComponent
from Components.MenuList import MenuList
from Components.MovieList import MovieList, resetMoviePlayState, AUDIO_EXTENSIONS, DVD_EXTENSIONS, IMAGE_EXTENSIONS, moviePlayState
from Components.DiskInfo import DiskInfo
from Components.Pixmap import Pixmap, MultiPixmap
from Components.Label import Label
from Components.PluginComponent import plugins
from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigSet, ConfigYesNo, ConfigSelection, getConfigListEntry
from Components.ConfigList import ConfigListScreen
from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
from Components.Sources.ServiceEvent import ServiceEvent
from Components.Sources.StaticText import StaticText
import Components.Harddisk
from Components.UsageConfig import preferredTimerPath
from Plugins.Plugin import PluginDescriptor
from Screens.MessageBox import MessageBox
from Screens.ChoiceBox import ChoiceBox
from Screens.LocationBox import MovieLocationBox
from Screens.HelpMenu import HelpableScreen
from Screens.InputBox import PinInput
import Screens.InfoBar
from Tools import NumericalTextInput
from Tools.Directories import resolveFilename, SCOPE_HDD
from Tools.BoundFunction import boundFunction
import Tools.Trashcan
import NavigationInstance
import RecordTimer
from enigma import eServiceReference, eServiceCenter, eTimer, eSize, iPlayableService, iServiceInformation, getPrevAsciiCode, eRCInput
import os
import time
import cPickle as pickle
config.movielist = ConfigSubsection()
config.movielist.moviesort = ConfigInteger(default=MovieList.SORT_GROUPWISE)
config.movielist.listtype = ConfigInteger(default=MovieList.LISTTYPE_MINIMAL)
config.movielist.description = ConfigInteger(default=MovieList.SHOW_DESCRIPTION)
config.movielist.last_videodir = ConfigText(default=resolveFilename(SCOPE_HDD))
config.movielist.last_timer_videodir = ConfigText(default=resolveFilename(SCOPE_HDD))
config.movielist.videodirs = ConfigLocations(default=[resolveFilename(SCOPE_HDD)])
config.movielist.last_selected_tags = ConfigSet([], default=[])
config.movielist.play_audio_internal = ConfigYesNo(default=True)
config.movielist.settings_per_directory = ConfigYesNo(default=True)
config.movielist.root = ConfigSelection(default="/media", choices=["/","/media","/media/hdd","/media/hdd/movie","/media/usb","/media/usb/movie"])
config.movielist.hide_extensions = ConfigYesNo(default=False)
config.movielist.stop_service = ConfigYesNo(default=True)
userDefinedButtons = None
last_selected_dest = []
preferredTagEditor = None
# this kludge is needed because ConfigSelection only takes numbers
# and someone appears to be fascinated by 'enums'.
l_moviesort = [
(str(MovieList.SORT_GROUPWISE), _("default") , '02/01 & A-Z'),
(str(MovieList.SORT_RECORDED), _("by date"), '03/02/01'),
(str(MovieList.SORT_ALPHANUMERIC), _("alphabetic"), 'A-Z'),
(str(MovieList.SORT_ALPHANUMERIC_FLAT), _("flat alphabetic"), 'A-Z Flat'),
(str(MovieList.SHUFFLE), _("shuffle"), '?'),
(str(MovieList.SORT_RECORDED_REVERSE), _("reverse by date"), '01/02/03'),
(str(MovieList.SORT_ALPHANUMERIC_REVERSE), _("alphabetic reverse"), 'Z-A'),
(str(MovieList.SORT_ALPHANUMERIC_FLAT_REVERSE), _("flat alphabetic reverse"), 'Z-A Flat')]
l_listtype = [(str(MovieList.LISTTYPE_ORIGINAL), _("list style default")),
(str(MovieList.LISTTYPE_COMPACT_DESCRIPTION), _("list style compact with description")),
(str(MovieList.LISTTYPE_COMPACT), _("list style compact")),
(str(MovieList.LISTTYPE_MINIMAL), _("list style single line"))]
try:
from Plugins.Extensions import BlurayPlayer
except Exception as e:
print "[ML] BlurayPlayer not installed:", e
BlurayPlayer = None
def defaultMoviePath():
result = config.usage.default_path.value
if not os.path.isdir(result):
from Tools import Directories
return Directories.defaultRecordingLocation()
return result
def setPreferredTagEditor(te):
global preferredTagEditor
if preferredTagEditor is None:
preferredTagEditor = te
print "Preferred tag editor changed to", preferredTagEditor
else:
print "Preferred tag editor already set to", preferredTagEditor, "ignoring", te
def getPreferredTagEditor():
global preferredTagEditor
return preferredTagEditor
def isTrashFolder(ref):
if not config.usage.movielist_trashcan.value or not ref.flags & eServiceReference.mustDescent:
return False
path = os.path.realpath(ref.getPath())
return path.endswith('.Trash') and path.startswith(Tools.Trashcan.getTrashFolder(path))
def isInTrashFolder(ref):
if not config.usage.movielist_trashcan.value or not ref.flags & eServiceReference.mustDescent:
return False
path = os.path.realpath(ref.getPath())
return path.startswith(Tools.Trashcan.getTrashFolder(path))
def isSimpleFile(item):
if not item:
return False
if not item[0] or not item[1]:
return False
return (item[0].flags & eServiceReference.mustDescent) == 0
def isFolder(item):
if not item:
return False
if not item[0] or not item[1]:
return False
return (item[0].flags & eServiceReference.mustDescent) != 0
def canMove(item):
if not item:
return False
if not item[0] or not item[1]:
return False
if item[0].flags & eServiceReference.mustDescent:
return not isTrashFolder(item[0])
return True
canDelete = canMove
def canCopy(item):
if not item:
return False
if not item[0] or not item[1]:
return False
if item[0].flags & eServiceReference.mustDescent:
return False
return True
def createMoveList(serviceref, dest):
#normpath is to remove the trailing '/' from directories
src = isinstance(serviceref, str) and serviceref + ".ts" or os.path.normpath(serviceref.getPath())
srcPath, srcName = os.path.split(src)
if os.path.normpath(srcPath) == dest:
# move file to itself is allowed, so we have to check it
raise Exception, "Refusing to move to the same directory"
# Make a list of items to move
moveList = [(src, os.path.join(dest, srcName))]
if isinstance(serviceref, str) or not serviceref.flags & eServiceReference.mustDescent:
# Real movie, add extra files...
srcBase = os.path.splitext(src)[0]
baseName = os.path.split(srcBase)[1]
eitName = srcBase + '.eit'
if os.path.exists(eitName):
moveList.append((eitName, os.path.join(dest, baseName+'.eit')))
baseName = os.path.split(src)[1]
for ext in ('.ap', '.cuts', '.meta', '.sc'):
candidate = src + ext
if os.path.exists(candidate):
moveList.append((candidate, os.path.join(dest, baseName+ext)))
return moveList
def moveServiceFiles(serviceref, dest, name=None, allowCopy=True):
moveList = createMoveList(serviceref, dest)
# Try to "atomically" move these files
movedList = []
try:
try:
for item in moveList:
os.rename(item[0], item[1])
movedList.append(item)
except OSError, e:
if e.errno == 18 and allowCopy:
print "[MovieSelection] cannot rename across devices, trying slow move"
import CopyFiles
# start with the smaller files, do the big one later.
moveList.reverse()
if name is None:
name = os.path.split(moveList[-1][0])[1]
CopyFiles.moveFiles(moveList, name)
print "[MovieSelection] Moving in background..."
else:
raise
except Exception, e:
print "[MovieSelection] Failed move:", e
for item in movedList:
try:
os.rename(item[1], item[0])
except:
print "[MovieSelection] Failed to undo move:", item
# rethrow exception
raise
def copyServiceFiles(serviceref, dest, name=None):
# current should be 'ref' type, dest a simple path string
moveList = createMoveList(serviceref, dest)
# Try to "atomically" move these files
movedList = []
try:
for item in moveList:
os.link(item[0], item[1])
movedList.append(item)
# this worked, we're done
return
except Exception, e:
print "[MovieSelection] Failed copy using link:", e
for item in movedList:
try:
os.unlink(item[1])
except:
print "[MovieSelection] Failed to undo copy:", item
#Link failed, really copy.
import CopyFiles
# start with the smaller files, do the big one later.
moveList.reverse()
if name is None:
name = os.path.split(moveList[-1][0])[1]
CopyFiles.copyFiles(moveList, name)
print "[MovieSelection] Copying in background..."
# Appends possible destinations to the bookmarks object. Appends tuples
# in the form (description, path) to it.
def buildMovieLocationList(bookmarks):
inlist = []
for d in config.movielist.videodirs.value:
d = os.path.normpath(d)
bookmarks.append((d,d))
inlist.append(d)
for p in Components.Harddisk.harddiskmanager.getMountedPartitions():
d = os.path.normpath(p.mountpoint)
if d in inlist:
# improve shortcuts to mountpoints
try:
bookmarks[bookmarks.index((d,d))] = (p.tabbedDescription(), d)
except:
pass # When already listed as some "friendly" name
else:
bookmarks.append((p.tabbedDescription(), d))
inlist.append(d)
class MovieBrowserConfiguration(ConfigListScreen,Screen):
skin = """
<screen position="center,center" size="560,400" title="Movie Browser Configuration" >
<ePixmap name="red" position="0,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
<ePixmap name="green" position="140,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
<widget name="key_red" position="0,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
<widget name="key_green" position="140,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
<widget name="config" position="10,40" size="540,340" scrollbarMode="showOnDemand" />
<ePixmap alphatest="on" pixmap="skin_default/icons/clock.png" position="480,383" size="14,14" zPosition="3"/>
<widget font="Regular;18" halign="left" position="505,380" render="Label" size="55,20" source="global.CurrentTime" transparent="1" valign="center" zPosition="3">
<convert type="ClockToText">Default</convert>
</widget>
</screen>"""
def __init__(self, session, args = 0):
self.session = session
self.setup_title = _("Movie list configuration")
Screen.__init__(self, session)
cfg = ConfigSubsection()
self.cfg = cfg
cfg.moviesort = ConfigSelection(default=str(config.movielist.moviesort.value), choices = l_moviesort)
cfg.listtype = ConfigSelection(default=str(config.movielist.listtype.value), choices = l_listtype)
cfg.description = ConfigYesNo(default=(config.movielist.description.value != MovieList.HIDE_DESCRIPTION))
configList = [
getConfigListEntry(_("Sort"), cfg.moviesort),
getConfigListEntry(_("Show extended description"), cfg.description),
getConfigListEntry(_("Type"), cfg.listtype),
getConfigListEntry(_("Use individual settings for each directory"), config.movielist.settings_per_directory),
getConfigListEntry(_("Allow quit movieplayer with exit"), config.usage.leave_movieplayer_onExit),
getConfigListEntry(_("Behavior when a movie reaches the end"), config.usage.on_movie_eof),
getConfigListEntry(_("Stop service on return to movie list"), config.movielist.stop_service),
getConfigListEntry(_("Load length of movies in movie list"), config.usage.load_length_of_movies_in_moviellist),
getConfigListEntry(_("Show status icons in movie list"), config.usage.show_icons_in_movielist),
getConfigListEntry(_("Show icon for new/unseen items"), config.usage.movielist_unseen),
getConfigListEntry(_("Play audio in background"), config.movielist.play_audio_internal),
getConfigListEntry(_("Root directory"), config.movielist.root),
getConfigListEntry(_("Hide known extensions"), config.movielist.hide_extensions),
]
for btn in ('red', 'green', 'yellow', 'blue', 'TV', 'Radio', 'Text', 'F1', 'F2', 'F3'):
configList.append(getConfigListEntry(_(btn), userDefinedButtons[btn]))
ConfigListScreen.__init__(self, configList, session=session, on_change = self.changedEntry)
self["key_red"] = Button(_("Cancel"))
self["key_green"] = Button(_("Ok"))
self["setupActions"] = ActionMap(["SetupActions", "ColorActions", "MenuActions"],
{
"red": self.cancel,
"green": self.save,
"save": self.save,
"cancel": self.cancel,
"ok": self.save,
"menu": self.cancel,
}, -2)
self.onChangedEntry = []
self.onLayoutFinish.append(self.layoutFinished)
def layoutFinished(self):
self.setTitle(self.setup_title)
# for summary:
def changedEntry(self):
for x in self.onChangedEntry:
x()
def getCurrentEntry(self):
return self["config"].getCurrent()[0]
def getCurrentValue(self):
return str(self["config"].getCurrent()[1].getText())
def createSummary(self):
from Screens.Setup import SetupSummary
return SetupSummary
def save(self):
self.saveAll()
cfg = self.cfg
config.movielist.moviesort.value = int(cfg.moviesort.value)
config.movielist.listtype.value = int(cfg.listtype.value)
if cfg.description.value:
config.movielist.description.value = MovieList.SHOW_DESCRIPTION
else:
config.movielist.description.value = MovieList.HIDE_DESCRIPTION
if not config.movielist.settings_per_directory.value:
config.movielist.moviesort.save()
config.movielist.listtype.save()
config.movielist.description.save()
config.usage.on_movie_eof.save()
self.close(True)
def cancel(self):
if self["config"].isChanged():
self.session.openWithCallback(self.cancelCallback, MessageBox, _("Really close without saving settings?"))
else:
self.cancelCallback(True)
def cancelCallback(self, answer):
if answer:
for x in self["config"].list:
x[1].cancel()
self.close(False)
class MovieContextMenuSummary(Screen):
def __init__(self, session, parent):
Screen.__init__(self, session, parent = parent)
self["selected"] = StaticText("")
self.onShow.append(self.__onShow)
self.onHide.append(self.__onHide)
def __onShow(self):
self.parent["menu"].onSelectionChanged.append(self.selectionChanged)
self.selectionChanged()
def __onHide(self):
self.parent["menu"].onSelectionChanged.remove(self.selectionChanged)
def selectionChanged(self):
item = self.parent["menu"].getCurrent()
self["selected"].text = item[0][0]
from Screens.ParentalControlSetup import ProtectedScreen
class MovieContextMenu(Screen, ProtectedScreen):
# Contract: On OK returns a callable object (e.g. delete)
def __init__(self, session, csel, service):
Screen.__init__(self, session)
self.csel = csel
ProtectedScreen.__init__(self)
self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "NumberActions", "MenuActions"],
{
"ok": self.okbuttonClick,
"cancel": self.cancelClick,
"yellow": self.do_showNetworkSetup,
"menu": self.do_configure,
"1": self.do_unhideParentalServices,
"2": self.do_rename,
"5": self.do_copy,
"6": self.do_move,
"7": self.do_createdir,
"8": self.do_delete
})
def append_to_menu(menu, args, key=""):
menu.append(ChoiceEntryComponent(key, args))
menu = []
if service:
if (service.flags & eServiceReference.mustDescent) and isTrashFolder(service):
append_to_menu(menu, (_("Permanently remove all deleted items"), csel.purgeAll), key="8")
else:
append_to_menu(menu, (_("Delete"), csel.do_delete), key="8")
append_to_menu(menu, (_("Move"), csel.do_move), key="6")
append_to_menu(menu, (_("Rename"), csel.do_rename), key="2")
if not (service.flags & eServiceReference.mustDescent):
append_to_menu(menu, (_("Copy"), csel.do_copy), key="5")
if self.isResetable():
append_to_menu(menu, (_("Reset playback position"), csel.do_reset))
if service.getPath().endswith('.ts'):
append_to_menu(menu, (_("Start offline decode"), csel.do_decode))
elif BlurayPlayer is None and csel.isBlurayFolderAndFile(service):
append_to_menu(menu, (_("Auto play blu-ray file"), csel.playBlurayFile))
if config.ParentalControl.hideBlacklist.value and config.ParentalControl.storeservicepin.value != "never":
from Components.ParentalControl import parentalControl
if not parentalControl.sessionPinCached:
append_to_menu(menu, (_("Unhide parental control services"), csel.unhideParentalServices), key="1")
# Plugins expect a valid selection, so only include them if we selected a non-dir
if not(service.flags & eServiceReference.mustDescent):
for p in plugins.getPlugins(PluginDescriptor.WHERE_MOVIELIST):
append_to_menu( menu, (p.description, boundFunction(p, session, service)), key="bullet")
if csel.exist_bookmark():
append_to_menu(menu, (_("Remove bookmark"), csel.do_addbookmark))
else:
append_to_menu(menu, (_("Add bookmark"), csel.do_addbookmark))
append_to_menu(menu, (_("create directory"), csel.do_createdir), key="7")
append_to_menu(menu, (_("Sort by") + "...", csel.selectSortby))
append_to_menu(menu, (_("Network") + "...", csel.showNetworkSetup), key="yellow")
append_to_menu(menu, (_("Settings") + "...", csel.configure), key="menu")
self["menu"] = ChoiceList(menu)
def isProtected(self):
return self.csel.protectContextMenu and config.ParentalControl.setuppinactive.value and config.ParentalControl.config_sections.context_menus.value
def isResetable(self):
item = self.csel.getCurrentSelection()
return not(item[1] and moviePlayState(item[0].getPath() + ".cuts", item[0], item[1].getLength(item[0])) is None)
def pinEntered(self, answer):
if answer:
self.csel.protectContextMenu = False
ProtectedScreen.pinEntered(self, answer)
def createSummary(self):
return MovieContextMenuSummary
def okbuttonClick(self):
self.close(self["menu"].getCurrent()[0][1])
def do_rename(self):
self.close(self.csel.do_rename())
def do_copy(self):
self.close(self.csel.do_copy())
def do_move(self):
self.close(self.csel.do_move())
def do_createdir(self):
self.close(self.csel.do_createdir())
def do_delete(self):
self.close(self.csel.do_delete())
def do_unhideParentalServices(self):
self.close(self.csel.unhideParentalServices())
def do_configure(self):
self.close(self.csel.configure())
def do_showNetworkSetup(self):
self.close(self.csel.showNetworkSetup())
def cancelClick(self):
self.close(None)
class SelectionEventInfo:
def __init__(self):
self["Service"] = ServiceEvent()
self.list.connectSelChanged(self.__selectionChanged)
self.timer = eTimer()
self.timer.callback.append(self.updateEventInfo)
self.onShown.append(self.__selectionChanged)
def __selectionChanged(self):
if self.execing and self.settings["description"] == MovieList.SHOW_DESCRIPTION:
self.timer.start(100, True)
def updateEventInfo(self):
serviceref = self.getCurrent()
self["Service"].newService(serviceref)
class MovieSelectionSummary(Screen):
# Kludgy component to display current selection on LCD. Should use
# parent.Service as source for everything, but that seems to have a
# performance impact as the MovieSelection goes through hoops to prevent
# this when the info is not selected
def __init__(self, session, parent):
Screen.__init__(self, session, parent = parent)
self["name"] = StaticText("")
self.onShow.append(self.__onShow)
self.onHide.append(self.__onHide)
def __onShow(self):
self.parent.list.connectSelChanged(self.selectionChanged)
self.selectionChanged()
def __onHide(self):
self.parent.list.disconnectSelChanged(self.selectionChanged)
def selectionChanged(self):
item = self.parent.getCurrentSelection()
if item and item[0]:
data = item[3]
if (data is not None) and (data != -1):
name = data.txt
elif not item[1]:
# special case, one up
name = ".."
else:
name = item[1].getName(item[0])
if (item[0].flags & eServiceReference.mustDescent):
if len(name) > 12:
name = os.path.split(os.path.normpath(name))[1]
name = "> " + name
self["name"].text = name
else:
self["name"].text = ""
class MovieSelection(Screen, HelpableScreen, SelectionEventInfo, InfoBarBase, ProtectedScreen):
# SUSPEND_PAUSES actually means "please call my pauseService()"
ALLOW_SUSPEND = Screen.SUSPEND_PAUSES
def __init__(self, session, selectedmovie = None, timeshiftEnabled = False):
Screen.__init__(self, session)
HelpableScreen.__init__(self)
if not timeshiftEnabled:
InfoBarBase.__init__(self) # For ServiceEventTracker
ProtectedScreen.__init__(self)
self.protectContextMenu = True
self.initUserDefinedActions()
self.tags = {}
if selectedmovie:
self.selected_tags = config.movielist.last_selected_tags.value
else:
self.selected_tags = None
self.selected_tags_ele = None
self.nextInBackground = None
self.movemode = False
self.bouquet_mark_edit = False
self.feedbackTimer = None
self.pathselectEnabled = False
self.numericalTextInput = NumericalTextInput.NumericalTextInput(mapping=NumericalTextInput.MAP_SEARCH_UPCASE)
self["chosenletter"] = Label("")
self["chosenletter"].visible = False
self["waitingtext"] = Label(_("Please wait... Loading list..."))
# create optional description border and hide immediately
self["DescriptionBorder"] = Pixmap()
self["DescriptionBorder"].hide()
if config.ParentalControl.servicepinactive.value:
from Components.ParentalControl import parentalControl
if not parentalControl.sessionPinCached and config.movielist.last_videodir.value and [x for x in config.movielist.last_videodir.value[1:].split("/") if x.startswith(".") and not x.startswith(".Trash")]:
config.movielist.last_videodir.value = ""
if not os.path.isdir(config.movielist.last_videodir.value):
config.movielist.last_videodir.value = defaultMoviePath()
config.movielist.last_videodir.save()
self.setCurrentRef(config.movielist.last_videodir.value)
self.settings = {\
"listtype": config.movielist.listtype.value,
"moviesort": config.movielist.moviesort.value,
"description": config.movielist.description.value,
"movieoff": config.usage.on_movie_eof.value
}
self.movieOff = self.settings["movieoff"]
self["list"] = MovieList(None, list_type=self.settings["listtype"], sort_type=self.settings["moviesort"], descr_state=self.settings["description"])
self.loadLocalSettings()
self.list = self["list"]
self.selectedmovie = selectedmovie
self.playGoTo = None #1 - preview next item / -1 - preview previous
title = _("Movie selection")
self.setTitle(title)
# Need list for init
SelectionEventInfo.__init__(self)
self["key_red"] = Button("")
self["key_green"] = Button("")
self["key_yellow"] = Button("")
self["key_blue"] = Button("")
self._updateButtonTexts()
self["movie_off"] = MultiPixmap()
self["movie_off"].hide()
self["movie_sort"] = MultiPixmap()
self["movie_sort"].hide()
self["freeDiskSpace"] = self.diskinfo = DiskInfo(config.movielist.last_videodir.value, DiskInfo.FREE, update=False)
self["InfobarActions"] = HelpableActionMap(self, "InfobarActions",
{
"showRadio": (self.btn_radio, boundFunction(self.getinitUserDefinedActionsDescription, "btn_radio")),
"showTv": (self.btn_tv, boundFunction(self.getinitUserDefinedActionsDescription, "btn_tv")),
"showText": (self.btn_text, boundFunction(self.getinitUserDefinedActionsDescription, "btn_text")),
})
self["NumberActions"] = NumberActionMap(["NumberActions", "InputAsciiActions"],
{
"gotAsciiCode": self.keyAsciiCode,
"0": self.keyNumberGlobal,
"1": self.keyNumberGlobal,
"2": self.keyNumberGlobal,
"3": self.keyNumberGlobal,
"4": self.keyNumberGlobal,
"5": self.keyNumberGlobal,
"6": self.keyNumberGlobal,
"7": self.keyNumberGlobal,
"8": self.keyNumberGlobal,
"9": self.keyNumberGlobal
})
self["playbackActions"] = HelpableActionMap(self, "MoviePlayerActions",
{
"leavePlayer": (self.playbackStop, _("Stop")),
"moveNext": (self.playNext, _("Play next")),
"movePrev": (self.playPrev, _("Play previous")),
"channelUp": (self.moveToFirstOrFirstFile, _("Go to first movie or top of list")),
"channelDown": (self.moveToLastOrFirstFile, _("Go to first movie or last item")),
})
self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
{
"contextMenu": (self.doContext, _("Menu")),
"showEventInfo": (self.showEventInformation, _("Show event details")),
"selectMovie": (self.itemSelected, _("Select movie")),
"showMovies": (self.doPathSelect, _("Select the movie path")),
})
self["ColorActions"] = HelpableActionMap(self, "ColorActions",
{
"red": (self.btn_red, boundFunction(self.getinitUserDefinedActionsDescription, "btn_red")),
"green": (self.btn_green, boundFunction(self.getinitUserDefinedActionsDescription, "btn_green")),
"yellow": (self.btn_yellow, boundFunction(self.getinitUserDefinedActionsDescription, "btn_yellow")),
"blue": (self.btn_blue, boundFunction(self.getinitUserDefinedActionsDescription, "btn_blue")),
})
self["FunctionKeyActions"] = HelpableActionMap(self, "FunctionKeyActions",
{
"f1": (self.btn_F1, boundFunction(self.getinitUserDefinedActionsDescription, "btn_F1")),
"f2": (self.btn_F2, boundFunction(self.getinitUserDefinedActionsDescription, "btn_F2")),
"f3": (self.btn_F3, boundFunction(self.getinitUserDefinedActionsDescription, "btn_F3")),
})
self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
{
"cancel": (self.abort, _("Exit movie list")),
"ok": (self.itemSelected, _("Select movie")),
})
self["DirectionActions"] = HelpableActionMap(self, "DirectionActions",
{
"up": (self.keyUp, _("Go up the list")),
"down": (self.keyDown, _("Go down the list"))
}, prio = -2)
tPreview = _("Preview")
tFwd = _("skip forward") + " (" + tPreview +")"
tBack= _("skip backward") + " (" + tPreview +")"
sfwd = lambda: self.seekRelative(1, config.seek.selfdefined_46.value * 90000)
ssfwd = lambda: self.seekRelative(1, config.seek.selfdefined_79.value * 90000)
sback = lambda: self.seekRelative(-1, config.seek.selfdefined_46.value * 90000)
ssback = lambda: self.seekRelative(-1, config.seek.selfdefined_79.value * 90000)
self["SeekActions"] = HelpableActionMap(self, "InfobarSeekActions",
{
"playpauseService": (self.preview, _("Preview")),
"seekFwd": (sfwd, tFwd),
"seekFwdManual": (ssfwd, tFwd),
"seekBack": (sback, tBack),
"seekBackManual": (ssback, tBack),
}, prio=5)
self.onShown.append(self.onFirstTimeShown)
self.onLayoutFinish.append(self.saveListsize)
self.list.connectSelChanged(self.updateButtons)
self.onClose.append(self.__onClose)
NavigationInstance.instance.RecordTimer.on_state_change.append(self.list.updateRecordings)
self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
{
#iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
iPlayableService.evStart: self.__serviceStarted,
iPlayableService.evEOF: self.__evEOF,
#iPlayableService.evSOF: self.__evSOF,
})
self.onExecBegin.append(self.asciiOn)
config.misc.standbyCounter.addNotifier(self.standbyCountChanged, initial_call=False)
def isProtected(self):
return config.ParentalControl.setuppinactive.value and config.ParentalControl.config_sections.movie_list.value
def standbyCountChanged(self, value):
path = self.getTitle().split(" /", 1)
if path and len(path) > 1:
if [x for x in path[1].split("/") if x.startswith(".") and not x.startswith(".Trash")]:
moviepath = defaultMoviePath()
if moviepath:
config.movielist.last_videodir.value = defaultMoviePath()
self.close(None)
def unhideParentalServices(self):
if self.protectContextMenu:
self.session.openWithCallback(self.unhideParentalServicesCallback, PinInput, pinList=[config.ParentalControl.servicepin[0].value], triesEntry=config.ParentalControl.retries.servicepin, title=_("Enter the service pin"), windowTitle=_("Enter pin code"))
else:
self.unhideParentalServicesCallback(True)
def unhideParentalServicesCallback(self, answer):
if answer:
from Components.ParentalControl import parentalControl
parentalControl.setSessionPinCached()
parentalControl.hideBlacklist()
self.reloadList()
elif answer is not None:
self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
def asciiOn(self):
rcinput = eRCInput.getInstance()
rcinput.setKeyboardMode(rcinput.kmAscii)
def asciiOff(self):
rcinput = eRCInput.getInstance()
rcinput.setKeyboardMode(rcinput.kmNone)
def initUserDefinedActions(self):
global userDefinedButtons, userDefinedActions, config
if userDefinedButtons is None:
userDefinedActions = {
'delete': _("Delete"),
'move': _("Move"),
'copy': _("Copy"),
'reset': _("Reset"),
'tags': _("Tags"),
'addbookmark': _("Add bookmark"),
'bookmarks': _("Location"),
'rename': _("Rename"),
'gohome': _("Home"),
'sort': _("Sort"),
'sortby': _("Sort by"),
'listtype': _("List type"),
'preview': _("Preview"),
'movieoff': _("On end of movie"),
'movieoff_menu': _("On end of movie (as menu)")
}
for p in plugins.getPlugins(PluginDescriptor.WHERE_MOVIELIST):
userDefinedActions['@' + p.name] = p.description
locations = []
buildMovieLocationList(locations)
prefix = _("Goto") + ": "
for d,p in locations:
if p and p.startswith('/'):
userDefinedActions[p] = prefix + d
config.movielist.btn_red = ConfigSelection(default='delete', choices=userDefinedActions)
config.movielist.btn_green = ConfigSelection(default='move', choices=userDefinedActions)
config.movielist.btn_yellow = ConfigSelection(default='bookmarks', choices=userDefinedActions)
config.movielist.btn_blue = ConfigSelection(default='sort', choices=userDefinedActions)
config.movielist.btn_radio = ConfigSelection(default='tags', choices=userDefinedActions)
config.movielist.btn_tv = ConfigSelection(default='gohome', choices=userDefinedActions)
config.movielist.btn_text = ConfigSelection(default='movieoff', choices=userDefinedActions)
config.movielist.btn_F1 = ConfigSelection(default='movieoff_menu', choices=userDefinedActions)
config.movielist.btn_F2 = ConfigSelection(default='preview', choices=userDefinedActions)
config.movielist.btn_F3 = ConfigSelection(default='/media', choices=userDefinedActions)
userDefinedButtons ={
'red': config.movielist.btn_red,
'green': config.movielist.btn_green,
'yellow': config.movielist.btn_yellow,
'blue': config.movielist.btn_blue,
'Radio': config.movielist.btn_radio,
'TV': config.movielist.btn_tv,
'Text': config.movielist.btn_text,
'F1': config.movielist.btn_F1,
'F2': config.movielist.btn_F2,
'F3': config.movielist.btn_F3
}
def getinitUserDefinedActionsDescription(self, key):
return _(userDefinedActions.get(eval("config.movielist." + key + ".value"), _("Not Defined")))
def _callButton(self, name):
if name.startswith('@'):
item = self.getCurrentSelection()
if isSimpleFile(item):
name = name[1:]
for p in plugins.getPlugins(PluginDescriptor.WHERE_MOVIELIST):
if name == p.name:
p(self.session, item[0])
elif name.startswith('/'):
self.gotFilename(name)
else:
try:
a = getattr(self, 'do_' + name)
except Exception:
# Undefined action
return
a()
def btn_red(self):
self._callButton(config.movielist.btn_red.value)
def btn_green(self):
self._callButton(config.movielist.btn_green.value)
def btn_yellow(self):
self._callButton(config.movielist.btn_yellow.value)
def btn_blue(self):
self._callButton(config.movielist.btn_blue.value)
def btn_radio(self):
self._callButton(config.movielist.btn_radio.value)
def btn_tv(self):
self._callButton(config.movielist.btn_tv.value)
def btn_text(self):
self._callButton(config.movielist.btn_text.value)
def btn_F1(self):
self._callButton(config.movielist.btn_F1.value)
def btn_F2(self):
self._callButton(config.movielist.btn_F2.value)
def btn_F3(self):
self._callButton(config.movielist.btn_F3.value)
def keyUp(self):
if self["list"].getCurrentIndex() < 1:
self["list"].moveToLast()
else:
self["list"].moveUp()
def keyDown(self):
if self["list"].getCurrentIndex() == len(self["list"]) - 1:
self["list"].moveToFirst()
else:
self["list"].moveDown()
def moveToFirstOrFirstFile(self):
if self.list.getCurrentIndex() <= self.list.firstFileEntry: #selection above or on first movie
if self.list.getCurrentIndex() < 1:
self.list.moveToLast()
else:
self.list.moveToFirst()
else:
self.list.moveToFirstMovie()
def moveToLastOrFirstFile(self):
if self.list.getCurrentIndex() >= self.list.firstFileEntry or self.list.firstFileEntry == len(self.list): #selection below or on first movie or no files
if self.list.getCurrentIndex() == len(self.list) - 1:
self.list.moveToFirst()
else:
self.list.moveToLast()
else:
self.list.moveToFirstMovie()
def keyNumberGlobal(self, number):
unichar = self.numericalTextInput.getKey(number)
charstr = unichar.encode("utf-8")
if len(charstr) == 1:
self.list.moveToChar(charstr[0], self["chosenletter"])
def keyAsciiCode(self):
unichar = unichr(getPrevAsciiCode())
charstr = unichar.encode("utf-8")
if len(charstr) == 1:
self.list.moveToString(charstr[0], self["chosenletter"])
def isItemPlayable(self, index):
item = self.list.getItem(index)
if item:
path = item.getPath()
if not item.flags & eServiceReference.mustDescent:
ext = os.path.splitext(path)[1].lower()
if ext in IMAGE_EXTENSIONS:
return False
else:
return True
return False
def goToPlayingService(self):
service = self.session.nav.getCurrentlyPlayingServiceOrGroup()
if service:
path = service.getPath()
if path:
path = os.path.split(os.path.normpath(path))[0]
if not path.endswith('/'):
path += '/'
self.gotFilename(path, selItem = service)
return True
return False
def playNext(self):
if self.list.playInBackground:
if self.list.moveTo(self.list.playInBackground):
if self.isItemPlayable(self.list.getCurrentIndex() + 1):
self.list.moveDown()
self.callLater(self.preview)
else:
self.playGoTo = 1
self.goToPlayingService()
else:
self.preview()
def playPrev(self):
if self.list.playInBackground:
if self.list.moveTo(self.list.playInBackground):
if self.isItemPlayable(self.list.getCurrentIndex() - 1):
self.list.moveUp()
self.callLater(self.preview)
else:
self.playGoTo = -1
self.goToPlayingService()
def __onClose(self):
config.misc.standbyCounter.removeNotifier(self.standbyCountChanged)
try:
NavigationInstance.instance.RecordTimer.on_state_change.remove(self.list.updateRecordings)
except Exception, e:
print "[ML] failed to unsubscribe:", e
pass
def createSummary(self):
return MovieSelectionSummary
def updateDescription(self):
if self.settings["description"] == MovieList.SHOW_DESCRIPTION:
self["DescriptionBorder"].show()
self["list"].instance.resize(eSize(self.listWidth, self.listHeight-self["DescriptionBorder"].instance.size().height()))
else:
self["Service"].newService(None)
self["DescriptionBorder"].hide()
self["list"].instance.resize(eSize(self.listWidth, self.listHeight))
def pauseService(self):
# Called when pressing Power button (go to standby)
self.playbackStop()
self.session.nav.stopService()
def unPauseService(self):
# When returning from standby. It might have been a while, so
# reload the list.
self.reloadList()
def can_delete(self, item):
if not item:
return False
return canDelete(item) or isTrashFolder(item[0])
def can_move(self, item):
return canMove(item)
def can_default(self, item):
# returns whether item is a regular file
return isSimpleFile(item)
def can_sort(self, item):
return True
def can_listtype(self, item):
return True
def can_preview(self, item):
return isSimpleFile(item)
def _updateButtonTexts(self):
for k in ('red', 'green', 'yellow', 'blue'):
btn = userDefinedButtons[k]
self['key_' + k].setText(userDefinedActions[btn.value])
def updateButtons(self):
item = self.getCurrentSelection()
for name in ('red', 'green', 'yellow', 'blue'):
action = userDefinedButtons[name].value
if action.startswith('@'):
check = self.can_default
elif action.startswith('/'):
check = self.can_gohome
else:
try:
check = getattr(self, 'can_' + action)
except:
check = self.can_default
gui = self["key_" + name]
if check(item):
gui.show()
else: