xref: /MusicFree/src/core/lyricManager.ts (revision 15900d057ad4df766b2f9ea5b48f92a8ce2664db)
1/**
2 * 管理当前歌曲的歌词
3 */
4
5import {isSameMediaItem} from '@/utils/mediaItem';
6import PluginManager from './pluginManager';
7import LyricParser from '@/utils/lrcParser';
8import {GlobalState} from '@/utils/stateMapper';
9import {EDeviceEvents} from '@/constants/commonConst';
10import {DeviceEventEmitter} from 'react-native';
11import Config from './config';
12import LyricUtil from '@/native/lyricUtil';
13import TrackPlayer from './trackPlayer';
14
15const lyricStateStore = new GlobalState<{
16    loading: boolean;
17    lyricParser?: LyricParser;
18    lyrics: ILyric.IParsedLrc;
19    meta?: Record<string, string>;
20}>({
21    loading: true,
22    lyrics: [],
23});
24
25const currentLyricStore = new GlobalState<ILyric.IParsedLrcItem | null>(null);
26
27// 重新获取歌词
28async function refreshLyric(fromStart?: boolean) {
29    const musicItem = TrackPlayer.getCurrentMusic();
30    try {
31        if (!musicItem) {
32            lyricStateStore.setValue({
33                loading: false,
34                lyrics: [],
35            });
36
37            currentLyricStore.setValue({
38                lrc: 'MusicFree',
39                time: 0,
40            });
41
42            return;
43        }
44
45        lyricStateStore.setValue({
46            loading: true,
47            lyrics: [],
48        });
49        currentLyricStore.setValue(null);
50
51        const lrc = await PluginManager.getByMedia(
52            musicItem,
53        )?.methods?.getLyricText(musicItem);
54        const realtimeMusicItem = TrackPlayer.getCurrentMusic();
55        if (isSameMediaItem(musicItem, realtimeMusicItem)) {
56            if (lrc) {
57                const parser = new LyricParser(lrc, musicItem);
58                lyricStateStore.setValue({
59                    loading: false,
60                    lyricParser: parser,
61                    lyrics: parser.getLyric(),
62                    meta: parser.getMeta(),
63                });
64                // 更新当前状态的歌词
65                const currentLyric = fromStart
66                    ? parser.getLyric()[0]
67                    : parser.getPosition(
68                          (await TrackPlayer.getProgress()).position,
69                      ).lrc;
70                currentLyricStore.setValue(currentLyric || null);
71            } else {
72                // 没有歌词
73                lyricStateStore.setValue({
74                    loading: false,
75                    lyrics: [],
76                });
77            }
78        }
79    } catch {
80        const realtimeMusicItem = TrackPlayer.getCurrentMusic();
81        if (isSameMediaItem(musicItem, realtimeMusicItem)) {
82            // 异常情况
83            lyricStateStore.setValue({
84                loading: false,
85                lyrics: [],
86            });
87        }
88    }
89}
90
91// 获取歌词
92async function setup() {
93    DeviceEventEmitter.addListener(EDeviceEvents.REFRESH_LYRIC, refreshLyric);
94
95    if (Config.get('setting.lyric.showStatusBarLyric')) {
96        LyricUtil.showStatusBarLyric(
97            'MusicFree',
98            Config.get('setting.lyric') ?? {},
99        );
100    }
101
102    refreshLyric();
103}
104
105const LyricManager = {
106    setup,
107    useLyricState: lyricStateStore.useValue,
108    getLyricState: lyricStateStore.getValue,
109    useCurrentLyric: currentLyricStore.useValue,
110    getCurrentLyric: currentLyricStore.getValue,
111    setCurrentLyric: currentLyricStore.setValue,
112};
113
114export default LyricManager;
115