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; Future 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 _getCacheDir() async { _cacheDir ??= await getTemporaryDirectory(); final dir = Directory('${_cacheDir!.path}/video_thumbnails'); if (!await dir.exists()) { await dir.create(recursive: true); } return dir; } }