RhythmBox/lib/services/server/routes/playback.dart

98 lines
3.5 KiB
Dart
Raw Permalink Normal View History

2024-09-06 14:19:26 +00:00
import 'dart:convert';
import 'dart:io';
2024-09-06 14:19:26 +00:00
2024-08-26 17:49:05 +00:00
import 'package:dio/dio.dart' hide Response;
import 'package:flutter/foundation.dart';
import 'package:get/get.dart' hide Response;
import 'package:rhythm_box/providers/audio_player.dart';
2024-09-02 13:20:30 +00:00
import 'package:rhythm_box/providers/error_notifier.dart';
2024-08-26 17:49:05 +00:00
import 'package:rhythm_box/services/audio_player/audio_player.dart';
import 'package:rhythm_box/services/server/active_sourced_track.dart';
import 'package:rhythm_box/services/server/sourced_track.dart';
2024-09-06 14:19:26 +00:00
import 'package:rhythm_box/services/sourced_track/sources/kugou.dart';
2024-09-04 15:28:59 +00:00
import 'package:rhythm_box/services/sourced_track/sources/netease.dart';
2024-08-26 17:49:05 +00:00
import 'package:shelf/shelf.dart';
class ServerPlaybackRoutesProvider {
/// @get('/stream/<trackId>')
Future<Response> getStreamTrackId(Request request, String trackId) async {
final AudioPlayerProvider playback = Get.find();
try {
final track = playback.state.value.tracks
.firstWhere((element) => element.id == trackId);
final ActiveSourcedTrackProvider activeSourcedTrack = Get.find();
final sourcedTrack = activeSourcedTrack.state.value?.id == track.id
2024-08-30 05:23:57 +00:00
? activeSourcedTrack.state.value
2024-08-26 17:49:05 +00:00
: await Get.find<SourcedTrackProvider>().fetch(RhythmMedia(track));
2024-08-30 05:23:57 +00:00
activeSourcedTrack.updateTrack(sourcedTrack);
2024-08-26 17:49:05 +00:00
2024-09-04 15:28:59 +00:00
var url = sourcedTrack!.url;
if (sourcedTrack is NeteaseSourcedTrack) {
// Special processing for netease to get real assets url
final resp = await GetConnect(timeout: const Duration(seconds: 30)).get(
'${sourcedTrack.url}&realIP=${await NeteaseSourcedTrack.lookupRealIp()}',
);
final realUrl = resp.body['data'][0]['url'];
url = realUrl;
2024-09-06 14:19:26 +00:00
} else if (sourcedTrack is KugouSourcedTrack) {
// Special processing for kugou to get real assets url
final resp = await GetConnect(timeout: const Duration(seconds: 30))
.get(sourcedTrack.url);
final urls = jsonDecode(resp.body)['url'];
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);
2024-09-06 14:19:26 +00:00
url = realUrl;
2024-09-04 15:28:59 +00:00
}
2024-08-26 17:49:05 +00:00
final res = await Dio().get(
2024-09-04 15:28:59 +00:00
url,
2024-08-26 17:49:05 +00:00
options: Options(
headers: {
...request.headers,
2024-08-27 06:48:31 +00:00
'User-Agent':
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36',
2024-09-04 15:28:59 +00:00
'host': Uri.parse(url).host,
2024-08-27 06:48:31 +00:00
'Cache-Control': 'max-age=0',
'Connection': 'keep-alive',
2024-08-26 17:49:05 +00:00
},
responseType: ResponseType.stream,
validateStatus: (status) => status! < 500,
),
);
final audioStream =
(res.data?.stream as Stream<Uint8List>?)?.asBroadcastStream();
audioStream!.listen(
(event) {},
cancelOnError: true,
);
return Response(
res.statusCode!,
body: audioStream,
context: {
2024-08-27 06:48:31 +00:00
'shelf.io.buffer_output': false,
2024-08-26 17:49:05 +00:00
},
headers: res.headers.map,
);
2024-09-02 13:20:30 +00:00
} catch (e, stack) {
Get.find<ErrorNotifier>()
.logError('[PlaybackSever] Error: $e', trace: stack);
2024-08-26 17:49:05 +00:00
return Response.internalServerError();
}
}
}