Package musicbrainz2 :: Module model

[frames] | no frames]

# Source Code for Module musicbrainz2.model

       1  """The MusicBrainz domain model.
       2
       3  These classes are part of the MusicBrainz domain model. They may be used
       4  by other modules and don't contain any network or other I/O code. If you
       5  want to request data from the web service, please have a look at
       6  L{musicbrainz2.webservice}.
       7
       8  The most important classes, usually acting as entry points, are
       9  L{Artist}, L{Release}, and L{Track}.
      10
      11  @var VARIOUS_ARTISTS_ID: The ID of the special 'Various Artists' artist.
      12
      13  @var NS_MMD_1: Default namespace prefix for all MusicBrainz metadata.
      14  @var NS_REL_1: Namespace prefix for relations.
      15  @var NS_EXT_1: Namespace prefix for MusicBrainz extensions.
      16
      17  @see: L{musicbrainz2.webservice}
      18
      19  @author: Matthias Friedrich <matt@mafr.de>
      20  """
      21  try:
      22          set
      23  except NameError:
      24          from sets import Set as set
      25
      26  __revision__ = '$Id: model.py 12829 2010-09-15 12:00:11Z luks $'
      27
      28  __all__ = [
      29          'VARIOUS_ARTISTS_ID', 'NS_MMD_1', 'NS_REL_1', 'NS_EXT_1',
      30          'Entity', 'Artist', 'Release', 'Track', 'User', 'ReleaseGroup',
      31          'Relation', 'Disc', 'ReleaseEvent', 'Label', 'Tag', 'Rating',
      32          'AbstractAlias', 'ArtistAlias', 'LabelAlias',
      33  ]
      34
      35
      36  VARIOUS_ARTISTS_ID = 'http://musicbrainz.org/artist/89ad4ac3-39f7-470e-963a-56509c546377'
      37
      38  # Namespace URI prefixes
      39  #
      40  NS_MMD_1 = 'http://musicbrainz.org/ns/mmd-1.0#'
      41  NS_REL_1 = 'http://musicbrainz.org/ns/rel-1.0#'
      42  NS_EXT_1 = 'http://musicbrainz.org/ns/ext-1.0#'
      43
      44
      45 -class Entity(object):
      46          """A first-level MusicBrainz class.
      47
      48          All entities in MusicBrainz have unique IDs (which are absolute URIs)
      49          as well as any number of L{relations <Relation>} to other entities
      50          and free text tags. This class is abstract and should not be
      51          instantiated.
      52
      53          Relations are differentiated by their I{target type}, that means,
      54          where they link to. MusicBrainz currently supports four target types
      55          (artists, releases, tracks, and URLs) each identified using a URI.
      56          To get all relations with a specific target type, you can use
      57          L{getRelations} and pass one of the following constants as the
      58          parameter:
      59
      60           - L{Relation.TO_ARTIST}
      61           - L{Relation.TO_RELEASE}
      62           - L{Relation.TO_TRACK}
      63           - L{Relation.TO_URL}
      64
      65          @see: L{Relation}
      66          """
      67
      68 -        def __init__(self, id_=None):
      69                  """Constructor.
      70
      71                  This should only used by derived classes.
      72
      73                  @param id_: a string containing an absolute URI
      74                  """
      75                  self._id = id_
      76                  self._relations = { }
      77                  self._tags = { }
      78                  self._rating = Rating()
      79
      80 -        def getId(self):
      81                  """Returns a MusicBrainz ID.
      82
      83                  @return: a string containing a URI, or None
      84                  """
      85                  return self._id
      86
      87 -        def setId(self, value):
      88                  """Sets a MusicBrainz ID.
      89
      90                  @param value: a string containing an absolute URI
      91                  """
      92                  self._id = value
      93
      94          id = property(getId, setId, doc='The MusicBrainz ID.')
      95
      96 -        def getRelations(self, targetType=None, relationType=None,
      97                          requiredAttributes=(), direction=None):
      98                  """Returns a list of relations.
      99
     100                  If C{targetType} is given, only relations of that target
     101                  type are returned. For MusicBrainz, the following target
     102                  types are defined:
     103                   - L{Relation.TO_ARTIST}
     104                   - L{Relation.TO_RELEASE}
     105                   - L{Relation.TO_TRACK}
     106                   - L{Relation.TO_URL}
     107
     108                  If C{targetType} is L{Relation.TO_ARTIST}, for example,
     109                  this method returns all relations between this Entity and
     110                  artists.
     111
     112                  You may use the C{relationType} parameter to further restrict
     113                  the selection. If it is set, only relations with the given
     114                  relation type are returned. The C{requiredAttributes} sequence
     115                  lists attributes that have to be part of all returned relations.
     116
     117                  If C{direction} is set, only relations with the given reading
     118                  direction are returned. You can use the L{Relation.DIR_FORWARD},
     119                  L{Relation.DIR_BACKWARD}, and L{Relation.DIR_NONE} constants
     120                  for this.
     121
     122                  @param targetType: a string containing an absolute URI, or None
     123                  @param relationType: a string containing an absolute URI, or None
     124                  @param requiredAttributes: a sequence containing absolute URIs
     125                  @param direction: one of L{Relation}'s direction constants
     126                  @return: a list of L{Relation} objects
     127
     128                  @see: L{Entity}
     129                  """
     130                  allRels = [ ]
     131                  if targetType is not None:
     132                          allRels = self._relations.setdefault(targetType, [ ])
     133                  else:
     134                          for (k, relList) in self._relations.items():
     135                                  for rel in relList:
     136                                          allRels.append(rel)
     137
     138                  # Filter for direction.
     139                  #
     140                  if direction is not None:
     141                          allRels = [r for r in allRels if r.getDirection() == direction]
     142
     143                  # Filter for relation type.
     144                  #
     145                  if relationType is None:
     146                          return allRels
     147                  else:
     148                          allRels = [r for r in allRels if r.getType() == relationType]
     149
     150                  # Now filer for attribute type.
     151                  #
     152                  tmp = []
     153                  required = set(iter(requiredAttributes))
     154
     155                  for r in allRels:
     156                          attrs = set(iter(r.getAttributes()))
     157                          if required.issubset(attrs):
     158                                  tmp.append(r)
     159                  return tmp
     160
     161
     162 -        def getRelationTargets(self, targetType=None, relationType=None,
     163                          requiredAttributes=(), direction=None):
     164                  """Returns a list of relation targets.
     165
     166                  The arguments work exactly like in L{getRelations}, but
     167                  instead of L{Relation} objects, the matching relation
     168                  targets are returned. This can be L{Artist}, L{Release},
     169                  or L{Track} objects, depending on the relations.
     170
     171                  As a special case, URL strings are returned if the target
     172                  is an URL.
     173
     174                  @param targetType: a string containing an absolute URI, or None
     175                  @param relationType: a string containing an absolute URI, or None
     176                  @param requiredAttributes: a sequence containing absolute URIs
     177                  @param direction: one of L{Relation}'s direction constants
     178                  @return: a list of objects, depending on the relation
     179
     180                  @see: L{getRelations}
     181                  """
     182                  ret = [ ]
     183                  rels =  self.getRelations(targetType, relationType,
     184                          requiredAttributes, direction)
     185
     186                  for r in rels:
     187                          if r.getTargetType() == Relation.TO_URL:
     188                                  ret.append(r.getTargetId())
     189                          else:
     190                                  ret.append(r.getTarget())
     191
     192                  return ret
     193
     194
     195 -        def addRelation(self, relation):
     196                  """Adds a relation.
     197
     198                  This method adds C{relation} to the list of relations. The
     199                  given relation has to be initialized, at least the target
     200                  type has to be set.
     201
     202                  @param relation: the L{Relation} object to add
     203
     204                  @see: L{Entity}
     205                  """
     206                  assert relation.getType is not None
     207                  assert relation.getTargetType is not None
     208                  assert relation.getTargetId is not None
     209                  l = self._relations.setdefault(relation.getTargetType(), [ ])
     210                  l.append(relation)
     211
     212
     213 -        def getRelationTargetTypes(self):
     214                  """Returns a list of target types available for this entity.
     215
     216                  Use this to find out to which types of targets this entity
     217                  has relations. If the entity only has relations to tracks and
     218                  artists, for example, then a list containg the strings
     219                  L{Relation.TO_TRACK} and L{Relation.TO_ARTIST} is returned.
     220
     221                  @return: a list of strings containing URIs
     222
     223                  @see: L{getRelations}
     224                  """
     225                  return self._relations.keys()
     226
     227 -        def getTag(self, value):
     228                  """Return the tag with the given value (aka the tag's name).
     229
     230                  @return: the L{Tag} with the given name or raises a KeyError
     231                  """
     232                  return self._tags[value]
     233
     234 -        def getTags(self):
     235                  """Return all tags attached to this Entity.
     236
     237                  @return: a list of L{Tag} objects
     238                  """
     239                  return self._tags.values()
     240
     241          tags = property(getTags, doc='The tags for this entity.')
     242
     243 -        def addTag(self, tag):
     244                  """Add a new tag.
     245
     246                  This merges an existing tag with the same name.
     247
     248                  @param tag: the L{Tag} object to add
     249
     250                  @see: L{getTags}
     251                  """
     252                  if self._tags.has_key(tag.value):
     253                          existing = self._tags[tag.value]
     254                          existing.count += tag.count
     255                  else:
     256                          self._tags[tag.value] = tag
     257
     258 -        def getRating(self):
     259                  """Return the rating of this Entity.
     260                  0 = Unrated
     261                  1 - 5 = Rating
     262
     263                  @return: rating
     264                  """
     265                  return self._rating
     266
     267          rating = property(getRating, doc='The rating for this entity.')
     268
     269 -        def setRating(self, value):
     270                  self._rating = value
     271
     272
     273 -class Artist(Entity):
     274          """Represents an artist.
     275
     276          Artists in MusicBrainz can have a type. Currently, this type can
     277          be either Person or Group for which the following URIs are assigned:
     278
     279           - C{http://musicbrainz.org/ns/mmd-1.0#Person}
     280           - C{http://musicbrainz.org/ns/mmd-1.0#Group}
     281
     282          Use the L{TYPE_PERSON} and L{TYPE_GROUP} constants for comparison.
     283          """
     284          TYPE_PERSON = NS_MMD_1 + 'Person'
     285          TYPE_GROUP = NS_MMD_1 + 'Group'
     286
     287 -        def __init__(self, id_=None, type_=None, name=None, sortName=None):
     288                  """Constructor.
     289
     290                  @param id_: a string containing an absolute URI
     291                  @param type_: a string containing an absolute URI
     292                  @param name: a string containing the artist's name
     293                  @param sortName: a string containing the artist's sort name
     294                  """
     295                  Entity.__init__(self, id_)
     296                  self._type = type_
     297                  self._name = name
     298                  self._sortName = sortName
     299                  self._disambiguation = None
     300                  self._beginDate = None
     301                  self._endDate = None
     302                  self._aliases = [ ]
     303                  self._releases = [ ]
     304                  self._releasesCount = None
     305                  self._releasesOffset = None
     306                  self._releaseGroups = [ ]
     307                  self._releaseGroupsCount = None
     308                  self._releaseGroupsOffset = None
     309
     310 -        def getType(self):
     311                  """Returns the artist's type.
     312
     313                  @return: a string containing an absolute URI, or None
     314                  """
     315                  return self._type
     316
     317 -        def setType(self, type_):
     318                  """Sets the artist's type.
     319
     320                  @param type_: a string containing an absolute URI
     321                  """
     322                  self._type = type_
     323
     324          type = property(getType, setType, doc="The artist's type.")
     325
     326 -        def getName(self):
     327                  """Returns the artist's name.
     328
     329                  @return: a string containing the artist's name, or None
     330                  """
     331                  return self._name
     332
     333 -        def setName(self, name):
     334                  """Sets the artist's name.
     335
     336                  @param name: a string containing the artist's name
     337                  """
     338                  self._name = name
     339
     340          name = property(getName, setName, doc="The artist's name.")
     341
     342 -        def getSortName(self):
     343                  """Returns the artist's sort name.
     344
     345                  The sort name is the artist's name in a special format which
     346                  is better suited for lexicographic sorting. The MusicBrainz
     347                  style guide specifies this format.
     348
     349                  @see: U{The MusicBrainz Style Guidelines
     350                          <http://musicbrainz.org/style.html>}
     351                  """
     352                  return self._sortName
     353
     354 -        def setSortName(self, sortName):
     355                  """Sets the artist's sort name.
     356
     357                  @param sortName: a string containing the artist's sort name
     358
     359                  @see: L{getSortName}
     360                  """
     361                  self._sortName = sortName
     362
     363          sortName = property(getSortName, setSortName,
     364                  doc="The artist's sort name.")
     365
     366 -        def getDisambiguation(self):
     367                  """Returns the disambiguation attribute.
     368
     369                  This attribute may be used if there is more than one artist
     370                  with the same name. In this case, disambiguation attributes
     371                  are added to the artists' names to keep them apart.
     372
     373                  For example, there are at least three bands named 'Vixen'.
     374                  Each band has a different disambiguation in the MusicBrainz
     375                  database, like 'Hip-hop' or 'all-female rock/glam band'.
     376
     377                  @return: a disambiguation string, or None
     378
     379                  @see: L{getUniqueName}
     380                  """
     381                  return self._disambiguation
     382
     383 -        def setDisambiguation(self, disambiguation):
     384                  """Sets the disambiguation attribute.
     385
     386                  @param disambiguation: a disambiguation string
     387
     388                  @see: L{getDisambiguation}, L{getUniqueName}
     389                  """
     390                  self._disambiguation = disambiguation
     391
     392          disambiguation = property(getDisambiguation, setDisambiguation,
     393                  doc="The disambiguation comment.")
     394
     395 -        def getUniqueName(self):
     396                  """Returns a unique artist name (using disambiguation).
     397
     398                  This method returns the artist name together with the
     399                  disambiguation attribute in parenthesis if it exists.
     400                  Example: 'Vixen (Hip-hop)'.
     401
     402                  @return: a string containing the unique name
     403
     404                  @see: L{getDisambiguation}
     405                  """
     406                  d = self.getDisambiguation()
     407                  if d is not None and d.strip() != '':
     408                          return '%s (%s)' % (self.getName(), d)
     409                  else:
     410                          return self.getName()
     411
     412 -        def getBeginDate(self):
     413                  """Returns the birth/foundation date.
     414
     415                  The definition of the I{begin date} depends on the artist's
     416                  type. For persons, this is the day of birth, for groups it
     417                  is the day the group was founded.
     418
     419                  The returned date has the format 'YYYY', 'YYYY-MM', or
     420                  'YYYY-MM-DD', depending on how much detail is known.
     421
     422                  @return: a string containing the date, or None
     423
     424                  @see: L{getType}
     425                  """
     426                  return self._beginDate
     427
     428 -        def setBeginDate(self, dateStr):
     429                  """Sets the begin/foundation date.
     430
     431                  @param dateStr: a date string
     432
     433                  @see: L{getBeginDate}
     434                  """
     435                  self._beginDate = dateStr
     436
     437          beginDate = property(getBeginDate, setBeginDate,
     438                  doc="The begin/foundation date.")
     439
     440 -        def getEndDate(self):
     441                  """Returns the death/dissolving date.
     442
     443                  The definition of the I{end date} depends on the artist's
     444                  type. For persons, this is the day of death, for groups it
     445                  is the day the group was dissolved.
     446
     447                  @return: a string containing a date, or None
     448
     449                  @see: L{getBeginDate}
     450                  """
     451                  return self._endDate
     452
     453 -        def setEndDate(self, dateStr):
     454                  """Sets the death/dissolving date.
     455
     456                  @param dateStr: a string containing a date
     457
     458                  @see: L{setEndDate}, L{getBeginDate}
     459                  """
     460                  self._endDate = dateStr
     461
     462          endDate = property(getEndDate, setEndDate,
     463                  doc="The death/dissolving date.")
     464
     465 -        def getAliases(self):
     466                  """Returns the list of aliases for this artist.
     467
     468                  @return: a list of L{ArtistAlias} objects
     469                  """
     470                  return self._aliases
     471
     472          aliases = property(getAliases, doc='The list of aliases.')
     473
     474 -        def addAlias(self, alias):
     475                  """Adds an alias for this artist.
     476
     477                  @param alias: an L{ArtistAlias} object
     478                  """
     479                  self._aliases.append(alias)
     480
     481 -        def getReleases(self):
     482                  """Returns a list of releases from this artist.
     483
     484                  This may also include releases where this artist isn't the
     485                  I{main} artist but has just contributed one or more tracks
     486                  (aka VA-Releases).
     487
     488                  @return: a list of L{Release} objects
     489                  """
     490                  return self._releases
     491
     492          releases = property(getReleases, doc='The list of releases')
     493
     494 -        def addRelease(self, release):
     495                  """Adds a release to this artist's list of releases.
     496
     497                  @param release: a L{Release} object
     498                  """
     499                  self._releases.append(release)
     500
     501 -        def getReleasesOffset(self):
     502                  """Returns the offset of the release list.
     503
     504                  This is used if the release list is incomplete (ie. the web
     505                  service only returned part of the release for this artist).
     506                  Note that the offset value is zero-based, which means release
     507                  C{0} is the first release.
     508
     509                  @return: an integer containing the offset, or None
     510
     511                  @see: L{getReleases}, L{getReleasesCount}
     512                  """
     513                  return self._releasesOffset
     514
     515 -        def setReleasesOffset(self, offset):
     516                  """Sets the offset of the release list.
     517
     518                  @param offset: an integer containing the offset, or None
     519
     520                  @see: L{getReleasesOffset}
     521                  """
     522                  self._releasesOffset = offset
     523
     524          releasesOffset = property(getReleasesOffset, setReleasesOffset,
     525                  doc='The offset of the release list.')
     526
     527 -        def getReleasesCount(self):
     528                  """Returns the number of existing releases.
     529
     530                  This may or may not match with the number of elements that
     531                  L{getReleases} returns. If the count is higher than
     532                  the list, it indicates that the list is incomplete.
     533
     534                  @return: an integer containing the count, or None
     535
     536                  @see: L{setReleasesCount}, L{getReleasesOffset}
     537                  """
     538                  return self._releasesCount
     539
     540 -        def setReleasesCount(self, value):
     541                  """Sets the number of existing releases.
     542
     543                  @param value: an integer containing the count, or None
     544
     545                  @see: L{getReleasesCount}, L{setReleasesOffset}
     546                  """
     547                  self._releasesCount = value
     548
     549          releasesCount = property(getReleasesCount, setReleasesCount,
     550                  doc='The total number of releases')
     551
     552 -        def getReleaseGroups(self):
     553                  """Returns a list of release groups from this artist.
     554
     555                  @return: a list of L{ReleaseGroup} objects
     556                  """
     557                  return self._releaseGroups
     558
     559          releaseGroups = property(getReleaseGroups, doc='The list of release groups')
     560
     561 -        def addReleaseGroup(self, releaseGroup):
     562                  """Adds a release group to this artist's list of release groups.
     563
     564                  @param releaseGroup: a L{ReleaseGroup} object
     565                  """
     566                  self._releaseGroups.append(releaseGroup)
     567
     568 -        def getReleaseGroupsOffset(self):
     569                  """Returns the offset of the release group list.
     570
     571                  This is used if the release group list is incomplete (ie. the
     572                  web service only returned part of the result for this artist).
     573                  Note that the offset value is zero-based, which means release
     574                  group C{0} is the first release group.
     575
     576                  @return: an integer containing the offset, or None
     577
     578                  @see: L{getReleaseGroups}, L{getReleaseGroupsCount}
     579                  """
     580                  return self._releaseGroupsOffset
     581
     582 -        def setReleaseGroupsOffset(self, offset):
     583                  """Sets the offset of the release group list.
     584
     585                  @param offset: an integer containing the offset, or None
     586
     587                  @see: L{getReleaseGroupsOffset}
     588                  """
     589                  self._releaseGroupsOffset = offset
     590
     591          releaseGroupsOffset = property(getReleaseGroupsOffset, setReleaseGroupsOffset,
     592                  doc='The offset of the release group list.')
     593
     594 -        def getReleaseGroupsCount(self):
     595                  """Returns the number of existing release groups.
     596
     597                  This may or may not match with the number of elements that
     598                  L{getReleaseGroups} returns. If the count is higher than
     599                  the list, it indicates that the list is incomplete.
     600
     601                  @return: an integer containing the count, or None
     602
     603                  @see: L{setReleaseGroupsCount}, L{getReleaseGroupsOffset}
     604                  """
     605                  return self._releaseGroupsCount
     606
     607 -        def setReleaseGroupsCount(self, value):
     608                  """Sets the number of existing release groups.
     609
     610                  @param value: an integer containing the count, or None
     611
     612                  @see: L{getReleaseGroupsCount}, L{setReleaseGroupsOffset}
     613                  """
     614                  self._releaseGroupsCount = value
     615
     616          releasesCount = property(getReleaseGroupsCount, setReleaseGroupsCount,
     617                  doc='The total number of release groups')
     618
     619
     620 -class Rating(object):
     621          """The representation of a MusicBrain rating.
     622
     623          The rating can have the following values:
     624
     625          0 = Unrated
     626          [1..5] = Rating
     627          """
     628 -        def __init__(self, value=None, count=None):
     629                  """Constructor.
     630
     631                  @param value: a string containing the tag's value
     632                  @param count: the number of users who added this tag
     633                  """
     634                  self._value = value
     635                  self._count = count
     636
     637 -        def getValue(self):
     638                  """Returns a string with the tag's value.
     639
     640                  @return: an integer containing the rating's value, or None
     641                  """
     642                  return self._value
     643
     644 -        def setValue(self, value):
     645                  """ Set the value of this rating.
     646
     647                  0 or None = Clear your rating
     648                  1 - 5 = Rating
     649
     650                  @param value: the rating to apply
     651
     652                  @raise ValueError: if value is not a double or not in the
     653                  range 0 - 5 or None.
     654                  """
     655                  if value == None:
     656                    value = 0
     657                  try:
     658                    value = float(value)
     659                  except ValueError, e:
     660                    raise ValueError("Value for rating needs to be an" \
     661                        "float.")
     662                  if value < 0.0 or value > 5.0:
     663                    raise ValueError("Value needs to be in the range [0..5]")
     664                  self._value = value
     665
     666          value = property(getValue, setValue, doc='The value of the rating.')
     667
     668 -        def getCount(self):
     669                  """Returns an integer containing the rating's frequency count.
     670
     671                  @return: an integer containing the rating's frequency count,
     672                  or None
     673                  """
     674                  return self._count
     675
     676 -        def setCount(self, count):
     677                  """Sets the frequency count of this rating.
     678
     679                  @param count: an integer containing the tag's frequency count
     680                  """
     681                  self._count = count
     682
     683          count = property(getCount, setCount, doc="This tag's frequency count.")
     684
     685 -        def __str__(self):
     686                  return str(self._value)
     687
     688 -        def __unicode__(self):
     689                  return unicode(self._value)
     690
     691
     692 -class Tag(object):
     693          """The representation of a MusicBrainz folksonomy tag.
     694
     695          The tag's value is the text that's displayed in the tag cloud.
     696          The count attribute keeps track of how many users added the tag
     697          to its owning entity.
     698          """
     699 -        def __init__(self, value=None, count=None):
     700                  """Constructor.
     701
     702                  @param value: a string containing the tag's value
     703                  @param count: the number of users who added this tag
     704                  """
     705                  self._value = value
     706                  self._count = count
     707
     708 -        def getValue(self):
     709                  """Returns a string with the tag's value.
     710
     711                  @return: a string containing the tags's value, or None
     712                  """
     713                  return self._value
     714
     715 -        def setValue(self, value):
     716                  """Sets the value of this tag.
     717
     718                  @param value: A string containing the value of the tag
     719                  """
     720                  self._value = value
     721
     722          value = property(getValue, setValue, doc='The value of the text.')
     723
     724 -        def getCount(self):
     725                  """Returns an integer containing the tag's frequency count.
     726
     727                  @return: an integer containing the tags's frequency count, or None
     728                  """
     729                  return self._count
     730
     731 -        def setCount(self, count):
     732                  """Sets the frequency count of this tag.
     733
     734                  @param count: an integer containing the tag's frequency count
     735                  """
     736                  self._count = count
     737
     738          count = property(getCount, setCount, doc="This tag's frequency count.")
     739
     740 -        def __str__(self):
     741                  return str(self._value)
     742
     743 -        def __unicode__(self):
     744                  return unicode(self._value)
     745
     746
     747 -class Label(Entity):
     748          """Represents a record label.
     749
     750          A label within MusicBrainz is an L{Entity}. It contains information
     751          about the label like when it was established, its name, label code and
     752          other relationships. All release events may be assigned a label.
     753          """
     754          TYPE_UNKNOWN = NS_MMD_1 + 'Unknown'
     755
     756          TYPE_DISTRIBUTOR = NS_MMD_1 + 'Distributor'
     757          TYPE_HOLDING = NS_MMD_1 + 'Holding'
     758          TYPE_PRODUCTION = NS_MMD_1 + 'Production'
     759
     760          TYPE_ORIGINAL = NS_MMD_1 + 'OriginalProduction'
     761          TYPE_BOOTLEG = NS_MMD_1 + 'BootlegProduction'
     762          TYPE_REISSUE = NS_MMD_1 + 'ReissueProduction'
     763
     764 -        def __init__(self, id_=None):
     765                  """Constructor.
     766
     767                  @param id_: a string containing an absolute URI
     768                  """
     769                  Entity.__init__(self, id_)
     770                  self._type = None
     771                  self._name = None
     772                  self._sortName = None
     773                  self._disambiguation = None
     774                  self._countryId = None
     775                  self._code = None
     776                  self._beginDate = None
     777                  self._endDate = None
     778                  self._aliases = [ ]
     779
     780 -        def getType(self):
     781                  """Returns the type of this label.
     782
     783                  @return: a string containing an absolute URI
     784                  """
     785                  return self._type
     786
     787 -        def setType(self, type_):
     788                  """Sets the type of this label.
     789
     790                  @param type_: A string containing the absolute URI of the type of label.
     791                  """
     792                  self._type = type_
     793
     794          type = property(getType, setType, doc='The type of label')
     795
     796 -        def getName(self):
     797                  """Returns a string with the name of the label.
     798
     799                  @return: a string containing the label's name, or None
     800                  """
     801                  return self._name
     802
     803 -        def setName(self, name):
     804                  """Sets the name of this label.
     805
     806                  @param name: A string containing the name of the label
     807                  """
     808                  self._name = name
     809
     810          name = property(getName, setName, doc='The name of the label.')
     811
     812 -        def getSortName(self):
     813                  """Returns the label's sort name.
     814
     815                  The sort name is the label's name in a special format which
     816                  is better suited for lexicographic sorting. The MusicBrainz
     817                  style guide specifies this format.
     818
     819                  @see: U{The MusicBrainz Style Guidelines
     820                          <http://musicbrainz.org/style.html>}
     821                  """
     822                  return self._sortName
     823
     824 -        def setSortName(self, sortName):
     825                  """Sets the label's sort name.
     826
     827                  @param sortName: a string containing the label's sort name
     828
     829                  @see: L{getSortName}
     830                  """
     831                  self._sortName = sortName
     832
     833          sortName = property(getSortName, setSortName,
     834                  doc="The label's sort name.")
     835
     836 -        def getDisambiguation(self):
     837                  """Returns the disambiguation attribute.
     838
     839                  This attribute may be used if there is more than one label
     840                  with the same name. In this case, disambiguation attributes
     841                  are added to the labels' names to keep them apart.
     842
     843                  @return: a disambiguation string, or None
     844
     845                  @see: L{getUniqueName}
     846                  """
     847                  return self._disambiguation
     848
     849 -        def setDisambiguation(self, disambiguation):
     850                  """Sets the disambiguation attribute.
     851
     852                  @param disambiguation: a disambiguation string
     853
     854                  @see: L{getDisambiguation}, L{getUniqueName}
     855                  """
     856                  self._disambiguation = disambiguation
     857
     858          disambiguation = property(getDisambiguation, setDisambiguation,
     859                  doc="The disambiguation comment.")
     860
     861 -        def getUniqueName(self):
     862                  """Returns a unique label name (using disambiguation).
     863
     864                  This method returns the label's name together with the
     865                  disambiguation attribute in parenthesis if it exists.
     866
     867                  @return: a string containing the unique name
     868
     869                  @see: L{getDisambiguation}
     870                  """
     871                  d = self.getDisambiguation()
     872                  if d is not None and d.strip() != '':
     873                          return '%s (%s)' % (self.getName(), d)
     874                  else:
     875                          return self.getName()
     876
     877 -        def getBeginDate(self):
     878                  """Returns the date this label was established.
     879
     880                  @return: A string contained the start date, or None
     881                  """
     882                  return self._beginDate
     883
     884 -        def setBeginDate(self, date):
     885                  """Set the date this label was established.
     886
     887                  @param date: A string in the format of YYYY-MM-DD
     888                  """
     889                  self._beginDate = date
     890
     891          beginDate = property(getBeginDate, setBeginDate,
     892                  doc='The date this label was established.')
     893
     894 -        def getEndDate(self):
     895                  """Returns the date this label closed.
     896
     897                  The returned date has the format 'YYYY', 'YYYY-MM', or
     898                  'YYYY-MM-DD', depending on how much detail is known.
     899
     900                  @return: A string containing the date, or None
     901                  """
     902                  return self._endDate
     903
     904 -        def setEndDate(self, date):
     905                  """Set the date this label closed.
     906
     907                  The date may have the format 'YYYY', 'YYYY-MM', or
     908                  'YYYY-MM-DD', depending on how much detail is known.
     909
     910                  @param date: A string containing the date, or None
     911                  """
     912                  self._endDate = date
     913
     914          endDate = property(getEndDate, setEndDate,
     915                  doc='The date this label closed.')
     916
     917 -        def getCountry(self):
     918                  """Returns the country the label is located.
     919
     920                  @return: a string containing an ISO-3166 country code, or None
     921
     922                  @see: L{musicbrainz2.utils.getCountryName}
     923                  """
     924                  return self._countryId
     925
     926 -        def setCountry(self, country):
     927                  """Sets the country the label is located.
     928
     929                  @param country: a string containing an ISO-3166 country code
     930                  """
     931                  self._countryId = country
     932
     933          country = property(getCountry, setCountry,
     934                  doc='The country the label is located.')
     935
     936 -        def getCode(self):
     937                  """Returns the label code.
     938
     939                  Label codes have been introduced by the IFPI (International
     940                  Federation of Phonogram and Videogram Industries) to uniquely
     941                  identify record labels. The label code consists of 'LC-' and 4
     942                  figures (currently being extended to 5 figures).
     943
     944                  @return: a string containing the label code, or None
     945                  """
     946                  return self._code
     947
     948 -        def setCode(self, code):
     949                  """Sets the label code.
     950
     951                  @param code: a string containing the label code
     952                  """
     953                  self._code = code
     954
     955          code = property(getCode, setCode,
     956                  doc='The label code.')
     957
     958 -        def getAliases(self):
     959                  """Returns the list of aliases for this label.
     960
     961                  @return: a list of L{LabelAlias} objects
     962                  """
     963                  return self._aliases
     964
     965          aliases = property(getAliases, doc='The list of aliases.')
     966
     967 -        def addAlias(self, alias):
     968                  """Adds an alias for this label.
     969
     970                  @param alias: a L{LabelAlias} object
     971                  """
     972                  self._aliases.append(alias)
     973
     974
     975 -class Release(Entity):
     976          """Represents a Release.
     977
     978          A release within MusicBrainz is an L{Entity} which contains L{Track}
     979          objects.  Releases may be of more than one type: There can be albums,
     980          singles, compilations, live recordings, official releases, bootlegs
     981          etc.
     982
     983          @note: The current MusicBrainz server implementation supports only a
     984          limited set of types.
     985          """
     986          TYPE_NONE = NS_MMD_1 + 'None'
     987          TYPE_NON_ALBUM_TRACKS = NS_MMD_1 + "NonAlbum Track"
     988
     989          TYPE_ALBUM = NS_MMD_1 + 'Album'
     990          TYPE_SINGLE = NS_MMD_1 + 'Single'
     991          TYPE_EP = NS_MMD_1 + 'EP'
     992          TYPE_COMPILATION = NS_MMD_1 + 'Compilation'
     993          TYPE_SOUNDTRACK = NS_MMD_1 + 'Soundtrack'
     994          TYPE_SPOKENWORD = NS_MMD_1 + 'Spokenword'
     995          TYPE_INTERVIEW = NS_MMD_1 + 'Interview'
     996          TYPE_AUDIOBOOK = NS_MMD_1 + 'Audiobook'
     997          TYPE_LIVE = NS_MMD_1 + 'Live'
     998          TYPE_REMIX = NS_MMD_1 + 'Remix'
     999          TYPE_OTHER = NS_MMD_1 + 'Other'
    1000
    1001          TYPE_OFFICIAL = NS_MMD_1 + 'Official'
    1002          TYPE_PROMOTION = NS_MMD_1 + 'Promotion'
    1003          TYPE_BOOTLEG = NS_MMD_1 + 'Bootleg'
    1004          TYPE_PSEUDO_RELEASE = NS_MMD_1 + 'Pseudo-Release'
    1005
    1006 -        def __init__(self, id_=None, title=None):
    1007                  """Constructor.
    1008
    1009                  @param id_: a string containing an absolute URI
    1010                  @param title: a string containing the title
    1011                  """
    1012                  Entity.__init__(self, id_)
    1013                  self._types = [ ]
    1014                  self._title = title
    1015                  self._textLanguage = None
    1016                  self._textScript = None
    1017                  self._asin = None
    1018                  self._artist = None
    1019                  self._releaseEvents = [ ]
    1020                  #self._releaseEventsCount = None
    1021                  self._releaseGroup = None
    1022                  self._discs = [ ]
    1023                  #self._discIdsCount = None
    1024                  self._tracks = [ ]
    1025                  self._tracksOffset = None
    1026                  self._tracksCount = None
    1027
    1028
    1029 -        def getTypes(self):
    1030                  """Returns the types of this release.
    1031
    1032                  To test for release types, you can use the constants
    1033                  L{TYPE_ALBUM}, L{TYPE_SINGLE}, etc.
    1034
    1035                  @return: a list of strings containing absolute URIs
    1036
    1037                  @see: L{musicbrainz2.utils.getReleaseTypeName}
    1038                  """
    1039                  return self._types
    1040
    1041          types = property(getTypes, doc='The list of types for this release.')
    1042
    1043 -        def addType(self, type_):
    1044                  """Add a type to the list of types.
    1045
    1046                  @param type_: a string containing absolute URIs
    1047
    1048                  @see: L{getTypes}
    1049                  """
    1050                  self._types.append(type_)
    1051
    1052 -        def getTitle(self):
    1053                  """Returns the release's title.
    1054
    1055                  @return: a string containing the release's title
    1056                  """
    1057                  return self._title
    1058
    1059 -        def setTitle(self, title):
    1060                  """Sets the release's title.
    1061
    1062                  @param title: a string containing the release's title, or None
    1063                  """
    1064                  self._title = title
    1065
    1066          title = property(getTitle, setTitle, doc='The title of this release.')
    1067
    1068 -        def getTextLanguage(self):
    1069                  """Returns the language used in release and track titles.
    1070
    1071                  To represent the language, the ISO-639-2/T standard is used,
    1072                  which provides three-letter terminological language codes like
    1073                  'ENG', 'DEU', 'JPN', 'KOR', 'ZHO' or 'YID'.
    1074
    1075                  Note that this refers to release and track I{titles}, not
    1076                  lyrics.
    1077
    1078                  @return: a string containing the language code, or None
    1079
    1080                  @see: L{musicbrainz2.utils.getLanguageName}
    1081                  """
    1082                  return self._textLanguage
    1083
    1084 -        def setTextLanguage(self, language):
    1085                  """Sets the language used in releaes and track titles.
    1086
    1087                  @param language: a string containing a language code
    1088
    1089                  @see: L{getTextLanguage}
    1090                  """
    1091                  self._textLanguage = language
    1092
    1093          textLanguage = property(getTextLanguage, setTextLanguage,
    1094                  doc='The language used in release and track titles.')
    1095
    1096 -        def getTextScript(self):
    1097                  """Returns the script used in release and track titles.
    1098
    1099                  To represent the script, ISO-15924 script codes are used.
    1100                  Valid codes are, among others: 'Latn', 'Cyrl', 'Hans', 'Hebr'
    1101
    1102                  Note that this refers to release and track I{titles}, not
    1103                  lyrics.
    1104
    1105                  @return: a string containing the script code, or None
    1106
    1107                  @see: L{musicbrainz2.utils.getScriptName}
    1108                  """
    1109                  return self._textScript
    1110
    1111 -        def setTextScript(self, script):
    1112                  """Sets the script used in releaes and track titles.
    1113
    1114                  @param script: a string containing a script code
    1115
    1116                  @see: L{getTextScript}
    1117                  """
    1118                  self._textScript = script
    1119
    1120          textScript = property(getTextScript, setTextScript,
    1121                  doc='The script used in release and track titles.')
    1122
    1123 -        def getAsin(self):
    1124                  """Returns the amazon shop identifier (ASIN).
    1125
    1126                  The ASIN is a 10-letter code (except for books) assigned
    1127                  by Amazon, which looks like 'B000002IT2' or 'B00006I4YD'.
    1128
    1129                  @return: a string containing the ASIN, or None
    1130                  """
    1131                  return self._asin
    1132
    1133 -        def setAsin(self, asin):
    1134                  """Sets the amazon shop identifier (ASIN).
    1135
    1136                  @param asin: a string containing the ASIN
    1137
    1138                  @see: L{getAsin}
    1139                  """
    1140                  self._asin = asin
    1141
    1142          asin = property(getAsin, setAsin, doc='The amazon shop identifier.')
    1143
    1144 -        def getArtist(self):
    1145                  """Returns the main artist of this release.
    1146
    1147                  @return: an L{Artist} object, or None
    1148                  """
    1149                  return self._artist
    1150
    1151 -        def setArtist(self, artist):
    1152                  """Sets this release's main artist.
    1153
    1154                  @param artist: an L{Artist} object
    1155                  """
    1156                  self._artist = artist
    1157
    1158          artist = property(getArtist, setArtist,
    1159                  doc='The main artist of this release.')
    1160
    1161 -        def getReleaseGroup(self):
    1162                  """Returns the release group to which this release belongs.
    1163
    1164                  @return: a L{ReleaseGroup} object, or None.
    1165                  """
    1166                  return self._releaseGroup
    1167
    1168 -        def setReleaseGroup(self, releaseGroup):
    1169                  """Sets the release's release group.
    1170
    1171                  @param releaseGroup: a L{ReleaseGroup} object, or None.
    1172                  """
    1173                  self._releaseGroup = releaseGroup
    1174
    1175          releaseGroup = property(getReleaseGroup, setReleaseGroup,
    1176                  doc='The release group this release belongs to.')
    1177
    1178 -        def isSingleArtistRelease(self):
    1179                  """Checks if this is a single artist's release.
    1180
    1181                  Returns C{True} if the release's main artist (L{getArtist}) is
    1182                  also the main artist for all of the tracks. This is checked by
    1183                  comparing the artist IDs.
    1184
    1185                  Note that the release's artist has to be set (see L{setArtist})
    1186                  for this. The track artists may be unset.
    1187
    1188                  @return: True, if this is a single artist's release
    1189                  """
    1190                  releaseArtist = self.getArtist()
    1191                  assert releaseArtist is not None, 'Release Artist may not be None!'
    1192                  for track in self.getTracks():
    1193                          if track.getArtist() is None:
    1194                                  continue
    1195                          if track.getArtist().getId() != releaseArtist.getId():
    1196                                  return False
    1197
    1198                  return True
    1199
    1200 -        def getTracks(self):
    1201                  """Returns the tracks this release contains.
    1202
    1203                  @return: a list containing L{Track} objects
    1204
    1205                  @see: L{getTracksOffset}, L{getTracksCount}
    1206                  """
    1207                  return self._tracks
    1208
    1209          tracks = property(getTracks, doc='The list of tracks.')
    1210
    1211 -        def addTrack(self, track):
    1212                  """Adds a track to this release.
    1213
    1214                  This appends a track at the end of this release's track list.
    1215
    1216                  @param track: a L{Track} object
    1217                  """
    1218                  self._tracks.append(track)
    1219
    1220 -        def getTracksOffset(self):
    1221                  """Returns the offset of the track list.
    1222
    1223                  This is used if the track list is incomplete (ie. the web
    1224                  service only returned part of the tracks on this release).
    1225                  Note that the offset value is zero-based, which means track
    1226                  C{0} is the first track.
    1227
    1228                  @return: an integer containing the offset, or None
    1229
    1230                  @see: L{getTracks}, L{getTracksCount}
    1231                  """
    1232                  return self._tracksOffset
    1233
    1234 -        def setTracksOffset(self, offset):
    1235                  """Sets the offset of the track list.
    1236
    1237                  @param offset: an integer containing the offset, or None
    1238
    1239                  @see: L{getTracksOffset}, L{setTracksCount}
    1240                  """
    1241                  self._tracksOffset = offset
    1242
    1243          tracksOffset = property(getTracksOffset, setTracksOffset,
    1244                  doc='The offset of the track list.')
    1245
    1246 -        def getTracksCount(self):
    1247                  """Returns the number of tracks on this release.
    1248
    1249                  This may or may not match with the number of elements that
    1250                  L{getTracks} returns. If the count is higher than
    1251                  the list, it indicates that the list is incomplete.
    1252
    1253                  @return: an integer containing the count, or None
    1254
    1255                  @see: L{setTracksCount}, L{getTracks}, L{getTracksOffset}
    1256                  """
    1257                  return self._tracksCount
    1258
    1259 -        def setTracksCount(self, value):
    1260                  """Sets the number of tracks on this release.
    1261
    1262                  @param value: an integer containing the count, or None
    1263
    1264                  @see: L{getTracksCount}, L{setTracksOffset}
    1265                  """
    1266                  self._tracksCount = value
    1267
    1268          tracksCount = property(getTracksCount, setTracksCount,
    1269                  doc='The total number of releases')
    1270
    1271
    1272 -        def getReleaseEvents(self):
    1273                  """Returns the list of release events.
    1274
    1275                  A L{Release} may contain a list of so-called release events,
    1276                  each represented using a L{ReleaseEvent} object. Release
    1277                  evens specify where and when this release was, well, released.
    1278
    1279                  @return: a list of L{ReleaseEvent} objects
    1280
    1281                  @see: L{getReleaseEventsAsDict}
    1282                  """
    1283                  return self._releaseEvents
    1284
    1285          releaseEvents = property(getReleaseEvents,
    1286                  doc='The list of release events.')
    1287
    1288 -        def addReleaseEvent(self, event):
    1289                  """Adds a release event to this release.
    1290
    1291                  @param event: a L{ReleaseEvent} object
    1292
    1293                  @see: L{getReleaseEvents}
    1294                  """
    1295                  self._releaseEvents.append(event)
    1296
    1297 -        def getReleaseEventsAsDict(self):
    1298                  """Returns the release events represented as a dict.
    1299
    1300                  Keys are ISO-3166 country codes like 'DE', 'UK', 'FR' etc.
    1301                  Values are dates in 'YYYY', 'YYYY-MM' or 'YYYY-MM-DD' format.
    1302
    1303                  @return: a dict containing (countryCode, date) entries
    1304
    1305                  @see: L{getReleaseEvents}, L{musicbrainz2.utils.getCountryName}
    1306                  """
    1307                  d = { }
    1308                  for event in self.getReleaseEvents():
    1309                          d[event.getCountry()] = event.getDate()
    1310                  return d
    1311
    1312 -        def getEarliestReleaseDate(self):
    1313                  """Returns the earliest release date.
    1314
    1315                  This favours complete dates. For example, '2006-09' is
    1316                  returned if there is '2000', too. If there is no release
    1317                  event associated with this release, None is returned.
    1318
    1319                  @return: a string containing the date, or None
    1320
    1321                  @see: L{getReleaseEvents}, L{getReleaseEventsAsDict}
    1322                  """
    1323                  event = self.getEarliestReleaseEvent()
    1324
    1325                  if event is None:
    1326                          return None
    1327                  else:
    1328                          return event.getDate()
    1329
    1330 -        def getEarliestReleaseEvent(self):
    1331                  """Returns the earliest release event.
    1332
    1333                  This works like L{getEarliestReleaseDate}, but instead of
    1334                  just the date, this returns a L{ReleaseEvent} object.
    1335
    1336                  @return: a L{ReleaseEvent} object, or None
    1337
    1338                  @see: L{getReleaseEvents}, L{getEarliestReleaseDate}
    1339                  """
    1340                  dates = [ ]
    1341                  for event in self.getReleaseEvents():
    1342                          date = event.getDate()
    1343                          if len(date) == 10:    # 'YYYY-MM-DD'
    1344                                  dates.append( (date, event) )
    1345                          elif len(date) == 7:   # 'YYYY-MM'
    1346                                  dates.append( (date + '-99', event) )
    1347                          else:
    1348                                  dates.append( (date + '-99-99', event) )
    1349
    1350                  dates.sort(lambda x, y: cmp(x[0], y[0]))
    1351
    1352                  if len(dates) > 0:
    1353                          return dates[0][1]
    1354                  else:
    1355                          return None
    1356
    1357
    1358          #def getReleaseEventsCount(self):
    1359          #       """Returns the number of release events.
    1360          #
    1361          #       This may or may not match with the number of elements that
    1362          #       getReleaseEvents() returns. If the count is higher than
    1363          #       the list, it indicates that the list is incomplete.
    1364          #       """
    1365          #       return self._releaseEventsCount
    1366
    1367          #def setReleaseEventsCount(self, value):
    1368          #       self._releaseEventsCount = value
    1369
    1370 -        def getDiscs(self):
    1371                  """Returns the discs associated with this release.
    1372
    1373                  Discs are currently containers for MusicBrainz DiscIDs.
    1374                  Note that under rare circumstances (identical TOCs), a
    1375                  DiscID could be associated with more than one release.
    1376
    1377                  @return: a list of L{Disc} objects
    1378                  """
    1379                  return self._discs
    1380
    1381          discs = property(getDiscs, doc='The list of associated discs.')
    1382
    1383 -        def addDisc(self, disc):
    1384                  """Adds a disc to this release.
    1385
    1386                  @param disc: a L{Disc} object
    1387                  """
    1388                  self._discs.append(disc)
    1389
    1390          #def getDiscIdsCount(self):
    1391          #       return self._discIdsCount
    1392
    1393          #def setDiscIdsCount(self, value):
    1394          #       self._discIdsCount = value
    1395
    1396
    1397 -class ReleaseGroup(Entity):
    1398          """Represents a ReleaseGroup.
    1399
    1400          A ReleaseGroup in MusicBrainz is an L{Entity} which groups several different
    1401          versions of L{Release} objects (e.g., different editions of the same album).
    1402
    1403          @see: L{Release}
    1404          @see: L{Entity}
    1405          """
    1406
    1407 -        def __init__(self, id_=None, title=None):
    1408                  """Constructor.
    1409
    1410                  @param id_: a string containing an absolute URI
    1411                  @param title: a string containing the title
    1412                  """
    1413                  Entity.__init__(self, id_)
    1414                  self._title = title
    1415                  self._id = id_
    1416                  self._type = None
    1417                  self._releases = [ ]
    1418                  self._artist = None
    1419                  self._releasesOffset = 0
    1420                  self._releasesCount = 0
    1421
    1422 -        def getType(self):
    1423                  """Returns the type of this release group.
    1424
    1425                  To test for release types, you can use the constants
    1426                  L{Release.TYPE_ALBUM}, L{Release.TYPE_SINGLE}, etc.
    1427
    1428                  @return: a string containing an absolute URI, or None.
    1429
    1430                  @see: L{musicbrainz2.utils.getReleaseTypeName}
    1431                  """
    1432                  return self._type
    1433
    1434 -        def setType(self, type_):
    1435                  """Sets the type of this release group.
    1436
    1437                  Use a constant from the L{Release} class, such as
    1438                  L{Release.TYPE_ALBUM} or L{Release.TYPE_SINGLE} to
    1439                  set the value.
    1440
    1441                  @param type_: a string containing an absolute URI, or None.
    1442
    1443                  @see: L{musicbrainz2.utils.getReleaseTypeName}
    1444                  """
    1445                  self._type = type_
    1446
    1447          type = property(getType, setType,
    1448                  doc = 'The type of this release group.')
    1449
    1450 -        def getReleases(self):
    1451                  """Gets the releases in this release group.
    1452
    1453                  @return: a list of L{Release} objects
    1454                  @see: L{Release}
    1455                  """
    1456                  return self._releases
    1457
    1458          releases = property(getReleases,
    1459                  doc = 'The list of releases in this release group.')
    1460
    1461 -        def addRelease(self, release):
    1462                  """Adds a L{Release} to this release group.
    1463
    1464                  @param release: a L{Release} object
    1465                  """
    1466                  self._releases.append(release)
    1467
    1468 -        def getReleasesOffset(self):
    1469                  """Returns the offset of the release list.
    1470
    1471                  This is used if the release list is incomplete (i.e., the web
    1472                  service only returned a portion of the releases in this release
    1473                  group).
    1474
    1475                  @return: an integer containing the offset, or None.
    1476                  @see: L{getReleases}, L{getReleasesCount}
    1477                  """
    1478                  return self._releasesOffset
    1479
    1480 -        def setReleasesOffset(self, offset):
    1481                  """Sets the offset of the release list.
    1482
    1483                  @param offset: an integer containing the offset, or None.
    1484                  @see: L{getReleases}, L{getReleasesOffset}
    1485                  """
    1486                  self._releasesOffset = offset
    1487
    1488          releasesOffset = property(getReleasesOffset, setReleasesOffset,
    1489                  doc='The offset of the release list.')
    1490
    1491 -        def getReleasesCount(self):
    1492                  """Returns the number of releases in this release group.
    1493
    1494                  This may or may not match the number of elements returned by
    1495                  L{getReleases}.  If the count is higher than the length of that
    1496                  list, then the list is incomplete.
    1497
    1498                  @return: an integer containing the count, or None
    1499                  @see: L{getReleases}, L{setReleasesCount}, L{getReleasesOffset}
    1500                  """
    1501                  return self._releasesCount
    1502
    1503 -        def setReleasesCount(self, value):
    1504                  """Sets the number of releases in this release group.
    1505
    1506                  @param value: an integer containing the count, or None.
    1507                  @see: L{getReleases}, L{getReleasesCount}, L{getReleasesOffset}
    1508                  """
    1509                  self._releasesCount = value
    1510
    1511          releasesCount = property(getReleasesCount, setReleasesCount,
    1512                  doc = 'The total number of releases')
    1513
    1514 -        def getTitle(self):
    1515                  """Returns this release group's title.
    1516
    1517                  @return: a string containing the release group's title
    1518                  """
    1519                  return self._title
    1520
    1521 -        def setTitle(self, title):
    1522                  """Sets the release group's title.
    1523
    1524                  @param title: a string containing the release group's title.
    1525                  """
    1526                  self._title = title
    1527
    1528          title = property(getTitle, setTitle,
    1529                  doc = 'The title of this release group.')
    1530
    1531 -        def getArtist(self):
    1532                  """Returns the main artist of this release group.
    1533
    1534                  @return: an L{Artist} object, or None
    1535                  """
    1536                  return self._artist
    1537
    1538 -        def setArtist(self, artist):
    1539                  """Sets the release group's main artist.
    1540
    1541                  @param artist: an L{Artist} object
    1542                  """
    1543                  self._artist = artist
    1544
    1545          artist = property(getArtist, setArtist,
    1546                  doc = 'The main artist of this release group')
    1547
    1548
    1549 -class Track(Entity):
    1550          """Represents a track.
    1551
    1552          This class represents a track which may appear on one or more releases.
    1553          A track may be associated with exactly one artist (the I{main} artist).
    1554
    1555          Using L{getReleases}, you can find out on which releases this track
    1556          appears. To get the track number, too, use the
    1557          L{Release.getTracksOffset} method.
    1558
    1559          @note: Currently, the MusicBrainz server doesn't support tracks to
    1560                 be on more than one release.
    1561
    1562          @see: L{Release}, L{Artist}
    1563          """
    1564 -        def __init__(self, id_=None, title=None):
    1565                  """Constructor.
    1566
    1567                  @param id_: a string containing an absolute URI
    1568                  @param title: a string containing the title
    1569                  """
    1570                  Entity.__init__(self, id_)
    1571                  self._title = title
    1572                  self._artist = None
    1573                  self._duration = None
    1574                  self._puids = [ ]
    1575                  self._releases = [ ]
    1576                  self._isrcs = [ ]
    1577
    1578 -        def getTitle(self):
    1579                  """Returns the track's title.
    1580
    1581                  The style and format of this attribute is specified by the
    1582                  style guide.
    1583
    1584                  @return: a string containing the title, or None
    1585
    1586                  @see: U{The MusicBrainz Style Guidelines
    1587                          <http://musicbrainz.org/style.html>}
    1588                  """
    1589                  return self._title
    1590
    1591 -        def setTitle(self, title):
    1592                  """Sets the track's title.
    1593
    1594                  @param title: a string containing the title
    1595
    1596                  @see: L{getTitle}
    1597                  """
    1598                  self._title = title
    1599
    1600          title = property(getTitle, setTitle, doc="The track's title.")
    1601
    1602 -        def getArtist(self):
    1603                  """Returns the main artist of this track.
    1604
    1605                  @return: an L{Artist} object, or None
    1606                  """
    1607                  return self._artist
    1608
    1609 -        def setArtist(self, artist):
    1610                  """Sets this track's main artist.
    1611
    1612                  @param artist: an L{Artist} object
    1613                  """
    1614                  self._artist = artist
    1615
    1616          artist = property(getArtist, setArtist, doc="The track's main artist.")
    1617
    1618 -        def getDuration(self):
    1619                  """Returns the duration of this track in milliseconds.
    1620
    1621                  @return: an int containing the duration in milliseconds, or None
    1622                  """
    1623                  return self._duration
    1624
    1625 -        def setDuration(self, duration):
    1626                  """Sets the duration of this track in milliseconds.
    1627
    1628                  @param duration: an int containing the duration in milliseconds
    1629                  """
    1630                  self._duration = duration
    1631
    1632          duration = property(getDuration, setDuration,
    1633                  doc='The duration in milliseconds.')
    1634
    1635 -        def getDurationSplit(self):
    1636                  """Returns the duration as a (minutes, seconds) tuple.
    1637
    1638                  If no duration is set, (0, 0) is returned. Seconds are
    1639                  rounded towards the ceiling if at least 500 milliseconds
    1640                  are left.
    1641
    1642                  @return: a (minutes, seconds) tuple, both entries being ints
    1643                  """
    1644                  duration = self.getDuration()
    1645                  if duration is None:
    1646                          return (0, 0)
    1647                  else:
    1648                          seconds = int( round(duration / 1000.0) )
    1649                          return (seconds / 60, seconds % 60)
    1650
    1651 -        def getPuids(self):
    1652                  """Returns the PUIDs associated with this track.
    1653
    1654                  Please note that a PUID may be associated with more than one
    1655                  track.
    1656
    1657                  @return: a list of strings, each containing one PUID
    1658                  """
    1659                  return self._puids
    1660
    1661          puids = property(getPuids, doc='The list of associated PUIDs.')
    1662
    1663 -        def addPuid(self, puid):
    1664                  """Add a PUID to this track.
    1665
    1666                  @param puid: a string containing a PUID
    1667                  """
    1668                  self._puids.append(puid)
    1669
    1670 -        def getISRCs(self):
    1671                  """Returns the ISRCs associated with this track.
    1672
    1673                  @return: a list of strings, each containing one ISRC
    1674                  """
    1675                  return self._isrcs
    1676
    1677          isrcs = property(getISRCs, doc='The list of associated ISRCs')
    1678
    1679 -        def addISRC(self, isrc):
    1680                  """Add a ISRC to this track.
    1681
    1682                  @param isrc: a string containing an ISRC
    1683                  """
    1684                  self._isrcs.append(isrc)
    1685
    1686 -        def getReleases(self):
    1687                  """Returns the list of releases this track appears on.
    1688
    1689                  @return: a list of L{Release} objects
    1690                  """
    1691                  return self._releases
    1692
    1693          releases = property(getReleases,
    1694                  doc='The releases on which this track appears.')
    1695
    1696 -        def addRelease(self, release):
    1697                  """Add a release on which this track appears.
    1698
    1699                  @param release: a L{Release} object
    1700                  """
    1701                  self._releases.append(release)
    1702
    1703
    1704 -class Relation(object):
    1705          """Represents a relation between two Entities.
    1706
    1707          There may be an arbitrary number of relations between all first
    1708          class objects in MusicBrainz. The Relation itself has multiple
    1709          attributes, which may or may not be used for a given relation
    1710          type.
    1711
    1712          Note that a L{Relation} object only contains the target but not
    1713          the source end of the relation.
    1714
    1715          @todo: Add some examples.
    1716
    1717          @cvar TO_ARTIST: Identifies relations linking to an artist.
    1718          @cvar TO_RELEASE: Identifies relations linking to a release.
    1719          @cvar TO_TRACK: Identifies relations linking to a track.
    1720          @cvar TO_URL: Identifies relations linking to an URL.
    1721
    1722          @cvar DIR_NONE: Relation reading direction doesn't matter.
    1723          @cvar DIR_FORWARD: Relation reading direction is from source to target.
    1724          @cvar DIR_BACKWARD: Relation reading direction is from target to source.
    1725          @cvar DIR_BOTH: Relation reading direction doesn't matter (no longer used!).
    1726          """
    1727          # Relation target types
    1728          #
    1729          TO_ARTIST = NS_REL_1 + 'Artist'
    1730          TO_RELEASE = NS_REL_1 + 'Release'
    1731          TO_TRACK = NS_REL_1 + 'Track'
    1732          TO_URL = NS_REL_1 + 'Url'
    1733
    1734          # Relation reading directions
    1735          #
    1736          DIR_BOTH = 'both'
    1737          DIR_FORWARD = 'forward'
    1738          DIR_BACKWARD = 'backward'
    1739          DIR_NONE = 'none'
    1740
    1741 -        def __init__(self, relationType=None, targetType=None, targetId=None,
    1742                          direction=DIR_NONE, attributes=None,
    1743                          beginDate=None, endDate=None, target=None):
    1744                  """Constructor.
    1745
    1746                  @param relationType: a string containing an absolute URI
    1747                  @param targetType: a string containing an absolute URI
    1748                  @param targetId: a string containing an absolute URI
    1749                  @param direction: one of C{Relation.DIR_FORWARD},
    1750                  C{Relation.DIR_BACKWARD}, or C{Relation.DIR_NONE}
    1751                  @param attributes: a list of strings containing absolute URIs
    1752                  @param beginDate: a string containing a date
    1753                  @param endDate: a string containing a date
    1754                  @param target: an instance of a subclass of L{Entity}
    1755                  """
    1756                  self._relationType = relationType
    1757                  self._targetType = targetType
    1758                  self._targetId = targetId
    1759                  self._direction = direction
    1760                  self._beginDate = beginDate
    1761                  self._endDate = endDate
    1762                  self._target = target
    1763                  self._attributes = attributes
    1764                  if self._attributes is None:
    1765                          self._attributes = [ ]
    1766
    1767 -        def getType(self):
    1768                  """Returns this relation's type.
    1769
    1770                  @return: a string containing an absolute URI, or None
    1771                  """
    1772                  return self._relationType
    1773
    1774 -        def setType(self, type_):
    1775                  """Sets this relation's type.
    1776
    1777                  @param type_: a string containing an absolute URI
    1778                  """
    1779                  self._relationType = type_
    1780
    1781          type = property(getType, setType, doc="The relation's type.")
    1782
    1783 -        def getTargetId(self):
    1784                  """Returns the target's ID.
    1785
    1786                  This is the ID the relation points to. It is an absolute
    1787                  URI, and in case of an URL relation, it is a URL.
    1788
    1789                  @return: a string containing an absolute URI
    1790                  """
    1791                  return self._targetId
    1792
    1793 -        def setTargetId(self, targetId):
    1794                  """Sets the target's ID.
    1795
    1796                  @param targetId: a string containing an absolute URI
    1797
    1798                  @see: L{getTargetId}
    1799                  """
    1800                  self._targetId = targetId
    1801
    1802          targetId = property(getTargetId, setTargetId, doc="The target's ID.")
    1803
    1804 -        def getTargetType(self):
    1805                  """Returns the target's type.
    1806
    1807                  For MusicBrainz data, the following target types are defined:
    1808                   - artists: L{Relation.TO_ARTIST}
    1809                   - releases: L{Relation.TO_RELEASE}
    1810                   - tracks: L{Relation.TO_TRACK}
    1811                   - urls: L{Relation.TO_URL}
    1812
    1813                  @return: a string containing an absolute URI
    1814                  """
    1815                  return self._targetType
    1816
    1817 -        def setTargetType(self, targetType):
    1818                  """Sets the target's type.
    1819
    1820                  @param targetType: a string containing an absolute URI
    1821
    1822                  @see: L{getTargetType}
    1823                  """
    1824                  self._targetType = targetType
    1825
    1826          targetId = property(getTargetId, setTargetId,
    1827                  doc="The type of target this relation points to.")
    1828
    1829 -        def getAttributes(self):
    1830                  """Returns a list of attributes describing this relation.
    1831
    1832                  The attributes permitted depend on the relation type.
    1833
    1834                  @return: a list of strings containing absolute URIs
    1835                  """
    1836                  return self._attributes
    1837
    1838          attributes = property(getAttributes,
    1839                  doc='The list of attributes describing this relation.')
    1840
    1841 -        def addAttribute(self, attribute):
    1842                  """Adds an attribute to the list.
    1843
    1844                  @param attribute: a string containing an absolute URI
    1845                  """
    1846                  self._attributes.append(attribute)
    1847
    1848 -        def getBeginDate(self):
    1849                  """Returns the begin date.
    1850
    1851                  The definition depends on the relation's type. It may for
    1852                  example be the day of a marriage or the year an artist
    1853                  joined a band. For other relation types this may be
    1854                  undefined.
    1855
    1856                  @return: a string containing a date
    1857                  """
    1858                  return self._beginDate
    1859
    1860 -        def setBeginDate(self, dateStr):
    1861                  """Sets the begin date.
    1862
    1863                  @param dateStr: a string containing a date
    1864
    1865                  @see: L{getBeginDate}
    1866                  """
    1867                  self._beginDate = dateStr
    1868
    1869          beginDate = property(getBeginDate, setBeginDate, doc="The begin date.")
    1870
    1871 -        def getEndDate(self):
    1872                  """Returns the end date.
    1873
    1874                  As with the begin date, the definition depends on the
    1875                  relation's type. Depending on the relation type, this may
    1876                  or may not be defined.
    1877
    1878                  @return: a string containing a date
    1879
    1880                  @see: L{getBeginDate}
    1881                  """
    1882                  return self._endDate
    1883
    1884 -        def setEndDate(self, dateStr):
    1885                  """Sets the end date.
    1886
    1887                  @param dateStr: a string containing a date
    1888
    1889                  @see: L{getBeginDate}
    1890                  """
    1891                  self._endDate = dateStr
    1892
    1893          endDate = property(getEndDate, setEndDate, doc="The end date.")
    1894
    1895 -        def getDirection(self):
    1896                  """Returns the reading direction.
    1897
    1898                  The direction may be one of L{Relation.DIR_FORWARD},
    1899                  L{Relation.DIR_BACKWARD}, or L{Relation.DIR_NONE},
    1900                  depending on how the relation should be read. For example,
    1901                  if direction is L{Relation.DIR_FORWARD} for a cover relation,
    1902                  it is read as "X is a cover of Y". For some relations there is
    1903                  no reading direction (like marriages) and the web service doesn't
    1904                  send a direction. In these cases, the direction is set to
    1905                  L{Relation.DIR_NONE}.
    1906
    1907                  @return: L{Relation.DIR_FORWARD}, L{Relation.DIR_BACKWARD},
    1908                  or L{Relation.DIR_NONE}
    1909                  """
    1910                  return self._direction
    1911
    1912 -        def setDirection(self, direction):
    1913                  """Sets the reading direction.
    1914
    1915                  @param direction: L{Relation.DIR_FORWARD},
    1916                  L{Relation.DIR_BACKWARD}, or L{Relation.DIR_NONE}
    1917
    1918                  @see: L{getDirection}
    1919                  """
    1920                  self._direction = direction
    1921
    1922          direction = property(getDirection, setDirection,
    1923                  doc="The reading direction.")
    1924
    1925 -        def getTarget(self):
    1926                  """Returns this relation's target object.
    1927
    1928                  Note that URL relations never have a target object. Use the
    1929                  L{getTargetId} method to get the URL.
    1930
    1931                  @return: a subclass of L{Entity}, or None
    1932                  """
    1933                  return self._target
    1934
    1935 -        def setTarget(self, target):
    1936                  """Sets this relation's target object.
    1937
    1938                  Note that URL relations never have a target object, they
    1939                  are set using L{setTargetId}.
    1940
    1941                  @param target: a subclass of L{Entity}
    1942                  """
    1943                  self._target = target
    1944
    1945          target = property(getTarget, setTarget,
    1946                  doc="The relation's target object.")
    1947
    1948
    1949 -class ReleaseEvent(object):
    1950          """A release event, indicating where and when a release took place.
    1951
    1952          All country codes used must be valid ISO-3166 country codes (i.e. 'DE',
    1953          'UK' or 'FR'). The dates are strings and must have the format 'YYYY',
    1954          'YYYY-MM' or 'YYYY-MM-DD'.
    1955
    1956          The format of the release medium is a URI that can be compared to the
    1957          constants on this class (L{FORMAT_CD}, L{FORMAT_DVD} and others).
    1958          """
    1959          FORMAT_CD = NS_MMD_1 + 'CD'
    1960          FORMAT_DVD = NS_MMD_1 + 'DVD'
    1961          FORMAT_SACD = NS_MMD_1 + 'SACD'
    1962          FORMAT_DUALDISC = NS_MMD_1 + 'DualDisc'
    1963          FORMAT_LASERDISC = NS_MMD_1 + 'LaserDisc'
    1964          FORMAT_MINIDISC = NS_MMD_1 + 'MiniDisc'
    1965          FORMAT_VINYL = NS_MMD_1 + 'Vinyl'
    1966          FORMAT_CASSETTE = NS_MMD_1 + 'Cassette'
    1967          FORMAT_CARTRIDGE = NS_MMD_1 + 'Cartridge'
    1968          FORMAT_REEL_TO_REEL = NS_MMD_1 + 'ReelToReel'
    1969          FORMAT_DAT = NS_MMD_1 + 'DAT'
    1970          FORMAT_DIGITAL = NS_MMD_1 + 'Digital'
    1971          FORMAT_WAX_CYLINDER = NS_MMD_1 + 'WaxCylinder'
    1972          FORMAT_PIANO_ROLL = NS_MMD_1 + 'PianoRoll'
    1973          FORMAT_OTHER = NS_MMD_1 + 'Other'
    1974
    1975 -        def __init__(self, country=None, dateStr=None):
    1976                  """Constructor.
    1977
    1978                  @param country: a string containing an ISO-3166 country code
    1979                  @param dateStr: a string containing a date string
    1980                  """
    1981                  self._countryId = country
    1982                  self._dateStr = dateStr
    1983                  self._catalogNumber = None
    1984                  self._barcode = None
    1985                  self._label = None
    1986                  self._format = None
    1987
    1988 -        def getCountry(self):
    1989                  """Returns the country a release took place.
    1990
    1991                  @note: Due to a server limitation, the web service does not
    1992                  return country IDs for release collection queries. This only
    1993                  affects the L{musicbrainz2.webservice.Query.getReleases} query.
    1994
    1995                  @return: a string containing an ISO-3166 country code, or None
    1996
    1997                  @see: L{musicbrainz2.utils.getCountryName}
    1998                  """
    1999                  return self._countryId
    2000
    2001 -        def setCountry(self, country):
    2002                  """Sets the country a release took place.
    2003
    2004                  @param country: a string containing an ISO-3166 country code
    2005                  """
    2006                  self._countryId = country
    2007
    2008          country = property(getCountry, setCountry,
    2009                  doc='The country a release took place.')
    2010
    2011 -        def getCatalogNumber(self):
    2012                  """Returns the catalog number of this release event.
    2013
    2014                  @return: A string containing the catalog number, or None
    2015                  """
    2016                  return self._catalogNumber
    2017
    2018 -        def setCatalogNumber(self, catalogNumber):
    2019                  """Sets the catalog number of this release event.
    2020
    2021                  @param catalogNumber: A string containing the catalog number
    2022                  """
    2023                  self._catalogNumber = catalogNumber
    2024
    2025          catalogNumber = property(getCatalogNumber, setCatalogNumber,
    2026                  doc='The catalog number of the release event')
    2027
    2028 -        def getBarcode(self):
    2029                  """Returns the barcode of this release event.
    2030
    2031                  @return: A string containing the barcode, or None
    2032                  """
    2033                  return self._barcode
    2034
    2035 -        def setBarcode(self, barcode):
    2036                  """Sets the barcode of this release event.
    2037
    2038                  @param barcode: A string containing the barcode
    2039                  """
    2040                  self._barcode = barcode
    2041
    2042          barcode = property(getBarcode, setBarcode,
    2043                  doc='The barcode of the release event')
    2044
    2045 -        def getLabel(self):
    2046                  """Returns a L{Label} object for the label associated with this release.
    2047
    2048                  @return: a L{Label} object, or None
    2049                  """
    2050                  return self._label
    2051
    2052 -        def setLabel(self, label):
    2053                  """Sets the label of this release event.
    2054
    2055                  @param label: A L{Label} object
    2056                  """
    2057                  self._label = label
    2058
    2059          label = property(getLabel, setLabel, doc='The label of the release')
    2060
    2061 -        def getDate(self):
    2062                  """Returns the date a release took place.
    2063
    2064                  @return: a string containing a date
    2065                  """
    2066                  return self._dateStr
    2067
    2068 -        def setDate(self, dateStr):
    2069                  """Sets the date a release took place.
    2070
    2071                  @param dateStr: a string containing a date
    2072                  """
    2073                  self._dateStr = dateStr
    2074
    2075          date = property(getDate, setDate, doc='The date a release took place.')
    2076
    2077 -        def getFormat(self):
    2078                  """Returns the format of the release medium.
    2079
    2080                  @return: a string containing a URI, or None
    2081                  """
    2082                  return self._format
    2083
    2084 -        def setFormat(self, format):
    2085                  """Sets the format of the release medium.
    2086
    2087                  @param format: a string containing a URI
    2088                  """
    2089                  self._format = format
    2090
    2091          format = property(getFormat, setFormat,
    2092                  doc='The format of the release medium.')
    2093
    2094
    2095 -class CDStub(object):
    2096          """Represents a CD Stub"""
    2097
    2098 -        def __init__(self, disc):
    2099                  """Constructor.
    2100
    2101                  @param disc: a L{Disc} object to create this CD Stub from
    2102                  """
    2103                  assert isinstance(disc, Disc), 'musicbrainz2.model.Disc expected'
    2104                  self._disc = disc
    2105                  self._tracks = [ ]
    2106                  self._title = ""
    2107                  self._artist = ""
    2108                  self._barcode = ""
    2109                  self._comment = ""
    2110
    2111 -        def setTitle(self, title):
    2112                  """Sets the title of this release.
    2113
    2114                  @param title: a string containing the title
    2115                  """
    2116                  self._title = title
    2117
    2118 -        def getTitle(self):
    2119                  """Returns the title of this release.
    2120
    2121                  @return: a string containing the title
    2122                  """
    2123                  return self._title
    2124
    2125          title = property(getTitle, setTitle,
    2126                 doc='The title of the release')
    2127
    2128 -        def setArtist(self, artist):
    2129                  """Sets the artist of this release.
    2130
    2131                  @param artist: a string containing the artist
    2132                  """
    2133                  self._artist = artist
    2134
    2135 -        def getArtist(self):
    2136                  """Returns the artist of this release.
    2137
    2138                  @return: a string containing the artist
    2139                  """
    2140                  return self._artist
    2141
    2142          artist = property(getArtist, setArtist,
    2143                  doc='The artist of the release')
    2144
    2145 -        def setComment(self, comment):
    2146                  """Sets the comment for this release.
    2147
    2148                  @param comment: a string containing the comment
    2149                  """
    2150                  self._comment = comment
    2151
    2152 -        def getComment(self):
    2153                  """Returns the comment for this release.
    2154
    2155                  @return: a string containing the comment
    2156                  """
    2157                  return self._comment
    2158
    2159          comment = property(getComment, setComment,
    2160                   doc='Comment for the release (optional)')
    2161
    2162 -        def setBarcode(self, barcode):
    2163                  """Sets the barcode of this release.
    2164
    2165                  @param barcode: a string containing the barcode
    2166                  """
    2167                  self._barcode = barcode
    2168
    2169 -        def getBarcode(self):
    2170                  """Returns the barcode of this release.
    2171
    2172                  @return: a string containing the barcode
    2173                  """
    2174                  return self._barcode
    2175
    2176          barcode = property(getBarcode, setBarcode,
    2177                   doc='Barcode for the release (optional)')
    2178
    2179 -        def addTrack(self, title, artist=''):
    2180                  """Add a track to this release
    2181
    2182                  @param title: a string containing the title of the track
    2183                  @param artist: a string containing the artist of the track,
    2184                                 if different to the album artist
    2185                  """
    2186                  self._tracks.append((title, artist))
    2187
    2188 -        def getTracks(self):
    2189                  """Return all the tracks on the release.
    2190
    2191                  @return: a list of tuples containing (title, artist) pairs
    2192                           for each track
    2193                  """
    2194                  return self._tracks
    2195
    2196          tracks = property(getTracks, doc='The tracks of the release.')
    2197
    2198 -class Disc(object):
    2199          """Represents an Audio CD.
    2200
    2201          This class represents an Audio CD. A disc can have an ID (the
    2202          MusicBrainz DiscID), which is calculated from the CD's table of
    2203          contents (TOC). There may also be data from the TOC like the length
    2204          of the disc in sectors, as well as position and length of the tracks.
    2205
    2206          Note that different TOCs, maybe due to different pressings, lead to
    2207          different DiscIDs. Conversely, if two different discs have the same
    2208          TOC, they also have the same DiscID (which is unlikely but not
    2209          impossible). DiscIDs are always 28 characters long and look like this:
    2210          C{'J68I_CDcUFdCRCIbHSEbTBCbooA-'}. Sometimes they are also referred
    2211          to as CDIndex IDs.
    2212
    2213          The L{MusicBrainz web service <musicbrainz2.webservice>} only returns
    2214          the DiscID and the number of sectors. The DiscID calculation function
    2215          L{musicbrainz2.disc.readDisc}, however, can retrieve the other
    2216          attributes of L{Disc} from an Audio CD in the disc drive.
    2217          """
    2218 -        def __init__(self, id_=None):
    2219                  """Constructor.
    2220
    2221                  @param id_: a string containing a 28-character DiscID
    2222                  """
    2223                  self._id = id_
    2224                  self._sectors = None
    2225                  self._firstTrackNum = None
    2226                  self._lastTrackNum = None
    2227                  self._tracks = [ ]
    2228
    2229 -        def getId(self):
    2230                  """Returns the MusicBrainz DiscID.
    2231
    2232                  @return: a string containing a 28-character DiscID
    2233                  """
    2234                  return self._id
    2235
    2236 -        def setId(self, id_):
    2237                  """Sets the MusicBrainz DiscId.
    2238
    2239                  @param id_: a string containing a 28-character DiscID
    2240                  """
    2241                  self._id = id_
    2242
    2243          id = property(getId, setId, doc="The MusicBrainz DiscID.")
    2244
    2245 -        def getSectors(self):
    2246                  """Returns the length of the disc in sectors.
    2247
    2248                  @return: the length in sectors as an integer, or None
    2249                  """
    2250                  return self._sectors
    2251
    2252 -        def setSectors(self, sectors):
    2253                  """Sets the length of the disc in sectors.
    2254
    2255                  @param sectors: the length in sectors as an integer
    2256                  """
    2257                  self._sectors = sectors
    2258
    2259          sectors = property(getSectors, setSectors,
    2260                  doc="The length of the disc in sectors.")
    2261
    2262 -        def getFirstTrackNum(self):
    2263                  """Returns the number of the first track on this disc.
    2264
    2265                  @return: an int containing the track number, or None
    2266                  """
    2267                  return self._firstTrackNum
    2268
    2269 -        def setFirstTrackNum(self, trackNum):
    2270                  """Sets the number of the first track on this disc.
    2271
    2272                  @param trackNum: an int containing the track number, or None
    2273                  """
    2274                  self._firstTrackNum = trackNum
    2275
    2276          firstTrackNum = property(getFirstTrackNum, setFirstTrackNum,
    2277                  doc="The number of the first track on this disc.")
    2278
    2279 -        def getLastTrackNum(self):
    2280                  """Returns the number of the last track on this disc.
    2281
    2282                  @return: an int containing the track number, or None
    2283                  """
    2284                  return self._lastTrackNum
    2285
    2286 -        def setLastTrackNum(self, trackNum):
    2287                  """Sets the number of the last track on this disc.
    2288
    2289                  @param trackNum: an int containing the track number, or None
    2290                  """
    2291                  self._lastTrackNum = trackNum
    2292
    2293          lastTrackNum = property(getLastTrackNum, setLastTrackNum,
    2294                  doc="The number of the last track on this disc.")
    2295
    2296 -        def getTracks(self):
    2297                  """Returns the sector offset and length of this disc.
    2298
    2299                  This method returns a list of tuples containing the track
    2300                  offset and length in sectors for all tracks on this disc.
    2301                  The track offset is measured from the beginning of the disc,
    2302                  the length is relative to the track's offset. Note that the
    2303                  leadout track is I{not} included.
    2304
    2305                  @return: a list of (offset, length) tuples (values are ints)
    2306                  """
    2307                  return self._tracks
    2308
    2309          tracks = property(getTracks,
    2310                  doc='Sector offset and length of all tracks.')
    2311
    2312 -        def addTrack(self, track):
    2313                  """Adds a track to the list.
    2314
    2315                  This method adds an (offset, length) tuple to the list of
    2316                  tracks. The leadout track must I{not} be added. The total
    2317                  length of the disc can be set using L{setSectors}.
    2318
    2319                  @param track: an (offset, length) tuple (values are ints)
    2320
    2321                  @see: L{getTracks}
    2322                  """
    2323                  self._tracks.append(track)
    2324
    2325
    2326 -class AbstractAlias(object):
    2327          """An abstract super class for all alias classes."""
    2328 -        def __init__(self, value=None, type_=None, script=None):
    2329                  """Constructor.
    2330
    2331                  @param value: a string containing the alias
    2332                  @param type_: a string containing an absolute URI
    2333                  @param script: a string containing an ISO-15924 script code
    2334                  """
    2335                  self._value = value
    2336                  self._type = type_
    2337                  self._script = script
    2338
    2339 -        def getValue(self):
    2340                  """Returns the alias.
    2341
    2342                  @return: a string containing the alias
    2343                  """
    2344                  return self._value
    2345
    2346 -        def setValue(self, value):
    2347                  """Sets the alias.
    2348
    2349                  @param value: a string containing the alias
    2350                  """
    2351                  self._value = value
    2352
    2353          value = property(getValue, setValue, doc='The alias value.')
    2354
    2355 -        def getType(self):
    2356                  """Returns the alias type.
    2357
    2358                  @return: a string containing an absolute URI, or None
    2359                  """
    2360                  return self._type
    2361
    2362 -        def setType(self, type_):
    2363                  """Sets the alias type.
    2364
    2365                  @param type_: a string containing an absolute URI, or None
    2366                  """
    2367                  self._type = type_
    2368
    2369          type = property(getType, setType, doc='The alias type.')
    2370
    2371 -        def getScript(self):
    2372                  """Returns the alias script.
    2373
    2374                  @return: a string containing an ISO-15924 script code
    2375                  """
    2376                  return self._script
    2377
    2378 -        def setScript(self, script):
    2379                  """Sets the alias script.
    2380
    2381                  @param script: a string containing an ISO-15924 script code
    2382                  """
    2383                  self._script = script
    2384
    2385          script = property(getScript, setScript, doc='The alias script.')
    2386
    2387
    2388 -class ArtistAlias(AbstractAlias):
    2389          """Represents an artist alias.
    2390
    2391          An alias (the I{alias value}) is a different representation of an
    2392          artist's name. This may be a common misspelling or a transliteration
    2393          (the I{alias type}).
    2394
    2395          The I{alias script} is interesting mostly for transliterations and
    2396          indicates which script is used for the alias value. To represent the
    2397          script, ISO-15924 script codes like 'Latn', 'Cyrl', or 'Hebr' are used.
    2398          """
    2399          pass
    2400
    2401
    2402 -class LabelAlias(AbstractAlias):
    2403          """Represents a label alias.
    2404
    2405          An alias (the I{alias value}) is a different representation of a
    2406          label's name. This may be a common misspelling or a transliteration
    2407          (the I{alias type}).
    2408
    2409          The I{alias script} is interesting mostly for transliterations and
    2410          indicates which script is used for the alias value. To represent the
    2411          script, ISO-15924 script codes like 'Latn', 'Cyrl', or 'Hebr' are used.
    2412          """
    2413          pass
    2414
    2415
    2416 -class User(object):
    2417          """Represents a MusicBrainz user."""
    2418
    2419 -        def __init__(self):
    2420                  """Constructor."""
    2421                  self._name = None
    2422                  self._types = [ ]
    2423                  self._showNag = None
    2424
    2425 -        def getName(self):
    2426                  """Returns the user name.
    2427
    2428                  @return: a string containing the user name
    2429                  """
    2430                  return self._name
    2431
    2432 -        def setName(self, name):
    2433                  """Sets the user name.
    2434
    2435                  @param name: a string containing the user name
    2436                  """
    2437                  self._name = name
    2438
    2439          name = property(getName, setName, doc='The MusicBrainz user name.')
    2440
    2441 -        def getTypes(self):
    2442                  """Returns the types of this user.
    2443
    2444                  Most users' type list is empty. Currently, the following types
    2445                  are defined:
    2446
    2447                   - 'http://musicbrainz.org/ns/ext-1.0#AutoEditor'
    2448                   - 'http://musicbrainz.org/ns/ext-1.0#RelationshipEditor'
    2449                   - 'http://musicbrainz.org/ns/ext-1.0#Bot'
    2450                   - 'http://musicbrainz.org/ns/ext-1.0#NotNaggable'
    2451
    2452                  @return: a list of strings containing absolute URIs
    2453                  """
    2454                  return self._types
    2455
    2456          types = property(getTypes, doc="The user's types.")
    2457
    2458 -        def addType(self, type_):
    2459                  """Add a type to the list of types.
    2460
    2461                  @param type_: a string containing absolute URIs
    2462
    2463                  @see: L{getTypes}
    2464                  """
    2465                  self._types.append(type_)
    2466
    2467 -        def getShowNag(self):
    2468                  """Returns true if a nag screen should be displayed to the user.
    2469
    2470                  @return: C{True}, C{False}, or None
    2471                  """
    2472                  return self._showNag
    2473
    2474 -        def setShowNag(self, value):
    2475                  """Sets the value of the nag screen flag.
    2476
    2477                  If set to C{True},
    2478
    2479                  @param value: C{True} or C{False}
    2480
    2481                  @see: L{getShowNag}
    2482                  """
    2483                  self._showNag = value
    2484
    2485          showNag = property(getShowNag, setShowNag,
    2486                  doc='The value of the nag screen flag.')
    2487
    2488  # EOF
    2489