包名: - debug 使用 com.lxh.qingting_player.dev(应用名"清听 Dev"),可与 release 并存 - release 保持 com.lxh.qingting_player - Android 包名每一段必须以字母开头,因此用 .dev 而非 _dev - AGP 9 需显式开启 buildFeatures.resValues;移除 manifest 中已废弃的 package 属性 元数据(两个独立原因叠加): 1. song_key 之前用 String.hashCode / 本地临时文件 mtime,都不稳定; 2. songs.remote_path 存的是完整 URL,而所有查询都用相对路径(song.id), getSongByPath 永远 miss,UI 只能回退到文件名。 - 新增 utils/song_key.dart:songKeyFor(url,size)=md5(url|size),跨进程稳定 - metadata_service: remote_path 改存 fileId(相对路径),并改用稳定 song_key - audio_service / file_provider: 同步使用稳定键 - 数据库升级 v5:清空 songs / metadata_cache(可再生缓存;歌单与收藏按路径存储,不受影响) - device-check.ps1: 支持 -Package,默认校验 dev 包,启动组件改为向 PackageManager 解析 验证:两次独立 dart 进程 song_key 输出一致;真机 debug/release 并存安装,单实例自检通过。
66 lines
1.7 KiB
Dart
66 lines
1.7 KiB
Dart
// lib/metadata/file_provider.dart
|
|
import 'dart:io';
|
|
import 'package:flutter/foundation.dart'; // ⭐ 添加
|
|
import 'package:path_provider/path_provider.dart';
|
|
import 'package:dio/dio.dart';
|
|
import '../services/webdav_service.dart';
|
|
import '../utils/song_key.dart';
|
|
|
|
abstract class FileProvider {
|
|
Future<File?> getFile(String url);
|
|
}
|
|
|
|
class WebDAVFileProvider implements FileProvider {
|
|
final Dio _dio = Dio();
|
|
|
|
@override
|
|
Future<File?> getFile(String url) async {
|
|
try {
|
|
// 1. 获取缓存目录
|
|
final cacheDir = await getTemporaryDirectory();
|
|
final cachePath = '${cacheDir.path}/metadata_${songKeyForUrl(url)}.tmp';
|
|
final cacheFile = File(cachePath);
|
|
|
|
// 2. 如果缓存存在且未过期,直接返回
|
|
if (await cacheFile.exists()) {
|
|
final stat = await cacheFile.stat();
|
|
// 缓存 1 小时内有效(86400 秒)
|
|
if (DateTime.now().difference(stat.modified).inSeconds < 86400) {
|
|
return cacheFile;
|
|
}
|
|
}
|
|
|
|
// 3. 获取认证头
|
|
final headers = await WebDAVService.instance.getAuthHeaders();
|
|
if (headers.isEmpty) return null;
|
|
|
|
// 4. 只下载前 1MB
|
|
await _dio.download(
|
|
url,
|
|
cachePath,
|
|
options: Options(
|
|
headers: headers,
|
|
receiveTimeout: const Duration(seconds: 10),
|
|
sendTimeout: const Duration(seconds: 10),
|
|
),
|
|
);
|
|
|
|
return cacheFile;
|
|
} catch (e) {
|
|
debugPrint('⚠️ [WebDAVFileProvider] download failed: $e');
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
class LocalFileProvider implements FileProvider {
|
|
@override
|
|
Future<File?> getFile(String url) async {
|
|
final file = File(url);
|
|
if (await file.exists()) {
|
|
return file;
|
|
}
|
|
return null;
|
|
}
|
|
}
|