petsHero-AI/lib/features/gallery/video_thumbnail_cache.dart
2026-03-29 23:53:24 +08:00

95 lines
2.7 KiB
Dart
Raw 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:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:path_provider/path_provider.dart';
import 'package:video_thumbnail/video_thumbnail.dart';
/// 视频封面缓存:优先从本地读取,未命中则生成并缓存
class VideoThumbnailCache {
VideoThumbnailCache._();
static final VideoThumbnailCache _instance = VideoThumbnailCache._();
static VideoThumbnailCache get instance => _instance;
static const int _maxWidth = 400;
static const int _quality = 75;
/// 全屏背景等大图:无 ExoPlayer仅抽一帧 JPEG例如生成页背景长边约 [maxWidth]
Future<Uint8List?> getPosterFrame(String videoUrl, {int maxWidth = 1024}) async {
final key = '${_cacheKey(videoUrl)}_poster_$maxWidth';
final cacheDir = await _getCacheDir();
final file = File('${cacheDir.path}/$key.jpg');
if (await file.exists()) {
return file.readAsBytes();
}
try {
final path = await VideoThumbnail.thumbnailFile(
video: videoUrl,
thumbnailPath: cacheDir.path,
imageFormat: ImageFormat.JPEG,
maxWidth: maxWidth,
quality: 78,
);
if (path != null) {
final cached = File(path);
final bytes = await cached.readAsBytes();
if (cached.path != file.path) {
await file.writeAsBytes(bytes);
cached.deleteSync();
}
return bytes;
}
} catch (_) {}
return null;
}
Future<Uint8List?> getThumbnail(String videoUrl) async {
final key = _cacheKey(videoUrl);
final cacheDir = await _getCacheDir();
final file = File('${cacheDir.path}/$key.jpg');
if (await file.exists()) {
return file.readAsBytes();
}
try {
final path = await VideoThumbnail.thumbnailFile(
video: videoUrl,
thumbnailPath: cacheDir.path,
imageFormat: ImageFormat.JPEG,
maxWidth: _maxWidth,
quality: _quality,
);
if (path != null) {
final cached = File(path);
final bytes = await cached.readAsBytes();
if (cached.path != file.path) {
await file.writeAsBytes(bytes);
cached.deleteSync();
}
return bytes;
}
} catch (_) {}
return null;
}
String _cacheKey(String url) {
final bytes = utf8.encode(url);
final digest = md5.convert(bytes);
return digest.toString();
}
Directory? _cacheDir;
Future<Directory> _getCacheDir() async {
_cacheDir ??= await getTemporaryDirectory();
final dir = Directory('${_cacheDir!.path}/video_thumbnails');
if (!await dir.exists()) {
await dir.create(recursive: true);
}
return dir;
}
}