forked from piaocbn2j/MTMusic
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
201 lines
5.5 KiB
201 lines
5.5 KiB
2 weeks ago
|
import 'dart:convert';
|
||
|
import 'dart:io';
|
||
|
|
||
|
import 'package:get/get.dart';
|
||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||
|
import '../api/api_download.dart';
|
||
|
import '../common_widget/Song_widegt.dart';
|
||
|
import 'package:path/path.dart' as path;
|
||
|
|
||
|
class DownloadItem {
|
||
|
final Song song;
|
||
|
double progress;
|
||
|
bool isCompleted;
|
||
|
bool isDownloading;
|
||
|
|
||
|
DownloadItem({
|
||
|
required this.song,
|
||
|
this.progress = 0.0,
|
||
|
this.isCompleted = false,
|
||
|
this.isDownloading = false,
|
||
|
});
|
||
|
|
||
|
Map<String, dynamic> toJson() {
|
||
|
return {
|
||
|
'song': {
|
||
|
'pic': song.pic,
|
||
|
'artistPic': song.artistPic,
|
||
|
'title': song.title,
|
||
|
'artist': song.artist,
|
||
|
'musicurl': song.musicurl,
|
||
|
'id': song.id,
|
||
|
'likes': song.likes,
|
||
|
'collection': song.collection
|
||
|
},
|
||
|
'progress': progress,
|
||
|
'isCompleted': isCompleted,
|
||
|
'isDownloading': isDownloading,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// 从JSON创建DownloadItem
|
||
|
factory DownloadItem.fromJson(Map<String, dynamic> json) {
|
||
|
return DownloadItem(
|
||
|
song: Song(
|
||
|
pic: json['song']['pic'],
|
||
|
artistPic: json['song']['artistPic'],
|
||
|
title: json['song']['title'],
|
||
|
artist: json['song']['artist'],
|
||
|
musicurl: json['song']['musicurl'],
|
||
|
id: json['song']['id'],
|
||
|
likes: json['song']['likes'],
|
||
|
collection: json['song']['collection'],
|
||
|
),
|
||
|
progress: json['progress'],
|
||
|
isCompleted: json['isCompleted'],
|
||
|
isDownloading: json['isDownloading'],
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class DownloadManager extends GetxController {
|
||
|
static const String PREFS_KEY = 'downloads_data';
|
||
|
final _downloads = <String, DownloadItem>{}.obs;
|
||
|
final downloadApi = DownloadApi();
|
||
|
late SharedPreferences _prefs;
|
||
|
|
||
|
@override
|
||
|
void onInit() async {
|
||
|
super.onInit();
|
||
|
await _initPrefs();
|
||
|
}
|
||
|
|
||
|
Future<void> _initPrefs() async {
|
||
|
_prefs = await SharedPreferences.getInstance();
|
||
|
await _loadDownloadsFromPrefs();
|
||
|
}
|
||
|
|
||
|
// 从SharedPreferences加载数据
|
||
|
Future<void> _loadDownloadsFromPrefs() async {
|
||
|
final String? downloadsJson = _prefs.getString(PREFS_KEY);
|
||
|
if (downloadsJson != null) {
|
||
|
final Map<String, dynamic> downloadsMap = json.decode(downloadsJson);
|
||
|
downloadsMap.forEach((key, value) {
|
||
|
_downloads[key] = DownloadItem.fromJson(value);
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 保存数据到SharedPreferences
|
||
|
Future<void> _saveDownloadsToPrefs() async {
|
||
|
final Map<String, dynamic> downloadsMap = {};
|
||
|
_downloads.forEach((key, value) {
|
||
|
downloadsMap[key] = value.toJson();
|
||
|
});
|
||
|
await _prefs.setString(PREFS_KEY, json.encode(downloadsMap));
|
||
|
}
|
||
|
|
||
|
List<Song> getLocalSongs() {
|
||
|
final localSongs = <Song>[];
|
||
|
_downloads.forEach((key, value) {
|
||
|
if (value.isCompleted) {
|
||
|
localSongs.add(value.song);
|
||
|
}
|
||
|
});
|
||
|
return localSongs;
|
||
|
}
|
||
|
|
||
|
Map<String, DownloadItem> get downloads => _downloads;
|
||
|
|
||
|
bool isDownloading(int id) => _downloads[id.toString()]?.isDownloading ?? false;
|
||
|
bool isCompleted(int id) => _downloads[id.toString()]?.isCompleted ?? false;
|
||
|
double getProgress(int id) => _downloads[id.toString()]?.progress ?? 0.0;
|
||
|
|
||
|
Song? getLocalSong(int id) {
|
||
|
final downloadItem = _downloads[id.toString()];
|
||
|
if (downloadItem?.isCompleted ?? false) {
|
||
|
return downloadItem!.song;
|
||
|
}
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
bool removeSong(int id) {
|
||
|
if (_downloads[id.toString()]?.isCompleted ?? false) {
|
||
|
File file = File.fromUri(Uri.parse(_downloads[id.toString()]!.song.musicurl));
|
||
|
file.deleteSync();
|
||
|
_downloads.remove(id.toString());
|
||
|
_saveDownloadsToPrefs();
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
int completedNumber() {
|
||
|
int count = 0;
|
||
|
_downloads.forEach((key, value) {
|
||
|
if (value.isCompleted) {
|
||
|
count++;
|
||
|
}
|
||
|
});
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
Future<void> startDownload({
|
||
|
required Song song,
|
||
|
required context,
|
||
|
}) async {
|
||
|
if (_downloads[song.id.toString()]?.isDownloading ?? false) return;
|
||
|
|
||
|
final fileName = '${song.id}_${song.title}_${song.artist}';
|
||
|
|
||
|
final downloadItem = DownloadItem(
|
||
|
song: song,
|
||
|
isDownloading: true,
|
||
|
);
|
||
|
_downloads[song.id.toString()] = downloadItem;
|
||
|
|
||
|
try {
|
||
|
final filePath = await downloadApi.downloadMusic(
|
||
|
musicUrl: song.musicurl,
|
||
|
name: fileName,
|
||
|
context: context,
|
||
|
onProgress: (progress) {
|
||
|
downloadItem.progress = progress;
|
||
|
_downloads[song.id.toString()] = downloadItem;
|
||
|
},
|
||
|
);
|
||
|
|
||
|
if (filePath != null) {
|
||
|
downloadItem.isCompleted = true;
|
||
|
downloadItem.isDownloading = false;
|
||
|
downloadItem.progress = 1.0;
|
||
|
song.musicurl = _getLocalAudioPath(fileName, song.musicurl);
|
||
|
print(song.musicurl);
|
||
|
} else {
|
||
|
downloadItem.isDownloading = false;
|
||
|
downloadItem.progress = 0.0;
|
||
|
}
|
||
|
} catch (e) {
|
||
|
print('Download error: $e');
|
||
|
downloadItem.isDownloading = false;
|
||
|
downloadItem.progress = 0.0;
|
||
|
}
|
||
|
|
||
|
_downloads[song.id.toString()] = downloadItem;
|
||
|
await _saveDownloadsToPrefs();
|
||
|
}
|
||
|
|
||
|
String _getFileExtension(String url) {
|
||
|
// Remove query parameters
|
||
|
final urlWithoutQuery = url.split('?').first;
|
||
|
// Get the extension including the dot
|
||
|
final extension = path.extension(urlWithoutQuery);
|
||
|
return extension.isNotEmpty ? extension : '.mp3'; // Default to .mp3 if no extension found
|
||
|
}
|
||
|
|
||
|
String _getLocalAudioPath(String fileName, String url) {
|
||
|
final extension = _getFileExtension(url);
|
||
|
final fullFileName = '$fileName$extension';
|
||
|
return path.join('/storage/emulated/0/MTMusic', fullFileName);
|
||
|
}
|
||
|
}
|