xref: /MusicFree/src/entry/bootstrap.ts (revision eea2f34f4c3284a4b0fcee0326ae6a3b9c7272ee)
1import MusicSheet from '@/core/musicSheet';
2import {check, PERMISSIONS, request} from 'react-native-permissions';
3import RNTrackPlayer, {
4    AppKilledPlaybackBehavior,
5    Capability,
6} from 'react-native-track-player';
7import 'react-native-get-random-values';
8import Config from '@/core/config';
9import RNBootSplash from 'react-native-bootsplash';
10import pathConst from '@/constants/pathConst';
11import {checkAndCreateDir} from '@/utils/fileUtils';
12import {errorLog, trace} from '@/utils/log';
13import MediaMeta from '@/core/mediaMeta.old';
14import Cache from '@/core/cache.old';
15import PluginManager from '@/core/pluginManager';
16import Network from '@/core/network';
17import {ImgAsset} from '@/constants/assetsConst';
18import LocalMusicSheet from '@/core/localMusicSheet';
19import {Linking} from 'react-native';
20import Theme from '@/core/theme';
21import LyricManager from '@/core/lyricManager';
22import {getStorage, setStorage} from '@/utils/storage';
23import Toast from '@/utils/toast';
24import {localPluginHash, supportLocalMediaType} from '@/constants/commonConst';
25import TrackPlayer from '@/core/trackPlayer';
26import musicHistory from '@/core/musicHistory';
27
28/** app加载前执行
29 * 1. 检查权限
30 * 2. 数据初始化
31 * 3.
32 */
33async function _bootstrap() {
34    // 1. 检查权限
35    const [readStoragePermission, writeStoragePermission] = await Promise.all([
36        check(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE),
37        check(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE),
38    ]);
39    if (
40        !(
41            readStoragePermission === 'granted' &&
42            writeStoragePermission === 'granted'
43        )
44    ) {
45        await request(PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE);
46        await request(PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE);
47    }
48
49    // 2. 数据初始化
50    /** 初始化路径 */
51    await setupFolder();
52    trace('文件夹初始化完成');
53    // 加载配置
54    await Promise.all([
55        Config.setup(),
56        MediaMeta.setup(),
57        MusicSheet.setup(),
58        Network.setup(),
59        musicHistory.setupMusicHistory(),
60    ]);
61    trace('配置初始化完成');
62    // 加载插件
63    try {
64        await RNTrackPlayer.setupPlayer({
65            maxCacheSize:
66                Config.get('setting.basic.maxCacheSize') ?? 1024 * 1024 * 512,
67        });
68    } catch (e: any) {
69        if (
70            e?.message !==
71            'The player has already been initialized via setupPlayer.'
72        ) {
73            throw e;
74        }
75    }
76    await RNTrackPlayer.updateOptions({
77        icon: ImgAsset.logoTransparent,
78        progressUpdateEventInterval: 1,
79        android: {
80            alwaysPauseOnInterruption: true,
81            appKilledPlaybackBehavior:
82                AppKilledPlaybackBehavior.ContinuePlayback,
83        },
84        capabilities: [
85            Capability.Play,
86            Capability.Pause,
87            Capability.SkipToNext,
88            Capability.SkipToPrevious,
89        ],
90        compactCapabilities: [
91            Capability.Play,
92            Capability.Pause,
93            Capability.SkipToNext,
94            Capability.SkipToPrevious,
95        ],
96        notificationCapabilities: [
97            Capability.Play,
98            Capability.Pause,
99            Capability.SkipToNext,
100            Capability.SkipToPrevious,
101        ],
102    });
103    trace('播放器初始化完成');
104    await Cache.setup();
105    trace('缓存初始化完成');
106    await PluginManager.setup();
107    trace('插件初始化完成');
108    await TrackPlayer.setupTrackPlayer();
109    trace('播放列表初始化完成');
110    await LocalMusicSheet.setup();
111    trace('本地音乐初始化完成');
112    Theme.setup();
113    trace('主题初始化完成');
114    await LyricManager.setup();
115
116    extraMakeup();
117    ErrorUtils.setGlobalHandler(error => {
118        errorLog('未捕获的错误', error);
119    });
120}
121
122/** 初始化 */
123async function setupFolder() {
124    await Promise.all([
125        checkAndCreateDir(pathConst.dataPath),
126        checkAndCreateDir(pathConst.logPath),
127        checkAndCreateDir(pathConst.cachePath),
128        checkAndCreateDir(pathConst.pluginPath),
129        checkAndCreateDir(pathConst.lrcCachePath),
130        checkAndCreateDir(pathConst.downloadPath).then(() => {
131            checkAndCreateDir(pathConst.downloadMusicPath);
132        }),
133    ]);
134}
135
136export default async function () {
137    try {
138        await _bootstrap();
139    } catch (e) {
140        errorLog('初始化出错', e);
141    }
142    // 隐藏开屏动画
143    console.log('HIDE');
144    RNBootSplash.hide({fade: true});
145}
146
147/** 不需要阻塞的 */
148async function extraMakeup() {
149    // 自动更新
150    try {
151        if (Config.get('setting.basic.autoUpdatePlugin')) {
152            const lastUpdated =
153                (await getStorage('pluginLastupdatedTime')) || 0;
154            const now = Date.now();
155            if (Math.abs(now - lastUpdated) > 86400000) {
156                setStorage('pluginLastupdatedTime', now);
157                const plugins = PluginManager.getValidPlugins();
158                for (let i = 0; i < plugins.length; ++i) {
159                    const srcUrl = plugins[i].instance.srcUrl;
160                    if (srcUrl) {
161                        await PluginManager.installPluginFromUrl(srcUrl);
162                    }
163                }
164            }
165        }
166    } catch {}
167
168    async function handleLinkingUrl(url: string) {
169        // 插件
170        try {
171            if (url.startsWith('musicfree://install/')) {
172                const plugins = url
173                    .slice(20)
174                    .split(',')
175                    .map(decodeURIComponent);
176                await Promise.all(
177                    plugins.map(it =>
178                        PluginManager.installPluginFromUrl(it).catch(() => {}),
179                    ),
180                );
181                Toast.success('安装成功~');
182            } else if (url.endsWith('.js')) {
183                PluginManager.installPlugin(url, {
184                    notCheckVersion: Config.get(
185                        'setting.basic.notCheckPluginVersion',
186                    ),
187                })
188                    .then(res => {
189                        Toast.success(`插件「${res.name}」安装成功~`);
190                    })
191                    .catch(e => {
192                        console.log(e);
193                        Toast.warn(e?.message ?? '无法识别此插件');
194                    });
195            } else if (supportLocalMediaType.some(it => url.endsWith(it))) {
196                // 本地播放
197                const musicItem = await PluginManager.getByHash(
198                    localPluginHash,
199                )?.instance?.importMusicItem?.(url);
200                console.log(musicItem);
201                if (musicItem) {
202                    TrackPlayer.play(musicItem);
203                }
204            }
205        } catch {}
206    }
207
208    // 开启监听
209    Linking.addEventListener('url', data => {
210        if (data.url) {
211            handleLinkingUrl(data.url);
212        }
213    });
214    const initUrl = await Linking.getInitialURL();
215    if (initUrl) {
216        handleLinkingUrl(initUrl);
217    }
218
219    if (Config.get('setting.basic.autoPlayWhenAppStart')) {
220        TrackPlayer.play();
221    }
222}
223