refactor: use replace http with dio and use it as the default

This commit is contained in:
Kingkor Roy Tirtho 2024-06-01 12:31:20 +06:00
parent d2683c52d8
commit b2d9e64758
7 changed files with 148 additions and 149 deletions

View File

@ -1,12 +1,11 @@
import 'dart:convert';
import 'package:catcher_2/catcher_2.dart';
import 'package:dio/dio.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:http/http.dart';
import 'package:spotube/models/skip_segment.dart';
import 'package:spotube/provider/server/active_sourced_track.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
import 'package:spotube/services/dio/dio.dart';
class SourcedSegments {
final String source;
@ -30,7 +29,8 @@ Future<List<SkipSegment>> getAndCacheSkipSegments(String id) async {
);
}
final res = await get(Uri(
final res = await globalDio.getUri(
Uri(
scheme: "https",
host: "sponsor.ajay.app",
path: "/api/skipSegments",
@ -46,13 +46,18 @@ Future<List<SkipSegment>> getAndCacheSkipSegments(String id) async {
],
"actionType": 'skip'
},
));
),
options: Options(
responseType: ResponseType.json,
validateStatus: (status) => (status ?? 0) < 500,
),
);
if (res.body == "Not Found") {
if (res.data == "Not Found") {
return List.castFrom<dynamic, SkipSegment>([]);
}
final data = jsonDecode(res.body) as List;
final data = res.data as List;
final segments = data.map((obj) {
final start = obj["segment"].first.toInt();
final end = obj["segment"].last.toInt();

View File

@ -9,29 +9,34 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
Track get _track => arg!;
Future<SubtitleSimple> getSpotifyLyrics(String? token) async {
final res = await http.get(
final res = await globalDio.getUri(
Uri.parse(
"https://spclient.wg.spotify.com/color-lyrics/v2/track/${_track.id}?format=json&market=from_token",
),
options: Options(
headers: {
"User-Agent":
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.0.0 Safari/537.36",
"App-platform": "WebPlayer",
"authorization": "Bearer $token"
});
},
responseType: ResponseType.json,
validateStatus: (status) => true,
),
);
if (res.statusCode != 200) {
return SubtitleSimple(
lyrics: [],
name: _track.name!,
uri: res.request!.url,
uri: res.realUri,
rating: 0,
provider: "Spotify",
);
}
final linesRaw = Map.castFrom<dynamic, dynamic, String, dynamic>(
jsonDecode(utf8.decode(res.bodyBytes)),
)["lyrics"]?["lines"] as List?;
final linesRaw =
Map.castFrom<dynamic, dynamic, String, dynamic>(res.data)["lyrics"]
?["lines"] as List?;
final lines = linesRaw?.map((line) {
return LyricSlice(
@ -44,7 +49,7 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
return SubtitleSimple(
lyrics: lines,
name: _track.name!,
uri: res.request!.url,
uri: res.realUri,
rating: 100,
provider: "Spotify",
);
@ -55,7 +60,7 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
Future<SubtitleSimple> getLRCLibLyrics() async {
final packageInfo = await PackageInfo.fromPlatform();
final res = await http.get(
final res = await globalDio.getUri(
Uri(
scheme: "https",
host: "lrclib.net",
@ -67,23 +72,26 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
"duration": _track.duration?.inSeconds.toString(),
},
),
options: Options(
headers: {
"User-Agent":
"Spotube v${packageInfo.version} (https://github.com/KRTirtho/spotube)"
},
responseType: ResponseType.json,
),
);
if (res.statusCode != 200) {
return SubtitleSimple(
lyrics: [],
name: _track.name!,
uri: res.request!.url,
uri: res.realUri,
rating: 0,
provider: "LRCLib",
);
}
final json = jsonDecode(utf8.decode(res.bodyBytes)) as Map<String, dynamic>;
final json = res.data as Map<String, dynamic>;
final syncedLyricsRaw = json["syncedLyrics"] as String?;
final syncedLyrics = syncedLyricsRaw?.isNotEmpty == true
@ -97,7 +105,7 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
return SubtitleSimple(
lyrics: syncedLyrics!,
name: _track.name!,
uri: res.request!.url,
uri: res.realUri,
rating: 100,
provider: "LRCLib",
);
@ -111,7 +119,7 @@ class SyncedLyricsNotifier extends FamilyAsyncNotifier<SubtitleSimple, Track?>
return SubtitleSimple(
lyrics: plainLyrics,
name: _track.name!,
uri: res.request!.url,
uri: res.realUri,
rating: 0,
provider: "LRCLib",
);

View File

@ -1,10 +1,10 @@
library spotify;
import 'dart:async';
import 'dart:convert';
import 'package:catcher_2/catcher_2.dart';
import 'package:collection/collection.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:intl/intl.dart';
@ -23,9 +23,9 @@ import 'package:spotube/models/spotify_friends.dart';
import 'package:spotube/provider/custom_spotify_endpoint_provider.dart';
import 'package:spotube/provider/spotify_provider.dart';
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
import 'package:spotube/services/dio/dio.dart';
import 'package:spotube/services/wikipedia/wikipedia.dart';
import 'package:spotube/utils/persisted_state_notifier.dart';
import 'package:http/http.dart' as http;
import 'package:wikipedia_api/wikipedia_api.dart';

View File

@ -1,6 +1,6 @@
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:dio/dio.dart';
import 'package:spotify/spotify.dart';
import 'package:spotube/models/spotify/home_feed.dart';
import 'package:spotube/models/spotify_friends.dart';
@ -9,9 +9,21 @@ import 'package:timezone/timezone.dart' as tz;
class CustomSpotifyEndpoints {
static const _baseUrl = 'https://api.spotify.com/v1';
final String accessToken;
final http.Client _client;
final Dio _client;
CustomSpotifyEndpoints(this.accessToken) : _client = http.Client();
CustomSpotifyEndpoints(this.accessToken)
: _client = Dio(
BaseOptions(
baseUrl: _baseUrl,
responseType: ResponseType.json,
headers: {
"content-type": "application/json",
if (accessToken.isNotEmpty)
"authorization": "Bearer $accessToken",
"accept": "application/json",
},
),
);
// views API
@ -65,44 +77,34 @@ class CustomSpotifyEndpoints {
if (country != null) 'country': country.name,
}.entries.map((e) => '${e.key}=${e.value}').join('&');
final res = await _client.get(
final res = await _client.getUri(
Uri.parse('$_baseUrl/views/$view?$queryParams'),
headers: {
"content-type": "application/json",
"authorization": "Bearer $accessToken",
"accept": "application/json",
},
);
if (res.statusCode == 200) {
return jsonDecode(utf8.decode(res.bodyBytes));
return res.data;
} else {
throw Exception(
'[CustomSpotifyEndpoints.getView]: Failed to get view'
'\nStatus code: ${res.statusCode}'
'\nBody: ${res.body}',
'\nBody: ${res.data}',
);
}
}
Future<List<String>> listGenreSeeds() async {
final res = await _client.get(
final res = await _client.getUri(
Uri.parse("$_baseUrl/recommendations/available-genre-seeds"),
headers: {
"content-type": "application/json",
if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken",
"accept": "application/json",
},
);
if (res.statusCode == 200) {
final body = jsonDecode(utf8.decode(res.bodyBytes));
final body = res.data;
return List<String>.from(body["genres"] ?? []);
} else {
throw Exception(
'[CustomSpotifyEndpoints.listGenreSeeds]: Failed to get genre seeds'
'\nStatus code: ${res.statusCode}'
'\nBody: ${res.body}',
'\nBody: ${res.data}',
);
}
}
@ -152,30 +154,18 @@ class CustomSpotifyEndpoints {
}
final pathQuery =
"$_baseUrl/recommendations?${parameters.entries.map((e) => '${e.key}=${e.value}').join('&')}";
final res = await _client.get(
Uri.parse(pathQuery),
headers: {
"content-type": "application/json",
if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken",
"accept": "application/json",
},
);
final result = jsonDecode(utf8.decode(res.bodyBytes));
final res = await _client.getUri(Uri.parse(pathQuery));
final result = res.data;
return List.castFrom<dynamic, Track>(
result["tracks"].map((track) => Track.fromJson(track)).toList(),
);
}
Future<SpotifyFriends> getFriendActivity() async {
final res = await _client.get(
final res = await _client.getUri(
Uri.parse("https://guc-spclient.spotify.com/presence-view/v1/buddylist"),
headers: {
"content-type": "application/json",
"authorization": "Bearer $accessToken",
"accept": "application/json",
},
);
return SpotifyFriends.fromJson(jsonDecode(utf8.decode(res.bodyBytes)));
return SpotifyFriends.fromJson(res.data);
}
Future<SpotifyHomeFeed> getHomeFeed({
@ -190,7 +180,7 @@ class CustomSpotifyEndpoints {
'origin': 'https://open.spotify.com',
'referer': 'https://open.spotify.com/'
};
final response = await http.get(
final response = await _client.getUri(
Uri(
scheme: "https",
host: "api-partner.spotify.com",
@ -219,21 +209,10 @@ class CustomSpotifyEndpoints {
),
},
),
headers: headers,
);
if (response.statusCode >= 400) {
throw Exception(
"[RequestException] "
"Status: ${response.statusCode}\n"
"Body: ${response.body}",
);
}
options: Options(headers: headers));
final data = SpotifyHomeFeed.fromJson(
transformHomeFeedJsonMap(
jsonDecode(utf8.decode(response.bodyBytes)),
),
transformHomeFeedJsonMap(response.data),
);
return data;
@ -252,7 +231,7 @@ class CustomSpotifyEndpoints {
'origin': 'https://open.spotify.com',
'referer': 'https://open.spotify.com/'
};
final response = await http.get(
final response = await _client.getUri(
Uri(
scheme: "https",
host: "api-partner.spotify.com",
@ -280,21 +259,12 @@ class CustomSpotifyEndpoints {
),
},
),
headers: headers,
options: Options(headers: headers),
);
if (response.statusCode >= 400) {
throw Exception(
"[RequestException] "
"Status: ${response.statusCode}\n"
"Body: ${response.body}",
);
}
final data = SpotifyHomeFeedSection.fromJson(
transformSectionItemJsonMap(
jsonDecode(utf8.decode(response.bodyBytes))["data"]["homeSections"]
["sections"][0],
response.data["data"]["homeSections"]["sections"][0],
),
);

View File

@ -0,0 +1,3 @@
import 'package:dio/dio.dart';
final globalDio = Dio();

View File

@ -1,13 +1,12 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:go_router/go_router.dart';
import 'package:html/dom.dart' hide Text;
import 'package:spotify/spotify.dart';
import 'package:spotube/components/library/user_local_tracks.dart';
import 'package:spotube/components/root/update_dialog.dart';
import 'package:spotube/models/logger.dart';
import 'package:http/http.dart' as http;
import 'package:spotube/models/lyrics.dart';
import 'package:spotube/services/dio/dio.dart';
import 'package:spotube/services/sourced_track/sourced_track.dart';
import 'package:spotube/utils/primitive_utils.dart';
@ -70,9 +69,12 @@ abstract class ServiceUtils {
}
static Future<String?> extractLyrics(Uri url) async {
final response = await http.get(url);
final response = await globalDio.getUri(
url,
options: Options(responseType: ResponseType.plain),
);
Document document = parser.parse(response.body);
Document document = parser.parse(response.data);
String? lyrics = document.querySelector('div.lyrics')?.text.trim();
if (lyrics == null) {
lyrics = "";
@ -111,11 +113,14 @@ abstract class ServiceUtils {
String reqUrl = "$searchUrl${Uri.encodeComponent(song)}";
Map<String, String> headers = {"Authorization": 'Bearer $apiKey'};
final response = await http.get(
final response = await globalDio.getUri(
Uri.parse(authHeader ? reqUrl : "$reqUrl&access_token=$apiKey"),
options: Options(
headers: authHeader ? headers : null,
responseType: ResponseType.json,
),
);
Map data = jsonDecode(utf8.decode(response.bodyBytes))["response"];
Map data = response.data["response"];
if (data["hits"]?.length == 0) return null;
List results = data["hits"]?.map((val) {
return <String, dynamic>{
@ -195,8 +200,11 @@ abstract class ServiceUtils {
queryParameters: {"q": query},
);
final res = await http.get(searchUri);
final document = parser.parse(res.body);
final res = await globalDio.getUri(
searchUri,
options: Options(responseType: ResponseType.plain),
);
final document = parser.parse(res.data);
final results =
document.querySelectorAll("#tablecontainer table tbody tr td a");
@ -229,7 +237,11 @@ abstract class ServiceUtils {
logger.v("[Selected subtitle] ${topResult.text} | $subtitleUri");
final lrcDocument = parser.parse((await http.get(subtitleUri)).body);
final lrcDocument = parser.parse((await globalDio.getUri(
subtitleUri,
options: Options(responseType: ResponseType.plain),
))
.data);
final lrcList = lrcDocument
.querySelector("#ctl00_ContentPlaceHolder1_lbllyrics")
?.innerHtml
@ -384,14 +396,16 @@ abstract class ServiceUtils {
final packageInfo = await PackageInfo.fromPlatform();
if (Env.releaseChannel == ReleaseChannel.nightly) {
final value = await http.get(
final value = await globalDio.getUri(
Uri.parse(
"https://api.github.com/repos/KRTirtho/spotube/actions/workflows/spotube-release-binary.yml/runs?status=success&per_page=1",
),
options: Options(
responseType: ResponseType.json,
),
);
final buildNum =
jsonDecode(value.body)["workflow_runs"][0]["run_number"] as int;
final buildNum = value.data["workflow_runs"][0]["run_number"] as int;
if (buildNum <= int.parse(packageInfo.buildNumber) || !context.mounted) {
return;
@ -406,13 +420,12 @@ abstract class ServiceUtils {
},
);
} else {
final value = await http.get(
final value = await globalDio.getUri(
Uri.parse(
"https://api.github.com/repos/KRTirtho/spotube/releases/latest",
),
);
final tagName =
(jsonDecode(value.body)["tag_name"] as String).replaceAll("v", "");
final tagName = (value.data["tag_name"] as String).replaceAll("v", "");
final currentVersion = packageInfo.version == "Unknown"
? null
: Version.parse(packageInfo.version);

View File

@ -55,7 +55,6 @@ dependencies:
hive_flutter: ^1.1.0
hooks_riverpod: ^2.5.1
html: ^0.15.1
http: ^1.2.0
image_picker: ^1.1.0
intl: ^0.18.0
introduction_screen: ^3.1.14
@ -131,6 +130,7 @@ dependencies:
crypto: ^3.0.3
local_notifier: ^0.1.6
tray_manager: ^0.2.2
http: ^1.2.1
dev_dependencies:
build_runner: ^2.4.9