diff --git a/CUEToolsLib/Main.cs b/CUEToolsLib/Main.cs index 86cc7e3..5807689 100644 --- a/CUEToolsLib/Main.cs +++ b/CUEToolsLib/Main.cs @@ -26,7 +26,9 @@ using System.Text; using System.Globalization; using System.IO; using System.Net; +using System.Security.Cryptography; using System.Threading; +using System.Xml; using AudioCodecsDotNet; using HDCDDotNet; #if !MONO @@ -428,6 +430,8 @@ namespace CUEToolsLib private uint? _minDataTrackLength; private string _accurateRipId; private string _accurateRipIdActual; + private string _mbDiscId; + private string _mbReleaseId; private string _eacLog; private string _cuePath; private NameValueCollection _albumTags; @@ -1378,6 +1382,123 @@ namespace CUEToolsLib } } + private void CalculateMusicBrainzDiscID() { + StringBuilder mbSB = new StringBuilder(); + byte[] hashBytes; + uint trackOffset = 150; + + for (int iTrack = 0; iTrack < TrackCount; iTrack++) { + TrackInfo track = _tracks[iTrack]; + + trackOffset += track.IndexLengths[0]; + mbSB.AppendFormat("{0:X8}", trackOffset); + + for (int iIndex = 1; iIndex <= track.LastIndex; iIndex++) + trackOffset += track.IndexLengths[iIndex]; + } + mbSB.Insert(0, String.Format("{0:X2}{1:X2}{2:X8}", 1, TrackCount, trackOffset)); + mbSB.Append(new string('0', (99 - TrackCount) * 8)); + + hashBytes = (new SHA1CryptoServiceProvider()).ComputeHash(Encoding.ASCII.GetBytes(mbSB.ToString())); + _mbDiscId = Convert.ToBase64String(hashBytes).Replace('+', '.').Replace('/', '_').Replace('=', '-'); + System.Diagnostics.Debug.WriteLine(_mbDiscId); + } + + private void GetMetadataFromMusicBrainz() { + if (_mbDiscId == null) return; + + using (Stream respStream = HttpGetToStream( + "http://musicbrainz.org/ws/1/release/?type=xml&limit=1&discid=" + _mbDiscId)) + { + XmlDocument xd = GetXmlDocument(respStream); + XmlNode xn; + + xn = xd.SelectSingleNode("/metadata/release-list/release"); + if (xn != null) + _mbReleaseId = xn.Attributes["id"].InnerText; + } + + if (_mbReleaseId == null) return; + + using (Stream respStream = HttpGetToStream(String.Format( + "http://musicbrainz.org/ws/1/release/{0}?type=xml&inc=artist+tracks", _mbReleaseId))) + { + string discArtist = null; + string discTitle = null; + XmlDocument xd = GetXmlDocument(respStream); + XmlNode xn; + + XmlNode xnRelease = xd.DocumentElement.SelectSingleNode("/metadata/release"); + if (xnRelease == null) return; + + XmlNodeList xnlTracks = xnRelease.SelectNodes("track-list/track"); + if (xnlTracks.Count != TrackCount) return; + + xn = xnRelease.SelectSingleNode("title"); + if (xn != null) + discTitle = xn.InnerText; + + xn = xnRelease.SelectSingleNode("artist/name"); + if (xn != null) + discArtist = xn.InnerText; + + Artist = discArtist; + Title = discTitle; + + for (int iTrack = 0; iTrack < TrackCount; iTrack++) { + string trackArtist = null; + string trackTitle = null; + XmlNode xnTrack = xnlTracks[iTrack]; + TrackInfo trackInfo = Tracks[iTrack]; + + xn = xnTrack.SelectSingleNode("title"); + if (xn != null) + trackTitle = xn.InnerText; + + xn = xnTrack.SelectSingleNode("artist/name"); + if (xn != null) + trackArtist = xn.InnerText; + + trackInfo.Artist = trackArtist ?? discArtist; + trackInfo.Title = trackTitle; + } + } + } + + private XmlDocument GetXmlDocument(Stream stream) { + XmlDocument xd = new XmlDocument(); + + xd.Load(stream); + + if (xd.DocumentElement.NamespaceURI.Length > 0) { + // Strip namespace to simplify xpath expressions + XmlDocument xdNew = new XmlDocument(); + xd.DocumentElement.SetAttribute("xmlns", String.Empty); + xdNew.LoadXml(xd.OuterXml); + xd = xdNew; + } + + return xd; + } + + private Stream HttpGetToStream(string url) { + HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url); + req.UserAgent = "CUE Tools"; + try { + HttpWebResponse resp = (HttpWebResponse)req.GetResponse(); + return resp.GetResponseStream(); + } + catch (WebException ex) { + if (ex.Status == WebExceptionStatus.ProtocolError) { + HttpStatusCode code = ((HttpWebResponse)ex.Response).StatusCode; + if (code == HttpStatusCode.NotFound) { + throw new HttpNotFoundException(); + } + } + throw; + } + } + unsafe private void CalculateAccurateRipCRCsSemifast(int* samples, uint count, int iTrack, uint currentOffset, uint previousOffset, uint trackLength) { fixed (uint* CRCsA = iTrack != 0 ? _tracks[iTrack - 1].OffsetedCRC : null, @@ -2564,6 +2685,9 @@ namespace CUEToolsLib CUELine line = General.FindCUELine(_attributes, "PERFORMER"); return (line == null) ? String.Empty : line.Params[1]; } + set { + General.SetCUELine(_attributes, "PERFORMER", value, true); + } } public string Title { @@ -2571,6 +2695,9 @@ namespace CUEToolsLib CUELine line = General.FindCUELine(_attributes, "TITLE"); return (line == null) ? String.Empty : line.Params[1]; } + set { + General.SetCUELine(_attributes, "TITLE", value, true); + } } public int WriteOffset { @@ -2829,4 +2956,7 @@ namespace CUEToolsLib public StopException() : base() { } } + + class HttpNotFoundException : Exception { + } } \ No newline at end of file