From c3bbec22db45253b699b6affc0c7990903688e1b Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Wed, 21 Feb 2024 12:17:42 -0800
Subject: [PATCH 01/11] feat: doc picker
---
android/app/src/main/AndroidManifest.xml | 11 +++++---
.../com/noxplay/noxplayer/MainApplication.kt | 26 +++++++++++++++++++
package.json | 1 +
.../playlist/BiliSearch/SearchMenu.tsx | 13 ++++++++++
yarn.lock | 5 ++++
5 files changed, 53 insertions(+), 3 deletions(-)
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index fd162103..4508a3c4 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,11 @@
+
+
+
-
+
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt b/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
index 613e790b..e5775728 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
@@ -2,6 +2,9 @@ package com.noxplay.noxplayer
import android.app.Application
import android.content.res.Configuration
+import android.net.Uri
+import android.provider.MediaStore
+import android.util.Log
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
@@ -53,6 +56,29 @@ class MainApplication : Application(), ReactApplication {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
+ val uri = Uri.parse("content://com.android.externalstorage.documents/document/primary%3AMusic")
+ Log.d("RNTP", MediaStore.Audio.Media.getContentUri(
+ MediaStore.VOLUME_EXTERNAL
+ ).toString())
+ Log.d("RNTP", MediaStore.Audio.Media.getContentUri(
+ MediaStore.VOLUME_INTERNAL
+ ).toString())
+ val query = this.contentResolver.query(
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ arrayOf(
+ MediaStore.Audio.Media._ID,
+ MediaStore.Audio.Media.RELATIVE_PATH,
+ MediaStore.Audio.Media.DISPLAY_NAME
+ ), null,null, null)
+ query?.use { cursor ->
+ Log.d("RNTP", cursor.count.toString())
+ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
+ val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
+ val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
+ while (cursor.moveToNext()) {
+ Log.d("RNTP", cursor.getString(idColumn) + cursor.getString(pathColumn) + cursor.getString(nameColumn))
+ }
+ }
onApplicationCreate(this)
}
diff --git a/package.json b/package.json
index 0a7c9d16..33c1084b 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"dropbox": "git+https://lovegaoshi@github.com/lovegaoshi/dropbox-sdk-js.git",
"expo": "^50.0.7",
"expo-clipboard": "~5.0.1",
+ "expo-document-picker": "~11.10.1",
"expo-image": "^1.10.6",
"expo-keep-awake": "^12.8.2",
"expo-secure-store": "~12.8.1",
diff --git a/src/components/playlist/BiliSearch/SearchMenu.tsx b/src/components/playlist/BiliSearch/SearchMenu.tsx
index f2aada7d..3ef11cce 100644
--- a/src/components/playlist/BiliSearch/SearchMenu.tsx
+++ b/src/components/playlist/BiliSearch/SearchMenu.tsx
@@ -1,5 +1,6 @@
import * as React from 'react';
import { Menu } from 'react-native-paper';
+import * as DocumentPicker from 'expo-document-picker';
import { SEARCH_OPTIONS } from '@enums/Storage';
import { MUSICFREE } from '@utils/mediafetch/musicfree';
@@ -44,6 +45,18 @@ export default ({
title={`MusicFree.${MUSICFREE.aggregated}`}
/>
)}
+ {
+ console.log(
+ await DocumentPicker.getDocumentAsync({
+ copyToCacheDirectory: false,
+ type: 'audio/*',
+ })
+ );
+ }}
+ title={'Local'}
+ />
);
};
diff --git a/yarn.lock b/yarn.lock
index 23d39e76..4509b6fa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7002,6 +7002,11 @@ expo-constants@~15.4.0:
dependencies:
"@expo/config" "~8.5.0"
+expo-document-picker@~11.10.1:
+ version "11.10.1"
+ resolved "https://registry.yarnpkg.com/expo-document-picker/-/expo-document-picker-11.10.1.tgz#03394d77842a2fd7cb0a784a60098ee1ddd1012e"
+ integrity sha512-A1MiLfyXQ+KxanRO5lYxYQy3ryV+25JHe5Ai/BLV+FJU0QXByUF+Y/dn35WVPx5gpdZXC8UJ4ejg5SKSoeconw==
+
expo-file-system@~16.0.0:
version "16.0.4"
resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-16.0.4.tgz#f76b05e2224e705a30a75d50d650ee1dbb4dbaf7"
From a4e71a08423b91d0f1a680dc0759b9d0b97b5f66 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Thu, 22 Feb 2024 10:36:36 -0800
Subject: [PATCH 02/11] feat: local playback
---
.../com/noxplay/noxplayer/MainApplication.kt | 26 ---------
.../noxplay/noxplayer/NoxAndroidAutoModule.kt | 58 +++++++++++++++++--
src/components/playlist/BiliSearch/Icons.tsx | 7 ++-
.../playlist/BiliSearch/SearchMenu.tsx | 9 ++-
src/utils/Utils.ts | 22 +++++++
5 files changed, 88 insertions(+), 34 deletions(-)
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt b/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
index e5775728..613e790b 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/MainApplication.kt
@@ -2,9 +2,6 @@ package com.noxplay.noxplayer
import android.app.Application
import android.content.res.Configuration
-import android.net.Uri
-import android.provider.MediaStore
-import android.util.Log
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactNativeHost
@@ -56,29 +53,6 @@ class MainApplication : Application(), ReactApplication {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
- val uri = Uri.parse("content://com.android.externalstorage.documents/document/primary%3AMusic")
- Log.d("RNTP", MediaStore.Audio.Media.getContentUri(
- MediaStore.VOLUME_EXTERNAL
- ).toString())
- Log.d("RNTP", MediaStore.Audio.Media.getContentUri(
- MediaStore.VOLUME_INTERNAL
- ).toString())
- val query = this.contentResolver.query(
- MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- arrayOf(
- MediaStore.Audio.Media._ID,
- MediaStore.Audio.Media.RELATIVE_PATH,
- MediaStore.Audio.Media.DISPLAY_NAME
- ), null,null, null)
- query?.use { cursor ->
- Log.d("RNTP", cursor.count.toString())
- val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
- val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
- val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
- while (cursor.moveToNext()) {
- Log.d("RNTP", cursor.getString(idColumn) + cursor.getString(pathColumn) + cursor.getString(nameColumn))
- }
- }
onApplicationCreate(this)
}
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
index 010ee960..fc0d02dd 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
@@ -2,28 +2,71 @@ package com.noxplay.noxplayer
import android.app.ActivityManager
import android.app.ApplicationExitInfo
+import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
+import android.provider.MediaStore
import android.provider.Settings
+import android.util.Log
import android.view.WindowManager
-import androidx.annotation.RequiresApi
+import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.Promise
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
+import com.facebook.react.bridge.WritableArray
+import com.facebook.react.bridge.WritableNativeArray
-class NoxAndroidAutoModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) {
+class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
+ ReactContextBaseJavaModule(reactContext) {
override fun getName() = "NoxAndroidAutoModule"
+ @ReactMethod fun listMediaDir(relativeDir: String, subdir: Boolean, callback: Promise) {
+ val results: WritableArray = WritableNativeArray()
+ try {
+ val query = reactApplicationContext.contentResolver.query(
+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ arrayOf(
+ MediaStore.Audio.Media._ID,
+ MediaStore.Audio.Media.RELATIVE_PATH,
+ MediaStore.Audio.Media.DISPLAY_NAME
+ ), null,null, null)
+ query?.use { cursor ->
+ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
+ val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
+ val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
+ while (cursor.moveToNext()) {
+ val mediaPath = cursor.getString(pathColumn)
+ if (mediaPath == relativeDir || (subdir && mediaPath.startsWith(relativeDir))) {
+
+ val mediaItem = Arguments.createMap()
+ mediaItem.putString("URI",
+ "content:/" + ContentUris.appendId(
+ Uri.Builder().path(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.path),
+ cursor.getLong(idColumn)).build().toString())
+ mediaItem.putString("relativePath",mediaPath)
+ mediaItem.putString("fileName", cursor.getString(nameColumn))
+ results.pushMap(mediaItem)
+ }
+ }
+ }
+ callback.resolve(results)
+ } catch (e: Exception) {
+ callback.resolve(results)
+ }
+ }
+
@ReactMethod fun getLastExitReason(callback: Promise) {
try {
val activity = reactApplicationContext.currentActivity
val am = activity?.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- val reason = am.getHistoricalProcessExitReasons("com.noxplay.noxplayer",0,0)[0].reason
+ val reason = am.getHistoricalProcessExitReasons(
+ "com.noxplay.noxplayer",0,0
+ )[0].reason
callback.resolve(reason in intArrayOf(
ApplicationExitInfo.REASON_USER_REQUESTED,
ApplicationExitInfo.REASON_USER_STOPPED,
@@ -53,7 +96,10 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) : ReactContext
@ReactMethod fun askDrawOverAppsPermission() {
val context = reactApplicationContext
- val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:com.noxplay.noxplayer"))
+ val intent = Intent(
+ Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:com.noxplay.noxplayer")
+ )
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
}
@@ -71,6 +117,8 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) : ReactContext
@ReactMethod fun isGestureNavigationMode(callback: Promise) {
val context = reactApplicationContext
- callback.resolve(Settings.Secure.getInt(context.contentResolver, "navigation_mode", 0) == 2)
+ callback.resolve(
+ Settings.Secure.getInt(context.contentResolver, "navigation_mode", 0) == 2
+ )
}
}
diff --git a/src/components/playlist/BiliSearch/Icons.tsx b/src/components/playlist/BiliSearch/Icons.tsx
index 3b08c579..43830322 100644
--- a/src/components/playlist/BiliSearch/Icons.tsx
+++ b/src/components/playlist/BiliSearch/Icons.tsx
@@ -27,9 +27,12 @@ const ICONS = {
style={style.musicFreeIcon}
/>
),
- LOCAL: () => (
+ LOCAL: (fill?: string) => (
),
};
diff --git a/src/components/playlist/BiliSearch/SearchMenu.tsx b/src/components/playlist/BiliSearch/SearchMenu.tsx
index 3ef11cce..142a9edb 100644
--- a/src/components/playlist/BiliSearch/SearchMenu.tsx
+++ b/src/components/playlist/BiliSearch/SearchMenu.tsx
@@ -1,11 +1,15 @@
import * as React from 'react';
import { Menu } from 'react-native-paper';
import * as DocumentPicker from 'expo-document-picker';
+import { Platform, NativeModules } from 'react-native';
import { SEARCH_OPTIONS } from '@enums/Storage';
import { MUSICFREE } from '@utils/mediafetch/musicfree';
import ICONS from './Icons';
import { useNoxSetting } from '@stores/useApp';
+import { rgb2Hex } from '@utils/Utils';
+
+const { NoxAndroidAutoModule } = NativeModules;
interface Props {
visible?: boolean;
@@ -20,6 +24,7 @@ export default ({
menuCoords = { x: 0, y: 0 },
showMusicFree,
}: Props) => {
+ const playerStyle = useNoxSetting(state => state.playerStyle);
const setSearchOption = useNoxSetting(state => state.setSearchOption);
const setDefaultSearch = (defaultSearch: SEARCH_OPTIONS | MUSICFREE) => {
toggleVisible();
@@ -46,8 +51,10 @@ export default ({
/>
)}
ICONS.LOCAL(rgb2Hex(playerStyle.colors.primary))}
onPress={async () => {
+ console.log(await NoxAndroidAutoModule.listMediaDir('Music/', true));
+ return;
console.log(
await DocumentPicker.getDocumentAsync({
copyToCacheDirectory: false,
diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts
index 7fd30f02..ce0069a0 100644
--- a/src/utils/Utils.ts
+++ b/src/utils/Utils.ts
@@ -49,6 +49,28 @@ export const rgb2rgba = (rgb: string, a = 1) => {
return `rgba(${extractedRGB[0][0]}, ${extractedRGB[1][0]}, ${extractedRGB[2][0]}, ${a})`;
};
+const rgbToHex = (r: number, g: number, b: number) =>
+ '#' +
+ [r, g, b]
+ .map(x => {
+ const hex = x.toString(16);
+ return hex.length === 1 ? '0' + hex : hex;
+ })
+ .join('');
+
+export const rgb2Hex = (rgb: string) => {
+ try {
+ const extractedRGB = [...rgb.matchAll(/(\d+)/g)];
+ return rgbToHex(
+ Number(extractedRGB[0][0]),
+ Number(extractedRGB[1][0]),
+ Number(extractedRGB[2][0])
+ );
+ } catch {
+ return rgb;
+ }
+};
+
export const getUniqObjects = (
objects: Array,
property: (object: T) => string
From e0188d4c15c3e440a5d9db180aa599d8eda08336 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Thu, 22 Feb 2024 10:46:14 -0800
Subject: [PATCH 03/11] feat: local playback
---
src/components/playlist/BiliSearch/Icons.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/components/playlist/BiliSearch/Icons.tsx b/src/components/playlist/BiliSearch/Icons.tsx
index 43830322..ff9be172 100644
--- a/src/components/playlist/BiliSearch/Icons.tsx
+++ b/src/components/playlist/BiliSearch/Icons.tsx
@@ -31,7 +31,7 @@ const ICONS = {
),
From baf8c2880de8c2e9726474d2b9c9f253a40e9ac5 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Thu, 22 Feb 2024 11:03:49 -0800
Subject: [PATCH 04/11] feat: local playback
---
.../playlist/BiliSearch/SearchMenu.tsx | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/src/components/playlist/BiliSearch/SearchMenu.tsx b/src/components/playlist/BiliSearch/SearchMenu.tsx
index 142a9edb..54c39104 100644
--- a/src/components/playlist/BiliSearch/SearchMenu.tsx
+++ b/src/components/playlist/BiliSearch/SearchMenu.tsx
@@ -8,6 +8,7 @@ import { MUSICFREE } from '@utils/mediafetch/musicfree';
import ICONS from './Icons';
import { useNoxSetting } from '@stores/useApp';
import { rgb2Hex } from '@utils/Utils';
+import logger from '@utils/Logger';
const { NoxAndroidAutoModule } = NativeModules;
@@ -53,14 +54,22 @@ export default ({
ICONS.LOCAL(rgb2Hex(playerStyle.colors.primary))}
onPress={async () => {
- console.log(await NoxAndroidAutoModule.listMediaDir('Music/', true));
- return;
- console.log(
+ let selectedFile = (
await DocumentPicker.getDocumentAsync({
copyToCacheDirectory: false,
type: 'audio/*',
})
- );
+ ).assets;
+ if (!selectedFile) return;
+ // TODO: he.decode?
+ let uri = selectedFile[0].uri;
+ logger.debug(`[DocumentPicker] selected uri: ${uri}`);
+ // content://com.android.externalstorage.documents/document/primary%3AMusic%2FTttt%2FGggg.mp3
+ let parsedURI = uri
+ .substring(uri.indexOf('%3A') + 3, uri.lastIndexOf('%2F'))
+ .replaceAll('%2F', '/');
+ console.log(await NoxAndroidAutoModule.listMediaDir(parsedURI, true));
+ return;
}}
title={'Local'}
/>
From c6d15ef6a271cf591222d90001a8994a0a267af0 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Thu, 22 Feb 2024 12:02:26 -0800
Subject: [PATCH 05/11] feat: local playback
---
.../java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt | 7 +++++--
src/components/playlist/BiliSearch/SearchMenu.tsx | 7 ++++++-
src/utils/ffmpeg/ffmpeg.ts | 8 +++++++-
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
index fc0d02dd..50afbddf 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
@@ -32,16 +32,17 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
arrayOf(
MediaStore.Audio.Media._ID,
MediaStore.Audio.Media.RELATIVE_PATH,
- MediaStore.Audio.Media.DISPLAY_NAME
+ MediaStore.Audio.Media.DISPLAY_NAME,
+ MediaStore.Audio.Media.DATA
), null,null, null)
query?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
+ val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
while (cursor.moveToNext()) {
val mediaPath = cursor.getString(pathColumn)
if (mediaPath == relativeDir || (subdir && mediaPath.startsWith(relativeDir))) {
-
val mediaItem = Arguments.createMap()
mediaItem.putString("URI",
"content:/" + ContentUris.appendId(
@@ -49,12 +50,14 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
cursor.getLong(idColumn)).build().toString())
mediaItem.putString("relativePath",mediaPath)
mediaItem.putString("fileName", cursor.getString(nameColumn))
+ mediaItem.putString("realPath", cursor.getString(dataColumn))
results.pushMap(mediaItem)
}
}
}
callback.resolve(results)
} catch (e: Exception) {
+ Log.e("NoxFileUtil", e.toString())
callback.resolve(results)
}
}
diff --git a/src/components/playlist/BiliSearch/SearchMenu.tsx b/src/components/playlist/BiliSearch/SearchMenu.tsx
index 54c39104..28601f02 100644
--- a/src/components/playlist/BiliSearch/SearchMenu.tsx
+++ b/src/components/playlist/BiliSearch/SearchMenu.tsx
@@ -9,6 +9,7 @@ import ICONS from './Icons';
import { useNoxSetting } from '@stores/useApp';
import { rgb2Hex } from '@utils/Utils';
import logger from '@utils/Logger';
+import { probeMetadata } from '@utils/ffmpeg/ffmpeg';
const { NoxAndroidAutoModule } = NativeModules;
@@ -68,7 +69,11 @@ export default ({
let parsedURI = uri
.substring(uri.indexOf('%3A') + 3, uri.lastIndexOf('%2F'))
.replaceAll('%2F', '/');
- console.log(await NoxAndroidAutoModule.listMediaDir(parsedURI, true));
+ let mediaFiles = await NoxAndroidAutoModule.listMediaDir(
+ parsedURI,
+ true
+ );
+ mediaFiles.forEach((v: any) => probeMetadata(v.realPath));
return;
}}
title={'Local'}
diff --git a/src/utils/ffmpeg/ffmpeg.ts b/src/utils/ffmpeg/ffmpeg.ts
index d03698e7..418225a9 100644
--- a/src/utils/ffmpeg/ffmpeg.ts
+++ b/src/utils/ffmpeg/ffmpeg.ts
@@ -1,10 +1,16 @@
-import { FFmpegKit } from 'ffmpeg-kit-react-native';
+import { FFmpegKit, FFprobeKit } from 'ffmpeg-kit-react-native';
import RNFetchBlob from 'react-native-blob-util';
import TrackPlayer from 'react-native-track-player';
import { logger } from '../Logger';
import { r128gain2Volume } from '../Utils';
+export const probeMetadata = async (fspath: string) => {
+ const session = await FFprobeKit.execute(
+ `-show_format -print_format json '${fspath}'`
+ );
+ console.log(await session.getOutput());
+};
const parseReplayGainLog = (log: string) => {
const regex = /Parsed_replaygain.+ track_gain = (.+) dB/g;
regex.exec(log);
From 02b4337e2b47071da6e38acd47ecc1d42dde0f69 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 06:14:19 -0800
Subject: [PATCH 06/11] feat: local playback
---
.../com/noxplay/noxplayer/NoxAndroidAutoModule.kt | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
index 50afbddf..e2504efa 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
@@ -24,7 +24,7 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
override fun getName() = "NoxAndroidAutoModule"
- @ReactMethod fun listMediaDir(relativeDir: String, subdir: Boolean, callback: Promise) {
+ private fun _listMediaDir(relativeDir: String, subdir: Boolean, selection: String? = null): WritableArray {
val results: WritableArray = WritableNativeArray()
try {
val query = reactApplicationContext.contentResolver.query(
@@ -34,7 +34,7 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
MediaStore.Audio.Media.RELATIVE_PATH,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DATA
- ), null,null, null)
+ ), selection,null, null)
query?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
@@ -55,11 +55,18 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
}
}
}
- callback.resolve(results)
} catch (e: Exception) {
Log.e("NoxFileUtil", e.toString())
- callback.resolve(results)
}
+ return results
+ }
+
+ @ReactMethod fun listMediaDir(relativeDir: String, subdir: Boolean, callback: Promise) {
+ callback.resolve(_listMediaDir(relativeDir, subdir))
+ }
+
+ @ReactMethod fun listMediaFile(relativeDir: String, subdir: Boolean, filename: String, callback: Promise) {
+ callback.resolve(_listMediaDir(relativeDir, subdir, "${MediaStore.Audio.Media.DISPLAY_NAME} = $filename"))
}
@ReactMethod fun getLastExitReason(callback: Promise) {
From eda66ec09e750c7dd38992642d46d099519e6fbf Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 13:44:13 -0800
Subject: [PATCH 07/11] feat: local playback
---
.../noxplay/noxplayer/NoxAndroidAutoModule.kt | 15 ++--
.../playlist/BiliSearch/BiliSearchbar.tsx | 1 +
.../playlist/BiliSearch/SearchMenu.tsx | 40 +++++------
src/enums/MediaFetch.ts | 1 +
src/utils/BiliSearch.ts | 5 ++
src/utils/ffmpeg/ffmpeg.ts | 7 +-
src/utils/mediafetch/local.ts | 69 +++++++++++++++++++
src/utils/mediafetch/resolveURL.ts | 2 +
8 files changed, 111 insertions(+), 29 deletions(-)
create mode 100644 src/utils/mediafetch/local.ts
diff --git a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
index e2504efa..80b0135f 100644
--- a/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
+++ b/android/app/src/main/java/com/noxplay/noxplayer/NoxAndroidAutoModule.kt
@@ -36,9 +36,9 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
MediaStore.Audio.Media.DATA
), selection,null, null)
query?.use { cursor ->
- val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
- val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.RELATIVE_PATH)
- val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
+ val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media._ID)
+ val pathColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.RELATIVE_PATH)
+ val nameColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME)
val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA)
while (cursor.moveToNext()) {
val mediaPath = cursor.getString(pathColumn)
@@ -65,10 +65,15 @@ class NoxAndroidAutoModule(reactContext: ReactApplicationContext) :
callback.resolve(_listMediaDir(relativeDir, subdir))
}
- @ReactMethod fun listMediaFile(relativeDir: String, subdir: Boolean, filename: String, callback: Promise) {
- callback.resolve(_listMediaDir(relativeDir, subdir, "${MediaStore.Audio.Media.DISPLAY_NAME} = $filename"))
+ @ReactMethod fun listMediaFileByFName(filename: String, callback: Promise) {
+ callback.resolve(_listMediaDir("", true,
+ "${MediaStore.Audio.Media.DISPLAY_NAME} = $filename"))
}
+ @ReactMethod fun listMediaFileByID(id: String, callback: Promise) {
+ callback.resolve(_listMediaDir("", true,
+ "${MediaStore.Audio.Media._ID} = $id"))
+ }
@ReactMethod fun getLastExitReason(callback: Promise) {
try {
val activity = reactApplicationContext.currentActivity
diff --git a/src/components/playlist/BiliSearch/BiliSearchbar.tsx b/src/components/playlist/BiliSearch/BiliSearchbar.tsx
index 5ea54657..2a79f3ce 100644
--- a/src/components/playlist/BiliSearch/BiliSearchbar.tsx
+++ b/src/components/playlist/BiliSearch/BiliSearchbar.tsx
@@ -137,6 +137,7 @@ export default ({
toggleVisible={toggleVisible}
menuCoords={menuCoords}
showMusicFree={showMusicFree}
+ setSearchVal={setSearchVal}
/>
void;
menuCoords?: NoxTheme.coordinates;
showMusicFree?: boolean;
+ setSearchVal: (v: string) => void;
}
export default ({
@@ -25,6 +26,7 @@ export default ({
toggleVisible = () => undefined,
menuCoords = { x: 0, y: 0 },
showMusicFree,
+ setSearchVal,
}: Props) => {
const playerStyle = useNoxSetting(state => state.playerStyle);
const setSearchOption = useNoxSetting(state => state.setSearchOption);
@@ -32,6 +34,21 @@ export default ({
toggleVisible();
setSearchOption(defaultSearch);
};
+ const chooseLocalFolder = async () => {
+ let selectedFile = (
+ await DocumentPicker.getDocumentAsync({
+ copyToCacheDirectory: false,
+ type: 'audio/*',
+ })
+ ).assets;
+ if (!selectedFile) return;
+ const uri = selectedFile[0].uri;
+ let mediaFiles = await NoxAndroidAutoModule.listMediaFileByID(
+ uri.substring(uri.lastIndexOf('%3A') + 3)
+ );
+ setSearchVal(`local://${mediaFiles[0].relativePath}`);
+ toggleVisible();
+ };
return (
diff --git a/src/enums/MediaFetch.ts b/src/enums/MediaFetch.ts
index d71fb821..6659b3c9 100644
--- a/src/enums/MediaFetch.ts
+++ b/src/enums/MediaFetch.ts
@@ -4,4 +4,5 @@ export enum SOURCE {
steriatk = 'steriatk',
ytbvideo = 'ytbvideo',
biliBangumi = 'biliBangumi',
+ local = 'local',
}
diff --git a/src/utils/BiliSearch.ts b/src/utils/BiliSearch.ts
index e5bdd1c6..ffab1cb7 100644
--- a/src/utils/BiliSearch.ts
+++ b/src/utils/BiliSearch.ts
@@ -20,6 +20,7 @@ import ytbmixlistFetch from './mediafetch/ytbmixlist';
import ytbsearchFetch from './mediafetch/ytbsearch';
import bililiveFetch from './mediafetch/bililive';
import bilisubliveFetch from './mediafetch/bilisublive';
+import localFetch from '@utils/mediafetch/local';
import { regexFetchProps } from './mediafetch/generic';
import { MUSICFREE, searcher } from './mediafetch/musicfree';
import { getMusicFreePlugin } from '@utils/ChromeStorage';
@@ -116,6 +117,10 @@ interface ReExtraction {
}
const reExtractions: ReExtraction[] = [
+ {
+ match: localFetch.regexSearchMatch,
+ fetch: localFetch.regexFetch,
+ },
{
match: biliBangumiFetch.regexSearchMatch,
fetch: biliBangumiFetch.regexFetch,
diff --git a/src/utils/ffmpeg/ffmpeg.ts b/src/utils/ffmpeg/ffmpeg.ts
index 418225a9..1026140f 100644
--- a/src/utils/ffmpeg/ffmpeg.ts
+++ b/src/utils/ffmpeg/ffmpeg.ts
@@ -7,10 +7,13 @@ import { r128gain2Volume } from '../Utils';
export const probeMetadata = async (fspath: string) => {
const session = await FFprobeKit.execute(
- `-show_format -print_format json '${fspath}'`
+ `-v quiet -print_format json -show_format '${fspath}'`
);
- console.log(await session.getOutput());
+ const parsedMetadata = JSON.parse(await session.getOutput());
+ logger.debug(parsedMetadata);
+ return parsedMetadata.format;
};
+
const parseReplayGainLog = (log: string) => {
const regex = /Parsed_replaygain.+ track_gain = (.+) dB/g;
regex.exec(log);
diff --git a/src/utils/mediafetch/local.ts b/src/utils/mediafetch/local.ts
new file mode 100644
index 00000000..bd5a0845
--- /dev/null
+++ b/src/utils/mediafetch/local.ts
@@ -0,0 +1,69 @@
+/**
+ * refactor:
+ * bilisearch workflow:
+ * reExtractSearch matches regex patterns and use the corresponding fetch functions;
+ * fetch function takes extracted and calls a dataProcess.js fetch function;
+ * dataprocess fetch function fetches VIDEOINFO using data.js fetch function, then parses into SONGS
+ * data.js fetch function fetches VIDEOINFO.
+ * steps to refactor:
+ * each site needs a fetch to parse regex extracted, a videoinfo fetcher and a song fetcher.
+ */
+import { Platform, NativeModules } from 'react-native';
+
+import { probeMetadata } from '@utils/ffmpeg/ffmpeg';
+import { SOURCE } from '@enums/MediaFetch';
+import { regexFetchProps } from './generic';
+import SongTS from '@objects/Song';
+
+const { NoxAndroidAutoModule } = NativeModules;
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const songFetch = async (
+ fpath: string,
+ favlist: string[]
+): Promise => {
+ const mediaFiles = await NoxAndroidAutoModule.listMediaDir(fpath, true);
+ return Promise.all(
+ mediaFiles
+ .filter((v: any) => !favlist.includes(v.realPath))
+ .map(async (v: any) => {
+ const probedMetadata = await probeMetadata(v.realPath);
+ return SongTS({
+ cid: `${SOURCE.local}-${v.realPath}`,
+ bvid: `file://${v.realPath}`,
+ name: probedMetadata.tags?.title || v.fileName,
+ nameRaw: probedMetadata.tags?.title || v.fileName,
+ singer: probedMetadata.tags?.artist || '',
+ singerId: probedMetadata.tags?.artist || '',
+ cover:
+ 'https://i2.hdslb.com/bfs/face/b70f6e62e4582d4fa5d48d86047e64eb57d7504e.jpg',
+ lyric: '',
+ page: 0,
+ duration: Number(probedMetadata.duration) || 0,
+ album: probedMetadata.tags?.album || '',
+ source: SOURCE.local,
+ });
+ })
+ );
+};
+
+const regexFetch = async ({
+ reExtracted,
+ favList = [],
+}: regexFetchProps): Promise => ({
+ songList: await songFetch(reExtracted[1]!, favList),
+});
+
+const resolveURL = async (song: NoxMedia.Song) => {
+ return { url: song.bvid };
+};
+
+const refreshSong = (song: NoxMedia.Song) => song;
+
+export default {
+ regexSearchMatch: /local:\/\/(.+)/,
+ regexFetch,
+ regexResolveURLMatch: /^local-/,
+ resolveURL,
+ refreshSong,
+};
diff --git a/src/utils/mediafetch/resolveURL.ts b/src/utils/mediafetch/resolveURL.ts
index 141487b0..21c07d5b 100644
--- a/src/utils/mediafetch/resolveURL.ts
+++ b/src/utils/mediafetch/resolveURL.ts
@@ -3,6 +3,7 @@ import biliaudioFetch from './biliaudio';
import ytbvideoFetch from '@utils/mediafetch/ytbvideo';
import bililiveFetch from './bililive';
import biliBangumiFetch from './biliBangumi';
+import localFetch from '@utils/mediafetch/local';
import { logger } from '../Logger';
import { regexMatchOperations } from '../Utils';
import { resolver, MUSICFREE } from './musicfree';
@@ -37,6 +38,7 @@ export const fetchPlayUrlPromise = async (
[ytbvideoFetch.regexResolveURLMatch, ytbvideoFetch.resolveURL],
[bililiveFetch.regexResolveURLMatch, bililiveFetch.resolveURL],
[biliBangumiFetch.regexResolveURLMatch, biliBangumiFetch.resolveURL],
+ [localFetch.regexResolveURLMatch, localFetch.resolveURL],
];
const regexResolveURLsWrapped: regResolve = regexResolveURLs.map(entry => [
entry[0],
From 8fd53729eaa2d7a06bec03174a3400fa3dd3e20b Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 14:20:04 -0800
Subject: [PATCH 08/11] feat: local playback
---
src/stores/appStore.ts | 10 +++++++---
src/utils/SongOperations.ts | 1 +
src/utils/ffmpeg/ffmpeg.ts | 8 ++++++++
src/utils/mediafetch/local.ts | 9 ++++-----
4 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/src/stores/appStore.ts b/src/stores/appStore.ts
index 7c839155..3a6a1e21 100644
--- a/src/stores/appStore.ts
+++ b/src/stores/appStore.ts
@@ -11,6 +11,7 @@ import {
import { logger } from '@utils/Logger';
import rejson from '../utils/rejson.json';
import { LoadJSONRegExtractors } from '../utils/re';
+import { SOURCE } from '@enums/MediaFetch';
interface AppStore {
pipMode: boolean;
@@ -180,9 +181,12 @@ export const cacheResolvedURL = async (
) {
logger.debug(`[CacheResolveURL] ${song.parsedName} needs to be refetched.`);
const result = await resolveURL(song);
- appStore.setState({
- cachedResolveURLMap: { ...cachedResolveURLMap, [song.id]: result },
- });
+ // HACK: do not cache any local source files
+ if (song.source !== SOURCE.local) {
+ appStore.setState({
+ cachedResolveURLMap: { ...cachedResolveURLMap, [song.id]: result },
+ });
+ }
return result;
}
return cachedResolvedURL;
diff --git a/src/utils/SongOperations.ts b/src/utils/SongOperations.ts
index 21274c27..2055a331 100644
--- a/src/utils/SongOperations.ts
+++ b/src/utils/SongOperations.ts
@@ -60,6 +60,7 @@ export const resolveUrl = async (song: NoxMedia.Song, iOS = true) => {
logger.debug(
`[SongResolveURL] cache ${cachedUrl ? 'found' : 'missed'}, ${song.id}`
);
+
const cacheWrapper = async (
song: NoxMedia.Song
): Promise => {
diff --git a/src/utils/ffmpeg/ffmpeg.ts b/src/utils/ffmpeg/ffmpeg.ts
index 1026140f..cbaf675b 100644
--- a/src/utils/ffmpeg/ffmpeg.ts
+++ b/src/utils/ffmpeg/ffmpeg.ts
@@ -5,6 +5,14 @@ import TrackPlayer from 'react-native-track-player';
import { logger } from '../Logger';
import { r128gain2Volume } from '../Utils';
+export const cacheAlbumArt = async (fpath: string) => {
+ // HACK: exoplayer handles embedded art but I also need this for the UI...
+ await FFmpegKit.execute(
+ `-i '${fpath}' -an -vcodec copy ${RNFetchBlob.fs.dirs.CacheDir}/tempCover.jpg`
+ );
+ return `${RNFetchBlob.fs.dirs.CacheDir}/tempCover.jpg`;
+};
+
export const probeMetadata = async (fspath: string) => {
const session = await FFprobeKit.execute(
`-v quiet -print_format json -show_format '${fspath}'`
diff --git a/src/utils/mediafetch/local.ts b/src/utils/mediafetch/local.ts
index bd5a0845..fc5a283f 100644
--- a/src/utils/mediafetch/local.ts
+++ b/src/utils/mediafetch/local.ts
@@ -8,9 +8,9 @@
* steps to refactor:
* each site needs a fetch to parse regex extracted, a videoinfo fetcher and a song fetcher.
*/
-import { Platform, NativeModules } from 'react-native';
+import { NativeModules } from 'react-native';
-import { probeMetadata } from '@utils/ffmpeg/ffmpeg';
+import { probeMetadata, cacheAlbumArt } from '@utils/ffmpeg/ffmpeg';
import { SOURCE } from '@enums/MediaFetch';
import { regexFetchProps } from './generic';
import SongTS from '@objects/Song';
@@ -35,8 +35,7 @@ const songFetch = async (
nameRaw: probedMetadata.tags?.title || v.fileName,
singer: probedMetadata.tags?.artist || '',
singerId: probedMetadata.tags?.artist || '',
- cover:
- 'https://i2.hdslb.com/bfs/face/b70f6e62e4582d4fa5d48d86047e64eb57d7504e.jpg',
+ cover: '',
lyric: '',
page: 0,
duration: Number(probedMetadata.duration) || 0,
@@ -55,7 +54,7 @@ const regexFetch = async ({
});
const resolveURL = async (song: NoxMedia.Song) => {
- return { url: song.bvid };
+ return { url: song.bvid, cover: await cacheAlbumArt(song.bvid) };
};
const refreshSong = (song: NoxMedia.Song) => song;
From 65b59faa53a26425c5bd5bd0d41a745065b037e0 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 14:47:07 -0800
Subject: [PATCH 09/11] feat: local playback
---
.../playlist/BiliSearch/SearchMenu.tsx | 16 +++++++++-------
src/localization/en/translation.json | 3 +++
src/localization/zhcn/translation.json | 3 +++
src/utils/mediafetch/local.ts | 3 ++-
4 files changed, 17 insertions(+), 8 deletions(-)
diff --git a/src/components/playlist/BiliSearch/SearchMenu.tsx b/src/components/playlist/BiliSearch/SearchMenu.tsx
index 62c4a129..82c3a213 100644
--- a/src/components/playlist/BiliSearch/SearchMenu.tsx
+++ b/src/components/playlist/BiliSearch/SearchMenu.tsx
@@ -2,14 +2,13 @@ import * as React from 'react';
import { Menu } from 'react-native-paper';
import * as DocumentPicker from 'expo-document-picker';
import { Platform, NativeModules } from 'react-native';
+import { useTranslation } from 'react-i18next';
import { SEARCH_OPTIONS } from '@enums/Storage';
import { MUSICFREE } from '@utils/mediafetch/musicfree';
import ICONS from './Icons';
import { useNoxSetting } from '@stores/useApp';
import { rgb2Hex } from '@utils/Utils';
-import logger from '@utils/Logger';
-import { probeMetadata } from '@utils/ffmpeg/ffmpeg';
const { NoxAndroidAutoModule } = NativeModules;
@@ -28,6 +27,7 @@ export default ({
showMusicFree,
setSearchVal,
}: Props) => {
+ const { t } = useTranslation();
const playerStyle = useNoxSetting(state => state.playerStyle);
const setSearchOption = useNoxSetting(state => state.setSearchOption);
const setDefaultSearch = (defaultSearch: SEARCH_OPTIONS | MUSICFREE) => {
@@ -69,11 +69,13 @@ export default ({
title={`MusicFree.${MUSICFREE.aggregated}`}
/>
)}
- ICONS.LOCAL(rgb2Hex(playerStyle.colors.primary))}
- onPress={chooseLocalFolder}
- title={'Local'}
- />
+ {Platform.OS === 'android' && (
+ ICONS.LOCAL(rgb2Hex(playerStyle.colors.primary))}
+ onPress={chooseLocalFolder}
+ title={t('Menu.local')}
+ />
+ )}
);
};
diff --git a/src/localization/en/translation.json b/src/localization/en/translation.json
index 2f44233a..fbbb2df1 100644
--- a/src/localization/en/translation.json
+++ b/src/localization/en/translation.json
@@ -284,5 +284,8 @@
},
"Accessibility": {
"gif": "GIF"
+ },
+ "Menu": {
+ "local": "Local"
}
}
diff --git a/src/localization/zhcn/translation.json b/src/localization/zhcn/translation.json
index 8aa033a6..44bcf9fe 100644
--- a/src/localization/zhcn/translation.json
+++ b/src/localization/zhcn/translation.json
@@ -253,5 +253,8 @@
"artistMatch": "搜索歌手",
"albumMatch": "搜索专辑",
"cachedMatch": "已缓存"
+ },
+ "Menu": {
+ "local": "本di"
}
}
diff --git a/src/utils/mediafetch/local.ts b/src/utils/mediafetch/local.ts
index fc5a283f..51fc9281 100644
--- a/src/utils/mediafetch/local.ts
+++ b/src/utils/mediafetch/local.ts
@@ -8,7 +8,7 @@
* steps to refactor:
* each site needs a fetch to parse regex extracted, a videoinfo fetcher and a song fetcher.
*/
-import { NativeModules } from 'react-native';
+import { Platform, NativeModules } from 'react-native';
import { probeMetadata, cacheAlbumArt } from '@utils/ffmpeg/ffmpeg';
import { SOURCE } from '@enums/MediaFetch';
@@ -22,6 +22,7 @@ const songFetch = async (
fpath: string,
favlist: string[]
): Promise => {
+ if (Platform.OS !== 'android') return [];
const mediaFiles = await NoxAndroidAutoModule.listMediaDir(fpath, true);
return Promise.all(
mediaFiles
From de4c7e4882294a6a59c0754a2c139e8ed6fd695d Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 14:56:02 -0800
Subject: [PATCH 10/11] feat: local playback
---
src/components/player/TrackInfo/AlbumArt.tsx | 1 +
src/stores/appStore.ts | 10 +++-------
src/utils/mediafetch/local.ts | 5 ++++-
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/components/player/TrackInfo/AlbumArt.tsx b/src/components/player/TrackInfo/AlbumArt.tsx
index 40c9564e..438d8a86 100644
--- a/src/components/player/TrackInfo/AlbumArt.tsx
+++ b/src/components/player/TrackInfo/AlbumArt.tsx
@@ -46,6 +46,7 @@ const AlbumArt: React.FC = ({
useNativeDriver: true,
}),
]).start(() => {
+ console.log('artwork', track?.artwork);
console.log('TrackInfo: Setting imagevisible to Image', !isImageVisible);
setIsImageVisible(false);
});
diff --git a/src/stores/appStore.ts b/src/stores/appStore.ts
index 3a6a1e21..7c839155 100644
--- a/src/stores/appStore.ts
+++ b/src/stores/appStore.ts
@@ -11,7 +11,6 @@ import {
import { logger } from '@utils/Logger';
import rejson from '../utils/rejson.json';
import { LoadJSONRegExtractors } from '../utils/re';
-import { SOURCE } from '@enums/MediaFetch';
interface AppStore {
pipMode: boolean;
@@ -181,12 +180,9 @@ export const cacheResolvedURL = async (
) {
logger.debug(`[CacheResolveURL] ${song.parsedName} needs to be refetched.`);
const result = await resolveURL(song);
- // HACK: do not cache any local source files
- if (song.source !== SOURCE.local) {
- appStore.setState({
- cachedResolveURLMap: { ...cachedResolveURLMap, [song.id]: result },
- });
- }
+ appStore.setState({
+ cachedResolveURLMap: { ...cachedResolveURLMap, [song.id]: result },
+ });
return result;
}
return cachedResolvedURL;
diff --git a/src/utils/mediafetch/local.ts b/src/utils/mediafetch/local.ts
index 51fc9281..bd342ba7 100644
--- a/src/utils/mediafetch/local.ts
+++ b/src/utils/mediafetch/local.ts
@@ -9,6 +9,7 @@
* each site needs a fetch to parse regex extracted, a videoinfo fetcher and a song fetcher.
*/
import { Platform, NativeModules } from 'react-native';
+import RNFetchBlob from 'react-native-blob-util';
import { probeMetadata, cacheAlbumArt } from '@utils/ffmpeg/ffmpeg';
import { SOURCE } from '@enums/MediaFetch';
@@ -55,7 +56,9 @@ const regexFetch = async ({
});
const resolveURL = async (song: NoxMedia.Song) => {
- return { url: song.bvid, cover: await cacheAlbumArt(song.bvid) };
+ const artworkURI = await cacheAlbumArt(song.bvid);
+ const artworkBase64 = await RNFetchBlob.fs.readFile(artworkURI, 'base64');
+ return { url: song.bvid, cover: `data:image/png;base64,${artworkBase64}` };
};
const refreshSong = (song: NoxMedia.Song) => song;
From 2a1eeafe3b2e71b7b8fbc17f103348fbd6af8b22 Mon Sep 17 00:00:00 2001
From: lovegaoshi <106490582+lovegaoshi@users.noreply.github.com>
Date: Fri, 23 Feb 2024 14:56:32 -0800
Subject: [PATCH 11/11] feat: local playback
---
src/components/player/TrackInfo/AlbumArt.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/components/player/TrackInfo/AlbumArt.tsx b/src/components/player/TrackInfo/AlbumArt.tsx
index 438d8a86..40c9564e 100644
--- a/src/components/player/TrackInfo/AlbumArt.tsx
+++ b/src/components/player/TrackInfo/AlbumArt.tsx
@@ -46,7 +46,6 @@ const AlbumArt: React.FC = ({
useNativeDriver: true,
}),
]).start(() => {
- console.log('artwork', track?.artwork);
console.log('TrackInfo: Setting imagevisible to Image', !isImageVisible);
setIsImageVisible(false);
});