mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-16 23:26:14 +08:00
feat: millisecond skip (#869)
* feat: millisecond skip * fix: formatDuration * fix: post segment
This commit is contained in:
committed by
GitHub
parent
bc2de4828b
commit
3655c31a48
@@ -10,11 +10,11 @@ class SegmentModel {
|
|||||||
required this.segmentType,
|
required this.segmentType,
|
||||||
required this.segment,
|
required this.segment,
|
||||||
required this.skipType,
|
required this.skipType,
|
||||||
this.hasSkipped,
|
this.hasSkipped = false,
|
||||||
});
|
});
|
||||||
String UUID;
|
String UUID;
|
||||||
SegmentType segmentType;
|
SegmentType segmentType;
|
||||||
Pair<int, int> segment;
|
Pair<int, int> segment;
|
||||||
SkipType skipType;
|
SkipType skipType;
|
||||||
bool? hasSkipped;
|
bool hasSkipped;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
class SegmentItemModel {
|
class SegmentItemModel {
|
||||||
String cid;
|
String? cid;
|
||||||
String category;
|
String category;
|
||||||
String actionType;
|
String? actionType;
|
||||||
List<int> segment;
|
List<int> segment;
|
||||||
String uuid;
|
String uuid;
|
||||||
double videoDuration;
|
num? videoDuration;
|
||||||
|
|
||||||
SegmentItemModel({
|
SegmentItemModel({
|
||||||
required this.cid,
|
this.cid,
|
||||||
required this.category,
|
required this.category,
|
||||||
required this.actionType,
|
this.actionType,
|
||||||
required this.segment,
|
required this.segment,
|
||||||
required this.uuid,
|
required this.uuid,
|
||||||
required this.videoDuration,
|
this.videoDuration,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory SegmentItemModel.fromJson(Map<String, dynamic> json) =>
|
factory SegmentItemModel.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -20,9 +20,12 @@ class SegmentItemModel {
|
|||||||
cid: json["cid"],
|
cid: json["cid"],
|
||||||
category: json["category"],
|
category: json["category"],
|
||||||
actionType: json["actionType"],
|
actionType: json["actionType"],
|
||||||
segment:
|
segment: (json["segment"] as List)
|
||||||
(json["segment"] as List).map((e) => (e as num).round()).toList(),
|
.map((e) => ((e as num) * 1000).round())
|
||||||
|
.toList(),
|
||||||
uuid: json["UUID"],
|
uuid: json["UUID"],
|
||||||
videoDuration: (json["videoDuration"] as num).toDouble(),
|
videoDuration: json["videoDuration"] == null
|
||||||
|
? null
|
||||||
|
: (json["videoDuration"] as num) * 1000,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -611,7 +611,7 @@ class VideoDetailController extends GetxController
|
|||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.only(left: 16, right: 8),
|
contentPadding: const EdgeInsets.only(left: 16, right: 8),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'${Utils.formatDuration(item.segment.first)} 至 ${Utils.formatDuration(item.segment.second)}',
|
'${Utils.formatDuration(item.segment.first / 1000)} 至 ${Utils.formatDuration(item.segment.second / 1000)}',
|
||||||
style: const TextStyle(fontSize: 13),
|
style: const TextStyle(fontSize: 13),
|
||||||
),
|
),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
@@ -696,7 +696,8 @@ class VideoDetailController extends GetxController
|
|||||||
void handleSBData(List<SegmentItemModel> list) {
|
void handleSBData(List<SegmentItemModel> list) {
|
||||||
if (list.isNotEmpty) {
|
if (list.isNotEmpty) {
|
||||||
try {
|
try {
|
||||||
double duration = list.first.videoDuration;
|
final duration = list.first.videoDuration ??
|
||||||
|
plPlayerController.duration.value.inMilliseconds;
|
||||||
// segmentList
|
// segmentList
|
||||||
segmentList.addAll(list
|
segmentList.addAll(list
|
||||||
.where((item) =>
|
.where((item) =>
|
||||||
@@ -704,13 +705,12 @@ class VideoDetailController extends GetxController
|
|||||||
item.segment[1] >= item.segment[0])
|
item.segment[1] >= item.segment[0])
|
||||||
.map(
|
.map(
|
||||||
(item) {
|
(item) {
|
||||||
SegmentType segmentType = SegmentType
|
final segmentType = SegmentType.values.byName(item.category);
|
||||||
.values[plPlayerController.segmentTypes.indexOf(item.category)];
|
|
||||||
if (item.segment[0] == 0 && item.segment[1] == 0) {
|
if (item.segment[0] == 0 && item.segment[1] == 0) {
|
||||||
videoLabel.value +=
|
videoLabel.value +=
|
||||||
'${videoLabel.value.isNotEmpty ? '/' : ''}${segmentType.title}';
|
'${videoLabel.value.isNotEmpty ? '/' : ''}${segmentType.title}';
|
||||||
}
|
}
|
||||||
SkipType skipType =
|
var skipType =
|
||||||
plPlayerController.blockSettings[segmentType.index].second;
|
plPlayerController.blockSettings[segmentType.index].second;
|
||||||
if (skipType != SkipType.showOnly) {
|
if (skipType != SkipType.showOnly) {
|
||||||
if (item.segment[1] == item.segment[0] ||
|
if (item.segment[1] == item.segment[0] ||
|
||||||
@@ -733,7 +733,7 @@ class VideoDetailController extends GetxController
|
|||||||
if (positionSubscription == null &&
|
if (positionSubscription == null &&
|
||||||
!isShowCover.value &&
|
!isShowCover.value &&
|
||||||
plPlayerController.videoPlayerController != null) {
|
plPlayerController.videoPlayerController != null) {
|
||||||
final currPost = plPlayerController.position.value.inSeconds;
|
final currPost = plPlayerController.position.value.inMilliseconds;
|
||||||
if (currPost > segmentModel.segment.first &&
|
if (currPost > segmentModel.segment.first &&
|
||||||
currPost < segmentModel.segment.second) {
|
currPost < segmentModel.segment.second) {
|
||||||
if (segmentModel.skipType == SkipType.alwaysSkip) {
|
if (segmentModel.skipType == SkipType.alwaysSkip) {
|
||||||
@@ -760,8 +760,7 @@ class VideoDetailController extends GetxController
|
|||||||
).toList());
|
).toList());
|
||||||
|
|
||||||
// _segmentProgressList
|
// _segmentProgressList
|
||||||
segmentProgressList ??= <Segment>[];
|
(segmentProgressList ??= <Segment>[]).addAll(segmentList.map((e) {
|
||||||
segmentProgressList!.addAll(segmentList.map((e) {
|
|
||||||
double start = (e.segment.first / duration).clamp(0.0, 1.0);
|
double start = (e.segment.first / duration).clamp(0.0, 1.0);
|
||||||
double end = (e.segment.second / duration).clamp(0.0, 1.0);
|
double end = (e.segment.second / duration).clamp(0.0, 1.0);
|
||||||
return Segment(start, end, _getColor(e.segmentType));
|
return Segment(start, end, _getColor(e.segmentType));
|
||||||
@@ -790,16 +789,18 @@ class VideoDetailController extends GetxController
|
|||||||
int currentPos = position.inSeconds;
|
int currentPos = position.inSeconds;
|
||||||
if (currentPos != _lastPos) {
|
if (currentPos != _lastPos) {
|
||||||
_lastPos = currentPos;
|
_lastPos = currentPos;
|
||||||
|
final msPos = currentPos * 1000;
|
||||||
for (SegmentModel item in segmentList) {
|
for (SegmentModel item in segmentList) {
|
||||||
// if (kDebugMode) {
|
// if (kDebugMode) {
|
||||||
// debugPrint(
|
// debugPrint(
|
||||||
// '${position.inSeconds},,${item.segment.first},,${item.segment.second},,${item.skipType.name},,${item.hasSkipped}');
|
// '${position.inSeconds},,${item.segment.first},,${item.segment.second},,${item.skipType.name},,${item.hasSkipped}');
|
||||||
// }
|
// }
|
||||||
if (item.segment.first == position.inSeconds) {
|
if (msPos <= item.segment.first &&
|
||||||
|
item.segment.first <= msPos + 1000) {
|
||||||
if (item.skipType == SkipType.alwaysSkip) {
|
if (item.skipType == SkipType.alwaysSkip) {
|
||||||
onSkip(item);
|
onSkip(item);
|
||||||
} else if (item.skipType == SkipType.skipOnce &&
|
} else if (item.skipType == SkipType.skipOnce &&
|
||||||
item.hasSkipped != true) {
|
item.hasSkipped) {
|
||||||
item.hasSkipped = true;
|
item.hasSkipped = true;
|
||||||
onSkip(item);
|
onSkip(item);
|
||||||
} else if (item.skipType == SkipType.skipManually) {
|
} else if (item.skipType == SkipType.skipManually) {
|
||||||
@@ -905,7 +906,7 @@ class VideoDetailController extends GetxController
|
|||||||
try {
|
try {
|
||||||
plPlayerController.danmakuController?.clear();
|
plPlayerController.danmakuController?.clear();
|
||||||
await plPlayerController.videoPlayerController
|
await plPlayerController.videoPlayerController
|
||||||
?.seek(Duration(seconds: item.segment.second));
|
?.seek(Duration(milliseconds: item.segment.second));
|
||||||
if (isSkip) {
|
if (isSkip) {
|
||||||
if (GStorage.blockToast) {
|
if (GStorage.blockToast) {
|
||||||
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
|
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
|
||||||
|
|||||||
@@ -325,8 +325,8 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
|||||||
int start = max(
|
int start = max(
|
||||||
0,
|
0,
|
||||||
(list![index].segment.first * 1000)
|
(list![index].segment.first * 1000)
|
||||||
.toInt() -
|
.round() -
|
||||||
2,
|
2000,
|
||||||
);
|
);
|
||||||
await widget
|
await widget
|
||||||
.plPlayerController.videoPlayerController!
|
.plPlayerController.videoPlayerController!
|
||||||
@@ -349,7 +349,7 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
|||||||
Duration(
|
Duration(
|
||||||
milliseconds:
|
milliseconds:
|
||||||
(list![index].segment.second * 1000)
|
(list![index].segment.second * 1000)
|
||||||
.toInt(),
|
.round(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,12 +300,10 @@ class PlPlayerController {
|
|||||||
late final List<Pair<SegmentType, SkipType>> blockSettings =
|
late final List<Pair<SegmentType, SkipType>> blockSettings =
|
||||||
GStorage.blockSettings;
|
GStorage.blockSettings;
|
||||||
late final List<Color> blockColor = GStorage.blockColor;
|
late final List<Color> blockColor = GStorage.blockColor;
|
||||||
late final List<String> segmentTypes =
|
late final Set<String> enableList = blockSettings
|
||||||
SegmentType.values.map((item) => item.name).toList();
|
|
||||||
late final List<String> enableList = blockSettings
|
|
||||||
.where((item) => item.second != SkipType.disable)
|
.where((item) => item.second != SkipType.disable)
|
||||||
.map((item) => item.first.name)
|
.map((item) => item.first.name)
|
||||||
.toList();
|
.toSet();
|
||||||
late final blockServer = GStorage.blockServer;
|
late final blockServer = GStorage.blockServer;
|
||||||
|
|
||||||
// settings
|
// settings
|
||||||
|
|||||||
@@ -455,22 +455,16 @@ class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static String formatDuration(num seconds) {
|
static String formatDuration(num seconds) {
|
||||||
int hours = seconds ~/ 3600;
|
int h = seconds ~/ 3600;
|
||||||
int minutes = (seconds % 3600) ~/ 60;
|
seconds %= 3600;
|
||||||
num remainingSeconds = seconds % 60;
|
int m = seconds ~/ 60;
|
||||||
if (remainingSeconds is double) {
|
seconds %= 60;
|
||||||
remainingSeconds = remainingSeconds.toPrecision(3);
|
String sms = seconds is double
|
||||||
}
|
? seconds.toStringAsFixed(3).padLeft(6, '0')
|
||||||
|
: seconds.toString().padLeft(2, '0');
|
||||||
String minutesStr = minutes.toString().padLeft(2, '0');
|
return h == 0
|
||||||
String secondsStr = remainingSeconds.toString().padLeft(2, '0');
|
? "${m.toString().padLeft(2, '0')}:$sms"
|
||||||
|
: "${h.toString().padLeft(2, '0')}:${m.toString().padLeft(2, '0')}:$sms";
|
||||||
if (hours > 0) {
|
|
||||||
String hoursStr = hours.toString().padLeft(2, '0');
|
|
||||||
return "$hoursStr:$minutesStr:$secondsStr";
|
|
||||||
} else {
|
|
||||||
return "$minutesStr:$secondsStr";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int duration(String duration) {
|
static int duration(String duration) {
|
||||||
|
|||||||
Reference in New Issue
Block a user