Merge branch 'main' into feature-notice

This commit is contained in:
guozhigq
2023-12-16 23:59:31 +08:00
89 changed files with 2771 additions and 1449 deletions

View File

@ -215,7 +215,7 @@ class Api {
// 粉丝
// vmid 用户id pn 页码 ps 每页个数最大50 order: desc
// order_type 排序规则 最近访问传空,最常访问传 attention
static const String fans = 'https://api.bilibili.com/x/relation/fans';
static const String fans = '/x/relation/fans';
// 直播
// ?page=1&page_size=30&platform=web
@ -312,6 +312,10 @@ class Api {
static const String webDanmaku = '/x/v2/dm/web/seg.so';
//发送视频弹幕
//https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/action.md
static const String shootDanmaku = '/x/v2/dm/post';
// up主分组
static const String followUpTag = '/x/relation/tags';
@ -405,4 +409,49 @@ class Api {
/// local_id
static const getWebKey =
'https://passport.bilibili.com/x/passport-login/web/key';
/// cookie转access_key
static const cookieToKey =
'https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/confirm';
/// 申请二维码(TV端)
static const getTVCode =
'https://passport.snm0516.aisee.tv/x/passport-tv-login/qrcode/auth_code';
///扫码登录TV端
static const qrcodePoll =
'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll';
/// 置顶视频
static const getTopVideoApi = '/x/space/top/arc';
/// 主页 - 最近投币的视频
/// vmid
/// gaia_source = main_web
/// web_location
/// w_rid
/// wts
static const getRecentCoinVideoApi = '/x/space/coin/video';
/// 最近点赞的视频
static const getRecentLikeVideoApi = '/x/space/like/video';
/// 最近追番
static const getRecentBangumiApi = '/x/space/bangumi/follow/list';
/// 用户专栏
static const getMemberSeasonsApi = '/x/polymer/web-space/home/seasons_series';
/// 获赞数 播放数
/// mid
static const getMemberViewApi = '/x/space/upstat';
/// 查询某个专栏
/// mid
/// season_id
/// sort_reverse
/// page_num
/// page_size
static const getSeasonDetailApi =
'/x/polymer/web-space/seasons_archives_list';
}

View File

@ -24,4 +24,72 @@ class DanmakaHttp {
);
return DmSegMobileReply.fromBuffer(response.data);
}
static Future shootDanmaku({
int type = 1,//弹幕类选择(1视频弹幕 2漫画弹幕)
required int oid,// 视频cid
required String msg,//弹幕文本(长度小于 100 字符)
int mode = 1,// 弹幕类型(1滚动弹幕 4底端弹幕 5顶端弹幕 6逆向弹幕(不能使用) 7高级弹幕 8代码弹幕不能使用 9BAS弹幕pool必须为2)
// String? aid,// 稿件avid
// String? bvid,// bvid与aid必须有一个
required String bvid,
int? progress,// 弹幕出现在视频内的时间单位为毫秒默认为0
int? color,// 弹幕颜色(默认白色16777215
int? fontsize,// 弹幕字号默认25
int? pool,// 弹幕池选择0普通池 1字幕池 2特殊池代码/BAS弹幕默认普通池0
//int? rnd,// 当前时间戳*1000000若无此项则发送弹幕冷却时间限制为90s若有此项则发送弹幕冷却时间限制为5s
int? colorful,//60001专属渐变彩色需要会员
int? checkbox_type,//是否带 UP 身份标识0普通4带有标识
// String? csrf,//CSRF Token位于 Cookie Cookie 方式必要
// String? access_key,// APP 登录 Token APP 方式必要
}) async {
// 构建参数对象
// assert(aid != null || bvid != null);
// assert(csrf != null || access_key != null);
assert(msg.length < 100);
// 构建参数对象
var params = <String, dynamic>{
'type': type,
'oid': oid,
'msg': msg,
'mode': mode,
//'aid': aid,
'bvid': bvid,
'progress': progress,
'color': color,
'fontsize': fontsize,
'pool': pool,
'rnd': DateTime.now().microsecondsSinceEpoch,
'colorful': colorful,
'checkbox_type': checkbox_type,
'csrf': await Request.getCsrf(),
// 'access_key': access_key,
}..removeWhere((key, value) => value == null);
var response = await Request().post(
Api.shootDanmaku,
data: params,
options: Options(
contentType: Headers.formUrlEncodedContentType,
),
);
if (response.statusCode != 200) {
return {
'status': false,
'data': [],
'msg': '弹幕发送失败,状态码:${response.statusCode}',
};
}
if (response.data['code'] == 0) {
return {
'status': true,
'data': response.data['data'],
};
} else {
return {
'status': false,
'data': [],
'msg': "${response.data['code']}: ${response.data['message']}",
};
}
}
}

View File

@ -115,30 +115,24 @@ class Request {
idleTimeout: const Duration(milliseconds: 10000),
onClientCreate: (_, config) => config.onBadCertificate = (_) => true,
),
)
);
/// 设置代理
..httpClientAdapter = IOHttpClientAdapter(
/// 设置代理
if (enableSystemProxy) {
dio.httpClientAdapter = IOHttpClientAdapter(
createHttpClient: () {
final client = HttpClient();
// Config the client.
client.findProxy = (uri) {
if (enableSystemProxy) {
print('🌹:$systemProxyHost');
print('🌹:$systemProxyPort');
// return 'PROXY host:port';
return 'PROXY $systemProxyHost:$systemProxyPort';
} else {
// 不设置代理
return 'DIRECT';
}
// return 'PROXY host:port';
return 'PROXY $systemProxyHost:$systemProxyPort';
};
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
return client;
},
);
}
//添加拦截器
dio.interceptors.add(ApiInterceptor());

View File

@ -1,9 +1,16 @@
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/http/index.dart';
import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/models/follow/result.dart';
import 'package:pilipala/models/member/archive.dart';
import 'package:pilipala/models/member/coin.dart';
import 'package:pilipala/models/member/info.dart';
import 'package:pilipala/models/member/seasons.dart';
import 'package:pilipala/models/member/tags.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/utils/wbi_sign.dart';
class MemberHttp {
@ -215,4 +222,243 @@ class MemberHttp {
};
}
}
// 获取up置顶
static Future getTopVideo(String? vmid) async {
var res = await Request().get(Api.getTopVideoApi);
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data']
.map<MemberTagItemModel>((e) => MemberTagItemModel.fromJson(e))
.toList()
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 获取uo专栏
static Future getMemberSeasons(int? mid, int? pn, int? ps) async {
var res = await Request().get(Api.getMemberSeasonsApi, data: {
'mid': mid,
'page_num': pn,
'page_size': ps,
});
if (res.data['code'] == 0) {
return {
'status': true,
'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 最近投币
static Future getRecentCoinVideo({required int mid}) async {
Map params = await WbiSign().makSign({
'mid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
});
var res = await Request().get(
Api.getRecentCoinVideoApi,
data: {
'vmid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
'w_rid': params['w_rid'],
'wts': params['wts'],
},
);
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data']
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
.toList(),
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 最近点赞
static Future getRecentLikeVideo({required int mid}) async {
Map params = await WbiSign().makSign({
'mid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
});
var res = await Request().get(
Api.getRecentLikeVideoApi,
data: {
'vmid': mid,
'gaia_source': 'main_web',
'web_location': 333.999,
'w_rid': params['w_rid'],
'wts': params['wts'],
},
);
if (res.data['code'] == 0) {
return {
'status': true,
'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 查看某个专栏
static Future getSeasonDetail({
required int mid,
required int seasonId,
bool sortReverse = false,
required int pn,
required int ps,
}) async {
var res = await Request().get(
Api.getSeasonDetailApi,
data: {
'mid': mid,
'season_id': seasonId,
'sort_reverse': sortReverse,
'page_num': pn,
'page_size': ps,
},
);
if (res.data['code'] == 0) {
try {
return {
'status': true,
'data': MemberSeasonsList.fromJson(res.data['data'])
};
} catch (err) {
print(err);
}
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 获取TV authCode
static Future getTVCode() async {
SmartDialog.showLoading();
var params = {
'appkey': Constants.appKey,
'local_id': '0',
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
};
String sign = Utils.appSign(
params,
Constants.appKey,
Constants.appSec,
);
var res = await Request()
.post(Api.getTVCode, queryParameters: {...params, 'sign': sign});
if (res.data['code'] == 0) {
return {
'status': true,
'data': res.data['data']['auth_code'],
'msg': '操作成功'
};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 获取access_key
static Future cookieToKey() async {
var authCodeRes = await getTVCode();
if (authCodeRes['status']) {
var res = await Request().post(Api.cookieToKey, queryParameters: {
'auth_code': authCodeRes['data'],
'build': 708200,
'csrf': await Request.getCsrf(),
});
await Future.delayed(const Duration(milliseconds: 300));
await qrcodePoll(authCodeRes['data']);
if (res.data['code'] == 0) {
return {'status': true, 'data': [], 'msg': '操作成功'};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
}
static Future qrcodePoll(authCode) async {
var params = {
'appkey': Constants.appKey,
'auth_code': authCode.toString(),
'local_id': '0',
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
};
String sign = Utils.appSign(
params,
Constants.appKey,
Constants.appSec,
);
var res = await Request()
.post(Api.qrcodePoll, queryParameters: {...params, 'sign': sign});
SmartDialog.dismiss();
if (res.data['code'] == 0) {
String accessKey = res.data['data']['access_token'];
Box localCache = GStrorage.localCache;
Box userInfoCache = GStrorage.userInfo;
var userInfo = userInfoCache.get('userInfoCache');
localCache.put(
LocalCacheKey.accessKey, {'mid': userInfo.mid, 'value': accessKey});
return {'status': true, 'data': [], 'msg': '操作成功'};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
// 获取up播放数、点赞数
static Future memberView({required int mid}) async {
var res = await Request().get(Api.getMemberViewApi, data: {'mid': mid});
if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']};
} else {
return {
'status': false,
'data': [],
'msg': res.data['message'],
};
}
}
}

View File

@ -199,7 +199,7 @@ class UserHttp {
}
}
// 获取用户凭证
// 获取用户凭证 失效
static Future thirdLogin() async {
var res = await Request().get(
'https://passport.bilibili.com/login/app/third',