freezer/lib/api/download_manager/download_service.dart

111 lines
3.5 KiB
Dart

import 'dart:io';
import 'package:dio/dio.dart';
import 'package:freezer/api/deezer.dart';
import 'package:freezer/api/deezer_audio.dart';
import 'package:freezer/api/download.dart';
import 'package:freezer/api/download_manager/service_interface.dart';
import 'package:freezer/main.dart';
import 'package:freezer/settings.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:path/path.dart';
part 'download_service.freezed.dart';
part 'download_service.g.dart';
class DownloadService {
static const NOTIFICATION_ID = 6969;
static const NOTIFICATION_CHANNEL_ID = "freezerdownloads";
final ServiceInterface service;
DownloadService(this.service);
AudioQuality? _preferredQuality;
AudioQuality? _downloadQuality;
bool useGetURL = false;
late String downloadFilename;
late DeezerAPI _deezerAPI;
void run() async {
service.on('addDownloads', (event) {
downloadTrack(DownloadInfo.fromJson(event!));
});
service.on('updateQuality', (event) {
_preferredQuality = AudioQuality.values[event!['q']!];
});
service.on('updateCapabilities', (event) {
final bool canStreamHQ = event!['canStreamHQ'];
final bool canStreamLossless = event['canStreamLossless'];
if (canStreamHQ || canStreamLossless) useGetURL = true;
_downloadQuality = settings.maxQualityFor(
_preferredQuality!, canStreamHQ, canStreamLossless);
});
service.on('updateSettings', (event) {
if (event!['downloadFilename'] != null) {
downloadFilename = event['downloadFilename'];
}
if (event['deezerLanguage'] != null) {
_deezerAPI.deezerLanguage = event['deezerLanguage'];
}
if (event['deezerCountry'] != null) {
_deezerAPI.deezerCountry = event['deezerCountry'];
}
});
_deezerAPI = DeezerAPI(await getCookieJar());
await _deezerAPI.authorize();
service.send('ready');
}
void downloadTrack(DownloadInfo info) async {
final trackId = info.trackId;
final deezerAudio = DeezerAudio(
deezerAPI: _deezerAPI,
quality: _downloadQuality ?? AudioQuality.MP3_128,
trackId: trackId);
final track = await _deezerAPI.track(trackId);
final file = File(join(
info.path!,
downloadFilename
.replaceAll('%artist%', track.artists?.join(',') ?? '')
.replaceAll('%title%', track.title!)));
print('downloading to ${file.path}');
final Uri uri;
if (useGetURL) {
// TODO: use pipe API to get track token!
final res = await deezerAudio.getUrl(
track.trackToken!, track.trackTokenExpiration!);
uri = res!.$1;
} else {
final res = await deezerAudio.fallback(
md5origin: track.playbackDetails![0],
mediaVersion: track.playbackDetails![1]);
uri = res.uri;
}
// download url and decrypt
final req = await _deezerAPI.dio.get(uri.toString(),
options: Options(responseType: ResponseType.bytes));
final stream =
DeezerAudio.decryptionStream(req.data, start: 0, trackId: trackId);
final fWrite = file.openWrite();
await stream.pipe(fWrite);
print('download complete!');
}
}
@freezed
class DownloadInfo with _$DownloadInfo {
const factory DownloadInfo({required String trackId, String? path}) =
_DownloadInfo;
factory DownloadInfo.fromJson(Map<String, dynamic> json) =>
_$DownloadInfoFromJson(json);
}