mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-04 16:20:14 +08:00
tweaks (#2426)
* opt: danmaku weight
* opt: cache clean
* opt: level img
* opt: play icon
* opt: svg big-vip
* opt: webview ua
* opt: simple dialog
* feat: export vtt
* tweak
* opt: mapIndexed
* feat: more subtitle
* refa: settings page
* feat: codec list options
* drawPath
Signed-off-by: dom <githubaccount56556@proton.me>
* custom dialog option
Signed-off-by: dom <githubaccount56556@proton.me>
* update
Signed-off-by: dom <githubaccount56556@proton.me>
* Revert "drawPath"
This reverts commit e8a4b19f0f.
* opt: _initStreamIndex
* fix: avoid gap
* fix: scale [skip ci]
* fix: hide repost menu not login
* tweaks
Signed-off-by: dom <githubaccount56556@proton.me>
---------
Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
committed by
GitHub
parent
3dee6a85e5
commit
9d94c72e95
@@ -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/grpc/bilibili/app/listener/v1.pbenum.dart'
|
||||
show PlaylistSource;
|
||||
import 'package:PiliPlus/grpc/dm.dart';
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
@@ -19,7 +20,6 @@ import 'package:PiliPlus/models/common/sponsor_block/segment_model.dart';
|
||||
import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
||||
import 'package:PiliPlus/models/common/video/source_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/subtitle_pref_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_decode_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_type.dart';
|
||||
@@ -143,8 +143,7 @@ class VideoDetailController extends GetxController
|
||||
Box setting = GStorage.setting;
|
||||
|
||||
// 预设的解码格式
|
||||
late String cacheDecode = Pref.defaultDecode; // def avc
|
||||
late String cacheSecondDecode = Pref.secondDecode; // def av1
|
||||
late List<VideoDecodeFormatType> preferCodecs = Pref.preferCodecs;
|
||||
|
||||
bool get showReply => isFileSource
|
||||
? false
|
||||
@@ -669,31 +668,38 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
}
|
||||
|
||||
VideoItem findVideoByQa(int qa) {
|
||||
VideoItem findVideoByQa(int qa, {bool setCodecs = false}) {
|
||||
/// 根据currentVideoQa和currentDecodeFormats 重新设置videoUrl
|
||||
final videoList = data.dash!.video!.where((i) => i.id == qa).toList();
|
||||
|
||||
final currentDecodeFormats = this.currentDecodeFormats.codes;
|
||||
final defaultDecodeFormats = VideoDecodeFormatType.fromString(
|
||||
cacheDecode,
|
||||
).codes;
|
||||
final secondDecodeFormats = VideoDecodeFormatType.fromString(
|
||||
cacheSecondDecode,
|
||||
).codes;
|
||||
|
||||
VideoItem? video;
|
||||
for (final i in videoList) {
|
||||
final codec = i.codecs!;
|
||||
if (currentDecodeFormats.any(codec.startsWith)) {
|
||||
video = i;
|
||||
break;
|
||||
} else if (defaultDecodeFormats.any(codec.startsWith)) {
|
||||
video = i;
|
||||
} else if (video == null && secondDecodeFormats.any(codec.startsWith)) {
|
||||
video = i;
|
||||
final currentCodes = currentDecodeFormats.codes;
|
||||
VideoItem? bestVideo;
|
||||
int bestIndex = preferCodecs.length;
|
||||
for (final video in videoList) {
|
||||
final c = video.codecs!;
|
||||
if (currentCodes.any(c.startsWith)) {
|
||||
return video;
|
||||
}
|
||||
for (int i = 0; i < bestIndex; i++) {
|
||||
if (preferCodecs[i].codes.any(c.startsWith)) {
|
||||
bestIndex = i;
|
||||
bestVideo = video;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return video ?? videoList.first;
|
||||
|
||||
if (setCodecs) {
|
||||
if (bestIndex < preferCodecs.length) {
|
||||
currentDecodeFormats = preferCodecs[bestIndex];
|
||||
} else {
|
||||
currentDecodeFormats = VideoDecodeFormatType.fromString(
|
||||
videoList.first.codecs!,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return bestVideo ?? videoList.first;
|
||||
}
|
||||
|
||||
/// 更新画质、音质
|
||||
@@ -706,11 +712,7 @@ class VideoDetailController extends GetxController
|
||||
..isBuffering.value = false
|
||||
..buffered.value = Duration.zero;
|
||||
|
||||
final video = findVideoByQa(currentVideoQa.code);
|
||||
if (firstVideo.codecs != video.codecs) {
|
||||
currentDecodeFormats = VideoDecodeFormatType.fromString(video.codecs!);
|
||||
}
|
||||
firstVideo = video;
|
||||
firstVideo = findVideoByQa(currentVideoQa.code, setCodecs: true);
|
||||
videoUrl = VideoUtils.getCdnUrl(firstVideo.playUrls);
|
||||
|
||||
/// 根据currentAudioQa 重新设置audioUrl
|
||||
@@ -817,6 +819,7 @@ class VideoDetailController extends GetxController
|
||||
Volume? volume;
|
||||
|
||||
// 视频链接
|
||||
/// TODO: merge [DownloadHttp.getVideoUrl].
|
||||
Future<void> queryVideoUrl({
|
||||
bool fromReset = false,
|
||||
bool autoFullScreenFlag = false,
|
||||
@@ -897,7 +900,7 @@ class VideoDetailController extends GetxController
|
||||
quality: videoQuality,
|
||||
);
|
||||
_setVideoHeight();
|
||||
currentDecodeFormats = VideoDecodeFormatType.fromString('avc1');
|
||||
currentDecodeFormats = VideoDecodeFormatType.AVC;
|
||||
currentVideoQa.value = videoQuality;
|
||||
await _initPlayerIfNeeded(autoFullScreenFlag);
|
||||
isQuerying = false;
|
||||
@@ -929,42 +932,25 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
currentVideoQa.value = VideoQuality.fromCode(targetVideoQa);
|
||||
|
||||
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||
final supportFormats = data.supportFormats!;
|
||||
|
||||
// 根据画质选编码格式
|
||||
currentDecodeFormats = VideoUtils.selectCodec(
|
||||
supportFormats
|
||||
.firstWhere(
|
||||
(e) => e.quality == targetVideoQa,
|
||||
orElse: () => supportFormats.first,
|
||||
)
|
||||
.codecs!,
|
||||
preferCodecs,
|
||||
);
|
||||
|
||||
/// 取出符合当前画质的videoList
|
||||
final List<VideoItem> videosList = videoList
|
||||
final videosList = videoList
|
||||
.where((e) => e.quality.code == targetVideoQa)
|
||||
.toList();
|
||||
|
||||
/// 优先顺序 设置中指定解码格式 -> 当前可选的首个解码格式
|
||||
final List<FormatItem> supportFormats = data.supportFormats!;
|
||||
// 根据画质选编码格式
|
||||
final List<String> supportDecodeFormats = supportFormats
|
||||
.firstWhere(
|
||||
(e) => e.quality == targetVideoQa,
|
||||
orElse: () => supportFormats.first,
|
||||
)
|
||||
.codecs!;
|
||||
// 默认从设置中取AV1
|
||||
currentDecodeFormats = VideoDecodeFormatType.fromString(cacheDecode);
|
||||
VideoDecodeFormatType secondDecodeFormats =
|
||||
VideoDecodeFormatType.fromString(cacheSecondDecode);
|
||||
// 当前视频没有对应格式返回第一个
|
||||
int flag = 0;
|
||||
for (final e in supportDecodeFormats) {
|
||||
if (currentDecodeFormats.codes.any(e.startsWith)) {
|
||||
flag = 1;
|
||||
break;
|
||||
} else if (secondDecodeFormats.codes.any(e.startsWith)) {
|
||||
flag = 2;
|
||||
}
|
||||
}
|
||||
if (flag == 2) {
|
||||
currentDecodeFormats = secondDecodeFormats;
|
||||
} else if (flag == 0) {
|
||||
currentDecodeFormats = VideoDecodeFormatType.fromString(
|
||||
supportDecodeFormats.first,
|
||||
);
|
||||
}
|
||||
|
||||
/// 取出符合当前解码格式的videoItem
|
||||
firstVideo = videosList.firstWhere(
|
||||
(e) => currentDecodeFormats.codes.any(e.codecs!.startsWith),
|
||||
@@ -1050,16 +1036,14 @@ class VideoDetailController extends GetxController
|
||||
|
||||
RxList<Subtitle> subtitles = RxList<Subtitle>();
|
||||
final Map<int, ({bool isData, String id})> vttSubtitles = {};
|
||||
late final RxInt vttSubtitlesIndex = (-1).obs;
|
||||
late final RxBool showVP = true.obs;
|
||||
late final RxList<ViewPointSegment> viewPointList = <ViewPointSegment>[].obs;
|
||||
late final vttSubtitlesIndex = (-1).obs;
|
||||
late final showVP = true.obs;
|
||||
late final viewPointList = <ViewPointSegment>[].obs;
|
||||
|
||||
// 设定字幕轨道
|
||||
Future<void> setSubtitle(int index) async {
|
||||
if (index <= 0) {
|
||||
await plPlayerController.videoPlayerController?.setSubtitleTrack(
|
||||
SubtitleTrack.no(),
|
||||
);
|
||||
await plPlayerController.videoPlayerController?.setSubtitleTrack(.no());
|
||||
vttSubtitlesIndex.value = index;
|
||||
return;
|
||||
}
|
||||
@@ -1136,9 +1120,9 @@ class VideoDetailController extends GetxController
|
||||
);
|
||||
if (res case Success(:final response)) {
|
||||
// interactive video
|
||||
late final introCtr = Get.find<UgcIntroController>(tag: heroTag);
|
||||
if (isUgc && graphVersion == null) {
|
||||
try {
|
||||
final introCtr = Get.find<UgcIntroController>(tag: heroTag);
|
||||
if (introCtr.videoDetail.value.rights?.isSteinGate == 1) {
|
||||
graphVersion = response.interaction?.graphVersion;
|
||||
getSteinEdgeInfo();
|
||||
@@ -1150,22 +1134,18 @@ class VideoDetailController extends GetxController
|
||||
|
||||
if (isUgc && continuePlayingPart) {
|
||||
continuePlayingPart = false;
|
||||
try {
|
||||
UgcIntroController ugcIntroController = Get.find<UgcIntroController>(
|
||||
tag: heroTag,
|
||||
);
|
||||
if ((ugcIntroController.videoDetail.value.pages?.length ?? 0) > 1 &&
|
||||
response.lastPlayCid != null &&
|
||||
response.lastPlayCid != 0) {
|
||||
if (response.lastPlayCid != cid.value) {
|
||||
int index = ugcIntroController.videoDetail.value.pages!
|
||||
.indexWhere((item) => item.cid == response.lastPlayCid);
|
||||
final lastCid = response.lastPlayCid;
|
||||
if (lastCid != null && lastCid != 0 && lastCid != cid.value) {
|
||||
try {
|
||||
final pages = introCtr.videoDetail.value.pages;
|
||||
if (pages != null && pages.length > 1) {
|
||||
final index = pages.indexWhere((item) => item.cid == lastCid);
|
||||
if (index != -1) {
|
||||
onAddItem(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
|
||||
if (plPlayerController.showViewPoints &&
|
||||
@@ -1184,27 +1164,53 @@ class VideoDetailController extends GetxController
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
if (response.subtitle?.subtitles?.isNotEmpty == true) {
|
||||
subtitles.value = response.subtitle!.subtitles!;
|
||||
|
||||
final idx = switch (Pref.subtitlePreferenceV2) {
|
||||
SubtitlePrefType.off => 0,
|
||||
SubtitlePrefType.on => 1,
|
||||
SubtitlePrefType.withoutAi =>
|
||||
subtitles.first.lan.startsWith('ai') ? 0 : 1,
|
||||
SubtitlePrefType.auto =>
|
||||
!subtitles.first.lan.startsWith('ai') ||
|
||||
(PlatformUtils.isMobile &&
|
||||
(await FlutterVolumeController.getVolume() ?? 0.0) <=
|
||||
0.0)
|
||||
? 1
|
||||
: 0,
|
||||
};
|
||||
await setSubtitle(idx);
|
||||
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;
|
||||
final idx = switch (Pref.subtitlePreferenceV2) {
|
||||
.off => 0,
|
||||
.on => 1,
|
||||
.withoutAi => sub.first.lan.startsWith('ai') ? 0 : 1,
|
||||
.auto =>
|
||||
!sub.first.lan.startsWith('ai') ||
|
||||
(PlatformUtils.isMobile &&
|
||||
(await FlutterVolumeController.getVolume() ?? 0.0) <= 0.0)
|
||||
? 1
|
||||
: 0,
|
||||
};
|
||||
await setSubtitle(idx);
|
||||
}
|
||||
|
||||
void updateMediaListHistory(int aid) {
|
||||
if (args['sortField'] != null) {
|
||||
VideoHttp.medialistHistory(
|
||||
|
||||
Reference in New Issue
Block a user