Initial revision
authorAnders Holst <aholst@users.schwerkraft.elitedvb.net>
Sun, 20 Jul 2008 18:54:20 +0000 (18:54 +0000)
committerAnders Holst <aholst@users.schwerkraft.elitedvb.net>
Sun, 20 Jul 2008 18:54:20 +0000 (18:54 +0000)
tageditor/CONTROL/control [new file with mode: 0644]
tageditor/Makefile.am [new file with mode: 0644]
tageditor/src/Makefile.am [new file with mode: 0755]
tageditor/src/__init__.py [new file with mode: 0644]
tageditor/src/plugin.py [new file with mode: 0644]

diff --git a/tageditor/CONTROL/control b/tageditor/CONTROL/control
new file mode 100644 (file)
index 0000000..d3fbf5d
--- /dev/null
@@ -0,0 +1,8 @@
+Package: enigma2-plugin-extensions-tageditor
+Version: 1.0-20080717
+Description: Edit tags of movies, and in timers
+Section: extra
+Priority: optional
+Architecture: mipsel
+Maintainer: Anders Holst <aho@sics.se> and Moritz Venn <moritz.venn@freaque.net>
+Depends: enigma2(>2.5cvs20080628)
diff --git a/tageditor/Makefile.am b/tageditor/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/tageditor/src/Makefile.am b/tageditor/src/Makefile.am
new file mode 100755 (executable)
index 0000000..ee42243
--- /dev/null
@@ -0,0 +1,3 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/TagEditor
+
+install_PYTHON = __init__.py plugin.py
diff --git a/tageditor/src/__init__.py b/tageditor/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tageditor/src/plugin.py b/tageditor/src/plugin.py
new file mode 100644 (file)
index 0000000..1eadd5b
--- /dev/null
@@ -0,0 +1,319 @@
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Screens.InputBox import InputBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.MessageBox import MessageBox
+from Components.config import config
+from Components.ActionMap import NumberActionMap
+from Components.Button import Button
+from Components.SelectionList import SelectionList
+from enigma import eServiceReference, eServiceCenter, iServiceInformation
+import os
+
+def main(session, service, **kwargs):
+       session.open(MovieTagEditor, service, **kwargs)
+
+def Plugins(**kwargs):
+       try:
+               from Screens.MovieSelection import setPreferredTagEditor
+               setPreferredTagEditor(TagEditor)
+       except:
+               pass
+       return PluginDescriptor(name="TagEditor", description=_("Edit tags..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
+
+
+class TagEditor(Screen):
+       skin = """
+       <screen name="TagEditor" title="Edit Tags" position="75,155" size="565,280">
+               <widget name="list" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+               <ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+               <ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+               <ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+               <ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+               <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" />
+               <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" />
+               <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" />
+               <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" />
+       </screen>"""
+
+       def __init__(self, session, tags, txt = None, args = 0):
+               Screen.__init__(self, session, args)
+
+               # Initialize Buttons
+               self["key_red"] = Button(_("Cancel"))
+               self["key_green"] = Button(_("OK"))
+               self["key_yellow"] = Button(_("New"))
+               self["key_blue"] = Button(_("Load"))
+
+               self.tags = self.loadTagsFile()
+               self.origtags = self.tags + []
+               self.ghosttags = self.tags + []
+               self.joinTags(self.tags, tags)
+               
+               self["list"] = SelectionList()
+               self.updateMenuList(self.tags, tags)
+
+               # Define Actions
+               self["actions"] = NumberActionMap(["OkCancelActions", "ColorActions", "MenuActions"],
+               {
+                       "ok": self["list"].toggleSelection,
+                       "cancel": self.cancel,
+                       "red": self.cancel,
+                       "green": self.accept,
+                       "yellow": self.addCustom,
+                       "blue": self.loadFromHdd,
+                       "menu": self.showMenu
+               }, -1)
+
+       def addCustom(self):
+               self.session.openWithCallback(
+                       self.addCustomCallback,
+                       InputBox,
+                       title = _("Please enter the new tag")
+               )
+
+       def addCustomCallback(self, ret):
+               ret = ret and ret.strip().replace(" ","_").capitalize()
+               if ret and ret not in self.tags:
+                       self.tags.append(ret)
+                       self.updateMenuList(self.tags, [ret])
+
+       def loadTagsFile(self):
+               try:
+                       file = open("/etc/enigma2/movietags")
+                       tags = [x.rstrip() for x in file.readlines()]
+                       while "" in tags:
+                               tags.remove("")
+                       file.close()
+               except IOError, ioe:
+                       tags = []
+               return tags
+
+       def saveTagsFile(self, tags):
+               try:
+                       file = open("/etc/enigma2/movietags", "w")
+                       file.write("\n".join(tags)+"\n")
+                       file.close()
+               except IOError, ioe:
+                       pass
+
+       def joinTags(self, taglist, newtags):
+               for tag in newtags:
+                       if not tag in taglist:
+                               taglist.append(tag)
+
+       def setTimerTags(self, timer, tags):
+               if timer.tags != tags:
+                       timer.tags = tags
+                       self.timerdirty = True
+
+       def setMovieTags(self, ref, tags):
+               file = ref.getPath()
+               if file.endswith(".ts") is True:
+                       file = file + ".meta"
+               else:
+                       file = file + ".ts.meta"
+               if os.path.exists(file):
+                       metafile = open(file, "r")
+                       sid = metafile.readline()
+                       title = metafile.readline()
+                       descr = metafile.readline()
+                       time = metafile.readline()
+                       oldtags = metafile.readline().rstrip()
+                       metafile.close()
+                       tags = " ".join(tags)
+                       if tags != oldtags:
+                               metafile = open(file, "w")
+                               metafile.write("%s%s%s%s%s" %(sid, title, descr, time, tags))
+                               metafile.close()
+
+       def foreachTimerTags(self, func):
+               self.timerdirty = False
+               for timer in self.session.nav.RecordTimer.timer_list + self.session.nav.RecordTimer.processed_timers:
+                       if timer.tags:
+                               func(timer, timer.tags+[])
+               if self.timerdirty:
+                       self.session.nav.RecordTimer.saveTimer()
+
+       def foreachMovieTags(self, func):
+               serviceHandler = eServiceCenter.getInstance()
+               for dir in config.movielist.videodirs.value:
+                       if os.path.isdir(dir):
+                               root = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + dir)
+                               list = serviceHandler.list(root)
+                               if list is None:
+                                       continue
+                               while 1:
+                                       serviceref = list.getNext()
+                                       if not serviceref.valid():
+                                               break
+                                       if (serviceref.flags & eServiceReference.mustDescent):
+                                               continue
+                                       info = serviceHandler.info(serviceref)
+                                       if info is None:
+                                               continue
+                                       tags = info.getInfoString(serviceref, iServiceInformation.sTags).split(' ')
+                                       if tags == ['']:
+                                               tags = []
+                                       if tags:
+                                               func(serviceref, tags)
+
+       def updateMenuList(self, tags, extrasel = []):
+               seltags = [x[1] for x in self["list"].getSelectionsList()] + extrasel
+               tags.sort()
+               self["list"].setList([])
+               for tag in tags:
+                       self["list"].addSelection(tag, tag, 0, tag in seltags)
+               
+       def loadFromHdd(self):
+               tags = self.tags + []
+               self.foreachTimerTags(lambda t, tg: self.joinTags(tags, tg))
+               self.foreachMovieTags(lambda r, tg: self.joinTags(tags, tg))
+               self.updateMenuList(tags)
+               self.tags = tags
+
+       def removeUnused(self):
+               tags = [x[1] for x in self["list"].getSelectionsList()]
+               self.foreachTimerTags(lambda t, tg: self.joinTags(tags, tg))
+               self.foreachMovieTags(lambda r, tg: self.joinTags(tags, tg))
+               self.updateMenuList(tags)
+               self.tags = tags
+
+       def listReplace(self, lst, fr, to=None):
+               if fr in lst:
+                       lst.remove(fr)
+                       if to != None and not to in lst:
+                               lst.append(to)
+                               lst.sort()
+               return lst
+
+       def renameTag(self):
+               self.thistag = self["list"].list[self["list"].getSelectedIndex()][0]
+               self.session.openWithCallback(
+                       self.renameTagCallback,
+                       InputBox,
+                       title = _("Replace tag \"%s\" everywhere with:   (Note that 'Cancel' will not undo this!)") % (self.thistag[1]),
+                       text = self.thistag[1]
+               )
+
+       def renameTagCallback(self, res):
+               res = res and res.strip().replace(" ", "_").capitalize()
+               if res and len(res) and res != self.thistag[1]:
+                       thistag = self.thistag[1]
+                       self.foreachTimerTags(lambda t, tg: (thistag in tg) and self.setTimerTags(t, self.listReplace(tg, thistag, res)))
+                       self.foreachMovieTags(lambda r, tg: (thistag in tg) and self.setMovieTags(r, self.listReplace(tg, thistag, res)))
+                       self.listReplace(self.tags, thistag, res)
+                       self.listReplace(self.ghosttags, thistag, res)
+                       self.updateMenuList(self.tags, self.thistag[3] and [res] or [])
+
+       def removeTag(self):
+               self.thistag = self["list"].list[self["list"].getSelectedIndex()][0]
+               self.session.openWithCallback(
+                       self.removeTagCallback,
+                       MessageBox,
+                       _("Do you really want to delete tag \"%s\" everywhere?\n(Note that 'Cancel' will not undo this!)") % (self.thistag[1])
+               )
+
+       def removeTagCallback(self, res):
+               if res:
+                       thistag = self.thistag[1]
+                       self.foreachTimerTags(lambda t, tg: (thistag in tg) and self.setTimerTags(t, self.listReplace(tg, thistag)))
+                       self.foreachMovieTags(lambda r, tg: (thistag in tg) and self.setMovieTags(r, self.listReplace(tg, thistag)))
+                       self.listReplace(self.tags, thistag)
+                       self.listReplace(self.ghosttags, thistag)
+                       self.updateMenuList(self.tags)
+
+       def removeAll(self):
+               self.session.openWithCallback(
+                       self.removeAllCallback,
+                       MessageBox,
+                       _("Do you really want to delete all tags everywhere?\n(Note that 'Cancel' will not undo this!)")
+               )
+
+       def removeAllCallback(self, res):
+               if res:
+                       self.foreachTimerTags(lambda t, tg: tg and self.setTimerTags(t, []))
+                       self.foreachMovieTags(lambda r, tg: tg and self.setMovieTags(r, []))
+                       self.tags = []
+                       self.ghosttags = []
+                       self.updateMenuList(self.tags)
+
+       def showMenu(self):
+               menu = []
+               menu.append((_("Add new tag"), self.addCustom))
+               menu.append((_("Rename this tag"), self.renameTag))
+               menu.append((_("Delete this tag"), self.removeTag))
+               menu.append((_("Delete unused tags"), self.removeUnused))
+               menu.append((_("Delete all tags"), self.removeAll))
+               self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
+
+       def menuCallback(self, choice):
+               if choice is None:
+                       return
+               choice[1]()
+
+       def cancel(self):
+               if not self.origtags == self.ghosttags:
+                       self.saveTagsFile(self.ghosttags)
+               self.close(None)
+
+       def accept(self):
+               list = [x[1] for x in self["list"].getSelectionsList()]
+               if not self.origtags == self.tags:
+                       self.saveTagsFile(self.tags)
+               self.close(list)
+
+class MovieTagEditor(TagEditor):
+       def __init__(self, session, service, args = 0):
+               self.service = service
+               serviceHandler = eServiceCenter.getInstance()
+               info = serviceHandler.info(self.service)
+               self.path = self.service.getPath()
+               if self.path.endswith(".ts") is True:
+                       self.path = self.path[:-3]
+               tags = info.getInfoString(self.service, iServiceInformation.sTags)
+               if tags:
+                       self.tags = tags.split(' ')
+               else:
+                       self.tags = []
+               TagEditor.__init__(self, session, self.tags, args)
+#              self.session.openWithCallback(self.tagsConfirmed, TagEditor, self.tags)
+
+       def saveTags(self, file, tags):
+               if os.path.exists(file + ".ts.meta"):
+                       metafile = open(file + ".ts.meta", "r")
+                       sid = metafile.readline()
+                       title = metafile.readline()
+                       descr = metafile.readline()
+                       time = metafile.readline()
+                       oldtags = metafile.readline().rstrip()
+                       metafile.close()
+                       tags = " ".join(tags)
+                       if tags != oldtags:
+                               metafile = open(file + ".ts.meta", "w")
+                               metafile.write("%s%s%s%s%s" %(sid, title, descr, time, tags))
+                               metafile.close()
+
+       def cancel(self):
+               if not self.origtags == self.ghosttags:
+                       self.saveTagsFile(self.ghosttags)
+                       self.exitDialog()
+               else:
+                       self.close()
+
+       def accept(self):
+               list = [x[1] for x in self["list"].getSelectionsList()]
+               if not self.origtags == self.tags:
+                       self.saveTagsFile(self.tags)
+               self.saveTags(self.path, list)
+               self.exitDialog()
+
+       def exitDialog(self):
+               self.close()
+               # This will try to get back to an updated movie list.
+               # A proper way to do this should be provided in enigma2.
+               try:
+                       self.session.current_dialog.csel.reloadList()
+                       self.session.current_dialog.close()
+               except AttributeError:
+                       pass