* tweak

* opt: show bar

* opt: crc32

* opt: appsign

* opt: Get

* opt: compress only if large

* opt: wbi

* tweak

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>

---------

Signed-off-by: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com>
Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2025-12-23 12:57:19 +08:00
committed by GitHub
parent 31e5692dff
commit 521ca3ad18
31 changed files with 165 additions and 210 deletions

View File

@@ -12,6 +12,7 @@ import 'package:protobuf/protobuf.dart' show GeneratedMessage;
abstract final class GrpcReq {
static const _isolateSize = 256 * 1024;
static const _gzipMinLength = 64;
static final options = Options(
contentType: 'application/grpc',
@@ -19,9 +20,12 @@ abstract final class GrpcReq {
);
static Uint8List compressProtobuf(Uint8List proto) {
final compress = proto.length > _gzipMinLength;
if (compress) {
proto = const GZipEncoder().encodeBytes(proto);
}
return Uint8List(5 + proto.length)
..[0] = 1
..[0] = compress ? 1 : 0
..buffer.asByteData(1, 4).setInt32(0, proto.length, Endian.big)
..setAll(5, proto);
}
@@ -48,7 +52,7 @@ abstract final class GrpcReq {
}
}
static Future<LoadingState<T>> request<T>(
static Future<LoadingState<T>> request<T extends GeneratedMessage>(
String url,
GeneratedMessage request,
T Function(Uint8List) grpcParser, {

View File

@@ -173,7 +173,6 @@ abstract final class LiveHttp {
}) async {
final params = {
'access_key': ?recommend.accessKey,
'appkey': Constants.appKey,
'channel': 'master',
'actionKey': 'appkey',
'build': 8430300,
@@ -194,7 +193,6 @@ abstract final class LiveHttp {
's_locale': 'zh_CN',
'scale': 2,
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(
@@ -250,7 +248,6 @@ abstract final class LiveHttp {
}) async {
final params = {
'access_key': ?recommend.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'channel': 'master',
'area_id': ?areaId,
@@ -276,7 +273,6 @@ abstract final class LiveHttp {
's_locale': 'zh_CN',
'scale': 2,
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(
@@ -310,7 +306,6 @@ abstract final class LiveHttp {
static Future<LoadingState<List<AreaList>?>> liveAreaList() async {
final params = {
'access_key': ?recommend.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'build': 8430300,
'channel': 'master',
@@ -322,7 +317,6 @@ abstract final class LiveHttp {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(
@@ -343,7 +337,6 @@ abstract final class LiveHttp {
static Future<LoadingState<List<AreaItem>>> getLiveFavTag() async {
final params = {
'access_key': ?Accounts.main.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'build': 8430300,
'channel': 'master',
@@ -355,7 +348,6 @@ abstract final class LiveHttp {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(
@@ -381,7 +373,6 @@ abstract final class LiveHttp {
final data = {
'tags': ids,
'access_key': Accounts.main.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'build': 8430300,
'channel': 'master',
@@ -393,7 +384,6 @@ abstract final class LiveHttp {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(data);
var res = await Request().post(
@@ -414,7 +404,6 @@ abstract final class LiveHttp {
}) async {
final params = {
'access_key': ?recommend.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'build': 8430300,
'channel': 'master',
@@ -429,7 +418,6 @@ abstract final class LiveHttp {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(
@@ -452,7 +440,6 @@ abstract final class LiveHttp {
}) async {
final params = {
'access_key': ?recommend.accessKey,
'appkey': Constants.appKey,
'actionKey': 'appkey',
'build': 8430300,
'channel': 'master',
@@ -467,7 +454,6 @@ abstract final class LiveHttp {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statisticsApp,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
'type': type.name,
};
AppSign.appSign(params);

View File

@@ -36,7 +36,6 @@ abstract final class LoginHttp {
var params = {
// 'local_id': 'Y952A395BB157D305D8A8340FC2AAECECE17',
'local_id': '0',
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
'platform': 'android',
'mobi_app': 'android_hd',
};
@@ -59,7 +58,6 @@ abstract final class LoginHttp {
var params = {
'auth_code': authCode,
'local_id': '0',
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
};
AppSign.appSign(params);
var res = await Request().post(Api.qrcodePoll, queryParameters: params);
@@ -118,7 +116,7 @@ abstract final class LoginHttp {
'local_id': buvid,
// https://chinggg.github.io/post/appre/
'login_session_id': md5
.convert(utf8.encode(buvid + timestamp.toString()))
.convert(ascii.encode(buvid + timestamp.toString()))
.toString(),
'mobi_app': 'android_hd',
'platform': 'android',
@@ -236,7 +234,6 @@ abstract final class LoginHttp {
'recaptcha_token': ?recaptchaToken,
's_locale': 'zh_CN',
'statistics': Constants.statistics,
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
'username': username,
};
AppSign.appSign(data);
@@ -304,7 +301,6 @@ abstract final class LoginHttp {
's_locale': 'zh_CN',
'statistics': Constants.statistics,
'tel': tel,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(data);
var res = await Request().post(
@@ -456,8 +452,7 @@ abstract final class LoginHttp {
static Future oauth2AccessToken({
required String code,
}) async {
Map<String, String> data = {
'appkey': Constants.appKey,
final Map<String, String> data = {
'build': '2001100',
'buvid': buvid,
// 'c_locale': 'zh_CN',
@@ -474,7 +469,6 @@ abstract final class LoginHttp {
'platform': 'android',
// 's_locale': 'zh_CN',
// 'statistics': Constants.statistics,
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
};
AppSign.appSign(data);
var res = await Request().post(
@@ -523,7 +517,6 @@ abstract final class LoginHttp {
'platform': 'android',
'access_key': account.accessKey,
'statistics': Constants.statistics,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
var res = await Request().get(

View File

@@ -356,7 +356,7 @@ abstract final class MemberHttp {
'mid': mid,
'ps': ps,
'tid': tid,
'pn': pn,
'pn': ?pn,
'keyword': ?keyword,
'order': order,
'platform': 'web',
@@ -392,7 +392,7 @@ abstract final class MemberHttp {
@pragma('vm:notify-debugger-on-exception')
static Future<LoadingState<DynamicsDataModel>> memberDynamic({
String? offset,
int? mid,
required int mid,
}) async {
String dmImgStr = Utils.base64EncodeRandomString(16, 64);
String dmCoverImgStr = Utils.base64EncodeRandomString(32, 128);
@@ -648,7 +648,7 @@ abstract final class MemberHttp {
required int pn,
required String name,
}) async {
Map<String, dynamic> data = {
final data = {
'vmid': mid,
'pn': pn,
'ps': ps,

View File

@@ -383,7 +383,7 @@ abstract final class MsgHttp {
}) async {
String csrf = Accounts.main.csrf;
final devId = getDevId();
Map<String, dynamic> data = {
final data = {
'msg': {
'sender_uid': senderUid,
'receiver_id': receiverId,

View File

@@ -73,7 +73,7 @@ abstract final class SponsorBlock {
assert((type == null) == (category == null));
final res = await Request().post(
_api(SponsorBlockApi.voteOnSponsorTime),
data: {
queryParameters: {
'UUID': uuid,
'type': ?type,
'category': ?category?.name,

View File

@@ -801,7 +801,7 @@ abstract final class VideoHttp {
final params = await WbiSign.makSign({
'bvid': bvid,
'cid': cid,
'up_mid': upMid,
'up_mid': ?upMid,
});
var res = await Request().get(Api.aiConclusion, queryParameters: params);
final int? code = res.data['code'];
@@ -1067,7 +1067,6 @@ abstract final class VideoHttp {
'playurl_type': playurlType,
'protocol': 0,
'qn': qn ?? 80,
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
};
AppSign.appSign(params);
final res = await Request().get(

View File

@@ -1,4 +1,3 @@
abstract class EnumWithLabel {
mixin EnumWithLabel on Enum {
String get label;
int get index;
}

View File

@@ -26,8 +26,7 @@ class LiveIndexData {
areaItem = LiveCardList.fromJson(json);
break;
case 'small_card_v1':
cardList ??= <LiveCardList>[];
cardList!.add(LiveCardList.fromJson(json));
(cardList ??= <LiveCardList>[]).add(LiveCardList.fromJson(json));
break;
}
}

View File

@@ -21,14 +21,11 @@ class LiveFollowData {
title = json['title'] as String?;
pageSize = json['pageSize'] as int?;
totalPage = json['totalPage'] as int?;
if ((json['list'] as List<dynamic>?)?.isNotEmpty == true) {
list = <LiveFollowItem>[];
for (var json in json['list']) {
if (json['live_status'] == 1) {
list!.add(LiveFollowItem.fromJson(json));
}
}
}
list = (json['list'] as List<dynamic>?)
?.cast<Map<String, dynamic>>()
.where((i) => i['live_status'] == 1)
.map(LiveFollowItem.fromJson)
.toList();
count = json['count'] as int?;
liveCount = json['live_count'] as int?;
}

View File

@@ -12,7 +12,6 @@ import 'package:PiliPlus/utils/date_utils.dart';
import 'package:PiliPlus/utils/grid.dart';
import 'package:PiliPlus/utils/num_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -26,7 +25,7 @@ class ArticleListPage extends StatefulWidget {
class _ArticleListPageState extends State<ArticleListPage> with GridMixin {
final _controller = Get.put(
ArticleListController(),
tag: Utils.generateRandomString(8),
tag: Get.parameters['id']!,
);
late EdgeInsets padding;

View File

@@ -1,5 +1,3 @@
import 'dart:async';
import 'package:PiliPlus/pages/common/common_controller.dart';
import 'package:PiliPlus/pages/home/controller.dart';
import 'package:PiliPlus/pages/main/controller.dart';
@@ -14,8 +12,8 @@ abstract class CommonPageState<
>
extends State<T> {
R get controller;
StreamController<bool>? mainStream;
StreamController<bool>? searchBarStream;
RxBool? showBottomBar;
RxBool? showSearchBar;
// late double _downScrollCount = 0.0; // 向下滚动计数器
late double _upScrollCount = 0.0; // 向上滚动计数器
double? _lastScrollPosition; // 记录上次滚动位置
@@ -27,18 +25,18 @@ abstract class CommonPageState<
void initState() {
super.initState();
try {
mainStream = Get.find<MainController>().bottomBarStream;
searchBarStream = Get.find<HomeController>().searchBarStream;
showBottomBar = Get.find<MainController>().bottomBar;
showSearchBar = Get.find<HomeController>().searchBar;
} catch (_) {}
if (_enableScrollThreshold &&
(mainStream != null || searchBarStream != null)) {
(showBottomBar != null || showSearchBar != null)) {
controller.scrollController.addListener(listener);
}
}
Widget onBuild(Widget child) {
if (!_enableScrollThreshold &&
(mainStream != null || searchBarStream != null)) {
(showBottomBar != null || showSearchBar != null)) {
return NotificationListener<UserScrollNotification>(
onNotification: onNotification,
child: child,
@@ -51,11 +49,11 @@ abstract class CommonPageState<
if (notification.metrics.axis == Axis.horizontal) return false;
final direction = notification.direction;
if (direction == ScrollDirection.forward) {
mainStream?.add(true);
searchBarStream?.add(true);
showBottomBar?.value = true;
showSearchBar?.value = true;
} else if (direction == ScrollDirection.reverse) {
mainStream?.add(false);
searchBarStream?.add(false);
showBottomBar?.value = false;
showSearchBar?.value = false;
}
return false;
}
@@ -72,8 +70,8 @@ abstract class CommonPageState<
final double scrollDelta = currentPosition - _lastScrollPosition!;
if (direction == ScrollDirection.reverse) {
mainStream?.add(false);
searchBarStream?.add(false); // // 向下滚动,累加向下滚动距离,重置向上滚动计数器
showBottomBar?.value = false;
showSearchBar?.value = false; // // 向下滚动,累加向下滚动距离,重置向上滚动计数器
_upScrollCount = 0.0; // 重置向上滚动计数器
// if (scrollDelta > 0) {
// _downScrollCount += scrollDelta;
@@ -93,8 +91,8 @@ abstract class CommonPageState<
// 当累计向上滚动距离超过阈值时,显示顶底栏
if (_upScrollCount >= _scrollThreshold) {
mainStream?.add(true);
searchBarStream?.add(true);
showBottomBar?.value = true;
showSearchBar?.value = true;
}
}
}
@@ -105,6 +103,8 @@ abstract class CommonPageState<
@override
void dispose() {
showSearchBar = null;
showBottomBar = null;
controller.scrollController.removeListener(listener);
super.dispose();
}

View File

@@ -17,7 +17,6 @@ import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:get/get.dart' hide ContextExtensionss;
abstract class CommonDynPageState<T extends StatefulWidget> extends State<T>
@@ -51,14 +50,9 @@ abstract class CommonDynPageState<T extends StatefulWidget> extends State<T>
void listener() {
final pos = scrollController.positions;
controller.showTitle.value = pos.first.pixels > 55;
final direction1 = pos.first.userScrollDirection;
late final direction2 = pos.last.userScrollDirection;
if (direction1 == ScrollDirection.forward ||
direction2 == ScrollDirection.forward) {
if (pos.any((e) => e.userScrollDirection == .forward)) {
showFab();
} else if (direction1 == ScrollDirection.reverse ||
direction2 == ScrollDirection.reverse) {
} else if (pos.any((e) => e.userScrollDirection == .reverse)) {
hideFab();
}
}

View File

@@ -3,7 +3,7 @@ import 'dart:convert';
import 'package:PiliPlus/http/danmaku_block.dart';
import 'package:PiliPlus/models/common/dm_block_type.dart';
import 'package:PiliPlus/models/user/danmaku_block.dart';
import 'package:crclib/catalog.dart';
import 'package:archive/archive.dart' show getCrc32;
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
@@ -64,7 +64,7 @@ class DanmakuBlockController extends GetxController
required int type,
}) async {
if (type == 2) {
filter = Crc32Xz().convert(utf8.encode(filter)).toRadixString(16);
filter = getCrc32(ascii.encode(filter), 0).toRadixString(16);
}
SmartDialog.showLoading(msg: '正在添加弹幕屏蔽规则……');
final result = await DanmakuFilterHttp.danmakuFilterAdd(

View File

@@ -7,6 +7,7 @@ import 'package:PiliPlus/pages/dynamics/controller.dart';
import 'package:PiliPlus/pages/dynamics/widgets/up_panel.dart';
import 'package:PiliPlus/pages/dynamics_create/view.dart';
import 'package:PiliPlus/pages/dynamics_tab/view.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:flutter/material.dart' hide DraggableScrollableSheet;
import 'package:get/get.dart';
@@ -19,7 +20,7 @@ class DynamicsPage extends StatefulWidget {
class _DynamicsPageState extends State<DynamicsPage>
with AutomaticKeepAliveClientMixin {
final DynamicsController _dynamicsController = Get.put(DynamicsController());
final _dynamicsController = Get.putOrFind(DynamicsController.new);
UpPanelPosition get upPanelPosition => _dynamicsController.upPanelPosition;
@override

View File

@@ -11,6 +11,7 @@ import 'package:PiliPlus/pages/dynamics/controller.dart';
import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart';
import 'package:PiliPlus/pages/dynamics_tab/controller.dart';
import 'package:PiliPlus/pages/main/controller.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/waterfall.dart';
import 'package:flutter/material.dart';
@@ -33,9 +34,10 @@ class _DynamicsTabPageState
StreamSubscription? _listener;
late final MainController _mainController = Get.find<MainController>();
DynamicsController dynamicsController = Get.put(DynamicsController());
DynamicsController dynamicsController = Get.putOrFind(DynamicsController.new);
@override
late DynamicsTabController controller = Get.put(
late final DynamicsTabController controller = Get.putOrFind(
() =>
DynamicsTabController(dynamicsType: widget.dynamicsType)
..mid = dynamicsController.mid.value,
tag: widget.dynamicsType.name,

View File

@@ -19,8 +19,7 @@ class HomeController extends GetxController
late List<HomeTabType> tabs;
late TabController tabController;
StreamController<bool>? searchBarStream;
final bool hideSearchBar = Pref.hideSearchBar;
RxBool? searchBar;
final bool useSideBar = Pref.useSideBar;
bool enableSearchWord = Pref.enableSearchWord;
@@ -38,8 +37,8 @@ class HomeController extends GetxController
void onInit() {
super.onInit();
if (hideSearchBar) {
searchBarStream = StreamController<bool>.broadcast();
if (Pref.hideSearchBar) {
searchBar = true.obs;
}
if (enableSearchWord) {
@@ -90,10 +89,4 @@ class HomeController extends GetxController
}
} catch (_) {}
}
@override
void onClose() {
searchBarStream?.close();
super.onClose();
}
}

View File

@@ -6,6 +6,7 @@ import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/pages/home/controller.dart';
import 'package:PiliPlus/pages/main/controller.dart';
import 'package:PiliPlus/pages/mine/controller.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/extension/size_ext.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:flutter/material.dart';
@@ -21,8 +22,8 @@ class HomePage extends StatefulWidget {
class _HomePageState extends State<HomePage>
with AutomaticKeepAliveClientMixin {
final HomeController _homeController = Get.put(HomeController());
final MainController _mainController = Get.put(MainController());
final _homeController = Get.putOrFind(HomeController.new);
final _mainController = Get.find<MainController>();
@override
bool get wantKeepAlive => true;
@@ -149,30 +150,28 @@ class _HomePageState extends State<HomePage>
}
Widget customAppBar(ThemeData theme) {
if (!_homeController.hideSearchBar) {
if (_homeController.searchBar case final searchBar?) {
return Obx(() {
final showSearchBar = searchBar.value;
return AnimatedOpacity(
opacity: showSearchBar ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: AnimatedContainer(
curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 500),
height: showSearchBar ? 52 : 0,
padding: const EdgeInsets.fromLTRB(14, 6, 14, 0),
child: searchBarAndUser(theme),
),
);
});
} else {
return Container(
height: 52,
padding: const EdgeInsets.fromLTRB(14, 6, 14, 0),
child: searchBarAndUser(theme),
);
}
return StreamBuilder(
stream: _homeController.searchBarStream?.stream.distinct(),
initialData: true,
builder: (BuildContext context, AsyncSnapshot snapshot) {
return AnimatedOpacity(
opacity: snapshot.data ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: AnimatedContainer(
curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 500),
height: snapshot.data ? 52 : 0,
padding: const EdgeInsets.fromLTRB(14, 6, 14, 0),
child: searchBarAndUser(theme),
),
);
},
);
}
Widget searchBar(ThemeData theme) {

View File

@@ -12,6 +12,7 @@ import 'package:PiliPlus/pages/dynamics/controller.dart';
import 'package:PiliPlus/pages/home/controller.dart';
import 'package:PiliPlus/pages/mine/view.dart';
import 'package:PiliPlus/services/account_service.dart';
import 'package:PiliPlus/utils/extension/get_ext.dart';
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart';
@@ -30,8 +31,7 @@ class MainController extends GetxController
List<NavigationBarType> navigationBars = <NavigationBarType>[];
StreamController<bool>? bottomBarStream;
late bool hideTabBar = Pref.hideTabBar;
RxBool? bottomBar;
late dynamic controller;
final RxInt selectedIndex = 0.obs;
@@ -41,12 +41,10 @@ class MainController extends GetxController
late int dynamicPeriod = Pref.dynamicPeriod * 60 * 1000;
late int _lastCheckDynamicAt = 0;
late bool hasDyn = false;
late final DynamicsController dynamicController = Get.put(
DynamicsController(),
);
late final dynamicController = Get.putOrFind(DynamicsController.new);
late bool hasHome = false;
late final HomeController homeController = Get.put(HomeController());
late final homeController = Get.putOrFind(HomeController.new);
late DynamicBadgeMode msgBadgeMode = Pref.msgBadgeMode;
late Set<MsgUnReadType> msgUnReadTypes = Pref.msgUnReadTypeV2;
@@ -84,8 +82,8 @@ class MainController extends GetxController
)
: PageController(initialPage: selectedIndex.value);
if (navigationBars.length > 1 && hideTabBar) {
bottomBarStream = StreamController<bool>.broadcast();
if (navigationBars.length > 1 && Pref.hideTabBar) {
bottomBar = true.obs;
}
dynamicBadgeMode = DynamicBadgeMode.values[Pref.dynamicBadgeMode];
@@ -321,13 +319,13 @@ class MainController extends GetxController
void setSearchBar() {
if (hasHome) {
homeController.searchBarStream?.add(true);
homeController.searchBar?.value = true;
}
}
@override
void onClose() {
bottomBarStream?.close();
bottomBar?.close();
controller.dispose();
super.onClose();
}

View File

@@ -36,7 +36,7 @@ class MainApp extends StatefulWidget {
class _MainAppState extends State<MainApp>
with RouteAware, WidgetsBindingObserver, WindowListener, TrayListener {
final MainController _mainController = Get.put(MainController());
final _mainController = Get.put(MainController());
late final _setting = GStorage.setting;
@override
@@ -294,7 +294,7 @@ class _MainAppState extends State<MainApp>
.toList(),
),
)
: const SizedBox.shrink()
: null
: null;
return PopScope(
canPop: false,
@@ -305,7 +305,7 @@ class _MainAppState extends State<MainApp>
if (_mainController.selectedIndex.value != 0) {
_mainController
..setIndex(0)
..bottomBarStream?.add(true)
..bottomBar?.value = true
..setSearchBar();
} else {
onBack();
@@ -439,27 +439,27 @@ class _MainAppState extends State<MainApp>
],
),
),
bottomNavigationBar: useBottomNav
? _mainController.hideTabBar
? StreamBuilder(
stream: _mainController.bottomBarStream?.stream
.distinct(),
initialData: true,
builder: (context, AsyncSnapshot snapshot) {
return AnimatedSlide(
bottomNavigationBar: _buildBottom(bottomNav),
),
),
);
}
Widget? _buildBottom(Widget? bottomNav) {
if (bottomNav != null) {
if (_mainController.bottomBar case final bottomBar?) {
return Obx(
() => AnimatedSlide(
curve: Curves.easeInOutCubicEmphasized,
duration: const Duration(milliseconds: 500),
offset: Offset(0, snapshot.data ? 0 : 1),
offset: Offset(0, bottomBar.value ? 0 : 1),
child: bottomNav,
);
},
)
: bottomNav
: null,
),
),
);
}
}
return bottomNav;
}
Widget _buildIcon({
required NavigationBarType type,

View File

@@ -363,7 +363,6 @@ class _EditProfilePageState extends State<EditProfilePage> {
'platform': 'android',
's_locale': 'zh_CN',
'statistics': Constants.statistics,
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
if (type == ProfileType.uname)
'uname': _textController.text
else if (type == ProfileType.sign)
@@ -500,15 +499,15 @@ class _EditProfilePageState extends State<EditProfilePage> {
toolbarColor: theme.colorScheme.secondaryContainer,
toolbarWidgetColor: theme.colorScheme.onSecondaryContainer,
statusBarLight: theme.colorScheme.isLight,
aspectRatioPresets: [CropAspectRatioPresetCustom()],
aspectRatioPresets: const [CropAspectRatioPresetCustom()],
lockAspectRatio: true,
hideBottomControls: true,
cropStyle: CropStyle.circle,
initAspectRatio: CropAspectRatioPresetCustom(),
initAspectRatio: const CropAspectRatioPresetCustom(),
),
IOSUiSettings(
title: '裁剪',
aspectRatioPresets: [CropAspectRatioPresetCustom()],
aspectRatioPresets: const [CropAspectRatioPresetCustom()],
cropStyle: CropStyle.circle,
aspectRatioLockEnabled: true,
resetAspectRatioEnabled: false,
@@ -556,8 +555,10 @@ class _EditProfilePageState extends State<EditProfilePage> {
}
class CropAspectRatioPresetCustom implements CropAspectRatioPresetData {
const CropAspectRatioPresetCustom();
@override
(int, int)? get data => (1, 1);
(int, int) get data => const (1, 1);
@override
String get name => '1x1 (customized)';

View File

@@ -245,7 +245,7 @@ List<SettingsModel> get styleSettings => [
},
);
if (result != null) {
MainController mainController = Get.put(MainController())
final mainController = Get.find<MainController>()
..dynamicBadgeMode = DynamicBadgeMode.values[result.index];
if (mainController.dynamicBadgeMode != DynamicBadgeMode.hidden) {
mainController.getUnreadDynamic();
@@ -275,7 +275,7 @@ List<SettingsModel> get styleSettings => [
},
);
if (result != null) {
MainController mainController = Get.put(MainController())
final mainController = Get.find<MainController>()
..msgBadgeMode = DynamicBadgeMode.values[result.index];
if (mainController.msgBadgeMode != DynamicBadgeMode.hidden) {
mainController.queryUnreadMsg(true);
@@ -304,7 +304,7 @@ List<SettingsModel> get styleSettings => [
},
);
if (result != null) {
MainController mainController = Get.put(MainController())
final mainController = Get.find<MainController>()
..msgUnReadTypes = result;
if (mainController.msgBadgeMode != DynamicBadgeMode.hidden) {
mainController.queryUnreadMsg();

View File

@@ -42,8 +42,8 @@ import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:archive/archive.dart' show getCrc32;
import 'package:canvas_danmaku/canvas_danmaku.dart';
import 'package:crclib/catalog.dart';
import 'package:dio/dio.dart' show Options;
import 'package:easy_debounce/easy_throttle.dart';
import 'package:floating/floating.dart';
@@ -329,9 +329,10 @@ class PlPlayerController {
bool showDanmaku = true;
Set<int> dmState = <int>{};
late final mergeDanmaku = Pref.mergeDanmaku;
late final String midHash = Crc32Xz()
.convert(utf8.encode(Accounts.main.mid.toString()))
.toRadixString(16);
late final String midHash = getCrc32(
ascii.encode(Accounts.main.mid.toString()),
0,
).toRadixString(16);
// 弹幕相关配置
late Set<int> blockTypes = Pref.danmakuBlockType;
late bool blockColorful = blockTypes.contains(6);

View File

@@ -538,8 +538,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
final List<SectionItem> sections = videoDetail.ugcSeason!.sections!;
for (int i = 0; i < sections.length; i++) {
final List<EpisodeItem> episodesList = sections[i].episodes!;
for (int j = 0; j < episodesList.length; j++) {
if (episodesList[j].cid == plPlayerController.cid) {
for (var item in episodesList) {
if (item.cid == currentCid) {
index = i;
episodes = episodesList;
break;
@@ -2102,7 +2102,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
return Transform.flip(
flipX: plPlayerController.flipX.value,
flipY: plPlayerController.flipY.value,
filterQuality: FilterQuality.low,
child: FittedBox(
fit: videoFit.boxFit,
alignment: widget.alignment,

View File

@@ -440,9 +440,9 @@ class DownloadService extends GetxService {
}
}
Future<void> _updateBiliDownloadEntryJson(BiliDownloadEntryInfo entry) async {
Future<void> _updateBiliDownloadEntryJson(BiliDownloadEntryInfo entry) {
final entryJsonFile = File(path.join(entry.entryDirPath, _entryFile));
await entryJsonFile.writeAsString(jsonEncode(entry.toJson()));
return entryJsonFile.writeAsString(jsonEncode(entry.toJson()));
}
void _onReceive(int progress, int total) {

View File

@@ -77,8 +77,6 @@ class AccountManager extends Interceptor {
if (!account.accessKey.isNullOrEmpty) {
dataPtr['access_key'] = account.accessKey!;
}
dataPtr['ts'] ??= (DateTime.now().millisecondsSinceEpoch ~/ 1000)
.toString();
AppSign.appSign(dataPtr);
// if (kDebugMode) debugPrint(dataPtr.toString());
}

View File

@@ -9,10 +9,14 @@ abstract final class AppSign {
String appkey = Constants.appKey,
String appsec = Constants.appSec,
}) {
params['appkey'] = appkey;
final sorted = Map.fromEntries(
params.entries.toList()..sort((a, b) => a.key.compareTo(b.key)),
assert(
params['appkey'] == null,
'appkey-appsec should be provided in appSign',
);
params['appkey'] = appkey;
params['ts'] ??= (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString();
final sorted = params.entries.toList()
..sort((a, b) => a.key.compareTo(b.key));
params['sign'] = md5
.convert(utf8.encode(_makeQueryFromParametersDefault(sorted) + appsec))
.toString(); // 获取MD5哈希值
@@ -20,12 +24,14 @@ abstract final class AppSign {
/// from [Uri]
static String _makeQueryFromParametersDefault(
Map<String, dynamic /*String?|Iterable<String>*/> queryParameters,
List<MapEntry<String, dynamic /*String?|Iterable<String>*/>>
queryParameters,
) {
var result = StringBuffer();
var separator = '';
void writeParameter(String key, String? value) {
assert(value != null, 'remove null value');
result.write(separator);
separator = '&';
result.write(Uri.encodeQueryComponent(key));
@@ -36,15 +42,15 @@ abstract final class AppSign {
}
}
queryParameters.forEach((key, value) {
if (value case Iterable<String> values) {
for (var i in queryParameters) {
if (i.value case Iterable<String> values) {
for (final String value in values) {
writeParameter(key, value);
writeParameter(i.key, value);
}
} else {
writeParameter(key, value?.toString());
writeParameter(i.key, i.value?.toString());
}
}
});
return result.toString();
}
}

View File

@@ -84,7 +84,7 @@ abstract final class IdUtils {
return '';
}
var midByte = utf8.encode(uid.toString());
var midByte = ascii.encode(uid.toString());
const key = 'ad1va46a7lza';
for (int i = 0; i < midByte.length; i++) {

View File

@@ -11,13 +11,11 @@ import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:crypto/crypto.dart';
import 'package:hive/hive.dart';
import 'package:synchronized/synchronized.dart';
abstract final class WbiSign {
static Box localCache = GStorage.localCache;
static final Lock lock = Lock();
static final RegExp chrFilter = RegExp(r"[!\'\(\)\*]");
static const mixinKeyEncTab = <int>[
static Box get _localCache => GStorage.localCache;
static final RegExp _chrFilter = RegExp(r"[!\'\(\)\*]");
static const _mixinKeyEncTab = <int>[
46,
47,
18,
@@ -52,20 +50,23 @@ abstract final class WbiSign {
13,
];
static Future<String>? _future;
// 对 imgKey 和 subKey 进行字符顺序打乱编码
static String getMixinKey(String orig) {
return mixinKeyEncTab.map((i) => orig[i]).join();
final codeUnits = orig.codeUnits;
return String.fromCharCodes(_mixinKeyEncTab.map((i) => codeUnits[i]));
}
// 为请求参数进行 wbi 签名
static void encWbi(Map<String, dynamic> params, String mixinKey) {
static void encWbi(Map<String, Object> params, String mixinKey) {
params['wts'] = DateTime.now().millisecondsSinceEpoch ~/ 1000;
// 按照 key 重排参数
final List<String> keys = params.keys.toList()..sort();
final queryStr = keys
.map(
(i) =>
'${Uri.encodeComponent(i)}=${Uri.encodeComponent(params[i].toString().replaceAll(chrFilter, ''))}',
'${Uri.encodeComponent(i)}=${Uri.encodeComponent(params[i].toString().replaceAll(_chrFilter, ''))}',
)
.join('&');
params['w_rid'] = md5
@@ -73,30 +74,19 @@ abstract final class WbiSign {
.toString(); // 计算 w_rid
}
// 获取最新的 img_key 和 sub_key 可以从缓存中获取
static Future<String> getWbiKeys() async {
final DateTime nowDate = DateTime.now();
String? mixinKey = localCache.get(LocalCacheKey.mixinKey);
if (mixinKey != null &&
DateTime.fromMillisecondsSinceEpoch(
localCache.get(LocalCacheKey.timeStamp) as int,
).day ==
nowDate.day) {
return mixinKey;
}
static Future<String> _getWbiKeys(DateTime nowDate) async {
final resp = await Request().get(Api.userInfo);
try {
final wbiUrls = resp.data['data']['wbi_img'];
mixinKey = getMixinKey(
final mixinKey = getMixinKey(
Utils.getFileName(wbiUrls['img_url'], fileExt: false) +
Utils.getFileName(wbiUrls['sub_url'], fileExt: false),
);
localCache
_localCache
..put(LocalCacheKey.mixinKey, mixinKey)
..put(LocalCacheKey.timeStamp, nowDate.millisecondsSinceEpoch);
..put(LocalCacheKey.timeStamp, DateTime.now().millisecondsSinceEpoch);
return mixinKey;
} catch (_) {
@@ -104,11 +94,25 @@ abstract final class WbiSign {
}
}
static Future<Map<String, dynamic>> makSign(
Map<String, dynamic> params,
static Future<String> getWbiKeys() async {
final DateTime nowDate = DateTime.now();
if (DateTime.fromMillisecondsSinceEpoch(
_localCache.get(LocalCacheKey.timeStamp, defaultValue: 0) as int,
).day ==
nowDate.day) {
final String? mixinKey = _localCache.get(LocalCacheKey.mixinKey);
if (mixinKey != null) return mixinKey;
return _future ??= _getWbiKeys(nowDate);
} else {
return _future = _getWbiKeys(nowDate);
}
}
static Future<Map<String, Object>> makSign(
Map<String, Object> params,
) async {
// params 为需要加密的请求参数
final String mixinKey = await lock.synchronized(getWbiKeys);
final String mixinKey = await getWbiKeys();
encWbi(params, mixinKey);
return params;
}

View File

@@ -340,14 +340,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.8"
crclib:
dependency: "direct main"
description:
name: crclib
sha256: "800f2226cd90c900ddcaaccb79449eabe690627ee8c7046737458f1a2509043d"
url: "https://pub.dev"
source: hosted
version: "3.0.0"
cross_file:
dependency: transitive
description:
@@ -1762,14 +1754,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.2"
tuple:
dependency: transitive
description:
name: tuple
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
url: "https://pub.dev"
source: hosted
version: "2.0.2"
typed_data:
dependency: transitive
description:

View File

@@ -205,7 +205,6 @@ dependencies:
git:
url: https://github.com/bggRGjQaUbCoE/flutter_sortable_wrap.git
ref: master
crclib: ^3.0.0
web_socket_channel: ^3.0.3
# image: ^4.7.1
# window_manager: ^0.5.1