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'; 14import MediaExtra from './mediaExtra'; 15 16const lyricStateStore = new GlobalState<{ 17 loading: boolean; 18 lyricParser?: LyricParser; 19 lyrics: ILyric.IParsedLrc; 20 meta?: Record<string, string>; 21}>({ 22 loading: true, 23 lyrics: [], 24}); 25 26const currentLyricStore = new GlobalState<ILyric.IParsedLrcItem | null>(null); 27 28// 重新获取歌词 29async function refreshLyric(fromStart?: boolean, forceRequest = false) { 30 const musicItem = TrackPlayer.getCurrentMusic(); 31 try { 32 if (!musicItem) { 33 lyricStateStore.setValue({ 34 loading: false, 35 lyrics: [], 36 }); 37 38 currentLyricStore.setValue({ 39 lrc: 'MusicFree', 40 time: 0, 41 }); 42 43 return; 44 } 45 46 const currentParserMusicItem = lyricStateStore 47 .getValue() 48 ?.lyricParser?.getCurrentMusicItem(); 49 50 let rawLrc: string | undefined; 51 if ( 52 forceRequest || 53 !isSameMediaItem(currentParserMusicItem, musicItem) 54 ) { 55 lyricStateStore.setValue({ 56 loading: true, 57 lyrics: [], 58 }); 59 currentLyricStore.setValue(null); 60 61 rawLrc = await PluginManager.getByMedia( 62 musicItem, 63 )?.methods?.getLyricText(musicItem); 64 } else { 65 rawLrc = lyricStateStore.getValue().lyricParser!.raw; 66 } 67 68 const realtimeMusicItem = TrackPlayer.getCurrentMusic(); 69 if (isSameMediaItem(musicItem, realtimeMusicItem)) { 70 if (rawLrc) { 71 const mediaExtra = MediaExtra.get(musicItem); 72 const parser = new LyricParser(rawLrc, musicItem, { 73 offset: (mediaExtra?.lyricOffset || 0) * -1, 74 }); 75 lyricStateStore.setValue({ 76 loading: false, 77 lyricParser: parser, 78 lyrics: parser.getLyric(), 79 meta: parser.getMeta(), 80 }); 81 // 更新当前状态的歌词 82 const currentLyric = fromStart 83 ? parser.getLyric()[0] 84 : parser.getPosition( 85 (await TrackPlayer.getProgress()).position, 86 ).lrc; 87 currentLyricStore.setValue(currentLyric || null); 88 } else { 89 // 没有歌词 90 lyricStateStore.setValue({ 91 loading: false, 92 lyrics: [], 93 }); 94 } 95 } 96 } catch { 97 const realtimeMusicItem = TrackPlayer.getCurrentMusic(); 98 if (isSameMediaItem(musicItem, realtimeMusicItem)) { 99 // 异常情况 100 lyricStateStore.setValue({ 101 loading: false, 102 lyrics: [], 103 }); 104 } 105 } 106} 107 108// 获取歌词 109async function setup() { 110 DeviceEventEmitter.addListener(EDeviceEvents.REFRESH_LYRIC, refreshLyric); 111 112 if (Config.get('setting.lyric.showStatusBarLyric')) { 113 LyricUtil.showStatusBarLyric( 114 'MusicFree', 115 Config.get('setting.lyric') ?? {}, 116 ); 117 } 118 119 refreshLyric(); 120} 121 122const LyricManager = { 123 setup, 124 useLyricState: lyricStateStore.useValue, 125 getLyricState: lyricStateStore.getValue, 126 useCurrentLyric: currentLyricStore.useValue, 127 getCurrentLyric: currentLyricStore.getValue, 128 setCurrentLyric: currentLyricStore.setValue, 129 refreshLyric, 130}; 131 132export default LyricManager; 133