feat: 番剧播放

This commit is contained in:
guozhigq
2023-06-24 15:00:43 +08:00
parent f113cdc364
commit f522886dc2
4 changed files with 290 additions and 15 deletions

View File

@ -157,4 +157,7 @@ class Api {
// 查询视频分P列表 (avid/bvid转cid)
static const String ab2c = '/x/player/pagelist';
// 番剧/剧集明细
static const String bangumiInfo = '/pgc/view/web/season';
}

View File

@ -1,6 +1,7 @@
import 'dart:developer';
import 'package:pilipala/http/index.dart';
import 'package:pilipala/models/bangumi/info.dart';
import 'package:pilipala/models/common/search_type.dart';
import 'package:pilipala/models/search/hot.dart';
import 'package:pilipala/models/search/result.dart';
@ -94,4 +95,26 @@ class SearchHttp {
var res = await Request().get(Api.ab2c, data: {...data});
return res.data['data'].first['cid'];
}
static Future bangumiInfo({int? seasonId, int? epId}) async {
Map<String, dynamic> data = {};
if (seasonId != null) {
data['season_id'] = seasonId;
} else if (epId != null) {
data['ep_id'] = epId;
}
var res = await Request().get(Api.bangumiInfo, data: {...data});
if (res.data['code'] == 0) {
return {
'status': true,
'data': BangumiInfoModel.fromJson(res.data['result']),
};
} else {
return {
'status': false,
'data': [],
'msg': '请求错误 🙅',
};
}
}
}

View File

@ -0,0 +1,214 @@
class BangumiInfoModel {
BangumiInfoModel({
this.activity,
this.actors,
this.alias,
this.areas,
this.bkgCover,
this.cover,
this.enableVt,
this.episodes,
this.evaluate,
this.freya,
this.jpTitle,
this.link,
this.mediaId,
this.newEp,
this.playStrategy,
this.positive,
this.publish,
this.rating,
this.record,
this.rights,
this.seasonId,
this.seasonTitle,
this.seasons,
this.series,
this.shareCopy,
this.shareSubTitle,
this.shareUrl,
this.show,
this.showSeasonType,
this.squareCover,
this.stat,
this.status,
this.styles,
this.subTitle,
this.title,
this.total,
this.type,
this.userStatus,
});
Map? activity;
String? actors;
String? alias;
List? areas;
String? bkgCover;
String? cover;
String? enableVt;
List<EpisodeItem>? episodes;
String? evaluate;
Map? freya;
String? jpTitle;
String? link;
int? mediaId;
Map? newEp;
Map? playStrategy;
Map? positive;
Map? publish;
Map? rating;
String? record;
Map? rights;
int? seasonId;
String? seasonTitle;
List? seasons;
Map? series;
String? shareCopy;
String? shareSubTitle;
String? shareUrl;
Map? show;
int? showSeasonType;
String? squareCover;
Map? stat;
int? status;
List? styles;
String? subTitle;
String? title;
int? total;
int? type;
Map? userStatus;
BangumiInfoModel.fromJson(Map<String, dynamic> json) {
activity = json['activity'];
actors = json['actors'];
alias = json['alias'];
areas = json['areas'];
bkgCover = json['bkg_cover'];
cover = json['cover'];
enableVt = json['enableVt'];
episodes = json['episodes']
.map<EpisodeItem>((e) => EpisodeItem.fromJson(e))
.toList();
evaluate = json['evaluate'];
freya = json['freya'];
jpTitle = json['jp_title'];
link = json['link'];
mediaId = json['media_id'];
newEp = json['newEp'];
playStrategy = json['play_strategy'];
positive = json['positive'];
publish = json['publish'];
rating = json['rating'];
record = json['record'];
rights = json['rights'];
seasonId = json['season_id'];
seasonTitle = json['season_title'];
seasons = json['seasons'];
series = json['series'];
shareCopy = json['share_copy'];
shareSubTitle = json['share_sub_title'];
shareUrl = json['share_url'];
show = json['show'];
showSeasonType = json['show_season_type'];
squareCover = json['square_cover'];
stat = json['stat'];
status = json['status'];
styles = json['styles'];
subTitle = json['sub_title'];
title = json['title'];
total = json['total'];
type = json['type'];
userStatus = json['user_status'];
}
}
class EpisodeItem {
EpisodeItem({
this.aid,
this.badge,
this.badgeInfo,
this.badgeType,
this.bvid,
this.cid,
this.cover,
this.dimension,
this.duration,
this.enableVt,
this.from,
this.id,
this.isViewHide,
this.link,
this.longTitle,
this.pubTime,
this.pv,
this.releaseDate,
this.rights,
this.shareCopy,
this.shareUrl,
this.shortLink,
this.skip,
this.status,
this.subtitle,
this.title,
this.vid,
});
int? aid;
String? badge;
Map? badgeInfo;
int? badgeType;
String? bvid;
int? cid;
String? cover;
Map? dimension;
int? duration;
bool? enableVt;
String? from;
int? id;
bool? isViewHide;
String? link;
String? longTitle;
int? pubTime;
int? pv;
String? releaseDate;
Map? rights;
String? shareCopy;
String? shareUrl;
String? shortLink;
Map? skip;
int? status;
String? subtitle;
String? title;
String? vid;
EpisodeItem.fromJson(Map<String, dynamic> json) {
aid = json['aid'];
badge = json['badge'];
badgeInfo = json['badge_info'];
badgeType = json['badge_type'];
bvid = json['bvid'];
cid = json['cid'];
cover = json['cover'];
dimension = json['dimension'];
duration = json['duration'];
enableVt = json['enable_vt'];
from = json['from'];
id = json['id'];
isViewHide = json['is_view_hide'];
link = json['link'];
longTitle = json['long_title'];
pubTime = json['pub_time'];
pv = json['pv'];
releaseDate = json['release_date'];
rights = json['rights'];
shareCopy = json['share_copy'];
shareUrl = json['share_url'];
shortLink = json['short_link'];
skip = json['skip'];
status = json['status'];
subtitle = json['subtitle'];
title = json['title'];
vid = json['vid'];
}
}

View File

@ -1,9 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/http/search.dart';
import 'package:pilipala/models/bangumi/info.dart';
import 'package:pilipala/utils/utils.dart';
Widget searchMbangumiPanel(BuildContext context, ctr, list) {
TextStyle style =
TextStyle(fontSize: Theme.of(context).textTheme.labelMedium!.fontSize);
return ListView.builder(
controller: ctr!.scrollController,
addAutomaticKeepAlives: false,
@ -21,10 +26,15 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
NetworkImgLayer(
width: 111,
height: 148,
src: i.cover,
Stack(
children: [
NetworkImgLayer(
width: 111,
height: 148,
src: i.cover,
),
Positioned(top: 6, right: 4, child: UpTag(type: i.mediaType))
],
),
const SizedBox(width: 10),
Expanded(
@ -33,11 +43,12 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
children: [
const SizedBox(height: 4),
RichText(
maxLines: 1,
overflow: TextOverflow.ellipsis,
text: TextSpan(
style: TextStyle(
color: Theme.of(context).colorScheme.onSurface),
children: [
WidgetSpan(child: UpTag(type: i.mediaType)),
for (var i in i.title) ...[
TextSpan(
text: i['text'],
@ -57,30 +68,54 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
),
),
const SizedBox(height: 12),
Text('评分:${i.mediaScore['score'].toString()}'),
const SizedBox(height: 2),
Text('评分:${i.mediaScore['score'].toString()}',
style: style),
Row(
children: [
Text(i.areas),
Text(i.areas, style: style),
const SizedBox(width: 3),
const Text('·'),
const SizedBox(width: 3),
Text(Utils.dateFormat(i.pubtime).toString()),
Text(Utils.dateFormat(i.pubtime).toString(),
style: style),
],
),
Row(
children: [
Text(i.styles),
Text(i.styles, style: style),
const SizedBox(width: 3),
const Text('·'),
const SizedBox(width: 3),
Text(i.indexShow),
const SizedBox(width: 3),
Text(i.indexShow, style: style),
],
),
// Text('声优:${i.cv}'),
const SizedBox(height: 6),
Text(i.desc, overflow: TextOverflow.ellipsis, maxLines: 2),
const SizedBox(height: 18),
SizedBox(
height: 32,
child: ElevatedButton(
onPressed: () async {
SmartDialog.showLoading(msg: '获取中...');
var res = await SearchHttp.bangumiInfo(
seasonId: i.seasonId);
SmartDialog.dismiss();
if (res['status']) {
EpisodeItem episode = res['data'].episodes.first;
String bvid = episode.bvid!;
int cid = episode.cid!;
String pic = episode.cover!;
String heroTag = Utils.makeHeroTag(cid);
Get.toNamed(
'/video?bvid=$bvid&cid=$cid',
arguments: {
'pic': pic,
'heroTag': heroTag,
},
);
}
},
child: const Text('观看'),
),
)
],
),
),