opt: webview to video

Closes #209

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-08 21:09:59 +08:00
parent 588a06bece
commit 9a3766e7b7
10 changed files with 54 additions and 72 deletions

View File

@@ -9,11 +9,11 @@ import 'package:PiliPlus/utils/utils.dart';
class SearchPanelController extends CommonController { class SearchPanelController extends CommonController {
SearchPanelController({ SearchPanelController({
this.keyword, required this.keyword,
required this.searchType, required this.searchType,
required this.tag, required this.tag,
}); });
String? keyword; String keyword;
SearchType searchType; SearchType searchType;
// 结果排序方式 搜索类型为视频、专栏及相簿时 // 结果排序方式 搜索类型为视频、专栏及相簿时
RxString order = ''.obs; RxString order = ''.obs;
@@ -99,7 +99,7 @@ class SearchPanelController extends CommonController {
@override @override
Future<LoadingState> customGetData() => SearchHttp.searchByType( Future<LoadingState> customGetData() => SearchHttp.searchByType(
searchType: searchType, searchType: searchType,
keyword: keyword!, keyword: keyword,
page: currentPage, page: currentPage,
order: order.value, order: order.value,
duration: searchType.name != 'video' ? null : duration.value, duration: searchType.name != 'video' ? null : duration.value,

View File

@@ -16,7 +16,7 @@ import 'widgets/media_bangumi_panel.dart';
import 'widgets/user_panel.dart'; import 'widgets/user_panel.dart';
class SearchPanel extends StatefulWidget { class SearchPanel extends StatefulWidget {
final String? keyword; final String keyword;
final SearchType searchType; final SearchType searchType;
final String tag; final String tag;
const SearchPanel({ const SearchPanel({
@@ -46,7 +46,7 @@ class _SearchPanelState extends State<SearchPanel>
searchType: widget.searchType, searchType: widget.searchType,
tag: widget.tag, tag: widget.tag,
), ),
tag: widget.searchType.name + widget.keyword!, tag: widget.searchType.name + widget.keyword,
); );
} }

View File

@@ -287,7 +287,7 @@ class ArticlePanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'article${searchPanelCtr.keyword!}'); tag: 'article${searchPanelCtr.keyword}');
ctr.order.value = item['order']; ctr.order.value = item['order'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();
@@ -321,7 +321,7 @@ class ArticlePanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'article${searchPanelCtr.keyword!}'); tag: 'article${searchPanelCtr.keyword}');
ctr.categoryId = item['categoryId']; ctr.categoryId = item['categoryId'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();

View File

@@ -214,7 +214,7 @@ class UserPanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'bili_user${searchPanelCtr.keyword!}'); tag: 'bili_user${searchPanelCtr.keyword}');
ctr.orderSort = item['orderSort']; ctr.orderSort = item['orderSort'];
ctr.order.value = item['order']; ctr.order.value = item['order'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
@@ -249,7 +249,7 @@ class UserPanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'bili_user${searchPanelCtr.keyword!}'); tag: 'bili_user${searchPanelCtr.keyword}');
ctr.userType = item['userType']; ctr.userType = item['userType'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();

View File

@@ -277,7 +277,7 @@ class VideoPanelController extends GetxController {
SmartDialog.dismiss(); SmartDialog.dismiss();
// SmartDialog.showToast("「${item['label']}」的筛选结果"); // SmartDialog.showToast("「${item['label']}」的筛选结果");
SearchPanelController ctr = Get.find<SearchPanelController>( SearchPanelController ctr = Get.find<SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword}');
ctr.pubBegin = DateTime( ctr.pubBegin = DateTime(
pubBegin.year, pubBegin.year,
pubBegin.month, pubBegin.month,
@@ -345,7 +345,7 @@ class VideoPanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword}');
DateTime now = DateTime.now(); DateTime now = DateTime.now();
if (item['value'] == 0) { if (item['value'] == 0) {
ctr.pubBegin = null; ctr.pubBegin = null;
@@ -424,7 +424,7 @@ class VideoPanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword}');
ctr.duration.value = item['value']; ctr.duration.value = item['value'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();
@@ -462,7 +462,7 @@ class VideoPanelController extends GetxController {
SmartDialog.showToast("${item['label']}」的筛选结果"); SmartDialog.showToast("${item['label']}」的筛选结果");
SearchPanelController ctr = SearchPanelController ctr =
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: 'video${searchPanelCtr.keyword!}'); tag: 'video${searchPanelCtr.keyword}');
ctr.tids = item['tids']; ctr.tids = item['tids'];
SmartDialog.showLoading(msg: 'loading'); SmartDialog.showLoading(msg: 'loading');
await ctr.onRefresh(); await ctr.onRefresh();

View File

@@ -2,16 +2,8 @@ import 'package:PiliPlus/models/common/search_type.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
class SearchResultController extends GetxController { class SearchResultController extends GetxController {
String? keyword; String keyword = Get.parameters['keyword'] ?? '';
RxList<int> count = RxList<int> count =
List.generate(SearchType.values.length, (_) => -1).toList().obs; List.generate(SearchType.values.length, (_) => -1).toList().obs;
@override
void onInit() {
super.onInit();
if (Get.parameters.keys.isNotEmpty) {
keyword = Get.parameters['keyword'];
}
}
} }

View File

@@ -60,7 +60,7 @@ class _SearchResultPageState extends State<SearchResultPage>
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
child: Text( child: Text(
'${_searchResultController.keyword}', _searchResultController.keyword,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
), ),
@@ -110,7 +110,7 @@ class _SearchResultPageState extends State<SearchResultPage>
if (_tabController.indexIsChanging.not) { if (_tabController.indexIsChanging.not) {
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: SearchType.values[index].name + tag: SearchType.values[index].name +
_searchResultController.keyword!) _searchResultController.keyword)
.animateToTop(); .animateToTop();
} }
}, },

View File

@@ -198,35 +198,38 @@ class _WebviewPageNewState extends State<WebviewPageNew> {
shouldOverrideUrlLoading: (controller, navigationAction) async { shouldOverrideUrlLoading: (controller, navigationAction) async {
final String? str = final String? str =
navigationAction.request.url!.pathSegments.getOrNull(0); navigationAction.request.url!.pathSegments.getOrNull(0);
final Map matchRes = IdUtils.matchAvorBv(input: str); if (str != null) {
final List matchKeys = matchRes.keys.toList(); final Map matchRes = IdUtils.matchAvorBv(input: str);
if (matchKeys.isNotEmpty) { if (matchRes.isNotEmpty) {
if (matchKeys.first == 'BV') { Get.back();
Get.offAndToNamed( PiliScheme.videoPush(matchRes['AV'], matchRes['BV']);
'/searchResult',
parameters: {'keyword': matchRes['BV']},
);
return NavigationActionPolicy.CANCEL; return NavigationActionPolicy.CANCEL;
} }
} }
var url = navigationAction.request.url!.toString(); var url = navigationAction.request.url!.toString();
if (url.startsWith('http')) { if (RegExp(
if (RegExp(r'https://www.bilibili.com/video/BV[a-zA-Z\d]+') r'^(https?://)?((www|m).)?(bilibili|b23).(com|tv)/video/BV[a-zA-Z\d]+')
.hasMatch(url)) { .hasMatch(url)) {
PiliScheme.routePush(Uri.parse(url)); try {
return NavigationActionPolicy.CANCEL; String? bvid =
} else if (url.startsWith('http://m.bilibili.com/playlist/')) { RegExp(r'BV[a-zA-Z\d]+').firstMatch(url)?.group(0);
try { if (bvid != null) {
String? bvid = Get.back();
RegExp(r'bvid=(BV[a-zA-Z\d]+)').firstMatch(url)?.group(1); PiliScheme.videoPush(null, bvid);
if (bvid != null) { return NavigationActionPolicy.CANCEL;
PiliScheme.videoPush(null, bvid); }
return NavigationActionPolicy.CANCEL; } catch (_) {}
} } else if (url.startsWith('http://m.bilibili.com/playlist/')) {
} catch (_) {} try {
} String? bvid =
RegExp(r'bvid=(BV[a-zA-Z\d]+)').firstMatch(url)?.group(1);
if (bvid != null) {
PiliScheme.videoPush(null, bvid);
return NavigationActionPolicy.CANCEL;
}
} catch (_) {}
} else { } else {
if (url.startsWith('bilibili://video/')) { if (url.startsWith('bilibili://video/')) {
String? str = Uri.parse(url).pathSegments.getOrNull(0); String? str = Uri.parse(url).pathSegments.getOrNull(0);

View File

@@ -225,18 +225,12 @@ class PiliScheme {
} }
// 投稿跳转 // 投稿跳转
static Future<void> videoPush(int? aidVal, String? bvidVal) async { static Future<void> videoPush(int? aid, String? bvid) async {
try { try {
int? aid = aidVal; aid ??= IdUtils.bv2av(bvid!);
String? bvid = bvidVal; bvid ??= IdUtils.av2bv(aid);
if (aidVal == null) {
aid = IdUtils.bv2av(bvidVal!);
}
if (bvidVal == null) {
bvid = IdUtils.av2bv(aidVal!);
}
SmartDialog.showLoading<dynamic>(msg: '获取中...'); SmartDialog.showLoading<dynamic>(msg: '获取中...');
final int cid = await SearchHttp.ab2c(bvid: bvidVal, aid: aidVal); final int cid = await SearchHttp.ab2c(bvid: bvid, aid: aid);
SmartDialog.dismiss(); SmartDialog.dismiss();
Utils.toDupNamed( Utils.toDupNamed(
'/video?bvid=$bvid&cid=$cid', '/video?bvid=$bvid&cid=$cid',

View File

@@ -68,23 +68,16 @@ class IdUtils {
if (input == null || input.isEmpty) { if (input == null || input.isEmpty) {
return result; return result;
} }
final RegExp bvRegex = final RegExp bvRegex = RegExp(r'bv([0-9A-Za-z]+)', caseSensitive: false);
RegExp(r'[bB][vV][0-9A-Za-z]{10}', caseSensitive: false); String? bvid = bvRegex.firstMatch(input)?.group(1);
final RegExp avRegex = RegExp(r'[aA][vV]\d+', caseSensitive: false);
final Iterable<Match> bvMatches = bvRegex.allMatches(input); late final RegExp avRegex = RegExp(r'av(\d+)', caseSensitive: false);
final Iterable<Match> avMatches = avRegex.allMatches(input); late String? aid = avRegex.firstMatch(input)?.group(1);
final List<String> bvs = if (bvid != null) {
bvMatches.map((Match match) => match.group(0)!).toList(); result['BV'] = 'BV$bvid';
final List<String> avs = } else if (aid != null) {
avMatches.map((Match match) => match.group(0)!).toList(); result['AV'] = int.parse(aid);
if (bvs.isNotEmpty) {
result['BV'] = bvs[0].substring(0, 2).toUpperCase() + bvs[0].substring(2);
}
if (avs.isNotEmpty) {
result['AV'] = int.parse(avs[0].substring(2));
} }
return result; return result;
} }