opt: buvid

This commit is contained in:
My-Responsitories
2025-09-23 12:20:07 +08:00
parent d727e2a62a
commit da1ea68f8b
11 changed files with 102 additions and 62 deletions

View File

@@ -13,7 +13,6 @@ import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/login_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:archive/archive.dart';
import 'package:dio/dio.dart';
@@ -21,35 +20,46 @@ import 'package:flutter/foundation.dart' show kDebugMode;
import 'package:protobuf/protobuf.dart' show GeneratedMessage;
class GrpcReq {
static String? _accessKey = Accounts.main.accessKey;
static const _build = 2001100;
static const _versionName = '2.0.1';
static const _biliChannel = 'master';
static const _mobiApp = 'android_hd';
static const _device = 'android';
static final _buvid = LoginUtils.buvid;
static final _traceId = IdUtils.genTraceId();
static final _sessionId = Utils.generateRandomString(8);
static void updateHeaders(String? accessKey) {
_accessKey = accessKey;
if (_accessKey != null) {
headers['authorization'] = 'identify_v1 $_accessKey';
static void updateHeaders(String? accessKey, String buvid) {
if (accessKey != null) {
headers['authorization'] = 'identify_v1 $accessKey';
} else {
headers.remove('authorization');
}
headers['x-bili-metadata-bin'] = base64Encode(
Metadata(
accessKey: _accessKey ?? '',
accessKey: accessKey ?? '',
mobiApp: _mobiApp,
device: _device,
build: _build,
channel: _biliChannel,
buvid: _buvid,
buvid: buvid,
platform: _device,
).writeToBuffer(),
);
headers['x-bili-device-bin'] = base64Encode(
Device(
appId: 5,
build: _build,
buvid: buvid,
mobiApp: _mobiApp,
platform: _device,
channel: _biliChannel,
brand: _device,
model: _device,
osver: '15',
versionName: _versionName,
).writeToBuffer(),
);
options = Options(headers: headers, responseType: ResponseType.bytes);
}
@@ -61,8 +71,9 @@ class GrpcReq {
'x-bili-gaia-vtoken': '',
'x-bili-aurora-zone': '',
'x-bili-trace-id': _traceId,
if (_accessKey != null) 'authorization': 'identify_v1 $_accessKey',
'buvid': _buvid,
if (Accounts.main.accessKey != null)
'authorization': 'identify_v1 ${Accounts.main.accessKey}',
'buvid': Accounts.main.buvid,
'bili-http-engine': 'cronet',
'te': 'trailers',
'x-bili-fawkes-req-bin': base64Encode(
@@ -74,12 +85,12 @@ class GrpcReq {
),
'x-bili-metadata-bin': base64Encode(
Metadata(
accessKey: _accessKey ?? '',
accessKey: Accounts.main.accessKey ?? '',
mobiApp: _mobiApp,
device: _device,
build: _build,
channel: _biliChannel,
buvid: _buvid,
buvid: Accounts.main.buvid,
platform: _device,
).writeToBuffer(),
),
@@ -87,7 +98,7 @@ class GrpcReq {
Device(
appId: 5,
build: _build,
buvid: _buvid,
buvid: Accounts.main.buvid,
mobiApp: _mobiApp,
platform: _device,
channel: _biliChannel,
@@ -141,7 +152,7 @@ class GrpcReq {
GeneratedMessage request,
T Function(Uint8List) grpcParser,
) async {
final response = await Request().post(
final response = await Request().post<Uint8List>(
HttpString.appBaseUrl + url,
data: compressProtobuf(request.writeToBuffer()),
options: options,

View File

@@ -2,7 +2,6 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/http/api.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/login.dart';
import 'package:PiliPlus/http/ua_type.dart';
import 'package:PiliPlus/models/common/account_type.dart';
import 'package:PiliPlus/models/common/live_search_type.dart';
@@ -211,7 +210,7 @@ abstract final class LiveHttp {
queryParameters: params,
options: Options(
headers: {
'buvid': LoginHttp.buvid,
'buvid': recommend.buvid,
'fp_local':
'1111111111111111111111111111111111111111111111111111111111111111',
'fp_remote':
@@ -297,7 +296,7 @@ abstract final class LiveHttp {
queryParameters: params,
options: Options(
headers: {
'buvid': LoginHttp.buvid,
'buvid': recommend.buvid,
'fp_local':
'1111111111111111111111111111111111111111111111111111111111111111',
'fp_remote':

View File

@@ -17,9 +17,9 @@ import 'package:encrypt/encrypt.dart';
class LoginHttp {
static final String deviceId = LoginUtils.genDeviceId();
static String get buvid => LoginUtils.buvid;
static String get _buvid => AnonymousAccount().buvid;
static final Map<String, String> headers = {
'buvid': buvid,
'buvid': _buvid,
'env': 'prod',
'app-key': 'android_hd',
'user-agent': Constants.userAgent,
@@ -99,7 +99,7 @@ class LoginHttp {
int timestamp = DateTime.now().millisecondsSinceEpoch;
var data = {
'build': '2001100',
'buvid': buvid,
'buvid': _buvid,
'c_locale': 'zh_CN',
'channel': 'master',
'cid': cid,
@@ -108,10 +108,10 @@ class LoginHttp {
'gee_challenge': ?geeChallenge,
'gee_seccode': ?geeSeccode,
'gee_validate': ?geeValidate,
'local_id': buvid,
'local_id': _buvid,
// https://chinggg.github.io/post/appre/
'login_session_id': md5
.convert(utf8.encode(buvid + timestamp.toString()))
.convert(utf8.encode(_buvid + timestamp.toString()))
.toString(),
'mobi_app': 'android_hd',
'platform': 'android',
@@ -202,7 +202,7 @@ class LoginHttp {
Map<String, String> data = {
'bili_local_id': deviceId,
'build': '2001100',
'buvid': buvid,
'buvid': _buvid,
'c_locale': 'zh_CN',
'channel': 'master',
'device': 'phone',
@@ -221,7 +221,7 @@ class LoginHttp {
'gee_challenge': ?geeChallenge,
'gee_seccode': ?geeSeccode,
'gee_validate': ?geeValidate,
'local_id': buvid, //LoginUtils.generateBuvid(),
'local_id': _buvid, //LoginUtils.generateBuvid(),
'mobi_app': 'android_hd',
'password': passwordEncrypted,
'permission': 'ALL',
@@ -271,7 +271,7 @@ class LoginHttp {
Map<String, String> data = {
'bili_local_id': deviceId,
'build': '2001100',
'buvid': buvid,
'buvid': _buvid,
'c_locale': 'zh_CN',
'captcha_key': captchaKey,
'channel': 'master',
@@ -291,7 +291,7 @@ class LoginHttp {
),
'from_pv': 'main.my-information.my-login.0.click',
'from_url': Uri.encodeComponent('bilibili://user_center/mine'),
'local_id': buvid,
'local_id': _buvid,
'mobi_app': 'android_hd',
'platform': 'android',
's_locale': 'zh_CN',
@@ -452,7 +452,7 @@ class LoginHttp {
Map<String, String> data = {
'appkey': Constants.appKey,
'build': '2001100',
'buvid': buvid,
'buvid': _buvid,
// 'c_locale': 'zh_CN',
// 'channel': 'master',
'code': code,
@@ -462,7 +462,7 @@ class LoginHttp {
// 'device_platform': 'Android14vivo',
'disable_rcmd': '0',
'grant_type': 'authorization_code',
'local_id': buvid,
'local_id': _buvid,
'mobi_app': 'android_hd',
'platform': 'android',
// 's_locale': 'zh_CN',
@@ -505,7 +505,7 @@ class LoginHttp {
static Future<LoadingState<LoginDevicesData>> loginDevices() async {
final account = Accounts.main;
final buvid = LoginUtils.buvid;
final buvid = account.buvid;
final params = {
'local_id': buvid,
'buvid': buvid,

View File

@@ -4,7 +4,6 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/http/api.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/login.dart';
import 'package:PiliPlus/http/ua_type.dart';
import 'package:PiliPlus/models/common/account_type.dart';
import 'package:PiliPlus/models/common/video/video_type.dart';
@@ -112,7 +111,7 @@ class VideoHttp {
queryParameters: params,
options: Options(
headers: {
'buvid': LoginHttp.buvid,
'buvid': Accounts.get(AccountType.recommend).buvid,
'fp_local':
'1111111111111111111111111111111111111111111111111111111111111111',
'fp_remote':

View File

@@ -688,6 +688,8 @@ class LoginPageController extends GetxController
BiliCookieJar.fromList(cookieInfo),
tokenInfo['access_token'],
tokenInfo['refresh_token'],
{},
AnonymousAccount().buvid,
);
await Future.wait([account.onChange(), AnonymousAccount().delete()]);
for (int i = 0; i < AccountType.values.length; i++) {

View File

@@ -41,11 +41,9 @@ List<SettingsModel> get privacySettings => [
context: Get.context!,
builder: (context) {
return AlertDialog(
title: const Text('查看详情'),
title: const Text('账号模式详情'),
content: SingleChildScrollView(
child: Text(
AccountManager.apiTypeSet[AccountType.heartbeat]!.join('\n'),
),
child: _getAccountDetail(context),
),
actions: [
TextButton(
@@ -58,7 +56,26 @@ List<SettingsModel> get privacySettings => [
);
},
leading: const Icon(Icons.flag_outlined),
title: '了解无痕模式',
subtitle: '查看无痕模式作用的API列表',
title: '了解账号模式',
subtitle: '查看各个账号模式作用的API列表',
),
];
Widget _getAccountDetail(BuildContext context) {
final slivers = <Widget>[];
final theme = TextTheme.of(context);
for (var i in AccountType.values) {
final url = AccountManager.apiTypeSet[i];
if (url == null) continue;
slivers
..add(Center(child: Text(i.title, style: theme.titleMedium)))
..add(SelectableText(url.join('\n')));
}
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 8,
children: slivers,
);
}

View File

@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/models/common/account_type.dart';
import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/login_utils.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:hive/hive.dart';
@@ -32,6 +33,8 @@ sealed class Account {
String? get refresh => throw UnimplementedError();
String get buvid => throw UnimplementedError();
const Account();
}
@@ -51,6 +54,9 @@ class LoginAccount extends Account {
@override
@HiveField(3)
final Set<AccountType> type;
@override
@HiveField(4)
final String buvid;
@override
bool activited = false;
@@ -69,11 +75,19 @@ class LoginAccount extends Account {
late final String csrf =
cookieJar.domainCookies['bilibili.com']!['/']!['bili_jct']!.cookie.value;
@override
Future<void> delete() => _box.delete(_midStr);
bool _hasDelete = false;
@override
Future<void> onChange() => _box.put(_midStr, this);
Future<void> delete() {
assert(_hasDelete = true);
return _box.delete(_midStr);
}
@override
Future<void> onChange() {
assert(!_hasDelete);
return _box.put(_midStr, this);
}
@override
Map<String, dynamic>? toJson() => {
@@ -81,6 +95,7 @@ class LoginAccount extends Account {
'accessKey': accessKey,
'refresh': refresh,
'type': type.map((i) => i.index).toList(),
'buvid': buvid,
};
late final String _midStr = cookieJar
@@ -95,7 +110,9 @@ class LoginAccount extends Account {
this.accessKey,
this.refresh, [
Set<AccountType>? type,
]) : type = type ?? {} {
String? buvid,
]) : type = type ?? {},
buvid = buvid ?? LoginUtils.generateBuvid() {
cookieJar.setBuvid3();
}
@@ -104,6 +121,7 @@ class LoginAccount extends Account {
json['accessKey'],
json['refresh'],
(json['type'] as Iterable?)?.map((i) => AccountType.values[i]).toSet(),
json['buvid'],
);
@override
@@ -131,12 +149,15 @@ class AnonymousAccount extends Account {
final String csrf = '';
@override
final Map<String, String> headers = Constants.baseHeaders;
@override
String buvid = LoginUtils.generateBuvid();
@override
bool activited = false;
@override
Future<void> delete() async {
buvid = LoginUtils.generateBuvid();
await cookieJar.deleteAll();
cookieJar.setBuvid3();
}

View File

@@ -18,13 +18,14 @@ class LoginAccountAdapter extends TypeAdapter<LoginAccount> {
fields[1] as String?,
fields[2] as String?,
(fields[3] as List?)?.cast<AccountType>().toSet(),
fields[4] as String?,
);
}
@override
void write(BinaryWriter writer, LoginAccount obj) {
writer
..writeByte(4)
..writeByte(5)
..writeByte(0)
..write(obj.cookieJar)
..writeByte(1)
@@ -32,7 +33,9 @@ class LoginAccountAdapter extends TypeAdapter<LoginAccount> {
..writeByte(2)
..write(obj.refresh)
..writeByte(3)
..write(obj.type.toList());
..write(obj.type.toList())
..writeByte(4)
..write(obj.buvid);
}
@override

View File

@@ -49,11 +49,12 @@ abstract class LoginUtils {
static Future<void> onLoginMain() async {
final account = Accounts.main;
GrpcReq.updateHeaders(account.accessKey);
setWebCookie(account);
RequestUtils.syncHistoryStatus();
final result = await UserHttp.userInfo();
if (result.isSuccess) {
GrpcReq.updateHeaders(account.accessKey, account.buvid);
setWebCookie(account);
RequestUtils.syncHistoryStatus();
final UserInfoData data = result.data;
if (data.isLogin == true) {
Get.find<AccountService>()
@@ -114,7 +115,7 @@ abstract class LoginUtils {
..face.value = ''
..isLogin.value = false;
GrpcReq.updateHeaders(null);
GrpcReq.updateHeaders(null, AnonymousAccount().buvid);
await Future.wait([
if (!Platform.isWindows) web.CookieManager.instance().deleteAllCookies(),
@@ -166,8 +167,6 @@ abstract class LoginUtils {
return 'XY${md5Str[2]}${md5Str[12]}${md5Str[22]}$md5Str';
}
static final buvid = Pref.buvid;
// static String getUUID() {
// return const Uuid().v4().replaceAll('-', '');
// }

View File

@@ -221,8 +221,7 @@ abstract class LocalCacheKey {
blackMids = 'blackMids',
danmakuFilterRules = 'danmakuFilterRules',
mixinKey = 'mixinKey',
timeStamp = 'timeStamp',
buvid = 'buvid';
timeStamp = 'timeStamp';
}
abstract class VideoBoxKey {

View File

@@ -26,7 +26,6 @@ import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
import 'package:PiliPlus/utils/context_ext.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/login_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:flutter/material.dart';
@@ -801,15 +800,6 @@ abstract class Pref {
static bool get silentDownImg =>
_setting.get(SettingBoxKey.silentDownImg, defaultValue: false);
static String get buvid {
String? buvid = _localCache.get(LocalCacheKey.buvid);
if (buvid == null) {
buvid = LoginUtils.generateBuvid();
_localCache.put(LocalCacheKey.buvid, buvid);
}
return buvid;
}
static bool get showMemberShop =>
_setting.get(SettingBoxKey.showMemberShop, defaultValue: false);