xref: /MusicFree/src/core/trackPlayer/index.ts (revision c341583d348145d6d39433f85a4322a26d806dad)
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