xref: /MusicFree/src/core/localMusicSheet.ts (revision afb5c234cc3fc767c9c82c88cbc40aa70fa6a140)
1*afb5c234S猫头猫import {internalSerialzeKey, StorageKeys} from '@/constants/commonConst';
2*afb5c234S猫头猫import mp3Util, {IBasicMeta} from '@/native/mp3Util';
3*afb5c234S猫头猫import {isSameMediaItem} from '@/utils/mediaItem';
4*afb5c234S猫头猫import StateMapper from '@/utils/stateMapper';
5*afb5c234S猫头猫import {getStorage, setStorage} from '@/utils/storage';
6*afb5c234S猫头猫import {FileSystem} from 'react-native-file-access';
7*afb5c234S猫头猫
8*afb5c234S猫头猫let localSheet: IMusic.IMusicItem[] = [];
9*afb5c234S猫头猫const localSheetStateMapper = new StateMapper(() => localSheet);
10*afb5c234S猫头猫
11*afb5c234S猫头猫export async function setup() {
12*afb5c234S猫头猫    const sheets = await getStorage(StorageKeys.LocalMusicSheet);
13*afb5c234S猫头猫    if (sheets) {
14*afb5c234S猫头猫        localSheet = sheets;
15*afb5c234S猫头猫    } else {
16*afb5c234S猫头猫        await setStorage(StorageKeys.LocalMusicSheet, []);
17*afb5c234S猫头猫    }
18*afb5c234S猫头猫    localSheetStateMapper.notify();
19*afb5c234S猫头猫}
20*afb5c234S猫头猫
21*afb5c234S猫头猫export async function addMusic(
22*afb5c234S猫头猫    musicItem: IMusic.IMusicItem | IMusic.IMusicItem[],
23*afb5c234S猫头猫) {
24*afb5c234S猫头猫    if (!Array.isArray(musicItem)) {
25*afb5c234S猫头猫        musicItem = [musicItem];
26*afb5c234S猫头猫    }
27*afb5c234S猫头猫    let newSheet = [...localSheet];
28*afb5c234S猫头猫    musicItem.forEach(mi => {
29*afb5c234S猫头猫        if (localSheet.findIndex(_ => isSameMediaItem(mi, _)) === -1) {
30*afb5c234S猫头猫            newSheet.push(mi);
31*afb5c234S猫头猫        }
32*afb5c234S猫头猫    });
33*afb5c234S猫头猫    await setStorage(StorageKeys.LocalMusicSheet, newSheet);
34*afb5c234S猫头猫    localSheet = newSheet;
35*afb5c234S猫头猫    localSheetStateMapper.notify();
36*afb5c234S猫头猫}
37*afb5c234S猫头猫
38*afb5c234S猫头猫export async function removeMusic(
39*afb5c234S猫头猫    musicItem: IMusic.IMusicItem,
40*afb5c234S猫头猫    deleteOriginalFile = false,
41*afb5c234S猫头猫) {
42*afb5c234S猫头猫    const idx = localSheet.findIndex(_ => isSameMediaItem(_, musicItem));
43*afb5c234S猫头猫    let newSheet = [...localSheet];
44*afb5c234S猫头猫    if (idx !== -1) {
45*afb5c234S猫头猫        newSheet.splice(idx, 1);
46*afb5c234S猫头猫        if (deleteOriginalFile && musicItem[internalSerialzeKey]?.localPath) {
47*afb5c234S猫头猫            await FileSystem.unlink(musicItem[internalSerialzeKey].localPath);
48*afb5c234S猫头猫        }
49*afb5c234S猫头猫    }
50*afb5c234S猫头猫    localSheet = newSheet;
51*afb5c234S猫头猫    localSheetStateMapper.notify();
52*afb5c234S猫头猫}
53*afb5c234S猫头猫
54*afb5c234S猫头猫function parseFilename(fn: string): Partial<IMusic.IMusicItem> | null {
55*afb5c234S猫头猫    const data = fn.slice(0, fn.lastIndexOf('.')).split('@');
56*afb5c234S猫头猫    const [platform, id, title, artist] = data;
57*afb5c234S猫头猫    if (!platform || !id) {
58*afb5c234S猫头猫        return null;
59*afb5c234S猫头猫    }
60*afb5c234S猫头猫    return {
61*afb5c234S猫头猫        id,
62*afb5c234S猫头猫        platform,
63*afb5c234S猫头猫        title,
64*afb5c234S猫头猫        artist,
65*afb5c234S猫头猫    };
66*afb5c234S猫头猫}
67*afb5c234S猫头猫
68*afb5c234S猫头猫export async function importFolder(folderPath: string) {
69*afb5c234S猫头猫    const dirFiles = await FileSystem.statDir(folderPath);
70*afb5c234S猫头猫    const musicFiles = dirFiles.filter(
71*afb5c234S猫头猫        _ => _.type === 'file' && _.filename.endsWith('.mp3'),
72*afb5c234S猫头猫    );
73*afb5c234S猫头猫
74*afb5c234S猫头猫    const musicItems: IMusic.IMusicItem[] = await Promise.all(
75*afb5c234S猫头猫        musicFiles.map(async mf => {
76*afb5c234S猫头猫            let {platform, id, title, artist} =
77*afb5c234S猫头猫                parseFilename(mf.filename) ?? {};
78*afb5c234S猫头猫
79*afb5c234S猫头猫            const decodedPath = decodeURIComponent(mf.path);
80*afb5c234S猫头猫            let meta: IBasicMeta | null;
81*afb5c234S猫头猫            try {
82*afb5c234S猫头猫                meta = await mp3Util.getBasicMeta(mf.path);
83*afb5c234S猫头猫            } catch {
84*afb5c234S猫头猫                meta = null;
85*afb5c234S猫头猫            }
86*afb5c234S猫头猫            if (!platform || !id) {
87*afb5c234S猫头猫                platform = '本地';
88*afb5c234S猫头猫                id = await FileSystem.hash(mf.path, 'MD5');
89*afb5c234S猫头猫            }
90*afb5c234S猫头猫            return {
91*afb5c234S猫头猫                id,
92*afb5c234S猫头猫                platform,
93*afb5c234S猫头猫                title: title ?? meta?.title ?? '未知名称',
94*afb5c234S猫头猫                artist: artist ?? meta?.artist ?? '未知歌手',
95*afb5c234S猫头猫                duration: parseInt(meta?.duration ?? '0') / 1000,
96*afb5c234S猫头猫                album: meta?.album ?? '',
97*afb5c234S猫头猫                artwork: '',
98*afb5c234S猫头猫                [internalSerialzeKey]: {
99*afb5c234S猫头猫                    localPath: decodedPath,
100*afb5c234S猫头猫                },
101*afb5c234S猫头猫            };
102*afb5c234S猫头猫        }),
103*afb5c234S猫头猫    );
104*afb5c234S猫头猫    addMusic(musicItems);
105*afb5c234S猫头猫}
106