public override async Task <TrackFile> GetDownloadableTrackAsync(Track track) { var response = await client.GetStreamUrlAsync(Int32.Parse(track.Id), settings.StreamQuality); var result = new TidalTrackFile { DownloadUri = new Uri(response.Url), Track = track }; // We can assume the MIME type and bitrate from the **returned** sound quality // It is unwise to use the stream quality stored in settings as users with lossless // subscriptions will get lossy streams simply because lossless streams are unavailable switch (response.SoundQuality) { case StreamingQuality.Low: result.BitRate = 96 * 1000; break; case StreamingQuality.High: result.BitRate = 320 * 1000; break; case StreamingQuality.HiRes: case StreamingQuality.Lossless: // Bitrate doesn't really matter since it's lossless result.BitRate = -1; break; default: result.BitRate = -1; break; } switch (response.Codec) { case TidalCodec.AAC: result.FileType = MediaFileTypes.Mpeg4Audio; break; case TidalCodec.FLAC: case TidalCodec.MQA: result.FileType = MediaFileTypes.FreeLosslessAudioCodec; break; case TidalCodec.MP3: result.FileType = MediaFileTypes.Mpeg3Audio; break; default: throw new ArgumentOutOfRangeException(); } if (!string.IsNullOrEmpty(response.EncryptionKey)) { result.FileKey = TidalDecryptor.ParseFileKey(Convert.FromBase64String(response.EncryptionKey)); } return(result); }
public async Task DownloadAsyncTask(TrackFile track, string destination) { var tidalTrack = (TidalTrackFile)track; // This is the way to do it as a stream. However this is also really slow. // var request = WebRequest.CreateHttp(tidalTrack.DownloadUri); // request.Method = "GET"; // var response = (HttpWebResponse) await request.GetResponseAsync(); // using ( // var cryptoStream = TidalDecryptor.CreateDecryptionStream(tidalTrack.FileKey, // response.GetResponseStream())) // { // using (var destFile = File.OpenWrite(destination)) // { // var eventArgs = new DownloadEventArgs {State = DownloadState.Downloading}; // int bytesRead, bytesReadTotal = 0; // var buffer = new byte[TidalDecryptor.BlockSize]; // while ((bytesRead = await cryptoStream.ReadAsync(buffer, 0, TidalDecryptor.BlockSize)) > 0) // { // bytesReadTotal += bytesRead; // await destFile.WriteAsync(buffer, 0, bytesRead); // eventArgs.PercentCompleted = (decimal)bytesReadTotal / response.ContentLength; // Progress?.Invoke(this, eventArgs); // } // } // } // Done?.Invoke(this, EventArgs.Empty); var data = await mClient.DownloadDataTaskAsync(tidalTrack.DownloadUri); Progress?.Invoke(this, new DownloadEventArgs { PercentCompleted = 1m, State = DownloadState.PostProcess }); using (var inputStream = new MemoryStream(data)) { using ( var cryptoStream = TidalDecryptor.CreateDecryptionStream(tidalTrack.FileKey, inputStream)) { using (var destFile = File.OpenWrite(destination)) { await cryptoStream.CopyToAsync(destFile, TidalDecryptor.BlockSize); } } } Done?.Invoke(this, EventArgs.Empty); }