🐛 Fix & optimize kugou audio source

🐛 Fix fallback source switch causing error
This commit is contained in:
LittleSheep 2024-09-08 01:20:46 +08:00
parent b099f63f61
commit 59783c48f7
8 changed files with 74 additions and 9 deletions

View File

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'package:dio/dio.dart' hide Response; import 'package:dio/dio.dart' hide Response;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -41,8 +42,17 @@ class ServerPlaybackRoutesProvider {
// Special processing for kugou to get real assets url // Special processing for kugou to get real assets url
final resp = await GetConnect(timeout: const Duration(seconds: 30)) final resp = await GetConnect(timeout: const Duration(seconds: 30))
.get(sourcedTrack.url); .get(sourcedTrack.url);
final realUrl = final urls = jsonDecode(resp.body)['url'];
KugouSourcedTrack.unescapeUrl(jsonDecode(resp.body)['url'][0]); if (urls?.isEmpty ?? true) {
Get.find<ErrorNotifier>().showError(
'[PlaybackServer] Unable get audio source via Kugou, probably cause by paid needed resources.',
);
return Response(
HttpStatus.notFound,
body: 'Unable get audio source via Kugou',
);
}
final realUrl = KugouSourcedTrack.unescapeUrl(urls.first);
url = realUrl; url = realUrl;
} }

View File

@ -81,6 +81,16 @@ abstract class SourcedTrack extends Track {
}; };
} }
static Type getTrackBySourceInfo(SourceInfo info) {
final sourceInfoTrackMap = {
YoutubeSourceInfo: YoutubeSourcedTrack,
PipedSourceInfo: PipedSourcedTrack,
NeteaseSourceInfo: NeteaseSourcedTrack,
KugouSourceInfo: KugouSourcedTrack,
};
return sourceInfoTrackMap[info.runtimeType]!;
}
static String getSearchTerm(Track track) { static String getSearchTerm(Track track) {
final artists = (track.artists ?? []) final artists = (track.artists ?? [])
.map((ar) => ar.name) .map((ar) => ar.name)

View File

@ -109,7 +109,9 @@ class KugouSourcedTrack extends SourcedTrack {
final hash = manifest is SourceMatchTableData final hash = manifest is SourceMatchTableData
? manifest.sourceId ? manifest.sourceId
: manifest?['hash']; : manifest is KugouSourceInfo
? manifest.id
: manifest?['hash'];
final key = md5.convert(utf8.encode('${hash}kgcloudv2')).toString(); final key = md5.convert(utf8.encode('${hash}kgcloudv2')).toString();
final url = final url =
'$baseUrl/song/url?key=$key&hash=$hash&appid=1005&pid=2&cmd=25&behavior=play'; '$baseUrl/song/url?key=$key&hash=$hash&appid=1005&pid=2&cmd=25&behavior=play';
@ -142,7 +144,8 @@ class KugouSourcedTrack extends SourcedTrack {
// We can just trust kugou music for now // We can just trust kugou music for now
// If we need to check is the result correct, refer to this code // If we need to check is the result correct, refer to this code
// https://github.com/KRTirtho/spotube/blob/9b024120601c0d381edeab4460cb22f87149d0f8/lib/services/sourced_track/sources/jiosaavn.dart#L129 // https://github.com/KRTirtho/spotube/blob/9b024120601c0d381edeab4460cb22f87149d0f8/lib/services/sourced_track/sources/jiosaavn.dart#L129
final matchedResults = results.map(toSiblingType).toList(); final matchedResults =
results.where((x) => x['pay_type'] == 0).map(toSiblingType).toList();
return matchedResults.cast<SiblingType>(); return matchedResults.cast<SiblingType>();
} }
@ -166,7 +169,12 @@ class KugouSourcedTrack extends SourcedTrack {
} }
@override @override
Future<KugouSourcedTrack?> swapWithSibling(SourceInfo sibling) async { Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async {
if (sibling is! KugouSourceInfo) {
return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack)
.swapWithSibling(sibling);
}
if (sibling.id == sourceInfo.id) { if (sibling.id == sourceInfo.id) {
return null; return null;
} }
@ -181,7 +189,7 @@ class KugouSourcedTrack extends SourcedTrack {
..insert(0, sourceInfo); ..insert(0, sourceInfo);
final info = newSourceInfo as KugouSourceInfo; final info = newSourceInfo as KugouSourceInfo;
final source = toSourceMap(newSourceInfo.id); final source = toSourceMap(newSourceInfo);
final db = Get.find<DatabaseProvider>(); final db = Get.find<DatabaseProvider>();
await db.database.into(db.database.sourceMatchTable).insert( await db.database.into(db.database.sourceMatchTable).insert(

View File

@ -200,7 +200,12 @@ class NeteaseSourcedTrack extends SourcedTrack {
} }
@override @override
Future<NeteaseSourcedTrack?> swapWithSibling(SourceInfo sibling) async { Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async {
if (sibling is! NeteaseSourceInfo) {
return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack)
.swapWithSibling(sibling);
}
if (sibling.id == sourceInfo.id) { if (sibling.id == sourceInfo.id) {
return null; return null;
} }

View File

@ -255,6 +255,11 @@ class PipedSourcedTrack extends SourcedTrack {
@override @override
Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async { Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async {
if (sibling is! PipedSourceInfo) {
return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack)
.swapWithSibling(sibling);
}
if (sibling.id == sourceInfo.id) { if (sibling.id == sourceInfo.id) {
return null; return null;
} }

View File

@ -269,7 +269,12 @@ class YoutubeSourcedTrack extends SourcedTrack {
} }
@override @override
Future<YoutubeSourcedTrack?> swapWithSibling(SourceInfo sibling) async { Future<SourcedTrack?> swapWithSibling(SourceInfo sibling) async {
if (sibling is! YoutubeSourceInfo) {
return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack)
.swapWithSibling(sibling);
}
if (sibling.id == sourceInfo.id) { if (sibling.id == sourceInfo.id) {
return null; return null;
} }

View File

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -124,6 +125,27 @@ class _SiblingTracksState extends State<SiblingTracks> {
.map(NeteaseSourcedTrack.toSourceInfo) .map(NeteaseSourcedTrack.toSourceInfo)
.toList(); .toList();
final activeSourceInfo = (_activeTrack! as SourcedTrack).sourceInfo;
_siblings = List.from(
searchResults
..removeWhere((element) => element.id == activeSourceInfo.id)
..insert(
0,
activeSourceInfo,
),
growable: true,
);
} else if (preferences.audioSource == AudioSource.kugou) {
final client = KugouSourcedTrack.getClient();
final resp = await client.get(
'/api/v3/search/song?keyword=${Uri.encodeComponent(searchTerm)}&page=1&pagesize=10',
);
final results = jsonDecode(resp.body)['data']['info'];
final searchResults = results
.where((x) => x['pay_type'] == 0)
.map(KugouSourcedTrack.toSourceInfo)
.toList();
final activeSourceInfo = (_activeTrack! as SourcedTrack).sourceInfo; final activeSourceInfo = (_activeTrack! as SourcedTrack).sourceInfo;
_siblings = List.from( _siblings = List.from(
searchResults searchResults

View File

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts # In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+14 version: 1.0.0+15
environment: environment:
sdk: ^3.5.0 sdk: ^3.5.0