Merge remote-tracking branch 'upstream/main'

This commit is contained in:
orz12
2024-02-24 10:46:18 +08:00
13 changed files with 187 additions and 50 deletions

View File

@@ -499,4 +499,10 @@ class Api {
/// 获取未读动态数 /// 获取未读动态数
static const getUnreadDynamic = '/x/web-interface/dynamic/entrance'; static const getUnreadDynamic = '/x/web-interface/dynamic/entrance';
/// 用户动态主页
static const dynamicSpmPrefix = 'https://space.bilibili.com/1/dynamic';
/// 激活buvid3
static const activateBuvidApi = '/x/internal/gaia-gateway/ExClimbWuzhi';
} }

View File

@@ -1,7 +1,9 @@
// ignore_for_file: avoid_print // ignore_for_file: avoid_print
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'dart:math' show Random;
import 'package:cookie_jar/cookie_jar.dart'; import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:dio/io.dart'; import 'package:dio/io.dart';
@@ -11,6 +13,7 @@ import 'package:hive/hive.dart';
import 'package:PiliPalaX/utils/id_utils.dart'; import 'package:PiliPalaX/utils/id_utils.dart';
import '../utils/storage.dart'; import '../utils/storage.dart';
import '../utils/utils.dart'; import '../utils/utils.dart';
import 'api.dart';
import 'constants.dart'; import 'constants.dart';
import 'interceptor.dart'; import 'interceptor.dart';
import 'interceptor_anonymity.dart'; import 'interceptor_anonymity.dart';
@@ -25,6 +28,7 @@ class Request {
late bool enableSystemProxy; late bool enableSystemProxy;
late String systemProxyHost; late String systemProxyHost;
late String systemProxyPort; late String systemProxyPort;
static final RegExp spmPrefixExp = RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
/// 设置cookie /// 设置cookie
static setCookie() async { static setCookie() async {
@@ -53,13 +57,12 @@ class Request {
} }
setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null); setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null);
if (cookie.isEmpty) { try {
try { await buvidActivate();
await Request().get(HttpString.baseUrl); } catch (e) {
} catch (e) { log("setCookie, ${e.toString()}");
log("setCookie, ${e.toString()}");
}
} }
final String cookieString = cookie final String cookieString = cookie
.map((Cookie cookie) => '${cookie.name}=${cookie.value}') .map((Cookie cookie) => '${cookie.name}=${cookie.value}')
.join('; '); .join('; ');
@@ -89,6 +92,33 @@ class Request {
dio.options.headers['referer'] = 'https://www.bilibili.com/'; dio.options.headers['referer'] = 'https://www.bilibili.com/';
} }
static Future buvidActivate() async {
var html = await Request().get(Api.dynamicSpmPrefix);
String spmPrefix = spmPrefixExp.firstMatch(html.data)!.group(1)!;
Random rand = Random();
String rand_png_end = base64.encode(
List<int>.generate(32, (_) => rand.nextInt(256)) +
List<int>.filled(4, 0) +
[73, 69, 78, 68] +
List<int>.generate(4, (_) => rand.nextInt(256))
);
String jsonData = json.encode({
'3064': 1,
'39c8': '${spmPrefix}.fp.risk',
'3c43': {
'adca': 'Linux',
'bfe9': rand_png_end.substring(rand_png_end.length - 50),
},
});
await Request().post(
Api.activateBuvidApi,
data: {'payload': jsonData},
options: Options(contentType: 'application/json')
);
}
/* /*
* config it and create * config it and create
*/ */

View File

@@ -94,6 +94,7 @@ class MemberHttp {
'dm_img_list': '[]', 'dm_img_list': '[]',
'dm_img_str': dmImgStr.substring(0, dmImgStr.length - 2), 'dm_img_str': dmImgStr.substring(0, dmImgStr.length - 2),
'dm_cover_img_str': dmCoverImgStr.substring(0, dmCoverImgStr.length - 2), 'dm_cover_img_str': dmCoverImgStr.substring(0, dmCoverImgStr.length - 2),
'dm_img_inter': '{"ds":[],"wh":[0,0,0],"of":[0,0,0]}',
}); });
var res = await Request().get( var res = await Request().get(
Api.memberArchive, Api.memberArchive,

View File

@@ -9,6 +9,7 @@ class ReplyContent {
this.vote, this.vote,
this.richText, this.richText,
this.isText, this.isText,
this.topicsMeta,
}); });
String? message; String? message;
@@ -20,6 +21,7 @@ class ReplyContent {
Map? vote; Map? vote;
Map? richText; Map? richText;
bool? isText; bool? isText;
Map? topicsMeta;
ReplyContent.fromJson(Map<String, dynamic> json) { ReplyContent.fromJson(Map<String, dynamic> json) {
message = json['message'] message = json['message']
@@ -39,6 +41,7 @@ class ReplyContent {
richText = json['rich_text'] ?? {}; richText = json['rich_text'] ?? {};
// 不包含@ 笔记 图片的时候,文字可折叠 // 不包含@ 笔记 图片的时候,文字可折叠
isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty; isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty;
topicsMeta = json['topics_meta'] ?? {};
} }
} }

View File

@@ -236,11 +236,26 @@ class AboutController extends GetxController {
); );
} }
githubRelease() {
launchUrl(
Uri.parse('https://github.com/guozhigq/pilipala/release'),
mode: LaunchMode.externalApplication,
);
}
// 从网盘下载 // 从网盘下载
panDownload() { panDownload() {
launchUrl( Clipboard.setData(
Uri.parse('https://www.123pan.com/s/9sVqVv-flu0A.html'), const ClipboardData(text: 'pili'),
mode: LaunchMode.externalApplication, );
SmartDialog.showToast(
'已复制提取码pili',
displayTime: const Duration(milliseconds: 500),
).then(
(value) => launchUrl(
Uri.parse('https://www.123pan.com/s/9sVqVv-flu0A.html'),
mode: LaunchMode.externalApplication,
),
); );
} }
// 问题反馈 // 问题反馈

View File

@@ -26,6 +26,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
late List defaultTabs; late List defaultTabs;
late List<String> tabbarSort; late List<String> tabbarSort;
RxString defaultSearch = ''.obs; RxString defaultSearch = ''.obs;
late bool enableGradientBg;
@override @override
void onInit() { void onInit() {
@@ -40,6 +41,8 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) { if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) {
searchDefault(); searchDefault();
} }
enableGradientBg =
setting.get(SettingBoxKey.enableGradientBg, defaultValue: true);
} }
void onRefresh() { void onRefresh() {

View File

@@ -48,38 +48,48 @@ class _HomePageState extends State<HomePage>
super.build(context); super.build(context);
Brightness currentBrightness = MediaQuery.of(context).platformBrightness; Brightness currentBrightness = MediaQuery.of(context).platformBrightness;
// 设置状态栏图标的亮度 // 设置状态栏图标的亮度
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( if (_homeController.enableGradientBg) {
statusBarIconBrightness: currentBrightness == Brightness.light SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
? Brightness.dark statusBarIconBrightness: currentBrightness == Brightness.light
: Brightness.light, ? Brightness.dark
)); : Brightness.light,
));
}
return Scaffold( return Scaffold(
extendBody: true, extendBody: true,
extendBodyBehindAppBar: true, extendBodyBehindAppBar: true,
body: Stack( body: Stack(
children: [ children: [
// gradient background // gradient background
Align( if (_homeController.enableGradientBg) ...[
alignment: Alignment.topLeft, Align(
child: Opacity( alignment: Alignment.topLeft,
opacity: 0.6, child: Opacity(
child: Container( opacity: 0.6,
width: MediaQuery.of(context).size.width, child: Container(
height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width,
decoration: BoxDecoration( height: MediaQuery.of(context).size.height,
gradient: LinearGradient( decoration: BoxDecoration(
colors: [ gradient: LinearGradient(
Theme.of(context).colorScheme.primary.withOpacity(0.9), colors: [
Theme.of(context).colorScheme.primary.withOpacity(0.5), Theme.of(context)
Theme.of(context).colorScheme.surface .colorScheme
], .primary
begin: Alignment.topLeft, .withOpacity(0.9),
end: Alignment.bottomRight, Theme.of(context)
stops: const [0, 0.0034, 0.34]), .colorScheme
.primary
.withOpacity(0.5),
Theme.of(context).colorScheme.surface
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: const [0, 0.0034, 0.34]),
),
), ),
), ),
), ),
), ],
Column( Column(
children: [ children: [
CustomAppBar( CustomAppBar(
@@ -90,7 +100,37 @@ class _HomePageState extends State<HomePage>
callback: showUserBottomSheet, callback: showUserBottomSheet,
), ),
if (_homeController.tabs.length > 1) ...[ if (_homeController.tabs.length > 1) ...[
const CustomTabs(), if (_homeController.enableGradientBg) ...[
const CustomTabs(),
] else ...[
const SizedBox(height: 4),
SizedBox(
width: double.infinity,
height: 42,
child: Align(
alignment: Alignment.center,
child: TabBar(
controller: _homeController.tabController,
tabs: [
for (var i in _homeController.tabs)
Tab(text: i['label'])
],
isScrollable: true,
dividerColor: Colors.transparent,
enableFeedback: true,
splashBorderRadius: BorderRadius.circular(10),
tabAlignment: TabAlignment.center,
onTap: (value) {
feedBack();
if (_homeController.initialIndex.value == value) {
_homeController.tabsCtrList[value]().animateToTop();
}
_homeController.initialIndex.value = value;
},
),
),
),
],
] else ...[ ] else ...[
const SizedBox(height: 6), const SizedBox(height: 6),
], ],

View File

@@ -4,6 +4,8 @@ import 'package:PiliPalaX/http/live.dart';
import 'package:PiliPalaX/models/live/room_info.dart'; import 'package:PiliPalaX/models/live/room_info.dart';
import 'package:PiliPalaX/plugin/pl_player/index.dart'; import 'package:PiliPalaX/plugin/pl_player/index.dart';
import '../../models/live/room_info_h5.dart'; import '../../models/live/room_info_h5.dart';
import '../../utils/storage.dart';
import '../../utils/video_utils.dart';
class LiveRoomController extends GetxController { class LiveRoomController extends GetxController {
String cover = ''; String cover = '';
@@ -16,6 +18,7 @@ class LiveRoomController extends GetxController {
PlPlayerController plPlayerController = PlPlayerController plPlayerController =
PlPlayerController.getInstance(videoType: 'live'); PlPlayerController.getInstance(videoType: 'live');
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs; Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
late bool enableCDN;
@override @override
void onInit() { void onInit() {
@@ -31,6 +34,8 @@ class LiveRoomController extends GetxController {
cover = liveItem.cover; cover = liveItem.cover;
} }
} }
// CDN优化
enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
} }
playerInit(source) async { playerInit(source) async {
@@ -57,9 +62,11 @@ class LiveRoomController extends GetxController {
List<CodecItem> codec = List<CodecItem> codec =
res['data'].playurlInfo.playurl.stream.first.format.first.codec; res['data'].playurlInfo.playurl.stream.first.format.first.codec;
CodecItem item = codec.first; CodecItem item = codec.first;
String videoUrl = (item.urlInfo?.first.host)! + String videoUrl = enableCDN
item.baseUrl! + ? VideoUtils.getCdnUrl(item)
item.urlInfo!.first.extra!; : (item.urlInfo?.first.host)! +
item.baseUrl! +
item.urlInfo!.first.extra!;
await playerInit(videoUrl); await playerInit(videoUrl);
return res; return res;
} }

View File

@@ -102,6 +102,12 @@ class _StyleSettingState extends State<StyleSetting> {
defaultVal: true, defaultVal: true,
needReboot: true, needReboot: true,
), ),
const SetSwitchItem(
title: '首页底栏背景渐变',
setKey: SettingBoxKey.enableGradientBg,
defaultVal: true,
needReboot: true,
),
ListTile( ListTile(
onTap: () async { onTap: () async {
double? result = await showDialog( double? result = await showDialog(

View File

@@ -507,6 +507,7 @@ InlineSpan buildContent(
// 构建正则表达式 // 构建正则表达式
final List<String> specialTokens = [ final List<String> specialTokens = [
...content.emote.keys, ...content.emote.keys,
...content.topicsMeta?.keys?.map((e) => '#$e#') ?? [],
...content.atNameToMid.keys.map((e) => '@$e'), ...content.atNameToMid.keys.map((e) => '@$e'),
...content.jumpUrl.keys.map((e) => ...content.jumpUrl.keys.map((e) =>
e.replaceAll('?', '\\?').replaceAll('+', '\\+').replaceAll('*', '\\*')), e.replaceAll('?', '\\?').replaceAll('+', '\\+').replaceAll('*', '\\*')),
@@ -590,7 +591,7 @@ InlineSpan buildContent(
), ),
); );
} else { } else {
// print("matchStr=$matchStr"); print("matchStr=$matchStr");
String appUrlSchema = ''; String appUrlSchema = '';
final bool enableWordRe = setting.get(SettingBoxKey.enableWordRe, final bool enableWordRe = setting.get(SettingBoxKey.enableWordRe,
defaultValue: false) as bool; defaultValue: false) as bool;
@@ -693,6 +694,23 @@ InlineSpan buildContent(
); );
// 只显示一次 // 只显示一次
matchedStrs.add(matchStr); matchedStrs.add(matchStr);
} else if (content
.topicsMeta[matchStr.substring(1, matchStr.length - 1)] !=
null) {
spanChilds.add(
TextSpan(
text: matchStr,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
final String topic =
matchStr.substring(1, matchStr.length - 1);
Get.toNamed('/searchResult', parameters: {'keyword': topic});
},
),
);
} else { } else {
addPlainTextSpan(matchStr); addPlainTextSpan(matchStr);
} }

View File

@@ -141,6 +141,7 @@ class SettingBoxKey {
tabbarSort = 'tabbarSort', // 首页tabbar tabbarSort = 'tabbarSort', // 首页tabbar
dynamicBadgeMode = 'dynamicBadgeMode', dynamicBadgeMode = 'dynamicBadgeMode',
hiddenSettingUnlocked = 'hiddenSettingUnlocked'; hiddenSettingUnlocked = 'hiddenSettingUnlocked';
enableGradientBg = 'enableGradientBg';
} }
class LocalCacheKey { class LocalCacheKey {

View File

@@ -17,6 +17,8 @@ import '../http/index.dart';
import '../models/github/latest.dart'; import '../models/github/latest.dart';
class Utils { class Utils {
static final Random random = Random();
static Future<String> getCookiePath() async { static Future<String> getCookiePath() async {
final Directory tempDir = await getApplicationSupportDirectory(); final Directory tempDir = await getApplicationSupportDirectory();
final String tempPath = "${tempDir.path}/.plpl/"; final String tempPath = "${tempDir.path}/.plpl/";
@@ -181,7 +183,7 @@ class Utils {
} }
static String makeHeroTag(v) { static String makeHeroTag(v) {
return v.toString() + Random().nextInt(9999).toString(); return v.toString() + random.nextInt(9999).toString();
} }
static int duration(String duration) { static int duration(String duration) {
@@ -340,18 +342,14 @@ class Utils {
return md5String; return md5String;
} }
static String generateRandomString(int minLength, int maxLength) { static List<int> generateRandomBytes(int minLength, int maxLength) {
const String printable = return List<int>.generate(
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#\$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ '; random.nextInt(maxLength-minLength+1), (_) => random.nextInt(0x60) + 0x20
);
var random = Random();
int length = minLength + random.nextInt(maxLength - minLength + 1);
return List<String>.generate(
length, (index) => printable[random.nextInt(printable.length)]).join();
} }
static String base64EncodeRandomString(int minLength, int maxLength) { static String base64EncodeRandomString(int minLength, int maxLength) {
String randomString = generateRandomString(minLength, maxLength); List<int> randomBytes = generateRandomBytes(minLength, maxLength);
return base64.encode(utf8.encode(randomString)); return base64.encode(randomBytes);
} }
} }

View File

@@ -1,5 +1,7 @@
import 'package:PiliPalaX/models/video/play/url.dart'; import 'package:PiliPalaX/models/video/play/url.dart';
import '../models/live/room_info.dart';
class VideoUtils { class VideoUtils {
static String getCdnUrl(dynamic item) { static String getCdnUrl(dynamic item) {
var backupUrl = ""; var backupUrl = "";
@@ -12,13 +14,20 @@ class VideoUtils {
} else if (item is AudioItem) { } else if (item is AudioItem) {
backupUrl = item.backupUrl ?? ""; backupUrl = item.backupUrl ?? "";
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? ""); videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else if (item is CodecItem) {
backupUrl = (item.urlInfo?.first.host)! +
item.baseUrl! +
item.urlInfo!.first.extra!;
videoUrl = backupUrl.contains("http") ? backupUrl : (item.baseUrl ?? "");
} else { } else {
return ""; return "";
} }
/// issues #70 /// issues #70
if (videoUrl.contains(".mcdn.bilivideo") || if (videoUrl.contains(".mcdn.bilivideo")) {
videoUrl.contains("/upgcxcode/")) { videoUrl =
'https://proxy-tf-all-ws.bilivideo.com/?url=${Uri.encodeComponent(videoUrl)}';
} else if (videoUrl.contains("/upgcxcode/")) {
//CDN列表 //CDN列表
var cdnList = { var cdnList = {
'ali': 'upos-sz-mirrorali.bilivideo.com', 'ali': 'upos-sz-mirrorali.bilivideo.com',