132683ee6Smaotoumaoimport { check, PERMISSIONS, request } from "react-native-permissions"; 232683ee6Smaotoumaoimport RNTrackPlayer, { AppKilledPlaybackBehavior, Capability } from "react-native-track-player"; 332683ee6Smaotoumaoimport "react-native-get-random-values"; 441ddce91Smaotoumaoimport Config from "@/core/config.ts"; 532683ee6Smaotoumaoimport pathConst from "@/constants/pathConst"; 632683ee6Smaotoumaoimport { checkAndCreateDir } from "@/utils/fileUtils"; 732683ee6Smaotoumaoimport { errorLog, trace } from "@/utils/log"; 832683ee6Smaotoumaoimport PluginManager from "@/core/pluginManager"; 932683ee6Smaotoumaoimport Network from "@/core/network"; 1032683ee6Smaotoumaoimport { ImgAsset } from "@/constants/assetsConst"; 1132683ee6Smaotoumaoimport LocalMusicSheet from "@/core/localMusicSheet"; 1232683ee6Smaotoumaoimport { Linking, Platform } from "react-native"; 1332683ee6Smaotoumaoimport Theme from "@/core/theme"; 1432683ee6Smaotoumaoimport LyricManager from "@/core/lyricManager"; 1532683ee6Smaotoumaoimport Toast from "@/utils/toast"; 1650245d53Smaotoumaoimport { emptyFunction, localPluginHash, supportLocalMediaType } from "@/constants/commonConst"; 1732683ee6Smaotoumaoimport TrackPlayer from "@/core/trackPlayer"; 1832683ee6Smaotoumaoimport musicHistory from "@/core/musicHistory"; 19819a9075Smaotoumaoimport PersistStatus from "@/core/persistStatus.ts"; 2032683ee6Smaotoumaoimport { perfLogger } from "@/utils/perfLogger"; 2132683ee6Smaotoumaoimport * as SplashScreen from "expo-splash-screen"; 2232683ee6Smaotoumaoimport MusicSheet from "@/core/musicSheet"; 2332683ee6Smaotoumaoimport NativeUtils from "@/native/utils"; 2432683ee6Smaotoumaoimport { showDialog } from "@/components/dialogs/useDialog.ts"; 25bf6e62f2S猫头猫 268b88e961S猫头猫/** app加载前执行 278b88e961S猫头猫 * 1. 检查权限 288b88e961S猫头猫 * 2. 数据初始化 298b88e961S猫头猫 */ 3091eb8fa8S猫头猫 3194a1b1fcS猫头猫async function _bootstrap() { 325589cdf3S猫头猫 await SplashScreen.preventAutoHideAsync() 335589cdf3S猫头猫 .then(result => 345589cdf3S猫头猫 console.log( 355589cdf3S猫头猫 `SplashScreen.preventAutoHideAsync() succeeded: ${result}`, 365589cdf3S猫头猫 ), 375589cdf3S猫头猫 ) 385589cdf3S猫头猫 .catch(console.warn); // it's good to explicitly catch and inspect any error 3991eb8fa8S猫头猫 const logger = perfLogger(); 40927dbe93S猫头猫 // 1. 检查权限 41740e3947S猫头猫 if (Platform.OS === 'android' && Platform.Version >= 30) { 42740e3947S猫头猫 const hasPermission = await NativeUtils.checkStoragePermission(); 43740e3947S猫头猫 if ( 44740e3947S猫头猫 !hasPermission && 45819a9075Smaotoumao !PersistStatus.get('app.skipBootstrapStorageDialog') 46740e3947S猫头猫 ) { 47740e3947S猫头猫 showDialog('CheckStorage'); 48740e3947S猫头猫 } 49740e3947S猫头猫 } else { 50740e3947S猫头猫 const [readStoragePermission, writeStoragePermission] = 51740e3947S猫头猫 await Promise.all([ 52bf6e62f2S猫头猫 check(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE), 53bf6e62f2S猫头猫 check(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE), 54bf6e62f2S猫头猫 ]); 55bf6e62f2S猫头猫 if ( 56bf6e62f2S猫头猫 !( 57bf6e62f2S猫头猫 readStoragePermission === 'granted' && 58bf6e62f2S猫头猫 writeStoragePermission === 'granted' 59bf6e62f2S猫头猫 ) 60bf6e62f2S猫头猫 ) { 61bf6e62f2S猫头猫 await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE); 62bf6e62f2S猫头猫 await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE); 63bf6e62f2S猫头猫 } 64740e3947S猫头猫 } 6591eb8fa8S猫头猫 logger.mark('权限检查完成'); 66bf6e62f2S猫头猫 67927dbe93S猫头猫 // 2. 数据初始化 686780f402S猫头猫 /** 初始化路径 */ 696780f402S猫头猫 await setupFolder(); 701e263108S猫头猫 trace('文件夹初始化完成'); 7191eb8fa8S猫头猫 logger.mark('文件夹初始化完成'); 7291eb8fa8S猫头猫 73bf6e62f2S猫头猫 // 加载配置 74ef714860S猫头猫 await Promise.all([ 7591eb8fa8S猫头猫 Config.setup().then(() => { 7691eb8fa8S猫头猫 logger.mark('Config'); 7791eb8fa8S猫头猫 }), 7891eb8fa8S猫头猫 MusicSheet.setup().then(() => { 7991eb8fa8S猫头猫 logger.mark('MusicSheet'); 8091eb8fa8S猫头猫 }), 8191eb8fa8S猫头猫 musicHistory.setupMusicHistory().then(() => { 8291eb8fa8S猫头猫 logger.mark('musicHistory'); 8391eb8fa8S猫头猫 }), 84ef714860S猫头猫 ]); 851e263108S猫头猫 trace('配置初始化完成'); 8691eb8fa8S猫头猫 logger.mark('配置初始化完成'); 8791eb8fa8S猫头猫 88bf6e62f2S猫头猫 // 加载插件 8994a1b1fcS猫头猫 try { 905500cea7S猫头猫 await RNTrackPlayer.setupPlayer({ 91b882a19dS猫头猫 maxCacheSize: 9241ddce91Smaotoumao Config.getConfig('basic.maxCacheSize') ?? 1024 * 1024 * 512, 93cfa0fc07S猫头猫 }); 9494a1b1fcS猫头猫 } catch (e: any) { 9594a1b1fcS猫头猫 if ( 964060c00aS猫头猫 e?.message !== 974060c00aS猫头猫 'The player has already been initialized via setupPlayer.' 9894a1b1fcS猫头猫 ) { 9994a1b1fcS猫头猫 throw e; 10094a1b1fcS猫头猫 } 10194a1b1fcS猫头猫 } 10291eb8fa8S猫头猫 logger.mark('加载播放器'); 10366e1d5fcS猫头猫 10441ddce91Smaotoumao const capabilities = Config.getConfig('basic.showExitOnNotification') 10566e1d5fcS猫头猫 ? [ 10666e1d5fcS猫头猫 Capability.Play, 10766e1d5fcS猫头猫 Capability.Pause, 10866e1d5fcS猫头猫 Capability.SkipToNext, 10966e1d5fcS猫头猫 Capability.SkipToPrevious, 11066e1d5fcS猫头猫 Capability.Stop, 11166e1d5fcS猫头猫 ] 11266e1d5fcS猫头猫 : [ 11366e1d5fcS猫头猫 Capability.Play, 11466e1d5fcS猫头猫 Capability.Pause, 11566e1d5fcS猫头猫 Capability.SkipToNext, 11666e1d5fcS猫头猫 Capability.SkipToPrevious, 11766e1d5fcS猫头猫 ]; 1185500cea7S猫头猫 await RNTrackPlayer.updateOptions({ 1192aa88193S猫头猫 icon: ImgAsset.logoTransparent, 120e2257bd6S猫头猫 progressUpdateEventInterval: 1, 1215500cea7S猫头猫 android: { 1225500cea7S猫头猫 alwaysPauseOnInterruption: true, 1235500cea7S猫头猫 appKilledPlaybackBehavior: 1245500cea7S猫头猫 AppKilledPlaybackBehavior.ContinuePlayback, 1255500cea7S猫头猫 }, 12666e1d5fcS猫头猫 capabilities: capabilities, 12766e1d5fcS猫头猫 compactCapabilities: capabilities, 12866e1d5fcS猫头猫 notificationCapabilities: [...capabilities, Capability.SeekTo], 1290d39db21S猫头猫 }); 13091eb8fa8S猫头猫 logger.mark('播放器初始化完成'); 1311e263108S猫头猫 trace('播放器初始化完成'); 13291eb8fa8S猫头猫 1338b88e961S猫头猫 await PluginManager.setup(); 13491eb8fa8S猫头猫 logger.mark('插件初始化完成'); 13591eb8fa8S猫头猫 1361e263108S猫头猫 trace('插件初始化完成'); 1375500cea7S猫头猫 await TrackPlayer.setupTrackPlayer(); 1381e263108S猫头猫 trace('播放列表初始化完成'); 13991eb8fa8S猫头猫 logger.mark('播放列表初始化完成'); 14091eb8fa8S猫头猫 1410e4173cdS猫头猫 await LocalMusicSheet.setup(); 1420e4173cdS猫头猫 trace('本地音乐初始化完成'); 14391eb8fa8S猫头猫 logger.mark('本地音乐初始化完成'); 14491eb8fa8S猫头猫 145a27adc20S猫头猫 Theme.setup(); 146a27adc20S猫头猫 trace('主题初始化完成'); 14791eb8fa8S猫头猫 logger.mark('主题初始化完成'); 14891eb8fa8S猫头猫 14957277364S猫头猫 await LyricManager.setup(); 1508b88e961S猫头猫 15191eb8fa8S猫头猫 logger.mark('歌词初始化完成'); 15291eb8fa8S猫头猫 153b3a3a048S猫头猫 extraMakeup(); 154c79c8a57S猫头猫 ErrorUtils.setGlobalHandler(error => { 155c79c8a57S猫头猫 errorLog('未捕获的错误', error); 156c79c8a57S猫头猫 }); 157bf6e62f2S猫头猫} 1586c6f45bdS猫头猫 1596c6f45bdS猫头猫/** 初始化 */ 1606c6f45bdS猫头猫async function setupFolder() { 1616780f402S猫头猫 await Promise.all([ 162be0a3650S猫头猫 checkAndCreateDir(pathConst.dataPath), 1637f771613S猫头猫 checkAndCreateDir(pathConst.logPath), 1647f771613S猫头猫 checkAndCreateDir(pathConst.cachePath), 165c79c8a57S猫头猫 checkAndCreateDir(pathConst.pluginPath), 16694a1b1fcS猫头猫 checkAndCreateDir(pathConst.lrcCachePath), 16742a9f3e6Smaotoumao checkAndCreateDir(pathConst.downloadCachePath), 16826f32636S猫头猫 checkAndCreateDir(pathConst.localLrcPath), 1690e4173cdS猫头猫 checkAndCreateDir(pathConst.downloadPath).then(() => { 1700e4173cdS猫头猫 checkAndCreateDir(pathConst.downloadMusicPath); 1710e4173cdS猫头猫 }), 1726780f402S猫头猫 ]); 1736c6f45bdS猫头猫} 17494a1b1fcS猫头猫 17594a1b1fcS猫头猫export default async function () { 17694a1b1fcS猫头猫 try { 17794a1b1fcS猫头猫 await _bootstrap(); 17894a1b1fcS猫头猫 } catch (e) { 17994a1b1fcS猫头猫 errorLog('初始化出错', e); 18094a1b1fcS猫头猫 } 18194a1b1fcS猫头猫 // 隐藏开屏动画 18294a1b1fcS猫头猫 console.log('HIDE'); 1835589cdf3S猫头猫 await SplashScreen.hideAsync(); 18494a1b1fcS猫头猫} 185b3a3a048S猫头猫 186b3a3a048S猫头猫/** 不需要阻塞的 */ 187b3a3a048S猫头猫async function extraMakeup() { 188a84a85c5S猫头猫 // 自动更新 189b3a3a048S猫头猫 try { 19091eb8fa8S猫头猫 // 初始化网络状态 19191eb8fa8S猫头猫 Network.setup(); 19291eb8fa8S猫头猫 19341ddce91Smaotoumao if (Config.getConfig('basic.autoUpdatePlugin')) { 194819a9075Smaotoumao const lastUpdated = PersistStatus.get('app.pluginUpdateTime') || 0; 195b3a3a048S猫头猫 const now = Date.now(); 196b3a3a048S猫头猫 if (Math.abs(now - lastUpdated) > 86400000) { 197819a9075Smaotoumao PersistStatus.set('app.pluginUpdateTime', now); 198b3a3a048S猫头猫 const plugins = PluginManager.getValidPlugins(); 199b3a3a048S猫头猫 for (let i = 0; i < plugins.length; ++i) { 200b3a3a048S猫头猫 const srcUrl = plugins[i].instance.srcUrl; 201b3a3a048S猫头猫 if (srcUrl) { 20250245d53Smaotoumao // 静默失败 20350245d53Smaotoumao await PluginManager.installPluginFromUrl(srcUrl).catch(emptyFunction); 204b3a3a048S猫头猫 } 205b3a3a048S猫头猫 } 206b3a3a048S猫头猫 } 207b3a3a048S猫头猫 } 208b3a3a048S猫头猫 } catch {} 209a84a85c5S猫头猫 210a84a85c5S猫头猫 async function handleLinkingUrl(url: string) { 211a84a85c5S猫头猫 // 插件 212a84a85c5S猫头猫 try { 213eea2f34fS猫头猫 if (url.startsWith('musicfree://install/')) { 214eea2f34fS猫头猫 const plugins = url 215eea2f34fS猫头猫 .slice(20) 216eea2f34fS猫头猫 .split(',') 217eea2f34fS猫头猫 .map(decodeURIComponent); 218eea2f34fS猫头猫 await Promise.all( 219eea2f34fS猫头猫 plugins.map(it => 22050245d53Smaotoumao PluginManager.installPluginFromUrl(it).catch(emptyFunction), 221eea2f34fS猫头猫 ), 222eea2f34fS猫头猫 ); 223eea2f34fS猫头猫 Toast.success('安装成功~'); 224eea2f34fS猫头猫 } else if (url.endsWith('.js')) { 22550245d53Smaotoumao PluginManager.installPluginFromLocalFile(url, { 22641ddce91Smaotoumao notCheckVersion: Config.getConfig( 22741ddce91Smaotoumao 'basic.notCheckPluginVersion', 228e36e2599S猫头猫 ), 229e36e2599S猫头猫 }) 230a84a85c5S猫头猫 .then(res => { 231*34bfbe58Smaotoumao if (res.success) { 232*34bfbe58Smaotoumao Toast.success(`插件「${res.pluginName}」安装成功~`); 233*34bfbe58Smaotoumao } else { 234*34bfbe58Smaotoumao Toast.warn("安装失败: " + res.message); 235*34bfbe58Smaotoumao } 236a84a85c5S猫头猫 }) 237a84a85c5S猫头猫 .catch(e => { 238a84a85c5S猫头猫 console.log(e); 239a84a85c5S猫头猫 Toast.warn(e?.message ?? '无法识别此插件'); 240a84a85c5S猫头猫 }); 241a84a85c5S猫头猫 } else if (supportLocalMediaType.some(it => url.endsWith(it))) { 242a84a85c5S猫头猫 // 本地播放 243a84a85c5S猫头猫 const musicItem = await PluginManager.getByHash( 244a84a85c5S猫头猫 localPluginHash, 245a84a85c5S猫头猫 )?.instance?.importMusicItem?.(url); 246a84a85c5S猫头猫 console.log(musicItem); 247a84a85c5S猫头猫 if (musicItem) { 2485500cea7S猫头猫 TrackPlayer.play(musicItem); 249a84a85c5S猫头猫 } 250a84a85c5S猫头猫 } 251a84a85c5S猫头猫 } catch {} 252a84a85c5S猫头猫 } 253a84a85c5S猫头猫 254a84a85c5S猫头猫 // 开启监听 255a84a85c5S猫头猫 Linking.addEventListener('url', data => { 256a84a85c5S猫头猫 if (data.url) { 257a84a85c5S猫头猫 handleLinkingUrl(data.url); 258a84a85c5S猫头猫 } 259a84a85c5S猫头猫 }); 260a84a85c5S猫头猫 const initUrl = await Linking.getInitialURL(); 261a84a85c5S猫头猫 if (initUrl) { 262a84a85c5S猫头猫 handleLinkingUrl(initUrl); 263a84a85c5S猫头猫 } 264aaa0db32S猫头猫 26541ddce91Smaotoumao if (Config.getConfig('basic.autoPlayWhenAppStart')) { 2665500cea7S猫头猫 TrackPlayer.play(); 267aaa0db32S猫头猫 } 268b3a3a048S猫头猫} 269