diff --git a/lib/http/user.dart b/lib/http/user.dart index 63f6bf66..99888aea 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -516,4 +516,34 @@ class UserHttp { }; } } + + // 解析up投稿 + static Future parseUpArchiveVideo({ + required int mid, + required int oid, + required String bvid, + String sortField = 'pubtime', + }) async { + var res = await Request().get( + 'https://www.bilibili.com/list/$mid', + data: { + 'oid': oid, + 'bvid': bvid, + 'sort_field': sortField, + }, + ); + String scriptContent = + extractScriptContents(parse(res.data).body!.outerHtml)[0]; + int startIndex = scriptContent.indexOf('{'); + int endIndex = scriptContent.lastIndexOf('};'); + String jsonContent = scriptContent.substring(startIndex, endIndex + 1); + // 解析JSON字符串为Map + Map jsonData = json.decode(jsonContent); + return { + 'status': true, + 'data': jsonData['resourceList'] + .map((e) => MediaVideoItemModel.fromJson(e)) + .toList() + }; + } } diff --git a/lib/pages/member_archive/controller.dart b/lib/pages/member_archive/controller.dart index 92f95da6..61816ed5 100644 --- a/lib/pages/member_archive/controller.dart +++ b/lib/pages/member_archive/controller.dart @@ -1,14 +1,16 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/member.dart'; +import 'package:pilipala/http/search.dart'; import 'package:pilipala/models/member/archive.dart'; import 'package:pilipala/utils/global_data_cache.dart'; +import 'package:pilipala/utils/utils.dart'; class MemberArchiveController extends GetxController { final ScrollController scrollController = ScrollController(); late int mid; int pn = 1; - int count = 0; + RxInt count = 0.obs; RxMap currentOrder = {}.obs; RxList> orderList = [ {'type': 'pubdate', 'label': '最新发布'}, @@ -50,11 +52,11 @@ class MemberArchiveController extends GetxController { if (res['status']) { if (type == 'init') { archivesList.value = res['data'].list.vlist; + count.value = res['data'].page['count']; } if (type == 'onLoad') { archivesList.addAll(res['data'].list.vlist); } - count = res['data'].page['count']; pn += 1; } isLoading.value = false; @@ -76,4 +78,29 @@ class MemberArchiveController extends GetxController { Future onLoad() async { getMemberArchive('onLoad'); } + + Future toViewPlayAll() async { + final VListItemModel firstItem = archivesList.first; + final String bvid = firstItem.bvid!; + final int cid = await SearchHttp.ab2c(bvid: bvid); + final String heroTag = Utils.makeHeroTag(bvid); + late Map sortFieldMap = { + 'pubdate': 'pubtime', + 'click': 'play', + 'fav': 'fav', + }; + Get.toNamed( + '/video?bvid=${firstItem.bvid}&cid=$cid', + arguments: { + 'videoItem': firstItem, + 'heroTag': heroTag, + 'sourceType': 'up_archive', + 'oid': firstItem.aid, + 'favTitle': '${firstItem.owner!.name!} - ${currentOrder['label']!}', + 'favInfo': firstItem, + 'count': count.value, + 'sortField': sortFieldMap[currentOrder['type']], + }, + ); + } } diff --git a/lib/pages/member_archive/view.dart b/lib/pages/member_archive/view.dart index 86ff9940..6963dad6 100644 --- a/lib/pages/member_archive/view.dart +++ b/lib/pages/member_archive/view.dart @@ -135,6 +135,15 @@ class _MemberArchivePageState extends State { ), ], ), + floatingActionButton: Obx( + () => _memberArchivesController.count > 0 + ? FloatingActionButton.extended( + onPressed: _memberArchivesController.toViewPlayAll, + label: const Text('播放全部'), + icon: const Icon(Icons.playlist_play), + ) + : const SizedBox(), + ), ); } } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 3fead9c7..925f770b 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -119,6 +119,7 @@ class VideoDetailController extends GetxController List mediaList = []; RxBool isWatchLaterVisible = false.obs; RxString watchLaterTitle = ''.obs; + RxInt watchLaterCount = 0.obs; @override void onInit() { @@ -170,7 +171,7 @@ class VideoDetailController extends GetxController sourceType.value = argMap['sourceType'] ?? 'normal'; isWatchLaterVisible.value = - sourceType.value == 'watchLater' || sourceType.value == 'fav'; + ['watchLater', 'fav', 'up_archive'].contains(sourceType.value); if (sourceType.value == 'watchLater') { watchLaterTitle.value = '稍后再看'; fetchMediaList(); @@ -179,6 +180,11 @@ class VideoDetailController extends GetxController watchLaterTitle.value = argMap['favTitle']; queryFavVideoList(); } + if (sourceType.value == 'up_archive') { + watchLaterTitle.value = argMap['favTitle']; + watchLaterCount.value = argMap['count']; + queryArchiveVideoList(); + } tabCtr.addListener(() { onTabChanged(); }); @@ -585,7 +591,9 @@ class VideoDetailController extends GetxController } void toggeleWatchLaterVisible(bool val) { - if (sourceType.value == 'watchLater' || sourceType.value == 'fav') { + if (sourceType.value == 'watchLater' || + sourceType.value == 'fav' || + sourceType.value == 'up_archive') { isWatchLaterVisible.value = !isWatchLaterVisible.value; } } @@ -616,8 +624,19 @@ class VideoDetailController extends GetxController changeMediaList: changeMediaList, panelTitle: watchLaterTitle.value, bvid: bvid, - mediaId: Get.arguments['mediaId'], + mediaId: [ + 'watchLater', + 'fav', + ].contains(sourceType.value) + ? Get.arguments['mediaId'] + : Get.arguments['favInfo'].owner.mid, hasMore: mediaList.length != Get.arguments['count'], + type: [ + 'watchLater', + 'fav', + ].contains(sourceType.value) + ? 3 + : 1, ); }); replyReplyBottomSheetCtr?.closed.then((value) { @@ -667,6 +686,21 @@ class VideoDetailController extends GetxController } } + Future queryArchiveVideoList() async { + final Map argMap = Get.arguments; + var favInfo = argMap['favInfo']; + var sortField = argMap['sortField']; + var res = await UserHttp.parseUpArchiveVideo( + mid: favInfo.owner.mid, + oid: oid.value, + bvid: bvid, + sortField: sortField, + ); + if (res['status']) { + mediaList = res['data']; + } + } + // 监听tabBarView切换 void onTabChanged() { isWatchLaterVisible.value = tabCtr.index == 0; diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 7fe76745..57523dd0 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -783,7 +783,8 @@ class _VideoDetailPageState extends State Obx( () => Visibility( visible: vdCtr.sourceType.value == 'watchLater' || - vdCtr.sourceType.value == 'fav', + vdCtr.sourceType.value == 'fav' || + vdCtr.sourceType.value == 'up_archive', child: AnimatedPositioned( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, @@ -815,17 +816,21 @@ class _VideoDetailPageState extends State child: Row(children: [ const Icon(Icons.playlist_play, size: 24), const SizedBox(width: 10), - Text( - vdCtr.watchLaterTitle.value, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .onSecondaryContainer, - fontWeight: FontWeight.bold, - letterSpacing: 0.2, + Expanded( + child: Text( + vdCtr.watchLaterTitle.value, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .onSecondaryContainer, + fontWeight: FontWeight.bold, + letterSpacing: 0.2, + ), ), ), - const Spacer(), + const SizedBox(width: 50), const Icon(Icons.keyboard_arrow_up_rounded, size: 26), ]), ), diff --git a/lib/pages/video/detail/widgets/watch_later_list.dart b/lib/pages/video/detail/widgets/watch_later_list.dart index 8e83af4e..eda6cf3e 100644 --- a/lib/pages/video/detail/widgets/watch_later_list.dart +++ b/lib/pages/video/detail/widgets/watch_later_list.dart @@ -19,8 +19,9 @@ class MediaListPanel extends StatefulWidget { this.changeMediaList, this.panelTitle, this.bvid, - this.mediaId, + required this.mediaId, this.hasMore = false, + required this.type, super.key, }); @@ -29,8 +30,9 @@ class MediaListPanel extends StatefulWidget { final Function? changeMediaList; final String? panelTitle; final String? bvid; - final int? mediaId; + final int mediaId; final bool hasMore; + final int type; @override State createState() => _MediaListPanelState(); @@ -59,8 +61,8 @@ class _MediaListPanelState extends State { void loadMore() async { var res = await UserHttp.getMediaList( - type: 3, - bizId: widget.mediaId!, + type: widget.type, + bizId: widget.mediaId, ps: 20, oid: mediaList.last.id, );