Files
YandexMusic/YandexMusic.API/API/YTrackAPI.cs
FrigaT 0bbaac5689
All checks were successful
Release / pack-and-publish (release) Successful in 1m5s
Переделан способ авторизации по qr
2026-04-20 14:31:47 +03:00

110 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Security.Cryptography;
using System.Text;
using YandexMusic.API.Models.Common;
using YandexMusic.API.Models.Track;
using YandexMusic.API.Requests.Track;
namespace YandexMusic.API;
/// <summary>API для работы с треками (получение, загрузка, метаданные).</summary>
public class YTrackAPI : YCommonAPI
{
public YTrackAPI(YandexMusicApi api) : base(api) { }
private static string BuildDownloadLink(YTrackDownloadInfo info, YStorageDownloadFile storageDownload)
{
var path = storageDownload.Path;
var host = storageDownload.Host;
var ts = storageDownload.Ts;
var s = storageDownload.S;
var codec = info.Codec;
var secret = $"XGRlBW9FXlekgbPrRHuSiA{path[1..]}{s}";
var md5Hash = MD5.HashData(Encoding.UTF8.GetBytes(secret));
var hmacsha1 = new HMACSHA1(md5Hash);
var sign = BitConverter.ToString(hmacsha1.ComputeHash(md5Hash)).Replace("-", "").ToLower();
return $"https://{host}/get-{codec}/{sign}/{ts}{path}";
}
public async Task<YTrack?> GetAsync(string trackId)
=> (await GetAsync([trackId]))?.FirstOrDefault();
public Task<List<YTrack>?> GetAsync(IEnumerable<string> trackIds)
=> new YGetTracksBuilder(Api).ExecuteAsync(trackIds);
public Task<List<YTrackDownloadInfo>?> GetMetadataForDownloadAsync(string trackKey, bool direct = false)
=> new YTrackDownloadInfoBuilder(Api).ExecuteAsync((trackKey, direct));
public Task<List<YTrackDownloadInfo>?> GetMetadataForDownloadAsync(YTrack track, bool direct = false)
=> GetMetadataForDownloadAsync(track.GetKey().ToString(), direct);
public Task<YStorageDownloadFile?> GetDownloadFileInfoAsync(YTrackDownloadInfo metadataInfo)
=> new YStorageDownloadFileBuilder(Api).ExecuteAsync(metadataInfo.DownloadInfoUrl);
public async Task<string?> GetFileLinkAsync(string trackKey)
{
var meta = await GetMetadataForDownloadAsync(trackKey);
var info = meta?.OrderByDescending(i => i.BitrateInKbps).FirstOrDefault(m => m.Codec == "mp3");
if (info == null) return null;
var storageDownload = await GetDownloadFileInfoAsync(info);
if (storageDownload == null) return null;
return BuildDownloadLink(info, storageDownload);
}
public Task<string?> GetFileLinkAsync(YTrack track)
=> GetFileLinkAsync(track.GetKey().ToString());
public async Task ExtractToFileAsync(string trackKey, string filePath)
{
var url = await GetFileLinkAsync(trackKey);
if (string.IsNullOrEmpty(url)) throw new Exception("Не удалось получить ссылку на трек");
using var response = await Api.HttpClient.GetAsync(url);
await using var fs = File.Create(filePath);
await response.Content.CopyToAsync(fs);
}
public Task ExtractToFileAsync(YTrack track, string filePath)
=> ExtractToFileAsync(track.GetKey().ToString(), filePath);
public async Task<byte[]> ExtractDataAsync(string trackKey)
{
var url = await GetFileLinkAsync(trackKey);
if (string.IsNullOrEmpty(url)) throw new Exception("Не удалось получить ссылку на трек");
return await Api.HttpClient.GetByteArrayAsync(url);
}
public Task<byte[]> ExtractDataAsync(YTrack track)
=> ExtractDataAsync(track.GetKey().ToString());
public async Task<Stream> ExtractStreamAsync(string trackKey, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
{
var url = await GetFileLinkAsync(trackKey);
if (string.IsNullOrEmpty(url)) throw new Exception("Не удалось получить ссылку на трек");
var response = await Api.HttpClient.GetAsync(url, completionOption);
return await response.Content.ReadAsStreamAsync();
}
public Task<Stream> ExtractStreamAsync(YTrack track, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
=> ExtractStreamAsync(track.GetKey().ToString(), completionOption);
public Task<string?> SendPlayTrackInfoAsync(
YTrack track,
string from,
bool fromCache = false,
string playId = "",
string playlistId = "",
double totalPlayedSeconds = 0,
double endPositionSeconds = 0)
=> new YSendTrackInfoBuilder(Api).ExecuteAsync((track, from, fromCache, playId, playlistId, totalPlayedSeconds, endPositionSeconds));
public Task<YTrackSupplement?> GetSupplementAsync(string trackId)
=> new YGetTrackSupplementBuilder(Api).ExecuteAsync(trackId);
public Task<YTrackSupplement?> GetSupplementAsync(YTrack track)
=> GetSupplementAsync(track.GetKey().ToString());
public Task<YTrackSimilar?> GetSimilarAsync(string trackId)
=> new YGetTrackSimilarBuilder(Api).ExecuteAsync(trackId);
public Task<YTrackSimilar?> GetSimilarAsync(YTrack track)
=> GetSimilarAsync(track.GetKey().ToString());
}