FunyMeeAI/lib/core/video_file_cache.dart
2026-04-13 22:25:08 +08:00

60 lines
1.9 KiB
Dart
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import 'dart:io';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
/// 与图片等分开的专用视频磁盘缓存(`flutter_cache_manager`)。
final CacheManager funymeeVideoCacheManager = CacheManager(
Config(
'funymeeVideoCache',
stalePeriod: const Duration(days: 14),
maxNrOfCacheObjects: 200,
),
);
/// 用 **scheme + host + path** 作缓存键,忽略 **query**GCS 等签名参数每次变化,否则永远 cache miss
/// 下载请求仍使用完整 [url](含 query
String videoCacheKeyForUrl(String url) {
final raw = url.trim();
final u = Uri.tryParse(raw);
if (u == null || !u.hasScheme) return raw;
if (u.scheme != 'http' && u.scheme != 'https') return raw;
if (u.host.isEmpty) return raw;
final path = u.path.isEmpty ? '/' : u.path;
return '${u.scheme}://${u.host}$path';
}
/// 排除明显非视频的磁盘文件HTML 错误页、JSON、过小避免 ExoPlayer
/// [UnrecognizedInputFormatException] 反复读坏缓存。
Future<bool> videoCachedFileLooksPlayable(File f) async {
try {
final len = await f.length();
if (len < 512) return false;
late List<int> head;
try {
head = await f.openRead(0, 16).first;
} catch (_) {
return false;
}
if (head.length < 12) return false;
// HTML / XML 错误页
if (head[0] == 0x3C) {
final s = String.fromCharCodes(head.take(8));
if (s.startsWith('<!') || s.startsWith('<?') || s.startsWith('<h')) {
return false;
}
}
if (head[0] == 0x7B) return false; // JSON
// MP4/MOV: box size + 'ftyp'
if (head.length >= 8) {
final tag = String.fromCharCodes(head.sublist(4, 8));
if (tag == 'ftyp') return true;
}
// WebM EBML
if (head[0] == 0x1a && head[1] == 0x45 && head[2] == 0xdf) return true;
// 较大二进制:交给解码器(避免误判少见封装)
return len >= 4096;
} catch (_) {
return false;
}
}