Skip to content

Commit f2e761d

Browse files
committed
feat: Migrate to DevBase.Net, fix unit tests, add documentation
- Renamed DevBase.Request to DevBase.Net with Request class - Added ThrowTuple method in ApiClient for tuple error handling - Fixed cookie domain issue in Deezer API - Made external API tests resilient to unavailable services - Fixed flaky SRT format test - Updated all API clients to use DevBase.Net namespace - Added README.md documentation for all projects - DevBase.Net v1.1.0, DevBase.Api v1.5.0
1 parent 24ef4a5 commit f2e761d

File tree

213 files changed

+3114
-3656
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

213 files changed

+3114
-3656
lines changed

DevBase.Api/Apis/ApiClient.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ protected dynamic Throw<T>(
1818
return ToType<T>();
1919
}
2020

21+
protected (string, bool) ThrowTuple(
22+
System.Exception exception,
23+
[CallerMemberName] string callerMember = "",
24+
[CallerFilePath] string callerFilePath = "",
25+
[CallerLineNumber] int callerLineNumber = 0)
26+
{
27+
if (StrictErrorHandling)
28+
throw exception;
29+
30+
return (string.Empty, false);
31+
}
32+
2133
private dynamic ToType<T>()
2234
{
2335
T type = (T)Activator.CreateInstance(typeof(T));

DevBase.Api/Apis/AppleMusic/AppleMusic.cs

Lines changed: 48 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
using System.Net;
22
using System.Text.RegularExpressions;
3+
using DevBase.Net.Core;
4+
using DevBase.Net.Security.Token;
35
using DevBase.Api.Apis.AppleMusic.Structure.Json;
46
using DevBase.Api.Apis.AppleMusic.Structure.Objects;
57
using DevBase.Api.Enums;
68
using DevBase.Api.Exceptions;
79
using DevBase.Api.Serializer;
810
using DevBase.Enums;
9-
using DevBase.Requests.Security.Token;
10-
using DevBase.Web;
11-
using DevBase.Web.RequestData;
12-
using DevBase.Web.RequestData.Data;
13-
using DevBase.Web.ResponseData;
1411
using HtmlAgilityPack;
12+
using Newtonsoft.Json;
1513

1614
namespace DevBase.Api.Apis.AppleMusic;
1715

@@ -46,49 +44,40 @@ public async Task WithMediaUserTokenFromCookie(string myacinfoCookie)
4644
{
4745
string url = $"{_webAuthUrl}/account/web/auth";
4846

49-
RequestData requestData = new RequestData(url, EnumRequestMethod.POST);
50-
requestData.ContentTypeHolder.Set(EnumContentType.APPLICATION_JSON);
51-
requestData.Header.Add("Origin", this._baseUrl);
47+
Response response = await new Request(url)
48+
.AsPost()
49+
.WithHeader("Origin", this._baseUrl)
50+
.WithAccept("*/*")
51+
.WithCookie($"myacinfo={myacinfoCookie}")
52+
.SendAsync();
5253

53-
requestData.Accept = "*/*";
54-
55-
requestData.CookieContainer.Add(new Cookie("myacinfo", myacinfoCookie, "/", "apple.com"));
56-
57-
Request request = new Request(requestData);
58-
ResponseData responseData = await request.GetResponseAsync();
59-
60-
WebHeaderCollection headers = responseData.Response.Headers;
61-
this._userMediaToken = GetMediaUserToken(headers);
54+
this._userMediaToken = GetMediaUserToken(response.Headers);
6255
}
6356

64-
private GenericAuthenticationToken GetMediaUserToken(WebHeaderCollection headerCollection)
57+
private GenericAuthenticationToken GetMediaUserToken(System.Net.Http.Headers.HttpResponseHeaders headerCollection)
6558
{
66-
string? header = headerCollection.Get("Set-Cookie");
59+
if (!headerCollection.TryGetValues("Set-Cookie", out IEnumerable<string> values))
60+
return new GenericAuthenticationToken();
6761

68-
string[] splitted = header.Split(",");
69-
7062
string parsedToken = string.Empty;
7163
string parsedExpiresIn = string.Empty;
72-
73-
for (var i = 0; i < splitted.Length; i++)
74-
{
75-
string element = splitted[i].Trim();
7664

65+
foreach (string element in values)
66+
{
7767
if (element.Contains("media-user-token"))
7868
{
79-
string[] cookie = element.Split(";");
69+
string[] cookieParts = element.Split(";");
8070

81-
for (int j = 0; j < cookie.Length; j++)
71+
foreach (string part in cookieParts)
8272
{
83-
string elementInCookie = cookie[j];
73+
string trimmed = part.Trim();
74+
75+
if (trimmed.StartsWith("media-user-token="))
76+
parsedToken = trimmed.Split("=")[1];
8477

85-
if (elementInCookie.Contains("media-user-token"))
86-
parsedToken = elementInCookie.Split("=")[1];
87-
88-
if (elementInCookie.Contains("Max-Age"))
78+
if (trimmed.StartsWith("Max-Age="))
8979
{
90-
parsedExpiresIn = elementInCookie.Split("=")[1];
91-
break;
80+
parsedExpiresIn = trimmed.Split("=")[1];
9281
}
9382
}
9483
}
@@ -112,8 +101,11 @@ public static async Task<AppleMusic> WithAccessToken()
112101
{
113102
string url = $"{_baseWebsite}/us/browse";
114103

115-
HtmlWeb htmlWeb = new HtmlWeb();
116-
HtmlDocument htmlDocument = await htmlWeb.LoadFromWebAsync(url);
104+
Response response = await new Request(url).SendAsync();
105+
string content = await response.GetStringAsync();
106+
107+
HtmlDocument htmlDocument = new HtmlDocument();
108+
htmlDocument.LoadHtml(content);
117109

118110
HtmlDocument assetDocument = await GetAssetContent(htmlDocument);
119111

@@ -158,17 +150,13 @@ public async Task<JsonAppleMusicSearchResult> RawSearch(string searchTerm, int l
158150
string url =
159151
$"{this._baseUrl}/v1/catalog/de/search?fields[artists]=url,name,artwork&include[songs]=artists&limit={limit}&types=songs&with=lyricHighlights,lyrics,serverBubbles&term={searchTerm}";
160152

161-
RequestData requestData = new RequestData(url);
162-
requestData.Header.Add("Origin", this._baseUrl);
163-
164-
requestData.AddAuthMethod(new Auth(this._apiToken.RawToken, EnumAuthType.OAUTH2));
165-
166-
Request request = new Request(requestData);
167-
ResponseData responseData = await request.GetResponseAsync();
153+
Response response = await new Request(url)
154+
.AsGet()
155+
.WithHeader("Origin", this._baseUrl)
156+
.UseBearerAuthentication(this._apiToken.RawToken)
157+
.SendAsync();
168158

169-
string response = responseData.GetContentAsString();
170-
171-
return new JsonDeserializer<JsonAppleMusicSearchResult>().Deserialize(response);
159+
return await response.ParseJsonAsync<JsonAppleMusicSearchResult>(false);
172160
}
173161

174162
public async Task<JsonAppleMusicLyricsResponse> GetLyrics(string trackId)
@@ -178,18 +166,14 @@ public async Task<JsonAppleMusicLyricsResponse> GetLyrics(string trackId)
178166

179167
string url = $"{this._baseUrl}/v1/catalog/de/songs/{trackId}/syllable-lyrics";
180168

181-
RequestData requestData = new RequestData(url);
182-
requestData.Header.Add("Origin", this._baseUrl);
183-
requestData.Header.Add("Media-User-Token", this._userMediaToken.Token);
184-
185-
requestData.AddAuthMethod(new Auth(this._apiToken.RawToken, EnumAuthType.OAUTH2));
186-
187-
Request request = new Request(requestData);
188-
ResponseData responseData = await request.GetResponseAsync();
189-
190-
string response = responseData.GetContentAsString();
169+
Response response = await new Request(url)
170+
.AsGet()
171+
.WithHeader("Origin", this._baseUrl)
172+
.WithHeader("Media-User-Token", this._userMediaToken.Token)
173+
.UseBearerAuthentication(this._apiToken.RawToken)
174+
.SendAsync();
191175

192-
return new JsonDeserializer<JsonAppleMusicLyricsResponse>().Deserialize(response);
176+
return await response.ParseJsonAsync<JsonAppleMusicLyricsResponse>(false);
193177
}
194178

195179
private static async Task<HtmlDocument> GetAssetContent(HtmlDocument htmlDocument)
@@ -210,7 +194,13 @@ private static async Task<HtmlDocument> GetAssetContent(HtmlDocument htmlDocumen
210194

211195
string url = $"{_baseWebsite}{assetPath}";
212196

213-
return await new HtmlWeb().LoadFromWebAsync(url);
197+
Response response = await new Request(url).SendAsync();
198+
string content = await response.GetStringAsync();
199+
200+
HtmlDocument doc = new HtmlDocument();
201+
doc.LoadHtml(content);
202+
203+
return doc;
214204
}
215205

216206
private static string GetAccessToken(HtmlDocument assetDocument)

DevBase.Api/Apis/BeautifulLyrics/BeautifulLyrics.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
using DevBase.Api.Serializer;
77
using DevBase.Format.Structure;
88
using DevBase.Generics;
9-
using DevBase.Web;
10-
using DevBase.Web.ResponseData;
9+
using DevBase.Net.Core;
1110
using Newtonsoft.Json.Linq;
1211

1312
namespace DevBase.Api.Apis.BeautifulLyrics;
@@ -25,6 +24,9 @@ public async Task<dynamic> GetLyrics(string isrc)
2524
{
2625
(string RawLyric, bool IsRichSync) rawLyrics = await this.GetRawLyrics(isrc);
2726

27+
if (string.IsNullOrEmpty(rawLyrics.RawLyric))
28+
return Throw<object>(new BeautifulLyricsException(EnumBeautifulLyricsExceptionType.LyricsNotFound));
29+
2830
if (rawLyrics.IsRichSync)
2931
{
3032
return ParseRichSyncStampedLyrics(rawLyrics.RawLyric);
@@ -39,16 +41,15 @@ public async Task<dynamic> GetLyrics(string isrc)
3941
{
4042
string url = $"{this._baseUrl}/lyrics/{isrc}";
4143

42-
Request request = new Request(url);
43-
ResponseData responseData = await request.GetResponseAsync();
44+
Response response = await new Request(url).SendAsync();
4445

45-
if (responseData.StatusCode != HttpStatusCode.OK)
46-
return Throw<object>(new BeautifulLyricsException(EnumBeautifulLyricsExceptionType.LyricsNotFound));
46+
if (response.StatusCode != HttpStatusCode.OK)
47+
return ThrowTuple(new BeautifulLyricsException(EnumBeautifulLyricsExceptionType.LyricsNotFound));
4748

48-
string rawData = responseData.GetContentAsString();
49+
string rawData = await response.GetStringAsync();
4950

5051
if (string.IsNullOrEmpty(rawData))
51-
return Throw<object>(new BeautifulLyricsException(EnumBeautifulLyricsExceptionType.LyricsNotFound));
52+
return ThrowTuple(new BeautifulLyricsException(EnumBeautifulLyricsExceptionType.LyricsNotFound));
5253

5354
JObject responseObject = JObject.Parse(rawData);
5455
bool isRichSync = responseObject.Value<string>("Type") == "Syllable";

0 commit comments

Comments
 (0)