do not use a custom attribute for the parent screen but the generic one
[vuplus_dvbapp-plugin] / tageditor / src / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Screen import Screen
3 from Screens.InputBox import InputBox
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.MessageBox import MessageBox
6 from Components.config import config
7 from Components.ActionMap import ActionMap
8 from Components.Button import Button
9 from Components.SelectionList import SelectionList
10 from enigma import eServiceReference, eServiceCenter, iServiceInformation
11 from os import path as os_path
12
13 def main(session, service, **kwargs):
14         session.open(MovieTagEditor, service, session.current_dialog, **kwargs)
15
16 def Plugins(**kwargs):
17         try:
18                 from Screens.MovieSelection import setPreferredTagEditor
19                 setPreferredTagEditor(TagEditor)
20         except:
21                 pass
22         return PluginDescriptor(name = "TagEditor", description = _("Edit tags..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc = main)
23
24 class TagEditor(Screen):
25         skin = """
26         <screen name="TagEditor" title="Edit Tags" position="75,155" size="565,280">
27                 <widget name="list" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
28                 <ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
29                 <ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
30                 <ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
31                 <ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
32                 <widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
33                 <widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
34                 <widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
35                 <widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
36         </screen>"""
37
38         def __init__(self, session, tags, txt = None, args = 0, parent = None):
39                 Screen.__init__(self, session, parent = parent)
40
41                 # Initialize Buttons
42                 self["key_red"] = Button(_("Cancel"))
43                 self["key_green"] = Button(_("OK"))
44                 self["key_yellow"] = Button(_("New"))
45                 self["key_blue"] = Button(_("Load"))
46
47                 self["list"] = SelectionList()
48
49                 allTags = self.loadTagsFile()
50                 self.joinTags(allTags, tags)
51                 self.updateMenuList(allTags, tags)
52
53                 self.ghostlist = tags[:]
54                 self.ghosttags = allTags[:]
55                 self.origtags = allTags[:]
56                 self.tags = allTags
57
58                 # Define Actions
59                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MenuActions"],
60                 {
61                         "ok": self["list"].toggleSelection,
62                         "cancel": self.cancel,
63                         "red": self.cancel,
64                         "green": self.accept,
65                         "yellow": self.addCustom,
66                         "blue": self.loadFromHdd,
67                         "menu": self.showMenu
68                 }, -1)
69
70         def addCustom(self):
71                 self.session.openWithCallback(
72                         self.addCustomCallback,
73                         InputBox,
74                         title = _("Please enter the new tag")
75                 )
76
77         def addCustomCallback(self, ret):
78                 ret = ret and ret.strip().replace(" ","_").capitalize()
79                 tags = self.tags
80                 if ret and ret not in tags:
81                         tags.append(ret)
82                         self.updateMenuList(tags, [ret])
83
84         def loadTagsFile(self):
85                 try:
86                         file = open("/etc/enigma2/movietags")
87                         tags = [x.rstrip() for x in file.readlines()]
88                         while "" in tags:
89                                 tags.remove("")
90                         file.close()
91                 except IOError, ioe:
92                         tags = []
93                 return tags
94
95         def saveTagsFile(self, tags):
96                 try:
97                         file = open("/etc/enigma2/movietags", "w")
98                         file.write("\n".join(tags)+"\n")
99                         file.close()
100                 except IOError, ioe:
101                         pass
102
103         def joinTags(self, taglist, newtags):
104                 for tag in newtags:
105                         if not tag in taglist:
106                                 taglist.append(tag)
107
108         def setTimerTags(self, timer, tags):
109                 if timer.tags != tags:
110                         timer.tags = tags
111                         self.timerdirty = True
112
113         def setMovieTags(self, ref, tags):
114                 file = ref.getPath()
115                 if file.endswith(".ts"):
116                         file = file + ".meta"
117                 else:
118                         file = file + ".ts.meta"
119                 if os_path.exists(file):
120                         metafile = open(file, "r")
121                         sid = metafile.readline()
122                         title = metafile.readline()
123                         descr = metafile.readline()
124                         time = metafile.readline()
125                         oldtags = metafile.readline().rstrip()
126                         metafile.close()
127                         tags = " ".join(tags)
128                         if tags != oldtags:
129                                 metafile = open(file, "w")
130                                 metafile.write("%s%s%s%s%s" %(sid, title, descr, time, tags))
131                                 metafile.close()
132
133         def foreachTimerTags(self, func):
134                 self.timerdirty = False
135                 for timer in self.session.nav.RecordTimer.timer_list + self.session.nav.RecordTimer.processed_timers:
136                         if timer.tags:
137                                 func(timer, timer.tags[:])
138                 if self.timerdirty:
139                         self.session.nav.RecordTimer.saveTimer()
140
141         def foreachMovieTags(self, func):
142                 serviceHandler = eServiceCenter.getInstance()
143                 for dir in config.movielist.videodirs.value:
144                         if os_path.isdir(dir):
145                                 root = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + dir)
146                                 list = serviceHandler.list(root)
147                                 if list is None:
148                                         continue
149                                 while 1:
150                                         serviceref = list.getNext()
151                                         if not serviceref.valid():
152                                                 break
153                                         if (serviceref.flags & eServiceReference.mustDescent):
154                                                 continue
155                                         info = serviceHandler.info(serviceref)
156                                         if info is None:
157                                                 continue
158                                         tags = info.getInfoString(serviceref, iServiceInformation.sTags).split(' ')
159                                         if not tags or tags == ['']:
160                                                 continue
161                                         func(serviceref, tags)
162
163         def updateMenuList(self, tags, extrasel = []):
164                 seltags = [x[1] for x in self["list"].getSelectionsList()] + extrasel
165                 tags.sort()
166                 self["list"].setList([])
167                 for tag in tags:
168                         self["list"].addSelection(tag, tag, 0, tag in seltags)
169
170         def loadFromHdd(self):
171                 tags = self.tags[:]
172                 self.foreachTimerTags(lambda t, tg: self.joinTags(tags, tg))
173                 self.foreachMovieTags(lambda r, tg: self.joinTags(tags, tg))
174                 self.updateMenuList(tags)
175                 self.tags = tags
176
177         def removeUnused(self):
178                 tags = [x[1] for x in self["list"].getSelectionsList()]
179                 self.foreachTimerTags(lambda t, tg: self.joinTags(tags, tg))
180                 self.foreachMovieTags(lambda r, tg: self.joinTags(tags, tg))
181                 self.updateMenuList(tags)
182                 self.tags = tags
183
184         def listReplace(self, lst, fr, to = None):
185                 if fr in lst:
186                         lst.remove(fr)
187                         if to != None and not to in lst:
188                                 lst.append(to)
189                                 lst.sort()
190                 return lst
191
192         def renameTag(self):
193                 self.thistag = self["list"].list[self["list"].getSelectedIndex()][0]
194                 self.session.openWithCallback(
195                         self.renameTagCallback,
196                         InputBox,
197                         title = _("Replace tag \"%s\" everywhere with:   (Note that 'Cancel' will not undo this!)") % (self.thistag[1]),
198                         text = self.thistag[1]
199                 )
200
201         def renameTagCallback(self, res):
202                 res = res and res.strip().replace(" ", "_").capitalize()
203                 if res and len(res) and res != self.thistag[1]:
204                         thistag = self.thistag[1]
205                         self.foreachTimerTags(lambda t, tg: (thistag in tg) and self.setTimerTags(t, self.listReplace(tg, thistag, res)))
206                         self.foreachMovieTags(lambda r, tg: (thistag in tg) and self.setMovieTags(r, self.listReplace(tg, thistag, res)))
207                         self.listReplace(self.tags, thistag, res)
208                         self.listReplace(self.ghosttags, thistag, res)
209                         self.listReplace(self.ghostlist, thistag, res)
210                         self.updateMenuList(self.tags, self.thistag[3] and [res] or [])
211
212         def removeTag(self):
213                 self.thistag = self["list"].list[self["list"].getSelectedIndex()][0]
214                 self.session.openWithCallback(
215                         self.removeTagCallback,
216                         MessageBox,
217                         _("Do you really want to delete tag \"%s\" everywhere?\n(Note that 'Cancel' will not undo this!)") % (self.thistag[1])
218                 )
219
220         def removeTagCallback(self, res):
221                 if res:
222                         thistag = self.thistag[1]
223                         self.foreachTimerTags(lambda t, tg: (thistag in tg) and self.setTimerTags(t, self.listReplace(tg, thistag)))
224                         self.foreachMovieTags(lambda r, tg: (thistag in tg) and self.setMovieTags(r, self.listReplace(tg, thistag)))
225                         self.listReplace(self.tags, thistag)
226                         self.listReplace(self.ghosttags, thistag)
227                         self.listReplace(self.ghostlist, thistag)
228                         self.updateMenuList(self.tags)
229
230         def removeAll(self):
231                 self.session.openWithCallback(
232                         self.removeAllCallback,
233                         MessageBox,
234                         _("Do you really want to delete all tags everywhere?\n(Note that 'Cancel' will not undo this!)")
235                 )
236
237         def removeAllCallback(self, res):
238                 if res:
239                         self.foreachTimerTags(lambda t, tg: tg and self.setTimerTags(t, []))
240                         self.foreachMovieTags(lambda r, tg: tg and self.setMovieTags(r, []))
241                         self.tags = []
242                         self.ghosttags = []
243                         self.ghostlist = []
244                         self.updateMenuList(self.tags)
245
246         def showMenu(self):
247                 menu = [
248                         (_("Add new tag"), self.addCustom),
249                         (_("Rename this tag"), self.renameTag),
250                         (_("Delete this tag"), self.removeTag),
251                         (_("Delete unused tags"), self.removeUnused),
252                         (_("Delete all tags"), self.removeAll)
253                 ]
254                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title = "", list = menu)
255
256         def menuCallback(self, choice):
257                 if choice:
258                         choice[1]()
259
260         def cancel(self):
261                 if not self.origtags == self.ghosttags:
262                         self.saveTagsFile(self.ghosttags)
263                         self.close(self.ghostlist)
264                 else:
265                         self.close(None)
266
267         def accept(self):
268                 list = [x[1] for x in self["list"].getSelectionsList()]
269                 if not self.origtags == self.tags:
270                         self.saveTagsFile(self.tags)
271                 self.close(list)
272
273 class MovieTagEditor(TagEditor):
274         def __init__(self, session, service, parent, args = 0):
275                 self.service = service
276                 serviceHandler = eServiceCenter.getInstance()
277                 info = serviceHandler.info(service)
278                 path = service.getPath()
279                 if path.endswith(".ts"):
280                         path = path[:-3]
281                 self.path = path
282                 tags = info.getInfoString(service, iServiceInformation.sTags)
283                 if tags:
284                         tags = tags.split(' ')
285                 else:
286                         tags = []
287                 TagEditor.__init__(self, session, tags, args, parent = parent)
288
289         def saveTags(self, file, tags):
290                 if os_path.exists(file + ".ts.meta"):
291                         metafile = open(file + ".ts.meta", "r")
292                         sid = metafile.readline()
293                         title = metafile.readline()
294                         descr = metafile.readline()
295                         time = metafile.readline()
296                         oldtags = metafile.readline().rstrip()
297                         metafile.close()
298                         tags = " ".join(tags)
299                         if tags != oldtags:
300                                 metafile = open(file + ".ts.meta", "w")
301                                 metafile.write("%s%s%s%s%s" %(sid, title, descr, time, tags))
302                                 metafile.close()
303
304         def cancel(self):
305                 if not self.origtags == self.ghosttags:
306                         self.saveTagsFile(self.ghosttags)
307                         self.exitDialog()
308                 else:
309                         self.close()
310
311         def accept(self):
312                 list = [x[1] for x in self["list"].getSelectionsList()]
313                 if not self.origtags == self.tags:
314                         self.saveTagsFile(self.tags)
315                 self.saveTags(self.path, list)
316                 self.exitDialog()
317
318         def exitDialog(self):
319                 self.close()
320                 # This will try to get back to an updated movie list.
321                 # A proper way to do this should be provided in enigma2.
322                 try:
323                         parentscreen = self.parent
324                         parentscreen.csel.reloadList()
325                         parentscreen.close()
326                 except AttributeError:
327                         pass
328