MusicBrainz support

This commit is contained in:
chudov
2008-11-30 03:04:05 +00:00
parent 2db66848bf
commit c289ecce0b
26 changed files with 3292 additions and 11 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
namespace CUETools.CDImage
@@ -283,7 +284,7 @@ namespace CUETools.CDImage
}
}
public String Catalog
public string Catalog
{
get
{
@@ -295,6 +296,20 @@ namespace CUETools.CDImage
}
}
public string MusicBrainzId
{
get
{
StringBuilder mbSB = new StringBuilder();
mbSB.AppendFormat("{0:X2}{1:X2}{2:X8}", 1, AudioTracks, _tracks[(int)AudioTracks-1].End + 1 + 150);
for (int iTrack = 0; iTrack < AudioTracks; iTrack++)
mbSB.AppendFormat("{0:X8}", _tracks[iTrack].Start + 150);
mbSB.Append(new string('0', (99 - (int)AudioTracks) * 8));
byte[] hashBytes = (new SHA1CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(mbSB.ToString()));
return Convert.ToBase64String(hashBytes).Replace('+', '.').Replace('/', '_').Replace('=', '-');
}
}
public void AddTrack(CDTrack track)
{
_tracks.Add(track);

View File

@@ -97,6 +97,10 @@
<Project>{8CF07381-BEA2-4AFC-B3DD-9B2F21C65A3A}</Project>
<Name>CUETools.Ripper.SCSI</Name>
</ProjectReference>
<ProjectReference Include="..\MusicBrainz\MusicBrainz.csproj">
<Project>{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}</Project>
<Name>MusicBrainz</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -27,6 +27,7 @@ using CUETools.Ripper.SCSI;
using CUETools.Codecs;
using CUETools.CDImage;
using CUETools.AccurateRip;
using MusicBrainz;
namespace CUERipper
{
@@ -40,7 +41,7 @@ namespace CUERipper
static void Main(string[] args)
{
string programVersion = "CUERipper v1.9.3";
string programVersion = "CUERipper v1.9.3 Copyright (C) 2008 Gregory S. Chudov";
Console.SetOut(Console.Error);
Console.WriteLine("{0}", programVersion);
Console.WriteLine("This is free software under the GNU GPLv3+ license; There is NO WARRANTY, to");
@@ -68,19 +69,37 @@ namespace CUERipper
bool toStdout = false;
AccurateRipVerify arVerify = new AccurateRipVerify(audioSource.TOC);
WAVWriter audioDest = new WAVWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate, toStdout ? Console.OpenStandardOutput() : null);
int[,] buff = new int[audioSource.BestBlockSize, audioSource.ChannelCount];
string CDDBId = AccurateRipVerify.CalculateCDDBId(audioSource.TOC);
string ArId = AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC);
Release release;
ReleaseQueryParameters p = new ReleaseQueryParameters();
p.DiscId = audioSource.TOC.MusicBrainzId;
Query<Release> results = Release.Query(p);
arVerify.ContactAccurateRip(ArId);
Console.WriteLine("Drive : {0}", audioSource.Path);
Console.WriteLine("File Info : {0}kHz; {1} channel; {2} bit; {3}", audioSource.SampleRate, audioSource.ChannelCount, audioSource.BitsPerSample, CDImageLayout.TimeToString((uint)(audioSource.Length / 588)));
Console.WriteLine("Filename : {0}", destFile);
Console.WriteLine("AR status : {0}", arVerify.ARStatus == null ? "ok" : arVerify.ARStatus);
try
{
release = results.First();
}
catch
{
release = null;
}
if (destFile == null || destFile == "")
destFile = (release == null) ? "cdimage.wav" : release.GetArtist() + " - " + release.GetTitle() + ".wav";
Console.WriteLine("Drive : {0}", audioSource.Path);
Console.WriteLine("Filename : {0}", destFile);
Console.WriteLine("Disk length : {0}", CDImageLayout.TimeToString((uint)(audioSource.Length / 588)));
Console.WriteLine("AccurateRip : {0}", arVerify.ARStatus == null ? "ok" : arVerify.ARStatus);
Console.WriteLine("MusicBrainz : {0}", release == null ? "not found" : release.GetArtist() + " - " + release.GetTitle());
WAVWriter audioDest = new WAVWriter(destFile, audioSource.BitsPerSample, audioSource.ChannelCount, audioSource.SampleRate, toStdout ? Console.OpenStandardOutput() : null);
audioDest.FinalSampleCount = (long)audioSource.Length;
audioDest.FinalSampleCount = (long) audioSource.Length;
DateTime start = DateTime.Now;
TimeSpan lastPrint = TimeSpan.FromMilliseconds(0);
@@ -94,7 +113,7 @@ namespace CUERipper
TimeSpan elapsed = DateTime.Now - start;
if ((elapsed - lastPrint).TotalMilliseconds > 60)
{
Console.Error.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}",
Console.Write("\rProgress : {0:00}%; {1:0.00}x; {2}/{3}",
100.0 * audioSource.Position / audioSource.Length,
audioSource.Position / elapsed.TotalSeconds / audioSource.SampleRate,
elapsed,
@@ -105,8 +124,8 @@ namespace CUERipper
} while (true);
TimeSpan totalElapsed = DateTime.Now - start;
Console.Error.Write("\r \r");
Console.WriteLine("Results : {0:0.00}x; {1}",
Console.Write("\r \r");
Console.WriteLine("Results : {0:0.00}x; {1}",
audioSource.Length / totalElapsed.TotalSeconds / audioSource.SampleRate,
totalElapsed
);
@@ -146,11 +165,23 @@ namespace CUERipper
cueWriter.WriteLine("REM COMMENT \"{0}\"", programVersion);
if (audioSource.TOC.Catalog != null)
cueWriter.WriteLine("CATALOG {0}", audioSource.TOC.Catalog);
if (release != null)
{
if (release.GetEvents().Count > 0)
cueWriter.WriteLine("DATE {0}", release.GetEvents()[0].Date);
cueWriter.WriteLine("PERFORMER {0}", release.GetArtist());
cueWriter.WriteLine("TITLE {0}", release.GetTitle());
}
cueWriter.WriteLine("FILE \"{0}\" WAVE", destFile);
for (int track = 1; track <= audioSource.TOC.TrackCount; track++)
if (audioSource.TOC[track].IsAudio)
{
cueWriter.WriteLine(" TRACK {0:00} AUDIO", audioSource.TOC[track].Number);
if (release != null && release.GetTracks().Count >= audioSource.TOC[track].Number)
{
cueWriter.WriteLine(" TITLE {0}", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetTitle());
cueWriter.WriteLine(" PERFORMER {0}", release.GetTracks()[(int)audioSource.TOC[track].Number - 1].GetArtist());
}
if (audioSource.TOC[track].ISRC != null)
cueWriter.WriteLine(" ISRC {0}", audioSource.TOC[track].ISRC);
for (int index = audioSource.TOC[track].Pregap > 0 ? 0 : 1; index <= audioSource.TOC[track].LastIndex; index++)

View File

@@ -71,6 +71,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.CDImage", "..\CUET
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools.AccurateRip", "..\CUETools.AccurateRip\CUETools.AccurateRip.csproj", "{5802C7E9-157E-4124-946D-70B5AE48A5A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicBrainz", "..\MusicBrainz\MusicBrainz.csproj", "{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -342,6 +344,18 @@ Global
{5802C7E9-157E-4124-946D-70B5AE48A5A1}.Release|x64.Build.0 = Release|x64
{5802C7E9-157E-4124-946D-70B5AE48A5A1}.Release|x86.ActiveCfg = Release|x86
{5802C7E9-157E-4124-946D-70B5AE48A5A1}.Release|x86.Build.0 = Release|x86
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|Any CPU.Build.0 = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|x64.ActiveCfg = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|x64.Build.0 = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|x86.ActiveCfg = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Debug|x86.Build.0 = Debug|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|Any CPU.ActiveCfg = Release|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|Any CPU.Build.0 = Release|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|x64.ActiveCfg = Release|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|x64.Build.0 = Release|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|x86.ActiveCfg = Release|Any CPU
{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

3
MusicBrainz/AUTHORS Normal file
View File

@@ -0,0 +1,3 @@
Scott Peterson
E-mail: lunchtimemama@gmail.com
Userid: scottp

17
MusicBrainz/COPYING Normal file
View File

@@ -0,0 +1,17 @@
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

503
MusicBrainz/ChangeLog Normal file
View File

@@ -0,0 +1,503 @@
2008-09-20 Scott Peterson <lunchtimemama@gmail.com>
2008-09-20 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Track.cs : GetDuration now returns a TimeSpan rather
than a uint. Don't know how I missed that.
* MusicBrainz/MusicBrainzObject.cs: Added GetPropertyOrDefault
overload which uses the "default" keyword for the default value.
2008-08-17 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Release.cs,
MusicBrainz/Track.cs: Made protected members internal. Minor
refactoring.
* MusicBrainz/Relation.cs: UrlRelations uses Uri instead of string.
* MusicBrainz/Label.cs: Made protected members internal. Minor
refactoring. Fixed bug with Country.
* MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/MusicBrainzItem.cs:
Made protected members internal.
* MusicBrainz/XmlRequestEventArgs.cs: Use Uri instead of string.
* MusicBrainz/LocalDisc.cs: Made protected members internal. Removed
ThreadStatic attributes and went for locks instead. This is the way
we concurentize our code, concurentize our code, concurentize our
code. TrackDuration is now an array of TimeSpans rather than ints.
Because that's more awesome. SubissionUrl is now a Uri rather than
a string. For the same reason. Added LocalDiscException class to
wrap problems with the hardware layer code.
* MusicBrainz/MusicBrainzException.cs: Minor refactoring.
* MusicBrainz/Query.cs: Throw ArgumentOutOfRangeException instead of
IndexOutOfRangeException because Framework Design Guidelines told
me to. Removed ToList and ToArray. People can use the
IEnumerable<T> extension methods if they want.
* MusicBrainz/Artist.cs: Made protected members internal. Removed
ThreadStatic attribute from static field and added locks for proper
concurrency handling. GetReleases (ArtistReleaseType) no longer
changes the Artist.ArtistReleaseType to the provided argument.
Added ReleaseArtistType enum to replace the various bool for
ArtistReleaseType (confusing names, I know. Tough titties).
* MusicBrainz/MusicBrainzService.cs: Got rid of ThreadStatic and added
locks. Yeah! Changed ServiceUrl to Uri from string. Yeah again!
2008-08-05 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Made some protected methods static.
* MusicBrainz/LocalDisc.cs: Changed protected properties to protected
fields and changed an array property to a method.
* MusicBrainz/DiscLinux.cs, MusicBrainz/DiscWin32.cs: Changed class
name to match file name and changed protected properties to
protected fields.
* MusicBrainz/Query.cs: Changed attribute public readonly fields to
public readonly properties.
* MusicBrainz/Artist.cs: Made public static field ThreadStatic and made
a private method static.
* MusicBrainz/MusicBrainzService.cs: Made public static fields
ThreadStatic.
2008-07-21 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Simplified relation creation
slightly and added equivilance operator overload.
* MusicBrainz/LinuxDisc.cs, MusicBrainz/DiscLinux.cs: Renamed back to
DiscLinux
* MusicBrainz/Query.cs: Renamed some public parameters to follow FDG
style and changed some public methods to return IList instead of
List.
* MusicBrainz/Win32Disc.cs, MusicBrainz/DiscWin32.cs: Renamed back to
DiscWin32
* MusicBrainz/Artist.cs: Added equivilance operator overload to
ArtistReleaseType type.
2008-04-15 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Relation.cs,
MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/Disc.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/XmlRequestEventArgs.cs, MusicBrainz/LocalDisc.cs,
MusicBrainz/Utils.cs, MusicBrainz/LinuxDisc.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzException.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Query.cs,
MusicBrainz/Win32Disc.cs, MusicBrainz/Artist.cs,
MusicBrainz/MusicBrainzService.cs: API BREAKING CHANGE!!! We now
use methods rather than properties if accessing the member can
incur an HTTP request. Update your code accordingly.
2008-04-05 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Release.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Utils.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzItem.cs: Some better
string building.
2008-04-05 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz.mdp, MusicBrainz/Relation.cs,
MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/LocalDisc.cs, MusicBrainz/Track.cs,
MusicBrainz/Query.cs, MusicBrainz/MusicBrainzItem.cs,
MusicBrainz/Artist.cs, MusicBrainz/MusicBrainzService.cs:
Reorganized some code.
* MusicBrainz/DiscLinux.cs, MusicBrainz/LinuxDisc.cs,
MusicBrainz/DiscWin32.cs, MusicBrainz/Win32Disc.cs: Renamed
2008-04-05 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Relation.cs,
MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/Disc.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/XmlRequestEventArgs.cs, MusicBrainz/LocalDisc.cs,
MusicBrainz/Utils.cs, MusicBrainz/DiscLinux.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzException.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Query.cs,
MusicBrainz/DiscWin32.cs, MusicBrainz/Artist.cs,
MusicBrainz/MusicBrainzService.cs: Put the license in a region
(yeah for the managed MD text editor!) and a few whitespace fixes.
2008-03-31 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Relation.cs: Renamed RelationPrimitive to RelationBase.
2008-03-31 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Artist.cs: Formatting
fixes.
2008-03-31 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Release.cs: Changed ReleaseQueryParameters.DiscID to
DiscId. This is an API breaking change (good thing we're not at
1.0!)
2008-03-31 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Relation.cs,
MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/Disc.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/XmlRequestEventArgs.cs, MusicBrainz/LocalDisc.cs,
MusicBrainz/DiscLinux.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzException.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Query.cs,
MusicBrainz/DiscWin32.cs, MusicBrainz/MusicBrainzService.cs:
Relicensed to MIT/X11
* MusicBrainz/Utils.cs: Relicensed to MIT/X11. New override for
EnumToString takes a StringBuider.
* MusicBrainz/Artist.cs: Relicensed to MIT/X11. ArtistReleaseType now
support specifying a ReleaseType and a ReleaseStatus.
2008-03-30 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Release.cs: Instantiate tracks with the artist of the
release.
* MusicBrainz/Track.cs: Use new constructor.
* MusicBrainz/MusicBrainzItem.cs: Added the ability for a
MusicBrainzItem to be instantiated with an Artist. This artist will
only be used if no artist was found in the XML.
2008-03-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Release.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/Artist.cs: Whitespace fixes which have somehow managed
to escape my attention, and used the AsReadOnly convenience method.
2008-03-21 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Query.cs: Add new PerfectMatch() method which returns a
result if it is the only result with a score of 100. If no result
has a score of 100, or if more than one result have a score of 100,
null is returned.
2008-03-14 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Artist.cs: Whitespace fixes.
I don't know where these tabs come from.
2008-02-13 Scott Peterson <lunchtimemama@gmail.com>
Got rid of unused Properties direcotry and AssemblyInfo.cs
2008-02-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Disc.cs: Use TryParse instead of a bunch of stuff.
2008-02-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/LocalDisc.cs: Added SubmissionUrl property.
2008-02-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Whatspace fixes.
2008-02-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Fixed bug w/ Release getting and
querying.
2008-02-25 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Improved a params method performance.
Used TimeSpan and DateTime operators.
* MusicBrainz/Release.cs: Improved a params method performance.
2008-02-23 Scott Peterson <lunchtimemama@gmail.com>
Renamed MusicBrainzObject.Mbid to just Id.
* MusicBrainz/MusicBrainzService.cs: Added static class for containing all
static setting pertaining globally to the use of the library. I think
this is more logical than sticking this stuff in the abstract
MusicBrainzObject type.
2008-02-22 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Relation.cs: Got rid of unneeded using.
2008-02-22 Scott Peterson <lunchtimemama@gmail.com>
Various whitespace fixes, refactoring, and using immutable collections
* MusicBrainz/Utilities.cs, MusicBrainz/Utils.cs: Renamed Utilities class to
Utils. It's internal, so an abriviated name is just fine.
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Release.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Artist.cs: Renamed MBID to
Mbid, made to use ReadOnlyCollection instead of List.
* MusicBrainz/Label.cs: Renamed MBID to Mbid
* MusicBrainz/Disc.cs, MusicBrainz/LocalDisc.cs: Split off local-disc
specific stuff into LocalDisc.
* MusicBrainz/DiscLinux.cs, MusicBrainz/DiscWin32.cs: Inherit from LocalDisc
* MusicBrainz/Query.cs: Added First () method which returns just the first
result (same as the implicit conversion to T).
2008-02-22 Scott Peterson <lunchtimemama@gmail.com>
More white space fixes
2008-02-21 Scott Peterson <lunchtimemama@gmail.com>
Whitespace changes. I'll probably work things a little more.
2008-02-21 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Track.cs: Added new overload to Query().
2008-02-20 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/MusicBrainzItem.cs: Made the abstract classes' constructors
internal. Since the all of the concrete classes are sealed, this
prevents any external assembly from inheriting from MusicBrainzObject &
al.
2008-02-13 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Release.cs: Changed return type of QueryFromDevice from
Release to Query<Release> (since Query<T> can now be implicitly
converted to T).
* MusicBrainz/Query.cs: Improvement to implicit conversion to prevent bad
performance after the conversion has been made when attempting to
enumerate.
2008-02-13 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Utilities.cs: Fixed bug in EnumToString.
* MusicBrainz/Query.cs: Minor changes
2008-02-13 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Track.cs,
MusicBrainz/Artist.cs: Got rid of Query*Single methods.
* MusicBrainz/Query.cs: Fancy new methods and operators.
2008-02-13 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/DiscLinux.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Query.cs: More aesthetic use
of nullable types.
2008-02-09 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/DiscLinux.cs: Minor refactor.
* MusicBrainz/DiscWin32.cs: Removed unnessisary ref.
2008-02-09 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/DiscLinux.cs: Fixed linux disc id code.
* MusicBrainz/DiscWin32.cs: Whitespace.
2008-02-09 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Disc.cs, MusicBrainz/DiscLinux.cs: More work on the linux
discid. Still not there yet. Damn marshaling.
2008-02-09 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/DiscLinux.cs: Improvements to the linux discid implimentation.
Still doesn't work, but getting closer.
2008-02-09 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/MusicBrainzObject.cs: Fixed bug when query returns no results.
* MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Track.cs,
MusicBrainz/Artist.cs: Whitespace fixes
* MusicBrainz/Disc.cs, MusicBrainz/DiscWin32.cs: Rejiggered
* MusicBrainz/DiscLinux.cs: Added linux DiscId implementation
2008-02-07 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Release.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzItem.cs,
MusicBrainz/Query.cs, MusicBrainz/Artist.cs: Refactored LINQ-related
attributes.
2008-02-03 Scott Peterson <lunchtimemama@gmail.com>
* MusicBrainz/Utilities.cs: Minor improvement to enum-to-string method.
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Event.cs,
MusicBrainz/MusicBrainzException.cs, MusicBrainz/Query.cs: Sealed some
classes.
2007-12-31 Scott Peterson <lunchtimemama>
* MusicBrainz/MusicBrainzObject.cs: Fixed generic constraint syntax that was
a problem for csc.
2007-12-09 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Event.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Artist.cs: Reverted
pluralization (my mistake)
2007-12-08 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/Event.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs, MusicBrainz/Artist.cs: Refactored
enumeration names to be plural.
2007-12-08 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs: Slight improvement to property handling.
2007-12-08 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzItem.cs,
MusicBrainz/Artist.cs: Property access is now nicer.
2007-11-13 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Track.cs: Added null argument check and a LINQ attribute.
2007-11-13 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Disc.cs,
MusicBrainz/Track.cs, MusicBrainz/Artist.cs: Added argument null-checks
for public methods.
2007-11-12 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs: Fixed bug when queries returned no
results.
2007-11-09 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Utilities.cs, MusicBrainz/MusicBrainzObject.cs,
MusicBrainz/Relation.cs, MusicBrainz/Label.cs, MusicBrainz/Release.cs,
MusicBrainz/Event.cs, MusicBrainz/Disc.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzException.cs, MusicBrainz/MusicBrainzItem.cs,
MusicBrainz/Query.cs, MusicBrainz/DiscWin32.cs, MusicBrainz/Artist.cs:
Relicenced.
* MusicBrainz/LinqBoilerplate.cs, MusicBrainz/Linq.cs: Removed for now.
2007-11-06 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Release.cs: Fixed bug with events list.
2007-11-06 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/MusicBrainzEntity.cs,
MusicBrainz/Track.cs, MusicBrainz/MusicBrainzItem.cs: Made LINQ-ready.
* MusicBrainz/LinqBoilerplate.cs, MusicBrainz/Linq.cs: Created a LINQ
provider.
* MusicBrainz/Query.cs: Added some custom atts used by the LINQ provider.
* MusicBrainz/Artist.cs: Made LINQ-ready. Fixed a silly sintax thing that
makes MSBuild barf. BWAAA!
* Makefile.am: Changed from wildcard *.cs to specific enumeration of source
files (because we now have some .cs files (the LINQ ones) which we do
not want to compile (... yet!)).
2007-10-31 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs: Made the ProviderUrl a public field.
Renamed a few methods.
* MusicBrainz/Query.cs: Refactored a method.
2007-10-31 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Release.cs: Fixed bug with ReleaseQueryParameter using
"language" instead of "lang" as a query parameter.
2007-10-30 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Artist.cs: Artist's will now fetch their Releases during
Artist.Get().
2007-10-30 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Utilities.cs: Moved percent-encoding code to Utilities class.
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Release.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/MusicBrainzItem.cs: Made to use Utilities.PercentEncoding().
* MusicBrainz/Query.cs: Got rid of stupid class QueryParameters.
* MusicBrainz/Artist.cs: Got rid of stupid overload for Get()
2007-10-30 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Utilities.cs, MusicBrainz/Relation.cs,
MusicBrainz/MusicBrainzObject.cs, MusicBrainz/Label.cs,
MusicBrainz/Release.cs, MusicBrainz/Event.cs, MusicBrainz/Disc.cs,
MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/Track.cs,
MusicBrainz/Query.cs, MusicBrainz/MusicBrainzItem.cs,
MusicBrainz/MusicBrainzException.cs, MusicBrainz/DiscWin32.cs,
MusicBrainz/Artist.cs: Added copyright notice and MIT licence.
2007-10-30 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs: Refactored Query methods (got rid of
them).
* MusicBrainz/Label.cs, MusicBrainz/Track.cs, MusicBrainz/Artist.cs:
Refactored Query methods.
* MusicBrainz/Release.cs: Refactored Query methods, spelling correction in
ReleaseFormat.Cassette.
* MusicBrainz/Disc.cs: Changed Id to ID. It seems better.
* MusicBrainz/MusicBrainzEntity.cs: Got rid of EntityQueryParameters (a
stupid class).
* MusicBrainz/Query.cs: Removed non-generic Query class (a stupid class to
begin with) and made a bunch of things private because the client really
shouldn't need to know about how we're doing things. Refactored
constructor a little.
2007-10-27 Scott Peterson <scottp@gnome.org>
* MusicBrainz/MusicBrainzObject.cs, MusicBrainz/MusicBrainzItem.cs: Method
accessor tightened up and method name changed.
* MusicBrainz/Label.cs, MusicBrainz/Release.cs, MusicBrainz/Track.cs,
MusicBrainz/Artist.cs: Method accessor tightened up.
* MusicBrainz/MusicBrainzEntity.cs: Method name changed.
2007-10-27 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Disc.cs: Made to use System.Security.Cryptography.SHA1.
* MusicBrainz/SHA1MusicBrainz.cs: Removed. It turns out
System.Security.Cryptography.SHA1 does the trick.
2007-10-27 Scott Peterson <scottp@gnome.org>
* ChangeLog: ChangeLog updated.
2007-10-27 Scott Peterson <scottp@gnome.org>
* MusicBrainz/Utilities.cs: Cleaned out a bunch of obsolete code.
* MusicBrainz/MusicBrainzObject.cs: Made HaveAllRels a protected
property and removed redundant constructors.
* MusicBrainz/Label.cs, MusicBrainz/Track.cs: Minor changes to
constructors.
* MusicBrainz/Release.cs: Minor changes to constructors and change
which fixes a theoretical bug where Tracks would not have
relations.
* MusicBrainz/MusicBrainzEntity.cs, MusicBrainz/MusicBrainzItem.cs:
Removed redundant constructors as per changes in MusicBrainzObject.
* MusicBrainz/Query.cs: Removed obsolete ArtistReleaseIncs field.
* MusicBrainz/Artist.cs: Minor changes to constructors and a new way of
specifying releases: Added ArtistRelease class and simplified code
regarding releases. Also made very fancy use of the coalesces
operator!
* MusicBrainz/Inc.cs: Removed. Changes in the way artists' handle
releases finally obsoletes this class.
2007-10-27 Aaron Bockover <abock@gnome.org>
* src/MusicBrainz/MusicBrainz/*.cs: Renamed the namespace from
MusicBrainzSharp to MusicBrainz
* configure.ac:
* m4/monodoc.m4:
* docs/: Added Monodoc support
2007-10-27 Aaron Bockover <abock@gnome.org>
* musicbrainz-sharp: Set up initial project infrastructure for Scott

7
MusicBrainz/HACKING Normal file
View File

@@ -0,0 +1,7 @@
When writing code for MusicBrainz-Sharp, follow the Mono coding guidlines [1].
MusicBrainz-Sharp is in the public domain. In order to preserve the freedom of the code, any patches or code which is submitted to MusicBrainz-Sharp must include the following disclaimer:
The author or authors of this code dedicate any and all copyright interest in this code to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this code under copyright law.
[1] http://www.mono-project.com/Coding_Guidelines

3
MusicBrainz/MAINTAINERS Normal file
View File

@@ -0,0 +1,3 @@
Scott Peterson
E-mail: lunchtimemama@gmail.com
Userid: scottp

38
MusicBrainz/Makefile.am Normal file
View File

@@ -0,0 +1,38 @@
ASSEMBLY = MusicBrainz.dll
REFERENCES = \
-r:System \
-r:System.Xml
SOURCES = \
MusicBrainz/Artist.cs \
MusicBrainz/Disc.cs \
MusicBrainz/DiscLinux.cs \
MusicBrainz/DiscWin32.cs \
MusicBrainz/DiscWin32NT.cs \
MusicBrainz/Event.cs \
MusicBrainz/Label.cs \
MusicBrainz/LocalDisc.cs \
MusicBrainz/MusicBrainzEntity.cs \
MusicBrainz/MusicBrainzException.cs \
MusicBrainz/MusicBrainzItem.cs \
MusicBrainz/MusicBrainzObject.cs \
MusicBrainz/MusicBrainzService.cs \
MusicBrainz/Query.cs \
MusicBrainz/Relation.cs \
MusicBrainz/Release.cs \
MusicBrainz/Track.cs \
MusicBrainz/Utils.cs \
MusicBrainz/XmlRequestEventArgs.cs
instdir = $(prefix)/lib/musicbrainz-sharp
inst_SCRIPTS = $(ASSEMBLY) $(ASSEMBLY).mdb
$(ASSEMBLY): $(SOURCES)
$(MCS) -out:$@ -debug -target:library -unsafe $(REFERENCES) $(SOURCES)
all: $(ASSEMBLY)
EXTRA_DIST = $(SOURCES) MusicBrainz.csproj
CLEANFILES = $(ASSEMBLY) $(ASSEMBLY).mdb
DISTCLEANFILES = *.pidb
MAINTAINERCLEANFILES = Makefile Makefile.in

View File

@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>8.0.50727</ProductVersion>
<ProjectGuid>{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>MusicBrainz</RootNamespace>
<AssemblyName>MusicBrainz</AssemblyName>
<FileUpgradeFlags>
</FileUpgradeFlags>
<UpgradeBackupLocation>
</UpgradeBackupLocation>
<OldToolsVersion>2.0</OldToolsVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyKeyFile>.</AssemblyKeyFile>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<RunWithWarnings>false</RunWithWarnings>
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>.</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AssemblyKeyFile>.</AssemblyKeyFile>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<TargetFrameworkVersion>v1.1</TargetFrameworkVersion>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Xml" />
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="MusicBrainz\Artist.cs" />
<Compile Include="MusicBrainz\Disc.cs" />
<Compile Include="MusicBrainz\Event.cs" />
<Compile Include="MusicBrainz\Label.cs" />
<Compile Include="MusicBrainz\MusicBrainzEntity.cs" />
<Compile Include="MusicBrainz\MusicBrainzException.cs" />
<Compile Include="MusicBrainz\MusicBrainzItem.cs" />
<Compile Include="MusicBrainz\MusicBrainzObject.cs" />
<Compile Include="MusicBrainz\Query.cs" />
<Compile Include="MusicBrainz\Relation.cs" />
<Compile Include="MusicBrainz\Release.cs" />
<Compile Include="MusicBrainz\Track.cs" />
<Compile Include="MusicBrainz\Utils.cs" />
<Compile Include="MusicBrainz\XmlRequestEventArgs.cs" />
<Compile Include="MusicBrainz\MusicBrainzService.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<MonoDevelop>
<Properties xmlns="">
<MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="Makefile.am" BuildTargetName="" CleanTargetName="" SyncReferences="true" IsAutotoolsProject="true" RelativeConfigureInPath="../..">
<BuildFilesVar Sync="true" Name="SOURCES" />
<DeployFilesVar />
<ResourcesVar Name="REFERENCES" />
<OthersVar />
<GacRefVar Sync="true" Name="REFERENCES" Prefix="-r:" />
<AsmRefVar Sync="true" Name="REFERENCES" Prefix="-r:" />
<ProjectRefVar Sync="true" Name="REFERENCES" Prefix="-r:" />
</MonoDevelop.Autotools.MakefileInfo>
<MonoDevelop.ChangeLogAddIn.ChangeLogInfo policy="UseParentPolicy" />
</Properties>
</MonoDevelop>
<VisualStudio />
</ProjectExtensions>
</Project>

View File

@@ -0,0 +1,276 @@
// Artist.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
public sealed class Artist : MusicBrainzEntity
{
#region Private
const string EXTENSION = "artist";
ArtistReleaseType artist_release_type = DefaultArtistReleaseType;
ArtistType? type;
ReadOnlyCollection<Release> releases;
bool have_all_releases;
#endregion
#region Constructors
Artist (string id) : base (id, null)
{
}
Artist (string id, ArtistReleaseType artist_release_type)
: base (id, "&inc=" + artist_release_type.ToString ())
{
have_all_releases = true;
this.artist_release_type = artist_release_type;
}
internal Artist (XmlReader reader) : base (reader, false)
{
}
#endregion
#region Protected
internal override string UrlExtension {
get { return EXTENSION; }
}
internal override void CreateIncCore (StringBuilder builder)
{
AppendIncParameters (builder, artist_release_type.ToString ());
base.CreateIncCore (builder);
}
internal override void LoadMissingDataCore ()
{
Artist artist = new Artist (Id);
type = artist.GetArtistType ();
base.LoadMissingDataCore (artist);
}
internal override void ProcessAttributes (XmlReader reader)
{
switch (reader ["type"]) {
case "Group":
type = ArtistType.Group;
break;
case "Person":
type = ArtistType.Person;
break;
}
}
internal override void ProcessXmlCore (XmlReader reader)
{
switch (reader.Name) {
case "release-list":
if (reader.ReadToDescendant ("release")) {
List<Release> releases = new List<Release> ();
do releases.Add (new Release (reader.ReadSubtree ()));
while (reader.ReadToNextSibling ("release"));
this.releases = releases.AsReadOnly ();
}
break;
default:
base.ProcessXmlCore (reader);
break;
}
}
#endregion
#region Public
static ArtistReleaseType default_artist_release_type = new ArtistReleaseType (ReleaseStatus.Official, ReleaseArtistType.SingleArtist);
public static ArtistReleaseType DefaultArtistReleaseType {
get { return default_artist_release_type; }
set {
if (value == null) throw new ArgumentNullException ("value");
default_artist_release_type = value;
}
}
public ArtistReleaseType ArtistReleaseType {
get { return artist_release_type; }
set {
if (artist_release_type == value) {
return;
}
artist_release_type = value;
releases = null;
have_all_releases = false;
}
}
[Queryable ("arid")]
public override string Id {
get { return base.Id; }
}
[Queryable ("artist")]
public override string GetName ()
{
return base.GetName ();
}
[Queryable ("artype")]
public ArtistType GetArtistType ()
{
return GetPropertyOrDefault (ref type, ArtistType.Unknown);
}
public ReadOnlyCollection<Release> GetReleases ()
{
return releases ?? (have_all_releases
? releases = new ReadOnlyCollection<Release> (new Release [0])
: new Artist (Id, ArtistReleaseType).GetReleases ());
}
public ReadOnlyCollection<Release> GetReleases (ArtistReleaseType artistReleaseType)
{
return new Artist (Id, artistReleaseType).GetReleases ();
}
#endregion
#region Static
public static Artist Get (string id)
{
if (id == null) throw new ArgumentNullException ("id");
return new Artist (id);
}
public static Query<Artist> Query (string name)
{
if (name == null) throw new ArgumentNullException ("name");
return new Query<Artist> (EXTENSION, CreateNameParameter (name));
}
public static Query<Artist> QueryLucene (string luceneQuery)
{
if (luceneQuery == null) throw new ArgumentNullException ("luceneQuery");
return new Query<Artist> (EXTENSION, CreateLuceneParameter (luceneQuery));
}
public static implicit operator string (Artist artist)
{
return artist.ToString ();
}
#endregion
}
#region Ancillary Types
public enum ArtistType
{
Unknown,
Group,
Person
}
public enum ReleaseArtistType
{
VariousArtists,
SingleArtist
}
public sealed class ArtistReleaseType
{
string str;
public ArtistReleaseType (ReleaseType type, ReleaseArtistType artistType) : this ((Enum)type, artistType)
{
}
public ArtistReleaseType (ReleaseStatus status, ReleaseArtistType artistType) : this ((Enum)status, artistType)
{
}
public ArtistReleaseType (ReleaseType type, ReleaseStatus status, ReleaseArtistType artistType)
{
StringBuilder builder = new StringBuilder ();
Format (builder, type, artistType);
builder.Append ('+');
Format (builder, status, artistType);
str = builder.ToString ();
}
ArtistReleaseType (Enum enumeration, ReleaseArtistType artistType)
{
StringBuilder builder = new StringBuilder ();
Format (builder, enumeration, artistType);
str = builder.ToString ();
}
static void Format (StringBuilder builder, Enum enumeration, ReleaseArtistType artistType)
{
builder.Append (artistType == ReleaseArtistType.VariousArtists ? "va-" : "sa-");
Utils.EnumToString (builder, enumeration.ToString ());
}
public override string ToString ()
{
return str;
}
public override bool Equals (object o)
{
return this == o as ArtistReleaseType;
}
public static bool operator ==(ArtistReleaseType artistReleaseType1, ArtistReleaseType artistReleaseType2)
{
if (Object.ReferenceEquals (artistReleaseType1, null)) {
return Object.ReferenceEquals (artistReleaseType2, null);
}
return !Object.ReferenceEquals (artistReleaseType2, null) && artistReleaseType1.str == artistReleaseType2.str;
}
public static bool operator !=(ArtistReleaseType artistReleaseType1, ArtistReleaseType artistReleaseType2)
{
return !(artistReleaseType1 == artistReleaseType2);
}
public override int GetHashCode ()
{
return str.GetHashCode ();
}
}
#endregion
}

View File

@@ -0,0 +1,55 @@
// Disc.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Xml;
namespace MusicBrainz
{
public class Disc
{
string id;
int sectors;
internal Disc ()
{
}
internal Disc (XmlReader reader)
{
reader.Read ();
int.TryParse (reader ["sectors"], out sectors);
id = reader ["id"];
reader.Close ();
}
public string Id {
get { return id; }
protected set { id = value; }
}
public int Sectors {
get { return sectors; }
protected set { sectors = value; }
}
}
}

View File

@@ -0,0 +1,76 @@
// Event.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Xml;
namespace MusicBrainz
{
public sealed class Event
{
string date;
string country;
string catalog_number;
string barcode;
Label label;
ReleaseFormat format = ReleaseFormat.None;
internal Event (XmlReader reader)
{
reader.Read ();
date = reader ["date"];
country = reader ["country"];
catalog_number = reader ["catalog-number"];
barcode = reader ["barcode"];
format = Utils.StringToEnum<ReleaseFormat> (reader ["format"]);
if (reader.ReadToDescendant ("label")) {
label = new Label (reader.ReadSubtree ());
reader.Read (); // FIXME this is a workaround for Mono bug 334752
}
reader.Close ();
}
public string Date {
get { return date; }
}
public string Country {
get { return country; }
}
public string CatalogNumber {
get { return catalog_number; }
}
public string Barcode {
get { return barcode; }
}
public Label Label {
get { return label; }
}
public ReleaseFormat Format {
get { return format; }
}
}
}

View File

@@ -0,0 +1,137 @@
// Label.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
public sealed class Label : MusicBrainzEntity
{
#region Private
const string EXTENSION = "label";
string country;
LabelType? type;
#endregion
#region Constructors
Label (string id) : base (id, null)
{
}
internal Label (XmlReader reader) : base (reader, false)
{
}
#endregion
#region Protected
internal override string UrlExtension {
get { return EXTENSION; }
}
internal override void LoadMissingDataCore ()
{
Label label = new Label (Id);
type = label.GetLabelType ();
country = label.GetCountry ();
base.LoadMissingDataCore (label);
}
internal override void ProcessAttributes (XmlReader reader)
{
type = Utils.StringToEnum<LabelType> (reader ["type"]);
}
internal override void ProcessXmlCore (XmlReader reader)
{
if (reader.Name == "country") {
country = reader.ReadString ();
} else base.ProcessXmlCore (reader);
}
#endregion
#region Public
public string GetCountry ()
{
return GetPropertyOrNull (ref country);
}
public LabelType GetLabelType ()
{
return GetPropertyOrDefault (ref type, LabelType.None);
}
#endregion
#region Static
public static Label Get (string id)
{
if (id == null) throw new ArgumentNullException ("id");
return new Label (id);
}
public static Query<Label> Query (string name)
{
if (name == null) throw new ArgumentNullException ("name");
return new Query<Label> (EXTENSION, CreateNameParameter (name));
}
public static Query<Label> QueryLucene (string luceneQuery)
{
if (luceneQuery == null) throw new ArgumentNullException ("luceneQuery");
return new Query<Label> (EXTENSION, CreateLuceneParameter (luceneQuery));
}
public static implicit operator string (Label label)
{
return label.ToString ();
}
#endregion
}
#region Ancillary Types
public enum LabelType
{
None,
Distributor,
Holding,
OriginalProduction,
BootlegProduction,
ReissueProduction
}
#endregion
}

View File

@@ -0,0 +1,162 @@
// MusicBrainzEntity.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
// A person-like entity, such as an artist or a label.
public abstract class MusicBrainzEntity : MusicBrainzObject
{
#region Private
string name;
string sort_name;
string disambiguation;
string begin_date;
string end_date;
ReadOnlyCollection<string> aliases;
#endregion
#region Constructors
internal MusicBrainzEntity (string id, string parameters) : base (id, parameters)
{
}
internal MusicBrainzEntity (XmlReader reader, bool all_rels_loaded) : base (reader, all_rels_loaded)
{
}
#endregion
#region Protected
internal override void CreateIncCore (StringBuilder builder)
{
if (aliases == null) AppendIncParameters (builder, "aliases");
base.CreateIncCore (builder);
}
internal void LoadMissingDataCore (MusicBrainzEntity entity)
{
name = entity.GetName ();
sort_name = entity.GetSortName ();
disambiguation = entity.GetDisambiguation ();
begin_date = entity.GetBeginDate ();
end_date = entity.GetEndDate ();
if (aliases == null) aliases = entity.GetAliases ();
base.LoadMissingDataCore (entity);
}
internal override void ProcessXmlCore (XmlReader reader)
{
switch (reader.Name) {
case "name":
name = reader.ReadString ();
break;
case "sort-name":
sort_name = reader.ReadString ();
break;
case "disambiguation":
disambiguation = reader.ReadString ();
break;
case "life-span":
begin_date = reader ["begin"];
end_date = reader ["end"];
break;
case "alias-list":
if (reader.ReadToDescendant ("alias")) {
List<string> aliases = new List<string> ();
do aliases.Add (reader.ReadString ());
while (reader.ReadToNextSibling ("alias"));
this.aliases = aliases.AsReadOnly ();
}
break;
default:
base.ProcessXmlCore (reader);
break;
}
}
internal static string CreateNameParameter (string name)
{
StringBuilder builder = new StringBuilder (name.Length + 6);
builder.Append ("&name=");
Utils.PercentEncode (builder, name);
return builder.ToString ();
}
#endregion
#region Public
public virtual string GetName ()
{
return GetPropertyOrNull (ref name);
}
[Queryable ("sortname")]
public virtual string GetSortName ()
{
return GetPropertyOrNull (ref sort_name);
}
[Queryable ("comment")]
public virtual string GetDisambiguation ()
{
return GetPropertyOrNull (ref disambiguation);
}
[Queryable ("begin")]
public virtual string GetBeginDate ()
{
return GetPropertyOrNull (ref begin_date);
}
[Queryable ("end")]
public virtual string GetEndDate ()
{
return GetPropertyOrNull (ref end_date);
}
[QueryableMember ("Contains", "alias")]
public virtual ReadOnlyCollection<string> GetAliases ()
{
return GetPropertyOrNew (ref aliases);
}
public override string ToString ()
{
return name;
}
#endregion
}
}

View File

@@ -0,0 +1,50 @@
// MusicBrainzException.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace MusicBrainz
{
public sealed class MusicBrainzInvalidParameterException : Exception
{
public MusicBrainzInvalidParameterException ()
: base ("One of the parameters is invalid. The ID may be invalid, or you may be using an illegal parameter for this resource type.")
{
}
}
public sealed class MusicBrainzNotFoundException : Exception
{
public MusicBrainzNotFoundException ()
: base ("Specified resource was not found. Perhaps it was merged or deleted.")
{
}
}
public sealed class MusicBrainzUnauthorizedException : Exception
{
public MusicBrainzUnauthorizedException ()
: base ("The client is not authorized to perform this action. You may not have authenticated, or the username or password may be incorrect.")
{
}
}
}

View File

@@ -0,0 +1,187 @@
// MusicBrainzItem.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
// The item-like product of an artist, such as a track or a release.
public abstract class MusicBrainzItem : MusicBrainzObject
{
#region Private
string title;
Artist artist;
#endregion
#region Constructors
internal MusicBrainzItem (string id) : base (id, null)
{
}
internal MusicBrainzItem (XmlReader reader, Artist artist, bool all_rels_loaded) : base (reader, all_rels_loaded)
{
if (this.artist == null) this.artist = artist;
}
#endregion
#region Protected Overrides
internal override void CreateIncCore (StringBuilder builder)
{
if (artist == null) AppendIncParameters(builder, "artist");
base.CreateIncCore (builder);
}
internal void LoadMissingDataCore (MusicBrainzItem item)
{
title = item.GetTitle ();
if (artist == null) artist = item.GetArtist ();
base.LoadMissingDataCore (item);
}
internal override void ProcessXmlCore (XmlReader reader)
{
switch (reader.Name) {
case "title":
title = reader.ReadString ();
break;
case "artist":
artist = new Artist (reader.ReadSubtree ());
break;
default:
base.ProcessXmlCore (reader);
break;
}
}
#endregion
#region Public
public virtual string GetTitle ()
{
return GetPropertyOrNull (ref title);
}
[Queryable ("artist")]
public virtual Artist GetArtist ()
{
return GetPropertyOrNull (ref artist);
}
public override string ToString ()
{
return title;
}
#endregion
}
#region Ancillary Types
public abstract class ItemQueryParameters
{
internal ItemQueryParameters ()
{
}
string title;
public string Title {
get { return title; }
set { title = value; }
}
string artist;
public string Artist {
get { return artist; }
set { artist = value; }
}
string artist_id;
public string ArtistId {
get { return artist_id; }
set { artist_id = value; }
}
ReleaseType? release_type;
public ReleaseType? ReleaseType {
get { return release_type; }
set { release_type = value; }
}
ReleaseStatus? release_status;
public ReleaseStatus? ReleaseStatus {
get { return release_status; }
set { release_status = value; }
}
int? count;
public int? TrackCount {
get { return count; }
set { count = value; }
}
internal abstract void ToStringCore (StringBuilder builder);
public override string ToString ()
{
StringBuilder builder = new StringBuilder ();
ToStringCore (builder);
if (title != null) {
builder.Append ("&title=");
Utils.PercentEncode (builder, title);
}
if (artist != null) {
builder.Append ("&artist=");
Utils.PercentEncode (builder, artist);
}
if (artist_id != null) {
builder.Append ("&artistid=");
builder.Append (artist_id);
}
if (release_type != null) {
builder.Append ("&releasetypes=");
builder.Append (Utils.EnumToString (release_type.Value));
}
if (release_status != null) {
builder.Append (release_type != null ? "+" : "&releasetypes=");
builder.Append (release_status);
}
if (count != null) {
builder.Append ("&count=");
builder.Append (count.Value);
}
return builder.ToString ();
}
}
#endregion
}

View File

@@ -0,0 +1,485 @@
// MusicBrainzObject.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Xml;
namespace MusicBrainz
{
public abstract class MusicBrainzObject
{
#region Private Fields
static DateTime last_accessed;
static readonly TimeSpan min_interval = new TimeSpan (0, 0, 1); // 1 second
static readonly object server_mutex = new object ();
static readonly string [] rels_params = new string [] {
"artist-rels",
"release-rels",
"track-rels",
"label-rels",
"url-rels"
};
bool all_data_loaded;
bool all_rels_loaded;
string id;
byte score;
ReadOnlyCollection<Relation<Artist>> artist_rels;
ReadOnlyCollection<Relation<Release>> release_rels;
ReadOnlyCollection<Relation<Track>> track_rels;
ReadOnlyCollection<Relation<Label>> label_rels;
ReadOnlyCollection<UrlRelation> url_rels;
#endregion
#region Constructors
internal MusicBrainzObject (string id, string parameters)
{
all_data_loaded = true;
CreateFromId (id, parameters ?? CreateInc ());
}
internal MusicBrainzObject (XmlReader reader, bool all_rels_loaded)
{
this.all_rels_loaded = all_rels_loaded;
CreateFromXml (reader);
}
#endregion
#region Private Methods
string CreateInc ()
{
StringBuilder builder = new StringBuilder ();
CreateIncCore (builder);
return builder.ToString ();
}
void CreateFromId (string id, string parameters)
{
XmlProcessingClosure (
CreateUrl (UrlExtension, id, parameters),
delegate (XmlReader reader) {
reader.ReadToFollowing ("metadata");
reader.Read ();
CreateFromXml (reader.ReadSubtree ());
reader.Close ();
}
);
}
void CreateFromXml (XmlReader reader)
{
reader.Read ();
id = reader ["id"];
byte.TryParse (reader ["ext:score"], out score);
ProcessAttributes (reader);
while (reader.Read () && reader.NodeType != XmlNodeType.EndElement) {
if (reader.Name == "relation-list") {
all_rels_loaded = true;
switch (reader ["target-type"]) {
case "Artist":
artist_rels = CreateRelation<Artist> (reader.ReadSubtree ());
break;
case "Release":
release_rels = CreateRelation<Release> (reader.ReadSubtree ());
break;
case "Track":
track_rels = CreateRelation<Track> (reader.ReadSubtree ());
break;
case "Label":
label_rels = CreateRelation<Label> (reader.ReadSubtree ());
break;
case "Url":
url_rels = CreateUrlRelation (reader.ReadSubtree ());
break;
}
} else
ProcessXml (reader.ReadSubtree ());
}
reader.Close ();
}
void ProcessXml (XmlReader reader)
{
reader.Read ();
ProcessXmlCore (reader);
reader.Close ();
}
#endregion
#region Protected
internal bool AllDataLoaded {
get { return all_data_loaded; }
}
internal bool AllRelsLoaded {
get { return all_rels_loaded; }
set { all_rels_loaded = value; }
}
internal virtual void CreateIncCore (StringBuilder builder)
{
if (!all_rels_loaded)
AppendIncParameters (builder, rels_params);
}
internal static void AppendIncParameters (StringBuilder builder, string parameter)
{
builder.Append (builder.Length == 0 ? "&inc=" : "+");
builder.Append (parameter);
}
internal static void AppendIncParameters (StringBuilder builder, string parameter1, string parameter2)
{
builder.Append (builder.Length == 0 ? "&inc=" : "+");
builder.Append (parameter1);
builder.Append ('+');
builder.Append (parameter2);
}
internal static void AppendIncParameters (StringBuilder builder, string [] parameters)
{
foreach (string parameter in parameters)
AppendIncParameters (builder, parameter);
}
internal void LoadMissingData ()
{
if (!all_data_loaded) {
LoadMissingDataCore ();
all_data_loaded = true;
}
}
internal void LoadMissingDataCore (MusicBrainzObject obj)
{
if (!all_rels_loaded) {
artist_rels = obj.GetArtistRelations ();
release_rels = obj.GetReleaseRelations ();
track_rels = obj.GetTrackRelations ();
label_rels = obj.GetLabelRelations ();
url_rels = obj.GetUrlRelations ();
}
}
internal T GetPropertyOrNull<T> (ref T field_reference) where T : class
{
if (field_reference == null) LoadMissingData ();
return field_reference;
}
internal T GetPropertyOrDefault<T> (ref T? field_reference) where T : struct
{
return GetPropertyOrDefault (ref field_reference, default (T));
}
internal T GetPropertyOrDefault<T> (ref T? field_reference, T default_value) where T : struct
{
if (field_reference == null) LoadMissingData ();
return field_reference ?? default_value;
}
internal ReadOnlyCollection<T> GetPropertyOrNew<T> (ref ReadOnlyCollection<T> field_reference)
{
return GetPropertyOrNew (ref field_reference, true);
}
internal ReadOnlyCollection<T> GetPropertyOrNew<T> (ref ReadOnlyCollection<T> field_reference, bool condition)
{
if (field_reference == null && condition) LoadMissingData ();
return field_reference ?? new ReadOnlyCollection<T> (new T [0]);
}
internal virtual void ProcessXmlCore (XmlReader reader)
{
reader.Skip (); // FIXME this is a workaround for Mono bug 334752
}
internal virtual void ProcessAttributes (XmlReader reader)
{
}
internal abstract void LoadMissingDataCore ();
internal abstract string UrlExtension { get; }
#endregion
#region Public
public virtual string Id {
get { return id; }
}
public virtual byte Score {
get { return score; }
}
public virtual ReadOnlyCollection<Relation<Artist>> GetArtistRelations ()
{
return GetPropertyOrNew (ref artist_rels, !all_rels_loaded);
}
public virtual ReadOnlyCollection<Relation<Release>> GetReleaseRelations ()
{
return GetPropertyOrNew (ref release_rels, !all_rels_loaded);
}
public virtual ReadOnlyCollection<Relation<Track>> GetTrackRelations ()
{
return GetPropertyOrNew (ref track_rels, !all_rels_loaded);
}
public virtual ReadOnlyCollection<Relation<Label>> GetLabelRelations ()
{
return GetPropertyOrNew (ref label_rels, !all_rels_loaded);
}
public virtual ReadOnlyCollection<UrlRelation> GetUrlRelations ()
{
return GetPropertyOrNew (ref url_rels, !all_rels_loaded);
}
public override bool Equals (object obj)
{
return this == obj as MusicBrainzObject;
}
public static bool operator ==(MusicBrainzObject obj1, MusicBrainzObject obj2)
{
if (Object.ReferenceEquals (obj1, null)) {
return Object.ReferenceEquals (obj2, null);
}
return !Object.ReferenceEquals (obj2, null) && obj1.GetType () == obj2.GetType () && obj1.Id == obj2.Id;
}
public static bool operator !=(MusicBrainzObject obj1, MusicBrainzObject obj2)
{
return !(obj1 == obj2);
}
public override int GetHashCode ()
{
return (GetType ().Name + Id).GetHashCode ();
}
#endregion
#region Static
static ReadOnlyCollection<Relation<T>> CreateRelation<T> (XmlReader reader) where T : MusicBrainzObject
{
List<Relation<T>> relations = new List<Relation<T>> ();
while (reader.ReadToFollowing ("relation")) {
string type = reader ["type"];
RelationDirection direction = RelationDirection.Forward;
string direction_string = reader ["direction"];
if (direction_string != null && direction_string == "backward")
direction = RelationDirection.Backward;
string begin = reader ["begin"];
string end = reader ["end"];
string attributes_string = reader ["attributes"];
string [] attributes = attributes_string == null
? null : attributes_string.Split (' ');
reader.Read ();
relations.Add (new Relation<T> (
type,
ConstructMusicBrainzObjectFromXml<T> (reader.ReadSubtree ()),
direction,
begin,
end,
attributes));
}
reader.Close ();
return relations.AsReadOnly ();
}
static ReadOnlyCollection<UrlRelation> CreateUrlRelation (XmlReader reader)
{
List<UrlRelation> url_rels = new List<UrlRelation> ();
while (reader.ReadToDescendant ("relation")) {
RelationDirection direction = RelationDirection.Forward;
string direction_string = reader["direction"];
if (direction_string != null && direction_string == "backward")
direction = RelationDirection.Backward;
string attributes_string = reader["attributes"];
string[] attributes = attributes_string == null
? null : attributes_string.Split (' ');
url_rels.Add (new UrlRelation (
reader["type"],
reader["target"],
direction,
reader["begin"],
reader["end"],
attributes));
}
return url_rels.AsReadOnly ();
}
static string CreateUrl (string url_extension, int limit, int offset, string parameters)
{
StringBuilder builder = new StringBuilder ();
if (limit != 25) {
builder.Append ("&limit=");
builder.Append (limit);
}
if (offset != 0) {
builder.Append ("&offset=");
builder.Append (offset);
}
builder.Append (parameters);
return CreateUrl (url_extension, string.Empty, builder.ToString ());
}
static string CreateUrl (string url_extension, string id, string parameters)
{
StringBuilder builder = new StringBuilder (
MusicBrainzService.ServiceUrl.AbsoluteUri.Length + id.Length + parameters.Length + 9);
builder.Append (MusicBrainzService.ServiceUrl.AbsoluteUri);
builder.Append (url_extension);
builder.Append ('/');
builder.Append (id);
builder.Append ("?type=xml");
builder.Append (parameters);
return builder.ToString ();
}
static void XmlProcessingClosure (string url, XmlProcessingDelegate code)
{
Monitor.Enter (server_mutex);
// Don't access the MB server twice within a second
TimeSpan time = DateTime.Now - last_accessed;
if (min_interval > time)
Thread.Sleep ((min_interval - time).Milliseconds);
WebRequest request = WebRequest.Create (url);
bool cache_implemented = false;
try {
request.CachePolicy = MusicBrainzService.CachePolicy;
cache_implemented = true;
} catch (NotImplementedException) {}
HttpWebResponse response = null;
try {
response = (HttpWebResponse)request.GetResponse ();
} catch (WebException e) {
response = (HttpWebResponse)e.Response;
}
if (response == null) throw new MusicBrainzNotFoundException ();
switch (response.StatusCode) {
case HttpStatusCode.BadRequest:
Monitor.Exit (server_mutex);
throw new MusicBrainzInvalidParameterException ();
case HttpStatusCode.Unauthorized:
Monitor.Exit (server_mutex);
throw new MusicBrainzUnauthorizedException ();
case HttpStatusCode.NotFound:
Monitor.Exit (server_mutex);
throw new MusicBrainzNotFoundException ();
}
bool from_cache = cache_implemented && response.IsFromCache;
if (from_cache) Monitor.Exit (server_mutex);
MusicBrainzService.OnXmlRequest (url, from_cache);
// Should we read the stream into a memory stream and run the XmlReader off of that?
code (new XmlTextReader (response.GetResponseStream ()));
response.Close ();
if (!from_cache) {
last_accessed = DateTime.Now;
Monitor.Exit (server_mutex);
}
}
#endregion
#region Query
internal static string CreateLuceneParameter (string query)
{
StringBuilder builder = new StringBuilder (query.Length + 7);
builder.Append ("&query=");
Utils.PercentEncode (builder, query);
return builder.ToString ();
}
internal static List<T> Query<T> (string url_extension,
int limit, int offset,
string parameters,
out int? count) where T : MusicBrainzObject
{
int count_value = 0;
List<T> results = new List<T> ();
XmlProcessingClosure (
CreateUrl (url_extension, limit, offset, parameters),
delegate (XmlReader reader) {
reader.ReadToFollowing ("metadata");
reader.Read ();
int.TryParse (reader ["count"], out count_value);
while (reader.Read () && reader.NodeType == XmlNodeType.Element)
results.Add (ConstructMusicBrainzObjectFromXml<T> (reader.ReadSubtree ()));
reader.Close ();
}
);
count = count_value == 0 ? results.Count : count_value;
return results;
}
static T ConstructMusicBrainzObjectFromXml<T> (XmlReader reader) where T : MusicBrainzObject
{
ConstructorInfo constructor = typeof (T).GetConstructor (
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new Type [] { typeof (XmlReader) },
null);
return (T)constructor.Invoke (new object [] {reader});
}
#endregion
}
internal delegate void XmlProcessingDelegate (XmlReader reader);
}

View File

@@ -0,0 +1,53 @@
// MusicBrainzService.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Net.Cache;
namespace MusicBrainz
{
public static class MusicBrainzService
{
static Uri service_url = new Uri (@"http://musicbrainz.org/ws/1/");
public static Uri ServiceUrl {
get { return service_url; }
set {
if (value == null) throw new ArgumentNullException ("value");
service_url = value;
}
}
static RequestCachePolicy cache_policy;
public static RequestCachePolicy CachePolicy {
get { return cache_policy; }
set { cache_policy = value; }
}
public static event EventHandler<XmlRequestEventArgs> XmlRequest;
internal static void OnXmlRequest (string url, bool fromCache)
{
EventHandler<XmlRequestEventArgs> handler = XmlRequest;
if (handler != null) handler (null, new XmlRequestEventArgs (new Uri (url), fromCache));
}
}
}

View File

@@ -0,0 +1,197 @@
// Query.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace MusicBrainz
{
public sealed class Query<T> : IEnumerable<T> where T : MusicBrainzObject
{
#region Private
const int default_limit = 100;
string parameters;
string url_extension;
int limit = default_limit;
int offset;
int? count;
List<T> results;
List<T> ResultsWindow {
get {
if (results == null)
LoadResults ();
return results;
}
}
void LoadResults ()
{
results = MusicBrainzObject.Query<T> (url_extension, limit, offset, parameters, out count);
}
Dictionary<int, WeakReference> weak_references = new Dictionary<int, WeakReference> ();
int Offset {
get { return offset; }
set {
if (value == offset) return;
// We WeakReference the results from previous offsets just in case.
if (results != null)
if (!weak_references.ContainsKey (offset))
weak_references.Add (offset, new WeakReference (results));
else weak_references [offset].Target = results;
results = null;
offset = value;
if (weak_references.ContainsKey (offset)) {
WeakReference weak_reference = weak_references [offset];
if (weak_reference.IsAlive)
results = (List<T>)weak_reference.Target;
}
}
}
#endregion
#region Constructors
internal Query (string url_extension, string parameters)
{
this.url_extension = url_extension;
this.parameters = parameters;
}
#endregion
#region Public
public int Count {
get {
if (count == null)
LoadResults ();
return count.Value;
}
}
public T this [int index] {
get {
if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException ("index");
if (index < offset || index >= offset + limit)
Offset = index;
return ResultsWindow[index - offset];
}
}
public T First ()
{
int tmp_limit = limit;
limit = 1;
T result = Count > 0 ? this [0] : null;
limit = tmp_limit;
return result;
}
public T PerfectMatch ()
{
int tmp_limit = limit;
limit = 2;
T result1 = Count > 0 ? this [0] : null;
T result2 = Count > 1 ? this [1] : null;
limit = tmp_limit;
return (result1 != null && result1.Score == 100 && (result2 == null || result2.Score < 100))
? result1 : null;
}
public IEnumerable<T> Best ()
{
return Best (100);
}
public IEnumerable<T> Best (int scoreThreshold)
{
foreach (T result in this) {
if (result.Score < scoreThreshold) yield break;
yield return result;
}
}
public IEnumerator<T> GetEnumerator ()
{
for (int i = 0; i < Count; i++) yield return this [i];
}
IEnumerator IEnumerable.GetEnumerator ()
{
return GetEnumerator ();
}
public static implicit operator T (Query<T> query)
{
return query.First ();
}
#endregion
}
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Property)]
internal sealed class QueryableAttribute : Attribute
{
readonly string name;
public QueryableAttribute (string name)
{
this.name = name;
}
public string Name {
get { return name; }
}
}
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Property)]
internal sealed class QueryableMemberAttribute : Attribute
{
readonly string member;
readonly string name;
public QueryableMemberAttribute (string member, string name)
{
this.member = member;
this.name = name;
}
public string Member {
get { return member; }
}
public string Name {
get { return name; }
}
}
}

View File

@@ -0,0 +1,104 @@
// Relation.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.ObjectModel;
namespace MusicBrainz
{
public abstract class RelationBase<T>
{
T target;
string type;
ReadOnlyCollection<string> attributes;
RelationDirection direction;
string begin;
string end;
internal RelationBase (string type, T target, RelationDirection direction,
string begin, string end, string [] attributes)
{
this.type = type;
this.target = target;
this.direction = direction;
this.begin = begin;
this.end = end;
this.attributes = new ReadOnlyCollection<string> (attributes ?? new string [0]);
}
public T Target {
get { return target; }
}
public string Type {
get { return type; }
}
public ReadOnlyCollection<string> Attributes {
get { return attributes; }
}
public RelationDirection Direction {
get { return direction; }
}
public string BeginDate {
get { return begin; }
}
public string EndDate {
get { return end; }
}
}
public sealed class Relation<T> : RelationBase<T> where T : MusicBrainzObject
{
internal Relation (string type,
T target,
RelationDirection direction,
string begin,
string end,
string [] attributes)
: base (type, target, direction, begin, end, attributes)
{
}
}
public sealed class UrlRelation : RelationBase<Uri>
{
internal UrlRelation(string type,
string target,
RelationDirection direction,
string begin,
string end,
string [] attributes)
: base (type, new Uri (target), direction, begin, end, attributes)
{
}
}
public enum RelationDirection
{
Forward,
Backward
}
}

View File

@@ -0,0 +1,395 @@
// Release.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
public sealed class Release : MusicBrainzItem
{
#region Private
const string EXTENSION = "release";
ReleaseType? type;
ReleaseStatus? status;
string language;
string script;
string asin;
ReadOnlyCollection<Disc> discs;
ReadOnlyCollection<Event> events;
ReadOnlyCollection<Track> tracks;
int? track_number;
#endregion
#region Constructors
Release (string id) : base (id)
{
}
internal Release (XmlReader reader) : base (reader, null, false)
{
}
#endregion
#region Protected
internal override string UrlExtension {
get { return EXTENSION; }
}
static readonly string [] track_params = new string [] { "tracks", "track-level-rels", "artist" };
internal override void CreateIncCore (StringBuilder builder)
{
AppendIncParameters (builder, "release-events", "labels");
if (discs == null) AppendIncParameters (builder, "discs");
if (tracks == null) {
AppendIncParameters (builder, track_params);
AllRelsLoaded = false;
}
base.CreateIncCore (builder);
}
internal override void LoadMissingDataCore ()
{
Release release = new Release (Id);
type = release.GetReleaseType ();
status = release.GetReleaseStatus ();
language = release.GetLanguage ();
script = release.GetScript ();
asin = release.GetAsin ();
events = release.GetEvents ();
if (discs == null) discs = release.GetDiscs ();
if (tracks == null) tracks = release.GetTracks ();
base.LoadMissingDataCore (release);
}
internal override void ProcessAttributes (XmlReader reader)
{
// How sure am I about getting the type and status in the "Type Status" format?
// MB really ought to specify these two things seperatly.
string type_string = reader ["type"];
if (type_string != null) {
foreach (string token in type_string.Split (' ')) {
if (type == null) {
type = Utils.StringToEnumOrNull<ReleaseType> (token);
if (type != null) continue;
}
this.status = Utils.StringToEnumOrNull<ReleaseStatus> (token);
}
}
}
internal override void ProcessXmlCore (XmlReader reader)
{
switch (reader.Name) {
case "text-representation":
language = reader["language"];
script = reader["script"];
break;
case "asin":
asin = reader.ReadString ();
break;
case "disc-list":
if (reader.ReadToDescendant ("disc")) {
List<Disc> discs = new List<Disc> ();
do discs.Add (new Disc (reader.ReadSubtree ()));
while (reader.ReadToNextSibling ("disc"));
this.discs = discs.AsReadOnly ();
}
break;
case "release-event-list":
if (!AllDataLoaded) {
reader.Skip (); // FIXME this is a workaround for Mono bug 334752
return;
}
if (reader.ReadToDescendant ("event")) {
List<Event> events = new List<Event> ();
do events.Add (new Event (reader.ReadSubtree ()));
while (reader.ReadToNextSibling ("event"));
this.events = events.AsReadOnly ();
}
break;
case "track-list":
string offset = reader["offset"];
if (offset != null)
track_number = int.Parse (offset) + 1;
if (reader.ReadToDescendant ("track")) {
List<Track> tracks = new List<Track> ();
do tracks.Add (new Track (reader.ReadSubtree (), GetArtist (), AllDataLoaded));
while (reader.ReadToNextSibling ("track"));
this.tracks = tracks.AsReadOnly ();
}
break;
default:
base.ProcessXmlCore (reader);
break;
}
}
#endregion
#region Public
[Queryable ("reid")]
public override string Id {
get { return base.Id; }
}
[Queryable ("release")]
public override string GetTitle ()
{
return base.GetTitle ();
}
[Queryable ("type")]
public ReleaseType GetReleaseType ()
{
return GetPropertyOrDefault (ref type, ReleaseType.None);
}
[Queryable ("status")]
public ReleaseStatus GetReleaseStatus ()
{
return GetPropertyOrDefault (ref status, ReleaseStatus.None);
}
public string GetLanguage ()
{
return GetPropertyOrNull (ref language);
}
[Queryable ("script")]
public string GetScript ()
{
return GetPropertyOrNull (ref script);
}
[Queryable ("asin")]
public string GetAsin ()
{
return GetPropertyOrNull (ref asin);
}
[QueryableMember("Count", "discids")]
public ReadOnlyCollection<Disc> GetDiscs ()
{
return GetPropertyOrNew (ref discs);
}
public ReadOnlyCollection<Event> GetEvents ()
{
return GetPropertyOrNew (ref events);
}
[QueryableMember ("Count", "tracks")]
public ReadOnlyCollection<Track> GetTracks ()
{
return GetPropertyOrNew (ref tracks);
}
internal int TrackNumber {
get { return track_number ?? -1; }
}
#endregion
#region Static
public static Release Get (string id)
{
if (id == null) throw new ArgumentNullException ("id");
return new Release (id);
}
public static Query<Release> Query (string title)
{
if (title == null) throw new ArgumentNullException ("title");
ReleaseQueryParameters parameters = new ReleaseQueryParameters ();
parameters.Title = title;
return Query (parameters);
}
public static Query<Release> Query (string title, string artist)
{
if (title == null) throw new ArgumentNullException ("title");
if (artist == null) throw new ArgumentNullException ("artist");
ReleaseQueryParameters parameters = new ReleaseQueryParameters ();
parameters.Title = title;
parameters.Artist = artist;
return Query (parameters);
}
public static Query<Release> Query (Disc disc)
{
if (disc == null) throw new ArgumentNullException ("disc");
ReleaseQueryParameters parameters = new ReleaseQueryParameters ();
parameters.DiscId = disc.Id;
return Query (parameters);
}
public static Query<Release> Query (ReleaseQueryParameters parameters)
{
if (parameters == null) throw new ArgumentNullException ("parameters");
return new Query<Release> (EXTENSION, parameters.ToString ());
}
//public static Query<Release> QueryFromDevice(string device)
//{
// if (device == null) throw new ArgumentNullException ("device");
// ReleaseQueryParameters parameters = new ReleaseQueryParameters ();
// parameters.DiscId = LocalDisc.GetFromDevice (device).Id;
// return Query (parameters);
//}
public static Query<Release> QueryLucene (string luceneQuery)
{
if (luceneQuery == null) throw new ArgumentNullException ("luceneQuery");
return new Query<Release> (EXTENSION, CreateLuceneParameter (luceneQuery));
}
public static implicit operator string (Release release)
{
return release.ToString ();
}
#endregion
}
#region Ancillary Types
public enum ReleaseType
{
None,
Album,
Single,
EP,
Compilation,
Soundtrack,
Spokenword,
Interview,
Audiobook,
Live,
Remix,
Other
}
public enum ReleaseStatus
{
None,
Official,
Promotion,
Bootleg,
PsudoRelease
}
public enum ReleaseFormat
{
None,
Cartridge,
Cassette,
CD,
DAT,
Digital,
DualDisc,
DVD,
LaserDisc,
MiniDisc,
Other,
ReelToReel,
SACD,
Vinyl
}
public sealed class ReleaseQueryParameters : ItemQueryParameters
{
string disc_id;
public string DiscId {
get { return disc_id; }
set { disc_id = value; }
}
string date;
public string Date {
get { return date; }
set { date = value; }
}
string asin;
public string Asin {
get { return asin; }
set { asin = value; }
}
string language;
public string Language {
get { return language; }
set { language = value; }
}
string script;
public string Script {
get { return script; }
set { script = value; }
}
internal override void ToStringCore (StringBuilder builder)
{
if (disc_id != null) {
builder.Append ("&discid=");
builder.Append (disc_id);
}
if (date != null) {
builder.Append ("&date=");
Utils.PercentEncode (builder, date);
}
if (asin != null) {
builder.Append ("&asin=");
builder.Append (asin);
}
if (language != null) {
builder.Append ("&lang=");
builder.Append (language);
}
if (script != null) {
builder.Append ("&script=");
builder.Append (script);
}
}
}
#endregion
}

View File

@@ -0,0 +1,276 @@
// Track.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Xml;
namespace MusicBrainz
{
public sealed class Track : MusicBrainzItem
{
#region Private
const string EXTENSION = "track";
TimeSpan? duration;
ReadOnlyCollection<Release> releases;
ReadOnlyCollection<string> puids;
#endregion
#region Constructors
Track (string id) : base (id)
{
}
internal Track (XmlReader reader) : base (reader, null, false)
{
}
internal Track (XmlReader reader, Artist artist, bool all_rels_loaded) : base (reader, artist, all_rels_loaded)
{
}
#endregion
#region Protected
internal override string UrlExtension {
get { return EXTENSION; }
}
internal override void CreateIncCore (StringBuilder builder)
{
if (releases == null) AppendIncParameters (builder, "releases");
if (puids == null) AppendIncParameters (builder, "puids");
base.CreateIncCore (builder);
}
internal override void LoadMissingDataCore ()
{
Track track = new Track (Id);
duration = track.GetDuration ();
if (releases == null) releases = track.GetReleases ();
if (puids == null) puids = track.GetPuids ();
base.LoadMissingDataCore (track);
}
internal override void ProcessXmlCore (XmlReader reader)
{
switch (reader.Name) {
case "duration":
duration = TimeSpan.FromMilliseconds (reader.ReadElementContentAsDouble ());
break;
case "release-list":
if (reader.ReadToDescendant ("release")) {
List<Release> releases = new List<Release> ();
do releases.Add (new Release (reader.ReadSubtree ()));
while (reader.ReadToNextSibling ("release"));
this.releases = releases.AsReadOnly ();
}
break;
case "puid-list":
if (reader.ReadToDescendant ("puid")) {
List<string> puids = new List<string> ();
do puids.Add (reader["id"]);
while (reader.ReadToNextSibling ("puid"));
this.puids = puids.AsReadOnly ();
}
break;
default:
base.ProcessXmlCore (reader);
break;
}
}
#endregion
#region Public
[Queryable ("trid")]
public override string Id {
get { return base.Id; }
}
[Queryable ("track")]
public override string GetTitle ()
{
return base.GetTitle ();
}
[Queryable ("dur")]
public TimeSpan GetDuration ()
{
return GetPropertyOrDefault (ref duration);
}
[QueryableMember ("Contains", "release")]
public ReadOnlyCollection<Release> GetReleases ()
{
return GetPropertyOrNew (ref releases);
}
public ReadOnlyCollection<string> GetPuids ()
{
return GetPropertyOrNew (ref puids);
}
public int GetTrackNumber (Release release)
{
if (release == null) throw new ArgumentNullException ("release");
foreach (Release r in GetReleases ())
if (r.Equals (release))
return r.TrackNumber;
return -1;
}
#endregion
#region Static
public static Track Get (string id)
{
if (id == null) throw new ArgumentNullException ("id");
return new Track (id);
}
public static Query<Track> Query (string title)
{
if (title == null) throw new ArgumentNullException ("title");
TrackQueryParameters parameters = new TrackQueryParameters ();
parameters.Title = title;
return Query (parameters);
}
public static Query<Track> Query (string title, string artist)
{
if (title == null) throw new ArgumentNullException ("title");
if (artist == null) throw new ArgumentNullException ("artist");
TrackQueryParameters parameters = new TrackQueryParameters ();
parameters.Title = title;
parameters.Artist = artist;
return Query (parameters);
}
public static Query<Track> Query (string title, string artist, string release)
{
if (title == null) throw new ArgumentNullException ("title");
if (artist == null) throw new ArgumentNullException ("artist");
if (release == null) throw new ArgumentNullException ("release");
TrackQueryParameters parameters = new TrackQueryParameters ();
parameters.Title = title;
parameters.Artist = artist;
parameters.Release = release;
return Query (parameters);
}
public static Query<Track> Query (TrackQueryParameters parameters)
{
if (parameters == null) throw new ArgumentNullException ("parameters");
return new Query<Track> (EXTENSION, parameters.ToString ());
}
public static Query<Track> QueryLucene (string luceneQuery)
{
if(luceneQuery == null) throw new ArgumentNullException ("luceneQuery");
return new Query<Track> (EXTENSION, CreateLuceneParameter (luceneQuery));
}
public static implicit operator string (Track track)
{
return track.ToString ();
}
#endregion
}
#region Ancillary Types
public sealed class TrackQueryParameters : ItemQueryParameters
{
string release;
public string Release {
get { return release; }
set { release = value; }
}
string release_id;
public string ReleaseId {
get { return release_id; }
set { release_id = value; }
}
uint? duration;
public uint? Duration {
get { return duration; }
set { duration = value; }
}
int? track_number;
public int? TrackNumber {
get { return track_number; }
set { track_number = value; }
}
string puid;
public string Puid {
get { return puid; }
set { puid = value; }
}
internal override void ToStringCore (StringBuilder builder)
{
if (release != null) {
builder.Append ("&release=");
Utils.PercentEncode (builder, release);
}
if (release_id != null) {
builder.Append ("&releaseid=");
builder.Append (release_id);
}
if (duration != null) {
builder.Append ("&duration=");
builder.Append (duration.Value);
}
if (track_number != null) {
builder.Append ("&tracknumber=");
builder.Append (track_number.Value);
}
if (puid != null) {
builder.Append ("&puid=");
builder.Append (puid);
}
}
}
#endregion
}

View File

@@ -0,0 +1,76 @@
// Utils.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Text;
namespace MusicBrainz
{
internal static class Utils
{
public static string EnumToString (Enum enumeration)
{
string str = enumeration.ToString ();
StringBuilder builder = new StringBuilder (str.Length);
EnumToString (builder, str);
return builder.ToString ();
}
public static void EnumToString (StringBuilder builder, string str)
{
builder.Append (str [0]);
for (int i = 1; i < str.Length; i++) {
if (str [i] >= 'A' && str [i] <= 'Z')
builder.Append ('-');
builder.Append (str [i]);
}
}
public static T StringToEnum<T> (string name) where T : struct
{
return StringToEnumOrNull<T> (name) ?? default (T);
}
public static T? StringToEnumOrNull<T> (string name) where T : struct
{
if (name != null)
foreach (T value in Enum.GetValues (typeof (T)))
if (Enum.GetName (typeof (T), value) == name)
return value;
return null;
}
public static void PercentEncode (StringBuilder builder, string value)
{
foreach (char c in value) {
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') ||
c == '-' || c == '_' || c == '.' || c == '~')
builder.Append (c);
else {
builder.Append ('%');
foreach (byte b in Encoding.UTF8.GetBytes (new char [] { c }))
builder.AppendFormat ("{0:X}", b);
}
}
}
}
}

View File

@@ -0,0 +1,38 @@
// XmlRequestEventArgs.cs
//
// Copyright (c) 2008 Scott Peterson <lunchtimemama@gmail.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
namespace MusicBrainz
{
public sealed class XmlRequestEventArgs : EventArgs
{
public readonly Uri Uri;
public readonly bool FromCache;
internal XmlRequestEventArgs (Uri uri, bool fromCache)
{
Uri = uri;
FromCache = fromCache;
}
}
}