From bde62a7b2c8f23b1bda28e9dc9a01b146d3bc36a Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Tue, 25 Mar 2025 00:33:39 +0800 Subject: [PATCH] :zap: Add cache for audio and video (experimental) --- assets/translations/en-US.json | 3 +- assets/translations/zh-CN.json | 3 +- lib/screens/sharing.dart | 1 + lib/widgets/attachment/attachment_item.dart | 96 +++++++++++++++++-- macos/Flutter/GeneratedPluginRegistrant.swift | 2 - pubspec.lock | 60 ++---------- 6 files changed, 103 insertions(+), 62 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index e28817e..a2ed6c0 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -915,5 +915,6 @@ "accountProgramJoined": "Joined Program.", "accountProgramAlreadyJoined": "Joined", "accountProgramLeft": "Left Program.", - "leave": "Leave" + "leave": "Leave", + "attachmentFailedToLoadMedia": "Unable to load media file, please try again later. If this error occurs repeatedly, the source file may not exist or the network connection may be abnormal." } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index 1546c37..1e2bf05 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -913,5 +913,6 @@ "accountProgramJoined": "已加入计划。", "accountProgramLeft": "已离开计划。", "accountProgramAlreadyJoined": "已加入", - "leave": "离开" + "leave": "离开", + "attachmentFailedToLoadMedia": "无法加载媒体文件,请稍后重试。若此错误重复出现,可能源文件不存在或者网络连接异常。" } diff --git a/lib/screens/sharing.dart b/lib/screens/sharing.dart index bde790c..976c8a1 100644 --- a/lib/screens/sharing.dart +++ b/lib/screens/sharing.dart @@ -50,6 +50,7 @@ class _AppSharingListenerState extends State { Card( child: Column( children: [ + const SizedBox(width: double.infinity), ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 24), diff --git a/lib/widgets/attachment/attachment_item.dart b/lib/widgets/attachment/attachment_item.dart index 9742c9a..4140a95 100644 --- a/lib/widgets/attachment/attachment_item.dart +++ b/lib/widgets/attachment/attachment_item.dart @@ -5,6 +5,7 @@ import 'dart:math' as math; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:gap/gap.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:material_symbols_icons/symbols.dart'; @@ -12,6 +13,7 @@ import 'package:media_kit/media_kit.dart'; import 'package:media_kit_video/media_kit_video.dart'; import 'package:provider/provider.dart'; import 'package:styled_widget/styled_widget.dart'; +import 'package:surface/logger.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/types/attachment.dart'; import 'package:surface/widgets/universal_image.dart'; @@ -222,20 +224,71 @@ class _AttachmentItemContentVideoState : sn.getAttachmentUrl(widget.data.compressed!.rid); _videoPlayer = Player(); _videoController = VideoController(_videoPlayer!); - _videoPlayer!.open(Media(url), play: !widget.isAutoload); + + String? uri; + final inCacheInfo = await DefaultCacheManager().getFileFromCache(url); + if (inCacheInfo == null) { + logging.info('[MediaPlayer] Miss cache: $url'); + final fileStream = DefaultCacheManager().getFileStream( + url, + withProgress: true, + ); + await for (var fileInfo in fileStream) { + if (fileInfo is FileInfo) { + uri = fileInfo.file.path; + break; + } + } + } else { + uri = inCacheInfo.file.path; + logging.info('[MediaPlayer] Hit cache: $url'); + } + if (uri == null) { + if (mounted) { + context.showErrorDialog('attachmentFailedToLoadMedia'.tr()); + } + return; + } + + _videoPlayer!.open(Media(uri), play: !widget.isAutoload); } - void _toggleOriginal() { + void _toggleOriginal() async { if (!mounted) return; if (widget.data.compressedId == null) return; setState(() => _showOriginal = !_showOriginal); final sn = context.read(); + final url = _showOriginal + ? sn.getAttachmentUrl(widget.data.rid) + : sn.getAttachmentUrl(widget.data.compressed!.rid); + + String? uri; + final inCacheInfo = await DefaultCacheManager().getFileFromCache(url); + if (inCacheInfo == null) { + logging.info('[MediaPlayer] Miss cache: $url'); + final fileStream = DefaultCacheManager().getFileStream( + url, + withProgress: true, + ); + await for (var fileInfo in fileStream) { + if (fileInfo is FileInfo) { + uri = fileInfo.file.path; + break; + } + } + } else { + uri = inCacheInfo.file.path; + logging.info('[MediaPlayer] Hit cache: $url'); + } + if (uri == null) { + if (mounted) { + context.showErrorDialog('attachmentFailedToLoadMedia'.tr()); + } + return; + } + _videoPlayer?.open( - Media( - _showOriginal - ? sn.getAttachmentUrl(widget.data.rid) - : sn.getAttachmentUrl(widget.data.compressed!.rid), - ), + Media(uri), play: true, ); } @@ -439,7 +492,33 @@ class _AttachmentItemContentAudioState final sn = context.read(); final url = sn.getAttachmentUrl(widget.data.rid); _audioPlayer = Player(); - await _audioPlayer!.open(Media(url), play: !widget.isAutoload); + + String? uri; + final inCacheInfo = await DefaultCacheManager().getFileFromCache(url); + if (inCacheInfo == null) { + logging.info('[MediaPlayer] Miss cache: $url'); + final fileStream = DefaultCacheManager().getFileStream( + url, + withProgress: true, + ); + await for (var fileInfo in fileStream) { + if (fileInfo is FileInfo) { + uri = fileInfo.file.path; + break; + } + } + } else { + uri = inCacheInfo.file.path; + logging.info('[MediaPlayer] Hit cache: $url'); + } + if (uri == null) { + if (mounted) { + context.showErrorDialog('attachmentFailedToLoadMedia'.tr()); + } + return; + } + + await _audioPlayer!.open(Media(uri), play: !widget.isAutoload); _audioPlayer!.stream.playing.listen((v) => setState(() => _isPlaying = v)); _audioPlayer!.stream.position.listen((v) => setState(() => _position = v)); _audioPlayer!.stream.duration.listen((v) => setState(() => _duration = v)); @@ -567,6 +646,7 @@ class _AttachmentItemContentAudioState ), ), Container( + padding: EdgeInsets.symmetric(horizontal: 16), constraints: const BoxConstraints(maxWidth: 320), child: Column( mainAxisAlignment: MainAxisAlignment.center, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 1561419..c8bfd94 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -38,7 +38,6 @@ import tray_manager import url_launcher_macos import video_compress import wakelock_plus -import webview_flutter_wkwebview func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) @@ -74,5 +73,4 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin")) WakelockPlusMacosPlugin.register(with: registry.registrar(forPlugin: "WakelockPlusMacosPlugin")) - WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 8b1231d..de328cc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: archive - sha256: "7dcbd0f87fe5f61cb28da39a1a8b70dbc106e2fe0516f7836eb7bb2948481a12" + sha256: "0c64e928dcbefddecd234205422bcfc2b5e6d31be0b86fef0d0dd48d7b4c9742" url: "https://pub.dev" source: hosted - version: "4.0.5" + version: "4.0.4" args: dependency: transitive description: @@ -365,10 +365,10 @@ packages: dependency: "direct main" description: name: dart_webrtc - sha256: "8565f1f1f412b8a6fd862f3a157560811e61eeeac26741c735a5d2ff409a0202" + sha256: b34e90bc82f33c1023cf98661369c37bccd648c8a4cf882a875d9f5d8bbef694 url: "https://pub.dev" source: hosted - version: "1.5.3" + version: "1.5.2+hotfix.1" dbus: dependency: transitive description: @@ -746,10 +746,10 @@ packages: dependency: "direct main" description: name: flutter_expandable_fab - sha256: "4d03f54e5384897e32606e9959cef5e7857e5a203e24684f95dfbb5f7fb9b88e" + sha256: b14caf78720a48f650e6e1a38d724e33b1f5348d646fa1c266570c31a7f87ef3 url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.0" flutter_highlight: dependency: "direct main" description: @@ -1013,14 +1013,6 @@ packages: url: "https://pub.dev" source: hosted version: "6.2.1" - google_mobile_ads: - dependency: "direct main" - description: - name: google_mobile_ads - sha256: "0d4a3744b5e8ed1b8be6a1b452d309f811688855a497c6113fc4400f922db603" - url: "https://pub.dev" - source: hosted - version: "5.3.1" graphs: dependency: transitive description: @@ -1145,10 +1137,10 @@ packages: dependency: transitive description: name: image - sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + sha256: "13d3349ace88f12f4a0d175eb5c12dcdd39d35c4c109a8a13dfeb6d0bd9e31c3" url: "https://pub.dev" source: hosted - version: "4.5.4" + version: "4.5.3" image_picker: dependency: "direct main" description: @@ -2502,42 +2494,10 @@ packages: dependency: transitive description: name: webrtc_interface - sha256: e92afec11152a9ccb5c9f35482754edd99696e886ab6acaf90c06dd2d09f09eb + sha256: e05f00091c9c70a15bab4ccb1b6c46d9a16a6075002f02cfac3641eccb05e25d url: "https://pub.dev" source: hosted - version: "1.2.2+hotfix.1" - webview_flutter: - dependency: transitive - description: - name: webview_flutter - sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" - url: "https://pub.dev" - source: hosted - version: "4.10.0" - webview_flutter_android: - dependency: transitive - description: - name: webview_flutter_android - sha256: e09150b28a07933839adef0e4a088bb43e8c8d9e6b93025b01882d4067a58ab0 - url: "https://pub.dev" - source: hosted - version: "4.3.4" - webview_flutter_platform_interface: - dependency: transitive - description: - name: webview_flutter_platform_interface - sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d - url: "https://pub.dev" - source: hosted - version: "2.10.0" - webview_flutter_wkwebview: - dependency: transitive - description: - name: webview_flutter_wkwebview - sha256: c49a98510080378b1525132f407a92c3dcd3b7145bef04fb8137724aadcf1cf0 - url: "https://pub.dev" - source: hosted - version: "3.18.4" + version: "1.2.1+hotfix.1" win32: dependency: transitive description: