mod: 合集season数据解析

This commit is contained in:
guozhigq
2023-06-24 12:14:25 +08:00
parent 4a94b6ba8c
commit f113cdc364
7 changed files with 231 additions and 5 deletions

View File

@ -60,6 +60,7 @@ class VideoDetailData {
List<Page>? pages;
Subtitle? subtitle;
// Label? label;
UgcSeason? ugcSeason;
bool? isSeasonDisplay;
UserGarb? userGarb;
HonorReply? honorReply;
@ -94,6 +95,7 @@ class VideoDetailData {
this.noCache,
this.pages,
this.subtitle,
this.ugcSeason,
this.isSeasonDisplay,
this.userGarb,
this.honorReply,
@ -137,6 +139,9 @@ class VideoDetailData {
: List<Page>.from(json["pages"]!.map((e) => Page.fromJson(e)));
subtitle =
json["subtitle"] == null ? null : Subtitle.fromJson(json["subtitle"]);
ugcSeason = json["ugc_season"] != null
? UgcSeason.fromJson(json["ugc_season"])
: null;
isSeasonDisplay = json["is_season_display"];
userGarb =
json["user_garb"] == null ? null : UserGarb.fromJson(json["user_garb"]);
@ -522,3 +527,111 @@ class UserGarb {
}
class Label {}
class UgcSeason {
UgcSeason({
this.id,
this.title,
this.cover,
this.mid,
this.intro,
this.signState,
this.attribute,
this.sections,
this.stat,
this.epCount,
this.seasonType,
this.isPaySeason,
});
int? id;
String? title;
String? cover;
int? mid;
String? intro;
int? signState;
int? attribute;
List<SectionItem>? sections;
Stat? stat;
int? epCount;
int? seasonType;
bool? isPaySeason;
UgcSeason.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
cover = json['cover'];
mid = json['mid'];
intro = json['intro'];
signState = json['sign_state'];
attribute = json['attribute'];
sections = json['sections']
.map<SectionItem>((e) => SectionItem.fromJson(e))
.toList();
stat = Stat.fromJson(json['stat']);
epCount = json['ep_count'];
seasonType = json['season_type'];
isPaySeason = json['is_pay_count'];
}
}
class SectionItem {
SectionItem({
this.seasonId,
this.id,
this.title,
this.type,
this.episodes,
});
int? seasonId;
int? id;
String? title;
int? type;
List<EpisodeItem>? episodes;
SectionItem.fromJson(Map<String, dynamic> json) {
seasonId = json['season_id'];
id = json['id'];
title = json['title'];
type = json['type'];
episodes = json['episodes']
.map<EpisodeItem>((e) => EpisodeItem.fromJson(e))
.toList();
}
}
class EpisodeItem {
EpisodeItem({
this.seasonId,
this.sectionId,
this.id,
this.aid,
this.cid,
this.title,
this.attribute,
this.page,
this.bvid,
});
int? seasonId;
int? sectionId;
int? id;
int? aid;
int? cid;
String? title;
int? attribute;
Page? page;
String? bvid;
EpisodeItem.fromJson(Map<String, dynamic> json) {
seasonId = json['season_id'];
sectionId = json['sectionId'];
id = json['id'];
aid = json['aid'];
cid = json['cid'];
title = json['title'];
attribute = json['attribute'];
page = Page.fromJson(json['page']);
bvid = json['bvid'];
}
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/utils/utils.dart';
@ -11,7 +12,10 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
itemBuilder: (context, index) {
var i = list![index];
return InkWell(
onTap: () {},
onTap: () {
Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}',
arguments: {'videoItem': i, 'heroTag': Utils.makeHeroTag(i.id)});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(

View File

@ -113,7 +113,6 @@ class VideoDetailController extends GetxController {
// 视频链接
queryVideoUrl() async {
print('🐶🐶🐶');
var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid);
// log('result: ${result.toString()}');
if (result['status']) {

View File

@ -76,7 +76,7 @@ class VideoIntroController extends GetxController {
userLogin = user.get(UserBoxKey.userLogin) != null;
}
// 获取视频简介
// 获取视频简介&分p
Future queryVideoIntro() async {
var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) {

View File

@ -16,6 +16,8 @@ import 'package:pilipala/pages/video/detail/introduction/controller.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import 'widgets/season.dart';
class VideoIntroPanel extends StatefulWidget {
const VideoIntroPanel({Key? key}) : super(key: key);
@ -342,7 +344,14 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
),
),
const SizedBox(height: 8),
// 点赞收藏转发
_actionGrid(context, videoIntroController),
// 合集
if (!widget.loadingStatus &&
widget.videoDetail!.ugcSeason != null) ...[
seasonPanel(widget.videoDetail!.ugcSeason!,
widget.videoDetail!.pages!.first.cid)
],
Divider(
height: 26,
color: Theme.of(context).dividerColor.withOpacity(0.1),

View File

@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/models/video_detail_res.dart';
Widget seasonPanel(UgcSeason ugcSeason, cid) {
return Builder(builder: (context) {
List<EpisodeItem> episodes = ugcSeason.sections!.first.episodes!;
int currentIndex = episodes.indexWhere((e) => e.cid == cid);
return Container(
margin: const EdgeInsets.only(
top: 15,
left: 2,
right: 2,
),
child: Material(
color: Theme.of(context).colorScheme.onInverseSurface,
borderRadius: BorderRadius.circular(6),
clipBehavior: Clip.hardEdge,
child: InkWell(
onTap: () => showBottomSheet(
context: context,
builder: (_) => Container(
height: Get.size.height - Get.size.width * 9 / 16 - 45,
color: Theme.of(context).colorScheme.background,
child: Column(
children: [
Container(
height: 45,
padding: const EdgeInsets.only(left: 14, right: 14),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'合集(${episodes.length}',
style: Theme.of(context).textTheme.titleMedium,
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
),
Divider(
height: 1,
color: Theme.of(context).dividerColor.withOpacity(0.1),
),
Expanded(
child: Material(
child: ListView.builder(
itemCount: episodes.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () {},
child: Padding(
padding: const EdgeInsets.only(
top: 10, bottom: 10, left: 15, right: 15),
child: Text(
episodes[index].title!,
style: TextStyle(
color: index == currentIndex
? Theme.of(context).colorScheme.primary
: Theme.of(context)
.colorScheme
.onSurface),
),
),
);
},
),
),
),
],
),
),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Row(
children: [
Text('合集:${ugcSeason.title!}'),
const Spacer(),
Text(
'${currentIndex + 1} / ${ugcSeason.epCount}',
style: Theme.of(context).textTheme.labelSmall,
),
const SizedBox(width: 2),
const Icon(
Icons.arrow_forward_ios_outlined,
size: 13,
)
],
),
),
),
),
);
});
}

View File

@ -59,6 +59,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
setState(() {});
Wakelock.disable();
}
// 播放完成停止 or 切换下一个
if (status == PlayerStatus.completed) {
_meeduPlayerController!.pause();
}
},
);
@ -67,8 +71,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
_extendNestCtr.addListener(
() {
print(_extendNestCtr.position.pixels);
double offset = _extendNestCtr.position.pixels;
if (offset > doubleOffset) {
animationController.forward();