Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First Commit

  • Loading branch information...
commit 5fb5e3db4af671c15c6f56094acca1fe4c08bb96 0 parents
Matt De Young authored
14 addon.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addon id="script.module.musicbrainz2"
+ name="musicbrainz2"
+ version="0.7.3"
+ provider-name="Matthias Friedrich">
+ <requires>
+ <import addon="xbmc.python" version="1.0"/>
+ </requires>
+ <extension point="xbmc.python.module"
+ library="lib" />
+ <extension point="xbmc.addon.metadata">
+ <platform>all</platform>
+ </extension>
+</addon>
26 lib/LICENSE.txt
@@ -0,0 +1,26 @@
+Copyright (c) 2006, Matthias Friedrich
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the MusicBrainz project nor the names of the
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 lib/musicbrainz2/__init__.py
@@ -0,0 +1,26 @@
+"""A collection of classes for MusicBrainz.
+
+To get started quickly, have a look at L{webservice.Query} and the examples
+there. The source distribution also contains example code you might find
+interesting.
+
+This package contains the following modules:
+
+ 1. L{model}: The MusicBrainz domain model, containing classes like
+ L{Artist <model.Artist>}, L{Release <model.Release>}, or
+ L{Track <model.Track>}
+
+ 2. L{webservice}: An interface to the MusicBrainz XML web service.
+
+ 3. L{wsxml}: A parser for the web service XML format (MMD).
+
+ 4. L{disc}: Functions for creating and submitting DiscIDs.
+
+ 5. L{utils}: Utilities for working with URIs and other commonly needed tools.
+
+@author: Matthias Friedrich <matt@mafr.de>
+"""
+__revision__ = '$Id: __init__.py 12974 2011-05-01 08:43:54Z luks $'
+__version__ = '0.7.3'
+
+# EOF
10 lib/musicbrainz2/data/__init__.py
@@ -0,0 +1,10 @@
+"""Support data for the musicbrainz2 package.
+
+This package is I{not} part of the public API, it has been added to work
+around shortcomings in python and may thus be removed at any time.
+
+Please use the L{musicbrainz2.utils} module instead.
+"""
+__revision__ = '$Id: __init__.py 7386 2006-04-30 11:12:55Z matt $'
+
+# EOF
253 lib/musicbrainz2/data/countrynames.py
@@ -0,0 +1,253 @@
+# -*- coding: utf-8 -*-
+
+__revision__ = '$Id: countrynames.py 7386 2006-04-30 11:12:55Z matt $'
+
+countryNames = {
+ u'BD': u'Bangladesh',
+ u'BE': u'Belgium',
+ u'BF': u'Burkina Faso',
+ u'BG': u'Bulgaria',
+ u'BB': u'Barbados',
+ u'WF': u'Wallis and Futuna Islands',
+ u'BM': u'Bermuda',
+ u'BN': u'Brunei Darussalam',
+ u'BO': u'Bolivia',
+ u'BH': u'Bahrain',
+ u'BI': u'Burundi',
+ u'BJ': u'Benin',
+ u'BT': u'Bhutan',
+ u'JM': u'Jamaica',
+ u'BV': u'Bouvet Island',
+ u'BW': u'Botswana',
+ u'WS': u'Samoa',
+ u'BR': u'Brazil',
+ u'BS': u'Bahamas',
+ u'BY': u'Belarus',
+ u'BZ': u'Belize',
+ u'RU': u'Russian Federation',
+ u'RW': u'Rwanda',
+ u'RE': u'Reunion',
+ u'TM': u'Turkmenistan',
+ u'TJ': u'Tajikistan',
+ u'RO': u'Romania',
+ u'TK': u'Tokelau',
+ u'GW': u'Guinea-Bissau',
+ u'GU': u'Guam',
+ u'GT': u'Guatemala',
+ u'GR': u'Greece',
+ u'GQ': u'Equatorial Guinea',
+ u'GP': u'Guadeloupe',
+ u'JP': u'Japan',
+ u'GY': u'Guyana',
+ u'GF': u'French Guiana',
+ u'GE': u'Georgia',
+ u'GD': u'Grenada',
+ u'GB': u'United Kingdom',
+ u'GA': u'Gabon',
+ u'SV': u'El Salvador',
+ u'GN': u'Guinea',
+ u'GM': u'Gambia',
+ u'GL': u'Greenland',
+ u'GI': u'Gibraltar',
+ u'GH': u'Ghana',
+ u'OM': u'Oman',
+ u'TN': u'Tunisia',
+ u'JO': u'Jordan',
+ u'HT': u'Haiti',
+ u'HU': u'Hungary',
+ u'HK': u'Hong Kong',
+ u'HN': u'Honduras',
+ u'HM': u'Heard and Mc Donald Islands',
+ u'VE': u'Venezuela',
+ u'PR': u'Puerto Rico',
+ u'PW': u'Palau',
+ u'PT': u'Portugal',
+ u'SJ': u'Svalbard and Jan Mayen Islands',
+ u'PY': u'Paraguay',
+ u'IQ': u'Iraq',
+ u'PA': u'Panama',
+ u'PF': u'French Polynesia',
+ u'PG': u'Papua New Guinea',
+ u'PE': u'Peru',
+ u'PK': u'Pakistan',
+ u'PH': u'Philippines',
+ u'PN': u'Pitcairn',
+ u'PL': u'Poland',
+ u'PM': u'St. Pierre and Miquelon',
+ u'ZM': u'Zambia',
+ u'EH': u'Western Sahara',
+ u'EE': u'Estonia',
+ u'EG': u'Egypt',
+ u'ZA': u'South Africa',
+ u'EC': u'Ecuador',
+ u'IT': u'Italy',
+ u'VN': u'Viet Nam',
+ u'SB': u'Solomon Islands',
+ u'ET': u'Ethiopia',
+ u'SO': u'Somalia',
+ u'ZW': u'Zimbabwe',
+ u'SA': u'Saudi Arabia',
+ u'ES': u'Spain',
+ u'ER': u'Eritrea',
+ u'MD': u'Moldova, Republic of',
+ u'MG': u'Madagascar',
+ u'MA': u'Morocco',
+ u'MC': u'Monaco',
+ u'UZ': u'Uzbekistan',
+ u'MM': u'Myanmar',
+ u'ML': u'Mali',
+ u'MO': u'Macau',
+ u'MN': u'Mongolia',
+ u'MH': u'Marshall Islands',
+ u'MK': u'Macedonia, The Former Yugoslav Republic of',
+ u'MU': u'Mauritius',
+ u'MT': u'Malta',
+ u'MW': u'Malawi',
+ u'MV': u'Maldives',
+ u'MQ': u'Martinique',
+ u'MP': u'Northern Mariana Islands',
+ u'MS': u'Montserrat',
+ u'MR': u'Mauritania',
+ u'UG': u'Uganda',
+ u'MY': u'Malaysia',
+ u'MX': u'Mexico',
+ u'IL': u'Israel',
+ u'FR': u'France',
+ u'IO': u'British Indian Ocean Territory',
+ u'SH': u'St. Helena',
+ u'FI': u'Finland',
+ u'FJ': u'Fiji',
+ u'FK': u'Falkland Islands (Malvinas)',
+ u'FM': u'Micronesia, Federated States of',
+ u'FO': u'Faroe Islands',
+ u'NI': u'Nicaragua',
+ u'NL': u'Netherlands',
+ u'NO': u'Norway',
+ u'NA': u'Namibia',
+ u'VU': u'Vanuatu',
+ u'NC': u'New Caledonia',
+ u'NE': u'Niger',
+ u'NF': u'Norfolk Island',
+ u'NG': u'Nigeria',
+ u'NZ': u'New Zealand',
+ u'ZR': u'Zaire',
+ u'NP': u'Nepal',
+ u'NR': u'Nauru',
+ u'NU': u'Niue',
+ u'CK': u'Cook Islands',
+ u'CI': u'Cote d\'Ivoire',
+ u'CH': u'Switzerland',
+ u'CO': u'Colombia',
+ u'CN': u'China',
+ u'CM': u'Cameroon',
+ u'CL': u'Chile',
+ u'CC': u'Cocos (Keeling) Islands',
+ u'CA': u'Canada',
+ u'CG': u'Congo',
+ u'CF': u'Central African Republic',
+ u'CZ': u'Czech Republic',
+ u'CY': u'Cyprus',
+ u'CX': u'Christmas Island',
+ u'CR': u'Costa Rica',
+ u'CV': u'Cape Verde',
+ u'CU': u'Cuba',
+ u'SZ': u'Swaziland',
+ u'SY': u'Syrian Arab Republic',
+ u'KG': u'Kyrgyzstan',
+ u'KE': u'Kenya',
+ u'SR': u'Suriname',
+ u'KI': u'Kiribati',
+ u'KH': u'Cambodia',
+ u'KN': u'Saint Kitts and Nevis',
+ u'KM': u'Comoros',
+ u'ST': u'Sao Tome and Principe',
+ u'SI': u'Slovenia',
+ u'KW': u'Kuwait',
+ u'SN': u'Senegal',
+ u'SM': u'San Marino',
+ u'SL': u'Sierra Leone',
+ u'SC': u'Seychelles',
+ u'KZ': u'Kazakhstan',
+ u'KY': u'Cayman Islands',
+ u'SG': u'Singapore',
+ u'SE': u'Sweden',
+ u'SD': u'Sudan',
+ u'DO': u'Dominican Republic',
+ u'DM': u'Dominica',
+ u'DJ': u'Djibouti',
+ u'DK': u'Denmark',
+ u'VG': u'Virgin Islands (British)',
+ u'DE': u'Germany',
+ u'YE': u'Yemen',
+ u'DZ': u'Algeria',
+ u'US': u'United States',
+ u'UY': u'Uruguay',
+ u'YT': u'Mayotte',
+ u'UM': u'United States Minor Outlying Islands',
+ u'LB': u'Lebanon',
+ u'LC': u'Saint Lucia',
+ u'LA': u'Lao People\'s Democratic Republic',
+ u'TV': u'Tuvalu',
+ u'TW': u'Taiwan',
+ u'TT': u'Trinidad and Tobago',
+ u'TR': u'Turkey',
+ u'LK': u'Sri Lanka',
+ u'LI': u'Liechtenstein',
+ u'LV': u'Latvia',
+ u'TO': u'Tonga',
+ u'LT': u'Lithuania',
+ u'LU': u'Luxembourg',
+ u'LR': u'Liberia',
+ u'LS': u'Lesotho',
+ u'TH': u'Thailand',
+ u'TF': u'French Southern Territories',
+ u'TG': u'Togo',
+ u'TD': u'Chad',
+ u'TC': u'Turks and Caicos Islands',
+ u'LY': u'Libyan Arab Jamahiriya',
+ u'VA': u'Vatican City State (Holy See)',
+ u'VC': u'Saint Vincent and The Grenadines',
+ u'AE': u'United Arab Emirates',
+ u'AD': u'Andorra',
+ u'AG': u'Antigua and Barbuda',
+ u'AF': u'Afghanistan',
+ u'AI': u'Anguilla',
+ u'VI': u'Virgin Islands (U.S.)',
+ u'IS': u'Iceland',
+ u'IR': u'Iran (Islamic Republic of)',
+ u'AM': u'Armenia',
+ u'AL': u'Albania',
+ u'AO': u'Angola',
+ u'AN': u'Netherlands Antilles',
+ u'AQ': u'Antarctica',
+ u'AS': u'American Samoa',
+ u'AR': u'Argentina',
+ u'AU': u'Australia',
+ u'AT': u'Austria',
+ u'AW': u'Aruba',
+ u'IN': u'India',
+ u'TZ': u'Tanzania, United Republic of',
+ u'AZ': u'Azerbaijan',
+ u'IE': u'Ireland',
+ u'ID': u'Indonesia',
+ u'UA': u'Ukraine',
+ u'QA': u'Qatar',
+ u'MZ': u'Mozambique',
+ u'BA': u'Bosnia and Herzegovina',
+ u'CD': u'Congo, The Democratic Republic of the',
+ u'CS': u'Serbia and Montenegro',
+ u'HR': u'Croatia',
+ u'KP': u'Korea (North), Democratic People\'s Republic of',
+ u'KR': u'Korea (South), Republic of',
+ u'SK': u'Slovakia',
+ u'SU': u'Soviet Union (historical, 1922-1991)',
+ u'TL': u'East Timor',
+ u'XC': u'Czechoslovakia (historical, 1918-1992)',
+ u'XE': u'Europe',
+ u'XG': u'East Germany (historical, 1949-1990)',
+ u'XU': u'[Unknown Country]',
+ u'XW': u'[Worldwide]',
+ u'YU': u'Yugoslavia (historical, 1918-1992)',
+}
+
+# EOF
400 lib/musicbrainz2/data/languagenames.py
@@ -0,0 +1,400 @@
+# -*- coding: utf-8 -*-
+
+__revision__ = '$Id: languagenames.py 8725 2006-12-17 22:39:07Z luks $'
+
+languageNames = {
+ u'ART': u'Artificial (Other)',
+ u'ROH': u'Raeto-Romance',
+ u'SCO': u'Scots',
+ u'SCN': u'Sicilian',
+ u'ROM': u'Romany',
+ u'RON': u'Romanian',
+ u'OSS': u'Ossetian; Ossetic',
+ u'ALE': u'Aleut',
+ u'MNI': u'Manipuri',
+ u'NWC': u'Classical Newari; Old Newari; Classical Nepal Bhasa',
+ u'OSA': u'Osage',
+ u'MNC': u'Manchu',
+ u'MWR': u'Marwari',
+ u'VEN': u'Venda',
+ u'MWL': u'Mirandese',
+ u'FAS': u'Persian',
+ u'FAT': u'Fanti',
+ u'FAN': u'Fang',
+ u'FAO': u'Faroese',
+ u'DIN': u'Dinka',
+ u'HYE': u'Armenian',
+ u'DSB': u'Lower Sorbian',
+ u'CAR': u'Carib',
+ u'DIV': u'Divehi',
+ u'TEL': u'Telugu',
+ u'TEM': u'Timne',
+ u'NBL': u'Ndebele, South; South Ndebele',
+ u'TER': u'Tereno',
+ u'TET': u'Tetum',
+ u'SUN': u'Sundanese',
+ u'KUT': u'Kutenai',
+ u'SUK': u'Sukuma',
+ u'KUR': u'Kurdish',
+ u'KUM': u'Kumyk',
+ u'SUS': u'Susu',
+ u'NEW': u'Newari; Nepal Bhasa',
+ u'KUA': u'Kuanyama; Kwanyama',
+ u'MEN': u'Mende',
+ u'LEZ': u'Lezghian',
+ u'GLA': u'Gaelic; Scottish Gaelic',
+ u'BOS': u'Bosnian',
+ u'GLE': u'Irish',
+ u'EKA': u'Ekajuk',
+ u'GLG': u'Gallegan',
+ u'AKA': u'Akan',
+ u'BOD': u'Tibetan',
+ u'GLV': u'Manx',
+ u'JRB': u'Judeo-Arabic',
+ u'VIE': u'Vietnamese',
+ u'IPK': u'Inupiaq',
+ u'UZB': u'Uzbek',
+ u'BRE': u'Breton',
+ u'BRA': u'Braj',
+ u'AYM': u'Aymara',
+ u'CHA': u'Chamorro',
+ u'CHB': u'Chibcha',
+ u'CHE': u'Chechen',
+ u'CHG': u'Chagatai',
+ u'CHK': u'Chuukese',
+ u'CHM': u'Mari',
+ u'CHN': u'Chinook jargon',
+ u'CHO': u'Choctaw',
+ u'CHP': u'Chipewyan',
+ u'CHR': u'Cherokee',
+ u'CHU': u'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic',
+ u'CHV': u'Chuvash',
+ u'CHY': u'Cheyenne',
+ u'MSA': u'Malay',
+ u'III': u'Sichuan Yi',
+ u'ACE': u'Achinese',
+ u'IBO': u'Igbo',
+ u'IBA': u'Iban',
+ u'XHO': u'Xhosa',
+ u'DEU': u'German',
+ u'CAT': u'Catalan; Valencian',
+ u'DEL': u'Delaware',
+ u'DEN': u'Slave (Athapascan)',
+ u'CAD': u'Caddo',
+ u'TAT': u'Tatar',
+ u'RAJ': u'Rajasthani',
+ u'SPA': u'Spanish; Castilian',
+ u'TAM': u'Tamil',
+ u'TAH': u'Tahitian',
+ u'AFH': u'Afrihili',
+ u'ENG': u'English',
+ u'CSB': u'Kashubian',
+ u'NYN': u'Nyankole',
+ u'NYO': u'Nyoro',
+ u'SID': u'Sidamo',
+ u'NYA': u'Chichewa; Chewa; Nyanja',
+ u'SIN': u'Sinhala; Sinhalese',
+ u'AFR': u'Afrikaans',
+ u'LAM': u'Lamba',
+ u'SND': u'Sindhi',
+ u'MAR': u'Marathi',
+ u'LAH': u'Lahnda',
+ u'NYM': u'Nyamwezi',
+ u'SNA': u'Shona',
+ u'LAD': u'Ladino',
+ u'SNK': u'Soninke',
+ u'MAD': u'Madurese',
+ u'MAG': u'Magahi',
+ u'MAI': u'Maithili',
+ u'MAH': u'Marshallese',
+ u'LAV': u'Latvian',
+ u'MAL': u'Malayalam',
+ u'MAN': u'Mandingo',
+ u'ZND': u'Zande',
+ u'ZEN': u'Zenaga',
+ u'KBD': u'Kabardian',
+ u'ITA': u'Italian',
+ u'VAI': u'Vai',
+ u'TSN': u'Tswana',
+ u'TSO': u'Tsonga',
+ u'TSI': u'Tsimshian',
+ u'BYN': u'Blin; Bilin',
+ u'FIJ': u'Fijian',
+ u'FIN': u'Finnish',
+ u'EUS': u'Basque',
+ u'CEB': u'Cebuano',
+ u'DAN': u'Danish',
+ u'NOG': u'Nogai',
+ u'NOB': u'Norwegian Bokmål; Bokmål, Norwegian',
+ u'DAK': u'Dakota',
+ u'CES': u'Czech',
+ u'DAR': u'Dargwa',
+ u'DAY': u'Dayak',
+ u'NOR': u'Norwegian',
+ u'KPE': u'Kpelle',
+ u'GUJ': u'Gujarati',
+ u'MDF': u'Moksha',
+ u'MAS': u'Masai',
+ u'LAO': u'Lao',
+ u'MDR': u'Mandar',
+ u'GON': u'Gondi',
+ u'SMS': u'Skolt Sami',
+ u'SMO': u'Samoan',
+ u'SMN': u'Inari Sami',
+ u'SMJ': u'Lule Sami',
+ u'GOT': u'Gothic',
+ u'SME': u'Northern Sami',
+ u'BLA': u'Siksika',
+ u'SMA': u'Southern Sami',
+ u'GOR': u'Gorontalo',
+ u'AST': u'Asturian; Bable',
+ u'ORM': u'Oromo',
+ u'QUE': u'Quechua',
+ u'ORI': u'Oriya',
+ u'CRH': u'Crimean Tatar; Crimean Turkish',
+ u'ASM': u'Assamese',
+ u'PUS': u'Pushto',
+ u'DGR': u'Dogrib',
+ u'LTZ': u'Luxembourgish; Letzeburgesch',
+ u'NDO': u'Ndonga',
+ u'GEZ': u'Geez',
+ u'ISL': u'Icelandic',
+ u'LAT': u'Latin',
+ u'MAK': u'Makasar',
+ u'ZAP': u'Zapotec',
+ u'YID': u'Yiddish',
+ u'KOK': u'Konkani',
+ u'KOM': u'Komi',
+ u'KON': u'Kongo',
+ u'UKR': u'Ukrainian',
+ u'TON': u'Tonga (Tonga Islands)',
+ u'KOS': u'Kosraean',
+ u'KOR': u'Korean',
+ u'TOG': u'Tonga (Nyasa)',
+ u'HUN': u'Hungarian',
+ u'HUP': u'Hupa',
+ u'CYM': u'Welsh',
+ u'UDM': u'Udmurt',
+ u'BEJ': u'Beja',
+ u'BEN': u'Bengali',
+ u'BEL': u'Belarusian',
+ u'BEM': u'Bemba',
+ u'AAR': u'Afar',
+ u'NZI': u'Nzima',
+ u'SAH': u'Yakut',
+ u'SAN': u'Sanskrit',
+ u'SAM': u'Samaritan Aramaic',
+ u'SAG': u'Sango',
+ u'SAD': u'Sandawe',
+ u'RAR': u'Rarotongan',
+ u'RAP': u'Rapanui',
+ u'SAS': u'Sasak',
+ u'SAT': u'Santali',
+ u'MIN': u'Minangkabau',
+ u'LIM': u'Limburgan; Limburger; Limburgish',
+ u'LIN': u'Lingala',
+ u'LIT': u'Lithuanian',
+ u'EFI': u'Efik',
+ u'BTK': u'Batak (Indonesia)',
+ u'KAC': u'Kachin',
+ u'KAB': u'Kabyle',
+ u'KAA': u'Kara-Kalpak',
+ u'KAN': u'Kannada',
+ u'KAM': u'Kamba',
+ u'KAL': u'Kalaallisut; Greenlandic',
+ u'KAS': u'Kashmiri',
+ u'KAR': u'Karen',
+ u'KAU': u'Kanuri',
+ u'KAT': u'Georgian',
+ u'KAZ': u'Kazakh',
+ u'TYV': u'Tuvinian',
+ u'AWA': u'Awadhi',
+ u'URD': u'Urdu',
+ u'DOI': u'Dogri',
+ u'TPI': u'Tok Pisin',
+ u'MRI': u'Maori',
+ u'ABK': u'Abkhazian',
+ u'TKL': u'Tokelau',
+ u'NLD': u'Dutch; Flemish',
+ u'OJI': u'Ojibwa',
+ u'OCI': u'Occitan (post 1500); Provençal',
+ u'WOL': u'Wolof',
+ u'JAV': u'Javanese',
+ u'HRV': u'Croatian',
+ u'DYU': u'Dyula',
+ u'SSW': u'Swati',
+ u'MUL': u'Multiple languages',
+ u'HIL': u'Hiligaynon',
+ u'HIM': u'Himachali',
+ u'HIN': u'Hindi',
+ u'BAS': u'Basa',
+ u'GBA': u'Gbaya',
+ u'WLN': u'Walloon',
+ u'BAD': u'Banda',
+ u'NEP': u'Nepali',
+ u'CRE': u'Cree',
+ u'BAN': u'Balinese',
+ u'BAL': u'Baluchi',
+ u'BAM': u'Bambara',
+ u'BAK': u'Bashkir',
+ u'SHN': u'Shan',
+ u'ARP': u'Arapaho',
+ u'ARW': u'Arawak',
+ u'ARA': u'Arabic',
+ u'ARC': u'Aramaic',
+ u'ARG': u'Aragonese',
+ u'SEL': u'Selkup',
+ u'ARN': u'Araucanian',
+ u'LUS': u'Lushai',
+ u'MUS': u'Creek',
+ u'LUA': u'Luba-Lulua',
+ u'LUB': u'Luba-Katanga',
+ u'LUG': u'Ganda',
+ u'LUI': u'Luiseno',
+ u'LUN': u'Lunda',
+ u'LUO': u'Luo (Kenya and Tanzania)',
+ u'IKU': u'Inuktitut',
+ u'TUR': u'Turkish',
+ u'TUK': u'Turkmen',
+ u'TUM': u'Tumbuka',
+ u'COP': u'Coptic',
+ u'COS': u'Corsican',
+ u'COR': u'Cornish',
+ u'ILO': u'Iloko',
+ u'GWI': u'Gwich´in',
+ u'TLI': u'Tlingit',
+ u'TLH': u'Klingon; tlhIngan-Hol',
+ u'POR': u'Portuguese',
+ u'PON': u'Pohnpeian',
+ u'POL': u'Polish',
+ u'TGK': u'Tajik',
+ u'TGL': u'Tagalog',
+ u'FRA': u'French',
+ u'BHO': u'Bhojpuri',
+ u'SWA': u'Swahili',
+ u'DUA': u'Duala',
+ u'SWE': u'Swedish',
+ u'YAP': u'Yapese',
+ u'TIV': u'Tiv',
+ u'YAO': u'Yao',
+ u'XAL': u'Kalmyk',
+ u'FRY': u'Frisian',
+ u'GAY': u'Gayo',
+ u'OTA': u'Turkish, Ottoman (1500-1928)',
+ u'HMN': u'Hmong',
+ u'HMO': u'Hiri Motu',
+ u'GAA': u'Ga',
+ u'FUR': u'Friulian',
+ u'MLG': u'Malagasy',
+ u'SLV': u'Slovenian',
+ u'FIL': u'Filipino; Pilipino',
+ u'MLT': u'Maltese',
+ u'SLK': u'Slovak',
+ u'FUL': u'Fulah',
+ u'JPN': u'Japanese',
+ u'VOL': u'Volapük',
+ u'VOT': u'Votic',
+ u'IND': u'Indonesian',
+ u'AVE': u'Avestan',
+ u'JPR': u'Judeo-Persian',
+ u'AVA': u'Avaric',
+ u'PAP': u'Papiamento',
+ u'EWO': u'Ewondo',
+ u'PAU': u'Palauan',
+ u'EWE': u'Ewe',
+ u'PAG': u'Pangasinan',
+ u'PAM': u'Pampanga',
+ u'PAN': u'Panjabi; Punjabi',
+ u'KIR': u'Kirghiz',
+ u'NIA': u'Nias',
+ u'KIK': u'Kikuyu; Gikuyu',
+ u'SYR': u'Syriac',
+ u'KIN': u'Kinyarwanda',
+ u'NIU': u'Niuean',
+ u'EPO': u'Esperanto',
+ u'JBO': u'Lojban',
+ u'MIC': u'Mi\'kmaq; Micmac',
+ u'THA': u'Thai',
+ u'HAI': u'Haida',
+ u'ELL': u'Greek, Modern (1453-)',
+ u'ADY': u'Adyghe; Adygei',
+ u'ELX': u'Elamite',
+ u'ADA': u'Adangme',
+ u'GRB': u'Grebo',
+ u'HAT': u'Haitian; Haitian Creole',
+ u'HAU': u'Hausa',
+ u'HAW': u'Hawaiian',
+ u'BIN': u'Bini',
+ u'AMH': u'Amharic',
+ u'BIK': u'Bikol',
+ u'BIH': u'Bihari',
+ u'MOS': u'Mossi',
+ u'MOH': u'Mohawk',
+ u'MON': u'Mongolian',
+ u'MOL': u'Moldavian',
+ u'BIS': u'Bislama',
+ u'TVL': u'Tuvalu',
+ u'IJO': u'Ijo',
+ u'EST': u'Estonian',
+ u'KMB': u'Kimbundu',
+ u'UMB': u'Umbundu',
+ u'TMH': u'Tamashek',
+ u'FON': u'Fon',
+ u'HSB': u'Upper Sorbian',
+ u'RUN': u'Rundi',
+ u'RUS': u'Russian',
+ u'PLI': u'Pali',
+ u'SRD': u'Sardinian',
+ u'ACH': u'Acoli',
+ u'NDE': u'Ndebele, North; North Ndebele',
+ u'DZO': u'Dzongkha',
+ u'KRU': u'Kurukh',
+ u'SRR': u'Serer',
+ u'IDO': u'Ido',
+ u'SRP': u'Serbian',
+ u'KRO': u'Kru',
+ u'KRC': u'Karachay-Balkar',
+ u'NDS': u'Low German; Low Saxon; German, Low; Saxon, Low',
+ u'ZUN': u'Zuni',
+ u'ZUL': u'Zulu',
+ u'TWI': u'Twi',
+ u'NSO': u'Northern Sotho, Pedi; Sepedi',
+ u'SOM': u'Somali',
+ u'SON': u'Songhai',
+ u'SOT': u'Sotho, Southern',
+ u'MKD': u'Macedonian',
+ u'HER': u'Herero',
+ u'LOL': u'Mongo',
+ u'HEB': u'Hebrew',
+ u'LOZ': u'Lozi',
+ u'GIL': u'Gilbertese',
+ u'WAS': u'Washo',
+ u'WAR': u'Waray',
+ u'BUL': u'Bulgarian',
+ u'WAL': u'Walamo',
+ u'BUA': u'Buriat',
+ u'BUG': u'Buginese',
+ u'AZE': u'Azerbaijani',
+ u'ZHA': u'Zhuang; Chuang',
+ u'ZHO': u'Chinese',
+ u'NNO': u'Norwegian Nynorsk; Nynorsk, Norwegian',
+ u'UIG': u'Uighur; Uyghur',
+ u'MYV': u'Erzya',
+ u'INH': u'Ingush',
+ u'KHM': u'Khmer',
+ u'MYA': u'Burmese',
+ u'KHA': u'Khasi',
+ u'INA': u'Interlingua (International Auxiliary Language Association)',
+ u'NAH': u'Nahuatl',
+ u'TIR': u'Tigrinya',
+ u'NAP': u'Neapolitan',
+ u'NAV': u'Navajo; Navaho',
+ u'NAU': u'Nauru',
+ u'GRN': u'Guarani',
+ u'TIG': u'Tigre',
+ u'YOR': u'Yoruba',
+ u'ILE': u'Interlingue',
+ u'SQI': u'Albanian',
+}
+
+# EOF
24 lib/musicbrainz2/data/releasetypenames.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+__revision__ = '$Id: releasetypenames.py 8728 2006-12-17 23:42:30Z luks $'
+
+releaseTypeNames = {
+ u'http://musicbrainz.org/ns/mmd-1.0#None': u'None',
+ u'http://musicbrainz.org/ns/mmd-1.0#Album': u'Album',
+ u'http://musicbrainz.org/ns/mmd-1.0#Single': u'Single',
+ u'http://musicbrainz.org/ns/mmd-1.0#EP': u'EP',
+ u'http://musicbrainz.org/ns/mmd-1.0#Compilation': u'Compilation',
+ u'http://musicbrainz.org/ns/mmd-1.0#Soundtrack': u'Soundtrack',
+ u'http://musicbrainz.org/ns/mmd-1.0#Spokenword': u'Spokenword',
+ u'http://musicbrainz.org/ns/mmd-1.0#Interview': u'Interview',
+ u'http://musicbrainz.org/ns/mmd-1.0#Audiobook': u'Audiobook',
+ u'http://musicbrainz.org/ns/mmd-1.0#Live': u'Live',
+ u'http://musicbrainz.org/ns/mmd-1.0#Remix': u'Remix',
+ u'http://musicbrainz.org/ns/mmd-1.0#Other': u'Other',
+ u'http://musicbrainz.org/ns/mmd-1.0#Official': u'Official',
+ u'http://musicbrainz.org/ns/mmd-1.0#Promotion': u'Promotion',
+ u'http://musicbrainz.org/ns/mmd-1.0#Bootleg': u'Bootleg',
+ u'http://musicbrainz.org/ns/mmd-1.0#Pseudo-Release': u'Pseudo-Release',
+}
+
+# EOF
59 lib/musicbrainz2/data/scriptnames.py
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+
+__revision__ = '$Id: scriptnames.py 7386 2006-04-30 11:12:55Z matt $'
+
+scriptNames = {
+ u'Yiii': u'Yi',
+ u'Telu': u'Telugu',
+ u'Taml': u'Tamil',
+ u'Guru': u'Gurmukhi',
+ u'Hebr': u'Hebrew',
+ u'Geor': u'Georgian (Mkhedruli)',
+ u'Ugar': u'Ugaritic',
+ u'Cyrl': u'Cyrillic',
+ u'Hrkt': u'Kanji & Kana',
+ u'Armn': u'Armenian',
+ u'Runr': u'Runic',
+ u'Khmr': u'Khmer',
+ u'Latn': u'Latin',
+ u'Hani': u'Han (Hanzi, Kanji, Hanja)',
+ u'Ital': u'Old Italic (Etruscan, Oscan, etc.)',
+ u'Hano': u'Hanunoo (Hanunóo)',
+ u'Ethi': u'Ethiopic (Ge\'ez)',
+ u'Gujr': u'Gujarati',
+ u'Hang': u'Hangul',
+ u'Arab': u'Arabic',
+ u'Thaa': u'Thaana',
+ u'Buhd': u'Buhid',
+ u'Sinh': u'Sinhala',
+ u'Orya': u'Oriya',
+ u'Hans': u'Han (Simplified variant)',
+ u'Thai': u'Thai',
+ u'Cprt': u'Cypriot',
+ u'Linb': u'Linear B',
+ u'Hant': u'Han (Traditional variant)',
+ u'Osma': u'Osmanya',
+ u'Mong': u'Mongolian',
+ u'Deva': u'Devanagari (Nagari)',
+ u'Laoo': u'Lao',
+ u'Tagb': u'Tagbanwa',
+ u'Hira': u'Hiragana',
+ u'Bopo': u'Bopomofo',
+ u'Goth': u'Gothic',
+ u'Tale': u'Tai Le',
+ u'Mymr': u'Myanmar (Burmese)',
+ u'Tglg': u'Tagalog',
+ u'Grek': u'Greek',
+ u'Mlym': u'Malayalam',
+ u'Cher': u'Cherokee',
+ u'Tibt': u'Tibetan',
+ u'Kana': u'Katakana',
+ u'Syrc': u'Syriac',
+ u'Cans': u'Unified Canadian Aboriginal Syllabics',
+ u'Beng': u'Bengali',
+ u'Limb': u'Limbu',
+ u'Ogam': u'Ogham',
+ u'Knda': u'Kannada',
+}
+
+# EOF
221 lib/musicbrainz2/disc.py
@@ -0,0 +1,221 @@
+"""Utilities for working with Audio CDs.
+
+This module contains utilities for working with Audio CDs.
+
+The functions in this module need both a working ctypes package (already
+included in python-2.5) and an installed libdiscid. If you don't have
+libdiscid, it can't be loaded, or your platform isn't supported by either
+ctypes or this module, a C{NotImplementedError} is raised when using the
+L{readDisc()} function.
+
+@author: Matthias Friedrich <matt@mafr.de>
+"""
+__revision__ = '$Id: disc.py 11987 2009-08-22 11:57:51Z matt $'
+
+import sys
+import urllib
+import urlparse
+import ctypes
+import ctypes.util
+from musicbrainz2.model import Disc
+
+__all__ = [ 'DiscError', 'readDisc', 'getSubmissionUrl' ]
+
+
+class DiscError(IOError):
+ """The Audio CD could not be read.
+
+ This may be simply because no disc was in the drive, the device name
+ was wrong or the disc can't be read. Reading errors can occur in case
+ of a damaged disc or a copy protection mechanism, for example.
+ """
+ pass
+
+
+def _openLibrary():
+ """Tries to open libdiscid.
+
+ @return: a C{ctypes.CDLL} object, representing the opened library
+
+ @raise NotImplementedError: if the library can't be opened
+ """
+ # This only works for ctypes >= 0.9.9.3. Any libdiscid is found,
+ # no matter how it's called on this platform.
+ try:
+ if hasattr(ctypes.cdll, 'find'):
+ libDiscId = ctypes.cdll.find('discid')
+ _setPrototypes(libDiscId)
+ return libDiscId
+ except OSError, e:
+ raise NotImplementedError('Error opening library: ' + str(e))
+
+ # Try to find the library using ctypes.util
+ libName = ctypes.util.find_library('discid')
+ if libName != None:
+ try:
+ libDiscId = ctypes.cdll.LoadLibrary(libName)
+ _setPrototypes(libDiscId)
+ return libDiscId
+ except OSError, e:
+ raise NotImplementedError('Error opening library: ' +
+ str(e))
+
+ # For compatibility with ctypes < 0.9.9.3 try to figure out the library
+ # name without the help of ctypes. We use cdll.LoadLibrary() below,
+ # which isn't available for ctypes == 0.9.9.3.
+ #
+ if sys.platform == 'linux2':
+ libName = 'libdiscid.so.0'
+ elif sys.platform == 'darwin':
+ libName = 'libdiscid.0.dylib'
+ elif sys.platform == 'win32':
+ libName = 'discid.dll'
+ else:
+ # This should at least work for Un*x-style operating systems
+ libName = 'libdiscid.so.0'
+
+ try:
+ libDiscId = ctypes.cdll.LoadLibrary(libName)
+ _setPrototypes(libDiscId)
+ return libDiscId
+ except OSError, e:
+ raise NotImplementedError('Error opening library: ' + str(e))
+
+ assert False # not reached
+
+
+def _setPrototypes(libDiscId):
+ ct = ctypes
+ libDiscId.discid_new.argtypes = ( )
+ libDiscId.discid_new.restype = ct.c_void_p
+
+ libDiscId.discid_free.argtypes = (ct.c_void_p, )
+
+ libDiscId.discid_read.argtypes = (ct.c_void_p, ct.c_char_p)
+
+ libDiscId.discid_get_error_msg.argtypes = (ct.c_void_p, )
+ libDiscId.discid_get_error_msg.restype = ct.c_char_p
+
+ libDiscId.discid_get_id.argtypes = (ct.c_void_p, )
+ libDiscId.discid_get_id.restype = ct.c_char_p
+
+ libDiscId.discid_get_first_track_num.argtypes = (ct.c_void_p, )
+ libDiscId.discid_get_first_track_num.restype = ct.c_int
+
+ libDiscId.discid_get_last_track_num.argtypes = (ct.c_void_p, )
+ libDiscId.discid_get_last_track_num.restype = ct.c_int
+
+ libDiscId.discid_get_sectors.argtypes = (ct.c_void_p, )
+ libDiscId.discid_get_sectors.restype = ct.c_int
+
+ libDiscId.discid_get_track_offset.argtypes = (ct.c_void_p, ct.c_int)
+ libDiscId.discid_get_track_offset.restype = ct.c_int
+
+ libDiscId.discid_get_track_length.argtypes = (ct.c_void_p, ct.c_int)
+ libDiscId.discid_get_track_length.restype = ct.c_int
+
+
+def getSubmissionUrl(disc, host='mm.musicbrainz.org', port=80):
+ """Returns a URL for adding a disc to the MusicBrainz database.
+
+ A fully initialized L{musicbrainz2.model.Disc} object is needed, as
+ returned by L{readDisc}. A disc object returned by the web service
+ doesn't provide the necessary information.
+
+ Note that the created URL is intended for interactive use and points
+ to the MusicBrainz disc submission wizard by default. This method
+ just returns a URL, no network connection is needed. The disc drive
+ isn't used.
+
+ @param disc: a fully initialized L{musicbrainz2.model.Disc} object
+ @param host: a string containing a host name
+ @param port: an integer containing a port number
+
+ @return: a string containing the submission URL
+
+ @see: L{readDisc}
+ """
+ assert isinstance(disc, Disc), 'musicbrainz2.model.Disc expected'
+ discid = disc.getId()
+ first = disc.getFirstTrackNum()
+ last = disc.getLastTrackNum()
+ sectors = disc.getSectors()
+ assert None not in (discid, first, last, sectors)
+
+ tracks = last - first + 1
+ toc = "%d %d %d " % (first, last, sectors)
+ toc = toc + ' '.join( map(lambda x: str(x[0]), disc.getTracks()) )
+
+ query = urllib.urlencode({ 'id': discid, 'toc': toc, 'tracks': tracks })
+
+ if port == 80:
+ netloc = host
+ else:
+ netloc = host + ':' + str(port)
+
+ url = ('http', netloc, '/bare/cdlookup.html', '', query, '')
+
+ return urlparse.urlunparse(url)
+
+
+def readDisc(deviceName=None):
+ """Reads an Audio CD in the disc drive.
+
+ This reads a CD's table of contents (TOC) and calculates the MusicBrainz
+ DiscID, which is a 28 character ASCII string. This DiscID can be used
+ to retrieve a list of matching releases from the web service (see
+ L{musicbrainz2.webservice.Query}).
+
+ Note that an Audio CD has to be in drive for this to work. The
+ C{deviceName} argument may be used to set the device. The default
+ depends on the operating system (on linux, it's C{'/dev/cdrom'}).
+ No network connection is needed for this function.
+
+ If the device doesn't exist or there's no valid Audio CD in the drive,
+ a L{DiscError} exception is raised.
+
+ @param deviceName: a string containing the CD drive's device name
+
+ @return: a L{musicbrainz2.model.Disc} object
+
+ @raise DiscError: if there was a problem reading the disc
+ @raise NotImplementedError: if DiscID generation isn't supported
+ """
+ libDiscId = _openLibrary()
+
+ handle = libDiscId.discid_new()
+ assert handle != 0, "libdiscid: discid_new() returned NULL"
+
+ # Access the CD drive. This also works if deviceName is None because
+ # ctypes passes a NULL pointer in this case.
+ #
+ res = libDiscId.discid_read(handle, deviceName)
+ if res == 0:
+ raise DiscError(libDiscId.discid_get_error_msg(handle))
+
+
+ # Now extract the data from the result.
+ #
+ disc = Disc()
+
+ disc.setId( libDiscId.discid_get_id(handle) )
+
+ firstTrackNum = libDiscId.discid_get_first_track_num(handle)
+ lastTrackNum = libDiscId.discid_get_last_track_num(handle)
+
+ disc.setSectors(libDiscId.discid_get_sectors(handle))
+
+ for i in range(firstTrackNum, lastTrackNum+1):
+ trackOffset = libDiscId.discid_get_track_offset(handle, i)
+ trackSectors = libDiscId.discid_get_track_length(handle, i)
+
+ disc.addTrack( (trackOffset, trackSectors) )
+
+ disc.setFirstTrackNum(firstTrackNum)
+ disc.setLastTrackNum(lastTrackNum)
+
+ libDiscId.discid_free(handle)
+
+ return disc
+
+# EOF
2,488 lib/musicbrainz2/model.py
@@ -0,0 +1,2488 @@
+"""The MusicBrainz domain model.
+
+These classes are part of the MusicBrainz domain model. They may be used
+by other modules and don't contain any network or other I/O code. If you
+want to request data from the web service, please have a look at
+L{musicbrainz2.webservice}.
+
+The most important classes, usually acting as entry points, are
+L{Artist}, L{Release}, and L{Track}.
+
+@var VARIOUS_ARTISTS_ID: The ID of the special 'Various Artists' artist.
+
+@var NS_MMD_1: Default namespace prefix for all MusicBrainz metadata.
+@var NS_REL_1: Namespace prefix for relations.
+@var NS_EXT_1: Namespace prefix for MusicBrainz extensions.
+
+@see: L{musicbrainz2.webservice}
+
+@author: Matthias Friedrich <matt@mafr.de>
+"""
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+__revision__ = '$Id: model.py 12829 2010-09-15 12:00:11Z luks $'
+
+__all__ = [
+ 'VARIOUS_ARTISTS_ID', 'NS_MMD_1', 'NS_REL_1', 'NS_EXT_1',
+ 'Entity', 'Artist', 'Release', 'Track', 'User', 'ReleaseGroup',
+ 'Relation', 'Disc', 'ReleaseEvent', 'Label', 'Tag', 'Rating',
+ 'AbstractAlias', 'ArtistAlias', 'LabelAlias',
+]
+
+
+VARIOUS_ARTISTS_ID = 'http://musicbrainz.org/artist/89ad4ac3-39f7-470e-963a-56509c546377'
+
+# Namespace URI prefixes
+#
+NS_MMD_1 = 'http://musicbrainz.org/ns/mmd-1.0#'
+NS_REL_1 = 'http://musicbrainz.org/ns/rel-1.0#'
+NS_EXT_1 = 'http://musicbrainz.org/ns/ext-1.0#'
+
+
+class Entity(object):
+ """A first-level MusicBrainz class.
+
+ All entities in MusicBrainz have unique IDs (which are absolute URIs)
+ as well as any number of L{relations <Relation>} to other entities
+ and free text tags. This class is abstract and should not be
+ instantiated.
+
+ Relations are differentiated by their I{target type}, that means,
+ where they link to. MusicBrainz currently supports four target types
+ (artists, releases, tracks, and URLs) each identified using a URI.
+ To get all relations with a specific target type, you can use
+ L{getRelations} and pass one of the following constants as the
+ parameter:
+
+ - L{Relation.TO_ARTIST}
+ - L{Relation.TO_RELEASE}
+ - L{Relation.TO_TRACK}
+ - L{Relation.TO_URL}
+
+ @see: L{Relation}
+ """
+
+ def __init__(self, id_=None):
+ """Constructor.
+
+ This should only used by derived classes.
+
+ @param id_: a string containing an absolute URI
+ """
+ self._id = id_
+ self._relations = { }
+ self._tags = { }
+ self._rating = Rating()
+
+ def getId(self):
+ """Returns a MusicBrainz ID.
+
+ @return: a string containing a URI, or None
+ """
+ return self._id
+
+ def setId(self, value):
+ """Sets a MusicBrainz ID.
+
+ @param value: a string containing an absolute URI
+ """
+ self._id = value
+
+ id = property(getId, setId, doc='The MusicBrainz ID.')
+
+ def getRelations(self, targetType=None, relationType=None,
+ requiredAttributes=(), direction=None):
+ """Returns a list of relations.
+
+ If C{targetType} is given, only relations of that target
+ type are returned. For MusicBrainz, the following target
+ types are defined:
+ - L{Relation.TO_ARTIST}
+ - L{Relation.TO_RELEASE}
+ - L{Relation.TO_TRACK}
+ - L{Relation.TO_URL}
+
+ If C{targetType} is L{Relation.TO_ARTIST}, for example,
+ this method returns all relations between this Entity and
+ artists.
+
+ You may use the C{relationType} parameter to further restrict
+ the selection. If it is set, only relations with the given
+ relation type are returned. The C{requiredAttributes} sequence
+ lists attributes that have to be part of all returned relations.
+
+ If C{direction} is set, only relations with the given reading
+ direction are returned. You can use the L{Relation.DIR_FORWARD},
+ L{Relation.DIR_BACKWARD}, and L{Relation.DIR_NONE} constants
+ for this.
+
+ @param targetType: a string containing an absolute URI, or None
+ @param relationType: a string containing an absolute URI, or None
+ @param requiredAttributes: a sequence containing absolute URIs
+ @param direction: one of L{Relation}'s direction constants
+ @return: a list of L{Relation} objects
+
+ @see: L{Entity}
+ """
+ allRels = [ ]
+ if targetType is not None:
+ allRels = self._relations.setdefault(targetType, [ ])
+ else:
+ for (k, relList) in self._relations.items():
+ for rel in relList:
+ allRels.append(rel)
+
+ # Filter for direction.
+ #
+ if direction is not None:
+ allRels = [r for r in allRels if r.getDirection() == direction]
+
+ # Filter for relation type.
+ #
+ if relationType is None:
+ return allRels
+ else:
+ allRels = [r for r in allRels if r.getType() == relationType]
+
+ # Now filer for attribute type.
+ #
+ tmp = []
+ required = set(iter(requiredAttributes))
+
+ for r in allRels:
+ attrs = set(iter(r.getAttributes()))
+ if required.issubset(attrs):
+ tmp.append(r)
+ return tmp
+
+
+ def getRelationTargets(self, targetType=None, relationType=None,
+ requiredAttributes=(), direction=None):
+ """Returns a list of relation targets.
+
+ The arguments work exactly like in L{getRelations}, but
+ instead of L{Relation} objects, the matching relation
+ targets are returned. This can be L{Artist}, L{Release},
+ or L{Track} objects, depending on the relations.
+
+ As a special case, URL strings are returned if the target
+ is an URL.
+
+ @param targetType: a string containing an absolute URI, or None
+ @param relationType: a string containing an absolute URI, or None
+ @param requiredAttributes: a sequence containing absolute URIs
+ @param direction: one of L{Relation}'s direction constants
+ @return: a list of objects, depending on the relation
+
+ @see: L{getRelations}
+ """
+ ret = [ ]
+ rels = self.getRelations(targetType, relationType,
+ requiredAttributes, direction)
+
+ for r in rels:
+ if r.getTargetType() == Relation.TO_URL:
+ ret.append(r.getTargetId())
+ else:
+ ret.append(r.getTarget())
+
+ return ret
+
+
+ def addRelation(self, relation):
+ """Adds a relation.
+
+ This method adds C{relation} to the list of relations. The
+ given relation has to be initialized, at least the target
+ type has to be set.
+
+ @param relation: the L{Relation} object to add
+
+ @see: L{Entity}
+ """
+ assert relation.getType is not None
+ assert relation.getTargetType is not None
+ assert relation.getTargetId is not None
+ l = self._relations.setdefault(relation.getTargetType(), [ ])
+ l.append(relation)
+
+
+ def getRelationTargetTypes(self):
+ """Returns a list of target types available for this entity.
+
+ Use this to find out to which types of targets this entity
+ has relations. If the entity only has relations to tracks and
+ artists, for example, then a list containg the strings
+ L{Relation.TO_TRACK} and L{Relation.TO_ARTIST} is returned.
+
+ @return: a list of strings containing URIs
+
+ @see: L{getRelations}
+ """
+ return self._relations.keys()
+
+ def getTag(self, value):
+ """Return the tag with the given value (aka the tag's name).
+
+ @return: the L{Tag} with the given name or raises a KeyError
+ """
+ return self._tags[value]
+
+ def getTags(self):
+ """Return all tags attached to this Entity.
+
+ @return: a list of L{Tag} objects
+ """
+ return self._tags.values()
+
+ tags = property(getTags, doc='The tags for this entity.')
+
+ def addTag(self, tag):
+ """Add a new tag.
+
+ This merges an existing tag with the same name.
+
+ @param tag: the L{Tag} object to add
+
+ @see: L{getTags}
+ """
+ if self._tags.has_key(tag.value):
+ existing = self._tags[tag.value]
+ existing.count += tag.count
+ else:
+ self._tags[tag.value] = tag
+
+ def getRating(self):
+ """Return the rating of this Entity.
+ 0 = Unrated
+ 1 - 5 = Rating
+
+ @return: rating
+ """
+ return self._rating
+
+ rating = property(getRating, doc='The rating for this entity.')
+
+ def setRating(self, value):
+ self._rating = value
+
+
+class Artist(Entity):
+ """Represents an artist.
+
+ Artists in MusicBrainz can have a type. Currently, this type can
+ be either Person or Group for which the following URIs are assigned:
+
+ - C{http://musicbrainz.org/ns/mmd-1.0#Person}
+ - C{http://musicbrainz.org/ns/mmd-1.0#Group}
+
+ Use the L{TYPE_PERSON} and L{TYPE_GROUP} constants for comparison.
+ """
+ TYPE_PERSON = NS_MMD_1 + 'Person'
+ TYPE_GROUP = NS_MMD_1 + 'Group'
+
+ def __init__(self, id_=None, type_=None, name=None, sortName=None):
+ """Constructor.
+
+ @param id_: a string containing an absolute URI
+ @param type_: a string containing an absolute URI
+ @param name: a string containing the artist's name
+ @param sortName: a string containing the artist's sort name
+ """
+ Entity.__init__(self, id_)
+ self._type = type_
+ self._name = name
+ self._sortName = sortName
+ self._disambiguation = None
+ self._beginDate = None
+ self._endDate = None
+ self._aliases = [ ]
+ self._releases = [ ]
+ self._releasesCount = None
+ self._releasesOffset = None
+ self._releaseGroups = [ ]
+ self._releaseGroupsCount = None
+ self._releaseGroupsOffset = None
+
+ def getType(self):
+ """Returns the artist's type.
+
+ @return: a string containing an absolute URI, or None
+ """
+ return self._type
+
+ def setType(self, type_):
+ """Sets the artist's type.
+
+ @param type_: a string containing an absolute URI
+ """
+ self._type = type_
+
+ type = property(getType, setType, doc="The artist's type.")
+
+ def getName(self):
+ """Returns the artist's name.
+
+ @return: a string containing the artist's name, or None
+ """
+ return self._name
+
+ def setName(self, name):
+ """Sets the artist's name.
+
+ @param name: a string containing the artist's name
+ """
+ self._name = name
+
+ name = property(getName, setName, doc="The artist's name.")
+
+ def getSortName(self):
+ """Returns the artist's sort name.
+
+ The sort name is the artist's name in a special format which
+ is better suited for lexicographic sorting. The MusicBrainz
+ style guide specifies this format.
+
+ @see: U{The MusicBrainz Style Guidelines
+ <http://musicbrainz.org/style.html>}
+ """
+ return self._sortName
+
+ def setSortName(self, sortName):
+ """Sets the artist's sort name.
+
+ @param sortName: a string containing the artist's sort name
+
+ @see: L{getSortName}
+ """
+ self._sortName = sortName
+
+ sortName = property(getSortName, setSortName,
+ doc="The artist's sort name.")
+
+ def getDisambiguation(self):
+ """Returns the disambiguation attribute.
+
+ This attribute may be used if there is more than one artist
+ with the same name. In this case, disambiguation attributes
+ are added to the artists' names to keep them apart.
+
+ For example, there are at least three bands named 'Vixen'.
+ Each band has a different disambiguation in the MusicBrainz
+ database, like 'Hip-hop' or 'all-female rock/glam band'.
+
+ @return: a disambiguation string, or None
+
+ @see: L{getUniqueName}
+ """
+ return self._disambiguation
+
+ def setDisambiguation(self, disambiguation):
+ """Sets the disambiguation attribute.
+
+ @param disambiguation: a disambiguation string
+
+ @see: L{getDisambiguation}, L{getUniqueName}
+ """
+ self._disambiguation = disambiguation
+
+ disambiguation = property(getDisambiguation, setDisambiguation,
+ doc="The disambiguation comment.")
+
+ def getUniqueName(self):
+ """Returns a unique artist name (using disambiguation).
+
+ This method returns the artist name together with the
+ disambiguation attribute in parenthesis if it exists.
+ Example: 'Vixen (Hip-hop)'.
+
+ @return: a string containing the unique name
+
+ @see: L{getDisambiguation}
+ """
+ d = self.getDisambiguation()
+ if d is not None and d.strip() != '':
+ return '%s (%s)' % (self.getName(), d)
+ else:
+ return self.getName()
+
+ def getBeginDate(self):
+ """Returns the birth/foundation date.
+
+ The definition of the I{begin date} depends on the artist's
+ type. For persons, this is the day of birth, for groups it
+ is the day the group was founded.
+
+ The returned date has the format 'YYYY', 'YYYY-MM', or
+ 'YYYY-MM-DD', depending on how much detail is known.
+
+ @return: a string containing the date, or None
+
+ @see: L{getType}
+ """
+ return self._beginDate
+
+ def setBeginDate(self, dateStr):
+ """Sets the begin/foundation date.
+
+ @param dateStr: a date string
+
+ @see: L{getBeginDate}
+ """
+ self._beginDate = dateStr
+
+ beginDate = property(getBeginDate, setBeginDate,
+ doc="The begin/foundation date.")
+
+ def getEndDate(self):
+ """Returns the death/dissolving date.
+
+ The definition of the I{end date} depends on the artist's
+ type. For persons, this is the day of death, for groups it
+ is the day the group was dissolved.
+
+ @return: a string containing a date, or None
+
+ @see: L{getBeginDate}
+ """
+ return self._endDate
+
+ def setEndDate(self, dateStr):
+ """Sets the death/dissolving date.
+
+ @param dateStr: a string containing a date
+
+ @see: L{setEndDate}, L{getBeginDate}
+ """
+ self._endDate = dateStr
+
+ endDate = property(getEndDate, setEndDate,
+ doc="The death/dissolving date.")
+
+ def getAliases(self):
+ """Returns the list of aliases for this artist.
+
+ @return: a list of L{ArtistAlias} objects
+ """
+ return self._aliases
+
+ aliases = property(getAliases, doc='The list of aliases.')
+
+ def addAlias(self, alias):
+ """Adds an alias for this artist.
+
+ @param alias: an L{ArtistAlias} object
+ """
+ self._aliases.append(alias)
+
+ def getReleases(self):
+ """Returns a list of releases from this artist.
+
+ This may also include releases where this artist isn't the
+ I{main} artist but has just contributed one or more tracks
+ (aka VA-Releases).
+
+ @return: a list of L{Release} objects
+ """
+ return self._releases
+
+ releases = property(getReleases, doc='The list of releases')
+
+ def addRelease(self, release):
+ """Adds a release to this artist's list of releases.
+
+ @param release: a L{Release} object
+ """
+ self._releases.append(release)
+
+ def getReleasesOffset(self):
+ """Returns the offset of the release list.
+
+ This is used if the release list is incomplete (ie. the web
+ service only returned part of the release for this artist).
+ Note that the offset value is zero-based, which means release
+ C{0} is the first release.
+
+ @return: an integer containing the offset, or None
+
+ @see: L{getReleases}, L{getReleasesCount}
+ """
+ return self._releasesOffset
+
+ def setReleasesOffset(self, offset):
+ """Sets the offset of the release list.
+
+ @param offset: an integer containing the offset, or None
+
+ @see: L{getReleasesOffset}
+ """
+ self._releasesOffset = offset
+
+ releasesOffset = property(getReleasesOffset, setReleasesOffset,
+ doc='The offset of the release list.')
+
+ def getReleasesCount(self):
+ """Returns the number of existing releases.
+
+ This may or may not match with the number of elements that
+ L{getReleases} returns. If the count is higher than
+ the list, it indicates that the list is incomplete.
+
+ @return: an integer containing the count, or None
+
+ @see: L{setReleasesCount}, L{getReleasesOffset}
+ """
+ return self._releasesCount
+
+ def setReleasesCount(self, value):
+ """Sets the number of existing releases.
+
+ @param value: an integer containing the count, or None
+
+ @see: L{getReleasesCount}, L{setReleasesOffset}
+ """
+ self._releasesCount = value
+
+ releasesCount = property(getReleasesCount, setReleasesCount,
+ doc='The total number of releases')
+
+ def getReleaseGroups(self):
+ """Returns a list of release groups from this artist.
+
+ @return: a list of L{ReleaseGroup} objects
+ """
+ return self._releaseGroups
+
+ releaseGroups = property(getReleaseGroups, doc='The list of release groups')
+
+ def addReleaseGroup(self, releaseGroup):
+ """Adds a release group to this artist's list of release groups.
+
+ @param releaseGroup: a L{ReleaseGroup} object
+ """
+ self._releaseGroups.append(releaseGroup)
+
+ def getReleaseGroupsOffset(self):
+ """Returns the offset of the release group list.
+
+ This is used if the release group list is incomplete (ie. the
+ web service only returned part of the result for this artist).
+ Note that the offset value is zero-based, which means release
+ group C{0} is the first release group.
+
+ @return: an integer containing the offset, or None
+
+ @see: L{getReleaseGroups}, L{getReleaseGroupsCount}
+ """
+ return self._releaseGroupsOffset
+
+ def setReleaseGroupsOffset(self, offset):
+ """Sets the offset of the release group list.
+
+ @param offset: an integer containing the offset, or None
+
+ @see: L{getReleaseGroupsOffset}
+ """
+ self._releaseGroupsOffset = offset
+
+ releaseGroupsOffset = property(getReleaseGroupsOffset, setReleaseGroupsOffset,
+ doc='The offset of the release group list.')
+
+ def getReleaseGroupsCount(self):
+ """Returns the number of existing release groups.
+
+ This may or may not match with the number of elements that
+ L{getReleaseGroups} returns. If the count is higher than
+ the list, it indicates that the list is incomplete.
+
+ @return: an integer containing the count, or None
+
+ @see: L{setReleaseGroupsCount}, L{getReleaseGroupsOffset}
+ """
+ return self._releaseGroupsCount
+
+ def setReleaseGroupsCount(self, value):
+ """Sets the number of existing release groups.
+
+ @param value: an integer containing the count, or None
+
+ @see: L{getReleaseGroupsCount}, L{setReleaseGroupsOffset}
+ """
+ self._releaseGroupsCount = value
+
+ releasesCount = property(getReleaseGroupsCount, setReleaseGroupsCount,
+ doc='The total number of release groups')
+
+
+class Rating(object):
+ """The representation of a MusicBrain rating.
+
+ The rating can have the following values:
+
+ 0 = Unrated
+ [1..5] = Rating
+ """
+ def __init__(self, value=None, count=None):
+ """Constructor.
+
+ @param value: a string containing the tag's value
+ @param count: the number of users who added this tag
+ """
+ self._value = value
+ self._count = count
+
+ def getValue(self):
+ """Returns a string with the tag's value.
+
+ @return: an integer containing the rating's value, or None
+ """
+ return self._value
+
+ def setValue(self, value):
+ """ Set the value of this rating.
+
+ 0 or None = Clear your rating
+ 1 - 5 = Rating
+
+ @param value: the rating to apply
+
+ @raise ValueError: if value is not a double or not in the
+ range 0 - 5 or None.
+ """
+ if value == None:
+ value = 0
+ try:
+ value = float(value)
+ except ValueError, e:
+ raise ValueError("Value for rating needs to be an" \
+ "float.")
+ if value < 0.0 or value > 5.0:
+ raise ValueError("Value needs to be in the range [0..5]")
+ self._value = value
+
+ value = property(getValue, setValue, doc='The value of the rating.')
+
+ def getCount(self):
+ """Returns an integer containing the rating's frequency count.
+
+ @return: an integer containing the rating's frequency count,
+ or None
+ """
+ return self._count
+
+ def setCount(self, count):
+ """Sets the frequency count of this rating.
+
+ @param count: an integer containing the tag's frequency count
+ """
+ self._count = count
+
+ count = property(getCount, setCount, doc="This tag's frequency count.")
+
+ def __str__(self):
+ return str(self._value)
+
+ def __unicode__(self):
+ return unicode(self._value)
+
+
+class Tag(object):
+ """The representation of a MusicBrainz folksonomy tag.
+
+ The tag's value is the text that's displayed in the tag cloud.
+ The count attribute keeps track of how many users added the tag
+ to its owning entity.
+ """
+ def __init__(self, value=None, count=None):
+ """Constructor.
+
+ @param value: a string containing the tag's value
+ @param count: the number of users who added this tag
+ """
+ self._value = value
+ self._count = count
+
+ def getValue(self):
+ """Returns a string with the tag's value.
+
+ @return: a string containing the tags's value, or None
+ """
+ return self._value
+
+ def setValue(self, value):
+ """Sets the value of this tag.
+
+ @param value: A string containing the value of the tag
+ """
+ self._value = value
+
+ value = property(getValue, setValue, doc='The value of the text.')
+
+ def getCount(self):
+ """Returns an integer containing the tag's frequency count.
+
+ @return: an integer containing the tags's frequency count, or None
+ """
+ return self._count
+
+ def setCount(self, count):
+ """Sets the frequency count of this tag.
+
+ @param count: an integer containing the tag's frequency count
+ """
+ self._count = count
+
+ count = property(getCount, setCount, doc="This tag's frequency count.")
+
+ def __str__(self):
+ return str(self._value)
+
+ def __unicode__(self):
+ return unicode(self._value)
+
+
+class Label(Entity):
+ """Represents a record label.
+
+ A label within MusicBrainz is an L{Entity}. It contains information
+ about the label like when it was established, its name, label code and
+ other relationships. All release events may be assigned a label.
+ """
+ TYPE_UNKNOWN = NS_MMD_1 + 'Unknown'
+
+ TYPE_DISTRIBUTOR = NS_MMD_1 + 'Distributor'
+ TYPE_HOLDING = NS_MMD_1 + 'Holding'
+ TYPE_PRODUCTION = NS_MMD_1 + 'Production'
+
+ TYPE_ORIGINAL = NS_MMD_1 + 'OriginalProduction'
+ TYPE_BOOTLEG = NS_MMD_1 + 'BootlegProduction'
+ TYPE_REISSUE = NS_MMD_1 + 'ReissueProduction'
+
+ def __init__(self, id_=None):
+ """Constructor.
+
+ @param id_: a string containing an absolute URI
+ """
+ Entity.__init__(self, id_)
+ self._type = None
+ self._name = None
+ self._sortName = None
+ self._disambiguation = None
+ self._countryId = None
+ self._code = None
+ self._beginDate = None
+ self._endDate = None
+ self._aliases = [ ]
+
+ def getType(self):
+ """Returns the type of this label.
+
+ @return: a string containing an absolute URI
+ """
+ return self._type
+
+ def setType(self, type_):
+ """Sets the type of this label.
+
+ @param type_: A string containing the absolute URI of the type of label.
+ """
+ self._type = type_
+
+ type = property(getType, setType, doc='The type of label')
+
+ def getName(self):
+ """Returns a string with the name of the label.
+
+ @return: a string containing the label's name, or None
+ """
+ return self._name
+
+ def setName(self, name):
+ """Sets the name of this label.
+
+ @param name: A string containing the name of the label
+ """
+ self._name = name
+
+ name = property(getName, setName, doc='The name of the label.')
+
+ def getSortName(self):
+ """Returns the label's sort name.
+
+ The sort name is the label's name in a special format which
+ is better suited for lexicographic sorting. The MusicBrainz
+ style guide specifies this format.
+
+ @see: U{The MusicBrainz Style Guidelines
+ <http://musicbrainz.org/style.html>}
+ """
+ return self._sortName
+
+ def setSortName(self, sortName):
+ """Sets the label's sort name.
+
+ @param sortName: a string containing the label's sort name
+
+ @see: L{getSortName}
+ """
+ self._sortName = sortName
+
+ sortName = property(getSortName, setSortName,
+ doc="The label's sort name.")
+
+ def getDisambiguation(self):
+ """Returns the disambiguation attribute.
+
+ This attribute may be used if there is more than one label
+ with the same name. In this case, disambiguation attributes
+ are added to the labels' names to keep them apart.
+
+ @return: a disambiguation string, or None
+
+ @see: L{getUniqueName}
+ """
+ return self._disambiguation
+
+ def setDisambiguation(self, disambiguation):
+ """Sets the disambiguation attribute.
+
+ @param disambiguation: a disambiguation string
+
+ @see: L{getDisambiguation}, L{getUniqueName}
+ """
+ self._disambiguation = disambiguation
+
+ disambiguation = property(getDisambiguation, setDisambiguation,
+ doc="The disambiguation comment.")
+
+ def getUniqueName(self):
+ """Returns a unique label name (using disambiguation).
+
+ This method returns the label's name together with the
+ disambiguation attribute in parenthesis if it exists.
+
+ @return: a string containing the unique name
+
+ @see: L{getDisambiguation}
+ """
+ d = self.getDisambiguation()
+ if d is not None and d.strip() != '':
+ return '%s (%s)' % (self.getName(), d)
+ else:
+ return self.getName()
+
+ def getBeginDate(self):
+ """Returns the date this label was established.
+
+ @return: A string contained the start date, or None
+ """
+ return self._beginDate
+
+ def setBeginDate(self, date):
+ """Set the date this label was established.
+
+ @param date: A string in the format of YYYY-MM-DD
+ """
+ self._beginDate = date
+
+ beginDate = property(getBeginDate, setBeginDate,
+ doc='The date this label was established.')
+
+ def getEndDate(self):
+ """Returns the date this label closed.
+
+ The returned date has the format 'YYYY', 'YYYY-MM', or
+ 'YYYY-MM-DD', depending on how much detail is known.
+
+ @return: A string containing the date, or None
+ """
+ return self._endDate
+
+ def setEndDate(self, date):
+ """Set the date this label closed.
+
+ The date may have the format 'YYYY', 'YYYY-MM', or
+ 'YYYY-MM-DD', depending on how much detail is known.
+
+ @param date: A string containing the date, or None
+ """
+ self._endDate = date
+
+ endDate = property(getEndDate, setEndDate,
+ doc='The date this label closed.')
+
+ def getCountry(self):
+ """Returns the country the label is located.
+
+ @return: a string containing an ISO-3166 country code, or None
+
+ @see: L{musicbrainz2.utils.getCountryName}
+ """
+ return self._countryId
+
+ def setCountry(self, country):
+ """Sets the country the label is located.
+
+ @param country: a string containing an ISO-3166 country code
+ """
+ self._countryId = country
+
+ country = property(getCountry, setCountry,
+ doc='The country the label is located.')
+
+ def getCode(self):
+ """Returns the label code.
+
+ Label codes have been introduced by the IFPI (International
+ Federation of Phonogram and Videogram Industries) to uniquely
+ identify record labels. The label code consists of 'LC-' and 4
+ figures (currently being extended to 5 figures).
+
+ @return: a string containing the label code, or None
+ """
+ return self._code
+
+ def setCode(self, code):
+ """Sets the label code.
+
+ @param code: a string containing the label code
+ """
+ self._code = code
+
+ code = property(getCode, setCode,
+ doc='The label code.')
+
+ def getAliases(self):
+ """Returns the list of aliases for this label.
+
+ @return: a list of L{LabelAlias} objects
+ """
+ return self._aliases
+
+ aliases = property(getAliases, doc='The list of aliases.')
+
+ def addAlias(self, alias):
+ """Adds an alias for this label.
+
+ @param alias: a L{LabelAlias} object
+ """
+ self._aliases.append(alias)
+
+
+class Release(Entity):
+ """Represents a Release.
+
+ A release within MusicBrainz is an L{Entity} which contains L{Track}
+ objects. Releases may be of more than one type: There can be albums,
+ singles, compilations, live recordings, official releases, bootlegs
+ etc.
+
+ @note: The current MusicBrainz server implementation supports only a
+ limited set of types.
+ """
+ TYPE_NONE = NS_MMD_1 + 'None'
+ TYPE_NON_ALBUM_TRACKS = NS_MMD_1 + "NonAlbum Track"
+
+ TYPE_ALBUM = NS_MMD_1 + 'Album'
+ TYPE_SINGLE = NS_MMD_1 + 'Single'
+ TYPE_EP = NS_MMD_1 + 'EP'
+ TYPE_COMPILATION = NS_MMD_1 + 'Compilation'
+ TYPE_SOUNDTRACK = NS_MMD_1 + 'Soundtrack'
+ TYPE_SPOKENWORD = NS_MMD_1 + 'Spokenword'
+ TYPE_INTERVIEW = NS_MMD_1 + 'Interview'
+ TYPE_AUDIOBOOK = NS_MMD_1 + 'Audiobook'
+ TYPE_LIVE = NS_MMD_1 + 'Live'
+ TYPE_REMIX = NS_MMD_1 + 'Remix'
+ TYPE_OTHER = NS_MMD_1 + 'Other'
+
+ TYPE_OFFICIAL = NS_MMD_1 + 'Official'
+ TYPE_PROMOTION = NS_MMD_1 + 'Promotion'
+ TYPE_BOOTLEG = NS_MMD_1 + 'Bootleg'
+ TYPE_PSEUDO_RELEASE = NS_MMD_1 + 'Pseudo-Release'
+
+ def __init__(self, id_=None, title=None):
+ """Constructor.
+
+ @param id_: a string containing an absolute URI
+ @param title: a string containing the title
+ """
+ Entity.__init__(self, id_)
+ self._types = [ ]
+ self._title = title
+ self._textLanguage = None
+ self._textScript = None
+ self._asin = None
+ self._artist = None
+ self._releaseEvents = [ ]
+ #self._releaseEventsCount = None
+ self._releaseGroup = None
+ self._discs = [ ]
+ #self._discIdsCount = None
+ self._tracks = [ ]
+ self._tracksOffset = None
+ self._tracksCount = None
+
+
+ def getTypes(self):
+ """Returns the types of this release.
+
+ To test for release types, you can use the constants
+ L{TYPE_ALBUM}, L{TYPE_SINGLE}, etc.
+
+ @return: a list of strings containing absolute URIs
+
+ @see: L{musicbrainz2.utils.getReleaseTypeName}
+ """
+ return self._types
+
+ types = property(getTypes, doc='The list of types for this release.')
+
+ def addType(self, type_):
+ """Add a type to the list of types.
+
+ @param type_: a string containing absolute URIs
+
+ @see: L{getTypes}
+ """
+ self._types.append(type_)
+
+ def getTitle(self):
+ """Returns the release's title.
+
+ @return: a string containing the release's title
+ """
+ return self._title
+
+ def setTitle(self, title):
+ """Sets the release's title.
+
+ @param title: a string containing the release's title, or None
+ """
+ self._title = title
+
+ title = property(getTitle, setTitle, doc='The title of this release.')
+
+ def getTextLanguage(self):
+ """Returns the language used in release and track titles.
+
+ To represent the language, the ISO-639-2/T standard is used,
+ which provides three-letter terminological language codes like
+ 'ENG', 'DEU', 'JPN', 'KOR', 'ZHO' or 'YID'.
+
+ Note that this refers to release and track I{titles}, not
+ lyrics.
+
+ @return: a string containing the language code, or None
+
+ @see: L{musicbrainz2.utils.getLanguageName}
+ """
+ return self._textLanguage
+
+ def setTextLanguage(self, language):
+ """Sets the language used in releaes and track titles.
+
+ @param language: a string containing a language code
+
+ @see: L{getTextLanguage}
+ """
+ self._textLanguage = language
+
+ textLanguage = property(getTextLanguage, setTextLanguage,
+ doc='The language used in release and track titles.')
+
+ def getTextScript(self):
+ """Returns the script used in release and track titles.
+
+ To represent the script, ISO-15924 script codes are used.
+ Valid codes are, among others: 'Latn', 'Cyrl', 'Hans', 'Hebr'
+
+ Note that this refers to release and track I{titles}, not
+ lyrics.
+
+ @return: a string containing the script code, or None
+
+ @see: L{musicbrainz2.utils.getScriptName}
+ """
+ return self._textScript
+
+ def setTextScript(self, script):
+ """Sets the script used in releaes and track titles.
+
+ @param script: a string containing a script code
+
+ @see: L{getTextScript}
+ """
+ self._textScript = script
+
+ textScript = property(getTextScript, setTextScript,
+ doc='The script used in release and track titles.')
+
+ def getAsin(self):
+ """Returns the amazon shop identifier (ASIN).
+
+ The ASIN is a 10-letter code (except for books) assigned
+ by Amazon, which looks like 'B000002IT2' or 'B00006I4YD'.
+
+ @return: a string containing the ASIN, or None
+ """
+ return self._asin
+
+ def setAsin(self, asin):
+ """Sets the amazon shop identifier (ASIN).
+
+ @param asin: a string containing the ASIN
+
+ @see: L{getAsin}
+ """
+ self._asin = asin
+
+ asin = property(getAsin, setAsin, doc='The amazon shop identifier.')
+
+ def getArtist(self):
+ """Returns the main artist of this release.
+
+ @return: an L{Artist} object, or None
+ """
+ return self._artist
+
+ def setArtist(self, artist):
+ """Sets this release's main artist.
+
+ @param artist: an L{Artist} object
+ """
+ self._artist = artist
+
+ artist = property(getArtist, setArtist,
+ doc='The main artist of this release.')
+
+ def getReleaseGroup(self):
+ """Returns the release group to which this release belongs.
+
+ @return: a L{ReleaseGroup} object, or None.
+ """
+ return self._releaseGroup
+
+ def setReleaseGroup(self, releaseGroup):
+ """Sets the release's release group.
+
+ @param releaseGroup: a L{ReleaseGroup} object, or None.
+ """
+ self._releaseGroup = releaseGroup
+
+ releaseGroup = property(getReleaseGroup, setReleaseGroup,
+ doc='The release group this release belongs to.')
+
+ def isSingleArtistRelease(self):
+ """Checks if this is a single artist's release.
+
+ Returns C{True} if the release's main artist (L{getArtist}) is
+ also the main artist for all of the tracks. This is checked by
+ comparing the artist IDs.
+
+ Note that the release's artist has to be set (see L{setArtist})
+ for this. The track artists may be unset.
+
+ @return: True, if this is a single artist's release
+ """
+ releaseArtist = self.getArtist()
+ assert releaseArtist is not None, 'Release Artist may not be None!'
+ for track in self.getTracks():
+ if track.getArtist() is None:
+ continue
+ if track.getArtist().getId() != releaseArtist.getId():
+ return False
+
+ return True
+
+ def getTracks(self):
+ """Returns the tracks this release contains.
+
+ @return: a list containing L{Track} objects
+
+ @see: L{getTracksOffset}, L{getTracksCount}
+ """
+ return self._tracks
+
+ tracks = property(getTracks, doc='The list of tracks.')
+
+ def addTrack(self, track):
+ """Adds a track to this release.
+
+ This appends a track at the end of this release's track list.
+
+ @param track: a L{Track} object
+ """
+ self._tracks.append(track)
+
+ def getTracksOffset(self):
+ """Returns the offset of the track list.
+
+ This is used if the track list is incomplete (ie. the web
+ service only returned part of the tracks on this release).
+ Note that the offset value is zero-based, which means track
+ C{0} is the first track.
+
+ @return: an integer containing the offset, or None
+
+ @see: L{getTracks}, L{getTracksCount}
+ """
+ return self._tracksOffset
+
+ def setTracksOffset(self, offset):
+ """Sets the offset of the track list.
+
+ @param offset: an integer containing the offset, or None
+
+ @see: L{getTracksOffset}, L{setTracksCount}
+ """
+ self._tracksOffset = offset
+
+ tracksOffset = property(getTracksOffset, setTracksOffset,
+ doc='The offset of the track list.')
+
+ def getTracksCount(self):
+ """Returns the number of tracks on this release.
+
+ This may or may not match with the number of elements that
+ L{getTracks} returns. If the count is higher than
+ the list, it indicates that the list is incomplete.
+
+ @return: an integer containing the count, or None
+
+ @see: L{setTracksCount}, L{getTracks}, L{getTracksOffset}
+ """
+ return self._tracksCount
+
+ def setTracksCount(self, value):
+ """Sets the number of tracks on this release.
+
+ @param value: an integer containing the count, or None
+
+ @see: L{getTracksCount}, L{setTracksOffset}
+ """
+ self._tracksCount = value
+
+ tracksCount = property(getTracksCount, setTracksCount,
+ doc='The total number of releases')
+
+
+ def getReleaseEvents(self):
+ """Returns the list of release events.
+
+ A L{Release} may contain a list of so-called release events,
+ each represented using a L{ReleaseEvent} object. Release
+ evens specify where and when this release was, well, released.
+
+ @return: a list of L{ReleaseEvent} objects
+
+ @see: L{getReleaseEventsAsDict}
+ """
+ return self._releaseEvents
+