mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 10:04:24 +00:00
more work on ripper
freedb support
This commit is contained in:
@@ -29,7 +29,7 @@ using System.Diagnostics;
|
||||
|
||||
namespace Bwg.Scsi
|
||||
{
|
||||
public class Command : IDisposable
|
||||
class Command : IDisposable
|
||||
{
|
||||
[DllImport("ntdll.dll")]
|
||||
internal static extern void RtlZeroMemory(IntPtr dest, int size);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
namespace Bwg.Scsi
|
||||
{
|
||||
public enum ScsiCommandCode
|
||||
enum ScsiCommandCode
|
||||
{
|
||||
TestUnitReady = 0x00,
|
||||
RequestSense = 0x03,
|
||||
|
||||
@@ -939,7 +939,7 @@ namespace Bwg.Scsi
|
||||
}
|
||||
#endregion
|
||||
|
||||
public CommandStatus SendCommand(Command cmd)
|
||||
private CommandStatus SendCommand(Command cmd)
|
||||
{
|
||||
return (m_ossize == 32) ? SendCommand32(cmd) : SendCommand64(cmd);
|
||||
}
|
||||
@@ -2131,29 +2131,51 @@ namespace Bwg.Scsi
|
||||
return CommandStatus.Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum SubChannelMode
|
||||
{
|
||||
/// <summary></summary>
|
||||
None,
|
||||
QOnly, /// + 16 bytes
|
||||
RWMode /// + 96 bytes
|
||||
/// <summary>+ 16 bytes</summary>
|
||||
QOnly,
|
||||
/// <summary>+ 96 bytes</summary>
|
||||
RWMode
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum C2ErrorMode
|
||||
{
|
||||
/// <summary></summary>
|
||||
None,
|
||||
Mode294, /// +294 bytes
|
||||
Mode296, /// +296 bytes
|
||||
/// <summary> +294 bytes</summary>
|
||||
Mode294,
|
||||
/// <summary> +296 bytes</summary>
|
||||
Mode296,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum MainChannelSelection
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
UserData,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
F8h
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="mainmode">main channel mode</param>
|
||||
/// <param name="submode">subchannel mode</param>
|
||||
/// <param name="c2mode">C2 errors report mode</param>
|
||||
/// <param name="exp">expected sector type</param>
|
||||
@@ -2309,6 +2331,7 @@ namespace Bwg.Scsi
|
||||
/// <param name="length"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="mode">the subchannel mode</param>
|
||||
/// <param name="timeout">timeout (in seconds)</param>
|
||||
/// <returns></returns>
|
||||
public CommandStatus ReadSubChannel(byte mode, uint sector, uint length, ref byte[] data, int timeout)
|
||||
{
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.configuration" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
@@ -111,6 +112,7 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<None Include="app.config" />
|
||||
<None Include="Properties\DataSources\MusicBrainz.Release.datasource" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
@@ -143,6 +145,10 @@
|
||||
<Project>{8CF07381-BEA2-4AFC-B3DD-9B2F21C65A3A}</Project>
|
||||
<Name>CUETools.Ripper.SCSI</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Freedb\Freedb.csproj">
|
||||
<Project>{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}</Project>
|
||||
<Name>Freedb</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\MusicBrainz\MusicBrainz.csproj">
|
||||
<Project>{74C2036B-2C9B-4FC8-B7BD-AE81A8DCE533}</Project>
|
||||
<Name>MusicBrainz</Name>
|
||||
|
||||
46
CUERipper/Properties/Settings.Designer.cs
generated
46
CUERipper/Properties/Settings.Designer.cs
generated
@@ -8,23 +8,31 @@
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace CUERipper.Properties
|
||||
{
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||
{
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default
|
||||
{
|
||||
get
|
||||
{
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace CUERipper.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "8.0.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("freedb.org")]
|
||||
public string MAIN_FREEDB_SITEADDRESS {
|
||||
get {
|
||||
return ((string)(this["MAIN_FREEDB_SITEADDRESS"]));
|
||||
}
|
||||
set {
|
||||
this["MAIN_FREEDB_SITEADDRESS"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="CUERipper.Properties" GeneratedClassName="Settings">
|
||||
<Profiles />
|
||||
<Settings>
|
||||
<Setting Name="MAIN_FREEDB_SITEADDRESS" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">freedb.org</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@@ -8,12 +8,14 @@ using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
using System.Configuration;
|
||||
using CUETools.AccurateRip;
|
||||
using CUETools.CDImage;
|
||||
using CUETools.Codecs;
|
||||
using CUETools.Processor;
|
||||
using CUETools.Ripper.SCSI;
|
||||
using MusicBrainz;
|
||||
using Freedb;
|
||||
|
||||
namespace CUERipper
|
||||
{
|
||||
@@ -228,6 +230,35 @@ namespace CUERipper
|
||||
});
|
||||
}
|
||||
|
||||
private CUESheet CreateCUESheet(CDDriveReader audioSource, Release release, CDEntry cdEntry)
|
||||
{
|
||||
CUESheet cueSheet = new CUESheet(_config);
|
||||
cueSheet.OpenCD(audioSource);
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
|
||||
if (release != null)
|
||||
cueSheet.FillFromMusicBrainz(release);
|
||||
else if (cdEntry != null)
|
||||
{
|
||||
cueSheet.Artist = cdEntry.Artist;
|
||||
cueSheet.Title = cdEntry.Title;
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "DATE", cdEntry.Year, false);
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "GENRE", cdEntry.Genre, true);
|
||||
for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
|
||||
cueSheet.Tracks[i].Title = cdEntry.Tracks[i].Title;
|
||||
}
|
||||
else
|
||||
{
|
||||
cueSheet.Artist = "Unknown Artist";
|
||||
cueSheet.Title = "Unknown Title";
|
||||
for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
|
||||
cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
|
||||
}
|
||||
cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
|
||||
cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
|
||||
return cueSheet;
|
||||
}
|
||||
|
||||
private void Lookup(object o)
|
||||
{
|
||||
CDDriveReader audioSource = (CDDriveReader)o;
|
||||
@@ -242,11 +273,7 @@ namespace CUERipper
|
||||
{
|
||||
release.GetEvents();
|
||||
release.GetTracks();
|
||||
CUESheet cueSheet = new CUESheet(_config);
|
||||
cueSheet.OpenCD(audioSource);
|
||||
cueSheet.FillFromMusicBrainz(release);
|
||||
cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
|
||||
cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
|
||||
CUESheet cueSheet = CreateCUESheet(audioSource, release, null);
|
||||
this.BeginInvoke((MethodInvoker)delegate()
|
||||
{
|
||||
comboRelease.Items.Add(cueSheet);
|
||||
@@ -257,20 +284,63 @@ namespace CUERipper
|
||||
{
|
||||
}
|
||||
MusicBrainzService.XmlRequest -= new EventHandler<XmlRequestEventArgs>(MusicBrainz_LookupProgress);
|
||||
|
||||
|
||||
FreedbHelper m_freedb = new FreedbHelper();
|
||||
|
||||
m_freedb.UserName = "gchudov";
|
||||
m_freedb.Hostname = "gmail.com";
|
||||
m_freedb.ClientName = "CUERipper";
|
||||
m_freedb.Version = "1.0";
|
||||
m_freedb.SetDefaultSiteAddress(Properties.Settings.Default.MAIN_FREEDB_SITEADDRESS);
|
||||
|
||||
QueryResult queryResult;
|
||||
QueryResultCollection coll;
|
||||
string code = string.Empty;
|
||||
try
|
||||
{
|
||||
code = m_freedb.Query(AccurateRipVerify.CalculateCDDBQuery(audioSource.TOC), out queryResult, out coll);
|
||||
if (code == FreedbHelper.ResponseCodes.CODE_200)
|
||||
{
|
||||
CDEntry cdEntry;
|
||||
code = m_freedb.Read(queryResult, out cdEntry);
|
||||
if (code == FreedbHelper.ResponseCodes.CODE_210)
|
||||
{
|
||||
CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
|
||||
this.BeginInvoke((MethodInvoker)delegate()
|
||||
{
|
||||
comboRelease.Items.Add(cueSheet);
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
if (code == FreedbHelper.ResponseCodes.CODE_210 ||
|
||||
code == FreedbHelper.ResponseCodes.CODE_211 )
|
||||
{
|
||||
foreach (QueryResult qr in coll)
|
||||
{
|
||||
CDEntry cdEntry;
|
||||
code = m_freedb.Read(qr, out cdEntry);
|
||||
if (code == FreedbHelper.ResponseCodes.CODE_210)
|
||||
{
|
||||
CUESheet cueSheet = CreateCUESheet(audioSource, null, cdEntry);
|
||||
this.BeginInvoke((MethodInvoker)delegate()
|
||||
{
|
||||
comboRelease.Items.Add(cueSheet);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
this.BeginInvoke((MethodInvoker)delegate()
|
||||
{
|
||||
if (comboRelease.Items.Count == 0)
|
||||
{
|
||||
CUESheet cueSheet = new CUESheet(_config);
|
||||
cueSheet.OpenCD(audioSource);
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(audioSource.TOC), false);
|
||||
General.SetCUELine(cueSheet.Attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
|
||||
cueSheet.Artist = "Unknown Artist";
|
||||
cueSheet.Title = "Unknown Title";
|
||||
cueSheet.AccurateRip = AccurateRipMode.VerifyAndConvert;
|
||||
cueSheet.ArVerify.ContactAccurateRip(AccurateRipVerify.CalculateAccurateRipId(audioSource.TOC));
|
||||
for (int i = 0; i < audioSource.TOC.AudioTracks; i++)
|
||||
cueSheet.Tracks[i].Title = string.Format("Track {0:00}", i + 1);
|
||||
CUESheet cueSheet = CreateCUESheet(audioSource, null, null);
|
||||
comboRelease.Items.Add(cueSheet);
|
||||
}
|
||||
});
|
||||
@@ -332,7 +402,8 @@ namespace CUERipper
|
||||
private void listTracks_AfterLabelEdit(object sender, LabelEditEventArgs e)
|
||||
{
|
||||
CUESheet cueSheet = (CUESheet)comboRelease.SelectedItem;
|
||||
cueSheet.Tracks[e.Item].Title = e.Label;
|
||||
if (e.Label != null)
|
||||
cueSheet.Tracks[e.Item].Title = e.Label;
|
||||
}
|
||||
|
||||
private void editToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
|
||||
@@ -491,6 +491,16 @@ namespace CUETools.AccurateRip
|
||||
return false;
|
||||
}
|
||||
|
||||
public static string CalculateCDDBQuery(CDImageLayout toc)
|
||||
{
|
||||
StringBuilder query = new StringBuilder(CalculateCDDBId(toc));
|
||||
query.AppendFormat("+{0}", toc.TrackCount);
|
||||
for (int iTrack = 1; iTrack <= toc.TrackCount; iTrack++)
|
||||
query.AppendFormat("+{0}", toc[iTrack].Start + 150);
|
||||
query.AppendFormat("+{0}", toc.Length / 75 - toc[1].Start / 75);
|
||||
return query.ToString();
|
||||
}
|
||||
|
||||
public static string CalculateCDDBId(CDImageLayout toc)
|
||||
{
|
||||
uint cddbDiscId = 0;
|
||||
|
||||
@@ -516,8 +516,6 @@ namespace CUETools.Processor
|
||||
|
||||
public void FillFromMusicBrainz(Release release)
|
||||
{
|
||||
General.SetCUELine(_attributes, "REM", "DISCID", AccurateRipVerify.CalculateCDDBId(_toc), false);
|
||||
General.SetCUELine(_attributes, "REM", "COMMENT", CDDriveReader.RipperVersion(), true);
|
||||
if (release.GetEvents().Count > 0)
|
||||
General.SetCUELine(_attributes, "REM", "DATE", release.GetEvents()[0].Date.Substring(0, 4), false);
|
||||
Artist = release.GetArtist();
|
||||
|
||||
@@ -75,6 +75,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MusicBrainz", "..\MusicBrai
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUERipper", "..\CUERipper\CUERipper.csproj", "{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Freedb", "..\Freedb\Freedb.csproj", "{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -370,6 +372,17 @@ Global
|
||||
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x64.Build.0 = Release|x64
|
||||
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x86.ActiveCfg = Release|x86
|
||||
{39B43BBB-BAFC-4D85-9BEA-3BCB7EFED89C}.Release|x86.Build.0 = Release|x86
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x64.Build.0 = Debug|x64
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x64.ActiveCfg = Release|x64
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x64.Build.0 = Release|x64
|
||||
{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
58
Freedb/AssemblyInfo.cs
Normal file
58
Freedb/AssemblyInfo.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("")]
|
||||
[assembly: AssemblyCopyright("")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.1")]
|
||||
|
||||
//
|
||||
// In order to sign your assembly you must specify a key to use. Refer to the
|
||||
// Microsoft .NET Framework documentation for more information on assembly signing.
|
||||
//
|
||||
// Use the attributes below to control which key is used for signing.
|
||||
//
|
||||
// Notes:
|
||||
// (*) If no key is specified, the assembly is not signed.
|
||||
// (*) KeyName refers to a key that has been installed in the Crypto Service
|
||||
// Provider (CSP) on your machine. KeyFile refers to a file which contains
|
||||
// a key.
|
||||
// (*) If the KeyFile and the KeyName values are both specified, the
|
||||
// following processing occurs:
|
||||
// (1) If the KeyName can be found in the CSP, that key is used.
|
||||
// (2) If the KeyName does not exist and the KeyFile does exist, the key
|
||||
// in the KeyFile is installed into the CSP and used.
|
||||
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
|
||||
// When specifying the KeyFile, the location of the KeyFile should be
|
||||
// relative to the project output directory which is
|
||||
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
|
||||
// located in the project directory, you would specify the AssemblyKeyFile
|
||||
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
|
||||
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
|
||||
// documentation for more information on this.
|
||||
//
|
||||
[assembly: AssemblyDelaySign(false)]
|
||||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
||||
385
Freedb/CDEntry.cs
Normal file
385
Freedb/CDEntry.cs
Normal file
@@ -0,0 +1,385 @@
|
||||
#region COPYRIGHT (c) 2004 by Brian Weeres
|
||||
/* Copyright (c) 2004 by Brian Weeres
|
||||
*
|
||||
* Email: bweeres@protegra.com; bweeres@hotmail.com
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* If you modify it then please indicate so.
|
||||
*
|
||||
* The software is provided "AS IS" and there are no warranties or implied warranties.
|
||||
* In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
|
||||
* direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
|
||||
* out of the use or performance of this software
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace Freedb
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for CDEntry.
|
||||
/// </summary>
|
||||
public class CDEntry
|
||||
{
|
||||
|
||||
|
||||
|
||||
#region Private Member Variables
|
||||
private string m_Discid;
|
||||
private string m_Artist;
|
||||
private string m_Title;
|
||||
private string m_Year;
|
||||
private string m_Genre;
|
||||
private TrackCollection m_Tracks = new TrackCollection(); // 0 based - first track is at 0 last track is at numtracks - 1
|
||||
private string m_ExtendedData;
|
||||
private string m_PlayOrder;
|
||||
|
||||
/// <summary>
|
||||
/// Property NumberOfTracks (int)
|
||||
/// </summary>
|
||||
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Member Variables
|
||||
/// <summary>
|
||||
/// Property Discid (string)
|
||||
/// </summary>
|
||||
public string Discid
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Discid;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Discid = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Artist (string)
|
||||
/// </summary>
|
||||
public string Artist
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Artist;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Artist = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Title (string)
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Title;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Title = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Year (string)
|
||||
/// </summary>
|
||||
public string Year
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Year;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Year = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Genre (string)
|
||||
/// </summary>
|
||||
public string Genre
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Genre;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Genre = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property Tracks (StringCollection)
|
||||
/// </summary>
|
||||
public TrackCollection Tracks
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Tracks;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Tracks = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property ExtendedData (string)
|
||||
/// </summary>
|
||||
public string ExtendedData
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ExtendedData;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ExtendedData = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property PlayOrder (string)
|
||||
/// </summary>
|
||||
public string PlayOrder
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_PlayOrder;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_PlayOrder = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int NumberOfTracks
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Tracks.Count;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
public CDEntry(StringCollection data)
|
||||
{
|
||||
if (!Parse(data))
|
||||
{
|
||||
throw new Exception("Unable to Parse CDEntry.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool Parse(StringCollection data)
|
||||
{
|
||||
foreach (string line in data)
|
||||
{
|
||||
|
||||
// check for comment
|
||||
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
int index = line.IndexOf('=');
|
||||
if (index == -1) // couldn't find equal sign have no clue what the data is
|
||||
continue;
|
||||
string field = line.Substring(0,index);
|
||||
index++; // move it past the equal sign
|
||||
|
||||
switch (field)
|
||||
{
|
||||
case "DISCID":
|
||||
{
|
||||
this.m_Discid = line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
case "DTITLE": // artist / title
|
||||
{
|
||||
this.m_Artist += line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
case "DYEAR":
|
||||
{
|
||||
this.m_Year = line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
case "DGENRE":
|
||||
{
|
||||
this.m_Genre += line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
case "EXTD":
|
||||
{
|
||||
// may be more than one - just concatenate them
|
||||
this.m_ExtendedData += line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
case "PLAYORDER":
|
||||
{
|
||||
this.m_PlayOrder += line.Substring(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
|
||||
//get track info or extended track info
|
||||
if (field.StartsWith("TTITLE"))
|
||||
{
|
||||
int trackNumber = -1;
|
||||
// Parse could throw an exception
|
||||
try
|
||||
{
|
||||
trackNumber = int.Parse(field.Substring("TTITLE".Length));
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Failed to parse track Number. Reason: " + ex.Message);
|
||||
continue;
|
||||
}
|
||||
|
||||
//may need to concatenate track info
|
||||
if (trackNumber < m_Tracks.Count )
|
||||
m_Tracks[trackNumber].Title += line.Substring(index);
|
||||
else
|
||||
{
|
||||
Track track = new Track(line.Substring(index));
|
||||
this.m_Tracks.Add(track);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (field.StartsWith("EXTT"))
|
||||
{
|
||||
int trackNumber = -1;
|
||||
// Parse could throw an exception
|
||||
try
|
||||
{
|
||||
trackNumber = int.Parse(field.Substring("EXTT".Length));
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Failed to parse track Number. Reason: " + ex.Message);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trackNumber < 0 || trackNumber > m_Tracks.Count -1)
|
||||
continue;
|
||||
|
||||
m_Tracks[trackNumber].ExtendedData += line.Substring(index);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
continue;
|
||||
|
||||
} //end of switch
|
||||
|
||||
}
|
||||
|
||||
|
||||
//split the title and artist from DTITLE;
|
||||
// see if we have a slash
|
||||
int slash = this.m_Artist.IndexOf(" / ");
|
||||
if (slash == -1)
|
||||
{
|
||||
this.m_Title= m_Artist;
|
||||
}
|
||||
else
|
||||
{
|
||||
string titleArtist = m_Artist;
|
||||
this.m_Artist = titleArtist.Substring(0,slash);
|
||||
slash +=3; // move past " / "
|
||||
this.m_Title = titleArtist.Substring(slash );
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append("Title: ");
|
||||
builder.Append(this.m_Title);
|
||||
builder.Append("\n");
|
||||
builder.Append("Artist: ");
|
||||
builder.Append(this.m_Artist);
|
||||
builder.Append("\n");
|
||||
builder.Append("Discid: ");
|
||||
builder.Append(this.m_Discid);
|
||||
builder.Append("\n");
|
||||
builder.Append("Genre: ");
|
||||
builder.Append(this.m_Genre);
|
||||
builder.Append("\n");
|
||||
builder.Append("Year: ");
|
||||
builder.Append(this.m_Year);
|
||||
builder.Append("\n");
|
||||
builder.Append("Tracks:");
|
||||
foreach (Track track in this.m_Tracks)
|
||||
{
|
||||
builder.Append("\n");
|
||||
builder.Append(track.Title);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
154
Freedb/Freedb.csproj
Normal file
154
Freedb/Freedb.csproj
Normal file
@@ -0,0 +1,154 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectType>Local</ProjectType>
|
||||
<ProductVersion>8.0.50727</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{5ADCFD6D-BFEA-4B10-BB45-9083BBB56AF4}</ProjectGuid>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ApplicationIcon>
|
||||
</ApplicationIcon>
|
||||
<AssemblyKeyContainerName>
|
||||
</AssemblyKeyContainerName>
|
||||
<AssemblyName>Freedb</AssemblyName>
|
||||
<AssemblyOriginatorKeyFile>
|
||||
</AssemblyOriginatorKeyFile>
|
||||
<DefaultClientScript>JScript</DefaultClientScript>
|
||||
<DefaultHTMLPageLayout>Grid</DefaultHTMLPageLayout>
|
||||
<DefaultTargetSchema>IE50</DefaultTargetSchema>
|
||||
<DelaySign>false</DelaySign>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Freedb</RootNamespace>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>..\bin\win32\Debug\</OutputPath>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<BaseAddress>285212672</BaseAddress>
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<ConfigurationOverrideFile>
|
||||
</ConfigurationOverrideFile>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<FileAlignment>4096</FileAlignment>
|
||||
<NoStdLib>false</NoStdLib>
|
||||
<NoWarn>
|
||||
</NoWarn>
|
||||
<Optimize>false</Optimize>
|
||||
<RegisterForComInterop>false</RegisterForComInterop>
|
||||
<RemoveIntegerChecks>false</RemoveIntegerChecks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>full</DebugType>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>..\bin\win32\Release\</OutputPath>
|
||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||
<BaseAddress>285212672</BaseAddress>
|
||||
<CheckForOverflowUnderflow>false</CheckForOverflowUnderflow>
|
||||
<ConfigurationOverrideFile>
|
||||
</ConfigurationOverrideFile>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DocumentationFile>
|
||||
</DocumentationFile>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<FileAlignment>4096</FileAlignment>
|
||||
<NoStdLib>false</NoStdLib>
|
||||
<NoWarn>
|
||||
</NoWarn>
|
||||
<Optimize>true</Optimize>
|
||||
<RegisterForComInterop>false</RegisterForComInterop>
|
||||
<RemoveIntegerChecks>false</RemoveIntegerChecks>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DebugType>none</DebugType>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<BaseAddress>285212672</BaseAddress>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<CodeAnalysisRuleAssemblies>C:\Program Files (x86)\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules</CodeAnalysisRuleAssemblies>
|
||||
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||
<OutputPath>..\bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<BaseAddress>285212672</BaseAddress>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>
|
||||
</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<CodeAnalysisRuleAssemblies>C:\Program Files (x86)\Microsoft Visual Studio 8\Team Tools\Static Analysis Tools\FxCop\\rules</CodeAnalysisRuleAssemblies>
|
||||
<CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
|
||||
<CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System">
|
||||
<Name>System</Name>
|
||||
</Reference>
|
||||
<Reference Include="System.Data">
|
||||
<Name>System.Data</Name>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing">
|
||||
<Name>System.Drawing</Name>
|
||||
</Reference>
|
||||
<Reference Include="System.Windows.Forms">
|
||||
<Name>System.Windows.Forms</Name>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml">
|
||||
<Name>System.XML</Name>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CDEntry.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="FreedbHelper.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="QueryResult.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="QueryResultCollection.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Site.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SiteCollection.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Track.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TrackCollection.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
685
Freedb/FreedbHelper.cs
Normal file
685
Freedb/FreedbHelper.cs
Normal file
@@ -0,0 +1,685 @@
|
||||
#region COPYRIGHT (c) 2004 by Brian Weeres
|
||||
/* Copyright (c) 2004 by Brian Weeres
|
||||
*
|
||||
* Email: bweeres@protegra.com; bweeres@hotmail.com
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* If you modify it then please indicate so.
|
||||
*
|
||||
* The software is provided "AS IS" and there are no warranties or implied warranties.
|
||||
* In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
|
||||
* direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
|
||||
* out of the use or performance of this software
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.IO;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Freedb
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for FreedbHelper.
|
||||
/// </summary>
|
||||
public class FreedbHelper
|
||||
{
|
||||
public const string MAIN_FREEDB_ADDRESS = "freedb.freedb.org";
|
||||
public const string DEFAULT_ADDITIONAL_URL_INFO = "/~cddb/cddb.cgi";
|
||||
private Site m_mainSite = new Site(MAIN_FREEDB_ADDRESS,"http",DEFAULT_ADDITIONAL_URL_INFO);
|
||||
private string m_UserName;
|
||||
private string m_Hostname;
|
||||
private string m_ClientName;
|
||||
private string m_Version;
|
||||
private string m_ProtocolLevel = "6"; // default to level 6 support
|
||||
private Site m_CurrentSite = null;
|
||||
|
||||
|
||||
#region Constants for Freedb commands
|
||||
public class Commands
|
||||
{
|
||||
public const string CMD_HELLO = "hello";
|
||||
public const string CMD_READ = "cddb+read";
|
||||
public const string CMD_QUERY = "cddb+query";
|
||||
public const string CMD_SITES = "sites";
|
||||
public const string CMD_PROTO = "proto";
|
||||
public const string CMD_CATEGORIES = "cddb+lscat";
|
||||
public const string CMD = "cmd="; // will never use without the equals so put it here
|
||||
public const string CMD_TERMINATOR = ".";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constants for Freedb ResponseCodes
|
||||
public class ResponseCodes
|
||||
{
|
||||
public const string CODE_210 = "210"; // Okay // or in a query multiple exact matches
|
||||
public const string CODE_401 = "401"; // sites: no site information available
|
||||
public const string CODE_402 = "402"; // Server Error
|
||||
|
||||
public const string CODE_500 = "500"; // Invalid command, invalid parameters, etc.
|
||||
//query codes
|
||||
public const string CODE_200 = "200"; // Exact match
|
||||
public const string CODE_211 = "211"; // InExact matches found - list follows
|
||||
public const string CODE_202 = "202"; // No match
|
||||
public const string CODE_403 = "403"; // Database entry is corrupt
|
||||
public const string CODE_409 = "409"; // No Handshake
|
||||
|
||||
// our own code
|
||||
public const string CODE_INVALID = "-1"; // Invalid code
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Property Version (string)
|
||||
/// </summary>
|
||||
public string Version
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Version;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Version = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property MainSite(string)
|
||||
/// </summary>
|
||||
public Site MainSite
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_mainSite ;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property ClientName (string)
|
||||
/// </summary>
|
||||
public string ClientName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ClientName;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ClientName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Hostname (string)
|
||||
/// </summary>
|
||||
public string Hostname
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Hostname;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Hostname = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property UserName (string)
|
||||
/// </summary>
|
||||
public string UserName
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_UserName;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_UserName = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property ProtocolLevel (string)
|
||||
/// </summary>
|
||||
public string ProtocolLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ProtocolLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ProtocolLevel = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property CurrentSite (Site)
|
||||
/// </summary>
|
||||
public Site CurrentSite
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_CurrentSite;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_CurrentSite = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public FreedbHelper()
|
||||
{
|
||||
m_ProtocolLevel = "6"; // default it
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve all Freedb servers from the main server site
|
||||
/// </summary>
|
||||
/// <param name="sites">SiteCollection that is populated with the site information</param>
|
||||
/// <returns>Response Code</returns>
|
||||
public string GetSites(out SiteCollection sites)
|
||||
{
|
||||
return GetSites(Site.PROTOCOLS.ALL, out sites);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Get the Freedb sites
|
||||
/// </summary>
|
||||
/// <param name="protocol"></param>
|
||||
/// <param name="sites">SiteCollection that is populated with the site information</param>
|
||||
/// <returns>Response Code</returns>
|
||||
///
|
||||
public string GetSites(string protocol, out SiteCollection sites)
|
||||
{
|
||||
if (protocol != Site.PROTOCOLS.CDDBP && protocol != Site.PROTOCOLS.HTTP)
|
||||
protocol = Site.PROTOCOLS.ALL;
|
||||
|
||||
StringCollection coll;
|
||||
|
||||
try
|
||||
{
|
||||
coll= Call(Commands.CMD_SITES,m_mainSite.GetUrl());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Error retrieving Sites." + ex.Message);
|
||||
Exception newEx = new Exception("FreedbHelper.GetSites: Error retrieving Sites.",ex);
|
||||
throw newEx;
|
||||
}
|
||||
|
||||
sites = null;
|
||||
|
||||
// check if results came back
|
||||
if (coll.Count < 0)
|
||||
{
|
||||
string msg = "No results returned from sites request.";
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
string code = GetCode(coll[0]);
|
||||
if (code == ResponseCodes.CODE_INVALID)
|
||||
{
|
||||
string msg = "Unable to process results Sites Request. Returned Data: " + coll[0];
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case ResponseCodes.CODE_500:
|
||||
return ResponseCodes.CODE_500;
|
||||
|
||||
case ResponseCodes.CODE_401:
|
||||
return ResponseCodes.CODE_401;
|
||||
|
||||
case ResponseCodes.CODE_210:
|
||||
{
|
||||
coll.RemoveAt(0);
|
||||
sites = new SiteCollection();
|
||||
foreach (String line in coll)
|
||||
{
|
||||
Debug.WriteLine("line: " + line);
|
||||
Site site = new Site(line);
|
||||
if (protocol == Site.PROTOCOLS.ALL)
|
||||
sites.Add(new Site(line));
|
||||
else if (site.Protocol == protocol)
|
||||
sites.Add(new Site(line));
|
||||
}
|
||||
|
||||
return ResponseCodes.CODE_210;
|
||||
}
|
||||
|
||||
default:
|
||||
return ResponseCodes.CODE_500;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Read Entry from the database.
|
||||
/// </summary>
|
||||
/// <param name="qr">A QueryResult object that is created by performing a query</param>
|
||||
/// <param name="cdEntry">out parameter - CDEntry object</param>
|
||||
/// <returns></returns>
|
||||
public string Read(QueryResult qr, out CDEntry cdEntry)
|
||||
{
|
||||
Debug.Assert(qr != null);
|
||||
cdEntry = null;
|
||||
|
||||
StringCollection coll = null;
|
||||
StringBuilder builder = new StringBuilder(FreedbHelper.Commands.CMD_READ);
|
||||
builder.Append("+");
|
||||
builder.Append(qr.Category);
|
||||
builder.Append("+");
|
||||
builder.Append(qr.Discid);
|
||||
|
||||
//make call
|
||||
try
|
||||
{
|
||||
coll = Call(builder.ToString());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = "Error performing cddb read.";
|
||||
Exception newex = new Exception(msg,ex);
|
||||
throw newex ;
|
||||
}
|
||||
|
||||
// check if results came back
|
||||
if (coll.Count < 0)
|
||||
{
|
||||
string msg = "No results returned from cddb read.";
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
string code = GetCode(coll[0]);
|
||||
if (code == ResponseCodes.CODE_INVALID)
|
||||
{
|
||||
string msg = "Unable to process results for cddb read. Returned Data: " + coll[0];
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case ResponseCodes.CODE_500:
|
||||
return ResponseCodes.CODE_500;
|
||||
|
||||
case ResponseCodes.CODE_401: // entry not found
|
||||
case ResponseCodes.CODE_402: // server error
|
||||
case ResponseCodes.CODE_403: // Database entry is corrupt
|
||||
case ResponseCodes.CODE_409: // No handshake
|
||||
return code;
|
||||
|
||||
case ResponseCodes.CODE_210: // good
|
||||
{
|
||||
coll.RemoveAt(0); // remove the 210
|
||||
cdEntry = new CDEntry(coll);
|
||||
return ResponseCodes.CODE_210;
|
||||
}
|
||||
default:
|
||||
return ResponseCodes.CODE_500;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Query the freedb server to see if there is information on this cd
|
||||
/// </summary>
|
||||
/// <param name="querystring"></param>
|
||||
/// <param name="queryResult"></param>
|
||||
/// <param name="queryResultsColl"></param>
|
||||
/// <returns></returns>
|
||||
public string Query(string querystring, out QueryResult queryResult, out QueryResultCollection queryResultsColl)
|
||||
{
|
||||
queryResult = null;
|
||||
queryResultsColl = null;
|
||||
StringCollection coll = null;
|
||||
|
||||
StringBuilder builder = new StringBuilder(FreedbHelper.Commands.CMD_QUERY);
|
||||
builder.Append("+");
|
||||
builder.Append(querystring);
|
||||
|
||||
//make call
|
||||
try
|
||||
{
|
||||
coll = Call(builder.ToString());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = "Unable to perform cddb query.";
|
||||
Exception newex = new Exception(msg,ex);
|
||||
throw newex ;
|
||||
}
|
||||
|
||||
// check if results came back
|
||||
if (coll.Count < 0)
|
||||
{
|
||||
string msg = "No results returned from cddb query.";
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
string code = GetCode(coll[0]);
|
||||
if (code == ResponseCodes.CODE_INVALID)
|
||||
{
|
||||
string msg = "Unable to process results returned for query: Data returned: " + coll[0];
|
||||
Exception ex = new Exception (msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case ResponseCodes.CODE_500:
|
||||
return ResponseCodes.CODE_500;
|
||||
|
||||
// Multiple results were returned
|
||||
// Put them into a queryResultCollection object
|
||||
case ResponseCodes.CODE_211:
|
||||
case ResponseCodes.CODE_210:
|
||||
{
|
||||
queryResultsColl = new QueryResultCollection();
|
||||
//remove the 210 or 211
|
||||
coll.RemoveAt(0);
|
||||
foreach (string line in coll)
|
||||
{
|
||||
QueryResult result = new QueryResult(line,true);
|
||||
queryResultsColl.Add(result);
|
||||
}
|
||||
|
||||
return ResponseCodes.CODE_211;
|
||||
}
|
||||
|
||||
|
||||
// exact match
|
||||
case ResponseCodes.CODE_200:
|
||||
{
|
||||
queryResult = new QueryResult(coll[0]);
|
||||
return ResponseCodes.CODE_200;
|
||||
}
|
||||
|
||||
|
||||
//not found
|
||||
case ResponseCodes.CODE_202:
|
||||
return ResponseCodes.CODE_202;
|
||||
|
||||
//Database entry is corrupt
|
||||
case ResponseCodes.CODE_403:
|
||||
return ResponseCodes.CODE_403;
|
||||
|
||||
//no handshake
|
||||
case ResponseCodes.CODE_409:
|
||||
return ResponseCodes.CODE_409;
|
||||
|
||||
default:
|
||||
return ResponseCodes.CODE_500;
|
||||
|
||||
} // end of switch
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the categories
|
||||
/// </summary>
|
||||
/// <param name="strings"></param>
|
||||
/// <returns></returns>
|
||||
public string GetCategories(out StringCollection strings)
|
||||
{
|
||||
|
||||
StringCollection coll;
|
||||
strings = null;
|
||||
|
||||
try
|
||||
{
|
||||
coll = Call(FreedbHelper.Commands.CMD_CATEGORIES);
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = "Unable to retrieve Categories.";
|
||||
Exception newex = new Exception(msg,ex);
|
||||
throw newex;
|
||||
}
|
||||
|
||||
// check if results came back
|
||||
if (coll.Count < 0)
|
||||
{
|
||||
string msg = "No results returned from categories request.";
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
string code = GetCode(coll[0]);
|
||||
if (code == ResponseCodes.CODE_INVALID)
|
||||
{
|
||||
string msg = "Unable to retrieve Categories. Data Returned: " + coll[0];
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case ResponseCodes.CODE_500:
|
||||
return ResponseCodes.CODE_500;
|
||||
|
||||
case ResponseCodes.CODE_210:
|
||||
{
|
||||
strings = coll;
|
||||
coll.RemoveAt(0);
|
||||
return ResponseCodes.CODE_210;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
string msg = "Unknown code returned from GetCategories: " + coll[0];
|
||||
Exception ex = new Exception(msg,null);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Call the Freedb server using the specified command and the current site
|
||||
/// If the current site is null use the default server
|
||||
/// </summary>
|
||||
/// <param name="command">The command to be exectued</param>
|
||||
/// <returns>StringCollection</returns>
|
||||
private StringCollection Call(string command)
|
||||
{
|
||||
if (m_CurrentSite != null)
|
||||
return Call(command,m_CurrentSite.GetUrl());
|
||||
else
|
||||
return Call(command,m_mainSite.GetUrl());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call the Freedb server using the specified command and the specified url
|
||||
/// The command should not include the cmd= and hello and proto parameters.
|
||||
/// They will be added automatically
|
||||
/// </summary>
|
||||
/// <param name="command">The command to be exectued</param>
|
||||
/// <param name="url">The Freedb server to use</param>
|
||||
/// <returns>StringCollection</returns>
|
||||
private StringCollection Call(string commandIn, string url)
|
||||
{
|
||||
StreamReader reader = null;
|
||||
HttpWebResponse response = null;
|
||||
StringCollection coll = new StringCollection();
|
||||
|
||||
try
|
||||
{
|
||||
//create our HttpWebRequest which we use to call the freedb server
|
||||
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
|
||||
req.ContentType = "text/plain";
|
||||
// we are using th POST method of calling the http server. We could have also used the GET method
|
||||
req.Method="POST";
|
||||
//add the hello and proto commands to the request
|
||||
string command = BuildCommand(Commands.CMD + commandIn);
|
||||
//using Unicode
|
||||
byte[] byteArray = Encoding.UTF8.GetBytes(command);
|
||||
//get our request stream
|
||||
Stream newStream= req.GetRequestStream();
|
||||
//write our command data to it
|
||||
newStream.Write(byteArray,0,byteArray.Length);
|
||||
newStream.Close();
|
||||
//Make the call. Note this is a synchronous call
|
||||
response = (HttpWebResponse) req.GetResponse();
|
||||
//put the results into a StreamReader
|
||||
reader = new StreamReader(response.GetResponseStream(),System.Text.Encoding.UTF8);
|
||||
// add each line to the StringCollection until we get the terminator
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.StartsWith(Commands.CMD_TERMINATOR))
|
||||
break;
|
||||
else
|
||||
coll.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
|
||||
finally
|
||||
{
|
||||
if (response != null)
|
||||
response.Close();
|
||||
if (reader != null)
|
||||
reader.Close();
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Given a specific command add on the hello and proto which are requied for an http call
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
private string BuildCommand(string command)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(command);
|
||||
builder.Append("&");
|
||||
builder.Append(Hello());
|
||||
builder.Append("&");
|
||||
builder.Append(Proto());
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the hello part of the command
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Hello()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(Commands.CMD_HELLO);
|
||||
builder.Append("=");
|
||||
builder.Append(m_UserName);
|
||||
builder.Append("+");
|
||||
builder.Append(this.m_Hostname);
|
||||
builder.Append("+");
|
||||
builder.Append(this.ClientName);
|
||||
builder.Append("+");
|
||||
builder.Append(this.m_Version);
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the Proto part of the command
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string Proto()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(Commands.CMD_PROTO);
|
||||
builder.Append("=");
|
||||
builder.Append(m_ProtocolLevel );
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// given the first line of a result set return the CDDB code
|
||||
/// </summary>
|
||||
/// <param name="firstLine"></param>
|
||||
/// <returns></returns>
|
||||
private string GetCode(string firstLine)
|
||||
{
|
||||
firstLine = firstLine.Trim();
|
||||
|
||||
//find first white space after start
|
||||
int index = firstLine.IndexOf(' ');
|
||||
if (index != -1)
|
||||
firstLine = firstLine.Substring(0,index);
|
||||
else
|
||||
{
|
||||
return ResponseCodes.CODE_INVALID;
|
||||
}
|
||||
|
||||
return firstLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// If a different default site address is preferred over "freedb.freedb.org"
|
||||
/// set it here
|
||||
/// NOTE: Only set the ip address
|
||||
/// </summary>
|
||||
/// <param name="ipAddress"></param>
|
||||
public void SetDefaultSiteAddress(string siteAddress)
|
||||
{
|
||||
//sanity check on the url
|
||||
if (siteAddress.IndexOf("http") != -1 ||
|
||||
siteAddress.IndexOf("cgi") != -1)
|
||||
throw new Exception("Invalid Site Address specified");
|
||||
|
||||
this.m_mainSite.SiteAddress = siteAddress;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
213
Freedb/QueryResult.cs
Normal file
213
Freedb/QueryResult.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
#region COPYRIGHT (c) 2004 by Brian Weeres
|
||||
/* Copyright (c) 2004 by Brian Weeres
|
||||
*
|
||||
* Email: bweeres@protegra.com; bweeres@hotmail.com
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* If you modify it then please indicate so.
|
||||
*
|
||||
* The software is provided "AS IS" and there are no warranties or implied warranties.
|
||||
* In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
|
||||
* direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
|
||||
* out of the use or performance of this software
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
|
||||
namespace Freedb
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for QueryResult.
|
||||
/// </summary>
|
||||
public class QueryResult
|
||||
{
|
||||
private string m_ResponseCode;
|
||||
private string m_Category;
|
||||
private string m_Discid;
|
||||
private string m_Artist;
|
||||
private string m_Title;
|
||||
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Property ResponseCode (string)
|
||||
/// </summary>
|
||||
public string ResponseCode
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ResponseCode;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ResponseCode = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property Category (string)
|
||||
/// </summary>
|
||||
public string Category
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Category;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Category = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Discid (string)
|
||||
/// </summary>
|
||||
public string Discid
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Discid;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Discid = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Artist (string)
|
||||
/// </summary>
|
||||
public string Artist
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Artist;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Artist = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Title (string)
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Title;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Title = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
public QueryResult(string queryResult)
|
||||
{
|
||||
if (!Parse(queryResult,false))
|
||||
{
|
||||
throw new Exception("Unable to Parse QueryResult. Input: " + queryResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The parsing for a queryresult returned as part of a number of matches is slightly different
|
||||
/// There is no response code
|
||||
/// </summary>
|
||||
/// <param name="queryResult"></param>
|
||||
/// <param name="multiMatchInput"> true if the result is part of multi-match which means it will not contain a response code</param>
|
||||
public QueryResult(string queryResult, bool multiMatchInput)
|
||||
{
|
||||
if (!Parse(queryResult,multiMatchInput))
|
||||
{
|
||||
throw new Exception("Unable to Parse QueryResult. Input: " + queryResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse the query result line from the cddb server
|
||||
/// </summary>
|
||||
/// <param name="queryResult"></param>
|
||||
public bool Parse(string queryResult,bool match)
|
||||
{
|
||||
|
||||
queryResult.Trim();
|
||||
int secondIndex =0;
|
||||
|
||||
// get first white space
|
||||
int index = queryResult.IndexOf(' ');
|
||||
//if we are parsing a matched queryresult there is no responsecode so skip it
|
||||
if (!match)
|
||||
{
|
||||
m_ResponseCode = queryResult.Substring(0,index);
|
||||
index++;
|
||||
secondIndex = queryResult.IndexOf(' ',index);
|
||||
}
|
||||
else
|
||||
{
|
||||
secondIndex = index;
|
||||
index=0;
|
||||
}
|
||||
|
||||
m_Category = queryResult.Substring(index,secondIndex-index);
|
||||
index = secondIndex;
|
||||
index++;
|
||||
secondIndex = queryResult.IndexOf(' ',index);
|
||||
m_Discid = queryResult.Substring(index,secondIndex-index);
|
||||
index = secondIndex;
|
||||
index++;
|
||||
secondIndex = queryResult.IndexOf('/',index);
|
||||
m_Artist = queryResult.Substring(index,secondIndex-index-1); // -1 because there is a space at the end of artist
|
||||
index = secondIndex;
|
||||
index+=2; //skip past / and space
|
||||
m_Title = queryResult.Substring(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// public bool Parse(string queryResult)
|
||||
// {
|
||||
// queryResult.Trim();
|
||||
// string [] values = queryResult.Split(' ');
|
||||
// if (values.Length <6)
|
||||
// return false;
|
||||
// this.m_ResponseCode = values[0];
|
||||
// m_Category = values[1];
|
||||
// m_Discid = values[2];
|
||||
//
|
||||
// // now we need to look for a slash
|
||||
// bool artist = true;
|
||||
// for (int i = 3; i < values.Length;i++)
|
||||
// {
|
||||
// if (values[i] == "/")
|
||||
// {
|
||||
// artist = false;
|
||||
// continue;
|
||||
// }
|
||||
// if (artist)
|
||||
// this.m_Artist += values[i];
|
||||
// else
|
||||
// this.m_Title += values[i];
|
||||
//
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.m_Artist + ", " + this.m_Title;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
2378
Freedb/QueryResultCollection.cs
Normal file
2378
Freedb/QueryResultCollection.cs
Normal file
File diff suppressed because it is too large
Load Diff
237
Freedb/Site.cs
Normal file
237
Freedb/Site.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
#region COPYRIGHT (c) 2004 by Brian Weeres
|
||||
/* Copyright (c) 2004 by Brian Weeres
|
||||
*
|
||||
* Email: bweeres@protegra.com; bweeres@hotmail.com
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* If you modify it then please indicate so.
|
||||
*
|
||||
* The software is provided "AS IS" and there are no warranties or implied warranties.
|
||||
* In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
|
||||
* direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
|
||||
* out of the use or performance of this software
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
|
||||
namespace Freedb
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for Site.
|
||||
/// </summary>
|
||||
public class Site
|
||||
{
|
||||
private string m_SiteAddress;
|
||||
private string m_Protocol;
|
||||
private string m_AdditionalAddressInfo;
|
||||
private string m_Port;
|
||||
private string m_Latitude;
|
||||
private string m_Longitude;
|
||||
private string m_Description;
|
||||
|
||||
|
||||
public class PROTOCOLS
|
||||
{
|
||||
public const string HTTP = "http";
|
||||
public const string CDDBP = "cddbp";
|
||||
public const string ALL = "all";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property AdditionalAddressInfo (string)
|
||||
/// Any additional addressing information needed to access the server.
|
||||
/// For example, for HTTP protocol servers, this would be the path to the CCDB server CGI script.
|
||||
/// This field will be "-" if no additional addressing information is needed.
|
||||
/// </summary>
|
||||
public string AdditionalAddressInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_AdditionalAddressInfo;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_AdditionalAddressInfo = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// Property Site (string) - Internet address of the remote site
|
||||
/// </summary>
|
||||
public string SiteAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SiteAddress;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_SiteAddress = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Protocol (string)
|
||||
/// The transfer protocol used to access the site
|
||||
/// </summary>
|
||||
public string Protocol
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Protocol;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Protocol = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Port (string)- The port at which the server resides on that site.
|
||||
/// </summary>
|
||||
public string Port
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Port;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Port = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property Description (string)
|
||||
/// A short description of the geographical location of the site.
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Description;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Description = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Property Latitude (string)
|
||||
/// The latitude of the server site. The format is as follows:
|
||||
/// CDDD.MM
|
||||
/// Where "C" is the compass direction (N, S), "DDD" is the
|
||||
/// degrees, and "MM" is the minutes.
|
||||
/// </summary>
|
||||
public string Latitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Latitude;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Latitude = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Longitude (string)
|
||||
/// The longitude of the server site. Format is as above, except
|
||||
/// the compass direction must be one of (E, W).
|
||||
/// </summary>
|
||||
public string Longitude
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Longitude;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Longitude = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public Site(string siteFromCDDB)
|
||||
{
|
||||
if (!Parse(siteFromCDDB))
|
||||
{
|
||||
throw new Exception("Unable to Parse Site. Input: " + siteFromCDDB);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Builds a site from an address, protocol and addition info
|
||||
/// </summary>
|
||||
/// <param name="siteAddress"></param>
|
||||
/// <param name="protocol"></param>
|
||||
/// <param name="additionAddressInfo"></param>
|
||||
public Site(string siteAddress, string protocol, string additionAddressInfo)
|
||||
{
|
||||
m_SiteAddress = siteAddress;
|
||||
m_Protocol = protocol;
|
||||
m_AdditionalAddressInfo = additionAddressInfo;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public bool Parse(string siteAsString)
|
||||
{
|
||||
siteAsString.Trim();
|
||||
string [] values = siteAsString.Split(' ');
|
||||
if (values.Length <5)
|
||||
return false;
|
||||
m_SiteAddress = values[0];
|
||||
this.m_Protocol = values[1];
|
||||
m_Port = values[2];
|
||||
if (values[3].Trim() != "-")
|
||||
m_AdditionalAddressInfo = values[3];
|
||||
m_Latitude = values[4];
|
||||
m_Longitude = values[5];
|
||||
|
||||
// description could be split over many because it could have spaces
|
||||
for (int i= 6; i < values.Length;i++)
|
||||
{
|
||||
m_Description += values[i];
|
||||
m_Description += " ";
|
||||
|
||||
}
|
||||
m_Description.Trim();
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetUrl()
|
||||
{
|
||||
|
||||
if (this.m_Protocol == Site.PROTOCOLS.HTTP)
|
||||
return "http://" + this.m_SiteAddress + this.m_AdditionalAddressInfo;
|
||||
else
|
||||
return this.m_SiteAddress;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return m_SiteAddress + ", " + this.m_Description;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
2378
Freedb/SiteCollection.cs
Normal file
2378
Freedb/SiteCollection.cs
Normal file
File diff suppressed because it is too large
Load Diff
99
Freedb/Track.cs
Normal file
99
Freedb/Track.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
#region COPYRIGHT (c) 2004 by Brian Weeres
|
||||
/* Copyright (c) 2004 by Brian Weeres
|
||||
*
|
||||
* Email: bweeres@protegra.com; bweeres@hotmail.com
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* If you modify it then please indicate so.
|
||||
*
|
||||
* The software is provided "AS IS" and there are no warranties or implied warranties.
|
||||
* In no event shall Brian Weeres and/or Protegra Technology Group be liable for any special,
|
||||
* direct, indirect, or consequential damages or any damages whatsoever resulting for any reason
|
||||
* out of the use or performance of this software
|
||||
*
|
||||
*/
|
||||
#endregion
|
||||
using System;
|
||||
|
||||
namespace Freedb
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for Track.
|
||||
/// </summary>
|
||||
public class Track
|
||||
{
|
||||
|
||||
private string m_Title;
|
||||
private string m_ExtendedData;
|
||||
|
||||
#region Public Properties
|
||||
/// <summary>
|
||||
/// Property ExtendedData (string)
|
||||
/// </summary>
|
||||
public string ExtendedData
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ExtendedData;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ExtendedData = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property Title (string)
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Title;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Title = value;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of a Track
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
public Track()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of a Track passing in a title
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
public Track(string title)
|
||||
{
|
||||
m_Title = title;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an instance of a Track passing in a title and extended data
|
||||
/// </summary>
|
||||
/// <param name="title"></param>
|
||||
public Track(string title, string extendedData)
|
||||
{
|
||||
m_Title = title;
|
||||
m_ExtendedData = extendedData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
2378
Freedb/TrackCollection.cs
Normal file
2378
Freedb/TrackCollection.cs
Normal file
File diff suppressed because it is too large
Load Diff
885
Freedb/cddbproto.txt
Normal file
885
Freedb/cddbproto.txt
Normal file
@@ -0,0 +1,885 @@
|
||||
CDDB Server Protocol
|
||||
--------------------
|
||||
|
||||
By Steve Scherf and Ti Kan
|
||||
(Protocol level 5 & 6 specification by freedb developer team)
|
||||
|
||||
|
||||
Applies to cddbd 1.5.2
|
||||
$Id: CDDBPROTO,v 1.10.2.2 2006/04/14 14:45:06 joerg78 Exp $
|
||||
|
||||
|
||||
Notation:
|
||||
-> : client to server
|
||||
<- : server to client
|
||||
|
||||
terminating marker: `.' character in the beginning of a line
|
||||
|
||||
|
||||
Server response code (three digit code):
|
||||
|
||||
First digit:
|
||||
1xx Informative message
|
||||
2xx Command OK
|
||||
3xx Command OK so far, continue
|
||||
4xx Command OK, but cannot be performed for some specified reasons
|
||||
5xx Command unimplemented, incorrect, or program error
|
||||
|
||||
Second digit:
|
||||
x0x Ready for further commands
|
||||
x1x More server-to-client output follows (until terminating marker)
|
||||
x2x More client-to-server input follows (until terminating marker)
|
||||
x3x Connection will close
|
||||
|
||||
Third digit:
|
||||
xx[0-9] Command-specific code
|
||||
|
||||
Note: "*" means, that the command is only for administrative use and requires
|
||||
special access permissions, that normal users don't have.
|
||||
|
||||
|
||||
CDDB Protocol Level 1:
|
||||
----------------------
|
||||
|
||||
Server sign-on banner:
|
||||
----------------------
|
||||
<- code hostname CDDBP server version ready at date
|
||||
|
||||
code:
|
||||
200 OK, read/write allowed
|
||||
201 OK, read only
|
||||
432 No connections allowed: permission denied
|
||||
433 No connections allowed: X users allowed, Y currently active
|
||||
434 No connections allowed: system load too high
|
||||
hostname:
|
||||
Server host name. Example: xyz.fubar.com
|
||||
version:
|
||||
Version number of server software. Example: v1.0PL0
|
||||
date:
|
||||
Current date and time. Example: Wed Mar 13 00:41:34 1996
|
||||
|
||||
|
||||
Initial client-server handshake:
|
||||
--------------------------------
|
||||
Note: This handshake must occur before other cddb commands
|
||||
are accepted by the server.
|
||||
|
||||
Client command:
|
||||
-> cddb hello username hostname clientname version
|
||||
|
||||
username:
|
||||
Login name of user. Example: johndoe
|
||||
hostname:
|
||||
Host name of client. Example: abc.fubar.com
|
||||
clientname:
|
||||
The name of the connecting client. Example: xmcd, cda, EasyCD,
|
||||
et cetera. Do not use the name of another client which already
|
||||
exists.
|
||||
version:
|
||||
Version number of client software. Example: v1.0PL0
|
||||
|
||||
Server response:
|
||||
<- code hello and welcome username@hostname running clientname version
|
||||
|
||||
code:
|
||||
200 Handshake successful
|
||||
431 Handshake not successful, closing connection
|
||||
402 Already shook hands
|
||||
|
||||
|
||||
List the genre categories:
|
||||
--------------------------
|
||||
Client command:
|
||||
-> cddb lscat
|
||||
|
||||
Server response:
|
||||
<- code Okay category list follows (until terminating marker)
|
||||
<- category
|
||||
<- category
|
||||
<- (more categories...)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 Okay category list follows
|
||||
category:
|
||||
CD category. Example: rock
|
||||
|
||||
|
||||
Query database for matching entries:
|
||||
------------------------------------
|
||||
Client command:
|
||||
-> cddb query discid ntrks off1 off2 ... nsecs
|
||||
|
||||
discid:
|
||||
CD disc ID number. Example: f50a3b13
|
||||
ntrks:
|
||||
Total number of tracks on CD.
|
||||
off1, off2, ...:
|
||||
Frame offset of the starting location of each track.
|
||||
nsecs:
|
||||
Total playing length of CD in seconds.
|
||||
|
||||
Server response:
|
||||
<- code categ discid dtitle
|
||||
or
|
||||
<- code close matches found
|
||||
<- categ discid dtitle
|
||||
<- categ discid dtitle
|
||||
<- (more matches...)
|
||||
<- .
|
||||
|
||||
code:
|
||||
200 Found exact match
|
||||
211 Found inexact matches, list follows (until terminating marker)
|
||||
202 No match found
|
||||
403 Database entry is corrupt
|
||||
409 No handshake
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
discid:
|
||||
CD disc ID number of the found entry. Example: f50a3b13
|
||||
dtitle:
|
||||
The Disc Artist and Disc Title (The DTITLE line). For example:
|
||||
Pink Floyd / The Dark Side of the Moon
|
||||
|
||||
|
||||
Read entry from database:
|
||||
-------------------------
|
||||
Client command:
|
||||
-> cddb read categ discid
|
||||
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
discid:
|
||||
CD disc ID number. Example: f50a3b13
|
||||
|
||||
Server response:
|
||||
<- code categ discid
|
||||
<- # xmcd 2.0 CD database file
|
||||
<- # ...
|
||||
<- (CDDB data...)
|
||||
<- .
|
||||
or
|
||||
<- code categ discid No such CD entry in database.
|
||||
|
||||
code:
|
||||
210 OK, CDDB database entry follows (until terminating marker)
|
||||
401 Specified CDDB entry not found.
|
||||
402 Server error.
|
||||
403 Database entry is corrupt.
|
||||
409 No handshake.
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
discid:
|
||||
CD disc ID number. Example: f50a3b13
|
||||
|
||||
|
||||
* Delete entry from database:
|
||||
-----------------------------
|
||||
Client command:
|
||||
-> cddb unlink categ discid
|
||||
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
discid:
|
||||
CD disc ID number. Example: f50a3b13
|
||||
|
||||
Server response:
|
||||
<- code and message
|
||||
|
||||
code and message:
|
||||
200 OK, file has been deleted.
|
||||
401 Permission denied.
|
||||
402 File access failed.
|
||||
501 Invalid category: categ.
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
|
||||
|
||||
* Write entry to database:
|
||||
--------------------------
|
||||
Client command:
|
||||
-> cddb write categ discid
|
||||
|
||||
categ:
|
||||
CD category. Example: rock
|
||||
discid:
|
||||
CD disc ID number. Example: f50a3b13
|
||||
|
||||
Server response:
|
||||
<- code and message
|
||||
|
||||
code and message:
|
||||
320 OK, input CDDB data (until terminating marker)
|
||||
401 Permission denied.
|
||||
402 Server file system full/file access failed.
|
||||
409 No handshake.
|
||||
|
||||
Client data:
|
||||
-> # xmcd 2.0 CD database file
|
||||
-> # ...
|
||||
-> (CDDB data)
|
||||
-> .
|
||||
|
||||
Server response:
|
||||
<- code message
|
||||
|
||||
code:
|
||||
200 CDDB entry accepted
|
||||
501 Entry rejected: reason for rejection.
|
||||
message:
|
||||
Message string to indicate write status:
|
||||
CDDB entry accepted, or CDDB entry rejected.
|
||||
|
||||
|
||||
Discid calculation:
|
||||
------------------
|
||||
Client command:
|
||||
-> discid ntrks off_1 off_2 ... off_n nsecs
|
||||
|
||||
ntrks:
|
||||
total number of tracks on CD.
|
||||
off_X:
|
||||
frame offset of track X.
|
||||
nsecs:
|
||||
total playing length of the CD in seconds.
|
||||
|
||||
Server response:
|
||||
<- code Disc ID is discid
|
||||
|
||||
code:
|
||||
200 Calculated disc ID properly
|
||||
500 Command Syntax error
|
||||
discid:
|
||||
CD disc ID number calculated from the given arguments.
|
||||
|
||||
|
||||
* Get a server system file:
|
||||
---------------------------
|
||||
Client command:
|
||||
-> get file
|
||||
|
||||
file:
|
||||
filename of the file to get
|
||||
|
||||
Server response:
|
||||
|
||||
<- code message
|
||||
|
||||
or
|
||||
|
||||
<- code OK, (filename) follows (until terminating `.')
|
||||
<- (file content)
|
||||
<- .
|
||||
|
||||
code and message:
|
||||
210 OK, %s follows (until terminating `.')
|
||||
401 Permission denied.
|
||||
402 File access failed.
|
||||
402 File not found.
|
||||
|
||||
|
||||
Help information:
|
||||
-----------------
|
||||
Client command:
|
||||
-> help
|
||||
or
|
||||
-> help cmd
|
||||
|
||||
cmd:
|
||||
CDDB command. Example: quit
|
||||
|
||||
or
|
||||
|
||||
-> help cmd subcmd
|
||||
|
||||
cmd:
|
||||
CDDB command. Example: cddb
|
||||
subcmd:
|
||||
CDDB command argument. Example: query
|
||||
|
||||
Server response:
|
||||
<- code Help information follows
|
||||
<- (help data ...)
|
||||
<- .
|
||||
or
|
||||
<- code no help information available
|
||||
|
||||
code:
|
||||
210 OK, help information follows (until terminating marker)
|
||||
401 No help information available
|
||||
|
||||
|
||||
* Log statistics:
|
||||
-----------------
|
||||
Client command:
|
||||
-> log [[-l lines] [start date [end date]] | [day [days]] | [get]]
|
||||
|
||||
lines:
|
||||
The maximum number of lines to print for each data list in the
|
||||
log statistics.
|
||||
start date:
|
||||
The date after which statistics should be calculated. Date is
|
||||
of the format: hh[mm[ss[MM[DD[[CC]YY]]]]]
|
||||
|
||||
E.g.: 201200053196 for 8:12 PM on May 31, 1996.
|
||||
20120005312096 for 8:12 PM on May 31, 2096.
|
||||
080530 for today at at 8:15 and 30 seconds.
|
||||
|
||||
If the century ("CC") is omitted, a reasonable guess is made. If
|
||||
this argument is omitted, all messages are considered.
|
||||
end date:
|
||||
The date after which statistics should not be calculated. If
|
||||
omitted, the end date is assumed to be the current date.
|
||||
day:
|
||||
The string "day". This solitary argument will cause a log search
|
||||
of messages generated within the last day.
|
||||
days:
|
||||
A positive numerical argument which modifies the number of days'
|
||||
messages to searh. If this argument is left out, the default is 1.
|
||||
get:
|
||||
The string "get". This solitary argument will cause the server
|
||||
to send the contents of the log file.
|
||||
|
||||
Server response:
|
||||
<- code Log summary follows
|
||||
<- (log stats)
|
||||
<- .
|
||||
or
|
||||
<- code Log follows
|
||||
<- (log stats)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 OK, log summary follows (until terminating marker)
|
||||
211 OK, log follows (until terminating marker)
|
||||
401 Permission denied
|
||||
402 No log information available
|
||||
501 Invalid start/end date
|
||||
|
||||
|
||||
Message of the day:
|
||||
------------------
|
||||
Client command:
|
||||
-> motd
|
||||
|
||||
Server response:
|
||||
<- code Last modified: date MOTD follows (until terminating marker)
|
||||
<- (message text)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 Last modified: 05/31/96 06:31:14 MOTD follows (until terminating marker)
|
||||
401 No message of the day available
|
||||
date:
|
||||
The date the text of the message of the day was modified. The date
|
||||
appears in the following format:
|
||||
|
||||
05/31/96 06:31:14
|
||||
|
||||
This value may be used by client software as a message timestamp
|
||||
for purposes of determining if it has already been displayed. This
|
||||
format was chosen because it is more easily parsed than the standard
|
||||
ctime() format.
|
||||
|
||||
|
||||
Server protocol level:
|
||||
----------------------
|
||||
Client command:
|
||||
-> proto [level]
|
||||
|
||||
level:
|
||||
The (numerical) protocol level to set the server to.
|
||||
|
||||
Server response:
|
||||
<- code CDDB protocol level: current cur_level, supported supported_level
|
||||
or
|
||||
<- code OK, protocol version now: cur_level
|
||||
|
||||
code:
|
||||
200 CDDB protocol level: current cur_level, supported supp_level
|
||||
201 OK, protocol version now: cur_level
|
||||
501 Illegal protocol level.
|
||||
502 Protocol level already cur_level.
|
||||
cur_level:
|
||||
The current protocol level at which the server is running.
|
||||
supported_level:
|
||||
The maximum supported protocol level.
|
||||
|
||||
|
||||
* Put a server system file:
|
||||
---------------------------
|
||||
Client command:
|
||||
-> put file
|
||||
|
||||
file:
|
||||
sites or motd
|
||||
|
||||
Server response:
|
||||
<- code message
|
||||
|
||||
code and message:
|
||||
320 OK, input file data (terminate with `.')
|
||||
401 Permission denied.
|
||||
402 File access failed.
|
||||
402 Not a regular file.
|
||||
|
||||
Client data:
|
||||
-> (file data of the file, that shall be written)
|
||||
-> .
|
||||
|
||||
Server response
|
||||
|
||||
<- code message
|
||||
|
||||
code and message:
|
||||
200 Put successful.
|
||||
402 File access failed.
|
||||
501 Input too long.
|
||||
|
||||
|
||||
Close connection to server:
|
||||
---------------------------
|
||||
Client command:
|
||||
-> quit
|
||||
|
||||
Server response:
|
||||
<- code hostname message
|
||||
|
||||
code and message:
|
||||
230 Closing connection. Goodbye.
|
||||
530 error, closing connection.
|
||||
hostname:
|
||||
Server host name. Example: xyz.fubar.com
|
||||
|
||||
|
||||
Server sites:
|
||||
--------------
|
||||
Client command:
|
||||
-> sites
|
||||
|
||||
Server response:
|
||||
<- code OK, site information follows (until terminating `.')
|
||||
<- (data)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 Ok, site information follows
|
||||
401 No site information available.
|
||||
|
||||
The data format is as follows:
|
||||
site port latitude longitude description
|
||||
|
||||
The fields are as follows:
|
||||
site:
|
||||
The Internet address of the remote site.
|
||||
port:
|
||||
The port at which the server resides on that site.
|
||||
latitude:
|
||||
The latitude of the server site. The format is as follows:
|
||||
CDDD.MM
|
||||
Where "C" is the compass direction (N, S), "DDD" is the
|
||||
degrees, and "MM" is the minutes.
|
||||
longitude:
|
||||
The longitude of the server site. Format is as above, except
|
||||
the compass direction must be one of (E, W).
|
||||
description:
|
||||
A short description of the geographical location of the site.
|
||||
|
||||
Example:
|
||||
us.freedb.org 8880 N037.21 W121.55 San Jose, CA USA
|
||||
|
||||
|
||||
Server status:
|
||||
--------------
|
||||
Client command:
|
||||
-> stat
|
||||
|
||||
Server response:
|
||||
<- code OK, status information follows (until terminating `.')
|
||||
<- (data)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 Ok, status information follows
|
||||
|
||||
The possible data is as follows:
|
||||
current proto: <current_level>
|
||||
An integer representing the server's current operating protocol
|
||||
level.
|
||||
max proto: <max_level>
|
||||
The maximum supported protocol level.
|
||||
gets: <yes | no>
|
||||
Whether or not the client is allowed to get log information,
|
||||
according to the string "yes" or "no".
|
||||
updates: <yes | no>
|
||||
Whether or not the client is allowed to initiate a database
|
||||
update, according to the string "yes" or "no".
|
||||
posting: <yes | no>
|
||||
Whether or not the client is allowed to post new entries,
|
||||
according to the string "yes" or "no".
|
||||
quotes: <yes | no>
|
||||
Whether or not quoted arguments are enabled, according to
|
||||
the string "yes" or "no".
|
||||
current users: <num_users>
|
||||
The number of users currently connected to the server.
|
||||
max users: <num_max_users>
|
||||
The number of users that can concurrently connect to the server.
|
||||
strip ext: <yes | no>
|
||||
Whether or not extended data is stripped by the server before
|
||||
presented to the user.
|
||||
Database entries: <num_db_entries>
|
||||
The total number of entries in the database.
|
||||
Database entries by category:
|
||||
This field is followed by a list of catgories and the number
|
||||
of entries in that category. Each entry is of the following
|
||||
format:
|
||||
|
||||
<white space>catgory: <num_db_entries>
|
||||
|
||||
The list of entries is terminated by the first line that does
|
||||
not begin with white space.
|
||||
|
||||
* Pending file transmissions:
|
||||
This field is followed by a list of sites that are fed new
|
||||
database entries at periodic intervals, and the number of
|
||||
entries that have yet to be transmitted to that site.
|
||||
Each entry is of the following format:
|
||||
|
||||
<white space>site: <num_db_entries>
|
||||
|
||||
The list of entries is terminated by the first line that does
|
||||
not begin with white space.
|
||||
|
||||
This list may grow as needed, so clients must expect possible
|
||||
unrecognizable data. Also, additional fields may be added to
|
||||
the currently existing lines, although no existing fields will
|
||||
be removed or change position.
|
||||
|
||||
|
||||
* Database update:
|
||||
----------------
|
||||
Client command:
|
||||
-> update
|
||||
|
||||
Server response:
|
||||
<- code Updating the database.
|
||||
or
|
||||
<- code Permission denied.
|
||||
or
|
||||
<- code Unable to update the database.
|
||||
|
||||
code:
|
||||
200 Updating the database.
|
||||
401 Permission denied.
|
||||
402 Unable to update the database.
|
||||
|
||||
|
||||
* Perform user validation:
|
||||
--------------------------
|
||||
Client command:
|
||||
-> validate
|
||||
|
||||
Server response:
|
||||
<- 503 Validation not required.
|
||||
|
||||
or
|
||||
|
||||
<- 320 OK, input validation string, salt=saltvalue (terminate with newline)
|
||||
|
||||
Client data:
|
||||
-> validation string
|
||||
|
||||
Server response:
|
||||
|
||||
-> code message
|
||||
|
||||
code and message:
|
||||
200 Validation successful.
|
||||
501 Incorrect validation string length.
|
||||
502 Invalid validation string.
|
||||
|
||||
|
||||
Server version:
|
||||
---------------
|
||||
Client command:
|
||||
-> ver
|
||||
|
||||
Server response:
|
||||
<- code servername version copyright
|
||||
or
|
||||
<- code Version information follows
|
||||
|
||||
code:
|
||||
200 Version information.
|
||||
211 OK, version information follows (until terminating marker)
|
||||
version:
|
||||
Server version. Example: v1.5PL0
|
||||
copyright:
|
||||
Copyright string. Example: Copyright (c) 1996-2001 Steve Scherf et al.
|
||||
|
||||
|
||||
* Server users:
|
||||
---------------
|
||||
Client command:
|
||||
-> whom
|
||||
|
||||
Server response:
|
||||
<- code message
|
||||
|
||||
code and message:
|
||||
210 OK, user list follows (until terminating marker)
|
||||
401 No user information available.
|
||||
|
||||
|
||||
General errors:
|
||||
---------------
|
||||
|
||||
Server response:
|
||||
<- code error
|
||||
code:
|
||||
402 Server error.
|
||||
408 CGI environment error.
|
||||
500 Command syntax error, command unknown, command unimplemented.
|
||||
530 Server error, server timeout.
|
||||
|
||||
|
||||
Reserved errors:
|
||||
----------------
|
||||
|
||||
The following error codes are reserved, and will never be returned as a
|
||||
response to a CDDB protocol command. They are intended to be used internally
|
||||
by clients that have a need for generating pseudo-responses.
|
||||
|
||||
600-699
|
||||
|
||||
|
||||
CDDB Protocol Level 2:
|
||||
----------------------
|
||||
|
||||
In all respects, protocol level 2 is the same as level 1, with the exceptions
|
||||
listed below.
|
||||
|
||||
Arguments to commands may be surrounded by double quotes. All characters
|
||||
within the quotes, including white space, are included in the argument. All
|
||||
white space is replaced by the `_' (2Dh) character by the server. White space
|
||||
is defined as ` ' (20h) and `^I' (control-I, or 09h).
|
||||
|
||||
Arguments containing quotes that should not be interpreted with the special
|
||||
meaning described above should be escaped with a preceding backslash character,
|
||||
or '\' (5Ch). If an actual backslash appears in an argument, it should be
|
||||
escaped with a preceding backslash. In both cases, the preceding backslash
|
||||
will be removed from the input before being interpreted.
|
||||
|
||||
|
||||
CDDB Protocol Level 3:
|
||||
----------------------
|
||||
|
||||
Protocol level 3 is the same as level 2, with the exception listed below.
|
||||
|
||||
The output of the "sites" command has changed to meet the folowing description:
|
||||
|
||||
The data format is as follows:
|
||||
site protocol port address latitude longitude description
|
||||
|
||||
The fields are as follows:
|
||||
site:
|
||||
The Internet address of the remote site.
|
||||
protocol:
|
||||
The transfer protocol used to access the site.
|
||||
port:
|
||||
The port at which the server resides on that site.
|
||||
address:
|
||||
Any additional addressing information needed to access the
|
||||
server. For example, for HTTP protocol servers, this would be
|
||||
the path to the CDDB server CGI script. This field will be
|
||||
"-" if no additional addressing information is needed.
|
||||
latitude:
|
||||
The latitude of the server site. The format is as follows:
|
||||
CDDD.MM
|
||||
Where "C" is the compass direction (N, S), "DDD" is the
|
||||
degrees, and "MM" is the minutes.
|
||||
longitude:
|
||||
The longitude of the server site. Format is as above, except
|
||||
the compass direction must be one of (E, W).
|
||||
description:
|
||||
A short description of the geographical location of the site.
|
||||
|
||||
Example:
|
||||
us.freedb.org cddbp 8880 - N037.21 W121.55 San Jose, CA USA
|
||||
us.freedb.org http 80 /~cddb/cddb.cgi N037.21 W121.55 San Jose, CA USA
|
||||
|
||||
Note that a site may appear once for each type of protocol it supports for
|
||||
accessing the server.
|
||||
|
||||
|
||||
CDDB Protocol Level 4:
|
||||
----------------------
|
||||
|
||||
Protocol level 4 is the same as level 3, with the exception listed below.
|
||||
|
||||
The output of the "cddb query" command may result in multiple exact matches.
|
||||
A new response code, 210, has been added to indicate that more than one
|
||||
exact match has been found.
|
||||
|
||||
Server response:
|
||||
----------------
|
||||
<- code exact matches found
|
||||
<- categ discid dtitle
|
||||
<- categ discid dtitle
|
||||
<- (more matches...)
|
||||
<- .
|
||||
|
||||
code:
|
||||
210 Found exact matches, list follows (until terminating marker)
|
||||
|
||||
|
||||
CDDB Protocol Level 5:
|
||||
----------------------
|
||||
|
||||
Protocol level 5 is the same as level 4, with the following exception:
|
||||
|
||||
The database entries returned when issuing the "cddb read" command now also
|
||||
contain DYEAR and DGENRE fields (between the DTITLE and the TTITLE's).
|
||||
For more info on the new database entry fields take a look at the
|
||||
database format specification
|
||||
|
||||
|
||||
CDDB Protocol Level 6:
|
||||
----------------------
|
||||
|
||||
Protocol level 6 is the same as level 5 except that the character set
|
||||
is now UTF-8 instead of ISO-8859-1. Note that UTF-8 is an extension of
|
||||
US-ASCII, just like ISO-8859-1 is an extension of US-ASCII, so there
|
||||
is no difference between levels 5 and 6 as far as 7-bit ASCII data is
|
||||
concerned.
|
||||
|
||||
Clients can convert data between UTF-8 and the user's preferred
|
||||
character set using the iconv program and library function which are
|
||||
provided by glibc-2.2 or by the portable library libiconv. (They are
|
||||
also provided by the C library on some non-glibc systems, but often in
|
||||
a buggy or incompatible form.) For example, to convert data to UTF-8
|
||||
from the character set of the current locale in a shell script use
|
||||
"iconv -t utf-8 < in > out".
|
||||
|
||||
For more information about Unicode and UTF-8 see:
|
||||
|
||||
ftp://ftp.ilog.fr/pub/Users/haible/utf8/Unicode-HOWTO.html
|
||||
http://www.cl.cam.ac.uk/~mgk25/unicode.html
|
||||
|
||||
|
||||
Addendum A: Proper use of CDDBP:
|
||||
--------------------------------
|
||||
|
||||
There are a few guidelines that must be followed in order to make proper use
|
||||
of CDDBP:
|
||||
|
||||
- When handshaking with the server via the "cddb hello" command, the client
|
||||
must specify its own name and version, not that of some other client (such
|
||||
as xmcd).
|
||||
|
||||
- Before performing a "cddb read", the client program MUST perform a
|
||||
"cddb query". Failure to do so may result in the client program receiving
|
||||
incorrect data from the server. Also, without performing a query, the
|
||||
client program will not benefit from close matches in the event of the
|
||||
lack of an exact match in the database.
|
||||
|
||||
|
||||
Addendum B: CDDBP under HTTP:
|
||||
-----------------------------
|
||||
|
||||
Accessing a server as a CGI script is done in much the same way as through
|
||||
direct interaction. The command set is identical, though the method of
|
||||
communication is through CDDBP commands encapsulated in the HTTP protocol.
|
||||
The only limitation is that a single command may be executed per connection,
|
||||
since HTTP is not truly interactive. For the server to be accessed in this
|
||||
way, it must reside on the target host at a known URL which is accessible by
|
||||
the host HTTP server. The client program must connect to the HTTP server on
|
||||
the target host and issue an HTTP command with the appropriate CDDBP command
|
||||
encapsulated within.
|
||||
|
||||
Commands may be submitted to servers in CGI mode using either the "GET" or
|
||||
"POST" HTTP commands. Both methods are supported, and there is no real
|
||||
difference between how both are to be used other than the syntactical
|
||||
difference between the two methods. The "POST" method may provide the ability
|
||||
to issue longer commands, though, depending on the architecture of the system
|
||||
on which the server resides.
|
||||
|
||||
The server command must be sent as part of the "Request-URL" in the case
|
||||
of the "GET" method, and as the "Entity-Body" in the case of the "POST"
|
||||
method. In both cases, the command must be of the following form:
|
||||
|
||||
cmd=server+command&hello=joe+my.host.com+clientname+version&proto=6
|
||||
|
||||
Where the text following the "cmd=" represents the CDDBP command to be
|
||||
executed, the text following the "hello=" represents the arguments to
|
||||
the "cddb hello" command that is implied by this operation, and the
|
||||
text following the "proto=" represents the argument to the "proto" command
|
||||
that is implied by this operation.
|
||||
|
||||
The "+" characters in the input represent spaces, and will be translated
|
||||
by the server before performing the request. Special characters may be
|
||||
represented by the sequence "%XX" where "XX" is a two-digit hex number
|
||||
corresponding to the ASCII (ISO-8859-1) sequence of that character. The
|
||||
"&" characters denote separations between the command, hello and proto
|
||||
arguments. Newlines and carriage returns must not appear anywhere in the
|
||||
string except at the end.
|
||||
|
||||
All CDDBP commands are supported under HTTP, except for "cddb hello",
|
||||
"cddb write", "proto", "put", "validate" and "quit".
|
||||
|
||||
For example, should user "joe" on system "my.host.com" be running xmcd 2.1,
|
||||
a read request for his currenly playing CD might look like this:
|
||||
|
||||
cmd=cddb+read+rock+12345678&hello=joe+my.host.com+xmcd+2.1&proto=3
|
||||
|
||||
The server will perform the implied "proto" and "cddb hello" commands,
|
||||
and then perform the requested "cddb read" command.
|
||||
|
||||
Server response to the command is encapsulated in the HTTP server response,
|
||||
and appears in the "Entity-Body" exactly as it would appear using the CDDBP
|
||||
protocol. Note that the HTTP response "Entity-Header" is not guaranteed to
|
||||
contain a "Content-Length" field, so clients should be prepared to accept
|
||||
variable length input. This is no different from operation under CDDBP. The
|
||||
header will always contain a Mime "Content-Type" field which describes the
|
||||
body of data as "text/plain".
|
||||
|
||||
For more detailed information on HTTP and Mime, see RFC 1945 and RFC 1521.
|
||||
|
||||
|
||||
Addendum C: CDDBP under SMTP:
|
||||
-----------------------------
|
||||
|
||||
The use of e-mail mode (SMTP) commands is simple. A special subject line
|
||||
lets the server know that the e-mail contains a command, and somewhere in the
|
||||
body there should be a HTTP-style server command; the server will execute
|
||||
only one such commands per e-mail.
|
||||
|
||||
The subject for e-mail commands should look like this:
|
||||
|
||||
Subject: cddb #command arbitrary_string
|
||||
|
||||
The "arbitrary_string" should be some randomly-chosen string. The server
|
||||
will include this string in the subject of the response. The rest of the
|
||||
subject should appear literally as it does here.
|
||||
|
||||
Somewhere in the body of the e-mail should be exactly one server command. For
|
||||
example:
|
||||
|
||||
cmd=motd&hello=joe+my.host.com+xmcd_via_email+v1.0&proto=6
|
||||
|
||||
As you might have noticed, this command is exactly the same as a HTTP-mode
|
||||
CDDBP command. The command response will be mailed to the sender. Upon
|
||||
successful completion of an e-mail command request (even if the command
|
||||
itself was not successful), the reply will contain a subject which looks
|
||||
like this:
|
||||
|
||||
Subject cddb #response ok arbitrary_string
|
||||
|
||||
Should the server be unable to process the e-mail command for some reason, the
|
||||
subject will look like this:
|
||||
|
||||
Subject cddb #response failed arbitrary_string
|
||||
|
||||
In both cases, the "arbitrary_string" is the same as the one specified in the
|
||||
initial command e-mail.
|
||||
Binary file not shown.
Reference in New Issue
Block a user