diff --git a/lib/services/server/routes/playback.dart b/lib/services/server/routes/playback.dart index 7511053..09a2643 100755 --- a/lib/services/server/routes/playback.dart +++ b/lib/services/server/routes/playback.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:dio/dio.dart' hide Response; import 'package:flutter/foundation.dart'; @@ -41,8 +42,17 @@ class ServerPlaybackRoutesProvider { // Special processing for kugou to get real assets url final resp = await GetConnect(timeout: const Duration(seconds: 30)) .get(sourcedTrack.url); - final realUrl = - KugouSourcedTrack.unescapeUrl(jsonDecode(resp.body)['url'][0]); + final urls = jsonDecode(resp.body)['url']; + if (urls?.isEmpty ?? true) { + Get.find().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; } diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 96781ba..effb17f 100755 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -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) { final artists = (track.artists ?? []) .map((ar) => ar.name) diff --git a/lib/services/sourced_track/sources/kugou.dart b/lib/services/sourced_track/sources/kugou.dart index aa81f00..b947481 100644 --- a/lib/services/sourced_track/sources/kugou.dart +++ b/lib/services/sourced_track/sources/kugou.dart @@ -109,7 +109,9 @@ class KugouSourcedTrack extends SourcedTrack { final hash = manifest is SourceMatchTableData ? manifest.sourceId - : manifest?['hash']; + : manifest is KugouSourceInfo + ? manifest.id + : manifest?['hash']; final key = md5.convert(utf8.encode('${hash}kgcloudv2')).toString(); final url = '$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 // 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 - final matchedResults = results.map(toSiblingType).toList(); + final matchedResults = + results.where((x) => x['pay_type'] == 0).map(toSiblingType).toList(); return matchedResults.cast(); } @@ -166,7 +169,12 @@ class KugouSourcedTrack extends SourcedTrack { } @override - Future swapWithSibling(SourceInfo sibling) async { + Future swapWithSibling(SourceInfo sibling) async { + if (sibling is! KugouSourceInfo) { + return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack) + .swapWithSibling(sibling); + } + if (sibling.id == sourceInfo.id) { return null; } @@ -181,7 +189,7 @@ class KugouSourcedTrack extends SourcedTrack { ..insert(0, sourceInfo); final info = newSourceInfo as KugouSourceInfo; - final source = toSourceMap(newSourceInfo.id); + final source = toSourceMap(newSourceInfo); final db = Get.find(); await db.database.into(db.database.sourceMatchTable).insert( diff --git a/lib/services/sourced_track/sources/netease.dart b/lib/services/sourced_track/sources/netease.dart index 3d69ca2..8133430 100755 --- a/lib/services/sourced_track/sources/netease.dart +++ b/lib/services/sourced_track/sources/netease.dart @@ -200,7 +200,12 @@ class NeteaseSourcedTrack extends SourcedTrack { } @override - Future swapWithSibling(SourceInfo sibling) async { + Future swapWithSibling(SourceInfo sibling) async { + if (sibling is! NeteaseSourceInfo) { + return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack) + .swapWithSibling(sibling); + } + if (sibling.id == sourceInfo.id) { return null; } diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 58bc2aa..7e64f9d 100755 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -255,6 +255,11 @@ class PipedSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { + if (sibling is! PipedSourceInfo) { + return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack) + .swapWithSibling(sibling); + } + if (sibling.id == sourceInfo.id) { return null; } diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index a3c35dc..ed51f03 100755 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -269,7 +269,12 @@ class YoutubeSourcedTrack extends SourcedTrack { } @override - Future swapWithSibling(SourceInfo sibling) async { + Future swapWithSibling(SourceInfo sibling) async { + if (sibling is! YoutubeSourceInfo) { + return (SourcedTrack.getTrackBySourceInfo(sibling) as SourcedTrack) + .swapWithSibling(sibling); + } + if (sibling.id == sourceInfo.id) { return null; } diff --git a/lib/widgets/player/sibling_tracks.dart b/lib/widgets/player/sibling_tracks.dart index 8ce03d1..0072bbd 100644 --- a/lib/widgets/player/sibling_tracks.dart +++ b/lib/widgets/player/sibling_tracks.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; @@ -124,6 +125,27 @@ class _SiblingTracksState extends State { .map(NeteaseSourcedTrack.toSourceInfo) .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; _siblings = List.from( searchResults diff --git a/pubspec.yaml b/pubspec.yaml index 579fedb..8433d65 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 # 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. -version: 1.0.0+14 +version: 1.0.0+15 environment: sdk: ^3.5.0