10e4173cdS猫头猫import {internalSerializeKey, StorageKeys} from '@/constants/commonConst'; 2afb5c234S猫头猫import mp3Util, {IBasicMeta} from '@/native/mp3Util'; 388772aabS猫头猫import { 488772aabS猫头猫 getInternalData, 588772aabS猫头猫 InternalDataType, 688772aabS猫头猫 isSameMediaItem, 788772aabS猫头猫} from '@/utils/mediaItem'; 8afb5c234S猫头猫import StateMapper from '@/utils/stateMapper'; 9afb5c234S猫头猫import {getStorage, setStorage} from '@/utils/storage'; 100e4173cdS猫头猫import {useEffect, useState} from 'react'; 11afb5c234S猫头猫import {FileSystem} from 'react-native-file-access'; 12afb5c234S猫头猫 13afb5c234S猫头猫let localSheet: IMusic.IMusicItem[] = []; 14afb5c234S猫头猫const localSheetStateMapper = new StateMapper(() => localSheet); 15afb5c234S猫头猫 16afb5c234S猫头猫export async function setup() { 1788772aabS猫头猫 const sheet = await getStorage(StorageKeys.LocalMusicSheet); 1888772aabS猫头猫 if (sheet) { 1988772aabS猫头猫 let validSheet = []; 2088772aabS猫头猫 for (let musicItem of sheet) { 2188772aabS猫头猫 const localPath = getInternalData<string>( 2288772aabS猫头猫 musicItem, 2388772aabS猫头猫 InternalDataType.LOCALPATH, 2488772aabS猫头猫 ); 2588772aabS猫头猫 if (localPath && (await FileSystem.exists(localPath))) { 2688772aabS猫头猫 validSheet.push(musicItem); 2788772aabS猫头猫 } 2888772aabS猫头猫 } 2988772aabS猫头猫 if (validSheet.length !== sheet.length) { 3088772aabS猫头猫 await setStorage(StorageKeys.LocalMusicSheet, validSheet); 3188772aabS猫头猫 } 3288772aabS猫头猫 localSheet = validSheet; 33afb5c234S猫头猫 } else { 34afb5c234S猫头猫 await setStorage(StorageKeys.LocalMusicSheet, []); 35afb5c234S猫头猫 } 36afb5c234S猫头猫 localSheetStateMapper.notify(); 37afb5c234S猫头猫} 38afb5c234S猫头猫 39afb5c234S猫头猫export async function addMusic( 40afb5c234S猫头猫 musicItem: IMusic.IMusicItem | IMusic.IMusicItem[], 41afb5c234S猫头猫) { 42afb5c234S猫头猫 if (!Array.isArray(musicItem)) { 43afb5c234S猫头猫 musicItem = [musicItem]; 44afb5c234S猫头猫 } 45afb5c234S猫头猫 let newSheet = [...localSheet]; 46afb5c234S猫头猫 musicItem.forEach(mi => { 47afb5c234S猫头猫 if (localSheet.findIndex(_ => isSameMediaItem(mi, _)) === -1) { 48afb5c234S猫头猫 newSheet.push(mi); 49afb5c234S猫头猫 } 50afb5c234S猫头猫 }); 51afb5c234S猫头猫 await setStorage(StorageKeys.LocalMusicSheet, newSheet); 52afb5c234S猫头猫 localSheet = newSheet; 53afb5c234S猫头猫 localSheetStateMapper.notify(); 54afb5c234S猫头猫} 55afb5c234S猫头猫 56afb5c234S猫头猫export async function removeMusic( 57afb5c234S猫头猫 musicItem: IMusic.IMusicItem, 58afb5c234S猫头猫 deleteOriginalFile = false, 59afb5c234S猫头猫) { 60afb5c234S猫头猫 const idx = localSheet.findIndex(_ => isSameMediaItem(_, musicItem)); 61afb5c234S猫头猫 let newSheet = [...localSheet]; 62afb5c234S猫头猫 if (idx !== -1) { 63afb5c234S猫头猫 newSheet.splice(idx, 1); 640e4173cdS猫头猫 if (deleteOriginalFile && musicItem[internalSerializeKey]?.localPath) { 650e4173cdS猫头猫 await FileSystem.unlink(musicItem[internalSerializeKey].localPath); 66afb5c234S猫头猫 } 67afb5c234S猫头猫 } 68afb5c234S猫头猫 localSheet = newSheet; 69afb5c234S猫头猫 localSheetStateMapper.notify(); 70afb5c234S猫头猫} 71afb5c234S猫头猫 72afb5c234S猫头猫function parseFilename(fn: string): Partial<IMusic.IMusicItem> | null { 73afb5c234S猫头猫 const data = fn.slice(0, fn.lastIndexOf('.')).split('@'); 74afb5c234S猫头猫 const [platform, id, title, artist] = data; 75afb5c234S猫头猫 if (!platform || !id) { 76afb5c234S猫头猫 return null; 77afb5c234S猫头猫 } 78afb5c234S猫头猫 return { 79afb5c234S猫头猫 id, 80afb5c234S猫头猫 platform, 81afb5c234S猫头猫 title, 82afb5c234S猫头猫 artist, 83afb5c234S猫头猫 }; 84afb5c234S猫头猫} 85afb5c234S猫头猫 860e4173cdS猫头猫/** 从文件夹导入 */ 870e4173cdS猫头猫async function importFolder(folderPath: string) { 88afb5c234S猫头猫 const dirFiles = await FileSystem.statDir(folderPath); 89afb5c234S猫头猫 const musicFiles = dirFiles.filter( 90afb5c234S猫头猫 _ => _.type === 'file' && _.filename.endsWith('.mp3'), 91afb5c234S猫头猫 ); 92afb5c234S猫头猫 93afb5c234S猫头猫 const musicItems: IMusic.IMusicItem[] = await Promise.all( 94afb5c234S猫头猫 musicFiles.map(async mf => { 95afb5c234S猫头猫 let {platform, id, title, artist} = 96afb5c234S猫头猫 parseFilename(mf.filename) ?? {}; 97afb5c234S猫头猫 98afb5c234S猫头猫 let meta: IBasicMeta | null; 99afb5c234S猫头猫 try { 100afb5c234S猫头猫 meta = await mp3Util.getBasicMeta(mf.path); 101afb5c234S猫头猫 } catch { 102afb5c234S猫头猫 meta = null; 103afb5c234S猫头猫 } 104afb5c234S猫头猫 if (!platform || !id) { 105afb5c234S猫头猫 platform = '本地'; 106afb5c234S猫头猫 id = await FileSystem.hash(mf.path, 'MD5'); 107afb5c234S猫头猫 } 108afb5c234S猫头猫 return { 109afb5c234S猫头猫 id, 110afb5c234S猫头猫 platform, 111afb5c234S猫头猫 title: title ?? meta?.title ?? '未知名称', 112afb5c234S猫头猫 artist: artist ?? meta?.artist ?? '未知歌手', 113afb5c234S猫头猫 duration: parseInt(meta?.duration ?? '0') / 1000, 114afb5c234S猫头猫 album: meta?.album ?? '', 115afb5c234S猫头猫 artwork: '', 1160e4173cdS猫头猫 [internalSerializeKey]: { 1170e4173cdS猫头猫 localPath: mf.path, 118afb5c234S猫头猫 }, 119afb5c234S猫头猫 }; 120afb5c234S猫头猫 }), 121afb5c234S猫头猫 ); 122afb5c234S猫头猫 addMusic(musicItems); 123afb5c234S猫头猫} 1240e4173cdS猫头猫 1250e4173cdS猫头猫/** 是否为本地音乐 */ 1260e4173cdS猫头猫function isLocalMusic( 1270e4173cdS猫头猫 musicItem: ICommon.IMediaBase | null, 1280e4173cdS猫头猫): IMusic.IMusicItem | undefined { 1290e4173cdS猫头猫 return musicItem 1300e4173cdS猫头猫 ? localSheet.find(_ => isSameMediaItem(_, musicItem)) 1310e4173cdS猫头猫 : undefined; 1320e4173cdS猫头猫} 1330e4173cdS猫头猫 1340e4173cdS猫头猫/** 状态-是否为本地音乐 */ 1350e4173cdS猫头猫function useIsLocal(musicItem: IMusic.IMusicItem | null) { 1360e4173cdS猫头猫 const localMusicState = localSheetStateMapper.useMappedState(); 1370e4173cdS猫头猫 const [isLocal, setIsLocal] = useState<boolean>(!!isLocalMusic(musicItem)); 1380e4173cdS猫头猫 useEffect(() => { 1390e4173cdS猫头猫 if (!musicItem) { 1400e4173cdS猫头猫 setIsLocal(false); 1410e4173cdS猫头猫 } else { 1420e4173cdS猫头猫 setIsLocal(!!isLocalMusic(musicItem)); 1430e4173cdS猫头猫 } 1440e4173cdS猫头猫 }, [localMusicState, musicItem]); 1450e4173cdS猫头猫 return isLocal; 1460e4173cdS猫头猫} 1470e4173cdS猫头猫 148*0224b881S猫头猫function getMusicList() { 149*0224b881S猫头猫 return localSheet; 150*0224b881S猫头猫} 151*0224b881S猫头猫 1520e4173cdS猫头猫const LocalMusicSheet = { 1530e4173cdS猫头猫 setup, 1540e4173cdS猫头猫 addMusic, 1550e4173cdS猫头猫 removeMusic, 1560e4173cdS猫头猫 importFolder, 1570e4173cdS猫头猫 isLocalMusic, 1580e4173cdS猫头猫 useIsLocal, 159*0224b881S猫头猫 getMusicList, 1600e4173cdS猫头猫 useMusicList: localSheetStateMapper.useMappedState, 1610e4173cdS猫头猫}; 1620e4173cdS猫头猫 1630e4173cdS猫头猫export default LocalMusicSheet; 164