mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
more work on ripper
freedb support
This commit is contained in:
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user