diff --git a/README.md b/README.md
index e859ba7..57ab3b3 100644
--- a/README.md
+++ b/README.md
@@ -18,10 +18,6 @@ Add [nuget package](https://www.nuget.org/packages/YandexMusicResolver/) to your
```
dotnet add package YandexMusicResolver
```
-or
-```
-Install-Package YandexMusicResolver -Version 2.0.0
-```
@@ -57,7 +53,7 @@ Example code for getting direct track download url:
var fileYandexConfig = new FileYandexConfig("yandex.config");
fileYandexConfig.Load();
var yandexMusicMainResolver = new YandexMusicMainResolver(fileYandexConfig);
-var directUrl = await yandexMusicMainResolver.DirectUrlLoader.GetDirectUrl("55561798", "mp3");
+var directUrl = await yandexMusicMainResolver.DirectUrlLoader.GetDirectUrl("55561798");
Console.WriteLine(directUrl);
```
**Warn:** Yandex will return a link to a 30-seconds track if you do not log in (do not use a config with a valid token).
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 74114ad..d1e9049 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -1,3 +1,9 @@
+# v3.0.0
+- ***BREAKING CHANGES***: `LoadPlaylist` -> `LoadAlbum`, remove `almubId` from `LoadTrack`, remove track `Metadata` `IsStream`, rework `YandexMusicMainResolver` and `YandexMusicSearchResultLoader` ctors, new `YandexMusicAuth` method names, ***`Load` in config now called by loaders and can be called multiple times***
+- Global type system rework: playlist now differs from album, no more meta classes as public API, new load on demand system for tracks in playlists and albums, remove `AudioTrackInfo`, now `YandexMusicTrack` are standalone, remove `IAudioItem` - `ResolveQueue` now return `YandexMusicSearchResult` and other changes
+- Extend MainResolver `ResolveQuery` functionality
+
+
# v2.2.1
- Add some missing xml docs
diff --git a/YandexMusicResolver.Tests/EnvironmentConfig.cs b/YandexMusicResolver.Tests/EnvironmentConfig.cs
index eef5c1d..5c3f410 100644
--- a/YandexMusicResolver.Tests/EnvironmentConfig.cs
+++ b/YandexMusicResolver.Tests/EnvironmentConfig.cs
@@ -5,7 +5,9 @@
namespace YandexMusicResolver.Tests {
public class EnvironmentConfig : IYandexConfig {
+ private bool isLoaded;
public void Load() {
+ if (isLoaded) return;
YandexLogin = Environment.GetEnvironmentVariable("YandexLogin");
YandexPassword = Environment.GetEnvironmentVariable("YandexPassword");
YandexToken = Environment.GetEnvironmentVariable("YandexToken");
@@ -14,6 +16,8 @@ public void Load() {
if (proxyUrl != null) {
YandexProxy = new WebProxy(proxyUrl);
}
+
+ isLoaded = true;
}
public void Save() { }
diff --git a/YandexMusicResolver.Tests/YandexMusicMainResolverTest.cs b/YandexMusicResolver.Tests/YandexMusicMainResolverTest.cs
index 7a4b32d..108f1e5 100644
--- a/YandexMusicResolver.Tests/YandexMusicMainResolverTest.cs
+++ b/YandexMusicResolver.Tests/YandexMusicMainResolverTest.cs
@@ -8,7 +8,12 @@ public class YandexMusicMainResolverTest : YandexTestBase{
public void GetTrack(string url) {
var audioItem = MainResolver.ResolveQuery(url).GetAwaiter().GetResult();
Assert.NotNull(audioItem);
- Assert.IsType(audioItem);
+ Assert.False(audioItem.IsSearchResult);
+ Assert.NotNull(audioItem.Tracks);
+ Assert.Null(audioItem.Playlists);
+ Assert.Null(audioItem.Albums);
+ Assert.NotEmpty(audioItem.Tracks);
+ Assert.Equal(YandexSearchType.Track, YandexSearchType.Track);
}
[Theory]
@@ -16,7 +21,12 @@ public void GetTrack(string url) {
public void GetAlbum(string url) {
var audioItem = MainResolver.ResolveQuery(url).GetAwaiter().GetResult();
Assert.NotNull(audioItem);
- Assert.IsType(audioItem);
+ Assert.False(audioItem.IsSearchResult);
+ Assert.NotNull(audioItem.Albums);
+ Assert.Null(audioItem.Tracks);
+ Assert.Null(audioItem.Playlists);
+ Assert.NotEmpty(audioItem.Albums);
+ Assert.Equal(YandexSearchType.Album, audioItem.Type);
}
[Theory]
@@ -24,16 +34,32 @@ public void GetAlbum(string url) {
public void GetPlaylist(string url) {
var audioItem = MainResolver.ResolveQuery(url).GetAwaiter().GetResult();
Assert.NotNull(audioItem);
- Assert.IsType(audioItem);
+ Assert.False(audioItem.IsSearchResult);
+ Assert.NotNull(audioItem.Playlists);
+ Assert.Null(audioItem.Tracks);
+ Assert.Null(audioItem.Albums);
+ Assert.NotEmpty(audioItem.Playlists);
+ Assert.Equal(YandexSearchType.Playlist, audioItem.Type);
}
- [Fact]
- public void TestDisabledSearch() {
- var yandexMusicMainResolver = new YandexMusicMainResolver(Config, false);
- var audioItem = yandexMusicMainResolver.ResolveQuery("Take Over").GetAwaiter().GetResult();
+ [Theory]
+ [InlineData("Take over")]
+ [InlineData("ymsearch:Track:10:Take over")]
+ public void TestDisabledSearch(string query) {
+ var yandexMusicMainResolver = new YandexMusicMainResolver(Config) {AllowSearch = false};
+ var audioItem = yandexMusicMainResolver.ResolveQuery(query).GetAwaiter().GetResult();
Assert.Null(audioItem);
}
+ [Theory]
+ [InlineData("Take over", true)]
+ [InlineData("ymsearch:Track:10:Take over", false)]
+ public void TestDisabledPlainTextSearch(string query, bool isPlainText) {
+ var yandexMusicMainResolver = new YandexMusicMainResolver(Config) {PlainTextIsSearchQuery = false};
+ var audioItem = yandexMusicMainResolver.ResolveQuery(query).GetAwaiter().GetResult();
+ Assert.Equal(isPlainText, audioItem == null);
+ }
+
[Theory]
[InlineData("Take Over")]
public void TestSearch(string url) {
diff --git a/YandexMusicResolver.Tests/YandexMusicPlaylistLoaderTest.cs b/YandexMusicResolver.Tests/YandexMusicPlaylistLoaderTest.cs
index b79f0b2..94aeaf5 100644
--- a/YandexMusicResolver.Tests/YandexMusicPlaylistLoaderTest.cs
+++ b/YandexMusicResolver.Tests/YandexMusicPlaylistLoaderTest.cs
@@ -7,21 +7,20 @@ public class YandexMusicPlaylistLoaderTest : YandexTestBase {
[InlineData("9425747", "Renovatio", 12)]
[InlineData("12033669", "Take Over", 1)]
public void LoadAlbum(string albumId, string expectedName, int trackCount) {
- TrackFactory = info => new YandexMusicTrack(info, MainResolver);
- var playlist = MainResolver.PlaylistLoader.LoadPlaylist(albumId, TrackFactory).GetAwaiter().GetResult();
- Assert.NotNull(playlist);
- Assert.Equal(expectedName, playlist.Title);
- Assert.Equal(trackCount, playlist.Tracks.Count);
+ var album = MainResolver.PlaylistLoader.LoadAlbum(albumId).GetAwaiter().GetResult();
+ Assert.NotNull(album);
+ Assert.Equal(expectedName, album.Title);
+ Assert.Equal(trackCount, album.Data.Count);
}
[Theory]
[InlineData("enlivenbot", "1000", "Test1", 60)]
[InlineData("enlivenbot", "1001", "Test2", 36)]
public void LoadPlaylist(string userId, string playlistId, string expectedName, int trackCount) {
- var playlist = MainResolver.PlaylistLoader.LoadPlaylist(userId, playlistId, TrackFactory).GetAwaiter().GetResult();
+ var playlist = MainResolver.PlaylistLoader.LoadPlaylist(userId, playlistId).GetAwaiter().GetResult();
Assert.NotNull(playlist);
Assert.Equal(expectedName, playlist.Title);
- Assert.Equal(trackCount, playlist.Tracks.Count);
+ Assert.Equal(trackCount, playlist.Data.Count);
}
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver.Tests/YandexMusicSearchResultLoaderTest.cs b/YandexMusicResolver.Tests/YandexMusicSearchResultLoaderTest.cs
index 7f136ae..da0db66 100644
--- a/YandexMusicResolver.Tests/YandexMusicSearchResultLoaderTest.cs
+++ b/YandexMusicResolver.Tests/YandexMusicSearchResultLoaderTest.cs
@@ -1,29 +1,27 @@
#nullable enable
using Xunit;
+using YandexMusicResolver.Config;
using YandexMusicResolver.Loaders;
namespace YandexMusicResolver.Tests {
public class YandexMusicSearchResultLoaderTest : YandexTestBase {
[Fact]
public void DoTrackSearch() {
- var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Track, "Take Over",
- MainResolver.PlaylistLoader, TrackFactory).GetAwaiter().GetResult();
+ var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Track, "Take Over").GetAwaiter().GetResult();
Assert.NotNull(trackSearchResult);
Assert.NotNull(trackSearchResult?.Tracks);
}
[Fact]
public void DoAlbumSearch() {
- var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Album, "Take Over",
- MainResolver.PlaylistLoader, TrackFactory).GetAwaiter().GetResult();
+ var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Album, "Take Over").GetAwaiter().GetResult();
Assert.NotNull(trackSearchResult);
Assert.NotNull(trackSearchResult?.Albums);
}
[Fact]
public void DoAllSearch() {
- var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.All, "Take Over",
- MainResolver.PlaylistLoader, TrackFactory).GetAwaiter().GetResult();
+ var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.All, "Take Over").GetAwaiter().GetResult();
Assert.NotNull(trackSearchResult);
Assert.NotNull(trackSearchResult?.Albums);
Assert.NotNull(trackSearchResult?.Playlists);
@@ -32,8 +30,7 @@ public void DoAllSearch() {
[Fact]
public void DoPlaylistSearch() {
- var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Playlist, "Take Over",
- MainResolver.PlaylistLoader, TrackFactory).GetAwaiter().GetResult();
+ var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Playlist, "Take Over").GetAwaiter().GetResult();
Assert.NotNull(trackSearchResult);
Assert.NotNull(trackSearchResult?.Playlists);
}
@@ -44,7 +41,8 @@ public void DoPlaylistSearch() {
[InlineData("myprefix")]
public void TestPrefixes(string? prefix) {
#pragma warning disable 8625
- var yandexMusicSearchResultLoader = new YandexMusicSearchResultLoader(null, prefix);
+ var yandexMusicSearchResultLoader = new YandexMusicSearchResultLoader(new EmptyYandexConfig(), null);
+ yandexMusicSearchResultLoader.SetSearchPrefix(prefix);
#pragma warning restore 8625
prefix ??= "ymsearch";
var correctQuery = $"{prefix}:playlist:25:take over";
diff --git a/YandexMusicResolver.Tests/YandexMusicTrackLoaderTest.cs b/YandexMusicResolver.Tests/YandexMusicTrackLoaderTest.cs
index 9237cc7..2a78893 100644
--- a/YandexMusicResolver.Tests/YandexMusicTrackLoaderTest.cs
+++ b/YandexMusicResolver.Tests/YandexMusicTrackLoaderTest.cs
@@ -8,7 +8,7 @@ public class YandexMusicTrackLoaderTest : YandexTestBase {
[InlineData("12033669", "70937156")]
public void GetTracksInfo(string albumId, string trackId) {
var yandexMusicTrackLoader = new YandexMusicTrackLoader(Config);
- var trackInfo = yandexMusicTrackLoader.LoadTrackInfo(albumId, trackId).GetAwaiter().GetResult();
+ var trackInfo = yandexMusicTrackLoader.LoadTrack(trackId).GetAwaiter().GetResult();
Assert.NotNull(trackInfo);
Assert.Equal($"https://music.yandex.ru/album/{albumId}/track/{trackId}", trackInfo.Uri);
}
diff --git a/YandexMusicResolver.Tests/YandexTestBase.cs b/YandexMusicResolver.Tests/YandexTestBase.cs
index 0fc5c80..e224985 100644
--- a/YandexMusicResolver.Tests/YandexTestBase.cs
+++ b/YandexMusicResolver.Tests/YandexTestBase.cs
@@ -7,7 +7,6 @@ namespace YandexMusicResolver.Tests {
public class YandexTestBase {
public IYandexConfig Config;
public YandexMusicMainResolver MainResolver;
- public Func TrackFactory;
public YandexTestBase() {
if (File.Exists("TestData.json")) {
@@ -17,9 +16,7 @@ public YandexTestBase() {
Config = new EnvironmentConfig();
}
- Config.Load();
- MainResolver = new YandexMusicMainResolver(Config, true);
- TrackFactory = info => new YandexMusicTrack(info, MainResolver);
+ MainResolver = new YandexMusicMainResolver(Config);
}
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/ApiResponceError.cs b/YandexMusicResolver/ApiResponceError.cs
index 9d68ab4..db01519 100644
--- a/YandexMusicResolver/ApiResponceError.cs
+++ b/YandexMusicResolver/ApiResponceError.cs
@@ -1,5 +1,5 @@
using System;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver {
///
diff --git a/YandexMusicResolver/AudioItems/IAudioItem.cs b/YandexMusicResolver/AudioItems/IAudioItem.cs
deleted file mode 100644
index f390a6b..0000000
--- a/YandexMusicResolver/AudioItems/IAudioItem.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace YandexMusicResolver.AudioItems {
- ///
- /// Marker interface for all loadable items
- ///
- public interface IAudioItem { }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/AudioItems/YandexMusicAlbum.cs b/YandexMusicResolver/AudioItems/YandexMusicAlbum.cs
new file mode 100644
index 0000000..e9b0d26
--- /dev/null
+++ b/YandexMusicResolver/AudioItems/YandexMusicAlbum.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.AudioItems {
+ public class YandexMusicAlbum : YandexMusicDataContainer> {
+ internal YandexMusicAlbum(long id, long year, List artists, string? artworkUrl, long trackCount, string genre, string title,
+ YandexMusicPlaylistLoader loader) : base(async () => (await loader.LoadAlbum(id.ToString()))!.Data.ToList()) {
+ Id = id;
+ Year = year;
+ Artists = artists;
+ ArtworkUrl = artworkUrl;
+ TrackCount = trackCount;
+ Genre = genre;
+ Title = title;
+ }
+
+ internal YandexMusicAlbum(long id, long year, List artists, string? artworkUrl, long trackCount, string genre, string title,
+ List tracks) : base(tracks) {
+ Id = id;
+ Year = year;
+ Artists = artists;
+ ArtworkUrl = artworkUrl;
+ TrackCount = trackCount;
+ Genre = genre;
+ Title = title;
+ }
+
+
+ ///
+ /// Album id
+ ///
+ public long Id { get; }
+
+ ///
+ /// Album release year
+ ///
+ public long Year { get; }
+
+ ///
+ /// Album artists
+ ///
+ public List Artists { get; }
+
+ ///
+ /// Track image uri
+ ///
+ public string? ArtworkUrl { get; }
+
+ ///
+ /// Album tracks count
+ ///
+ public long TrackCount { get; }
+
+ ///
+ /// Album genre
+ ///
+ public string Genre { get; }
+
+ ///
+ /// Track title
+ ///
+ public string Title { get; }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaArtist.cs b/YandexMusicResolver/AudioItems/YandexMusicArtist.cs
similarity index 83%
rename from YandexMusicResolver/Responces/MetaArtist.cs
rename to YandexMusicResolver/AudioItems/YandexMusicArtist.cs
index a188ec3..f5d1725 100644
--- a/YandexMusicResolver/Responces/MetaArtist.cs
+++ b/YandexMusicResolver/AudioItems/YandexMusicArtist.cs
@@ -1,10 +1,10 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.AudioItems {
///
/// Represent a artist in Yandex Music
///
- public class MetaArtist {
+ public class YandexMusicArtist {
///
/// Artist ID
///
diff --git a/YandexMusicResolver/AudioItems/YandexMusicDataContainer.cs b/YandexMusicResolver/AudioItems/YandexMusicDataContainer.cs
new file mode 100644
index 0000000..f807e1f
--- /dev/null
+++ b/YandexMusicResolver/AudioItems/YandexMusicDataContainer.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Threading.Tasks;
+
+namespace YandexMusicResolver.AudioItems {
+ ///
+ /// Represents class that contains data which could be loaded
+ ///
+ ///
+ public abstract class YandexMusicDataContainer {
+ private Func> loadDataFactory;
+ private Task? _loadDataTask;
+
+ ///
+ /// Create instance of
+ ///
+ /// Data creation factory
+ public YandexMusicDataContainer(Func> loadDataFactory) {
+ this.loadDataFactory = loadDataFactory;
+ }
+
+ ///
+ /// Create instance of
+ ///
+ /// Target data
+ public YandexMusicDataContainer(T data) {
+ var task = Task.FromResult(data);
+ loadDataFactory = () => task;
+ _loadDataTask = task;
+ }
+
+ private Task LoadDataTask => _loadDataTask ??= loadDataFactory();
+
+ ///
+ /// Load target data
+ ///
+ /// Task
+ public Task LoadDataAsync() {
+ return LoadDataTask;
+ }
+
+ ///
+ /// Return true if data already loaded
+ ///
+ public bool IsDataLoaded => _loadDataTask?.IsCompleted ?? false;
+
+ ///
+ /// Synchronously wait for data loading
+ ///
+ public T Data => LoadDataAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaOwner.cs b/YandexMusicResolver/AudioItems/YandexMusicOwner.cs
similarity index 89%
rename from YandexMusicResolver/Responces/MetaOwner.cs
rename to YandexMusicResolver/AudioItems/YandexMusicOwner.cs
index 9f28480..2da3c9e 100644
--- a/YandexMusicResolver/Responces/MetaOwner.cs
+++ b/YandexMusicResolver/AudioItems/YandexMusicOwner.cs
@@ -1,10 +1,10 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.AudioItems {
///
/// Represent playlist owner
///
- public class MetaOwner {
+ public class YandexMusicOwner {
///
/// Owner ID
///
diff --git a/YandexMusicResolver/AudioItems/YandexMusicPlaylist.cs b/YandexMusicResolver/AudioItems/YandexMusicPlaylist.cs
index fee8a22..285070e 100644
--- a/YandexMusicResolver/AudioItems/YandexMusicPlaylist.cs
+++ b/YandexMusicResolver/AudioItems/YandexMusicPlaylist.cs
@@ -1,35 +1,62 @@
-using System.Collections.ObjectModel;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using YandexMusicResolver.Loaders;
namespace YandexMusicResolver.AudioItems {
///
/// Represents playlist from Yandex Music
///
- public class YandexMusicPlaylist : IAudioItem {
- ///
- /// Initializes a new instance of the class.
- ///
- /// Playlist title
- /// Collection with tracks
- /// Is this playlist is search result
- public YandexMusicPlaylist(string title, ReadOnlyCollection tracks, bool isSearchResult) {
+ public class YandexMusicPlaylist : YandexMusicDataContainer> {
+ internal YandexMusicPlaylist(long uid, long kind, long trackCount, string title, YandexMusicOwner owner, string? artworkUrl,
+ YandexMusicPlaylistLoader loader) :
+ base(async () => (await loader.LoadPlaylist(owner.Login, kind.ToString()))!.Data.ToList()) {
+ Uid = uid;
+ Kind = kind;
+ TrackCount = trackCount;
Title = title;
- Tracks = tracks;
- IsSearchResult = isSearchResult;
+ Owner = owner;
+ ArtworkUrl = artworkUrl;
}
+ internal YandexMusicPlaylist(long uid, long kind, long trackCount, string title, YandexMusicOwner owner, string? artworkUrl,
+ List tracks) : base(tracks) {
+ Uid = uid;
+ Kind = kind;
+ TrackCount = trackCount;
+ Title = title;
+ Owner = owner;
+ ArtworkUrl = artworkUrl;
+ }
+
+ ///
+ /// Playlist UID
+ ///
+ public long Uid { get; }
+
+ ///
+ /// Playlist kind (something like the user's playlist index)
+ ///
+ public long Kind { get; }
+
+ ///
+ /// Playlist tracks count
+ ///
+ public long TrackCount { get; }
+
///
/// Playlist title
///
public string Title { get; }
///
- /// Collection with tracks in playlist
+ /// Playlist owner
///
- public ReadOnlyCollection Tracks { get; }
+ public YandexMusicOwner Owner { get; }
///
- /// Is this playlist a search result
+ /// Playlist artwork url
///
- public bool IsSearchResult { get; }
+ public string? ArtworkUrl { get; }
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/AudioItems/YandexMusicSearchResult.cs b/YandexMusicResolver/AudioItems/YandexMusicSearchResult.cs
index c857eca..93d7db9 100644
--- a/YandexMusicResolver/AudioItems/YandexMusicSearchResult.cs
+++ b/YandexMusicResolver/AudioItems/YandexMusicSearchResult.cs
@@ -1,19 +1,25 @@
-using System.Collections.ObjectModel;
-using YandexMusicResolver.Responces;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
namespace YandexMusicResolver.AudioItems {
///
/// Represents YandexMusic search result
///
- public class YandexMusicSearchResult : IAudioItem {
- public YandexMusicSearchResult(string query, int limit, YandexSearchType type, ReadOnlyCollection? albums,
- ReadOnlyCollection? playlists, ReadOnlyCollection? tracks) {
+ public class YandexMusicSearchResult {
+ internal YandexMusicSearchResult(string query,
+ bool isSearchResult,
+ YandexSearchType type,
+ IReadOnlyCollection? albums,
+ IReadOnlyCollection? playlists,
+ IReadOnlyCollection? tracks,
+ int? limit = null) {
Query = query;
Limit = limit;
Type = type;
Albums = albums;
Playlists = playlists;
Tracks = tracks;
+ IsSearchResult = isSearchResult;
}
///
@@ -22,31 +28,37 @@ public YandexMusicSearchResult(string query, int limit, YandexSearchType type, R
public string Query { get; }
///
- /// Tracks limit count
+ /// Tracks limit count.
+ /// Will be null
if the is false
///
- public int Limit { get; }
+ public int? Limit { get; }
///
/// Search data type
///
public YandexSearchType Type { get; }
+ ///
+ /// Is this playlist a search result
+ ///
+ public bool IsSearchResult { get; }
+
///
/// Albums list.
/// Will be null
if the search should not search for albums
///
- public ReadOnlyCollection? Albums { get; set; }
+ public IReadOnlyCollection? Albums { get; set; }
///
/// Playlists list.
/// Will be null
if the search should not search for playlists
///
- public ReadOnlyCollection? Playlists { get; set; }
+ public IReadOnlyCollection? Playlists { get; set; }
///
/// Tracks list.
/// Will be null
if the search should not search for tracks
///
- public ReadOnlyCollection? Tracks { get; set; }
+ public IReadOnlyCollection? Tracks { get; set; }
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/AudioItems/YandexMusicTrack.cs b/YandexMusicResolver/AudioItems/YandexMusicTrack.cs
index d9e0f58..3c5b5a6 100644
--- a/YandexMusicResolver/AudioItems/YandexMusicTrack.cs
+++ b/YandexMusicResolver/AudioItems/YandexMusicTrack.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -6,37 +8,49 @@ namespace YandexMusicResolver.AudioItems {
///
/// AudioTrackInfo wrapper to resolve track direct url
///
- public class YandexMusicTrack : IAudioItem {
+ public class YandexMusicTrack {
+ internal YandexMusicTrack(string title, List authors, TimeSpan length, string id, string uri, string? artworkUrl = null) {
+ Title = title;
+ Authors = authors;
+ Length = length;
+ Id = id;
+ Uri = uri;
+ ArtworkUrl = artworkUrl;
+ }
+
///
- /// Get track info
+ /// Track title
///
- public AudioTrackInfo TrackInfo { get; }
+ public string Title { get; }
- private YandexMusicMainResolver _mainResolver;
- private readonly Lazy> _directUrlLoader;
+ ///
+ /// Track authors
+ ///
+ public List Authors { get; }
///
- /// Initializes a new instance of the class.
+ /// Compose names into single string
///
- /// Track info
- /// Resolver for direct url getting
- public YandexMusicTrack(AudioTrackInfo trackInfo, YandexMusicMainResolver mainResolver) {
- _mainResolver = mainResolver;
- TrackInfo = trackInfo;
- _directUrlLoader = new Lazy>(GetDirectUrlInternal, LazyThreadSafetyMode.ExecutionAndPublication);
- }
+ public string Author => string.Join(", ", Authors.Select(artist => artist.Name));
///
- /// Get direct url to track
+ /// Track lenght
///
- /// If you not authorized will return 30s track version. This is YandexMusic restriction
- /// Direct url to download track
- public Task GetDirectUrl() {
- return _directUrlLoader.Value;
- }
+ public TimeSpan Length { get; }
- private async Task GetDirectUrlInternal() {
- return await _mainResolver.DirectUrlLoader.GetDirectUrl(TrackInfo.Identifier, "mp3");
- }
+ ///
+ /// Track id
+ ///
+ public string Id { get; }
+
+ ///
+ /// Track link
+ ///
+ public string Uri { get; }
+
+ ///
+ /// Track image uri
+ ///
+ public string? ArtworkUrl { get; }
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/AudioTrackInfo.cs b/YandexMusicResolver/AudioTrackInfo.cs
deleted file mode 100644
index 859cc1c..0000000
--- a/YandexMusicResolver/AudioTrackInfo.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace YandexMusicResolver {
- ///
- /// Contains info about track
- ///
- public class AudioTrackInfo {
- ///
- /// Track title
- ///
- public string Title { get; }
-
- ///
- /// Track author
- ///
- public string Author { get; }
-
- ///
- /// Track lenght
- ///
- public TimeSpan Length { get; }
-
- ///
- /// Track identifier
- ///
- public string Identifier { get; }
-
- ///
- /// Is track live stream
- ///
- [Obsolete("There is no streams support in library. \nWill removed in 3.0")]
- public bool IsStream { get; }
-
- ///
- /// Track link
- ///
- public string Uri { get; }
-
- ///
- /// Additional track metadata
- ///
- [Obsolete("Metadata used only for image uri storing. Use ArtworkUrl property instead. \nWill be removed in 3.0")]
- public Dictionary Metadata { get; }
-
- ///
- /// Track image uri
- ///
- public string? ArtworkUrl { get; }
-
- public AudioTrackInfo(string title, string author, TimeSpan length, string identifier, bool isStream, string uri, Dictionary metadata) {
- Title = title;
- Author = author;
- Length = length;
- Identifier = identifier;
- 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();
- if (artworkUrl != null) {
- Metadata.Add("artworkUrl", artworkUrl);
- ArtworkUrl = artworkUrl;
- }
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Config/FileYandexConfig.cs b/YandexMusicResolver/Config/FileYandexConfig.cs
index 4af99a9..de3bb9c 100644
--- a/YandexMusicResolver/Config/FileYandexConfig.cs
+++ b/YandexMusicResolver/Config/FileYandexConfig.cs
@@ -8,7 +8,8 @@ namespace YandexMusicResolver.Config {
/// Represents implementation that stores data in a file
///
public class FileYandexConfig : IYandexConfig {
- private string? _filePath;
+ private string _filePath;
+ private bool isLoaded;
///
/// Initializes a new instance of the class.
@@ -20,6 +21,7 @@ public FileYandexConfig(string? filePath = null) {
///
public virtual void Load() {
+ if (isLoaded) return;
try {
if (File.Exists(_filePath)) {
var fileYandexConfig = JsonConvert.DeserializeObject(File.ReadAllText(_filePath));
@@ -39,6 +41,8 @@ public virtual void Load() {
catch (Exception) {
// ignored
}
+
+ isLoaded = true;
}
///
diff --git a/YandexMusicResolver/Config/IYandexConfig.cs b/YandexMusicResolver/Config/IYandexConfig.cs
index 2d46f0e..abd9df7 100644
--- a/YandexMusicResolver/Config/IYandexConfig.cs
+++ b/YandexMusicResolver/Config/IYandexConfig.cs
@@ -8,7 +8,7 @@ namespace YandexMusicResolver.Config {
///
public interface IYandexConfig : IYandexProxyTokenHolder {
///
- /// Load config
+ /// Load config. This method can be called multiple times
///
void Load();
@@ -37,7 +37,7 @@ public interface IYandexConfig : IYandexProxyTokenHolder {
/// Will be thrown if we cant authorize and is false
public async Task AuthorizeAsync(bool allowRunWithoutAuth = true) {
if (YandexToken != null)
- if (await YandexMusicAuth.CheckToken(YandexToken, this))
+ if (await YandexMusicAuth.ValidateTokenAsync(YandexToken, this))
return;
if (YandexLogin == null || YandexPassword == null) {
@@ -46,7 +46,7 @@ public async Task AuthorizeAsync(bool allowRunWithoutAuth = true) {
}
try {
- YandexToken = await YandexMusicAuth.GetToken(YandexLogin, YandexPassword, this);
+ YandexToken = await YandexMusicAuth.LoginAsync(YandexLogin, YandexPassword, this);
Save();
}
catch (Exception e) {
diff --git a/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs b/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs
index 9c465a4..eb6ffda 100644
--- a/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs
+++ b/YandexMusicResolver/Loaders/YandexMusicDirectUrlLoader.cs
@@ -6,7 +6,7 @@
using System.Xml.Serialization;
using YandexMusicResolver.Config;
using YandexMusicResolver.Requests;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Loaders {
///
@@ -20,6 +20,7 @@ public class YandexMusicDirectUrlLoader {
///
/// Config instance for performing requests
public YandexMusicDirectUrlLoader(IYandexConfig config) {
+ config.Load();
_config = config;
}
diff --git a/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs b/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs
index 075186f..0d73b10 100644
--- a/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs
+++ b/YandexMusicResolver/Loaders/YandexMusicPlaylistLoader.cs
@@ -4,18 +4,22 @@
using YandexMusicResolver.AudioItems;
using YandexMusicResolver.Config;
using YandexMusicResolver.Requests;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Loaders {
///
/// Represents class to getting playlists and albums from Yandex Music
///
- public class YandexMusicPlaylistLoader : YandexMusicTrackLoader {
+ public class YandexMusicPlaylistLoader {
+ protected readonly IYandexConfig Config;
+
///
/// Initializes a new instance of the class.
///
/// Config instance for performing requests
- public YandexMusicPlaylistLoader(IYandexConfig config) : base(config) { }
+ public YandexMusicPlaylistLoader(IYandexConfig config) {
+ Config = config;
+ }
private const string PlaylistInfoFormat = "https://api.music.yandex.net/users/{0}/playlists/{1}";
private const string AlbumInfoFormat = "https://api.music.yandex.net/albums/{0}/with-tracks";
@@ -24,42 +28,31 @@ public YandexMusicPlaylistLoader(IYandexConfig config) : base(config) { }
/// Loads the playlist from Yandex Music
///
/// Id of user who created the playlist
- /// Target playlist id
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
+ /// Target playlist id
/// Playlist instance
- public Task LoadPlaylist(string userId, string playlistId, Func trackFactory) {
- return LoadPlaylistUrl(string.Format(PlaylistInfoFormat, userId, playlistId), trackFactory);
- }
+ public async Task LoadPlaylist(string userId, string playlistKind) {
+ string url = string.Format(PlaylistInfoFormat, userId, playlistKind);
+ var playlistData = await new YandexCustomRequest(Config).Create(url).GetResponseAsync();
+ if (playlistData.Tracks == null) {
+ throw new Exception("Empty playlist found.");
+ }
- ///
- /// Loads the album from Yandex Music
- ///
- /// Target album id
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
- /// Playlist instance
- [Obsolete("For album loading use LoadAlbum method. \nWill be removed in 3.0")]
- public Task LoadPlaylist(string albumId, Func trackFactory) {
- return LoadPlaylistUrl(string.Format(AlbumInfoFormat, albumId), trackFactory);
+ return playlistData.ToYaPlaylist(this);
}
///
/// Loads the album from Yandex Music
///
/// Target album id
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
/// Playlist instance
- public Task LoadAlbum(string albumId, Func trackFactory) {
- return LoadPlaylistUrl(string.Format(AlbumInfoFormat, albumId), trackFactory);
- }
-
- private async Task LoadPlaylistUrl(string url, Func trackFactory) {
- var playlistData = await new YandexCustomRequest(Config).Create(url).GetResponseAsync();
+ public async Task LoadAlbum(string albumId) {
+ string url = string.Format(AlbumInfoFormat, albumId);
+ var playlistData = await new YandexCustomRequest(Config).Create(url).GetResponseAsync();
if (playlistData.Tracks == null) {
throw new Exception("Empty album or playlist found.");
}
- var tracks = await Task.WhenAll(playlistData.Tracks.Select(async container => trackFactory(await container.ToAudioTrackInfo(this))));
- return new YandexMusicPlaylist(playlistData.Title, tracks.ToList().AsReadOnly(), false);
+ return playlistData.ToYmAlbum(this);
}
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/Loaders/YandexMusicSearchResultLoader.cs b/YandexMusicResolver/Loaders/YandexMusicSearchResultLoader.cs
index b6c50f3..7c15b73 100644
--- a/YandexMusicResolver/Loaders/YandexMusicSearchResultLoader.cs
+++ b/YandexMusicResolver/Loaders/YandexMusicSearchResultLoader.cs
@@ -5,7 +5,7 @@
using YandexMusicResolver.AudioItems;
using YandexMusicResolver.Config;
using YandexMusicResolver.Requests;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Loaders {
///
@@ -18,24 +18,35 @@ public class YandexMusicSearchResultLoader {
public const int DefaultLimit = 10;
private const string TracksInfoFormat = "https://api.music.yandex.net/search?type={0}&page=0&text={1}";
- private Regex SearchRegex;
+ private Regex SearchRegex = new Regex($"ymsearch(:([a-zA-Z]+))?(:([0-9]+))?:([^:]+)");
private IYandexConfig _config;
+ private string _searchPrefix = "ymsearch";
+ #pragma warning disable 1591
+ protected YandexMusicPlaylistLoader PlaylistLoader;
+ #pragma warning restore 1591
///
/// Special prefix for complicated requests
///
- public string SearchPrefix { get; }
+ public string SearchPrefix => _searchPrefix;
///
/// Initializes a new instance of the class.
///
/// Config instance for performing requests
- ///
- public YandexMusicSearchResultLoader(IYandexConfig config, string? searchPrefix = null) {
- // ReSharper disable once StringLiteralTypo
- SearchPrefix = searchPrefix ?? "ymsearch";
+ public YandexMusicSearchResultLoader(IYandexConfig config, YandexMusicPlaylistLoader playlistLoader) {
+ PlaylistLoader = playlistLoader;
+ config.Load();
_config = config;
- SearchRegex = new Regex($"{SearchPrefix}(:([a-zA-Z]+))?(:([0-9]+))?:([^:]+)");
+ }
+
+ ///
+ /// Set a new search prefix for complicated queries
+ ///
+ /// New prefix. null
will be replaced with "ymsearch"
+ public void SetSearchPrefix(string? prefix = null) {
+ _searchPrefix = prefix ?? "ymsearch";
+ SearchRegex = new Regex($"{_searchPrefix}(:([a-zA-Z]+))?(:([0-9]+))?:([^:]+)");
}
///
@@ -43,13 +54,10 @@ public YandexMusicSearchResultLoader(IYandexConfig config, string? searchPrefix
///
/// Complicated query is ::limit:text
/// Search query. May be complicated or default values will be used
- /// Playlist loader instance
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
/// Instance of YandexMusicSearchResult
- public Task LoadSearchResult(string query, YandexMusicPlaylistLoader playlistLoader,
- Func trackFactory) {
+ public Task LoadSearchResult(string query) {
TryParseQuery(query, out var text, out var type, out var limit);
- return LoadSearchResult(type, text, playlistLoader, trackFactory, limit);
+ return LoadSearchResult(type, text, limit);
}
///
@@ -82,24 +90,23 @@ public bool TryParseQuery(string query, out string text, out YandexSearchType ty
/// Search type
/// Search text
/// Playlist loader instance
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
/// Search results limit count
/// Instance of YandexMusicSearchResult
/// Throws exception if something went wrong
- public async Task LoadSearchResult(YandexSearchType type, string query, YandexMusicPlaylistLoader playlistLoader,
- Func trackFactory, int limit = DefaultLimit) {
+ public async Task LoadSearchResult(YandexSearchType type, string query, int limit = DefaultLimit) {
try {
var searchResponse = await new YandexCustomRequest(_config)
.Create(string.Format(TracksInfoFormat, type, query))
.GetResponseAsync();
- var albums = searchResponse.Albums?.Results.Take(limit);
- var playlists = searchResponse.Playlists?.Results.Take(limit);
- var tracks = searchResponse.Tracks?.Results.Take(limit);
+ var albums = searchResponse.Albums?.Results.Take(limit).Select(signature => signature.ToYmAlbum(PlaylistLoader));
+ var playlists = searchResponse.Playlists?.Results.Take(limit).Select(signature => signature.ToYaPlaylist(PlaylistLoader));
+ var tracks = searchResponse.Tracks?.Results.Take(limit).Select(track => track.ToYmTrack());
- return new YandexMusicSearchResult(query, limit, type,
+ return new YandexMusicSearchResult(query, true, type,
albums?.ToList().AsReadOnly(),
playlists?.ToList().AsReadOnly(),
- tracks?.ToList().AsReadOnly());
+ tracks?.ToList().AsReadOnly(),
+ limit);
}
catch (Exception e) {
throw new Exception("Could not load search results", e);
diff --git a/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs b/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs
index af304d9..817859d 100644
--- a/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs
+++ b/YandexMusicResolver/Loaders/YandexMusicTrackLoader.cs
@@ -5,7 +5,7 @@
using YandexMusicResolver.AudioItems;
using YandexMusicResolver.Config;
using YandexMusicResolver.Requests;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Loaders {
///
@@ -22,53 +22,20 @@ public class YandexMusicTrackLoader {
///
/// Config instance for performing requests
public YandexMusicTrackLoader(IYandexConfig config) {
+ config.Load();
Config = config;
}
private const string TracksInfoFormat = "https://api.music.yandex.net/tracks?trackIds=";
- ///
- /// Load track
- ///
- /// Album id with track
- /// Target track id
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
- /// Instance of
- [Obsolete("We do not need an album ID to load track information. \nWill be removed in 3.0")]
- public Task LoadTrack(string albumId, string trackId, Func trackFactory) {
- return LoadTrack(trackId, trackFactory);
- }
-
- ///
- /// Load track
- ///
- /// Target track id
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
- /// Instance of
- public async Task LoadTrack(string trackId, Func trackFactory) {
- return trackFactory((await LoadTrackInfo(trackId))!);
- }
-
- ///
- /// Load track info
- ///
- /// Album id with track
- /// Target track id
- /// Instance of
- [Obsolete("We do not need an album ID to load track information. \nWill be removed in 3.0")]
- public Task LoadTrackInfo(string albumId, string trackId) {
- return LoadTrackInfo(trackId);
- }
-
///
/// Load track info
///
/// Target track id
/// Instance of
- public async Task LoadTrackInfo(string trackId) {
+ public async Task LoadTrack(string trackId) {
var response = await new YandexCustomRequest(Config).Create(TracksInfoFormat + trackId).GetResponseAsync>();
- var entry = response.First();
- return await entry.ToAudioTrackInfo(this);
+ return response.FirstOrDefault()?.ToYmTrack();
}
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/Requests/YandexAuthRequest.cs b/YandexMusicResolver/Requests/YandexAuthRequest.cs
index 4fa3b52..8839d79 100644
--- a/YandexMusicResolver/Requests/YandexAuthRequest.cs
+++ b/YandexMusicResolver/Requests/YandexAuthRequest.cs
@@ -5,7 +5,7 @@
using System.Web;
using Newtonsoft.Json;
using YandexMusicResolver.Config;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Requests {
internal class YandexAuthRequest : YandexRequest {
diff --git a/YandexMusicResolver/Requests/YandexRequest.cs b/YandexMusicResolver/Requests/YandexRequest.cs
index b3ab847..32981c4 100644
--- a/YandexMusicResolver/Requests/YandexRequest.cs
+++ b/YandexMusicResolver/Requests/YandexRequest.cs
@@ -9,7 +9,7 @@
using System.Web;
using Newtonsoft.Json;
using YandexMusicResolver.Config;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver.Requests {
internal class YandexRequest {
diff --git a/YandexMusicResolver/Responces/ITrackInfoContainer.cs b/YandexMusicResolver/Responces/ITrackInfoContainer.cs
deleted file mode 100644
index 9ea1f82..0000000
--- a/YandexMusicResolver/Responces/ITrackInfoContainer.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using System.Threading.Tasks;
-using YandexMusicResolver.Loaders;
-
-namespace YandexMusicResolver.Responces {
- ///
- /// Represents entity from which we can get
- ///
- public interface ITrackInfoContainer {
- ///
- /// Get related
- ///
- /// Track loader instance
- /// Instance of
- Task ToAudioTrackInfo(YandexMusicTrackLoader loader);
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaAlbumSignature.cs b/YandexMusicResolver/Responces/MetaAlbumSignature.cs
deleted file mode 100644
index b7e8b33..0000000
--- a/YandexMusicResolver/Responces/MetaAlbumSignature.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using YandexMusicResolver.AudioItems;
-using YandexMusicResolver.Loaders;
-
-namespace YandexMusicResolver.Responces {
- ///
- /// Represents data to resolve album
- ///
- public class MetaAlbumSignature {
- ///
- /// Id of this entity
- ///
- [JsonProperty("id")]
- public long Id { get; set; }
-
- ///
- /// Title of this album
- ///
- [JsonProperty("title")]
- public string Title { get; set; } = null!;
-
- ///
- /// Cover link
- ///
- [JsonProperty("coverUri")]
- public string? CoverUri { get; set; }
-
- ///
- /// Opengraph image (alternative cover) url
- ///
- [JsonProperty("ogImage")]
- public string? OgImage { get; set; }
-
- ///
- /// Count of tracks
- ///
- [JsonProperty("trackCount")]
- public long TrackCount { get; set; }
-
- ///
- /// Is this playlist available now
- ///
- [JsonProperty("available")]
- public bool Available { get; set; }
-
- ///
- /// Get full playlist with tracks
- ///
- /// Instance of playlist loader to load playlist
- /// Track factory to create YandexMusicTrack from AudioTrackInfo
- /// Playlist with tracks
- public virtual async Task GetPlaylist(YandexMusicPlaylistLoader yandexMusicPlaylistLoader,
- Func trackFactory) {
- return (await yandexMusicPlaylistLoader.LoadPlaylist(Id.ToString(), trackFactory))!;
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaPlaylist.cs b/YandexMusicResolver/Responces/MetaPlaylist.cs
deleted file mode 100644
index 5f86f60..0000000
--- a/YandexMusicResolver/Responces/MetaPlaylist.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using Newtonsoft.Json;
-
-namespace YandexMusicResolver.Responces {
- internal class MetaPlaylist {
- [JsonProperty("title")]
- public string Title { get; set; } = null!;
-
- [JsonProperty("trackCount")]
- public long TrackCount { get; set; }
-
- [JsonProperty("ogImage")]
- public string? OgImage { get; set; }
-
- [JsonProperty("coverUri")]
- public string? CoverUri { get; set; }
-
- [JsonProperty("available")]
- public bool Available { get; set; } = true;
-
- [JsonProperty("tracks")]
- private List PlaylistTracks {
- set => Tracks = value.Select(container => container.Track).Cast().ToList();
- }
-
- [JsonProperty("volumes")]
- private List> AlbumVolumes {
- set => Tracks = value.SelectMany(list => list).Cast().ToList();
- }
-
- public List Tracks { get; set; } = null!;
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaPlaylistSignature.cs b/YandexMusicResolver/Responces/MetaPlaylistSignature.cs
deleted file mode 100644
index c2bcb13..0000000
--- a/YandexMusicResolver/Responces/MetaPlaylistSignature.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using YandexMusicResolver.AudioItems;
-using YandexMusicResolver.Loaders;
-
-namespace YandexMusicResolver.Responces {
- ///
- /// Represents data to resolve playlist
- ///
- public class MetaPlaylistSignature : MetaAlbumSignature {
- [JsonProperty("uid")]
- [Obsolete]
- public long PlaylistId {
- set => Id = value;
- }
-
- ///
- /// Playlist owner info
- ///
- [JsonProperty("owner")]
- public MetaOwner Owner { get; set; } = null!;
-
- ///
- public override async Task GetPlaylist(YandexMusicPlaylistLoader yandexMusicPlaylistLoader,
- Func trackFactory) {
- return (await yandexMusicPlaylistLoader.LoadPlaylist(Owner.Uid.ToString(), Id.ToString(), trackFactory))!;
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaPlaylistTrack.cs b/YandexMusicResolver/Responces/MetaPlaylistTrack.cs
deleted file mode 100644
index ca1a3ef..0000000
--- a/YandexMusicResolver/Responces/MetaPlaylistTrack.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using YandexMusicResolver.AudioItems;
-using YandexMusicResolver.Loaders;
-
-namespace YandexMusicResolver.Responces {
- ///
- /// Represent
- ///
- internal class MetaPlaylistTrack : ITrackInfoContainer {
- ///
- /// Track id
- ///
- [JsonProperty("id")]
- public long Id { get; set; }
-
- ///
- /// List of albums that contain this track
- ///
- [JsonProperty("albums")]
- public List Albums { get; set; } = null!;
-
- ///
- /// Creation timestamp
- ///
- [JsonProperty("timestamp")]
- public DateTimeOffset Timestamp { get; set; }
-
- ///
- public async Task ToAudioTrackInfo(YandexMusicTrackLoader loader) {
- return (await loader.LoadTrack(Albums.First().Id.ToString(), Id.ToString(), TrackFactory))?.TrackInfo!;
- }
-
- private YandexMusicTrack TrackFactory(AudioTrackInfo arg) {
- // This is fake for retrieving track info
- return new YandexMusicTrack(arg, null!);
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaTrack.cs b/YandexMusicResolver/Responces/MetaTrack.cs
deleted file mode 100644
index b1007b2..0000000
--- a/YandexMusicResolver/Responces/MetaTrack.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Newtonsoft.Json;
-using YandexMusicResolver.Converters;
-using YandexMusicResolver.Loaders;
-
-namespace YandexMusicResolver.Responces {
- ///
- /// Track data from Yandex Music
- ///
- public class MetaTrack : ITrackInfoContainer {
- private const string TrackUrlFormat = "https://music.yandex.ru/album/{0}/track/{1}";
-
- ///
- /// Track ID
- ///
- [JsonProperty("id")]
- [JsonConverter(typeof(ParseStringConverter))]
- public long Id { get; set; }
-
- ///
- /// Track title
- ///
- [JsonProperty("title")]
- public string Title { get; set; } = null!;
-
- ///
- /// Is track available
- ///
- /// If false, then most likely you are trying to get this information while not in the CIS. At the moment, you need to use a proxy in the CIS or log in with an account that has Yandex Plus (a subscription from Yandex)
- [JsonProperty("available")]
- public bool Available { get; set; }
-
- ///
- /// Track duration in ms
- ///
- [JsonProperty("durationMs")]
- public long DurationMs { get; set; }
-
- ///
- /// Track authors list
- ///
- [JsonProperty("artists")]
- public MetaArtist[] Artists { get; set; } = null!;
-
- ///
- /// List of albums that contain this track
- ///
- [JsonProperty("albums")]
- public MetaAlbumSignature[] Albums { get; set; } = null!;
-
- ///
- /// Cover link
- ///
- [JsonProperty("coverUri")]
- public string? CoverUri { get; set; }
-
- ///
- /// Opengraph image (alternative cover) link
- ///
- [JsonProperty("ogImage")]
- public string? OgImage { get; set; }
-
- ///
- /// Is lyrics available for this track
- ///
- [JsonProperty("lyricsAvailable")]
- public bool LyricsAvailable { get; set; }
-
- ///
- /// Convert this meta class to
- ///
- /// Instance of
- public Task ToAudioTrackInfo() {
- var artists = string.Join(", ", Artists.Select(artist => artist.Name));
- var album = Albums.First();
-
- string? artworkUrl = null;
- TryApplyArtwork(ref artworkUrl, CoverUri);
- TryApplyArtwork(ref artworkUrl, OgImage);
- TryApplyArtwork(ref artworkUrl, album.CoverUri);
- TryApplyArtwork(ref artworkUrl, album.OgImage);
-
- return Task.FromResult(
- new AudioTrackInfo(
- Title,
- artists,
- TimeSpan.FromMilliseconds(DurationMs),
- Id.ToString(),
- false,
- string.Format(TrackUrlFormat, album.Id, Id),
- new Dictionary {{"artworkUrl", artworkUrl!}}));
- }
-
- ///
- public Task ToAudioTrackInfo(YandexMusicTrackLoader loader) {
- return ToAudioTrackInfo();
- }
-
- private static void TryApplyArtwork(ref string? final, string? artwork) {
- if (final != null || artwork == null) return;
- final = "https://" + artwork.Replace("%%", "200x200");
- }
- }
-}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaAccount.cs b/YandexMusicResolver/Responses/MetaAccount.cs
similarity index 95%
rename from YandexMusicResolver/Responces/MetaAccount.cs
rename to YandexMusicResolver/Responses/MetaAccount.cs
index 4ff7a18..9e5a61d 100644
--- a/YandexMusicResolver/Responces/MetaAccount.cs
+++ b/YandexMusicResolver/Responses/MetaAccount.cs
@@ -3,7 +3,7 @@
#pragma warning disable 8618
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaAccount {
[JsonProperty("now")]
public DateTimeOffset Now { get; set; }
diff --git a/YandexMusicResolver/Responces/MetaAccountResponse.cs b/YandexMusicResolver/Responses/MetaAccountResponse.cs
similarity index 86%
rename from YandexMusicResolver/Responces/MetaAccountResponse.cs
rename to YandexMusicResolver/Responses/MetaAccountResponse.cs
index def533b..320376a 100644
--- a/YandexMusicResolver/Responces/MetaAccountResponse.cs
+++ b/YandexMusicResolver/Responses/MetaAccountResponse.cs
@@ -2,7 +2,7 @@
#pragma warning disable 8618
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaAccountResponse {
[JsonProperty("account")]
public MetaAccount? Account { get; set; }
diff --git a/YandexMusicResolver/Responses/MetaAlbum.cs b/YandexMusicResolver/Responses/MetaAlbum.cs
new file mode 100644
index 0000000..c1a1452
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaAlbum.cs
@@ -0,0 +1,25 @@
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+using YandexMusicResolver.AudioItems;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.Responses {
+ internal class MetaAlbum : MetaAlbumSignature {
+ [JsonProperty("volumes", NullValueHandling = NullValueHandling.Ignore)]
+ public List> Tracks { get; set; }
+
+ [JsonProperty("ogImage")]
+ public string OgImage { get; set; }
+
+ public override YandexMusicAlbum ToYmAlbum(YandexMusicPlaylistLoader loader) {
+ var artwork = CoverUri;
+ if (string.IsNullOrEmpty(artwork)) {
+ artwork = OgImage;
+ }
+
+ return new YandexMusicAlbum(Id, Year, Artists, artwork, TrackCount, Genre, Title,
+ Tracks.SelectMany(list => list).Select(track => track.ToYmTrack()).ToList());
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responses/MetaAlbumSignature.cs b/YandexMusicResolver/Responses/MetaAlbumSignature.cs
new file mode 100644
index 0000000..d8f0cb2
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaAlbumSignature.cs
@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using YandexMusicResolver.AudioItems;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.Responses {
+ internal class MetaAlbumSignature
+ {
+ [JsonProperty("id")]
+ public long Id { get; set; }
+
+ [JsonProperty("year")]
+ public long Year { get; set; }
+
+ [JsonProperty("artists")]
+ public List Artists { get; set; } = null!;
+
+ [JsonProperty("coverUri")]
+ public string? CoverUri { get; set; }
+
+ [JsonProperty("trackCount")]
+ public long TrackCount { get; set; }
+
+ [JsonProperty("genre")]
+ public string Genre { get; set; } = null!;
+
+ [JsonProperty("available")]
+ public bool Available { get; set; }
+
+ [JsonProperty("availableForPremiumUsers")]
+ public bool AvailableForPremiumUsers { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; }
+
+ public virtual YandexMusicAlbum ToYmAlbum(YandexMusicPlaylistLoader loader) {
+ return new(Id, Year, Artists, CoverUri, TrackCount, Genre, Title, loader);
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaAuthResponse.cs b/YandexMusicResolver/Responses/MetaAuthResponse.cs
similarity index 90%
rename from YandexMusicResolver/Responces/MetaAuthResponse.cs
rename to YandexMusicResolver/Responses/MetaAuthResponse.cs
index bc6c607..fbf8484 100644
--- a/YandexMusicResolver/Responces/MetaAuthResponse.cs
+++ b/YandexMusicResolver/Responses/MetaAuthResponse.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaAuthResponse {
[JsonProperty("access_token")]
public string AccessToken { get; set; } = null!;
diff --git a/YandexMusicResolver/Responses/MetaCover.cs b/YandexMusicResolver/Responses/MetaCover.cs
new file mode 100644
index 0000000..8fedb1f
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaCover.cs
@@ -0,0 +1,25 @@
+using Newtonsoft.Json;
+
+namespace YandexMusicResolver.Responses {
+ internal class MetaCover {
+ [JsonProperty("type")]
+ public string Type { get; set; } = null!;
+
+ [JsonProperty("dir")]
+ public string? Dir { get; set; }
+
+ [JsonProperty("version")]
+ public string? Version { get; set; }
+
+ [JsonProperty("uri")]
+ public string? Uri { get; set; }
+
+ [JsonProperty("custom")]
+ public bool Custom { get; set; }
+
+ public string? GetCoverUrl() {
+ if (Uri == null) return null;
+ return "https://" + Uri.Replace("%%", "200x200");
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaError.cs b/YandexMusicResolver/Responses/MetaError.cs
similarity index 91%
rename from YandexMusicResolver/Responces/MetaError.cs
rename to YandexMusicResolver/Responses/MetaError.cs
index 39fac58..fb21301 100644
--- a/YandexMusicResolver/Responces/MetaError.cs
+++ b/YandexMusicResolver/Responses/MetaError.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
///
/// Represents error that returned from Yandex Music
///
diff --git a/YandexMusicResolver/Responses/MetaPlaylist.cs b/YandexMusicResolver/Responses/MetaPlaylist.cs
new file mode 100644
index 0000000..b166fe7
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaPlaylist.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Newtonsoft.Json;
+using YandexMusicResolver.AudioItems;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.Responses {
+ internal class MetaPlaylist : MetaPlaylistSignature {
+ [JsonProperty("tracks")]
+ private List PlaylistTracks {
+ set => Tracks = value.Select(container => container.Track).ToList();
+ }
+
+ public List Tracks { get; set; } = null!;
+ public override YandexMusicPlaylist ToYaPlaylist(YandexMusicPlaylistLoader loader) {
+ return new(Uid, Kind, TrackCount, Title, Owner, Cover.GetCoverUrl(), Tracks.Select(track => track.ToYmTrack()).ToList());
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responses/MetaPlaylistSignature.cs b/YandexMusicResolver/Responses/MetaPlaylistSignature.cs
new file mode 100644
index 0000000..c76b05d
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaPlaylistSignature.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using YandexMusicResolver.AudioItems;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.Responses {
+ internal class MetaPlaylistSignature {
+ [JsonProperty("uid")]
+ public long Uid { get; set; }
+
+ [JsonProperty("kind")]
+ public long Kind { get; set; }
+
+ [JsonProperty("trackCount")]
+ public long TrackCount { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; }
+
+ [JsonProperty("owner")]
+ public YandexMusicOwner Owner { get; set; }
+
+ [JsonProperty("cover")]
+ public MetaCover Cover { get; set; }
+
+ public virtual YandexMusicPlaylist ToYaPlaylist(YandexMusicPlaylistLoader loader) {
+ return new(Uid, Kind, TrackCount, Title, Owner, Cover.GetCoverUrl(), loader);
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs b/YandexMusicResolver/Responses/MetaPlaylistTrackContainer.cs
similarity index 63%
rename from YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs
rename to YandexMusicResolver/Responses/MetaPlaylistTrackContainer.cs
index c7da8e0..9f971cf 100644
--- a/YandexMusicResolver/Responces/MetaPlaylistTrackContainer.cs
+++ b/YandexMusicResolver/Responses/MetaPlaylistTrackContainer.cs
@@ -1,11 +1,11 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaPlaylistTrackContainer {
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("track")]
- public MetaPlaylistTrack Track { get; set; } = null!;
+ public MetaTrack Track { get; set; } = null!;
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaSearchResponse.cs b/YandexMusicResolver/Responses/MetaSearchResponse.cs
similarity index 95%
rename from YandexMusicResolver/Responces/MetaSearchResponse.cs
rename to YandexMusicResolver/Responses/MetaSearchResponse.cs
index daca6e2..d0f2dad 100644
--- a/YandexMusicResolver/Responces/MetaSearchResponse.cs
+++ b/YandexMusicResolver/Responses/MetaSearchResponse.cs
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaSearchResponse {
[JsonProperty("albums")]
public MetaSearchContentProxy? Albums { get; set; }
diff --git a/YandexMusicResolver/Responses/MetaTrack.cs b/YandexMusicResolver/Responses/MetaTrack.cs
new file mode 100644
index 0000000..50258a8
--- /dev/null
+++ b/YandexMusicResolver/Responses/MetaTrack.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+using YandexMusicResolver.AudioItems;
+using YandexMusicResolver.Converters;
+using YandexMusicResolver.Loaders;
+
+namespace YandexMusicResolver.Responses {
+ ///
+ /// Track data from Yandex Music
+ ///
+ internal class MetaTrack {
+ private const string TrackUrlFormat = "https://music.yandex.ru/album/{0}/track/{1}";
+
+ [JsonProperty("id")]
+ [JsonConverter(typeof(ParseStringConverter))]
+ public long Id { get; set; }
+
+ [JsonProperty("title")]
+ public string Title { get; set; } = null!;
+
+ [JsonProperty("available")]
+ public bool Available { get; set; }
+
+ [JsonProperty("durationMs")]
+ public long DurationMs { get; set; }
+
+ [JsonProperty("artists")]
+ public List Artists { get; set; } = null!;
+
+ [JsonProperty("albums")]
+ public List Albums { get; set; } = null!;
+
+ [JsonProperty("coverUri")]
+ public string? CoverUri { get; set; }
+
+ [JsonProperty("ogImage")]
+ public string? OgImage { get; set; }
+
+ [JsonProperty("lyricsAvailable")]
+ public bool LyricsAvailable { get; set; }
+
+ public YandexMusicTrack ToYmTrack() {
+ var album = Albums.First();
+
+ string? artworkUrl = null;
+ TryApplyArtwork(ref artworkUrl, CoverUri);
+ TryApplyArtwork(ref artworkUrl, OgImage);
+ TryApplyArtwork(ref artworkUrl, album.CoverUri);
+ // TryApplyArtwork(ref artworkUrl, album.OgImage);
+
+ return new YandexMusicTrack(Title, Artists,
+ TimeSpan.FromMilliseconds(DurationMs), Id.ToString(),
+ string.Format(TrackUrlFormat, album.Id, Id), artworkUrl);
+ }
+
+ private static void TryApplyArtwork(ref string? final, string? artwork) {
+ if (final != null || artwork == null) return;
+ final = "https://" + artwork.Replace("%%", "200x200");
+ }
+ }
+}
\ No newline at end of file
diff --git a/YandexMusicResolver/Responces/MetaTrackDownloadInfo.cs b/YandexMusicResolver/Responses/MetaTrackDownloadInfo.cs
similarity index 93%
rename from YandexMusicResolver/Responces/MetaTrackDownloadInfo.cs
rename to YandexMusicResolver/Responses/MetaTrackDownloadInfo.cs
index 64bfcca..57ebb68 100644
--- a/YandexMusicResolver/Responces/MetaTrackDownloadInfo.cs
+++ b/YandexMusicResolver/Responses/MetaTrackDownloadInfo.cs
@@ -1,7 +1,7 @@
using System;
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class MetaTrackDownloadInfo {
[JsonProperty("codec")]
public string Codec { get; set; } = null!;
diff --git a/YandexMusicResolver/Responces/MetaTrackDownloadInfoXml.cs b/YandexMusicResolver/Responses/MetaTrackDownloadInfoXml.cs
similarity index 93%
rename from YandexMusicResolver/Responces/MetaTrackDownloadInfoXml.cs
rename to YandexMusicResolver/Responses/MetaTrackDownloadInfoXml.cs
index 3bac4d2..2c2f767 100644
--- a/YandexMusicResolver/Responces/MetaTrackDownloadInfoXml.cs
+++ b/YandexMusicResolver/Responses/MetaTrackDownloadInfoXml.cs
@@ -2,7 +2,7 @@
#pragma warning disable 1591
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
[XmlRoot(ElementName = "download-info")]
public class MetaTrackDownloadInfoXml {
[XmlElement(ElementName = "host")]
diff --git a/YandexMusicResolver/Responces/YandexApiResponce.cs b/YandexMusicResolver/Responses/YandexApiResponce.cs
similarity index 84%
rename from YandexMusicResolver/Responces/YandexApiResponce.cs
rename to YandexMusicResolver/Responses/YandexApiResponce.cs
index 671f9a5..b28dfbf 100644
--- a/YandexMusicResolver/Responces/YandexApiResponce.cs
+++ b/YandexMusicResolver/Responses/YandexApiResponce.cs
@@ -1,6 +1,6 @@
using Newtonsoft.Json;
-namespace YandexMusicResolver.Responces {
+namespace YandexMusicResolver.Responses {
internal class YandexApiResponse {
[JsonProperty("result")]
public T? Result { get; set; }
diff --git a/YandexMusicResolver/YandexMusicAuth.cs b/YandexMusicResolver/YandexMusicAuth.cs
index a16683b..cfae0e0 100644
--- a/YandexMusicResolver/YandexMusicAuth.cs
+++ b/YandexMusicResolver/YandexMusicAuth.cs
@@ -1,22 +1,23 @@
using System.Threading.Tasks;
using YandexMusicResolver.Config;
using YandexMusicResolver.Requests;
-using YandexMusicResolver.Responces;
+using YandexMusicResolver.Responses;
namespace YandexMusicResolver {
///
/// Represents a set of methods that serve for authorization in Yandex Music
///
- public class YandexMusicAuth {
+ public static class YandexMusicAuth {
///
/// Validates token
///
/// Token to validate
/// Container for proxy, which should be used for request
- /// True if token correct
- public static async Task CheckToken(string token, IYandexProxyHolder? proxyHolder = null) {
- var metaAccountResponse = await new YandexCustomRequest(proxyHolder, new TokenHolder(token)).Create("https://api.music.yandex.net/account/status")
- .GetResponseAsync();
+ /// True if token valid
+ public static async Task ValidateTokenAsync(string token, IYandexProxyHolder? proxyHolder = null) {
+ var metaAccountResponse = await new YandexCustomRequest(proxyHolder, new TokenHolder(token))
+ .Create("https://api.music.yandex.net/account/status")
+ .GetResponseAsync();
return !string.IsNullOrEmpty(metaAccountResponse.Account?.Uid);
}
@@ -27,7 +28,7 @@ public static async Task CheckToken(string token, IYandexProxyHolder? prox
/// Password from Yandex account
/// Container for proxy, which should be used for request
/// Token
- public static async Task GetToken(string login, string password, IYandexProxyHolder? proxyHolder = null) {
+ public static async Task LoginAsync(string login, string password, IYandexProxyHolder? proxyHolder = null) {
return (await new YandexAuthRequest(proxyHolder).Create(login, password).ParseResponseAsync()).AccessToken;
}
@@ -39,13 +40,13 @@ public static async Task GetToken(string login, string password, IYandex
/// Password from Yandex account
/// Container for proxy, which should be used for request
/// Valid token, true if this is new token otherwise false
- public static async Task<(string, bool)> GetToken(string? existentToken, string fallbackLogin, string fallbackPassword,
+ public static async Task ValidateOrLoginAsync(string? existentToken, string fallbackLogin, string fallbackPassword,
IYandexProxyHolder? proxyHolder = null) {
- if (string.IsNullOrWhiteSpace(existentToken) || !await CheckToken(existentToken, proxyHolder)) {
- return (await GetToken(fallbackLogin, fallbackPassword, proxyHolder), true);
+ if (string.IsNullOrWhiteSpace(existentToken) || !await ValidateTokenAsync(existentToken, proxyHolder)) {
+ return await LoginAsync(fallbackLogin, fallbackPassword, proxyHolder);
}
- return (existentToken, false);
+ return existentToken;
}
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/YandexMusicMainResolver.cs b/YandexMusicResolver/YandexMusicMainResolver.cs
index 3326294..71b9d71 100644
--- a/YandexMusicResolver/YandexMusicMainResolver.cs
+++ b/YandexMusicResolver/YandexMusicMainResolver.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using YandexMusicResolver.AudioItems;
@@ -14,9 +15,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 readonly Regex TrackUrlRegex = new Regex(TrackUrlPattern);
- private static readonly Regex AlbumUrlRegex = new Regex(AlbumUrlPattern);
- private static readonly Regex PlaylistUrlRegex = new Regex(PlaylistUrlPattern);
+ private static readonly Regex TrackUrlRegex = new(TrackUrlPattern);
+ private static readonly Regex AlbumUrlRegex = new(AlbumUrlPattern);
+ private static readonly Regex PlaylistUrlRegex = new(PlaylistUrlPattern);
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
private readonly IYandexConfig _config;
@@ -45,82 +46,93 @@ public class YandexMusicMainResolver {
/// Initializes a new instance of the class.
///
/// Yandex config instance
- /// Is query in can be resolved with search
/// Instance of
/// Instance of
/// Instance of
/// Instance of
- [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,
YandexMusicTrackLoader? trackLoader = null,
YandexMusicDirectUrlLoader? directUrlLoader = null,
YandexMusicSearchResultLoader? searchResultLoader = null) {
+ config.Load();
_config = config;
PlaylistLoader = playlistLoader ?? new YandexMusicPlaylistLoader(_config);
TrackLoader = trackLoader ?? new YandexMusicTrackLoader(_config);
DirectUrlLoader = directUrlLoader ?? new YandexMusicDirectUrlLoader(_config);
- SearchResultLoader = searchResultLoader ?? new YandexMusicSearchResultLoader(_config);
- AllowSearch = allowSearch;
+ SearchResultLoader = searchResultLoader ?? new YandexMusicSearchResultLoader(_config, PlaylistLoader);
}
-
+
///
- /// Initializes a new instance of the class.
+ /// Is complicated query in can be resolved
///
- /// Yandex config instance
- /// Instance of
- /// Instance of
- /// Instance of
- /// Instance of
- 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);
- }
+ public bool AllowSearch { get; set; } = true;
///
- /// Is query in can be resolved with search
+ /// If we pass plain text to it will be interpreted as search query with this search type. Set to false
to disable this
///
- public bool AllowSearch { get; set; } = true;
+ public YandexSearchType PlainTextIsSearchQueryType { get; set; } = YandexSearchType.Track;
+
+ ///
+ /// Will plain text be interpreted as a search query in
+ ///
+ public bool PlainTextIsSearchQuery { get; set; } = true;
///
/// Resolves yandex query. Can directly resolve playlists, albums, tracks by url and search queries
///
/// Direct url or search query
/// Is query in can be resolved with search. This parameter overrides
- /// Instance of
- public async Task ResolveQuery(string query, bool? allowSearchOverride = null) {
+ /// Will plain text be interpreted as a search query in
+ /// If we pass plain text to it will be interpreted as search query with this search type
+ /// Instance of . Null if track will now an valid url and is false.
+ public async Task ResolveQuery(string query, bool? allowSearchOverride = null,
+ bool? plainTextIsSearchQueryOverride = null,
+ YandexSearchType? plainTextAsSearchQueryTypeOverride = null) {
var trackMatch = TrackUrlRegex.Match(query);
if (trackMatch.Success) {
- return await TrackLoader.LoadTrack(trackMatch.Groups[1].Value, trackMatch.Groups[2].Value, GetTrack);
+ var tracks = new List();
+
+ var yandexMusicTrack = await TrackLoader.LoadTrack(trackMatch.Groups[2].Value);
+ if (yandexMusicTrack != null) tracks.Add(yandexMusicTrack);
+
+ return new YandexMusicSearchResult(query, false, YandexSearchType.Track, null, null, tracks.AsReadOnly());
}
var playlistMatch = PlaylistUrlRegex.Match(query);
if (playlistMatch.Success) {
- return await PlaylistLoader.LoadPlaylist(playlistMatch.Groups[1].Value, playlistMatch.Groups[2].Value, GetTrack);
+ var playlists = new List();
+
+ var playlist = await PlaylistLoader.LoadPlaylist(playlistMatch.Groups[1].Value, playlistMatch.Groups[2].Value);
+ if (playlist != null) playlists.Add(playlist);
+
+ return new YandexMusicSearchResult(query, false, YandexSearchType.Playlist, null, playlists.AsReadOnly(), null);
}
var albumMatch = AlbumUrlRegex.Match(query);
if (albumMatch.Success) {
- return await PlaylistLoader.LoadPlaylist(albumMatch.Groups[1].Value, GetTrack);
+ var albums = new List();
+
+ var album = await PlaylistLoader.LoadAlbum(albumMatch.Groups[1].Value);
+ if (album != null) albums.Add(album);
+
+ return new YandexMusicSearchResult(query, false, YandexSearchType.Album, albums.AsReadOnly(), null, null);
}
- if (allowSearchOverride ?? AllowSearch) {
- return await SearchResultLoader.LoadSearchResult(query, PlaylistLoader, GetTrack);
+ if (!(allowSearchOverride ?? AllowSearch)) return null;
+ string searchText = query;
+ var searchType = plainTextAsSearchQueryTypeOverride ?? PlainTextIsSearchQueryType;
+ var searchLimit = 10;
+ var needSearch = plainTextIsSearchQueryOverride ?? PlainTextIsSearchQuery;
+ if (SearchResultLoader.TryParseQuery(query, out var text, out var type, out var limit)) {
+ searchText = text;
+ searchType = type;
+ searchLimit = limit;
+ needSearch = true;
}
+ if (needSearch) return await SearchResultLoader.LoadSearchResult(searchType, searchText, searchLimit);
return null;
}
-
- private YandexMusicTrack GetTrack(AudioTrackInfo arg) {
- return new(arg, this);
- }
}
}
\ No newline at end of file
diff --git a/YandexMusicResolver/YandexMusicResolver.csproj b/YandexMusicResolver/YandexMusicResolver.csproj
index bb8731b..4692828 100644
--- a/YandexMusicResolver/YandexMusicResolver.csproj
+++ b/YandexMusicResolver/YandexMusicResolver.csproj
@@ -12,7 +12,7 @@
A library aimed at searching, resolving and getting direct links to tracks, playlists or albums in Yandex.Music. Can work without authorization.
Git
https://github.com/SKProCH/YandexMusicResolver
- 2.2.1
+ 3.0.0
https://github.com/SKProCH/YandexMusicResolver/blob/master/LICENSE
Please write the package release notes in “RELEASE NOTES.md”
@@ -23,12 +23,18 @@
-
+
+
+
+
+
+
+
-
+
@(ReleaseNoteLines, '%0a')
diff --git a/YandexMusicResolver/YandexMusicResolver.xml b/YandexMusicResolver/YandexMusicResolver.xml
index dc65616..42a995d 100644
--- a/YandexMusicResolver/YandexMusicResolver.xml
+++ b/YandexMusicResolver/YandexMusicResolver.xml
@@ -14,15 +14,119 @@
Contains info about error from yandex api
-
+
-
+
-
+
- Marker interface for all loadable items
+ Album id
+
+
+
+
+ Album release year
+
+
+
+
+ Album artists
+
+
+
+
+ Track image uri
+
+
+
+
+ Album tracks count
+
+
+
+
+ Album genre
+
+
+
+
+ Track title
+
+
+
+
+ Represent a artist in Yandex Music
+
+
+
+
+ Artist ID
+
+
+
+
+ Artist name
+
+
+
+
+ Represents class that contains data which could be loaded
+
+
+
+
+
+ Create instance of
+
+ Data creation factory
+
+
+
+ Create instance of
+
+ Target data
+
+
+
+ Load target data
+
+ Task
+
+
+
+ Return true if data already loaded
+
+
+
+
+ Synchronously wait for data loading
+
+
+
+
+ Represent playlist owner
+
+
+
+
+ Owner ID
+
+
+
+
+ Owner login
+
+
+
+
+ Owner name
+
+
+
+
+ Is owner verified
@@ -30,27 +134,34 @@
Represents playlist from Yandex Music
-
+
+
+ Playlist UID
+
+
+
+
+ Playlist kind (something like the user's playlist index)
+
+
+
- Initializes a new instance of the class.
+ Playlist tracks count
- Playlist title
- Collection with tracks
- Is this playlist is search result
Playlist title
-
+
- Collection with tracks in playlist
+ Playlist owner
-
+
- Is this playlist a search result
+ Playlist artwork url
@@ -65,7 +176,8 @@
- Tracks limit count
+ Tracks limit count.
+ Will be null
if the is false
@@ -73,6 +185,11 @@
Search data type
+
+
+ Is this playlist a search result
+
+
Albums list.
@@ -96,66 +213,37 @@
AudioTrackInfo wrapper to resolve track direct url
-
-
- Get track info
-
-
-
-
- Initializes a new instance of the class.
-
- Track info
- Resolver for direct url getting
-
-
-
- Get direct url to track
-
- If you not authorized will return 30s track version. This is YandexMusic restriction
- Direct url to download track
-
-
-
- Contains info about track
-
-
-
+
Track title
-
+
- Track author
+ Track authors
-
+
- Track lenght
+ Compose names into single string
-
+
- Track identifier
+ Track lenght
-
+
- Is track live stream
+ Track id
-
+
Track link
-
-
- Additional track metadata
-
-
-
+
Track image uri
@@ -224,7 +312,7 @@
- Load config
+ Load config. This method can be called multiple times
@@ -309,29 +397,19 @@
Config instance for performing requests
-
+
Loads the playlist from Yandex Music
Id of user who created the playlist
- Target playlist id
- Track factory to create YandexMusicTrack from AudioTrackInfo
- Playlist instance
-
-
-
- Loads the album from Yandex Music
-
- Target album id
- Track factory to create YandexMusicTrack from AudioTrackInfo
+ Target playlist id
Playlist instance
-
+
Loads the album from Yandex Music
Target album id
- Track factory to create YandexMusicTrack from AudioTrackInfo
Playlist instance
@@ -349,21 +427,24 @@
Special prefix for complicated requests
-
+
Initializes a new instance of the class.
Config instance for performing requests
-
-
+
+
+ Set a new search prefix for complicated queries
+
+ New prefix. null
will be replaced with "ymsearch"
+
+
Perform search request on Yandex Music
Complicated query is ::limit:text
Search query. May be complicated or default values will be used
- Playlist loader instance
- Track factory to create YandexMusicTrack from AudioTrackInfo
Instance of YandexMusicSearchResult
@@ -377,14 +458,13 @@
Search limit
True if is this complicated query
-
+
Perform search request on Yandex Music
Search type
Search text
Playlist loader instance
- Track factory to create YandexMusicTrack from AudioTrackInfo
Search results limit count
Instance of YandexMusicSearchResult
Throws exception if something went wrong
@@ -405,258 +485,47 @@
Config instance for performing requests
-
-
- Load track
-
- Album id with track
- Target track id
- Track factory to create YandexMusicTrack from AudioTrackInfo
- Instance of
-
-
-
- Load track
-
- Target track id
- Track factory to create YandexMusicTrack from AudioTrackInfo
- Instance of
-
-
-
- Load track info
-
- Album id with track
- Target track id
- Instance of
-
-
+
Load track info
Target track id
- Instance of
+ Instance of
-
-
- Represents entity from which we can get
-
-
-
-
- Get related
-
- Track loader instance
- Instance of
-
-
-
- Represents data to resolve album
-
-
-
-
- Id of this entity
-
-
-
-
- Title of this album
-
-
-
-
- Cover link
-
-
-
-
- Opengraph image (alternative cover) url
-
-
-
-
- Count of tracks
-
-
-
-
- Is this playlist available now
-
-
-
-
- Get full playlist with tracks
-
- Instance of playlist loader to load playlist
- Track factory to create YandexMusicTrack from AudioTrackInfo
- Playlist with tracks
-
-
-
- Represent a artist in Yandex Music
-
-
-
-
- Artist ID
-
-
-
-
- Artist name
-
-
-
+
Represents error that returned from Yandex Music
-
+
Error name
-
+
Error message
-
-
- Represent playlist owner
-
-
-
-
- Owner ID
-
-
-
-
- Owner login
-
-
-
-
- Owner name
-
-
-
-
- Is owner verified
-
-
-
-
- Represents data to resolve playlist
-
-
-
-
- Playlist owner info
-
-
-
-
-
-
-
- Represent
-
-
-
-
- Track id
-
-
-
-
- List of albums that contain this track
-
-
-
-
- Creation timestamp
-
-
-
-
-
-
+
Track data from Yandex Music
-
-
- Track ID
-
-
-
-
- Track title
-
-
-
-
- Is track available
-
- If false, then most likely you are trying to get this information while not in the CIS. At the moment, you need to use a proxy in the CIS or log in with an account that has Yandex Plus (a subscription from Yandex)
-
-
-
- Track duration in ms
-
-
-
-
- Track authors list
-
-
-
-
- List of albums that contain this track
-
-
-
-
- Cover link
-
-
-
-
- Opengraph image (alternative cover) link
-
-
-
-
- Is lyrics available for this track
-
-
-
-
- Convert this meta class to
-
- Instance of
-
-
-
-
Represents a set of methods that serve for authorization in Yandex Music
-
+
Validates token
Token to validate
Container for proxy, which should be used for request
- True if token correct
+ True if token valid
-
+
Attempt to authorise
@@ -665,7 +534,7 @@
Container for proxy, which should be used for request
Token
-
+
Try to validate token or get new one using login and password
@@ -700,39 +569,40 @@
Instance of
-
+
Initializes a new instance of the class.
Yandex config instance
- Is query in can be resolved with search
Instance of
Instance of
Instance of
Instance of
-
+
- Initializes a new instance of the class.
+ Is complicated query in can be resolved
- Yandex config instance
- Instance of
- Instance of
- Instance of
- Instance of
-
+
+
+ If we pass plain text to it will be interpreted as search query with this search type. Set to false
to disable this
+
+
+
- Is query in can be resolved with search
+ Will plain text be interpreted as a search query in
-
+
Resolves yandex query. Can directly resolve playlists, albums, tracks by url and search queries
Direct url or search query
- Is query in can be resolved with search. This parameter overrides
- Instance of
+ Is query in can be resolved with search. This parameter overrides
+ Will plain text be interpreted as a search query in
+ If we pass plain text to it will be interpreted as search query with this search type
+ Instance of . Null if track will now an valid url and is false.