diff --git a/lib/common/constants.dart b/lib/common/constants.dart index 08a54805..cac13688 100644 --- a/lib/common/constants.dart +++ b/lib/common/constants.dart @@ -9,7 +9,11 @@ class StyleString { } class Constants { - static const String appKey = '27eb53fc9058f8c3'; + // 27eb53fc9058f8c3 移动端 Android + // 4409e2ce8ffd12b8 TV端 + static const String appKey = '4409e2ce8ffd12b8'; + // 59b43e04ad6965f34319062b478f83dd TV端 + static const String appSec = '59b43e04ad6965f34319062b478f83dd'; static const String thirdSign = '04224646d1fea004e79606d3b038c84a'; static const String thirdApi = 'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png'; diff --git a/lib/http/api.dart b/lib/http/api.dart index af7d8b9e..0125c742 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -373,6 +373,18 @@ class Api { 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'; diff --git a/lib/http/member.dart b/lib/http/member.dart index 9dc6da85..a2af8d82 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -1,5 +1,6 @@ -import 'dart:ffi'; - +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'; @@ -8,6 +9,8 @@ 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 { @@ -359,4 +362,89 @@ class MemberHttp { }; } } + + // 获取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)); + 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'], + }; + } + } } diff --git a/lib/pages/setting/privacy_setting.dart b/lib/pages/setting/privacy_setting.dart index a6d085ab..07a02318 100644 --- a/lib/pages/setting/privacy_setting.dart +++ b/lib/pages/setting/privacy_setting.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/http/member.dart'; import 'package:pilipala/utils/storage.dart'; class PrivacySetting extends StatefulWidget { @@ -53,6 +54,16 @@ class _PrivacySettingState extends State { title: Text('黑名单管理', style: titleStyle), subtitle: Text('已拉黑用户', style: subTitleStyle), ), + ListTile( + onTap: () { + if (!userLogin) { + SmartDialog.showToast('请先登录'); + } + MemberHttp.cookieToKey(); + }, + dense: false, + title: Text('刷新access_key', style: titleStyle), + ), ], ), ); diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 19979df6..25488d59 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -2,8 +2,10 @@ // ignore_for_file: non_constant_identifier_names import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'dart:math'; +import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -297,4 +299,18 @@ class Utils { return '$formattedHours:$formattedMinutes'; } + + static String appSign( + Map params, String appkey, String appsec) { + params['appkey'] = appkey; + var searchParams = Uri(queryParameters: params).query; + var sortedParams = searchParams.split('&')..sort(); + var sortedQueryString = sortedParams.join('&'); + + var appsecString = sortedQueryString + appsec; + var md5Digest = md5.convert(utf8.encode(appsecString)); + var md5String = md5Digest.toString(); // 获取MD5哈希值 + + return md5String; + } }