Merge branch 'main' into feature-notice
This commit is contained in:
@ -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';
|
||||
}
|
||||
|
@ -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:代码弹幕(不能使用) 9:BAS弹幕(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']}",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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'],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ class UserHttp {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取用户凭证
|
||||
// 获取用户凭证 失效
|
||||
static Future thirdLogin() async {
|
||||
var res = await Request().get(
|
||||
'https://passport.bilibili.com/login/app/third',
|
||||
|
Reference in New Issue
Block a user