feat: more subtitle

This commit is contained in:
My-Responsitories
2026-06-23 16:07:43 +08:00
parent 9d6d3d524c
commit fa69955b76
5 changed files with 65 additions and 22 deletions

View File

@@ -21,4 +21,12 @@ abstract final class DmGrpc {
isolate: true, isolate: true,
); );
} }
static Future<LoadingState<DmViewReply>> dmView(int aid, int cid) {
return GrpcReq.request(
GrpcUrl.dmView,
DmViewReq(pid: Int64(aid), oid: Int64(cid), type: 1),
DmViewReply.fromBuffer,
);
}
} }

View File

@@ -14,6 +14,7 @@ abstract final class GrpcUrl {
// danmaku // danmaku
static const dmSegMobile = '/bilibili.community.service.dm.v1.DM/DmSegMobile'; static const dmSegMobile = '/bilibili.community.service.dm.v1.DM/DmSegMobile';
static const dmView = '/bilibili.community.service.dm.v1.DM/DmView';
// reply // reply
static const reply = '/bilibili.main.community.reply.v1.Reply'; static const reply = '/bilibili.main.community.reply.v1.Reply';

View File

@@ -1,4 +1,4 @@
class Subtitle { class Subtitle implements Comparable<Subtitle> {
late String lan; late String lan;
String? lanDoc; String? lanDoc;
String? subtitleUrl; String? subtitleUrl;
@@ -8,6 +8,8 @@ class Subtitle {
Subtitle({ Subtitle({
required this.lan, required this.lan,
this.lanDoc, this.lanDoc,
this.subtitleUrl,
this.isAi = false,
}); });
Subtitle.fromJson(Map<String, dynamic> json) { Subtitle.fromJson(Map<String, dynamic> json) {
@@ -17,4 +19,13 @@ class Subtitle {
subtitleUrl = json["subtitle_url"]; subtitleUrl = json["subtitle_url"];
subtitleUrlV2 = json["subtitle_url_v2"]; subtitleUrlV2 = json["subtitle_url_v2"];
} }
@override
int compareTo(Subtitle other) {
final thisHasZh = lan.contains('zh');
final otherHasZh = other.lan.contains('zh');
if (thisHasZh != otherHasZh) return thisHasZh ? -1 : 1;
if (isAi != other.isAi) return isAi ? 1 : -1;
return 0;
}
} }

View File

@@ -14,12 +14,6 @@ class SubtitleInfo {
(json['subtitles'] as List<dynamic>?) (json['subtitles'] as List<dynamic>?)
?.map((e) => Subtitle.fromJson(e as Map<String, dynamic>)) ?.map((e) => Subtitle.fromJson(e as Map<String, dynamic>))
.toList() .toList()
?..sort((a, b) { ?..sort(),
final aHasZh = a.lan.contains('zh');
final bHasZh = b.lan.contains('zh');
if (aHasZh != bHasZh) return aHasZh ? -1 : 1;
if (a.isAi != b.isAi) return a.isAi ? 1 : -1;
return 0;
}),
); );
} }

View File

@@ -7,6 +7,7 @@ import 'package:PiliPlus/common/widgets/pair.dart';
import 'package:PiliPlus/common/widgets/progress_bar/segment_progress_bar.dart'; import 'package:PiliPlus/common/widgets/progress_bar/segment_progress_bar.dart';
import 'package:PiliPlus/grpc/bilibili/app/listener/v1.pbenum.dart' import 'package:PiliPlus/grpc/bilibili/app/listener/v1.pbenum.dart'
show PlaylistSource; show PlaylistSource;
import 'package:PiliPlus/grpc/dm.dart';
import 'package:PiliPlus/http/fav.dart'; import 'package:PiliPlus/http/fav.dart';
import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
@@ -1178,6 +1179,37 @@ class VideoDetailController extends GetxController
} }
if (response.subtitle?.subtitles case final sub? when (sub.isNotEmpty)) { if (response.subtitle?.subtitles case final sub? when (sub.isNotEmpty)) {
_setSubtitle(sub);
} else if (!Accounts.main.isLogin) {
final res = await DmGrpc.dmView(aid, cid.value);
if (res case Success(:final response)) {
if (response.hasSubtitle() &&
response.subtitle.subtitles.isNotEmpty) {
_setSubtitle(
response.subtitle.subtitles
.map(
(i) => Subtitle(
lan: i.lan,
lanDoc: i.lanDoc,
subtitleUrl: i.subtitleUrl.replaceFirst(
RegExp('^https?:'),
'',
),
isAi: i.type == .AI,
),
)
.toList()
..sort(),
);
}
} else {
res.toast();
}
}
}
}
Future<void> _setSubtitle(List<Subtitle> sub) async {
subtitles.value = sub; subtitles.value = sub;
final idx = switch (Pref.subtitlePreferenceV2) { final idx = switch (Pref.subtitlePreferenceV2) {
.off => 0, .off => 0,
@@ -1186,15 +1218,12 @@ class VideoDetailController extends GetxController
.auto => .auto =>
!sub.first.lan.startsWith('ai') || !sub.first.lan.startsWith('ai') ||
(PlatformUtils.isMobile && (PlatformUtils.isMobile &&
(await FlutterVolumeController.getVolume() ?? 0.0) <= (await FlutterVolumeController.getVolume() ?? 0.0) <= 0.0)
0.0)
? 1 ? 1
: 0, : 0,
}; };
await setSubtitle(idx); await setSubtitle(idx);
} }
}
}
void updateMediaListHistory(int aid) { void updateMediaListHistory(int aid) {
if (args['sortField'] != null) { if (args['sortField'] != null) {