forked from piaocbn2j/MTMusic
parent
5a0540924d
commit
91386b243f
After Width: | Height: | Size: 749 B |
After Width: | Height: | Size: 356 B |
@ -0,0 +1,3 @@
|
||||
description: This file stores settings for Dart & Flutter DevTools.
|
||||
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||
extensions:
|
@ -0,0 +1,201 @@
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,12 +1,20 @@
|
||||
class Song {
|
||||
final String pic;
|
||||
final String artistPic;
|
||||
final String title;
|
||||
final String artist;
|
||||
final String musicurl;
|
||||
final int id;
|
||||
final bool likes;
|
||||
final bool collection;
|
||||
String pic;
|
||||
String artistPic;
|
||||
String title;
|
||||
String artist;
|
||||
String musicurl;
|
||||
int id;
|
||||
bool likes;
|
||||
bool collection;
|
||||
|
||||
Song({required this.pic,required this.artistPic,required this.title, required this.artist, required this.musicurl,required this.id,required this.likes,required this.collection});
|
||||
Song(
|
||||
{required this.pic,
|
||||
required this.artistPic,
|
||||
required this.title,
|
||||
required this.artist,
|
||||
required this.musicurl,
|
||||
required this.id,
|
||||
required this.likes,
|
||||
required this.collection});
|
||||
}
|
||||
|
Loading…
Reference in new issue