16 """Various utilities using the musicbrainzngs python bindings to access the MB database"""
18 from optparse
import OptionParser
23 __author__ =
"Paul Harrison'"
24 __title__ =
"Music Brainz utilities"
25 __description__ =
"Various utilities using the musicbrainzngs python bindings to access the MB database"
30 musicbrainzngs.set_useragent(
33 "https://www.mythtv.org",
36 musicbrainzngs.set_hostname(
"musicbrainz.org")
43 """lxml.etree.tostring is a bytes object in python3, and a str in python2.
45 return(etostr.decode())
48 from lxml
import etree
50 root = etree.XML(
u'<searchreleases></searchreleases>')
52 result = musicbrainzngs.search_releases(artist=artist, release=album, country=
"GB", limit=limit)
54 if not result[
'release-list']:
55 etree.SubElement(root,
"error").text =
"No Releases found"
56 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
59 for (idx, release)
in enumerate(result[
'release-list']):
60 pprint.pprint(release)
61 relNode = etree.SubElement(root,
"release")
63 etree.SubElement(relNode,
"id").text = release[
'id']
64 etree.SubElement(relNode,
"ext-score").text = release[
'ext:score']
65 etree.SubElement(relNode,
"title").text = release[
'title']
66 etree.SubElement(relNode,
"artist-credit-phrase").text = release[
"artist-credit-phrase"]
67 etree.SubElement(relNode,
"country").text = release[
"country"]
70 etree.SubElement(relNode,
"date").text = release[
'date']
71 etree.SubElement(relNode,
"status").text = release[
'status']
73 if 'release-group' in release:
74 etree.SubElement(relNode,
"releasegroup").text = release[
"release-group"][
"id"]
76 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
81 from lxml
import etree
83 root = etree.XML(
u'<artists></artists>')
84 result = musicbrainzngs.search_artists(artist=artist, limit=limit)
89 if result[
'artist-list']:
90 for (idx, artist)
in enumerate(result[
'artist-list']):
91 artistNode = etree.SubElement(root,
"id")
92 etree.SubElement(artistNode,
"id").text = artist[
'id']
93 etree.SubElement(artistNode,
"name").text = artist[
'name']
94 etree.SubElement(artistNode,
"sort-name").text = artist[
'sort-name']
96 etree.SubElement(root,
"error").text =
"No Artists found"
97 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
100 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
105 from lxml
import etree
107 root = etree.XML(
u'<artist></artist>')
110 result = musicbrainzngs.get_artist_by_id(artistid, includes=[
'url-rels'])
113 pprint.pprint(result)
116 etree.SubElement(root,
"id").text = result[
'artist'][
'id']
117 etree.SubElement(root,
"name").text = result[
'artist'][
'name']
118 etree.SubElement(root,
"sort-name").text = result[
'artist'][
'sort-name']
120 if 'url-relation-list' in result[
'artist']:
121 urls = result[
'artist'][
'url-relation-list']
123 for (idx, url)
in enumerate(urls):
124 node = etree.SubElement(root,
"url")
125 node.text = url[
'target']
126 node.set(
"type", url[
'type'])
128 etree.SubElement(root,
"error").text =
"MusicBrainz ID was not found"
129 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
132 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
136 from lxml
import etree
138 root = etree.XML(
u'<coverart></coverart>')
141 data = musicbrainzngs.get_image_list(release)
143 if err.cause.code == 404:
144 etree.SubElement(root,
"error").text =
"Release ID not found"
145 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
148 etree.SubElement(root,
"error").text =
"Received bad response from the MB server"
149 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
155 for image
in data[
"images"]:
156 imageNode = etree.SubElement(root,
"image")
157 etree.SubElement(imageNode,
"image").text = image[
"image"]
158 etree.SubElement(imageNode,
"approved").text = str(image[
"approved"])
159 etree.SubElement(imageNode,
"front").text = str(image[
"front"])
160 etree.SubElement(imageNode,
"back").text = str(image[
"back"])
162 etree.SubElement(imageNode,
"thumb-small").text = image[
"thumbnails"][
"small"]
163 etree.SubElement(imageNode,
"thumb-large").text = image[
"thumbnails"][
"large"]
165 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
169 from lxml
import etree
171 root = etree.XML(
u'<coverart></coverart>')
174 data = musicbrainzngs.get_release_group_image_list(releaseGroup)
176 if err.cause.code == 404:
177 etree.SubElement(root,
"error").text =
"Release ID not found"
178 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
181 etree.SubElement(root,
"error").text =
"Received bad response from the MB server"
182 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
188 for image
in data[
"images"]:
189 imageNode = etree.SubElement(root,
"image")
190 etree.SubElement(imageNode,
"image").text = image[
"image"]
191 etree.SubElement(imageNode,
"approved").text = str(image[
"approved"])
192 etree.SubElement(imageNode,
"front").text = str(image[
"front"])
193 etree.SubElement(imageNode,
"back").text = str(image[
"back"])
195 etree.SubElement(imageNode,
"thumb-small").text = image[
"thumbnails"][
"small"]
196 etree.SubElement(imageNode,
"thumb-large").text = image[
"thumbnails"][
"large"]
198 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
203 from lxml
import etree
205 root = etree.XML(
u'<finddisc></finddisc>')
208 disc = discid.read(cddrive, [
"mcn",
"isrc"])
210 toc = disc.toc_string
212 etree.SubElement(root,
"error").text =
"Failed to get discid ({})".format(str(err))
213 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
216 etree.SubElement(root,
"discid").text = id
217 etree.SubElement(root,
"toc").text = toc
221 result = musicbrainzngs.get_releases_by_discid(id, includes=[
"labels"], toc=toc, cdstubs=
False)
223 if err.cause.code == 404:
224 etree.SubElement(root,
"error").text =
"Disc not found"
225 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
228 etree.SubElement(root,
"error").text =
"Received bad response from the MB server"
229 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
233 if result.get(
'disc'):
234 discnode = etree.SubElement(root,
"disc")
236 etree.SubElement(discnode,
"sectors").text = result[
'disc'][
'sectors']
238 if "offset-list" in result[
'disc']:
240 for offset
in result[
'disc'][
'offset-list']:
242 offsets = str(offset)
244 offsets +=
" " + str(offset)
246 etree.SubElement(discnode,
"offsets").text = offsets
247 etree.SubElement(discnode,
"tracks").text = str(result[
'disc'][
'offset-count'])
249 for release
in result[
'disc'][
'release-list']:
250 relnode = etree.SubElement(discnode,
"release")
252 etree.SubElement(relnode,
"title").text = release[
'title']
253 etree.SubElement(relnode,
"musicbrainzid").text = release[
'id']
255 if release.get(
'barcode'):
256 etree.SubElement(relnode,
"barcode").text = release[
'barcode']
257 for info
in release[
'label-info-list']:
258 if info.get(
'catalog-number'):
259 etree.SubElement(relnode,
"catalog-number").text = info[
'catalog-number']
260 elif result.get(
'cdstub'):
261 stubnode = etree.SubElement(root,
"cdstub")
263 etree.SubElement(stubnode,
"artist").text = result[
'cdstub'][
'artist']
264 etree.SubElement(stubnode,
"title").text = result[
'cdstub'][
'title']
266 if result[
'cdstub'].
get(
'barcode'):
267 etree.SubElement(stubnode,
"barcode").text = result[
'cdstub'][
'barcode']
269 etree.SubElement(root,
"error").text =
"No valid results"
270 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
273 log(
True,
convert_etree(etree.tostring(root, encoding=
'UTF-8', pretty_print=
True, xml_declaration=
True)))
277 from lxml
import etree
278 version = etree.XML(
u'<version></version>')
279 etree.SubElement(version,
"name").text = __title__
280 etree.SubElement(version,
"author").text = __author__
281 etree.SubElement(version,
"command").text =
'mbutils.py'
282 etree.SubElement(version,
"description").text = __description__
283 etree.SubElement(version,
"version").text = __version__
285 log(
True,
convert_etree(etree.tostring(version, encoding=
'UTF-8', pretty_print=
True,
286 xml_declaration=
True)))
295 print (
"Failed to import python discid lirary. Is libdiscid installed?")
300 print(
"Failed to import python lxml library.")
303 print(
"Everything appears in order.")
310 parser = OptionParser()
312 parser.add_option(
'-v',
"--version", action=
"store_true", default=
False,
313 dest=
"version", help=
"Display version and author")
314 parser.add_option(
'-t',
"--test", action=
"store_true", default=
False,
315 dest=
"test", help=
"Perform self-test for dependencies.")
316 parser.add_option(
'-r',
"--searchreleases", action=
"store_true", default=
False,
317 dest=
"searchreleases", help=
"Search for musicbrainz release id's for a given artist & album. Requires --artist/--album. Optional --limit.")
318 parser.add_option(
'-s',
"--searchartists", action=
"store_true", default=
False,
319 dest=
"searchartists", help=
"Search for musicbrainz artist id's for a given artist. Requires --artist. Optional --limit.")
320 parser.add_option(
'-g',
"--getartist", action=
"store_true", default=
False,
321 dest=
"getartist", help=
"Lookup the details of a given musicbrainz id of an artist. Requires --id.")
322 parser.add_option(
'-c',
"--finddisc", action=
"store_true", default=
None,
323 dest=
"finddisc", help=
"Find the musicbrainz id for a cd. Requires --cddevice.")
324 parser.add_option(
'-f',
"--findcoverart", action=
"store_true", default=
None,
325 dest=
"findcoverart", help=
"Find coverart for a given musicbrainz id of a release or release group. Requires --id or --relgroupid.")
326 parser.add_option(
'-d',
'--debug', action=
"store_true", default=
False,
327 dest=
"debug", help=(
"Show debug messages"))
328 parser.add_option(
'-a',
'--artist', metavar=
"ARTIST", default=
None,
329 dest=
"artist", help=(
"Name of artist"))
330 parser.add_option(
'-b',
'--album', metavar=
"ALBUM", default=
None,
331 dest=
"album", help=(
"Name of Album"))
332 parser.add_option(
'-l',
'--limit', metavar=
"LIMIT", default=
None,
333 dest=
"limit", help=(
"Limits the maximum number of results to return for some commands (defaults to 5)"))
334 parser.add_option(
'-i',
'--id', metavar=
"ID", default=
None,
335 dest=
"id", help=(
"Music Brainz ID to use"))
336 parser.add_option(
'-I',
'--relgroupid', metavar=
"RELEASEGROUPID", default=
None,
337 dest=
"relgroupid", help=(
"Music Brainz ID of Release Group to use"))
338 parser.add_option(
'-D',
'--cddevice', metavar=
"CDDEVICE", default=
None,
339 dest=
"cddevice", help=(
"CD device to use"))
341 opts, args = parser.parse_args()
352 if opts.searchreleases:
353 if opts.artist
is None:
354 print(
"Missing --artist argument")
357 if opts.album
is None:
358 print(
"Missing --album argument")
363 limit = int(opts.limit)
367 if opts.searchartists:
368 if opts.artist
is None:
369 print(
"Missing --artist argument")
374 limit = int(opts.limit)
380 print(
"Missing --id argument")
386 if opts.cddevice
is None:
387 print(
"Missing --cddevice argument")
392 if opts.findcoverart:
393 if opts.id
is None and opts.relgroupid
is None:
394 print(
"Missing --id or --relgroupid argument")
397 if opts.id
is not None:
404 if __name__ ==
'__main__':