From f522886dc2562e5020893ed1f5e488da6735c494 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 24 Jun 2023 15:00:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=95=AA=E5=89=A7=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 3 + lib/http/search.dart | 23 ++ lib/models/bangumi/info.dart | 214 ++++++++++++++++++ .../widgets/media_bangumi_panel.dart | 65 ++++-- 4 files changed, 290 insertions(+), 15 deletions(-) create mode 100644 lib/models/bangumi/info.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index c8a02d6e..872cedd5 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -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'; } diff --git a/lib/http/search.dart b/lib/http/search.dart index 476f2bcc..d7655e7a 100644 --- a/lib/http/search.dart +++ b/lib/http/search.dart @@ -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 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': '请求错误 🙅', + }; + } + } } diff --git a/lib/models/bangumi/info.dart b/lib/models/bangumi/info.dart new file mode 100644 index 00000000..3bc2af25 --- /dev/null +++ b/lib/models/bangumi/info.dart @@ -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? 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 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((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 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']; + } +} diff --git a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart index 863c55a4..5512f720 100644 --- a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart +++ b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart @@ -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('观看'), + ), + ) ], ), ),