IMDb: keep search string after manual search
[enigma2-plugins.git] / cdinfo / src / plugin.py
1 from enigma import eServiceReference, eConsoleAppContainer
2 from Components.MediaPlayer import PlayList
3 import xml.dom.minidom
4 from Plugins.Plugin import PluginDescriptor
5 from Components.ActionMap import ActionMap
6 from Components.Sources.StaticText import StaticText
7 from Screens.Screen import Screen
8 from Components.config import config, ConfigSubsection, ConfigInteger, ConfigYesNo, ConfigText, getConfigListEntry
9 from Components.ConfigList import ConfigListScreen
10
11 config.plugins.CDInfo = ConfigSubsection()
12 config.plugins.CDInfo.useCDTEXT = ConfigYesNo(default = True)
13 config.plugins.CDInfo.useCDDB = ConfigYesNo(default = True)
14 config.plugins.CDInfo.displayString = ConfigText("$i - $t ($a)", fixed_size = False)
15 config.plugins.CDInfo.preferCDDB = ConfigYesNo(default = False)
16 config.plugins.CDInfo.CDDB_server = ConfigText("freedb.freedb.org", fixed_size = False)
17 config.plugins.CDInfo.CDDB_port = ConfigInteger(8880,limits = (1, 65536))
18 config.plugins.CDInfo.CDDB_timeout = ConfigInteger(20,limits = (-1, 60))
19 config.plugins.CDInfo.CDDB_cache = ConfigYesNo(default = True)
20
21 class CDInfo(ConfigListScreen,Screen):
22         skin = """
23                 <screen name="CDInfo" position="center,center" size="560,440" title="CDInfo" >
24                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
25                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
26                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
27                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
28                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
29                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
30                         <widget source="info" render="Label" position="5,50" size="550,40" font="Regular;20" backgroundColor="#25062748" transparent="1" />
31                         <widget name="config" position="5,115" size="550,200" scrollbarMode="showOnDemand" />
32                         <ePixmap pixmap="skin_default/div-h.png" position="0,330" zPosition="1" size="560,2" />
33                         <widget source="info2" render="Label" position="5,350" size="520,80" font="Regular;20" backgroundColor="#25062748" transparent="1" />
34                 </screen>
35                 """
36         
37         def __init__(self, session, args = None):
38                 self.skin = CDInfo.skin
39                 Screen.__init__(self, session)
40
41                 self["info"] = StaticText("Gather audio cd album information and track listing from CDDB (online database) and / or CD-Text (from medium).")
42
43                 self["info2"] = StaticText("Playlist string variables: $i=track, $t=title, $a=artist\nCDDB query will not delay start of audio CD playback. The request will be sent asynchronously and playlist text will be updated when match was found.")
44
45                 self.list = []
46                 self.list.append(getConfigListEntry("Try to extract CDTEXT", config.plugins.CDInfo.useCDTEXT))
47                 self.list.append(getConfigListEntry("Try to query CDDB", config.plugins.CDInfo.useCDDB))
48                 self.list.append(getConfigListEntry("Playlist string", config.plugins.CDInfo.displayString))
49                 self.list.append(getConfigListEntry("CDDB overwrites CDTEXT info", config.plugins.CDInfo.preferCDDB))
50                 self.list.append(getConfigListEntry("CDDB server hostname", config.plugins.CDInfo.CDDB_server))
51                 self.list.append(getConfigListEntry("CDDB server port number", config.plugins.CDInfo.CDDB_port))
52                 self.list.append(getConfigListEntry("CDDB retrieval timeout (s)", config.plugins.CDInfo.CDDB_timeout))
53                 self.list.append(getConfigListEntry("store local CDDB cache", config.plugins.CDInfo.CDDB_cache))
54
55                 ConfigListScreen.__init__(self, self.list)
56                 self["key_red"] = StaticText(_("Cancel"))
57                 self["key_green"] = StaticText(_("OK"))
58                 self["key_blue"] = StaticText(_("Defaults"))
59
60                 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
61                 {
62                     "green": self.save,
63                     "red": self.cancel,
64                     "blue": self.defaults,
65                     "save": self.save,
66                     "cancel": self.cancel,
67                     "ok": self.save,
68                 }, -2)
69
70                 self.onLayoutFinish.append(self.layoutFinished)
71
72         def layoutFinished(self):
73                 self.setTitle(_("CDInfo"))
74
75         def save(self):
76                 for x in self["config"].list:
77                         x[1].save()
78                 self.close(True)
79
80         def cancel(self):
81                 for x in self["config"].list:
82                         x[1].cancel()
83                 self.close(False)
84
85         def defaults(self):
86                 config.plugins.CDInfo.useCDTEXT.setValue(True)
87                 config.plugins.CDInfo.useCDDB.setValue(True)
88                 config.plugins.CDInfo.displayString.setValue("$i - $t ($a)")
89                 config.plugins.CDInfo.preferCDDB.setValue(False)
90                 config.plugins.CDInfo.CDDB_server.setValue("freedb.freedb.org")
91                 config.plugins.CDInfo.CDDB_port.setValue(8880)
92                 config.plugins.CDInfo.CDDB_timeout.setValue(20)
93                 config.plugins.CDInfo.CDDB_cache.setValue(True)
94                 for x in self["config"].list:
95                         x[1].save()
96                 self.close(True)
97
98 class Query:
99         def __init__(self, mediaplayer):
100                 self.playlist = mediaplayer.playlist
101                 self.mp = mediaplayer
102                 self.cddb_container = eConsoleAppContainer()
103                 self.cddb_output = ""
104                 self.cdtext_container = eConsoleAppContainer()
105                 self.cdtext_output = ""
106                 self.tracklisting = {}
107                 self.albuminfo = {}
108
109         def getText(self, nodelist):
110                 rc = ""
111                 for node in nodelist:
112                         if node.nodeType == node.TEXT_NODE:
113                                 rc = rc + node.data
114                 return rc.encode("utf-8")
115
116         def xml_parse_output(self,string):
117                 data = string.decode("utf-8","replace").replace('&',"&amp;").encode("ascii",'xmlcharrefreplace')
118                 try:
119                         cdinfodom = xml.dom.minidom.parseString(data)
120                 except:
121                         print "[xml_parse_output] error, could not parse"
122                         return False
123                 xmldata = cdinfodom.childNodes[0]
124                 queries = xmldata.childNodes
125                 self.xml_parse_query(queries)
126                 print "[xml_parse_output] albuminfo: " + str(self.albuminfo)
127                 print "[xml_parse_output] tracklisting: " + str(self.tracklisting)
128                 return True
129
130         def xml_parse_query(self, queries_xml):
131                 for queries in queries_xml:
132                         if queries.nodeType == xml.dom.minidom.Element.nodeType:
133                                 if queries.tagName == 'query':
134                                         print "[xml_parse_query] cdinfo source is %s, hit %s of %s" % (queries.getAttribute("source"),queries.getAttribute("match"),queries.getAttribute("num_matches"))
135                                         for query in queries.childNodes:
136                                                 if query.nodeType == xml.dom.minidom.Element.nodeType:
137                                                         if query.tagName == 'albuminfo':
138                                                                 self.xml_parse_albuminfo(query.childNodes)
139                                                         elif query.tagName == 'tracklisting':
140                                                                 self.xml_parse_tracklisting(query.childNodes)
141
142         def xml_parse_albuminfo(self, albuminfo_xml):
143                 for albuminfo in albuminfo_xml:
144                         if albuminfo.nodeType == xml.dom.minidom.Element.nodeType:
145                                 if albuminfo.tagName == 'PERFORMER' or albuminfo.tagName == 'artist':
146                                         artist = self.getText(albuminfo.childNodes)
147                                         self.albuminfo["artist"] = artist
148                                 elif albuminfo.tagName.upper() == 'TITLE':
149                                         title = self.getText(albuminfo.childNodes)
150                                         self.albuminfo["title"] = title
151                                 elif albuminfo.tagName.upper() == 'YEAR':
152                                         year = self.getText(albuminfo.childNodes)
153                                         self.albuminfo["year"] = year
154                                 elif albuminfo.tagName.upper() == 'GENRE':
155                                         genre = self.getText(albuminfo.childNodes)
156                                         self.albuminfo["genre"] = genre
157                                 elif albuminfo.tagName == 'category' and not "GENRE" in self.albuminfo:
158                                         category = self.getText(albuminfo.childNodes)
159                                         self.albuminfo["genre"] = category
160
161         def xml_parse_tracklisting(self, tracklisting_xml):
162                 for tracklist in tracklisting_xml:
163                         if tracklist.nodeType == xml.dom.minidom.Element.nodeType:
164                                 if tracklist.tagName == 'track':
165                                         index = int(tracklist.getAttribute("number"))
166                                         trackinfo = {}
167                                         for track in tracklist.childNodes:
168                                                 if track.nodeType == xml.dom.minidom.Element.nodeType:
169                                                         if track.tagName == 'PERFORMER' or track.tagName == 'artist':
170                                                                 artist = self.getText(track.childNodes)
171                                                                 trackinfo["artist"] = artist
172                                                         if track.tagName.upper() == 'TITLE':
173                                                                 title = self.getText(track.childNodes)
174                                                                 trackinfo["title"] = title
175                                                         #elif track.tagName == 'length':
176                                                                 #tracktext += "Dauer=%ss " % self.getText(track.childNodes)
177                                         self.tracklisting[index]=trackinfo
178
179         def updateAlbuminfo(self, replace = False):
180                 for tag in self.albuminfo:
181                         if tag not in self.mp.AudioCD_albuminfo or replace:
182                                 self.mp.AudioCD_albuminfo[tag] = self.albuminfo[tag]
183         
184         def updatePlaylist(self, replace = False):
185                 for idx in range(len(self.playlist)):
186                         ref = self.playlist.getServiceRefList()[idx]
187                         track = idx+1
188                         if idx < len(self.tracklisting):
189                                 if replace or not ref.getName():
190                                         trackinfo = self.tracklisting[track]
191                                         displayString = config.plugins.CDInfo.displayString.value.replace("$i", str(track))
192                                         if "title" in trackinfo:
193                                                 displayString = displayString.replace("$t", trackinfo["title"])
194                                         if "artist" in trackinfo:
195                                                 displayString = displayString.replace("$a", trackinfo["artist"])
196                                         ref.setName(displayString)
197                                         self.playlist.updateFile(idx, ref)
198                 self.playlist.updateList()
199
200         def scan(self):
201                 if config.plugins.CDInfo.useCDTEXT.value:
202                     self.cdtext_scan()
203                 if config.plugins.CDInfo.useCDDB.value:
204                     self.cddb_scan()
205
206         def cdtext_scan(self):
207                 cmd = "cdtextinfo -xalT"
208                 print "[cdtext_scan] " + cmd
209                 self.cdtext_appClosed_conn = self.cdtext_container.appClosed.connect(self.cdtext_finished)
210                 self.cdtext_dataAvail_conn = self.cdtext_container.dataAvail.connect(self.cdtext_avail)
211                 self.cdtext_container.execute(cmd)
212
213         def cddb_scan(self):
214                 cmd = "cdtextinfo -xalD --cddb-port=%d --cddb-server=%s --cddb-timeout=%s" % (config.plugins.CDInfo.CDDB_port.value, config.plugins.CDInfo.CDDB_server.value, config.plugins.CDInfo.CDDB_timeout.value)
215                 if not config.plugins.CDInfo.CDDB_cache.value:
216                         cmd += " --no-cddb-cache"
217                 print "[cddb_scan] " + cmd
218                 self.cddb_appClosed_conn = self.cddb_container.appClosed.connect(self.cddb_finished)
219                 self.cddb_dataAvail_conn = self.cddb_container.dataAvail.connect(self.cddb_avail)
220                 self.cddb_container.execute(cmd)
221
222         def cddb_avail(self,string):
223                 self.cddb_output += string
224
225         def cdtext_avail(self,string):
226                 self.cdtext_output += string
227
228         def cddb_finished(self,retval):
229                 self.cddb_container.appClosed.remove(self.cddb_finished)
230                 self.cddb_container.dataAvail.remove(self.cddb_avail)
231                 if not self.xml_parse_output(self.cddb_output):
232                         return
233                 if config.plugins.CDInfo.preferCDDB.value:
234                         self.updatePlaylist(replace = True)
235                         self.updateAlbuminfo(replace = True)
236                 else:
237                         self.updatePlaylist(replace = False)
238                         self.updateAlbuminfo(replace = False)
239                 self.mp.readTitleInformation()
240                 self.cddb_output = ""
241
242         def cdtext_finished(self,retval):
243                 self.cdtext_container.appClosed.remove(self.cdtext_finished)
244                 self.cdtext_container.dataAvail.remove(self.cdtext_avail)
245                 if not self.xml_parse_output(self.cdtext_output):
246                         return
247                 if not config.plugins.CDInfo.preferCDDB.value:
248                         self.updatePlaylist(replace = True)
249                         self.updateAlbuminfo(replace = True)
250                 else:
251                         self.updatePlaylist(replace = False)
252                         self.updateAlbuminfo(replace = False)
253                 self.mp.readTitleInformation()
254                 self.cdtext_output = ""
255
256 def main(session, **kwargs):
257         session.open(CDInfo)
258
259 def Plugins(**kwargs):
260         return [ PluginDescriptor(name="CDInfo", description="AudioCD info from CDDB & CD-Text", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main, icon="plugin.png") ]