1 from enigma import eServiceReference, eConsoleAppContainer
2 from Components.MediaPlayer import PlayList
4 from Plugins.Plugin import PluginDescriptor
5 from Components.ActionMap import ActionMap
6 from Components.Label import Label
7 from Components.Button import Button
8 from Screens.Screen import Screen
9 from Components.config import config, ConfigSubsection, ConfigInteger, ConfigYesNo, ConfigText, getConfigListEntry
10 from Components.ConfigList import ConfigListScreen
12 config.plugins.CDInfo = ConfigSubsection()
13 config.plugins.CDInfo.useCDTEXT = ConfigYesNo(default = True)
14 config.plugins.CDInfo.useCDDB = ConfigYesNo(default = True)
15 config.plugins.CDInfo.displayString = ConfigText("$i - $t ($a)", fixed_size = False)
16 config.plugins.CDInfo.preferCDDB = ConfigYesNo(default = False)
17 config.plugins.CDInfo.CDDB_server = ConfigText("freedb.freedb.org", fixed_size = False)
18 config.plugins.CDInfo.CDDB_port = ConfigInteger(8880,limits = (1, 65536))
19 config.plugins.CDInfo.CDDB_timeout = ConfigInteger(20,limits = (-1, 60))
20 config.plugins.CDInfo.CDDB_cache = ConfigYesNo(default = True)
22 class CDInfo(ConfigListScreen,Screen):
24 <screen position="90,95" size="560,430" title="CDInfo" >
25 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
26 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
27 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
28 <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
29 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
30 <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
31 <widget name="info" position="20,50" size="520,40" font="Regular;20" transparent="1" />
32 <widget name="config" position="20,120" size="520,200" scrollbarMode="showOnDemand" />
33 <widget name="info2" position="20,340" size="520,80" font="Regular;20" transparent="1" />
37 def __init__(self, session, args = None):
38 self.skin = CDInfo.skin
39 Screen.__init__(self, session)
41 self["info"] = Label("Gather audio cd album information and track listing from CDDB (online database) and / or CD-Text (from medium).")
43 self["info2"] = Label("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.")
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))
55 ConfigListScreen.__init__(self, self.list)
56 self["key_red"] = Button(_("cancel"))
57 self["key_green"] = Button(_("ok"))
58 self["key_blue"] = Button(_("defaults"))
60 self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
64 "blue": self.defaults,
66 "cancel": self.cancel,
71 for x in self["config"].list:
76 for x in self["config"].list:
81 config.plugins.CDInfo.useCDTEXT.setValue(True)
82 config.plugins.CDInfo.useCDDB.setValue(True)
83 config.plugins.CDInfo.displayString.setValue("$i - $t ($a)")
84 config.plugins.CDInfo.preferCDDB.setValue(False)
85 config.plugins.CDInfo.CDDB_server.setValue("freedb.freedb.org")
86 config.plugins.CDInfo.CDDB_port.setValue(8880)
87 config.plugins.CDInfo.CDDB_timeout.setValue(20)
88 config.plugins.CDInfo.CDDB_cache.setValue(True)
89 for x in self["config"].list:
94 def __init__(self, mediaplayer):
95 self.playlist = mediaplayer.playlist
97 self.cddb_container = eConsoleAppContainer()
99 self.cdtext_container = eConsoleAppContainer()
100 self.cdtext_output = ""
101 self.tracklisting = {}
104 def getText(self, nodelist):
106 for node in nodelist:
107 if node.nodeType == node.TEXT_NODE:
109 return rc.encode("utf-8")
111 def xml_parse_output(self,string):
112 data = string.decode("utf-8","replace").replace('&',"&").encode("ascii",'xmlcharrefreplace')
114 cdinfodom = xml.dom.minidom.parseString(data)
116 print "[xml_parse_output] error, could not parse"
118 xmldata = cdinfodom.childNodes[0]
119 queries = xmldata.childNodes
120 self.xml_parse_query(queries)
121 print "[xml_parse_output] albuminfo: " + str(self.albuminfo)
122 print "[xml_parse_output] tracklisting: " + str(self.tracklisting)
125 def xml_parse_query(self, queries_xml):
126 for queries in queries_xml:
127 if queries.nodeType == xml.dom.minidom.Element.nodeType:
128 if queries.tagName == 'query':
129 print "[xml_parse_query] cdinfo source is %s, hit %s of %s" % (queries.getAttribute("source"),queries.getAttribute("match"),queries.getAttribute("num_matches"))
130 for query in queries.childNodes:
131 if query.nodeType == xml.dom.minidom.Element.nodeType:
132 if query.tagName == 'albuminfo':
133 self.xml_parse_albuminfo(query.childNodes)
134 elif query.tagName == 'tracklisting':
135 self.xml_parse_tracklisting(query.childNodes)
137 def xml_parse_albuminfo(self, albuminfo_xml):
138 for albuminfo in albuminfo_xml:
139 if albuminfo.nodeType == xml.dom.minidom.Element.nodeType:
140 if albuminfo.tagName == 'PERFORMER' or albuminfo.tagName == 'artist':
141 artist = self.getText(albuminfo.childNodes)
142 self.albuminfo["artist"] = artist
143 elif albuminfo.tagName.upper() == 'TITLE':
144 title = self.getText(albuminfo.childNodes)
145 self.albuminfo["title"] = title
146 elif albuminfo.tagName.upper() == 'YEAR':
147 year = self.getText(albuminfo.childNodes)
148 self.albuminfo["year"] = year
149 elif albuminfo.tagName.upper() == 'GENRE':
150 genre = self.getText(albuminfo.childNodes)
151 self.albuminfo["genre"] = genre
152 elif albuminfo.tagName == 'category' and not "GENRE" in self.albuminfo:
153 category = self.getText(albuminfo.childNodes)
154 self.albuminfo["genre"] = category
156 def xml_parse_tracklisting(self, tracklisting_xml):
157 for tracklist in tracklisting_xml:
158 if tracklist.nodeType == xml.dom.minidom.Element.nodeType:
159 if tracklist.tagName == 'track':
160 index = int(tracklist.getAttribute("number"))
162 for track in tracklist.childNodes:
163 if track.nodeType == xml.dom.minidom.Element.nodeType:
164 if track.tagName == 'PERFORMER' or track.tagName == 'artist':
165 artist = self.getText(track.childNodes)
166 trackinfo["artist"] = artist
167 if track.tagName.upper() == 'TITLE':
168 title = self.getText(track.childNodes)
169 trackinfo["title"] = title
170 #elif track.tagName == 'length':
171 #tracktext += "Dauer=%ss " % self.getText(track.childNodes)
172 self.tracklisting[index]=trackinfo
174 def updateAlbuminfo(self, replace = False):
175 for tag in self.albuminfo:
176 if tag not in self.mp.AudioCD_albuminfo or replace:
177 self.mp.AudioCD_albuminfo[tag] = self.albuminfo[tag]
179 def updatePlaylist(self, replace = False):
180 for idx in range(len(self.playlist)):
181 ref = self.playlist.getServiceRefList()[idx]
183 if idx < len(self.tracklisting):
184 if replace or not ref.getName():
185 trackinfo = self.tracklisting[track]
186 displayString = config.plugins.CDInfo.displayString.value.replace("$i", str(track))
187 if "title" in trackinfo:
188 displayString = displayString.replace("$t", trackinfo["title"])
189 if "artist" in trackinfo:
190 displayString = displayString.replace("$a", trackinfo["artist"])
191 ref.setName(displayString)
192 self.playlist.updateFile(idx, ref)
193 self.playlist.updateList()
196 if config.plugins.CDInfo.useCDTEXT.value:
198 if config.plugins.CDInfo.useCDDB.value:
201 def cdtext_scan(self):
202 cmd = "cdtextinfo -xalT"
203 print "[cdtext_scan] " + cmd
204 self.cdtext_container.appClosed.append(self.cdtext_finished)
205 self.cdtext_container.dataAvail.append(self.cdtext_avail)
206 self.cdtext_container.execute(cmd)
209 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)
210 if not config.plugins.CDInfo.CDDB_cache.value:
211 cmd += " --no-cddb-cache"
212 print "[cddb_scan] " + cmd
213 self.cddb_container.appClosed.append(self.cddb_finished)
214 self.cddb_container.dataAvail.append(self.cddb_avail)
215 self.cddb_container.execute(cmd)
217 def cddb_avail(self,string):
218 self.cddb_output += string
220 def cdtext_avail(self,string):
221 self.cdtext_output += string
223 def cddb_finished(self,retval):
224 self.cddb_container.appClosed.remove(self.cddb_finished)
225 self.cddb_container.dataAvail.remove(self.cddb_avail)
226 if not self.xml_parse_output(self.cddb_output):
228 if config.plugins.CDInfo.preferCDDB.value:
229 self.updatePlaylist(replace = True)
230 self.updateAlbuminfo(replace = True)
232 self.updatePlaylist(replace = False)
233 self.updateAlbuminfo(replace = False)
234 self.mp.readTitleInformation()
235 self.cddb_output = ""
237 def cdtext_finished(self,retval):
238 self.cdtext_container.appClosed.remove(self.cdtext_finished)
239 self.cdtext_container.dataAvail.remove(self.cdtext_avail)
240 if not self.xml_parse_output(self.cdtext_output):
242 if not config.plugins.CDInfo.preferCDDB.value:
243 self.updatePlaylist(replace = True)
244 self.updateAlbuminfo(replace = True)
246 self.updatePlaylist(replace = False)
247 self.updateAlbuminfo(replace = False)
248 self.mp.readTitleInformation()
249 self.cdtext_output = ""
251 def main(session, **kwargs):
254 def Plugins(**kwargs):
255 return [ PluginDescriptor(name="CDInfo", description="AudioCD info from CDDB & CD-Text", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main, icon="plugin.png") ]