diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7aa9fd1..66a4a32 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -31,6 +31,7 @@ jobs: with: PROJECT_FILE_PATH: YandexMusicResolver/YandexMusicResolver.csproj NUGET_KEY: ${{secrets.NUGETAPIKEY}} + NUGET_SOURCE: https://api.nuget.org/v3 THOW_ERROR_IF_VERSION_EXISTS: false - name: Publish Github Packages uses: Rebel028/publish-nuget@v2.6.0 diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 9a491f2..08e9e33 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,3 +1,11 @@ +# v2.2.0 +- Add ArtworkUrl to TrackInfo and mark Metadata obsolete, mark IsStream obsolete +- Add default codec to GetDirectUrl +- Remove unnecessary albumId from track loader +- Album load method now actually called LoadAlbum +- Make meta json properties private, classes internal +- Make YandexMusicMainResolver DI suitable + # v2.1.0 - Add public members documentation diff --git a/YandexMusicResolver.Tests/YandexTestBase.cs b/YandexMusicResolver.Tests/YandexTestBase.cs index e2ee48d..0fc5c80 100644 --- a/YandexMusicResolver.Tests/YandexTestBase.cs +++ b/YandexMusicResolver.Tests/YandexTestBase.cs @@ -18,7 +18,7 @@ public YandexTestBase() { } Config.Load(); - MainResolver = new YandexMusicMainResolver(Config); + MainResolver = new YandexMusicMainResolver(Config, true); TrackFactory = info => new YandexMusicTrack(info, MainResolver); } } diff --git a/YandexMusicResolver/AudioTrackInfo.cs b/YandexMusicResolver/AudioTrackInfo.cs index dd1800d..859cc1c 100644 --- a/YandexMusicResolver/AudioTrackInfo.cs +++ b/YandexMusicResolver/AudioTrackInfo.cs @@ -29,6 +29,7 @@ public class AudioTrackInfo { /// <summary> /// Is track live stream /// </summary> + [Obsolete("There is no streams support in library. \nWill removed in 3.0")] public bool IsStream { get; } /// <summary> @@ -39,8 +40,14 @@ public class AudioTrackInfo { /// <summary> /// Additional track metadata /// </summary> + [Obsolete("Metadata used only for image uri storing. Use ArtworkUrl property instead. \nWill be removed in 3.0")] public Dictionary<string, string> Metadata { get; } + /// <summary> + /// Track image uri + /// </summary> + public string? ArtworkUrl { get; } + public AudioTrackInfo(string title, string author, TimeSpan length, string identifier, bool isStream, string uri, Dictionary<string, string> metadata) { Title = title; Author = author; @@ -49,6 +56,23 @@ public AudioTrackInfo(string title, string author, TimeSpan length, string ident IsStream = isStream; Uri = uri; Metadata = metadata; + if (Metadata.TryGetValue("artworkUrl", out var artworkUrl)) { + ArtworkUrl = artworkUrl; + } + } + + public AudioTrackInfo(string title, string author, TimeSpan length, string identifier, bool isStream, string uri, string? artworkUrl = null) { + Title = title; + Author = author; + Length = length; + Identifier = identifier; + IsStream = isStream; + Uri = uri; + Metadata = new Dictionary<string, string>(); + if (artworkUrl != null) { + Metadata.Add("artworkUrl", artworkUrl); + ArtworkUrl = artworkUrl; + } } } } \ No newline at end of file diff --git a/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs b/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs index a235c4e..9c465a4 100644 --- a/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs +++ b/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs @@ -35,7 +35,7 @@ public YandexMusicDirectUrlLoader(IYandexConfig config) { /// <param name="codec">Target codec. mp3 by default</param> /// <returns>Direct url to download track</returns> /// <exception cref="Exception">Couldn't find supported track format</exception> - public async Task<string> GetDirectUrl(string trackId, string codec) { + public async Task<string> GetDirectUrl(string trackId, string codec = "mp3") { var trackDownloadInfos = await new YandexCustomRequest(_config).Create(string.Format(TrackDownloadInfoFormat, trackId)) .GetResponseAsync<List<MetaTrackDownloadInfo>>(); var track = trackDownloadInfos.FirstOrDefault(downloadInfo => downloadInfo.Codec == codec); diff --git a/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs b/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs index 6d6e869..075186f 100644 --- a/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs +++ b/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs @@ -37,9 +37,20 @@ public YandexMusicPlaylistLoader(IYandexConfig config) : base(config) { } /// <param name="albumId">Target album id</param> /// <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> /// <returns>Playlist instance</returns> + [Obsolete("For album loading use LoadAlbum method. \nWill be removed in 3.0")] public Task<YandexMusicPlaylist?> LoadPlaylist(string albumId, Func<AudioTrackInfo, YandexMusicTrack> trackFactory) { return LoadPlaylistUrl(string.Format(AlbumInfoFormat, albumId), trackFactory); } + + /// <summary> + /// Loads the album from Yandex Music + /// </summary> + /// <param name="albumId">Target album id</param> + /// <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> + /// <returns>Playlist instance</returns> + public Task<YandexMusicPlaylist?> LoadAlbum(string albumId, Func<AudioTrackInfo, YandexMusicTrack> trackFactory) { + return LoadPlaylistUrl(string.Format(AlbumInfoFormat, albumId), trackFactory); + } private async Task<YandexMusicPlaylist?> LoadPlaylistUrl(string url, Func<AudioTrackInfo, YandexMusicTrack> trackFactory) { var playlistData = await new YandexCustomRequest(Config).Create(url).GetResponseAsync<MetaPlaylist>(); diff --git a/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs b/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs index 2aa09c6..af304d9 100644 --- a/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs +++ b/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs @@ -34,8 +34,19 @@ public YandexMusicTrackLoader(IYandexConfig config) { /// <param name="trackId">Target track id</param> /// <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> /// <returns>Instance of <see cref="YandexMusicTrack"/></returns> - public async Task<YandexMusicTrack?> LoadTrack(string albumId, string trackId, Func<AudioTrackInfo, YandexMusicTrack?> trackFactory) { - return trackFactory((await LoadTrackInfo(albumId, trackId))!); + [Obsolete("We do not need an album ID to load track information. \nWill be removed in 3.0")] + public Task<YandexMusicTrack?> LoadTrack(string albumId, string trackId, Func<AudioTrackInfo, YandexMusicTrack?> trackFactory) { + return LoadTrack(trackId, trackFactory); + } + + /// <summary> + /// Load track + /// </summary> + /// <param name="trackId">Target track id</param> + /// <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> + /// <returns>Instance of <see cref="YandexMusicTrack"/></returns> + public async Task<YandexMusicTrack?> LoadTrack(string trackId, Func<AudioTrackInfo, YandexMusicTrack?> trackFactory) { + return trackFactory((await LoadTrackInfo(trackId))!); } /// <summary> @@ -44,8 +55,18 @@ public YandexMusicTrackLoader(IYandexConfig config) { /// <param name="albumId">Album id with track</param> /// <param name="trackId">Target track id</param> /// <returns>Instance of <see cref="AudioTrackInfo"/></returns> - public async Task<AudioTrackInfo?> LoadTrackInfo(string albumId, string trackId) { - var response = await new YandexCustomRequest(Config).Create(TracksInfoFormat + $"{trackId}:{albumId}").GetResponseAsync<List<MetaTrack>>(); + [Obsolete("We do not need an album ID to load track information. \nWill be removed in 3.0")] + public Task<AudioTrackInfo?> LoadTrackInfo(string albumId, string trackId) { + return LoadTrackInfo(trackId); + } + + /// <summary> + /// Load track info + /// </summary> + /// <param name="trackId">Target track id</param> + /// <returns>Instance of <see cref="AudioTrackInfo"/></returns> + public async Task<AudioTrackInfo?> LoadTrackInfo(string trackId) { + var response = await new YandexCustomRequest(Config).Create(TracksInfoFormat + trackId).GetResponseAsync<List<MetaTrack>>(); var entry = response.First(); return await entry.ToAudioTrackInfo(this); } diff --git a/YandexMusicResolver/Responces/MetaPlaylist.cs b/YandexMusicResolver/Responces/MetaPlaylist.cs index 8d9b74e..5f86f60 100644 --- a/YandexMusicResolver/Responces/MetaPlaylist.cs +++ b/YandexMusicResolver/Responces/MetaPlaylist.cs @@ -21,14 +21,12 @@ internal class MetaPlaylist { public bool Available { get; set; } = true; [JsonProperty("tracks")] - [Obsolete] - public List<MetaPlaylistTrackContainer> PlaylistTracks { + private List<MetaPlaylistTrackContainer> PlaylistTracks { set => Tracks = value.Select(container => container.Track).Cast<ITrackInfoContainer>().ToList(); } [JsonProperty("volumes")] - [Obsolete] - public List<List<MetaTrack>> AlbumVolumes { + private List<List<MetaTrack>> AlbumVolumes { set => Tracks = value.SelectMany(list => list).Cast<ITrackInfoContainer>().ToList(); } diff --git a/YandexMusicResolver/Responces/MetaPlaylistTrack.cs b/YandexMusicResolver/Responces/MetaPlaylistTrack.cs index a3c9204..ca1a3ef 100644 --- a/YandexMusicResolver/Responces/MetaPlaylistTrack.cs +++ b/YandexMusicResolver/Responces/MetaPlaylistTrack.cs @@ -10,7 +10,7 @@ namespace YandexMusicResolver.Responces { /// <summary> /// Represent /// </summary> - public class MetaPlaylistTrack : ITrackInfoContainer { + internal class MetaPlaylistTrack : ITrackInfoContainer { /// <summary> /// Track id /// </summary> diff --git a/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs b/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs index a4c3aaa..c7da8e0 100644 --- a/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs +++ b/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs @@ -1,7 +1,7 @@ using Newtonsoft.Json; namespace YandexMusicResolver.Responces { - public class MetaPlaylistTrackContainer { + internal class MetaPlaylistTrackContainer { [JsonProperty("id")] public long Id { get; set; } diff --git a/YandexMusicResolver/YandexMusicMainResolver.cs b/YandexMusicResolver/YandexMusicMainResolver.cs index f6b2cf6..3326294 100644 --- a/YandexMusicResolver/YandexMusicMainResolver.cs +++ b/YandexMusicResolver/YandexMusicMainResolver.cs @@ -1,4 +1,5 @@ -using System.Text.RegularExpressions; +using System; +using System.Text.RegularExpressions; using System.Threading.Tasks; using YandexMusicResolver.AudioItems; using YandexMusicResolver.Config; @@ -13,9 +14,9 @@ public class YandexMusicMainResolver { private const string AlbumUrlPattern = "^https?://music\\.yandex\\.[a-zA-Z]+/album/([0-9]+)$"; private const string PlaylistUrlPattern = "^https?://music\\.yandex\\.[a-zA-Z]+/users/(.+)/playlists/([0-9]+)$"; - private static Regex TrackUrlRegex = new Regex(TrackUrlPattern); - private static Regex AlbumUrlRegex = new Regex(AlbumUrlPattern); - private static Regex PlaylistUrlRegex = new Regex(PlaylistUrlPattern); + private static readonly Regex TrackUrlRegex = new Regex(TrackUrlPattern); + private static readonly Regex AlbumUrlRegex = new Regex(AlbumUrlPattern); + private static readonly Regex PlaylistUrlRegex = new Regex(PlaylistUrlPattern); // ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable private readonly IYandexConfig _config; @@ -49,6 +50,7 @@ public class YandexMusicMainResolver { /// <param name="trackLoader">Instance of <see cref="YandexMusicTrackLoader"/></param> /// <param name="directUrlLoader">Instance of <see cref="YandexMusicDirectUrlLoader"/></param> /// <param name="searchResultLoader">Instance of <see cref="YandexMusicSearchResultLoader"/></param> + [Obsolete("Use another ctor and set AllowSearch property after that. \nWill be removed in 3.0")] public YandexMusicMainResolver(IYandexConfig config, bool allowSearch = true, YandexMusicPlaylistLoader? playlistLoader = null, @@ -62,11 +64,31 @@ public YandexMusicMainResolver(IYandexConfig config, SearchResultLoader = searchResultLoader ?? new YandexMusicSearchResultLoader(_config); AllowSearch = allowSearch; } + + /// <summary> + /// Initializes a new instance of the <see cref="YandexMusicMainResolver"/> class. + /// </summary> + /// <param name="config">Yandex config instance</param> + /// <param name="playlistLoader">Instance of <see cref="YandexMusicPlaylistLoader"/></param> + /// <param name="trackLoader">Instance of <see cref="YandexMusicTrackLoader"/></param> + /// <param name="directUrlLoader">Instance of <see cref="YandexMusicDirectUrlLoader"/></param> + /// <param name="searchResultLoader">Instance of <see cref="YandexMusicSearchResultLoader"/></param> + public YandexMusicMainResolver(IYandexConfig config, + YandexMusicPlaylistLoader? playlistLoader = null, + YandexMusicTrackLoader? trackLoader = null, + YandexMusicDirectUrlLoader? directUrlLoader = null, + YandexMusicSearchResultLoader? searchResultLoader = null) { + _config = config; + PlaylistLoader = playlistLoader ?? new YandexMusicPlaylistLoader(_config); + TrackLoader = trackLoader ?? new YandexMusicTrackLoader(_config); + DirectUrlLoader = directUrlLoader ?? new YandexMusicDirectUrlLoader(_config); + SearchResultLoader = searchResultLoader ?? new YandexMusicSearchResultLoader(_config); + } /// <summary> /// Is query in <see cref="ResolveQuery"/> can be resolved with search /// </summary> - public bool AllowSearch { get; } + public bool AllowSearch { get; set; } = true; /// <summary> /// Resolves yandex query. Can directly resolve playlists, albums, tracks by url and search queries diff --git a/YandexMusicResolver/YandexMusicResolver.csproj b/YandexMusicResolver/YandexMusicResolver.csproj index 8697f16..127dc86 100644 --- a/YandexMusicResolver/YandexMusicResolver.csproj +++ b/YandexMusicResolver/YandexMusicResolver.csproj @@ -12,7 +12,7 @@ <Description>A library aimed at searching, resolving and getting direct links to tracks, playlists or albums in Yandex.Music. Can work without authorization.</Description> <RepositoryType>Git</RepositoryType> <PackageProjectUrl>https://github.com/SKProCH/YandexMusicResolver</PackageProjectUrl> - <Version>2.1.0</Version> + <Version>2.2.0</Version> <PackageLicenseUrl>https://github.com/SKProCH/YandexMusicResolver/blob/master/LICENSE</PackageLicenseUrl> <PackageReleaseNotes>Please write the package release notes in “RELEASE NOTES.md”</PackageReleaseNotes> diff --git a/YandexMusicResolver/YandexMusicResolver.xml b/YandexMusicResolver/YandexMusicResolver.xml index f9bdfe5..a1fc583 100644 --- a/YandexMusicResolver/YandexMusicResolver.xml +++ b/YandexMusicResolver/YandexMusicResolver.xml @@ -155,6 +155,11 @@ Additional track metadata </summary> </member> + <member name="P:YandexMusicResolver.AudioTrackInfo.ArtworkUrl"> + <summary> + Track image uri + </summary> + </member> <member name="T:YandexMusicResolver.Config.EmptyYandexConfig"> <summary> Represents <see cref="T:YandexMusicResolver.Config.IYandexConfig"/> implementation placeholder @@ -401,6 +406,14 @@ <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> <returns>Instance of <see cref="T:YandexMusicResolver.AudioItems.YandexMusicTrack"/></returns> </member> + <member name="M:YandexMusicResolver.Loaders.YandexMusicTrackLoader.LoadTrack(System.String,System.Func{YandexMusicResolver.AudioTrackInfo,YandexMusicResolver.AudioItems.YandexMusicTrack})"> + <summary> + Load track + </summary> + <param name="trackId">Target track id</param> + <param name="trackFactory">Track factory to create YandexMusicTrack from AudioTrackInfo</param> + <returns>Instance of <see cref="T:YandexMusicResolver.AudioItems.YandexMusicTrack"/></returns> + </member> <member name="M:YandexMusicResolver.Loaders.YandexMusicTrackLoader.LoadTrackInfo(System.String,System.String)"> <summary> Load track info @@ -409,6 +422,13 @@ <param name="trackId">Target track id</param> <returns>Instance of <see cref="T:YandexMusicResolver.AudioTrackInfo"/></returns> </member> + <member name="M:YandexMusicResolver.Loaders.YandexMusicTrackLoader.LoadTrackInfo(System.String)"> + <summary> + Load track info + </summary> + <param name="trackId">Target track id</param> + <returns>Instance of <see cref="T:YandexMusicResolver.AudioTrackInfo"/></returns> + </member> <member name="T:YandexMusicResolver.Responces.ITrackInfoContainer"> <summary> Represents entity from which we can get <see cref="T:YandexMusicResolver.AudioTrackInfo"/>