diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 952c920f8..5ddc01d69 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -1373,6 +1373,7 @@ class VideoDetailController extends GetxController } } + dynamic subtitles; late List> _vttSubtitles = >[]; int? vttSubtitlesIndex; late bool showVP = true; @@ -1499,6 +1500,7 @@ class VideoDetailController extends GetxController } if (res["data"] is List && res["data"].isNotEmpty) { + subtitles = res["data"]; var result = await VideoHttp.vttSubtitles(res["data"]); if (result != null) { _vttSubtitles = result; @@ -1569,6 +1571,7 @@ class VideoDetailController extends GetxController savedDanmaku = null; // subtitle + subtitles = null; vttSubtitlesIndex = null; _vttSubtitles.clear(); diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 0ffc4a085..e05b99291 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -13,6 +13,8 @@ import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; +import 'package:dio/dio.dart'; +import 'package:document_file_save_plus/document_file_save_plus_platform_interface.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -30,6 +32,7 @@ import 'package:PiliPlus/plugin/pl_player/index.dart'; import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/services/shutdown_timer_service.dart'; +import 'package:share_plus/share_plus.dart'; import '../../../../models/video/play/CDN.dart'; import '../../../setting/widgets/select_dialog.dart'; import '../introduction/index.dart'; @@ -386,6 +389,14 @@ class _HeaderControlState extends State { leading: const Icon(Icons.subtitles_outlined, size: 20), title: const Text('字幕设置', style: titleStyle), ), + if (videoDetailCtr.subtitles is List && + videoDetailCtr.subtitles.isNotEmpty) + ListTile( + dense: true, + onTap: () => {Get.back(), onExportSubtitle()}, + leading: const Icon(Icons.download_outlined, size: 20), + title: const Text('保存字幕', style: titleStyle), + ), ListTile( dense: true, title: const Text('播放信息', style: titleStyle), @@ -1035,6 +1046,66 @@ class _HeaderControlState extends State { ); } + void onExportSubtitle() { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + clipBehavior: Clip.hardEdge, + contentPadding: const EdgeInsets.fromLTRB(0, 12, 0, 12), + title: const Text('保存字幕'), + content: SingleChildScrollView( + child: Column( + children: (videoDetailCtr.subtitles as List) + .map( + (item) => ListTile( + dense: true, + onTap: () async { + Get.back(); + try { + final res = await Dio().get( + (item['subtitle_url'] as String).http2https, + options: Options( + responseType: ResponseType.bytes, + ), + ); + if (res.statusCode == 200) { + final name = + '${videoIntroController.videoDetail.value.title}-${videoDetailCtr.bvid}-${videoDetailCtr.cid.value}-${item['lan_doc']}'; + try { + DocumentFileSavePlusPlatform.instance + .saveMultipleFiles( + dataList: [res.data], + fileNameList: [name], + mimeTypeList: ['text/plain'], + ); + SmartDialog.showToast('已保存'); + } catch (e) { + Share.shareXFiles([ + XFile.fromData( + res.data, + name: name, + mimeType: 'application/json', + ) + ]); + } + } + } catch (e) { + SmartDialog.showToast(e.toString()); + } + }, + title: + Text(item['lan_doc'], style: TextStyle(fontSize: 14)), + ), + ) + .toList(), + ), + ), + ); + }, + ); + } + /// 字幕设置 void showSetSubtitle() { double subtitleFontScale = widget.controller.subtitleFontScale; diff --git a/pubspec.lock b/pubspec.lock index 5b39ae852..23b5aa584 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -441,6 +441,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + document_file_save_plus: + dependency: "direct main" + description: + name: document_file_save_plus + sha256: ff05c6a3b072377566e8e92666db38eb277786f90c0ac267ea47dc22725c1df3 + url: "https://pub.dev" + source: hosted + version: "2.0.0" dynamic_color: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 569fdda06..f5ca1e8fd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -187,6 +187,7 @@ dependencies: live_photo_maker: ^0.0.6 fl_chart: ^0.69.2 synchronized: ^3.3.0 + document_file_save_plus: ^2.0.0 dependency_overrides: screen_brightness: ^2.0.1