using System.Security.Cryptography; using System.Text; using YandexMusic.API.Common; using YandexMusic.API.Models.Common; using YandexMusic.API.Models.Track; using YandexMusic.API.Requests.Track; namespace YandexMusic.API { /// /// API для взаимодействия с треками /// public partial class YTrackAPI : YCommonAPI { #region Вспомогательные функции private string BuildLinkForDownload(YTrackDownloadInfo mainDownloadResponse, YStorageDownloadFile storageDownload) { string path = storageDownload.Path; string host = storageDownload.Host; string ts = storageDownload.Ts; string s = storageDownload.S; string codec = mainDownloadResponse.Codec; string secret = $"XGRlBW9FXlekgbPrRHuSiA{path.Substring(1, path.Length - 1)}{s}"; MD5 md5 = MD5.Create(); byte[] md5Hash = md5.ComputeHash(Encoding.UTF8.GetBytes(secret)); HMACSHA1 hmacsha1 = new(); byte[] hmasha1Hash = hmacsha1.ComputeHash(md5Hash); string sign = BitConverter.ToString(hmasha1Hash).Replace("-", "").ToLower(); string link = $"https://{host}/get-{codec}/{sign}/{ts}{path}"; return link; } #endregion Вспомогательные функции public YTrackAPI(YandexMusicApi yandex) : base(yandex) { } /// /// Получение треков /// /// Хранилище /// Идентификатор трека /// public Task>> GetAsync(AuthStorage storage, string trackId) { return new YGetTracksBuilder(api, storage) .Build(new[] { trackId }) .GetResponseAsync(); } /// /// Получение треков /// /// Хранилище /// Идентификаторы треков /// public Task>> GetAsync(AuthStorage storage, IEnumerable trackIds) { return new YGetTracksBuilder(api, storage) .Build(trackIds) .GetResponseAsync(); } /// /// Получение метаданных для загрузки /// /// Хранилище /// Ключ трека в формате {идентифактор трека:идентификатор альбома} /// Должен ли ответ содержать прямую ссылку на загрузку /// public Task>> GetMetadataForDownloadAsync(AuthStorage storage, string trackKey, bool direct = false) { return new YTrackDownloadInfoBuilder(api, storage) .Build((trackKey, direct)) .GetResponseAsync(); } /// /// Получение метаданных для загрузки /// /// Хранилище /// Трек /// Должен ли ответ содержать прямую ссылку на загрузку /// public Task>> GetMetadataForDownloadAsync(AuthStorage storage, YTrack track, bool direct = false) { return GetMetadataForDownloadAsync(storage, track.GetKey().ToString(), direct); } /// /// Получение информации для формирования ссылки для загрузки /// /// Хранилище /// Метаданные для загрузки /// public Task GetDownloadFileInfoAsync(AuthStorage storage, YTrackDownloadInfo metadataInfo) { return new YStorageDownloadFileBuilder(api, storage) .Build(metadataInfo.DownloadInfoUrl) .GetResponseAsync(); } /// /// Получение ссылки для загрузки /// /// Хранилище /// Ключ трека в формате {идентификатор трека:идентификатор альбома} /// public async Task GetFileLinkAsync(AuthStorage storage, string trackKey) { YResponse> meta = await GetMetadataForDownloadAsync(storage, trackKey); YTrackDownloadInfo info = meta.Result .OrderByDescending(i => i.BitrateInKbps) .First(m => m.Codec == "mp3"); YStorageDownloadFile storageDownload = await GetDownloadFileInfoAsync(storage, info); return BuildLinkForDownload(info, storageDownload); } /// /// Получение ссылки для загрузки /// /// Хранилище /// Трек /// public Task GetFileLinkAsync(AuthStorage storage, YTrack track) { return GetFileLinkAsync(storage, track.GetKey().ToString()); } /// /// Отправка текущего состояния прослушиваемого трека /// Хранилище /// Трек /// Наименования клиента, с которого происходит прослушивание /// Проигрывается ли трек с кеша /// Уникальный идентификатор проигрывания /// Уникальный идентификатор плейлиста, если таковой прослушивается /// Сколько было всего воспроизведено трека в секундах /// Окончательное значение воспроизведенных секунд /// /// public Task SendPlayTrackInfoAsync(AuthStorage storage, YTrack track, string from, bool fromCache = false, string playId = "", string playlistId = "", double totalPlayedSeconds = 0, double endPositionSeconds = 0) { return new YSendTrackInfoBuilder(api, storage) .Build((track, from, fromCache, playId, playlistId, totalPlayedSeconds, endPositionSeconds)) .GetResponseAsync(); } #region GetSupplement /// /// Получение дополнительной информации для трека /// /// Хранилище /// Идентификатор трека /// public Task> GetSupplementAsync(AuthStorage storage, string trackId) { return new YGetTrackSupplementBuilder(api, storage) .Build(trackId) .GetResponseAsync(); } /// /// Получение дополнительной информации для трека /// /// Хранилище /// Трек /// public Task> GetSupplementAsync(AuthStorage storage, YTrack track) { return new YGetTrackSupplementBuilder(api, storage) .Build(track.GetKey().ToString()) .GetResponseAsync(); } #endregion GetSupplement #region GetSimilar /// /// Получение похожих треков /// /// Хранилище /// Идентификатор трека /// public Task> GetSimilarAsync(AuthStorage storage, string trackId) { return new YGetTrackSimilarBuilder(api, storage) .Build(trackId) .GetResponseAsync(); } /// /// Получение похожих треков /// /// Хранилище /// Трек /// public Task> GetSimilarAsync(AuthStorage storage, YTrack track) { return new YGetTrackSimilarBuilder(api, storage) .Build(track.GetKey().ToString()) .GetResponseAsync(); } #endregion GetSimilar #region Получение данных трека #region В файл /// /// Выгрузка в файл /// /// Хранилище /// Ключ трека в формате {идентификатор трека:идентификатор альбома} /// Путь для файла public async Task ExtractToFileAsync(AuthStorage storage, string trackKey, string filePath) { string url = await GetFileLinkAsync(storage, trackKey); await new DataDownloader(storage).ToFile(url, filePath); } /// /// Выгрузка в файл /// /// Хранилище /// Трек /// Путь для файла public Task ExtractToFileAsync(AuthStorage storage, YTrack track, string filePath) { return ExtractToFileAsync(storage, track.GetKey().ToString(), filePath); } #endregion В файл #region В массив байт /// /// Получение двоичного массива данных /// /// Хранилище /// Ключ трека в формате {идентификатор трека:идентификатор альбома} /// public async Task ExtractDataAsync(AuthStorage storage, string trackKey) { string url = await GetFileLinkAsync(storage, trackKey); return await new DataDownloader(storage).AsBytes(url); } /// /// Получение двоичного массива данных /// /// Хранилище /// Трек /// public Task ExtractDataAsync(AuthStorage storage, YTrack track) { return ExtractDataAsync(storage, track.GetKey().ToString()); } #endregion В массив байт #region В поток /// /// Получение потока данных /// /// Хранилище /// Ключ трека в формате {идентификатор трека:идентификатор альбома} /// Параметры передачи управления при http запросе /// public async Task ExtractStreamAsync(AuthStorage storage, string trackKey, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) { string url = await GetFileLinkAsync(storage, trackKey); return await new DataDownloader(storage).AsStream(url, httpCompletionOption); } /// /// Получение потока данных /// /// Хранилище /// Трек /// Параметры передачи управления при http запросе /// public Task ExtractStreamAsync(AuthStorage storage, YTrack track, HttpCompletionOption httpCompletionOption = HttpCompletionOption.ResponseContentRead) { return ExtractStreamAsync(storage, track.GetKey().ToString(), httpCompletionOption); } #endregion В поток #endregion Получение данных трека } }