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