Skip to content

Commit

Permalink
Merge pull request #7 from SKProCH/diSupport
Browse files Browse the repository at this point in the history
Add dependency injection support
  • Loading branch information
SKProCH authored Aug 23, 2024
2 parents 18e3ebe + a58fc48 commit 98c0537
Show file tree
Hide file tree
Showing 20 changed files with 188 additions and 81 deletions.
66 changes: 40 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,47 @@ Can work without authorization.
```
dotnet add package YandexMusicResolver
```
2. Create auth service instance (`YandexMusicAuthService` this is the default implementation):
```c#
var authService = new YandexMusicAuthService(httpClient);
```
Actually, **preferred way is to use `IHttpClientFactory`** to pass it to all services.
If you use `IHttpClientFactory` default HttpClient name is `YandexMusic`.
3. Create credentials provider instance (`YandexCredentialsProvider` this is the default implementation):
```c#
var credentialProvider = new YandexMusicAuthService(authService, "Login", "Pass");
```
2. You need somehow to instantiate `YandexMusicMainResolver`.
- If you are using dependency injection, use `.AddYandexMusicResolver()` to your `IServiceCollection`. E.g.:
```csharp
var serviceCollection = new ServiceCollection();
serviceCollection.AddYandexMusicResolver();
4. Create an instance of `YandexMusicMainResolver` and pass config to it
```c#
var yandexMusicMainResolver = new YandexMusicMainResolver(credentialProvider, httpClient);
```
After that we can use `YandexMusicMainResolver` methods and other loaders methods.
var serviceProvider = serviceCollection.BuildServiceProvider();
// Resolve the IYandexMusicMainResolver
var yandexMusicMainResolver = serviceProvider.GetRequiredService<IYandexMusicMainResolver>();
```
- Or instantiate it as usually:
1. Create auth service instance (`YandexMusicAuthService` this is the default implementation):
```csharp#
var authService = new YandexMusicAuthService(httpClient);
```
Actually, **preferred way is to use `IHttpClientFactory`** to pass it to all services.
If you use `IHttpClientFactory` default HttpClient name is `YandexMusic`.
2. Create credentials provider instance (`YandexCredentialsProvider` this is the default implementation):
```csharp#
var credentialProvider = new YandexMusicAuthService(authService, "Login", "Pass");
```
Example code for getting direct track download url:
```c#
var httpClient = new HttpClient();
var authService = new YandexMusicAuthService(httpClient);
var credentialProvider = new YandexMusicAuthService(authService, "Login", "Pass");
var yandexMusicMainResolver = new YandexMusicMainResolver(credentialProvider, httpClient);
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).
3. Create an instance of `YandexMusicMainResolver` and pass config to it
```csharp
var yandexMusicMainResolver = new YandexMusicMainResolver(credentialProvider, httpClient);
```
Full example:
```csharp
var httpClient = new HttpClient();
var authService = new YandexMusicAuthService.Create(httpClient);
var credentialProvider = new YandexMusicAuthService.Create(authService, "Login", "Pass");
var yandexMusicMainResolver = new YandexMusicMainResolver.Create(credentialProvider, httpClient);
```
3. After that you can use different methods and properties of `IYandexMusicMainResolver`.
Example code for getting direct track download url:
```c#
var directUrl = await yandexMusicMainResolver.DirectUrlLoader.GetDirectUrl("55561798");
Console.WriteLine(directUrl);
```
> [!IMPORTANT]
> 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).
You can take a look at unit test project for additional examples.
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
using Xunit;

namespace YandexMusicResolver.Tests {
public class YandexMusicAuthServiceTest : YandexTestBase {
public class AuthServiceTest : YandexTestBase {
[Fact]
public async System.Threading.Tasks.Task AuthFailure() {
await Assert.ThrowsAsync<InvalidCredentialException>(async () => {
await new YandexMusicAuthService(new HttpClient()).LoginAsync("Invalid", "Invalid");
await YandexMusicAuthService.Create(new HttpClient()).LoginAsync("Invalid", "Invalid");
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
using Xunit.Abstractions;

namespace YandexMusicResolver.Tests {
public class YandexMusicDirectUrlLoaderTest : YandexTestBase{
public class DirectUrlLoaderTest : YandexTestBase{
private readonly ITestOutputHelper _output;
public YandexMusicDirectUrlLoaderTest(ITestOutputHelper output) {
public DirectUrlLoaderTest(ITestOutputHelper output) {
_output = output;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using YandexMusicResolver.AudioItems;

namespace YandexMusicResolver.Tests {
public class YandexMusicMainResolverTest : YandexTestBase{
public class MainResolverTest : YandexTestBase{
[Theory]
[InlineData("https://music.yandex.ru/album/9425747/track/55561798")]
public void GetTrack(string url) {
Expand Down Expand Up @@ -47,7 +47,8 @@ public void GetPlaylist(string url) {
[InlineData("Take over")]
[InlineData("ymsearch:Track:10:Take over")]
public void TestDisabledSearch(string query) {
var yandexMusicMainResolver = new YandexMusicMainResolver(YandexCredentialsProviderMock.Object, new HttpClient()) {AllowSearch = false};
var yandexMusicMainResolver = YandexMusicMainResolver.Create(YandexCredentialsProviderMock.Object, new HttpClient());
yandexMusicMainResolver.AllowSearch = false;
var audioItem = yandexMusicMainResolver.ResolveQuery(query).GetAwaiter().GetResult();
Assert.Null(audioItem);
}
Expand All @@ -56,7 +57,8 @@ public void TestDisabledSearch(string query) {
[InlineData("Take over", true)]
[InlineData("ymsearch:Track:10:Take over", false)]
public void TestDisabledPlainTextSearch(string query, bool isPlainText) {
var yandexMusicMainResolver = new YandexMusicMainResolver(YandexCredentialsProviderMock.Object, new HttpClient()) {PlainTextIsSearchQuery = false};
var yandexMusicMainResolver = YandexMusicMainResolver.Create(YandexCredentialsProviderMock.Object, new HttpClient());
yandexMusicMainResolver.PlainTextIsSearchQuery = false;
var audioItem = yandexMusicMainResolver.ResolveQuery(query).GetAwaiter().GetResult();
Assert.Equal(isPlainText, audioItem == null);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Xunit;

namespace YandexMusicResolver.Tests {
public class YandexMusicPlaylistLoaderTest : YandexTestBase {
public class PlaylistLoaderTest : YandexTestBase {
[Theory]
[InlineData("9425747", "Renovatio", 12)]
[InlineData("12033669", "Take Over", 1)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using YandexMusicResolver.Loaders;

namespace YandexMusicResolver.Tests {
public class YandexMusicSearchResultLoaderTest : YandexTestBase {
public class SearchResultLoaderTest : YandexTestBase {
[Fact]
public void DoTrackSearch() {
var trackSearchResult = MainResolver.SearchResultLoader.LoadSearchResult(YandexSearchType.Track, "Take Over").GetAwaiter().GetResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using YandexMusicResolver.Loaders;

namespace YandexMusicResolver.Tests {
public class YandexMusicTrackLoaderTest : YandexTestBase {
public class TrackLoaderTest : YandexTestBase {
[Theory]
[InlineData(9425747, 55561798)]
[InlineData(12033669, 70937156)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Moq.AutoMock;
using Moq.Contrib.HttpClient;
using Xunit;
using YandexMusicResolver.Config;

namespace YandexMusicResolver.Tests {
public class YandexMusicUtilitiesTests {
public class UtilitiesTests {
[Fact]
public async Task PerformYMusicRequestAsync_ShouldCallTokenVerifyIfUnauthorized() {
var autoMocker = new AutoMocker();
Expand All @@ -31,5 +32,16 @@ public async Task PerformYMusicRequestAsync_ShouldCallTokenVerifyIfUnauthorized(

httpClientMock.VerifyAnyRequest(Times.Exactly(2));
}

[Fact]
public void ShouldPropertyRegisterAllServices()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddYandexMusicResolver();

var serviceProvider = serviceCollection.BuildServiceProvider();

var yandexMusicMainResolver = serviceProvider.GetRequiredService<IYandexMusicMainResolver>();
}
}
}
2 changes: 1 addition & 1 deletion YandexMusicResolver.Tests/YandexTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class YandexTestBase {

public YandexTestBase() {
YandexCredentialsProviderMock = AutoMocker.GetMock<IYandexCredentialsProvider>();
MainResolver = new YandexMusicMainResolver(YandexCredentialsProviderMock.Object, new HttpClient());
MainResolver = YandexMusicMainResolver.Create(YandexCredentialsProviderMock.Object, new HttpClient());
}
}
}
2 changes: 1 addition & 1 deletion YandexMusicResolver/ApiResponceError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ public YandexApiResponseException(string message, MetaError apiMetaError) : base
ApiMetaError = apiMetaError;
}
}
}
}
2 changes: 1 addition & 1 deletion YandexMusicResolver/AudioItems/YandexMusicDataContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ public Task<T> LoadDataAsync() {
/// </summary>
public T Data => LoadDataAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
}
}
40 changes: 34 additions & 6 deletions YandexMusicResolver/Config/YandexCredentialsProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Security.Authentication;
using System.Threading.Tasks;
using Microsoft.Extensions.Options;

namespace YandexMusicResolver.Config;

Expand All @@ -18,34 +19,61 @@ public class YandexCredentialsProvider : IYandexCredentialsProvider {
/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/> with login, password, token and <see cref="IYandexMusicAuthService"/>
/// </summary>
public YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, string login, string password, string? token = null) {
private YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, string login, string password, string? token = null) {
_yandexMusicAuthService = yandexMusicAuthService;
_login = login;
_password = password;
_token = token;
AllowAnonymous = false;
}


/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/> with login, password, token and <see cref="IYandexMusicAuthService"/>
/// </summary>
public static YandexCredentialsProvider Create(IYandexMusicAuthService yandexMusicAuthService, string login, string password, string? token = null) {
return new YandexCredentialsProvider(yandexMusicAuthService, login, password, token);
}

/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/>
/// </summary>
public YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, string token, bool allowAnonymous) {
private YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, string token, bool allowAnonymous) {
_yandexMusicAuthService = yandexMusicAuthService;
_token = token;
AllowAnonymous = allowAnonymous;
}

/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/> with anonymizes access
/// Initializes a new <see cref="YandexCredentialsProvider"/> using token
/// </summary>
public YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, YandexCredentials credentials) {
public static YandexCredentialsProvider Create(IYandexMusicAuthService yandexMusicAuthService, string token, bool allowAnonymous) {
return new YandexCredentialsProvider(yandexMusicAuthService, token, allowAnonymous);
}

/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/>
/// </summary>
private YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService, YandexCredentials credentials) {
_yandexMusicAuthService = yandexMusicAuthService;
_login = credentials.Login;
_password = credentials.Login;
_token = credentials.Token;
AllowAnonymous = credentials.AllowAnonymous;
}

/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/>
/// </summary>
public static YandexCredentialsProvider Create(IYandexMusicAuthService yandexMusicAuthService, YandexCredentials credentials) {
return new YandexCredentialsProvider(yandexMusicAuthService, credentials);
}

/// <summary>
/// Initializes a new <see cref="YandexCredentialsProvider"/>
/// </summary>
public YandexCredentialsProvider(IYandexMusicAuthService yandexMusicAuthService,
IOptions<YandexCredentials> credentials) : this(yandexMusicAuthService, credentials.Value) { }

/// <inheritdoc />
public async Task<string?> GetTokenAsync() {
if (_token == null) {
Expand Down
2 changes: 1 addition & 1 deletion YandexMusicResolver/IYandexMusicMainResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,4 @@ bool CanResolveQuery(string query, bool? allowSearchOverride = null,
bool? plainTextIsSearchQueryOverride = null,
YandexSearchType? plainTextAsSearchQueryTypeOverride = null);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ public interface IYandexMusicSearchResultLoader {
/// <returns>True if is this complicated query</returns>
bool TryParseQuery(string query, out string text, out YandexSearchType type, out int limit);
}
}
}
2 changes: 1 addition & 1 deletion YandexMusicResolver/Responses/MetaTrackDownloadInfoXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ public class MetaTrackDownloadInfoXml {
[XmlElement(ElementName = "s")]
public string S { get; set; } = null!;
}
}
}
10 changes: 9 additions & 1 deletion YandexMusicResolver/YandexMusicAuthService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,18 @@ public YandexMusicAuthService(IHttpClientFactory httpClientFactory) {
/// Create instance of <see cref="YandexMusicAuthService"/>
/// </summary>
/// <param name="httpClient">HttpClient for performing requests. But preferred way is use another ctor and pass <see cref="IHttpClientFactory"/></param>
public YandexMusicAuthService(HttpClient httpClient) {
private YandexMusicAuthService(HttpClient httpClient) {
_httpClient = httpClient;
}

/// <summary>
/// Create instance of <see cref="YandexMusicAuthService"/>
/// </summary>
/// <param name="httpClient">HttpClient for performing requests. But preferred way is use ctor and pass <see cref="IHttpClientFactory"/></param>
public static YandexMusicAuthService Create(HttpClient httpClient) {
return new YandexMusicAuthService(httpClient);
}

/// <inheritdoc />
public async Task<bool> ValidateTokenAsync(string token) {
var metaAccountResponse = await _httpClient.PerformYMusicRequestAsync<MetaAccountResponse>(null, StatusUrl);
Expand Down
Loading

0 comments on commit 98c0537

Please sign in to comment.