mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
fix: memberArchive challenge (#646)
This commit is contained in:
committed by
GitHub
parent
d3cbc95235
commit
5da86d85de
@@ -1,8 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:math' show Random;
|
|
||||||
import 'package:PiliPlus/build_config.dart';
|
import 'package:PiliPlus/build_config.dart';
|
||||||
import 'package:PiliPlus/http/retry_interceptor.dart';
|
import 'package:PiliPlus/http/retry_interceptor.dart';
|
||||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||||
@@ -13,7 +11,6 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:dio/io.dart';
|
import 'package:dio/io.dart';
|
||||||
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
||||||
import '../utils/storage.dart';
|
import '../utils/storage.dart';
|
||||||
import 'api.dart';
|
|
||||||
import 'constants.dart';
|
import 'constants.dart';
|
||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
||||||
|
|
||||||
@@ -25,9 +22,8 @@ class Request {
|
|||||||
static late AccountManager accountManager;
|
static late AccountManager accountManager;
|
||||||
static late final Dio dio;
|
static late final Dio dio;
|
||||||
factory Request() => _instance;
|
factory Request() => _instance;
|
||||||
static final _rand = Random();
|
// static final _rand = Random();
|
||||||
static final RegExp _spmPrefixExp =
|
// static final RegExp _spmPrefixExp = RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
||||||
RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
|
||||||
|
|
||||||
/// 设置cookie
|
/// 设置cookie
|
||||||
static Future<void> setCookie() async {
|
static Future<void> setCookie() async {
|
||||||
@@ -52,36 +48,36 @@ class Request {
|
|||||||
return Accounts.main.csrf;
|
return Accounts.main.csrf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> buvidActive(Account account) async {
|
// static Future<void> buvidActive(Account account) async {
|
||||||
// 这样线程不安全, 但仍按预期进行
|
// // 这样线程不安全, 但仍按预期进行
|
||||||
if (account.activited) return;
|
// if (account.activited) return;
|
||||||
account.activited = true;
|
// account.activited = true;
|
||||||
try {
|
// try {
|
||||||
final html = await Request().get(Api.dynamicSpmPrefix,
|
// final html = await Request().get(Api.dynamicSpmPrefix,
|
||||||
options: Options(extra: {'account': account}));
|
// options: Options(extra: {'account': account}));
|
||||||
final String spmPrefix = _spmPrefixExp.firstMatch(html.data)!.group(1)!;
|
// final String spmPrefix = _spmPrefixExp.firstMatch(html.data)!.group(1)!;
|
||||||
final String randPngEnd = base64.encode(
|
// final String randPngEnd = base64.encode(
|
||||||
List<int>.generate(32, (_) => _rand.nextInt(256)) +
|
// List<int>.generate(32, (_) => _rand.nextInt(256)) +
|
||||||
List<int>.filled(4, 0) +
|
// List<int>.filled(4, 0) +
|
||||||
[73, 69, 78, 68] +
|
// [73, 69, 78, 68] +
|
||||||
List<int>.generate(4, (_) => _rand.nextInt(256)));
|
// List<int>.generate(4, (_) => _rand.nextInt(256)));
|
||||||
|
|
||||||
String jsonData = json.encode({
|
// String jsonData = json.encode({
|
||||||
'3064': 1,
|
// '3064': 1,
|
||||||
'39c8': '$spmPrefix.fp.risk',
|
// '39c8': '$spmPrefix.fp.risk',
|
||||||
'3c43': {
|
// '3c43': {
|
||||||
'adca': 'Linux',
|
// 'adca': 'Linux',
|
||||||
'bfe9': randPngEnd.substring(randPngEnd.length - 50),
|
// 'bfe9': randPngEnd.substring(randPngEnd.length - 50),
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
|
|
||||||
await Request().post(Api.activateBuvidApi,
|
// await Request().post(Api.activateBuvidApi,
|
||||||
data: {'payload': jsonData},
|
// data: {'payload': jsonData},
|
||||||
options: Options(contentType: Headers.jsonContentType));
|
// options: Options(contentType: Headers.jsonContentType));
|
||||||
} catch (e) {
|
// } catch (e) {
|
||||||
log("setCookie, $e");
|
// log("setCookie, $e");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* config it and create
|
* config it and create
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/grpc/grpc_repo.dart';
|
import 'package:PiliPlus/grpc/grpc_repo.dart';
|
||||||
@@ -337,14 +338,14 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Future memberArchive({
|
static Future memberArchive({
|
||||||
int? mid,
|
required int mid,
|
||||||
int ps = 40,
|
int ps = 25,
|
||||||
int tid = 0,
|
int tid = 0,
|
||||||
int? pn,
|
int? pn,
|
||||||
String? keyword,
|
String? keyword,
|
||||||
String order = 'pubdate',
|
String order = 'pubdate',
|
||||||
bool orderAvoided = true,
|
bool orderAvoided = true,
|
||||||
dynamic wwebid,
|
String? wwebid,
|
||||||
}) async {
|
}) async {
|
||||||
String dmImgStr = Utils.base64EncodeRandomString(16, 64);
|
String dmImgStr = Utils.base64EncodeRandomString(16, 64);
|
||||||
String dmCoverImgStr = Utils.base64EncodeRandomString(32, 128);
|
String dmCoverImgStr = Utils.base64EncodeRandomString(32, 128);
|
||||||
@@ -356,7 +357,7 @@ class MemberHttp {
|
|||||||
'keyword': keyword ?? '',
|
'keyword': keyword ?? '',
|
||||||
'order': order,
|
'order': order,
|
||||||
'platform': 'web',
|
'platform': 'web',
|
||||||
'web_location': 1550101,
|
'web_location': '333.1387',
|
||||||
'order_avoided': orderAvoided,
|
'order_avoided': orderAvoided,
|
||||||
'dm_img_list': '[]',
|
'dm_img_list': '[]',
|
||||||
'dm_img_str': dmImgStr,
|
'dm_img_str': dmImgStr,
|
||||||
@@ -367,7 +368,11 @@ class MemberHttp {
|
|||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
Api.memberArchive,
|
Api.memberArchive,
|
||||||
queryParameters: params,
|
queryParameters: params,
|
||||||
extra: {'ua': 'Mozilla/5.0'},
|
options: Options(headers: {
|
||||||
|
HttpHeaders.userAgentHeader: Request.headerUa(type: 'pc'),
|
||||||
|
HttpHeaders.refererHeader: HttpString.spaceBaseUrl,
|
||||||
|
'origin': HttpString.spaceBaseUrl,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -646,9 +646,8 @@ class LoginPageController extends GetxController
|
|||||||
tokenInfo['access_token'], tokenInfo['refresh_token']);
|
tokenInfo['access_token'], tokenInfo['refresh_token']);
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
account.onChange(),
|
account.onChange(),
|
||||||
AnonymousAccount()
|
AnonymousAccount().delete()
|
||||||
.delete()
|
// .then((_) => Request.buvidActive(AnonymousAccount()))
|
||||||
.then((_) => Request.buvidActive(AnonymousAccount()))
|
|
||||||
]);
|
]);
|
||||||
Accounts.accountMode.updateAll((_, a) => a == account ? account : a);
|
Accounts.accountMode.updateAll((_, a) => a == account ? account : a);
|
||||||
if (Accounts.main.isLogin) {
|
if (Accounts.main.isLogin) {
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MemberController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getMemberInfo() async {
|
Future<Map<String, dynamic>> getMemberInfo() async {
|
||||||
wwebid = await Utils.getWwebid(mid);
|
wwebid ??= await Utils.getWwebid(mid);
|
||||||
await getMemberStat();
|
await getMemberStat();
|
||||||
await getMemberView();
|
await getMemberView();
|
||||||
var res = await MemberHttp.memberInfo(mid: mid, wwebid: wwebid);
|
var res = await MemberHttp.memberInfo(mid: mid, wwebid: wwebid);
|
||||||
@@ -268,7 +268,10 @@ class MemberController extends GetxController {
|
|||||||
void pushDynamicsPage() => Get.toNamed('/memberDynamics?mid=$mid');
|
void pushDynamicsPage() => Get.toNamed('/memberDynamics?mid=$mid');
|
||||||
|
|
||||||
// 跳转查看投稿
|
// 跳转查看投稿
|
||||||
void pushArchivesPage() => Get.toNamed('/memberArchive?mid=$mid');
|
void pushArchivesPage() async {
|
||||||
|
wwebid ??= await Utils.getWwebid(mid);
|
||||||
|
Get.toNamed('/memberArchive?mid=$mid&wwebid=$wwebid');
|
||||||
|
}
|
||||||
|
|
||||||
// 跳转查看专栏
|
// 跳转查看专栏
|
||||||
void pushSeasonsPage() {}
|
void pushSeasonsPage() {}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:PiliPlus/models/member/archive.dart';
|
|||||||
class MemberArchiveController extends GetxController {
|
class MemberArchiveController extends GetxController {
|
||||||
final ScrollController scrollController = ScrollController();
|
final ScrollController scrollController = ScrollController();
|
||||||
late int mid;
|
late int mid;
|
||||||
|
late String wwebid;
|
||||||
int pn = 1;
|
int pn = 1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
RxMap<String, String> currentOrder = <String, String>{}.obs;
|
RxMap<String, String> currentOrder = <String, String>{}.obs;
|
||||||
@@ -21,6 +22,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
void onInit() {
|
void onInit() {
|
||||||
super.onInit();
|
super.onInit();
|
||||||
mid = int.parse(Get.parameters['mid']!);
|
mid = int.parse(Get.parameters['mid']!);
|
||||||
|
wwebid = Get.parameters['wwebid']!;
|
||||||
currentOrder.value = orderList.first;
|
currentOrder.value = orderList.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +35,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
mid: mid,
|
mid: mid,
|
||||||
pn: pn,
|
pn: pn,
|
||||||
order: currentOrder['type']!,
|
order: currentOrder['type']!,
|
||||||
|
wwebid: wwebid,
|
||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
if (type == 'init') {
|
if (type == 'init') {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ abstract class Account {
|
|||||||
late String csrf;
|
late String csrf;
|
||||||
final Map<String, String> headers = const {};
|
final Map<String, String> headers = const {};
|
||||||
|
|
||||||
bool activited = false;
|
// bool activited = false;
|
||||||
|
|
||||||
Future<void> delete();
|
Future<void> delete();
|
||||||
Future<void> onChange();
|
Future<void> onChange();
|
||||||
@@ -51,9 +51,6 @@ class LoginAccount implements Account {
|
|||||||
late String csrf =
|
late String csrf =
|
||||||
cookieJar.domainCookies['bilibili.com']!['/']!['bili_jct']!.cookie.value;
|
cookieJar.domainCookies['bilibili.com']!['/']!['bili_jct']!.cookie.value;
|
||||||
|
|
||||||
@override
|
|
||||||
bool activited = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> delete() => _box.delete(_midStr);
|
Future<void> delete() => _box.delete(_midStr);
|
||||||
|
|
||||||
@@ -74,9 +71,8 @@ class LoginAccount implements Account {
|
|||||||
late final Box<LoginAccount> _box = Accounts.account;
|
late final Box<LoginAccount> _box = Accounts.account;
|
||||||
|
|
||||||
LoginAccount(this.cookieJar, this.accessKey, this.refresh,
|
LoginAccount(this.cookieJar, this.accessKey, this.refresh,
|
||||||
[Set<AccountType>? type]) {
|
[Set<AccountType>? type])
|
||||||
this.type = type ?? {};
|
: this.type = type ?? {};
|
||||||
}
|
|
||||||
|
|
||||||
LoginAccount.fromJson(Map json) {
|
LoginAccount.fromJson(Map json) {
|
||||||
cookieJar = BiliCookieJar.fromJson(json['cookies']);
|
cookieJar = BiliCookieJar.fromJson(json['cookies']);
|
||||||
@@ -93,7 +89,7 @@ class LoginAccount implements Account {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) || (other is Account && mid == other.mid);
|
identical(this, other) || (other is LoginAccount && mid == other.mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnonymousAccount implements Account {
|
class AnonymousAccount implements Account {
|
||||||
@@ -114,13 +110,10 @@ class AnonymousAccount implements Account {
|
|||||||
@override
|
@override
|
||||||
final Map<String, String> headers = const {};
|
final Map<String, String> headers = const {};
|
||||||
|
|
||||||
@override
|
|
||||||
bool activited = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> delete() async {
|
Future<void> delete() async {
|
||||||
await cookieJar.deleteAll();
|
await cookieJar.deleteAll();
|
||||||
activited = false;
|
cookieJar.setBuvid3();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -132,7 +125,7 @@ class AnonymousAccount implements Account {
|
|||||||
static final _instance = AnonymousAccount._();
|
static final _instance = AnonymousAccount._();
|
||||||
|
|
||||||
AnonymousAccount._() {
|
AnonymousAccount._() {
|
||||||
cookieJar = DefaultCookieJar(ignoreExpires: true);
|
cookieJar = DefaultCookieJar(ignoreExpires: true)..setBuvid3();
|
||||||
}
|
}
|
||||||
|
|
||||||
factory AnonymousAccount() => _instance;
|
factory AnonymousAccount() => _instance;
|
||||||
@@ -143,7 +136,7 @@ class AnonymousAccount implements Account {
|
|||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
(other is Account && cookieJar == other.cookieJar);
|
(other is AnonymousAccount && cookieJar == other.cookieJar);
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BiliCookie on Cookie {
|
extension BiliCookie on Cookie {
|
||||||
@@ -168,6 +161,12 @@ extension BiliCookieJar on DefaultCookieJar {
|
|||||||
.toList() ??
|
.toList() ??
|
||||||
[];
|
[];
|
||||||
|
|
||||||
|
void setBuvid3() {
|
||||||
|
domainCookies['bilibili.com'] ??= {'/': {}};
|
||||||
|
domainCookies['bilibili.com']!['/']!['buvid3'] ??= SerializableCookie(
|
||||||
|
Cookie('buvid3', Utils.genBuvid3())..setBiliDomain());
|
||||||
|
}
|
||||||
|
|
||||||
static DefaultCookieJar fromJson(Map json) =>
|
static DefaultCookieJar fromJson(Map json) =>
|
||||||
DefaultCookieJar(ignoreExpires: true)
|
DefaultCookieJar(ignoreExpires: true)
|
||||||
..domainCookies['bilibili.com'] = {
|
..domainCookies['bilibili.com'] = {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:PiliPlus/common/widgets/pair.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'
|
||||||
show kDragContainerExtentPercentage, displacement;
|
show kDragContainerExtentPercentage, displacement;
|
||||||
import 'package:PiliPlus/http/constants.dart';
|
import 'package:PiliPlus/http/constants.dart';
|
||||||
import 'package:PiliPlus/http/index.dart';
|
|
||||||
import 'package:PiliPlus/models/common/dynamic_badge_mode.dart';
|
import 'package:PiliPlus/models/common/dynamic_badge_mode.dart';
|
||||||
import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart';
|
import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart';
|
||||||
import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart';
|
import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart';
|
||||||
@@ -903,9 +902,9 @@ class Accounts {
|
|||||||
for (var type in AccountType.values) {
|
for (var type in AccountType.values) {
|
||||||
accountMode[type] ??= AnonymousAccount();
|
accountMode[type] ??= AnonymousAccount();
|
||||||
}
|
}
|
||||||
await Future.wait((accountMode.values.toSet()
|
// await Future.wait((accountMode.values.toSet()
|
||||||
..retainWhere((i) => !i.activited))
|
// ..retainWhere((i) => !i.activited))
|
||||||
.map((i) => Request.buvidActive(i)));
|
// .map((i) => Request.buvidActive(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> clear() async {
|
static Future<void> clear() async {
|
||||||
@@ -914,7 +913,7 @@ class Accounts {
|
|||||||
accountMode[i] = AnonymousAccount();
|
accountMode[i] = AnonymousAccount();
|
||||||
}
|
}
|
||||||
await AnonymousAccount().delete();
|
await AnonymousAccount().delete();
|
||||||
Request.buvidActive(AnonymousAccount());
|
// Request.buvidActive(AnonymousAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> close() async {
|
static Future<void> close() async {
|
||||||
@@ -936,7 +935,7 @@ class Accounts {
|
|||||||
await (accountMode[key]?..type.remove(key))?.onChange();
|
await (accountMode[key]?..type.remove(key))?.onChange();
|
||||||
accountMode[key] = account..type.add(key);
|
accountMode[key] = account..type.add(key);
|
||||||
await account.onChange();
|
await account.onChange();
|
||||||
if (!account.activited) await Request.buvidActive(account);
|
// if (!account.activited) await Request.buvidActive(account);
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case AccountType.main:
|
case AccountType.main:
|
||||||
await (account.isLogin
|
await (account.isLogin
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import 'package:url_launcher/url_launcher.dart';
|
|||||||
import 'package:html/dom.dart' as dom;
|
import 'package:html/dom.dart' as dom;
|
||||||
import 'package:html/parser.dart' as html_parser;
|
import 'package:html/parser.dart' as html_parser;
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:uuid/v4.dart';
|
||||||
|
|
||||||
import '../models/home/rcmd/result.dart';
|
import '../models/home/rcmd/result.dart';
|
||||||
import '../models/model_rec_video_item.dart';
|
import '../models/model_rec_video_item.dart';
|
||||||
@@ -1875,13 +1876,16 @@ class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<int> generateRandomBytes(int minLength, int maxLength) {
|
static List<int> generateRandomBytes(int minLength, int maxLength) {
|
||||||
return List<int>.generate(random.nextInt(maxLength - minLength + 1),
|
return List<int>.generate(
|
||||||
(_) => random.nextInt(0x60) + 0x20);
|
minLength + random.nextInt(maxLength - minLength + 1),
|
||||||
|
(_) => 0x26 + random.nextInt(0x59), // dm_img_str不能有`%`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String base64EncodeRandomString(int minLength, int maxLength) {
|
static String base64EncodeRandomString(int minLength, int maxLength) {
|
||||||
List<int> randomBytes = generateRandomBytes(minLength, maxLength);
|
final randomBytes = generateRandomBytes(minLength, maxLength);
|
||||||
return base64.encode(randomBytes);
|
final randomBase64 = base64.encode(randomBytes);
|
||||||
|
return randomBase64.substring(0, randomBase64.length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getFileName(String uri, {bool fileExt = true}) {
|
static String getFileName(String uri, {bool fileExt = true}) {
|
||||||
@@ -1889,4 +1893,8 @@ class Utils {
|
|||||||
final i1 = fileExt ? uri.length : uri.lastIndexOf('.');
|
final i1 = fileExt ? uri.length : uri.lastIndexOf('.');
|
||||||
return uri.substring(i0, i1);
|
return uri.substring(i0, i1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String genBuvid3() {
|
||||||
|
return '${const UuidV4().generate().toUpperCase()}${random.nextInt(100000).toString().padLeft(5, "0")}infoc';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user