opt change episode

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-05 19:56:22 +08:00
parent 170b2aa6d9
commit 80a4c8c24d
10 changed files with 79 additions and 81 deletions

View File

@@ -5,7 +5,6 @@ import 'package:PiliPlus/models_new/media_list/ogv_info.dart';
import 'package:PiliPlus/models_new/media_list/page.dart'; import 'package:PiliPlus/models_new/media_list/page.dart';
import 'package:PiliPlus/models_new/media_list/rights.dart'; import 'package:PiliPlus/models_new/media_list/rights.dart';
import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; import 'package:PiliPlus/models_new/video/video_detail/episode.dart';
import 'package:PiliPlus/utils/extension.dart';
class MediaListItemModel extends BaseEpisodeItem { class MediaListItemModel extends BaseEpisodeItem {
@override @override
@@ -35,6 +34,8 @@ class MediaListItemModel extends BaseEpisodeItem {
bool? forbidFav; bool? forbidFav;
int? moreType; int? moreType;
int? businessOid; int? businessOid;
@override
int? get cid => pages?.firstOrNull?.id;
MediaListItemModel({ MediaListItemModel({
super.aid, super.aid,
@@ -105,6 +106,5 @@ class MediaListItemModel extends BaseEpisodeItem {
forbidFav = json['forbid_fav'] as bool?; forbidFav = json['forbid_fav'] as bool?;
moreType = json['more_type'] as int?; moreType = json['more_type'] as int?;
businessOid = json['business_oid'] as int?; businessOid = json['business_oid'] as int?;
cid = pages.getOrNull((page ?? 1) - 1)?.id;
} }
} }

View File

@@ -24,7 +24,7 @@ mixin BaseFavController
bool get isOwner; bool get isOwner;
int get mediaId; int get mediaId;
ValueChanged<int>? updateLength; ValueChanged<int>? updateCount;
void onViewFav(FavDetailItemModel item, int? index); void onViewFav(FavDetailItemModel item, int? index);
@@ -37,7 +37,7 @@ mixin BaseFavController
loadingState loadingState
..value.data!.removeAt(index) ..value.data!.removeAt(index)
..refresh(); ..refresh();
updateLength?.call(1); updateCount?.call(1);
SmartDialog.showToast('取消收藏'); SmartDialog.showToast('取消收藏');
} else { } else {
SmartDialog.showToast(result['msg']); SmartDialog.showToast(result['msg']);
@@ -59,7 +59,7 @@ mixin BaseFavController
delIds: mediaId.toString(), delIds: mediaId.toString(),
); );
if (result['status']) { if (result['status']) {
updateLength?.call(removeList.length); updateCount?.call(removeList.length);
afterDelete(removeList); afterDelete(removeList);
SmartDialog.showToast('取消收藏'); SmartDialog.showToast('取消收藏');
} else { } else {
@@ -124,7 +124,7 @@ class FavDetailController
} }
@override @override
ValueChanged<int>? get updateLength => ValueChanged<int>? get updateCount =>
(count) => folderInfo (count) => folderInfo
..value.mediaCount -= count ..value.mediaCount -= count
..refresh(); ..refresh();
@@ -147,9 +147,6 @@ class FavDetailController
if (element.ugc?.firstCid == null) { if (element.ugc?.firstCid == null) {
continue; continue;
} else { } else {
if (element.bvid != list.first.bvid) {
SmartDialog.showToast('已跳过不支持播放的视频');
}
onViewFav(element, null); onViewFav(element, null);
break; break;
} }

View File

@@ -76,6 +76,7 @@ class _LaterViewChildPageState extends State<LaterViewChildPage>
} }
var videoItem = response[index]; var videoItem = response[index];
return VideoCardHLater( return VideoCardHLater(
index: index,
videoItem: videoItem, videoItem: videoItem,
ctr: _laterController, ctr: _laterController,
onViewLater: (cid) { onViewLater: (cid) {
@@ -97,12 +98,6 @@ class _LaterViewChildPageState extends State<LaterViewChildPage>
}, },
); );
}, },
onRemove: () => _laterController.toViewDel(
context,
index,
videoItem.aid,
onSuccess: () => _laterController.updateLength?.call(1),
),
); );
}, },
childCount: response!.length, childCount: response!.length,

View File

@@ -22,7 +22,7 @@ mixin BaseLaterController
CommonListController<LaterData, LaterItemModel>, CommonListController<LaterData, LaterItemModel>,
CommonMultiSelectMixin<LaterItemModel>, CommonMultiSelectMixin<LaterItemModel>,
DeleteItemMixin<LaterData, LaterItemModel> { DeleteItemMixin<LaterData, LaterItemModel> {
ValueChanged<int>? updateLength; ValueChanged<int>? updateCount;
@override @override
void onRemove() { void onRemove() {
@@ -37,7 +37,7 @@ mixin BaseLaterController
aids: removeList.map((item) => item.aid).join(','), aids: removeList.map((item) => item.aid).join(','),
); );
if (res['status']) { if (res['status']) {
updateLength?.call(removeList.length); updateCount?.call(removeList.length);
afterDelete(removeList); afterDelete(removeList);
} }
SmartDialog.dismiss(); SmartDialog.dismiss();
@@ -50,9 +50,8 @@ mixin BaseLaterController
void toViewDel( void toViewDel(
BuildContext context, BuildContext context,
int index, int index,
int? aid, { int? aid,
VoidCallback? onSuccess, ) {
}) {
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
@@ -75,7 +74,7 @@ mixin BaseLaterController
loadingState loadingState
..value.data!.removeAt(index) ..value.data!.removeAt(index)
..refresh(); ..refresh();
onSuccess?.call(); updateCount?.call(1);
} }
SmartDialog.showToast(res['msg']); SmartDialog.showToast(res['msg']);
}, },
@@ -169,9 +168,6 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel>
if (item.cid == null || item.pgcLabel?.isNotEmpty == true) { if (item.cid == null || item.pgcLabel?.isNotEmpty == true) {
continue; continue;
} else { } else {
if (item.bvid != list.first.bvid) {
SmartDialog.showToast('已跳过不支持播放的视频');
}
PageUtils.toVideoPage( PageUtils.toVideoPage(
bvid: item.bvid, bvid: item.bvid,
cid: item.cid!, cid: item.cid!,
@@ -192,7 +188,7 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel>
} }
@override @override
ValueChanged<int>? get updateLength => ValueChanged<int>? get updateCount =>
(count) => baseCtr.counts[laterViewType] = (count) => baseCtr.counts[laterViewType] =
baseCtr.counts[laterViewType]! - count; baseCtr.counts[laterViewType]! - count;

View File

@@ -21,14 +21,14 @@ class VideoCardHLater extends StatelessWidget {
const VideoCardHLater({ const VideoCardHLater({
super.key, super.key,
required this.ctr, required this.ctr,
required this.index,
required this.videoItem, required this.videoItem,
this.onViewLater, required this.onViewLater,
required this.onRemove,
}); });
final int index;
final BaseLaterController ctr; final BaseLaterController ctr;
final LaterItemModel videoItem; final LaterItemModel videoItem;
final ValueChanged<int>? onViewLater; final ValueChanged<int> onViewLater;
final VoidCallback onRemove;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -72,7 +72,7 @@ class VideoCardHLater extends StatelessWidget {
bvid: videoItem.bvid, bvid: videoItem.bvid,
); );
if (cid != null) { if (cid != null) {
onViewLater!(cid); onViewLater(cid);
} }
} catch (err) { } catch (err) {
SmartDialog.showToast(err.toString()); SmartDialog.showToast(err.toString());
@@ -192,7 +192,7 @@ class VideoCardHLater extends StatelessWidget {
iconButton( iconButton(
tooltip: '移除', tooltip: '移除',
context: context, context: context,
onPressed: onRemove, onPressed: () => ctr..toViewDel(context, index, videoItem.aid),
icon: Icons.clear, icon: Icons.clear,
iconColor: theme.colorScheme.outline, iconColor: theme.colorScheme.outline,
bgColor: Colors.transparent, bgColor: Colors.transparent,

View File

@@ -38,6 +38,7 @@ class _LaterSearchPageState
} }
final item = list[index]; final item = list[index];
return VideoCardHLater( return VideoCardHLater(
index: index,
videoItem: item, videoItem: item,
ctr: controller, ctr: controller,
onViewLater: (cid) { onViewLater: (cid) {
@@ -57,11 +58,6 @@ class _LaterSearchPageState
}, },
); );
}, },
onRemove: () => controller.toViewDel(
context,
index,
item.aid!,
),
); );
}), }),
); );

View File

@@ -11,7 +11,6 @@ import 'package:PiliPlus/pages/common/common_list_controller.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class MemberVideoCtr class MemberVideoCtr
@@ -186,9 +185,6 @@ class MemberVideoCtr
if (element.cid == null) { if (element.cid == null) {
continue; continue;
} else { } else {
if (element.bvid != list.first.bvid) {
SmartDialog.showToast('已跳过不支持播放的视频');
}
bool desc = seasonId != null ? false : true; bool desc = seasonId != null ? false : true;
desc = desc =
(seasonId != null || seriesId != null) && (seasonId != null || seriesId != null) &&

View File

@@ -534,17 +534,16 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
/// 播放上一个 /// 播放上一个
@override @override
bool prevPlay([bool skipPages = false]) { bool prevPlay([bool skipPart = false]) {
final List<BaseEpisodeItem> episodes = <BaseEpisodeItem>[]; final List<BaseEpisodeItem> episodes = <BaseEpisodeItem>[];
bool isPages = false; bool isPart = false;
final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag); final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
final videoDetail = this.videoDetail.value; final videoDetail = this.videoDetail.value;
if (!skipPages && (videoDetail.pages?.length ?? 0) > 1) { if (!skipPart && (videoDetail.pages?.length ?? 0) > 1) {
isPages = true; isPart = true;
final List<Part> pages = videoDetail.pages!; episodes.addAll(videoDetail.pages!);
episodes.addAll(pages);
} else if (videoDetailCtr.isPlayAll) { } else if (videoDetailCtr.isPlayAll) {
episodes.addAll(videoDetailCtr.mediaList); episodes.addAll(videoDetailCtr.mediaList);
} else if (videoDetail.ugcSeason != null) { } else if (videoDetail.ugcSeason != null) {
@@ -559,18 +558,19 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
final int currentIndex = episodes.indexWhere( final int currentIndex = episodes.indexWhere(
(e) => (e) =>
e.cid == e.cid ==
(skipPages (skipPart
? videoDetail.isPageReversed == true ? videoDetail.isPageReversed == true
? videoDetail.pages!.last.cid ? videoDetail.pages!.last.cid
: videoDetail.pages!.first.cid : videoDetail.pages!.first.cid
: cid.value), : this.cid.value),
); );
int prevIndex = currentIndex - 1; int prevIndex = currentIndex - 1;
final PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat; final PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
// 列表循环 // 列表循环
if (prevIndex < 0) { if (prevIndex < 0) {
if (isPages && if (isPart &&
(videoDetailCtr.isPlayAll || videoDetail.ugcSeason != null)) { (videoDetailCtr.isPlayAll || videoDetail.ugcSeason != null)) {
return prevPlay(true); return prevPlay(true);
} }
@@ -580,22 +580,36 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
return false; return false;
} }
} }
onChangeEpisode(episodes[prevIndex]);
return true; int? cid = episodes[prevIndex].cid;
while (cid == null) {
prevIndex--;
if (prevIndex < 0) {
return false;
}
cid = episodes[prevIndex].cid;
}
if (cid != this.cid.value) {
onChangeEpisode(episodes[prevIndex]);
return true;
} else {
return false;
}
} }
/// 列表循环或者顺序播放时,自动播放下一个 /// 列表循环或者顺序播放时,自动播放下一个
@override @override
bool nextPlay([bool skipPages = false]) { bool nextPlay([bool skipPart = false]) {
try { try {
final List<BaseEpisodeItem> episodes = <BaseEpisodeItem>[]; final List<BaseEpisodeItem> episodes = <BaseEpisodeItem>[];
bool isPages = false; bool isPart = false;
final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag); final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
final videoDetail = this.videoDetail.value; final videoDetail = this.videoDetail.value;
// part -> playall -> season // part -> playall -> season
if (!skipPages && (videoDetail.pages?.length ?? 0) > 1) { if (!skipPart && (videoDetail.pages?.length ?? 0) > 1) {
isPages = true; isPart = true;
final List<Part> pages = videoDetail.pages!; final List<Part> pages = videoDetail.pages!;
episodes.addAll(pages); episodes.addAll(pages);
} else if (videoDetailCtr.isPlayAll) { } else if (videoDetailCtr.isPlayAll) {
@@ -623,16 +637,16 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
final int currentIndex = episodes.indexWhere( final int currentIndex = episodes.indexWhere(
(e) => (e) =>
e.cid == e.cid ==
(skipPages (skipPart
? videoDetail.isPageReversed == true ? videoDetail.isPageReversed == true
? videoDetail.pages!.last.cid ? videoDetail.pages!.last.cid
: videoDetail.pages!.first.cid : videoDetail.pages!.first.cid
: videoDetailCtr.cid.value), : this.cid.value),
); );
int nextIndex = currentIndex + 1; int nextIndex = currentIndex + 1;
if (!isPages && if (!isPart &&
videoDetailCtr.isPlayAll && videoDetailCtr.isPlayAll &&
currentIndex == episodes.length - 2) { currentIndex == episodes.length - 2) {
videoDetailCtr.getMediaList(); videoDetailCtr.getMediaList();
@@ -640,7 +654,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
// 列表循环 // 列表循环
if (nextIndex >= episodes.length) { if (nextIndex >= episodes.length) {
if (isPages && if (isPart &&
(videoDetailCtr.isPlayAll || videoDetail.ugcSeason != null)) { (videoDetailCtr.isPlayAll || videoDetail.ugcSeason != null)) {
return nextPlay(true); return nextPlay(true);
} }
@@ -655,18 +669,21 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
} }
} }
int cid = episodes[nextIndex].cid!; int? cid = episodes[nextIndex].cid;
while (cid == null) {
while (cid == -1) {
SmartDialog.showToast('当前视频暂不支持播放,自动跳过');
nextIndex++; nextIndex++;
if (nextIndex >= episodes.length) { if (nextIndex >= episodes.length) {
return false; return false;
} }
cid = episodes[nextIndex].cid!; cid = episodes[nextIndex].cid;
}
if (cid != this.cid.value) {
onChangeEpisode(episodes[nextIndex]);
return true;
} else {
return false;
} }
onChangeEpisode(episodes[nextIndex]);
return true;
} catch (_) { } catch (_) {
return false; return false;
} }

View File

@@ -2011,7 +2011,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
} }
void showEpisodes([int? index, season, episodes, bvid, aid, cid]) { void showEpisodes([int? index, season, episodes, bvid, aid, cid]) {
if (bvid == null) { if (cid == null) {
videoDetailController.showMediaListPanel(context); videoDetailController.showMediaListPanel(context);
return; return;
} }

View File

@@ -7,7 +7,6 @@ import 'package:PiliPlus/common/widgets/progress_bar/audio_video_progress_bar.da
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/models/common/super_resolution_type.dart'; import 'package:PiliPlus/models/common/super_resolution_type.dart';
import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; import 'package:PiliPlus/models_new/video/video_detail/episode.dart';
import 'package:PiliPlus/models_new/video/video_detail/page.dart';
import 'package:PiliPlus/models_new/video/video_detail/section.dart'; import 'package:PiliPlus/models_new/video/video_detail/section.dart';
import 'package:PiliPlus/models_new/video/video_shot/data.dart'; import 'package:PiliPlus/models_new/video/video_shot/data.dart';
import 'package:PiliPlus/pages/common/common_intro_controller.dart'; import 'package:PiliPlus/pages/common/common_intro_controller.dart';
@@ -257,11 +256,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// 动态构建底部控制条 // 动态构建底部控制条
Widget buildBottomControl() { Widget buildBottomControl() {
final videoDetail = introController.videoDetail.value; final videoDetail = introController.videoDetail.value;
bool isSeason = videoDetail.ugcSeason != null; final isSeason = videoDetail.ugcSeason != null;
bool isPage = videoDetail.pages != null && videoDetail.pages!.length > 1; final isPart = videoDetail.pages != null && videoDetail.pages!.length > 1;
bool isPgc = pgcIntroController != null; final isPgc = pgcIntroController != null;
bool anySeason = isSeason || isPage || isPgc; final anySeason = isSeason || isPart || isPgc;
double widgetWidth = isFullScreen && context.isLandscape ? 42 : 35; final isPlayAll = widget.videoDetailController?.isPlayAll == true;
final double widgetWidth = isFullScreen && context.isLandscape ? 42 : 35;
Map<BottomControlType, Widget> videoProgressWidgets = { Map<BottomControlType, Widget> videoProgressWidgets = {
/// 上一集 /// 上一集
BottomControlType.pre: Container( BottomControlType.pre: Container(
@@ -460,7 +462,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
color: Colors.white, color: Colors.white,
), ),
onTap: () { onTap: () {
if (!anySeason || widget.videoDetailController?.isPlayAll == true) { // part -> playAll -> season(pgc)
if (!anySeason || !isPart) {
widget.showEpisodes?.call(); widget.showEpisodes?.call();
return; return;
} }
@@ -481,9 +484,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
} }
} }
} }
} else if (isPage) { } else if (isPart) {
final List<Part> pages = videoDetail.pages!; episodes = videoDetail.pages!;
episodes = pages;
} else if (isPgc) { } else if (isPgc) {
episodes = pgcIntroController!.pgcItem.episodes!; episodes = pgcIntroController!.pgcItem.episodes!;
} }
@@ -493,7 +495,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
isSeason ? null : episodes, isSeason ? null : episodes,
bvid, bvid,
IdUtils.bv2av(bvid), IdUtils.bv2av(bvid),
isSeason && isPage isSeason && isPart
? widget.videoDetailController?.seasonCid ?? currentCid ? widget.videoDetailController?.seasonCid ?? currentCid
: currentCid, : currentCid,
); );
@@ -642,7 +644,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
List<BottomControlType> userSpecifyItemLeft = [ List<BottomControlType> userSpecifyItemLeft = [
BottomControlType.playOrPause, BottomControlType.playOrPause,
BottomControlType.time, BottomControlType.time,
if (anySeason || widget.videoDetailController?.isPlayAll == true) ...[ if (anySeason || isPlayAll) ...[
BottomControlType.pre, BottomControlType.pre,
BottomControlType.next, BottomControlType.next,
], ],
@@ -652,8 +654,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
BottomControlType.dmChart, BottomControlType.dmChart,
BottomControlType.superResolution, BottomControlType.superResolution,
BottomControlType.viewPoints, BottomControlType.viewPoints,
if (anySeason || widget.videoDetailController?.isPlayAll == true) if (anySeason || isPlayAll) BottomControlType.episode,
BottomControlType.episode,
if (isFullScreen) BottomControlType.fit, if (isFullScreen) BottomControlType.fit,
BottomControlType.subtitle, BottomControlType.subtitle,
BottomControlType.speed, BottomControlType.speed,