xref: /MusicFree/src/entry/bootstrap.ts (revision 34bfbe58c7be2b25145bbf29046f8a418be73f02)
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