Merge branch 'feature-invalidInfo'

This commit is contained in:
guozhigq
2024-11-24 16:43:02 +08:00
8 changed files with 243 additions and 5 deletions

View File

@ -622,4 +622,8 @@ class Api {
/// 视频标签 /// 视频标签
static const String videoTag = '/x/tag/archive/tags'; static const String videoTag = '/x/tag/archive/tags';
/// 修复标题和海报
// /api/view?id=${aid} /all/video/av${aid} /video/av${aid}/
static const String fixTitleAndPic = '${HttpString.biliplusBaseUrl}/api/view';
} }

View File

@ -1,3 +1,4 @@
import 'package:pilipala/models/common/invalid_video.dart';
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
@ -50,6 +51,32 @@ class CommonHttp {
} }
} }
static Future fixVideoPicAndTitle({required int aid}) async {
var res = await Request().getWithoutCookie(Api.fixTitleAndPic, data: {
'id': aid,
});
if (res != null) {
if (res.data['code'] == -404) {
return {
'status': false,
'data': null,
'msg': '没有相关信息',
};
} else {
return {
'status': true,
'data': InvalidVideoModel.fromJson(res.data),
};
}
} else {
return {
'status': false,
'data': null,
'msg': '没有相关信息',
};
}
}
static Future buvidActivate() async { static Future buvidActivate() async {
try { try {
// 获取 HTML 数据 // 获取 HTML 数据

View File

@ -8,6 +8,8 @@ class HttpString {
static const String messageBaseUrl = 'https://message.bilibili.com'; static const String messageBaseUrl = 'https://message.bilibili.com';
static const String bangumiBaseUrl = 'https://bili.meark.me'; static const String bangumiBaseUrl = 'https://bili.meark.me';
static const String sponsorBlockBaseUrl = 'https://www.bsbsb.top'; static const String sponsorBlockBaseUrl = 'https://www.bsbsb.top';
static const String biliplusBaseUrl = 'https://www.biliplus.com';
static const List<int> validateStatusCodes = [ static const List<int> validateStatusCodes = [
302, 302,
304, 304,

View File

@ -0,0 +1,73 @@
class InvalidVideoModel {
final int? id;
final int? ver;
final int? aid;
final String? lastupdate;
final int? lastupdatets;
final String? title;
final String? description;
final String? pic;
final int? tid;
final String? typename;
final int? created;
final String? createdAt;
final String? author;
final int? mid;
final String? play;
final String? coins;
final String? review;
final String? videoReview;
final String? favorites;
final String? tag;
final List<String>? tagList;
InvalidVideoModel({
this.id,
this.ver,
this.aid,
this.lastupdate,
this.lastupdatets,
this.title,
this.description,
this.pic,
this.tid,
this.typename,
this.created,
this.createdAt,
this.author,
this.mid,
this.play,
this.coins,
this.review,
this.videoReview,
this.favorites,
this.tag,
this.tagList,
});
factory InvalidVideoModel.fromJson(Map<String, dynamic> json) {
return InvalidVideoModel(
id: json['id'],
ver: json['ver'],
aid: json['aid'],
lastupdate: json['lastupdate'],
lastupdatets: json['lastupdatets'],
title: json['title'],
description: json['description'],
pic: json['pic'],
tid: json['tid'],
typename: json['typename'],
created: json['created'],
createdAt: json['created_at'],
author: json['author'],
mid: json['mid'],
play: json['play'],
coins: json['coins'],
review: json['review'],
videoReview: json['video_review'],
favorites: json['favorites'],
tag: json['tag'],
tagList: json['tag'].toString().split(',').toList(),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/common.dart';
import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/user/fav_detail.dart'; import 'package:pilipala/models/user/fav_detail.dart';
@ -8,6 +9,8 @@ import 'package:pilipala/models/user/fav_folder.dart';
import 'package:pilipala/pages/fav/index.dart'; import 'package:pilipala/pages/fav/index.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
import 'widget/invalid_video_card.dart';
class FavDetailController extends GetxController { class FavDetailController extends GetxController {
FavFolderItemData? item; FavFolderItemData? item;
RxString title = ''.obs; RxString title = ''.obs;
@ -152,4 +155,22 @@ class FavDetailController extends GetxController {
}, },
); );
} }
// 查看无效视频信息
Future toViewInvalidVideo(FavDetailItemData item) async {
SmartDialog.showLoading(msg: '加载中...');
var res = await CommonHttp.fixVideoPicAndTitle(aid: item.id!);
SmartDialog.dismiss();
if (res['status']) {
showModalBottomSheet(
context: Get.context!,
isScrollControlled: true,
builder: (context) {
return InvalidVideoCard(videoInfo: res['data']);
},
);
} else {
SmartDialog.showToast(res['msg']);
}
}
} }

View File

@ -226,6 +226,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
isOwner: _favDetailController.isOwner, isOwner: _favDetailController.isOwner,
callFn: () => _favDetailController callFn: () => _favDetailController
.onCancelFav(favList[index].id), .onCancelFav(favList[index].id),
viewInvalidVideoCb: () => _favDetailController
.toViewInvalidVideo(favList[index]),
); );
}, childCount: favList.length), }, childCount: favList.length),
), ),

View File

@ -19,6 +19,7 @@ class FavVideoCardH extends StatelessWidget {
final Function? callFn; final Function? callFn;
final int? searchType; final int? searchType;
final String isOwner; final String isOwner;
final Function? viewInvalidVideoCb;
const FavVideoCardH({ const FavVideoCardH({
Key? key, Key? key,
@ -26,6 +27,7 @@ class FavVideoCardH extends StatelessWidget {
this.callFn, this.callFn,
this.searchType, this.searchType,
required this.isOwner, required this.isOwner,
this.viewInvalidVideoCb,
}) : super(key: key); }) : super(key: key);
@override @override
@ -36,6 +38,10 @@ class FavVideoCardH extends StatelessWidget {
return InkWell( return InkWell(
onTap: () async { onTap: () async {
// int? seasonId; // int? seasonId;
if (videoItem.title == '已失效视频') {
viewInvalidVideoCb?.call();
return;
}
String? epId; String? epId;
if (videoItem.ogv != null && if (videoItem.ogv != null &&
(videoItem.ogv['type_name'] == '番剧' || (videoItem.ogv['type_name'] == '番剧' ||
@ -65,11 +71,17 @@ class FavVideoCardH extends StatelessWidget {
epId != null ? SearchType.media_bangumi : SearchType.video, epId != null ? SearchType.media_bangumi : SearchType.video,
}); });
}, },
onLongPress: () => imageSaveDialog( onLongPress: () {
context, if (videoItem.title == '已失效视频') {
videoItem, SmartDialog.showToast('视频已失效');
SmartDialog.dismiss, return;
), }
imageSaveDialog(
context,
videoItem,
SmartDialog.dismiss,
);
},
child: Column( child: Column(
children: [ children: [
Padding( Padding(

View File

@ -0,0 +1,97 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/common/invalid_video.dart';
class InvalidVideoCard extends StatelessWidget {
const InvalidVideoCard({required this.videoInfo, Key? key}) : super(key: key);
final InvalidVideoModel videoInfo;
@override
Widget build(BuildContext context) {
const TextStyle textStyle = TextStyle(fontSize: 14.0);
return Padding(
padding: EdgeInsets.fromLTRB(
12,
14,
12,
MediaQuery.of(context).padding.bottom + 20,
),
child: LayoutBuilder(
builder: (context, constraints) {
double maxWidth = constraints.maxWidth;
double maxHeight = maxWidth * 9 / 16;
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
NetworkImgLayer(
width: maxWidth,
height: maxHeight,
src: videoInfo.pic,
radius: 20,
),
const SizedBox(height: 10),
SelectableText(
videoInfo.title!,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 2),
SelectableText(videoInfo.author!, style: textStyle),
const SizedBox(height: 2),
SelectableText('创建时间:${videoInfo.createdAt}', style: textStyle),
SelectableText('更新时间:${videoInfo.lastupdate}',
style: textStyle),
SelectableText('分类:${videoInfo.typename}', style: textStyle),
SelectableText(
'投币:${videoInfo.coins} 收藏:${videoInfo.favorites}',
style: textStyle),
if (videoInfo.tagList != null &&
videoInfo.tagList!.isNotEmpty) ...[
const SizedBox(height: 6),
_buildTags(context, videoInfo.tagList),
],
],
),
);
},
),
);
}
Widget _buildTags(BuildContext context, List<String>? videoTags) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
return Wrap(
spacing: 6,
runSpacing: 6,
direction: Axis.horizontal,
textDirection: TextDirection.ltr,
children: videoTags!.map((tag) {
return InkWell(
onTap: () {
Get.toNamed('/searchResult', parameters: {'keyword': tag});
},
borderRadius: BorderRadius.circular(6),
child: Container(
decoration: BoxDecoration(
color: colorScheme.surfaceVariant.withOpacity(0.5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10),
child: Text(
tag,
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
),
);
}).toList(),
);
}
}