163c74e8eSmaotoumaoimport { produce } from "immer"; 25500cea7S猫头猫import ReactNativeTrackPlayer, { 35500cea7S猫头猫 Event, 45500cea7S猫头猫 State, 55500cea7S猫头猫 Track, 65500cea7S猫头猫 TrackMetadataBase, 75500cea7S猫头猫 usePlaybackState, 863c74e8eSmaotoumao useProgress 963c74e8eSmaotoumao} from "react-native-track-player"; 1063c74e8eSmaotoumaoimport shuffle from "lodash.shuffle"; 1141ddce91Smaotoumaoimport Config from "../config.ts"; 1263c74e8eSmaotoumaoimport { EDeviceEvents, internalFakeSoundKey, sortIndexSymbol, timeStampSymbol } from "@/constants/commonConst"; 1363c74e8eSmaotoumaoimport { GlobalState } from "@/utils/stateMapper"; 1463c74e8eSmaotoumaoimport delay from "@/utils/delay"; 15*c341583dSmaotoumaoimport { 16*c341583dSmaotoumao getInternalData, 17*c341583dSmaotoumao InternalDataType, 18*c341583dSmaotoumao isSameMediaItem, 19*c341583dSmaotoumao mergeProps, 20*c341583dSmaotoumao sortByTimestampAndIndex 21*c341583dSmaotoumao} from "@/utils/mediaItem"; 2263c74e8eSmaotoumaoimport Network from "../network"; 2363c74e8eSmaotoumaoimport LocalMusicSheet from "../localMusicSheet"; 2463c74e8eSmaotoumaoimport { SoundAsset } from "@/constants/assetsConst"; 2563c74e8eSmaotoumaoimport { getQualityOrder } from "@/utils/qualities"; 2663c74e8eSmaotoumaoimport musicHistory from "../musicHistory"; 2763c74e8eSmaotoumaoimport getUrlExt from "@/utils/getUrlExt"; 2863c74e8eSmaotoumaoimport { DeviceEventEmitter } from "react-native"; 2963c74e8eSmaotoumaoimport LyricManager from "../lyricManager"; 3063c74e8eSmaotoumaoimport { MusicRepeatMode } from "./common"; 315500cea7S猫头猫import { 325500cea7S猫头猫 getMusicIndex, 335500cea7S猫头猫 getPlayList, 345500cea7S猫头猫 getPlayListMusicAt, 355500cea7S猫头猫 isInPlayList, 365500cea7S猫头猫 isPlayListEmpty, 375500cea7S猫头猫 setPlayList, 3863c74e8eSmaotoumao usePlayList 3963c74e8eSmaotoumao} from "./internal/playList"; 4063c74e8eSmaotoumaoimport { createMediaIndexMap } from "@/utils/mediaIndexMap"; 4163c74e8eSmaotoumaoimport PluginManager from "../pluginManager"; 4263c74e8eSmaotoumaoimport { musicIsPaused } from "@/utils/trackUtils"; 4363c74e8eSmaotoumaoimport { errorLog, trace } from "@/utils/log"; 44819a9075Smaotoumaoimport PersistStatus from "../persistStatus.ts"; 4563c74e8eSmaotoumaoimport { getCurrentDialog, showDialog } from "@/components/dialogs/useDialog"; 4663c74e8eSmaotoumaoimport getSimilarMusic from "@/utils/getSimilarMusic"; 47*c341583dSmaotoumaoimport MediaExtra from "@/core/mediaExtra.ts"; 485500cea7S猫头猫 495500cea7S猫头猫/** 当前播放 */ 505500cea7S猫头猫const currentMusicStore = new GlobalState<IMusic.IMusicItem | null>(null); 515500cea7S猫头猫 525500cea7S猫头猫/** 播放模式 */ 535500cea7S猫头猫const repeatModeStore = new GlobalState<MusicRepeatMode>(MusicRepeatMode.QUEUE); 545500cea7S猫头猫 555500cea7S猫头猫/** 音质 */ 565500cea7S猫头猫const qualityStore = new GlobalState<IMusic.IQualityKey>('standard'); 575500cea7S猫头猫 585500cea7S猫头猫let currentIndex = -1; 595500cea7S猫头猫 604c222b69S猫头猫const maxMusicQueueLength = 10000; // 当前播放最大限制 615500cea7S猫头猫const halfMaxMusicQueueLength = Math.floor(maxMusicQueueLength / 2); 625500cea7S猫头猫const shrinkPlayListToSize = ( 635500cea7S猫头猫 queue: IMusic.IMusicItem[], 645500cea7S猫头猫 targetIndex = currentIndex, 655500cea7S猫头猫) => { 665500cea7S猫头猫 // 播放列表上限,太多无法缓存状态 675500cea7S猫头猫 if (queue.length > maxMusicQueueLength) { 685500cea7S猫头猫 if (targetIndex < halfMaxMusicQueueLength) { 695500cea7S猫头猫 queue = queue.slice(0, maxMusicQueueLength); 705500cea7S猫头猫 } else { 715500cea7S猫头猫 const right = Math.min( 725500cea7S猫头猫 queue.length, 735500cea7S猫头猫 targetIndex + halfMaxMusicQueueLength, 745500cea7S猫头猫 ); 755500cea7S猫头猫 const left = Math.max(0, right - maxMusicQueueLength); 765500cea7S猫头猫 queue = queue.slice(left, right); 775500cea7S猫头猫 } 785500cea7S猫头猫 } 795500cea7S猫头猫 return queue; 805500cea7S猫头猫}; 815500cea7S猫头猫 827aed04d4S猫头猫let hasSetupListener = false; 837aed04d4S猫头猫 846e000b99S猫头猫async function setupTrackPlayer() { 85819a9075Smaotoumao const rate = PersistStatus.get('music.rate'); 86819a9075Smaotoumao const musicQueue = PersistStatus.get('music.playList'); 87819a9075Smaotoumao const repeatMode = PersistStatus.get('music.repeatMode'); 88819a9075Smaotoumao const progress = PersistStatus.get('music.progress'); 89819a9075Smaotoumao const track = PersistStatus.get('music.musicItem'); 906e000b99S猫头猫 const quality = 91819a9075Smaotoumao PersistStatus.get('music.quality') || 9241ddce91Smaotoumao Config.getConfig('basic.defaultPlayQuality') || 936e000b99S猫头猫 'standard'; 945500cea7S猫头猫 955500cea7S猫头猫 // 状态恢复 965500cea7S猫头猫 if (rate) { 9791eb8fa8S猫头猫 ReactNativeTrackPlayer.setRate(+rate / 100); 985500cea7S猫头猫 } 99e476f1a0S猫头猫 if (repeatMode) { 100e476f1a0S猫头猫 repeatModeStore.setValue(repeatMode as MusicRepeatMode); 101e476f1a0S猫头猫 } 1025500cea7S猫头猫 1035500cea7S猫头猫 if (musicQueue && Array.isArray(musicQueue)) { 1045500cea7S猫头猫 addAll(musicQueue, undefined, repeatMode === MusicRepeatMode.SHUFFLE); 1055500cea7S猫头猫 } 1065500cea7S猫头猫 1075500cea7S猫头猫 if (track && isInPlayList(track)) { 10841ddce91Smaotoumao if (!Config.getConfig('basic.autoPlayWhenAppStart')) { 1098b9904b3S猫头猫 track.isInit = true; 1108b9904b3S猫头猫 } 1110dd58d38S猫头猫 11291eb8fa8S猫头猫 // 异步 11391eb8fa8S猫头猫 PluginManager.getByMedia(track) 11491eb8fa8S猫头猫 ?.methods.getMediaSource(track, quality, 0) 11591eb8fa8S猫头猫 .then(async newSource => { 11691eb8fa8S猫头猫 track.url = newSource?.url || track.url; 11791eb8fa8S猫头猫 track.headers = newSource?.headers || track.headers; 11891eb8fa8S猫头猫 11991eb8fa8S猫头猫 if (isSameMediaItem(currentMusicStore.getValue(), track)) { 1205500cea7S猫头猫 await setTrackSource(track as Track, false); 12191eb8fa8S猫头猫 } 12291eb8fa8S猫头猫 }); 1235500cea7S猫头猫 setCurrentMusic(track); 1245500cea7S猫头猫 1256e000b99S猫头猫 if (progress) { 12691eb8fa8S猫头猫 // 异步 12791eb8fa8S猫头猫 ReactNativeTrackPlayer.seekTo(progress); 1285500cea7S猫头猫 } 1295500cea7S猫头猫 } 1305500cea7S猫头猫 1317aed04d4S猫头猫 if (!hasSetupListener) { 1325500cea7S猫头猫 ReactNativeTrackPlayer.addEventListener( 1335500cea7S猫头猫 Event.PlaybackActiveTrackChanged, 1345500cea7S猫头猫 async evt => { 1355500cea7S猫头猫 if ( 1365500cea7S猫头猫 evt.index === 1 && 1375500cea7S猫头猫 evt.lastIndex === 0 && 1385500cea7S猫头猫 evt.track?.$ === internalFakeSoundKey 1395500cea7S猫头猫 ) { 14062e73a5eS猫头猫 trace('队列末尾,播放下一首'); 1415500cea7S猫头猫 if (repeatModeStore.getValue() === MusicRepeatMode.SINGLE) { 1425500cea7S猫头猫 await play(null, true); 1435500cea7S猫头猫 } else { 1445500cea7S猫头猫 // 当前生效的歌曲是下一曲的标记 1456f57784cS猫头猫 await skipToNext(); 1465500cea7S猫头猫 } 1475500cea7S猫头猫 } 1485500cea7S猫头猫 }, 1495500cea7S猫头猫 ); 1505500cea7S猫头猫 1517aed04d4S猫头猫 ReactNativeTrackPlayer.addEventListener( 1527aed04d4S猫头猫 Event.PlaybackError, 15362e73a5eS猫头猫 async e => { 15417958235S猫头猫 errorLog('播放出错', e.message); 15562e73a5eS猫头猫 // WARNING: 不稳定,报错的时候有可能track已经变到下一首歌去了 1568b9904b3S猫头猫 const currentTrack = 1578b9904b3S猫头猫 await ReactNativeTrackPlayer.getActiveTrack(); 1588b9904b3S猫头猫 if (currentTrack?.isInit) { 1598b9904b3S猫头猫 // HACK: 避免初始失败的情况 1608b9904b3S猫头猫 ReactNativeTrackPlayer.updateMetadataForTrack(0, { 1618b9904b3S猫头猫 ...currentTrack, 1628b9904b3S猫头猫 // @ts-ignore 1638b9904b3S猫头猫 isInit: undefined, 1648b9904b3S猫头猫 }); 1658b9904b3S猫头猫 return; 1668b9904b3S猫头猫 } 1678b9904b3S猫头猫 1687aed04d4S猫头猫 if ( 16962e73a5eS猫头猫 (await ReactNativeTrackPlayer.getActiveTrackIndex()) === 17062e73a5eS猫头猫 0 && 17162e73a5eS猫头猫 e.message && 17262e73a5eS猫头猫 e.message !== 'android-io-file-not-found' 1737aed04d4S猫头猫 ) { 17462e73a5eS猫头猫 trace('播放出错', { 17562e73a5eS猫头猫 message: e.message, 17662e73a5eS猫头猫 code: e.code, 17762e73a5eS猫头猫 }); 1788b9904b3S猫头猫 1795500cea7S猫头猫 failToPlay(); 1805500cea7S猫头猫 } 1817aed04d4S猫头猫 }, 1827aed04d4S猫头猫 ); 1837aed04d4S猫头猫 1847aed04d4S猫头猫 hasSetupListener = true; 1857aed04d4S猫头猫 } 1865500cea7S猫头猫} 1875500cea7S猫头猫 1885500cea7S猫头猫/** 1895500cea7S猫头猫 * 获取自动播放的下一个track 1905500cea7S猫头猫 */ 1915500cea7S猫头猫const getFakeNextTrack = () => { 1925500cea7S猫头猫 let track: Track | undefined; 1935500cea7S猫头猫 const repeatMode = repeatModeStore.getValue(); 1945500cea7S猫头猫 if (repeatMode === MusicRepeatMode.SINGLE) { 1955500cea7S猫头猫 // 单曲循环 1965500cea7S猫头猫 track = getPlayListMusicAt(currentIndex) as Track; 1975500cea7S猫头猫 } else { 1985500cea7S猫头猫 // 下一曲 1995500cea7S猫头猫 track = getPlayListMusicAt(currentIndex + 1) as Track; 2005500cea7S猫头猫 } 2015500cea7S猫头猫 2025500cea7S猫头猫 if (track) { 2035500cea7S猫头猫 return produce(track, _ => { 2045500cea7S猫头猫 _.url = SoundAsset.fakeAudio; 2055500cea7S猫头猫 _.$ = internalFakeSoundKey; 206cc77e86bS猫头猫 if (!_.artwork?.trim()?.length) { 207cc77e86bS猫头猫 _.artwork = undefined; 208cc77e86bS猫头猫 } 2095500cea7S猫头猫 }); 2105500cea7S猫头猫 } else { 2115500cea7S猫头猫 // 只有列表长度为0时才会出现的特殊情况 2125500cea7S猫头猫 return {url: SoundAsset.fakeAudio, $: internalFakeSoundKey} as Track; 2135500cea7S猫头猫 } 2145500cea7S猫头猫}; 2155500cea7S猫头猫 2165500cea7S猫头猫/** 播放失败时的情况 */ 2176f57784cS猫头猫async function failToPlay() { 2185500cea7S猫头猫 // 如果自动跳转下一曲, 500s后自动跳转 21941ddce91Smaotoumao if (!Config.getConfig('basic.autoStopWhenError')) { 2205500cea7S猫头猫 await ReactNativeTrackPlayer.reset(); 2215500cea7S猫头猫 await delay(500); 2226f57784cS猫头猫 await skipToNext(); 2235500cea7S猫头猫 } 2245500cea7S猫头猫} 2255500cea7S猫头猫 2265500cea7S猫头猫// 播放模式相关 2275500cea7S猫头猫const _toggleRepeatMapping = { 2285500cea7S猫头猫 [MusicRepeatMode.SHUFFLE]: MusicRepeatMode.SINGLE, 2295500cea7S猫头猫 [MusicRepeatMode.SINGLE]: MusicRepeatMode.QUEUE, 2305500cea7S猫头猫 [MusicRepeatMode.QUEUE]: MusicRepeatMode.SHUFFLE, 2315500cea7S猫头猫}; 2325500cea7S猫头猫/** 切换下一个模式 */ 2335500cea7S猫头猫const toggleRepeatMode = () => { 2345500cea7S猫头猫 setRepeatMode(_toggleRepeatMapping[repeatModeStore.getValue()]); 2355500cea7S猫头猫}; 2365500cea7S猫头猫 2375500cea7S猫头猫/** 2385500cea7S猫头猫 * 添加到播放列表 2395500cea7S猫头猫 * @param musicItems 目标歌曲 2405500cea7S猫头猫 * @param beforeIndex 在第x首歌曲前添加 2415500cea7S猫头猫 * @param shouldShuffle 随机排序 2425500cea7S猫头猫 */ 2435500cea7S猫头猫const addAll = ( 2445500cea7S猫头猫 musicItems: Array<IMusic.IMusicItem> = [], 2455500cea7S猫头猫 beforeIndex?: number, 2465500cea7S猫头猫 shouldShuffle?: boolean, 2475500cea7S猫头猫) => { 2485500cea7S猫头猫 const now = Date.now(); 2495500cea7S猫头猫 let newPlayList: IMusic.IMusicItem[] = []; 2505500cea7S猫头猫 let currentPlayList = getPlayList(); 2514c222b69S猫头猫 musicItems.forEach((item, index) => { 2524c222b69S猫头猫 item[timeStampSymbol] = now; 2534c222b69S猫头猫 item[sortIndexSymbol] = index; 2544c222b69S猫头猫 }); 2554c222b69S猫头猫 2565500cea7S猫头猫 if (beforeIndex === undefined || beforeIndex < 0) { 2575500cea7S猫头猫 // 1.1. 添加到歌单末尾,并过滤掉已有的歌曲 2585500cea7S猫头猫 newPlayList = currentPlayList.concat( 2594c222b69S猫头猫 musicItems.filter(item => !isInPlayList(item)), 2605500cea7S猫头猫 ); 2615500cea7S猫头猫 } else { 2625500cea7S猫头猫 // 1.2. 新的播放列表,插入 2634c222b69S猫头猫 const indexMap = createMediaIndexMap(musicItems); 2645500cea7S猫头猫 const beforeDraft = currentPlayList 2655500cea7S猫头猫 .slice(0, beforeIndex) 2665500cea7S猫头猫 .filter(item => !indexMap.has(item)); 2675500cea7S猫头猫 const afterDraft = currentPlayList 2685500cea7S猫头猫 .slice(beforeIndex) 2695500cea7S猫头猫 .filter(item => !indexMap.has(item)); 2705500cea7S猫头猫 2714c222b69S猫头猫 newPlayList = [...beforeDraft, ...musicItems, ...afterDraft]; 2725500cea7S猫头猫 } 27315900d05S猫头猫 2745500cea7S猫头猫 // 如果太长了 2755500cea7S猫头猫 if (newPlayList.length > maxMusicQueueLength) { 2765500cea7S猫头猫 newPlayList = shrinkPlayListToSize( 2775500cea7S猫头猫 newPlayList, 2785500cea7S猫头猫 beforeIndex ?? newPlayList.length - 1, 2795500cea7S猫头猫 ); 2805500cea7S猫头猫 } 2815500cea7S猫头猫 2825500cea7S猫头猫 // 2. 如果需要随机 2835500cea7S猫头猫 if (shouldShuffle) { 2845500cea7S猫头猫 newPlayList = shuffle(newPlayList); 2855500cea7S猫头猫 } 2865500cea7S猫头猫 // 3. 设置播放列表 2875500cea7S猫头猫 setPlayList(newPlayList); 2885500cea7S猫头猫 const currentMusicItem = currentMusicStore.getValue(); 2895500cea7S猫头猫 2905500cea7S猫头猫 // 4. 重置下标 2915500cea7S猫头猫 if (currentMusicItem) { 2925500cea7S猫头猫 currentIndex = getMusicIndex(currentMusicItem); 2935500cea7S猫头猫 } 2945500cea7S猫头猫}; 2955500cea7S猫头猫 2965500cea7S猫头猫/** 追加到队尾 */ 2975500cea7S猫头猫const add = ( 2985500cea7S猫头猫 musicItem: IMusic.IMusicItem | IMusic.IMusicItem[], 2995500cea7S猫头猫 beforeIndex?: number, 3005500cea7S猫头猫) => { 3015500cea7S猫头猫 addAll(Array.isArray(musicItem) ? musicItem : [musicItem], beforeIndex); 3025500cea7S猫头猫}; 3035500cea7S猫头猫 3045500cea7S猫头猫/** 3055500cea7S猫头猫 * 下一首播放 3065500cea7S猫头猫 * @param musicItem 3075500cea7S猫头猫 */ 3085500cea7S猫头猫const addNext = (musicItem: IMusic.IMusicItem | IMusic.IMusicItem[]) => { 3095500cea7S猫头猫 const shouldPlay = isPlayListEmpty(); 3105500cea7S猫头猫 add(musicItem, currentIndex + 1); 3115500cea7S猫头猫 if (shouldPlay) { 3125500cea7S猫头猫 play(Array.isArray(musicItem) ? musicItem[0] : musicItem); 3135500cea7S猫头猫 } 3145500cea7S猫头猫}; 3155500cea7S猫头猫 3163991724eS猫头猫const isCurrentMusic = (musicItem: IMusic.IMusicItem | null | undefined) => { 3175500cea7S猫头猫 return isSameMediaItem(musicItem, currentMusicStore.getValue()) ?? false; 3185500cea7S猫头猫}; 3195500cea7S猫头猫 3205500cea7S猫头猫const remove = async (musicItem: IMusic.IMusicItem) => { 3215500cea7S猫头猫 const playList = getPlayList(); 3225500cea7S猫头猫 let newPlayList: IMusic.IMusicItem[] = []; 3235500cea7S猫头猫 let currentMusic: IMusic.IMusicItem | null = currentMusicStore.getValue(); 3245500cea7S猫头猫 const targetIndex = getMusicIndex(musicItem); 3255500cea7S猫头猫 let shouldPlayCurrent: boolean | null = null; 3265500cea7S猫头猫 if (targetIndex === -1) { 3275500cea7S猫头猫 // 1. 这种情况应该是出错了 3285500cea7S猫头猫 return; 3295500cea7S猫头猫 } 3305500cea7S猫头猫 // 2. 移除的是当前项 3315500cea7S猫头猫 if (currentIndex === targetIndex) { 3325500cea7S猫头猫 // 2.1 停止播放,移除当前项 3335500cea7S猫头猫 newPlayList = produce(playList, draft => { 3345500cea7S猫头猫 draft.splice(targetIndex, 1); 3355500cea7S猫头猫 }); 3365500cea7S猫头猫 // 2.2 设置新的播放列表,并更新当前音乐 3375500cea7S猫头猫 if (newPlayList.length === 0) { 3385500cea7S猫头猫 currentMusic = null; 3395500cea7S猫头猫 shouldPlayCurrent = false; 3405500cea7S猫头猫 } else { 3415500cea7S猫头猫 currentMusic = newPlayList[currentIndex % newPlayList.length]; 3425500cea7S猫头猫 try { 3435500cea7S猫头猫 const state = (await ReactNativeTrackPlayer.getPlaybackState()) 3445500cea7S猫头猫 .state; 3456f73e807S猫头猫 shouldPlayCurrent = !musicIsPaused(state); 3465500cea7S猫头猫 } catch { 3475500cea7S猫头猫 shouldPlayCurrent = false; 3485500cea7S猫头猫 } 3495500cea7S猫头猫 } 3505500cea7S猫头猫 } else { 3515500cea7S猫头猫 // 3. 删除 3525500cea7S猫头猫 newPlayList = produce(playList, draft => { 3535500cea7S猫头猫 draft.splice(targetIndex, 1); 3545500cea7S猫头猫 }); 3555500cea7S猫头猫 } 3565500cea7S猫头猫 3575500cea7S猫头猫 setPlayList(newPlayList); 3585500cea7S猫头猫 setCurrentMusic(currentMusic); 3595500cea7S猫头猫 if (shouldPlayCurrent === true) { 3605500cea7S猫头猫 await play(currentMusic, true); 3615500cea7S猫头猫 } else if (shouldPlayCurrent === false) { 3625500cea7S猫头猫 await ReactNativeTrackPlayer.reset(); 3635500cea7S猫头猫 } 3645500cea7S猫头猫}; 3655500cea7S猫头猫 3665500cea7S猫头猫/** 3675500cea7S猫头猫 * 设置播放模式 3685500cea7S猫头猫 * @param mode 播放模式 3695500cea7S猫头猫 */ 3705500cea7S猫头猫const setRepeatMode = (mode: MusicRepeatMode) => { 3715500cea7S猫头猫 const playList = getPlayList(); 3725500cea7S猫头猫 let newPlayList; 37391eb8fa8S猫头猫 const prevMode = repeatModeStore.getValue(); 37491eb8fa8S猫头猫 if ( 37591eb8fa8S猫头猫 (prevMode === MusicRepeatMode.SHUFFLE && 37691eb8fa8S猫头猫 mode !== MusicRepeatMode.SHUFFLE) || 37791eb8fa8S猫头猫 (mode === MusicRepeatMode.SHUFFLE && 37891eb8fa8S猫头猫 prevMode !== MusicRepeatMode.SHUFFLE) 37991eb8fa8S猫头猫 ) { 3805500cea7S猫头猫 if (mode === MusicRepeatMode.SHUFFLE) { 3815500cea7S猫头猫 newPlayList = shuffle(playList); 3825500cea7S猫头猫 } else { 38391eb8fa8S猫头猫 newPlayList = sortByTimestampAndIndex(playList, true); 38491eb8fa8S猫头猫 } 38591eb8fa8S猫头猫 setPlayList(newPlayList); 3865500cea7S猫头猫 } 3875500cea7S猫头猫 3885500cea7S猫头猫 const currentMusicItem = currentMusicStore.getValue(); 3895500cea7S猫头猫 currentIndex = getMusicIndex(currentMusicItem); 3905500cea7S猫头猫 repeatModeStore.setValue(mode); 3915500cea7S猫头猫 // 更新下一首歌的信息 3925500cea7S猫头猫 ReactNativeTrackPlayer.updateMetadataForTrack(1, getFakeNextTrack()); 3935500cea7S猫头猫 // 记录 394819a9075Smaotoumao PersistStatus.set('music.repeatMode', mode); 3955500cea7S猫头猫}; 3965500cea7S猫头猫 3975500cea7S猫头猫/** 清空播放列表 */ 3985500cea7S猫头猫const clear = async () => { 3995500cea7S猫头猫 setPlayList([]); 4005500cea7S猫头猫 setCurrentMusic(null); 4015500cea7S猫头猫 4025500cea7S猫头猫 await ReactNativeTrackPlayer.reset(); 403819a9075Smaotoumao PersistStatus.set('music.musicItem', undefined); 404819a9075Smaotoumao PersistStatus.set('music.progress', 0); 4055500cea7S猫头猫}; 4065500cea7S猫头猫 4075500cea7S猫头猫/** 暂停 */ 4085500cea7S猫头猫const pause = async () => { 4095500cea7S猫头猫 await ReactNativeTrackPlayer.pause(); 4105500cea7S猫头猫}; 4115500cea7S猫头猫 4128b9904b3S猫头猫/** 设置音源 */ 4138b9904b3S猫头猫const setTrackSource = async (track: Track, autoPlay = true) => { 41411908939S猫头猫 if (!track.artwork?.trim()?.length) { 41511908939S猫头猫 track.artwork = undefined; 41611908939S猫头猫 } 4178b9904b3S猫头猫 await ReactNativeTrackPlayer.setQueue([track, getFakeNextTrack()]); 418819a9075Smaotoumao PersistStatus.set('music.musicItem', track as IMusic.IMusicItem); 419819a9075Smaotoumao PersistStatus.set('music.progress', 0); 4208b9904b3S猫头猫 if (autoPlay) { 4218b9904b3S猫头猫 await ReactNativeTrackPlayer.play(); 4228b9904b3S猫头猫 } 4238b9904b3S猫头猫}; 4248b9904b3S猫头猫 4255500cea7S猫头猫const setCurrentMusic = (musicItem?: IMusic.IMusicItem | null) => { 4265500cea7S猫头猫 if (!musicItem) { 4275500cea7S猫头猫 currentIndex = -1; 428f511aee9S猫头猫 currentMusicStore.setValue(null); 429819a9075Smaotoumao PersistStatus.set('music.musicItem', undefined); 430819a9075Smaotoumao PersistStatus.set('music.progress', 0); 4316e000b99S猫头猫 return; 4325500cea7S猫头猫 } 4335500cea7S猫头猫 currentIndex = getMusicIndex(musicItem); 4346e000b99S猫头猫 currentMusicStore.setValue(musicItem); 4355500cea7S猫头猫}; 4365500cea7S猫头猫 4376e000b99S猫头猫const setQuality = (quality: IMusic.IQualityKey) => { 4386e000b99S猫头猫 qualityStore.setValue(quality); 439819a9075Smaotoumao PersistStatus.set('music.quality', quality); 4406e000b99S猫头猫}; 4415500cea7S猫头猫/** 4425500cea7S猫头猫 * 播放 4435500cea7S猫头猫 * 4445500cea7S猫头猫 * 当musicItem 为空时,代表暂停/播放 4455500cea7S猫头猫 * 4465500cea7S猫头猫 * @param musicItem 4475500cea7S猫头猫 * @param forcePlay 4485500cea7S猫头猫 * @returns 4495500cea7S猫头猫 */ 4505500cea7S猫头猫const play = async ( 4515500cea7S猫头猫 musicItem?: IMusic.IMusicItem | null, 4525500cea7S猫头猫 forcePlay?: boolean, 4535500cea7S猫头猫) => { 4545500cea7S猫头猫 try { 4555500cea7S猫头猫 if (!musicItem) { 4565500cea7S猫头猫 musicItem = currentMusicStore.getValue(); 4575500cea7S猫头猫 } 4585500cea7S猫头猫 if (!musicItem) { 4595500cea7S猫头猫 throw new Error(PlayFailReason.PLAY_LIST_IS_EMPTY); 4605500cea7S猫头猫 } 4615500cea7S猫头猫 // 1. 移动网络禁止播放 462*c341583dSmaotoumao const mediaExtra = MediaExtra.get(musicItem); 463*c341583dSmaotoumao // TODO: 优化本地音乐的逻辑 464*c341583dSmaotoumao const localPath = 465*c341583dSmaotoumao mediaExtra?.localPath || 466*c341583dSmaotoumao getInternalData<string>(musicItem, InternalDataType.LOCALPATH) 4675500cea7S猫头猫 if ( 4685500cea7S猫头猫 Network.isCellular() && 46941ddce91Smaotoumao !Config.getConfig('basic.useCelluarNetworkPlay') && 470*c341583dSmaotoumao !LocalMusicSheet.isLocalMusic(musicItem) && 471*c341583dSmaotoumao !localPath 4725500cea7S猫头猫 ) { 4735500cea7S猫头猫 await ReactNativeTrackPlayer.reset(); 4745500cea7S猫头猫 throw new Error(PlayFailReason.FORBID_CELLUAR_NETWORK_PLAY); 4755500cea7S猫头猫 } 4765500cea7S猫头猫 4775500cea7S猫头猫 // 2. 如果是当前正在播放的音频 4785500cea7S猫头猫 if (isCurrentMusic(musicItem)) { 4795500cea7S猫头猫 const currentTrack = await ReactNativeTrackPlayer.getTrack(0); 4805500cea7S猫头猫 // 2.1 如果当前有源 4815500cea7S猫头猫 if ( 4825500cea7S猫头猫 currentTrack?.url && 4835500cea7S猫头猫 isSameMediaItem(musicItem, currentTrack as IMusic.IMusicItem) 4845500cea7S猫头猫 ) { 4855500cea7S猫头猫 const currentActiveIndex = 4865500cea7S猫头猫 await ReactNativeTrackPlayer.getActiveTrackIndex(); 4875500cea7S猫头猫 if (currentActiveIndex !== 0) { 4885500cea7S猫头猫 await ReactNativeTrackPlayer.skip(0); 4895500cea7S猫头猫 } 4905500cea7S猫头猫 if (forcePlay) { 4915500cea7S猫头猫 // 2.1.1 强制重新开始 4925500cea7S猫头猫 await ReactNativeTrackPlayer.seekTo(0); 4936f57784cS猫头猫 } 49466e1d5fcS猫头猫 const currentState = ( 49566e1d5fcS猫头猫 await ReactNativeTrackPlayer.getPlaybackState() 49666e1d5fcS猫头猫 ).state; 49766e1d5fcS猫头猫 if (currentState === State.Stopped) { 49866e1d5fcS猫头猫 await setTrackSource(currentTrack); 49966e1d5fcS猫头猫 } 50066e1d5fcS猫头猫 if (currentState !== State.Playing) { 5015500cea7S猫头猫 // 2.1.2 恢复播放 5025500cea7S猫头猫 await ReactNativeTrackPlayer.play(); 5035500cea7S猫头猫 } 5045500cea7S猫头猫 // 这种情况下,播放队列和当前歌曲都不需要变化 5055500cea7S猫头猫 return; 5065500cea7S猫头猫 } 5075500cea7S猫头猫 // 2.2 其他情况:重新获取源 5085500cea7S猫头猫 } 5095500cea7S猫头猫 5105500cea7S猫头猫 // 3. 如果没有在播放列表中,添加到队尾;同时更新列表状态 5115500cea7S猫头猫 const inPlayList = isInPlayList(musicItem); 5125500cea7S猫头猫 if (!inPlayList) { 5135500cea7S猫头猫 add(musicItem); 5145500cea7S猫头猫 } 5155500cea7S猫头猫 5165500cea7S猫头猫 // 4. 更新列表状态和当前音乐 5175500cea7S猫头猫 setCurrentMusic(musicItem); 5189cfce1b6S猫头猫 await ReactNativeTrackPlayer.reset(); 5199cfce1b6S猫头猫 5209cfce1b6S猫头猫 // 4.1 刷新歌词信息 5219cfce1b6S猫头猫 if ( 5229cfce1b6S猫头猫 !isSameMediaItem( 52348036ddaS猫头猫 LyricManager.getLyricState()?.lyricParser?.musicItem, 5249cfce1b6S猫头猫 musicItem, 5259cfce1b6S猫头猫 ) 5269cfce1b6S猫头猫 ) { 5279cfce1b6S猫头猫 DeviceEventEmitter.emit(EDeviceEvents.REFRESH_LYRIC, true); 5289cfce1b6S猫头猫 } 5295500cea7S猫头猫 5305500cea7S猫头猫 // 5. 获取音源 5315500cea7S猫头猫 let track: IMusic.IMusicItem; 5325500cea7S猫头猫 5335500cea7S猫头猫 // 5.1 通过插件获取音源 5345500cea7S猫头猫 const plugin = PluginManager.getByName(musicItem.platform); 5355500cea7S猫头猫 // 5.2 获取音质排序 5365500cea7S猫头猫 const qualityOrder = getQualityOrder( 53741ddce91Smaotoumao Config.getConfig('basic.defaultPlayQuality') ?? 'standard', 53841ddce91Smaotoumao Config.getConfig('basic.playQualityOrder') ?? 'asc', 5395500cea7S猫头猫 ); 5405500cea7S猫头猫 // 5.3 插件返回音源 5415500cea7S猫头猫 let source: IPlugin.IMediaSourceResult | null = null; 5425500cea7S猫头猫 for (let quality of qualityOrder) { 5435500cea7S猫头猫 if (isCurrentMusic(musicItem)) { 5445500cea7S猫头猫 source = 5455500cea7S猫头猫 (await plugin?.methods?.getMediaSource( 5465500cea7S猫头猫 musicItem, 5475500cea7S猫头猫 quality, 5485500cea7S猫头猫 )) ?? null; 5495500cea7S猫头猫 // 5.3.1 获取到真实源 5505500cea7S猫头猫 if (source) { 5516e000b99S猫头猫 setQuality(quality); 5525500cea7S猫头猫 break; 5535500cea7S猫头猫 } 5545500cea7S猫头猫 } else { 5555500cea7S猫头猫 // 5.3.2 已经切换到其他歌曲了, 5565500cea7S猫头猫 return; 5575500cea7S猫头猫 } 5585500cea7S猫头猫 } 5595500cea7S猫头猫 5605500cea7S猫头猫 if (!isCurrentMusic(musicItem)) { 5615500cea7S猫头猫 return; 5625500cea7S猫头猫 } 5635500cea7S猫头猫 if (!source) { 56443eb30bfS猫头猫 // 如果有source 56543eb30bfS猫头猫 if (musicItem.source) { 56643eb30bfS猫头猫 for (let quality of qualityOrder) { 56743eb30bfS猫头猫 if (musicItem.source[quality]?.url) { 56843eb30bfS猫头猫 source = musicItem.source[quality]!; 5696e000b99S猫头猫 setQuality(quality); 5706e000b99S猫头猫 57143eb30bfS猫头猫 break; 5725500cea7S猫头猫 } 57343eb30bfS猫头猫 } 57443eb30bfS猫头猫 } 57543eb30bfS猫头猫 // 5.4 没有返回源 57643eb30bfS猫头猫 if (!source && !musicItem.url) { 5773991724eS猫头猫 // 插件失效的情况 57841ddce91Smaotoumao if (Config.getConfig('basic.tryChangeSourceWhenPlayFail')) { 5793991724eS猫头猫 // 重试 5803991724eS猫头猫 const similarMusic = await getSimilarMusic( 5813991724eS猫头猫 musicItem, 5823991724eS猫头猫 'music', 5833991724eS猫头猫 () => !isCurrentMusic(musicItem), 5843991724eS猫头猫 ); 5853991724eS猫头猫 5863991724eS猫头猫 if (similarMusic) { 5873991724eS猫头猫 const similarMusicPlugin = 5883991724eS猫头猫 PluginManager.getByMedia(similarMusic); 5893991724eS猫头猫 5903991724eS猫头猫 for (let quality of qualityOrder) { 5913991724eS猫头猫 if (isCurrentMusic(musicItem)) { 5923991724eS猫头猫 source = 5933991724eS猫头猫 (await similarMusicPlugin?.methods?.getMediaSource( 5943991724eS猫头猫 similarMusic, 5953991724eS猫头猫 quality, 5963991724eS猫头猫 )) ?? null; 5973991724eS猫头猫 // 5.4.1 获取到真实源 5983991724eS猫头猫 if (source) { 5993991724eS猫头猫 setQuality(quality); 6003991724eS猫头猫 break; 6013991724eS猫头猫 } 6023991724eS猫头猫 } else { 6033991724eS猫头猫 // 5.4.2 已经切换到其他歌曲了, 6043991724eS猫头猫 return; 6053991724eS猫头猫 } 6063991724eS猫头猫 } 6073991724eS猫头猫 } 6083991724eS猫头猫 6093991724eS猫头猫 if (!source) { 61043eb30bfS猫头猫 throw new Error(PlayFailReason.INVALID_SOURCE); 6113991724eS猫头猫 } 6123991724eS猫头猫 } else { 6133991724eS猫头猫 throw new Error(PlayFailReason.INVALID_SOURCE); 6143991724eS猫头猫 } 61543eb30bfS猫头猫 } else { 6165500cea7S猫头猫 source = { 6175500cea7S猫头猫 url: musicItem.url, 6185500cea7S猫头猫 }; 6196e000b99S猫头猫 setQuality('standard'); 6205500cea7S猫头猫 } 62143eb30bfS猫头猫 } 6225500cea7S猫头猫 6235500cea7S猫头猫 // 6. 特殊类型源 6245500cea7S猫头猫 if (getUrlExt(source.url) === '.m3u8') { 6255500cea7S猫头猫 // @ts-ignore 6265500cea7S猫头猫 source.type = 'hls'; 6275500cea7S猫头猫 } 6285500cea7S猫头猫 // 7. 合并结果 6295500cea7S猫头猫 track = mergeProps(musicItem, source) as IMusic.IMusicItem; 6305500cea7S猫头猫 6315500cea7S猫头猫 // 8. 新增历史记录 6325500cea7S猫头猫 musicHistory.addMusic(musicItem); 6335500cea7S猫头猫 63462e73a5eS猫头猫 trace('获取音源成功', track); 6355500cea7S猫头猫 // 9. 设置音源 6365500cea7S猫头猫 await setTrackSource(track as Track); 6375500cea7S猫头猫 6385500cea7S猫头猫 // 10. 获取补充信息 6395500cea7S猫头猫 let info: Partial<IMusic.IMusicItem> | null = null; 6405500cea7S猫头猫 try { 6415500cea7S猫头猫 info = (await plugin?.methods?.getMusicInfo?.(musicItem)) ?? null; 64263d241f1S猫头猫 if ( 64363d241f1S猫头猫 (typeof info?.url === 'string' && info.url.trim() === '') || 64463d241f1S猫头猫 (info?.url && typeof info.url !== 'string') 64563d241f1S猫头猫 ) { 646f9c53a4cS猫头猫 delete info.url; 647f9c53a4cS猫头猫 } 6485500cea7S猫头猫 } catch {} 6495500cea7S猫头猫 6505500cea7S猫头猫 // 11. 设置补充信息 6515500cea7S猫头猫 if (info && isCurrentMusic(musicItem)) { 6525500cea7S猫头猫 const mergedTrack = mergeProps(track, info); 6535500cea7S猫头猫 currentMusicStore.setValue(mergedTrack as IMusic.IMusicItem); 6545500cea7S猫头猫 await ReactNativeTrackPlayer.updateMetadataForTrack( 6555500cea7S猫头猫 0, 6565500cea7S猫头猫 mergedTrack as TrackMetadataBase, 6575500cea7S猫头猫 ); 6585500cea7S猫头猫 } 6595500cea7S猫头猫 } catch (e: any) { 6605500cea7S猫头猫 const message = e?.message; 6615500cea7S猫头猫 if ( 6625500cea7S猫头猫 message === 'The player is not initialized. Call setupPlayer first.' 6635500cea7S猫头猫 ) { 6645500cea7S猫头猫 await ReactNativeTrackPlayer.setupPlayer(); 6655500cea7S猫头猫 play(musicItem, forcePlay); 6665500cea7S猫头猫 } else if (message === PlayFailReason.FORBID_CELLUAR_NETWORK_PLAY) { 667dffbbaffS猫头猫 if (getCurrentDialog()?.name !== 'SimpleDialog') { 668595a35deS猫头猫 showDialog('SimpleDialog', { 669595a35deS猫头猫 title: '流量提醒', 670595a35deS猫头猫 content: 6712dd57e49S猫头猫 '当前非WIFI环境,侧边栏设置中打开【使用移动网络播放】功能后可继续播放', 672595a35deS猫头猫 }); 673dffbbaffS猫头猫 } 6745500cea7S猫头猫 } else if (message === PlayFailReason.INVALID_SOURCE) { 67562e73a5eS猫头猫 trace('音源为空,播放失败'); 6766f57784cS猫头猫 await failToPlay(); 6775500cea7S猫头猫 } else if (message === PlayFailReason.PLAY_LIST_IS_EMPTY) { 6785500cea7S猫头猫 // 队列是空的,不应该出现这种情况 6795500cea7S猫头猫 } 6805500cea7S猫头猫 } 6815500cea7S猫头猫}; 6825500cea7S猫头猫 6835500cea7S猫头猫/** 6845500cea7S猫头猫 * 播放音乐,同时替换播放队列 6855500cea7S猫头猫 * @param musicItem 音乐 6865500cea7S猫头猫 * @param newPlayList 替代列表 6875500cea7S猫头猫 */ 6885500cea7S猫头猫const playWithReplacePlayList = async ( 6895500cea7S猫头猫 musicItem: IMusic.IMusicItem, 6905500cea7S猫头猫 newPlayList: IMusic.IMusicItem[], 6915500cea7S猫头猫) => { 6925500cea7S猫头猫 if (newPlayList.length !== 0) { 6935500cea7S猫头猫 const now = Date.now(); 6945500cea7S猫头猫 if (newPlayList.length > maxMusicQueueLength) { 6955500cea7S猫头猫 newPlayList = shrinkPlayListToSize( 6965500cea7S猫头猫 newPlayList, 6975500cea7S猫头猫 newPlayList.findIndex(it => isSameMediaItem(it, musicItem)), 6985500cea7S猫头猫 ); 6995500cea7S猫头猫 } 7004c222b69S猫头猫 7014c222b69S猫头猫 newPlayList.forEach((it, index) => { 7024c222b69S猫头猫 it[timeStampSymbol] = now; 7034c222b69S猫头猫 it[sortIndexSymbol] = index; 7044c222b69S猫头猫 }); 7054c222b69S猫头猫 7065500cea7S猫头猫 setPlayList( 7075500cea7S猫头猫 repeatModeStore.getValue() === MusicRepeatMode.SHUFFLE 7084c222b69S猫头猫 ? shuffle(newPlayList) 7094c222b69S猫头猫 : newPlayList, 7105500cea7S猫头猫 ); 7115500cea7S猫头猫 await play(musicItem, true); 7125500cea7S猫头猫 } 7135500cea7S猫头猫}; 7145500cea7S猫头猫 7156f57784cS猫头猫const skipToNext = async () => { 7165500cea7S猫头猫 if (isPlayListEmpty()) { 7175500cea7S猫头猫 setCurrentMusic(null); 7185500cea7S猫头猫 return; 7195500cea7S猫头猫 } 7205500cea7S猫头猫 7215500cea7S猫头猫 await play(getPlayListMusicAt(currentIndex + 1), true); 7225500cea7S猫头猫}; 7235500cea7S猫头猫 7245500cea7S猫头猫const skipToPrevious = async () => { 7255500cea7S猫头猫 if (isPlayListEmpty()) { 7265500cea7S猫头猫 setCurrentMusic(null); 7275500cea7S猫头猫 return; 7285500cea7S猫头猫 } 7295500cea7S猫头猫 7306f57784cS猫头猫 await play( 7316f57784cS猫头猫 getPlayListMusicAt(currentIndex === -1 ? 0 : currentIndex - 1), 7326f57784cS猫头猫 true, 7336f57784cS猫头猫 ); 7345500cea7S猫头猫}; 7355500cea7S猫头猫 7365500cea7S猫头猫/** 修改当前播放的音质 */ 7375500cea7S猫头猫const changeQuality = async (newQuality: IMusic.IQualityKey) => { 7385500cea7S猫头猫 // 获取当前的音乐和进度 7395500cea7S猫头猫 if (newQuality === qualityStore.getValue()) { 7405500cea7S猫头猫 return true; 7415500cea7S猫头猫 } 7425500cea7S猫头猫 7435500cea7S猫头猫 // 获取当前歌曲 7445500cea7S猫头猫 const musicItem = currentMusicStore.getValue(); 7455500cea7S猫头猫 if (!musicItem) { 7465500cea7S猫头猫 return false; 7475500cea7S猫头猫 } 7485500cea7S猫头猫 try { 7495500cea7S猫头猫 const progress = await ReactNativeTrackPlayer.getProgress(); 7505500cea7S猫头猫 const plugin = PluginManager.getByMedia(musicItem); 7515500cea7S猫头猫 const newSource = await plugin?.methods?.getMediaSource( 7525500cea7S猫头猫 musicItem, 7535500cea7S猫头猫 newQuality, 7545500cea7S猫头猫 ); 7555500cea7S猫头猫 if (!newSource?.url) { 7565500cea7S猫头猫 throw new Error(PlayFailReason.INVALID_SOURCE); 7575500cea7S猫头猫 } 7585500cea7S猫头猫 if (isCurrentMusic(musicItem)) { 7595500cea7S猫头猫 const playingState = ( 7605500cea7S猫头猫 await ReactNativeTrackPlayer.getPlaybackState() 7615500cea7S猫头猫 ).state; 7625500cea7S猫头猫 await setTrackSource( 7635500cea7S猫头猫 mergeProps(musicItem, newSource) as unknown as Track, 7645500cea7S猫头猫 !musicIsPaused(playingState), 7655500cea7S猫头猫 ); 7665500cea7S猫头猫 7675500cea7S猫头猫 await ReactNativeTrackPlayer.seekTo(progress.position ?? 0); 7686e000b99S猫头猫 setQuality(newQuality); 7695500cea7S猫头猫 } 7705500cea7S猫头猫 return true; 7715500cea7S猫头猫 } catch { 7725500cea7S猫头猫 // 修改失败 7735500cea7S猫头猫 return false; 7745500cea7S猫头猫 } 7755500cea7S猫头猫}; 7765500cea7S猫头猫 7775500cea7S猫头猫enum PlayFailReason { 7785500cea7S猫头猫 /** 禁止移动网络播放 */ 7795500cea7S猫头猫 FORBID_CELLUAR_NETWORK_PLAY = 'FORBID_CELLUAR_NETWORK_PLAY', 7805500cea7S猫头猫 /** 播放列表为空 */ 7815500cea7S猫头猫 PLAY_LIST_IS_EMPTY = 'PLAY_LIST_IS_EMPTY', 7825500cea7S猫头猫 /** 无效源 */ 7835500cea7S猫头猫 INVALID_SOURCE = 'INVALID_SOURCE', 7845500cea7S猫头猫 /** 非当前音乐 */ 7855500cea7S猫头猫} 7865500cea7S猫头猫 7875500cea7S猫头猫function useMusicState() { 7885500cea7S猫头猫 const playbackState = usePlaybackState(); 7895500cea7S猫头猫 7905500cea7S猫头猫 return playbackState.state; 7915500cea7S猫头猫} 7925500cea7S猫头猫 793f511aee9S猫头猫function getPreviousMusic() { 794f511aee9S猫头猫 const currentMusicItem = currentMusicStore.getValue(); 795f511aee9S猫头猫 if (!currentMusicItem) { 796f511aee9S猫头猫 return null; 797f511aee9S猫头猫 } 798f511aee9S猫头猫 799f511aee9S猫头猫 return getPlayListMusicAt(currentIndex - 1); 800f511aee9S猫头猫} 801f511aee9S猫头猫 802f511aee9S猫头猫function getNextMusic() { 803f511aee9S猫头猫 const currentMusicItem = currentMusicStore.getValue(); 804f511aee9S猫头猫 if (!currentMusicItem) { 805f511aee9S猫头猫 return null; 806f511aee9S猫头猫 } 807f511aee9S猫头猫 808f511aee9S猫头猫 return getPlayListMusicAt(currentIndex + 1); 809f511aee9S猫头猫} 810f511aee9S猫头猫 8115500cea7S猫头猫const TrackPlayer = { 8125500cea7S猫头猫 setupTrackPlayer, 8135500cea7S猫头猫 usePlayList, 8145500cea7S猫头猫 getPlayList, 8155500cea7S猫头猫 addAll, 8165500cea7S猫头猫 add, 8175500cea7S猫头猫 addNext, 8185500cea7S猫头猫 skipToNext, 8195500cea7S猫头猫 skipToPrevious, 8205500cea7S猫头猫 play, 8215500cea7S猫头猫 playWithReplacePlayList, 8225500cea7S猫头猫 pause, 8235500cea7S猫头猫 remove, 8245500cea7S猫头猫 clear, 8255500cea7S猫头猫 useCurrentMusic: currentMusicStore.useValue, 8265500cea7S猫头猫 getCurrentMusic: currentMusicStore.getValue, 8275500cea7S猫头猫 useRepeatMode: repeatModeStore.useValue, 8285500cea7S猫头猫 getRepeatMode: repeatModeStore.getValue, 8295500cea7S猫头猫 toggleRepeatMode, 8305500cea7S猫头猫 usePlaybackState, 8315500cea7S猫头猫 getProgress: ReactNativeTrackPlayer.getProgress, 8325500cea7S猫头猫 useProgress: useProgress, 8335500cea7S猫头猫 seekTo: ReactNativeTrackPlayer.seekTo, 8345500cea7S猫头猫 changeQuality, 8355500cea7S猫头猫 useCurrentQuality: qualityStore.useValue, 8365500cea7S猫头猫 getCurrentQuality: qualityStore.getValue, 8375500cea7S猫头猫 getRate: ReactNativeTrackPlayer.getRate, 8385500cea7S猫头猫 setRate: ReactNativeTrackPlayer.setRate, 8395500cea7S猫头猫 useMusicState, 8405500cea7S猫头猫 reset: ReactNativeTrackPlayer.reset, 841f511aee9S猫头猫 getPreviousMusic, 842f511aee9S猫头猫 getNextMusic, 8435500cea7S猫头猫}; 8445500cea7S猫头猫 8455500cea7S猫头猫export default TrackPlayer; 8465500cea7S猫头猫export {MusicRepeatMode, State as MusicState}; 847