feat: music search (#1270)

* tweak

* feat: music search
This commit is contained in:
My-Responsitories
2025-09-17 00:33:33 +08:00
committed by GitHub
parent 3897efd82f
commit 349a4dfc0b
3 changed files with 113 additions and 69 deletions

View File

@@ -1,17 +1,19 @@
package com.example.piliplus
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import com.ryanheise.audioservice.AudioServiceActivity
import android.app.SearchManager
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.provider.Settings
import android.view.WindowManager.LayoutParams
import androidx.core.net.toUri
import com.ryanheise.audioservice.AudioServiceActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import kotlin.system.exitProcess
class MainActivity : AudioServiceActivity() {
@@ -22,59 +24,85 @@ class MainActivity : AudioServiceActivity() {
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "PiliPlus")
methodChannel.setMethodCallHandler { call, result ->
if (call.method == "back") {
back()
} else if (call.method == "biliSendCommAntifraud") {
try {
val action = call.argument<Int>("action") ?: 0
val oid = call.argument<Number>("oid") ?: 0L
val type = call.argument<Int>("type") ?: 0
val rpid = call.argument<Number>("rpid") ?: 0L
val root = call.argument<Number>("root") ?: 0L
val parent = call.argument<Number>("parent") ?: 0L
val ctime = call.argument<Number>("ctime") ?: 0L
val commentText = call.argument<String>("comment_text") ?: ""
val pictures = call.argument<String?>("pictures")
val sourceId = call.argument<String>("source_id") ?: ""
val uid = call.argument<Number>("uid") ?: 0L
val cookies = call.argument<List<String>>("cookies") ?: emptyList<String>()
val intent = Intent().apply {
component = ComponentName("icu.freedomIntrovert.biliSendCommAntifraud", "icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity")
putExtra("action", action)
putExtra("oid", oid.toLong())
putExtra("type", type)
putExtra("rpid", rpid.toLong())
putExtra("root", root.toLong())
putExtra("parent", parent.toLong())
putExtra("ctime", ctime.toLong())
putExtra("comment_text", commentText)
if(pictures != null)
putExtra("pictures", pictures)
putExtra("source_id", sourceId)
putExtra("uid", uid.toLong())
putStringArrayListExtra("cookies", ArrayList(cookies))
}
startActivity(intent)
} catch (e: Exception) {}
} else if (call.method == "linkVerifySettings") {
try {
val intent = Intent(android.provider.Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS,
Uri.parse("package:" + context.packageName))
context.startActivity(intent)
} catch (t: Throwable) {
when (call.method) {
"back" -> back();
"biliSendCommAntifraud" -> {
try {
val intent = Intent("android.intent.action.MAIN", Uri.parse("package:" + context.packageName))
intent.setClassName("com.android.settings", "com.android.settings.applications.InstalledAppOpenByDefaultActivity")
val action = call.argument<Int>("action") ?: 0
val oid = call.argument<Number>("oid") ?: 0L
val type = call.argument<Int>("type") ?: 0
val rpid = call.argument<Number>("rpid") ?: 0L
val root = call.argument<Number>("root") ?: 0L
val parent = call.argument<Number>("parent") ?: 0L
val ctime = call.argument<Number>("ctime") ?: 0L
val commentText = call.argument<String>("comment_text") ?: ""
val pictures = call.argument<String?>("pictures")
val sourceId = call.argument<String>("source_id") ?: ""
val uid = call.argument<Number>("uid") ?: 0L
val cookies = call.argument<List<String>>("cookies") ?: emptyList<String>()
val intent = Intent().apply {
component = ComponentName("icu.freedomIntrovert.biliSendCommAntifraud", "icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity")
putExtra("action", action)
putExtra("oid", oid.toLong())
putExtra("type", type)
putExtra("rpid", rpid.toLong())
putExtra("root", root.toLong())
putExtra("parent", parent.toLong())
putExtra("ctime", ctime.toLong())
putExtra("comment_text", commentText)
if(pictures != null)
putExtra("pictures", pictures)
putExtra("source_id", sourceId)
putExtra("uid", uid.toLong())
putStringArrayListExtra("cookies", ArrayList(cookies))
}
startActivity(intent)
} catch (_: Exception) {}
}
"linkVerifySettings" -> {
val uri = ("package:" + context.packageName).toUri()
try {
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri)
} else {
Intent("android.intent.action.MAIN", uri).setClassName("com.android.settings",
"com.android.settings.applications.InstalledAppOpenByDefaultActivity")
}
context.startActivity(intent)
} catch (t2: Throwable) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + context.packageName))
} catch (_: Throwable) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri)
context.startActivity(intent)
}
}
} else {
result.notImplemented()
"music" -> {
val title = call.argument<String>("title")
val intent = Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH).apply {
putExtra(SearchManager.QUERY, title)
putExtra(MediaStore.EXTRA_MEDIA_TITLE, title)
call.argument<String?>("artist")?.let { putExtra(MediaStore.EXTRA_MEDIA_ARTIST, it) }
call.argument<String?>("album")?.let { putExtra(MediaStore.EXTRA_MEDIA_ALBUM, it) }
addCategory(Intent.CATEGORY_DEFAULT)
}
try {
if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {}
try {
intent.action = MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
if (packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {}
result.success(false)
}
else -> result.notImplemented()
}
}
}
@@ -109,7 +137,7 @@ class MainActivity : AudioServiceActivity() {
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration?) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
MethodChannel(
flutterEngine!!.getDartExecutor()!!.getBinaryMessenger(),
flutterEngine!!.dartExecutor.binaryMessenger,
"floating"
).invokeMethod("onPipChanged", isInPictureInPictureMode)
}

View File

@@ -1,3 +1,4 @@
import 'dart:io';
import 'dart:math';
import 'package:PiliPlus/common/widgets/badge.dart';
@@ -448,10 +449,8 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
GestureDetector(
// TODO: android intent ACTION_MEDIA_SEARCH
onTap: () => Utils.copyText(
item.musicTitle!,
),
onTap: () => _searchMusic(item),
onLongPress: () => Utils.copyText(item.musicTitle!),
behavior: HitTestBehavior.opaque,
child: MarqueeText(
item.musicTitle!,
@@ -493,13 +492,18 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
cid: item.mvCid!,
aid: item.mvAid,
),
child: ColoredBox(
color: theme.colorScheme.secondaryContainer
.withValues(alpha: 0.5),
child: DecoratedBox(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(4),
),
color: theme.colorScheme.secondaryContainer
.withValues(alpha: 0.5),
),
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 3,
vertical: 3,
horizontal: 4,
),
child: Row(
mainAxisSize: MainAxisSize.min,
@@ -676,4 +680,18 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
),
);
}
Future<void> _searchMusic(MusicDetail item) async {
final res =
Platform.isAndroid &&
(await Utils.channel.invokeMethod<bool>('music', {
'title': item.musicTitle,
'artist': item.originArtist ?? item.originArtistList,
'album': item.album,
}) ??
false);
if (!res) {
Utils.copyText(item.musicTitle!);
}
}
}

View File

@@ -1,6 +1,5 @@
import 'dart:async' show FutureOr;
import 'dart:io' show Platform;
import 'dart:math';
import 'package:PiliPlus/grpc/grpc_req.dart';
import 'package:PiliPlus/http/loading_state.dart';
@@ -21,13 +20,12 @@ import 'package:PiliPlus/utils/accounts/account.dart';
import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
abstract class LoginUtils {
static final random = Random();
static FutureOr setWebCookie([Account? account]) {
if (Platform.isWindows) {
return null;
@@ -163,7 +161,7 @@ abstract class LoginUtils {
static String generateBuvid() {
var md5Str = Iterable.generate(
32,
(_) => random.nextInt(16).toRadixString(16),
(_) => Utils.random.nextInt(16).toRadixString(16),
).join().toUpperCase();
return 'XY${md5Str[2]}${md5Str[12]}${md5Str[22]}$md5Str';
}
@@ -188,11 +186,11 @@ abstract class LoginUtils {
final String randomHex32 = List.generate(
32,
(index) => random.nextInt(16).toRadixString(16),
(index) => Utils.random.nextInt(16).toRadixString(16),
).join();
final String randomHex16 = List.generate(
16,
(index) => random.nextInt(16).toRadixString(16),
(index) => Utils.random.nextInt(16).toRadixString(16),
).join();
final String deviceID = randomHex32 + yyyyMMddHHmmss + randomHex16;