xref: /MusicFree/src/core/musicSheet/index.ts (revision adf41771e5c3ca7c27879b461cece7e444d1dc58)
1740e3947S猫头猫/**
2740e3947S猫头猫 * 歌单管理
3740e3947S猫头猫 */
4740e3947S猫头猫import {Immer} from 'immer';
5740e3947S猫头猫import {useEffect, useMemo, useState} from 'react';
6740e3947S猫头猫import {nanoid} from 'nanoid';
7740e3947S猫头猫import {isSameMediaItem} from '@/utils/mediaItem';
8740e3947S猫头猫import storage from '@/core/musicSheet/storage.ts';
9740e3947S猫头猫import migrate, {migrateV2} from '@/core/musicSheet/migrate.ts';
10740e3947S猫头猫import {getDefaultStore, useAtomValue} from 'jotai';
11740e3947S猫头猫import {
12740e3947S猫头猫    musicListMap,
13740e3947S猫头猫    musicSheetsBaseAtom,
14740e3947S猫头猫    starredMusicSheetsAtom,
15740e3947S猫头猫} from '@/core/musicSheet/atoms.ts';
16*adf41771S猫头猫import {ResumeMode, SortType} from '@/constants/commonConst.ts';
17740e3947S猫头猫import SortedMusicList from '@/core/musicSheet/sortedMusicList.ts';
18740e3947S猫头猫import ee from '@/core/musicSheet/ee.ts';
19740e3947S猫头猫import Config from '@/core/config.ts';
20740e3947S猫头猫
21740e3947S猫头猫const produce = new Immer({
22740e3947S猫头猫    autoFreeze: false,
23740e3947S猫头猫}).produce;
24740e3947S猫头猫
25740e3947S猫头猫const defaultSheet: IMusic.IMusicSheetItemBase = {
26740e3947S猫头猫    id: 'favorite',
27740e3947S猫头猫    coverImg: undefined,
28740e3947S猫头猫    title: '我喜欢',
29740e3947S猫头猫    worksNum: 0,
30740e3947S猫头猫};
31740e3947S猫头猫
32740e3947S猫头猫async function setup() {
33740e3947S猫头猫    // 升级逻辑 - 从 AsyncStorage 升级到 MMKV
34740e3947S猫头猫    await migrate();
35740e3947S猫头猫    try {
36740e3947S猫头猫        const allSheets: IMusic.IMusicSheetItemBase[] = storage.getSheets();
37740e3947S猫头猫
38740e3947S猫头猫        if (!Array.isArray(allSheets)) {
39740e3947S猫头猫            throw new Error('not exist');
40740e3947S猫头猫        }
41740e3947S猫头猫
42740e3947S猫头猫        let needRestore = false;
43740e3947S猫头猫        if (!allSheets.length) {
44740e3947S猫头猫            allSheets.push({
45740e3947S猫头猫                ...defaultSheet,
46740e3947S猫头猫            });
47740e3947S猫头猫            needRestore = true;
48740e3947S猫头猫        }
49740e3947S猫头猫        if (allSheets[0].id !== defaultSheet.id) {
50740e3947S猫头猫            const defaultSheetIndex = allSheets.findIndex(
51740e3947S猫头猫                it => it.id === defaultSheet.id,
52740e3947S猫头猫            );
53740e3947S猫头猫
54740e3947S猫头猫            if (defaultSheetIndex === -1) {
55740e3947S猫头猫                allSheets.unshift({
56740e3947S猫头猫                    ...defaultSheet,
57740e3947S猫头猫                });
58740e3947S猫头猫            } else {
59740e3947S猫头猫                const firstSheet = allSheets.splice(defaultSheetIndex, 1);
60740e3947S猫头猫                allSheets.unshift(firstSheet[0]);
61740e3947S猫头猫            }
62740e3947S猫头猫            needRestore = true;
63740e3947S猫头猫        }
64740e3947S猫头猫
65740e3947S猫头猫        if (needRestore) {
66740e3947S猫头猫            await storage.setSheets(allSheets);
67740e3947S猫头猫        }
68740e3947S猫头猫
69740e3947S猫头猫        for (let sheet of allSheets) {
70740e3947S猫头猫            const musicList = storage.getMusicList(sheet.id);
71740e3947S猫头猫            const sortType = storage.getSheetMeta(sheet.id, 'sort') as SortType;
72740e3947S猫头猫            sheet.worksNum = musicList.length;
73740e3947S猫头猫            migrateV2.migrate(sheet.id, musicList);
74740e3947S猫头猫            musicListMap.set(
75740e3947S猫头猫                sheet.id,
76740e3947S猫头猫                new SortedMusicList(musicList, sortType, true),
77740e3947S猫头猫            );
78740e3947S猫头猫            sheet.worksNum = musicList.length;
79740e3947S猫头猫            ee.emit('UpdateMusicList', {
80740e3947S猫头猫                sheetId: sheet.id,
81740e3947S猫头猫                updateType: 'length',
82740e3947S猫头猫            });
83740e3947S猫头猫        }
84740e3947S猫头猫        migrateV2.done();
85740e3947S猫头猫        getDefaultStore().set(musicSheetsBaseAtom, allSheets);
86740e3947S猫头猫        setupStarredMusicSheets();
87740e3947S猫头猫    } catch (e: any) {
88740e3947S猫头猫        if (e.message === 'not exist') {
89740e3947S猫头猫            await storage.setSheets([defaultSheet]);
90740e3947S猫头猫            await storage.setMusicList(defaultSheet.id, []);
91740e3947S猫头猫            getDefaultStore().set(musicSheetsBaseAtom, [defaultSheet]);
92740e3947S猫头猫            musicListMap.set(
93740e3947S猫头猫                defaultSheet.id,
94740e3947S猫头猫                new SortedMusicList([], SortType.None, true),
95740e3947S猫头猫            );
96740e3947S猫头猫        }
97740e3947S猫头猫    }
98740e3947S猫头猫}
99740e3947S猫头猫
100740e3947S猫头猫// 获取音乐
101740e3947S猫头猫function getSortedMusicListBySheetId(sheetId: string) {
102740e3947S猫头猫    let musicList: SortedMusicList;
103740e3947S猫头猫    if (!musicListMap.has(sheetId)) {
104740e3947S猫头猫        musicList = new SortedMusicList([], SortType.None, true);
105740e3947S猫头猫        musicListMap.set(sheetId, musicList);
106740e3947S猫头猫    } else {
107740e3947S猫头猫        musicList = musicListMap.get(sheetId)!;
108740e3947S猫头猫    }
109740e3947S猫头猫
110740e3947S猫头猫    return musicList;
111740e3947S猫头猫}
112740e3947S猫头猫
113740e3947S猫头猫/**
114740e3947S猫头猫 * 更新基本信息
115740e3947S猫头猫 * @param sheetId 歌单ID
116740e3947S猫头猫 * @param data 歌单数据
117740e3947S猫头猫 */
118740e3947S猫头猫async function updateMusicSheetBase(
119740e3947S猫头猫    sheetId: string,
120740e3947S猫头猫    data: Partial<IMusic.IMusicSheetItemBase>,
121740e3947S猫头猫) {
122740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
123740e3947S猫头猫    const targetSheetIndex = musicSheets.findIndex(it => it.id === sheetId);
124740e3947S猫头猫
125740e3947S猫头猫    if (targetSheetIndex === -1) {
126740e3947S猫头猫        return;
127740e3947S猫头猫    }
128740e3947S猫头猫
129740e3947S猫头猫    const newMusicSheets = produce(musicSheets, draft => {
130740e3947S猫头猫        draft[targetSheetIndex] = {
131740e3947S猫头猫            ...draft[targetSheetIndex],
132740e3947S猫头猫            ...data,
133740e3947S猫头猫            id: sheetId,
134740e3947S猫头猫        };
135740e3947S猫头猫        return draft;
136740e3947S猫头猫    });
137740e3947S猫头猫    await storage.setSheets(newMusicSheets);
138740e3947S猫头猫    getDefaultStore().set(musicSheetsBaseAtom, newMusicSheets);
139756bc302S猫头猫    ee.emit('UpdateSheetBasic', {
140756bc302S猫头猫        sheetId,
141756bc302S猫头猫    });
142740e3947S猫头猫}
143740e3947S猫头猫
144740e3947S猫头猫/**
145740e3947S猫头猫 * 新建歌单
146740e3947S猫头猫 * @param title 歌单名称
147740e3947S猫头猫 */
148740e3947S猫头猫async function addSheet(title: string) {
149740e3947S猫头猫    const newId = nanoid();
150740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
151740e3947S猫头猫
152740e3947S猫头猫    const newSheets: IMusic.IMusicSheetItemBase[] = [
153740e3947S猫头猫        musicSheets[0],
154740e3947S猫头猫        {
155740e3947S猫头猫            title,
156740e3947S猫头猫            id: newId,
157740e3947S猫头猫            coverImg: undefined,
158740e3947S猫头猫            worksNum: 0,
159740e3947S猫头猫            createAt: Date.now(),
160740e3947S猫头猫        },
161740e3947S猫头猫        ...musicSheets.slice(1),
162740e3947S猫头猫    ];
163740e3947S猫头猫    // 写入存储
164740e3947S猫头猫    await storage.setSheets(newSheets);
165740e3947S猫头猫    await storage.setMusicList(newId, []);
166740e3947S猫头猫
167740e3947S猫头猫    // 更新状态
168740e3947S猫头猫    getDefaultStore().set(musicSheetsBaseAtom, newSheets);
169740e3947S猫头猫    let defaultSortType = Config.get('setting.basic.musicOrderInLocalSheet');
170740e3947S猫头猫    if (
171740e3947S猫头猫        defaultSortType &&
172740e3947S猫头猫        [
173740e3947S猫头猫            SortType.Newest,
174740e3947S猫头猫            SortType.Artist,
175740e3947S猫头猫            SortType.Album,
176740e3947S猫头猫            SortType.Oldest,
177740e3947S猫头猫            SortType.Title,
178740e3947S猫头猫        ].includes(defaultSortType)
179740e3947S猫头猫    ) {
180740e3947S猫头猫        storage.setSheetMeta(newId, 'sort', defaultSortType);
181740e3947S猫头猫    } else {
182740e3947S猫头猫        defaultSortType = SortType.None;
183740e3947S猫头猫    }
184740e3947S猫头猫    musicListMap.set(newId, new SortedMusicList([], defaultSortType, true));
185740e3947S猫头猫    return newId;
186740e3947S猫头猫}
187740e3947S猫头猫
188740e3947S猫头猫async function resumeSheets(
189740e3947S猫头猫    sheets: IMusic.IMusicSheetItem[],
190*adf41771S猫头猫    resumeMode: ResumeMode,
191740e3947S猫头猫) {
192*adf41771S猫头猫    if (resumeMode === ResumeMode.Append) {
193*adf41771S猫头猫        // 逆序恢复,最新创建的在最上方
194*adf41771S猫头猫        for (let i = sheets.length - 1; i >= 0; --i) {
195*adf41771S猫头猫            const newSheetId = await addSheet(sheets[i].title || '');
196*adf41771S猫头猫            await addMusic(newSheetId, sheets[i].musicList || []);
197*adf41771S猫头猫        }
198*adf41771S猫头猫        return;
199*adf41771S猫头猫    }
200740e3947S猫头猫    // 1. 分离默认歌单和其他歌单
201740e3947S猫头猫    const defaultSheetIndex = sheets.findIndex(it => it.id === defaultSheet.id);
202740e3947S猫头猫
203740e3947S猫头猫    let exportedDefaultSheet: IMusic.IMusicSheetItem | null = null;
204740e3947S猫头猫
205740e3947S猫头猫    if (defaultSheetIndex !== -1) {
206740e3947S猫头猫        exportedDefaultSheet = sheets.splice(defaultSheetIndex, 1)[0];
207740e3947S猫头猫    }
208740e3947S猫头猫
209*adf41771S猫头猫    // 2. 合并默认歌单
210*adf41771S猫头猫    await addMusic(defaultSheet.id, exportedDefaultSheet?.musicList || []);
211*adf41771S猫头猫
212*adf41771S猫头猫    // 3. 合并其他歌单
213*adf41771S猫头猫    if (resumeMode === ResumeMode.OverwriteDefault) {
214740e3947S猫头猫        // 逆序恢复,最新创建的在最上方
215740e3947S猫头猫        for (let i = sheets.length - 1; i >= 0; --i) {
216740e3947S猫头猫            const newSheetId = await addSheet(sheets[i].title || '');
217740e3947S猫头猫            await addMusic(newSheetId, sheets[i].musicList || []);
218740e3947S猫头猫        }
219*adf41771S猫头猫    } else {
220*adf41771S猫头猫        // 合并同名
221*adf41771S猫头猫        const existsSheetIdMap: Record<string, string> = {};
222*adf41771S猫头猫        const allSheets = getDefaultStore().get(musicSheetsBaseAtom);
223*adf41771S猫头猫        allSheets.forEach(it => {
224*adf41771S猫头猫            existsSheetIdMap[it.title!] = it.id;
225*adf41771S猫头猫        });
226*adf41771S猫头猫        for (let i = sheets.length - 1; i >= 0; --i) {
227*adf41771S猫头猫            let newSheetId = existsSheetIdMap[sheets[i].title || ''];
228*adf41771S猫头猫            if (!newSheetId) {
229*adf41771S猫头猫                newSheetId = await addSheet(sheets[i].title || '');
230*adf41771S猫头猫            }
231*adf41771S猫头猫            await addMusic(newSheetId, sheets[i].musicList || []);
232*adf41771S猫头猫        }
233*adf41771S猫头猫    }
234740e3947S猫头猫
235740e3947S猫头猫    if (overwrite) {
236740e3947S猫头猫    } else {
237740e3947S猫头猫        const newSheetId = await addSheet(
238740e3947S猫头猫            exportedDefaultSheet?.title || defaultSheet.title!,
239740e3947S猫头猫        );
240740e3947S猫头猫        await addMusic(newSheetId, exportedDefaultSheet?.musicList || []);
241740e3947S猫头猫    }
242740e3947S猫头猫}
243740e3947S猫头猫
244740e3947S猫头猫function backupSheets() {
245740e3947S猫头猫    const allSheets = getDefaultStore().get(musicSheetsBaseAtom);
246740e3947S猫头猫    return allSheets.map(it => ({
247740e3947S猫头猫        ...it,
248740e3947S猫头猫        musicList: musicListMap.get(it.id)?.musicList || [],
249740e3947S猫头猫    })) as IMusic.IMusicSheetItem[];
250740e3947S猫头猫}
251740e3947S猫头猫
252740e3947S猫头猫/**
253740e3947S猫头猫 * 删除歌单
254740e3947S猫头猫 * @param sheetId 歌单id
255740e3947S猫头猫 */
256740e3947S猫头猫async function removeSheet(sheetId: string) {
257740e3947S猫头猫    // 只能删除非默认歌单
258740e3947S猫头猫    if (sheetId === defaultSheet.id) {
259740e3947S猫头猫        return;
260740e3947S猫头猫    }
261740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
262740e3947S猫头猫
263740e3947S猫头猫    // 删除后的歌单
264740e3947S猫头猫    const newSheets = musicSheets.filter(item => item.id !== sheetId);
265740e3947S猫头猫
266740e3947S猫头猫    // 写入存储
267740e3947S猫头猫    storage.removeMusicList(sheetId);
268740e3947S猫头猫    await storage.setSheets(newSheets);
269740e3947S猫头猫
270740e3947S猫头猫    // 修改状态
271740e3947S猫头猫    getDefaultStore().set(musicSheetsBaseAtom, newSheets);
272740e3947S猫头猫    musicListMap.delete(sheetId);
273740e3947S猫头猫}
274740e3947S猫头猫
275740e3947S猫头猫/**
276740e3947S猫头猫 * 向歌单内添加音乐
277740e3947S猫头猫 * @param sheetId 歌单id
278740e3947S猫头猫 * @param musicItem 音乐
279740e3947S猫头猫 */
280740e3947S猫头猫async function addMusic(
281740e3947S猫头猫    sheetId: string,
282740e3947S猫头猫    musicItem: IMusic.IMusicItem | Array<IMusic.IMusicItem>,
283740e3947S猫头猫) {
284740e3947S猫头猫    const now = Date.now();
285740e3947S猫头猫    if (!Array.isArray(musicItem)) {
286740e3947S猫头猫        musicItem = [musicItem];
287740e3947S猫头猫    }
288740e3947S猫头猫    const taggedMusicItems = musicItem.map((it, index) => ({
289740e3947S猫头猫        ...it,
290740e3947S猫头猫        $timestamp: now,
291740e3947S猫头猫        $sortIndex: musicItem.length - index,
292740e3947S猫头猫    }));
293740e3947S猫头猫
294740e3947S猫头猫    let musicList = getSortedMusicListBySheetId(sheetId);
295740e3947S猫头猫
296740e3947S猫头猫    const addedCount = musicList.add(taggedMusicItems);
297740e3947S猫头猫
298740e3947S猫头猫    // Update
299740e3947S猫头猫    if (!addedCount) {
300740e3947S猫头猫        return;
301740e3947S猫头猫    }
302740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
303740e3947S猫头猫    if (
304740e3947S猫头猫        !musicSheets
305740e3947S猫头猫            .find(_ => _.id === sheetId)
306740e3947S猫头猫            ?.coverImg?.startsWith('file://')
307740e3947S猫头猫    ) {
308740e3947S猫头猫        await updateMusicSheetBase(sheetId, {
309740e3947S猫头猫            coverImg: musicList.at(0)?.artwork,
310740e3947S猫头猫        });
311740e3947S猫头猫    }
312740e3947S猫头猫
313740e3947S猫头猫    // 更新音乐数量
314740e3947S猫头猫    getDefaultStore().set(
315740e3947S猫头猫        musicSheetsBaseAtom,
316740e3947S猫头猫        produce(draft => {
317740e3947S猫头猫            const musicSheet = draft.find(it => it.id === sheetId);
318740e3947S猫头猫            if (musicSheet) {
319740e3947S猫头猫                musicSheet.worksNum = musicList.length;
320740e3947S猫头猫            }
321740e3947S猫头猫        }),
322740e3947S猫头猫    );
323740e3947S猫头猫
324740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
325740e3947S猫头猫    ee.emit('UpdateMusicList', {
326740e3947S猫头猫        sheetId,
327740e3947S猫头猫        updateType: 'length',
328740e3947S猫头猫    });
329740e3947S猫头猫}
330740e3947S猫头猫
331740e3947S猫头猫async function removeMusicByIndex(sheetId: string, indices: number | number[]) {
332740e3947S猫头猫    if (!Array.isArray(indices)) {
333740e3947S猫头猫        indices = [indices];
334740e3947S猫头猫    }
335740e3947S猫头猫
336740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
337740e3947S猫头猫
338740e3947S猫头猫    musicList.removeByIndex(indices);
339740e3947S猫头猫
340740e3947S猫头猫    // Update
341740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
342740e3947S猫头猫    if (
343740e3947S猫头猫        !musicSheets
344740e3947S猫头猫            .find(_ => _.id === sheetId)
345740e3947S猫头猫            ?.coverImg?.startsWith('file://')
346740e3947S猫头猫    ) {
347740e3947S猫头猫        await updateMusicSheetBase(sheetId, {
348740e3947S猫头猫            coverImg: musicList.at(0)?.artwork,
349740e3947S猫头猫        });
350740e3947S猫头猫    }
351740e3947S猫头猫    // 更新音乐数量
352740e3947S猫头猫    getDefaultStore().set(
353740e3947S猫头猫        musicSheetsBaseAtom,
354740e3947S猫头猫        produce(draft => {
355740e3947S猫头猫            const musicSheet = draft.find(it => it.id === sheetId);
356740e3947S猫头猫            if (musicSheet) {
357740e3947S猫头猫                musicSheet.worksNum = musicList.length;
358740e3947S猫头猫            }
359740e3947S猫头猫        }),
360740e3947S猫头猫    );
361740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
362740e3947S猫头猫    ee.emit('UpdateMusicList', {
363740e3947S猫头猫        sheetId,
364740e3947S猫头猫        updateType: 'length',
365740e3947S猫头猫    });
366740e3947S猫头猫}
367740e3947S猫头猫
368740e3947S猫头猫async function removeMusic(
369740e3947S猫头猫    sheetId: string,
370740e3947S猫头猫    musicItems: IMusic.IMusicItem | IMusic.IMusicItem[],
371740e3947S猫头猫) {
372740e3947S猫头猫    if (!Array.isArray(musicItems)) {
373740e3947S猫头猫        musicItems = [musicItems];
374740e3947S猫头猫    }
375740e3947S猫头猫
376740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
377740e3947S猫头猫    musicList.remove(musicItems);
378740e3947S猫头猫
379740e3947S猫头猫    // Update
380740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
381915d90f1S猫头猫
382915d90f1S猫头猫    let patchData: Partial<IMusic.IMusicSheetItemBase> = {};
383740e3947S猫头猫    if (
384740e3947S猫头猫        !musicSheets
385740e3947S猫头猫            .find(_ => _.id === sheetId)
386740e3947S猫头猫            ?.coverImg?.startsWith('file://')
387740e3947S猫头猫    ) {
388915d90f1S猫头猫        patchData.coverImg = musicList.at(0)?.artwork;
389915d90f1S猫头猫    }
390915d90f1S猫头猫    patchData.worksNum = musicList.length;
391740e3947S猫头猫    await updateMusicSheetBase(sheetId, {
392740e3947S猫头猫        coverImg: musicList.at(0)?.artwork,
393740e3947S猫头猫    });
394915d90f1S猫头猫
395740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
396740e3947S猫头猫    ee.emit('UpdateMusicList', {
397740e3947S猫头猫        sheetId,
398740e3947S猫头猫        updateType: 'length',
399740e3947S猫头猫    });
400740e3947S猫头猫}
401740e3947S猫头猫
402740e3947S猫头猫async function setSortType(sheetId: string, sortType: SortType) {
403740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
404740e3947S猫头猫    musicList.setSortType(sortType);
405740e3947S猫头猫
406740e3947S猫头猫    // update
407740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
408740e3947S猫头猫    storage.setSheetMeta(sheetId, 'sort', sortType);
409740e3947S猫头猫    ee.emit('UpdateMusicList', {
410740e3947S猫头猫        sheetId,
411740e3947S猫头猫        updateType: 'resort',
412740e3947S猫头猫    });
413740e3947S猫头猫}
414740e3947S猫头猫
415740e3947S猫头猫async function manualSort(
416740e3947S猫头猫    sheetId: string,
417740e3947S猫头猫    musicListAfterSort: IMusic.IMusicItem[],
418740e3947S猫头猫) {
419740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
420740e3947S猫头猫    musicList.manualSort(musicListAfterSort);
421740e3947S猫头猫
422740e3947S猫头猫    // update
423740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
424740e3947S猫头猫    storage.setSheetMeta(sheetId, 'sort', SortType.None);
425740e3947S猫头猫
426740e3947S猫头猫    ee.emit('UpdateMusicList', {
427740e3947S猫头猫        sheetId,
428740e3947S猫头猫        updateType: 'resort',
429740e3947S猫头猫    });
430740e3947S猫头猫}
431740e3947S猫头猫
432740e3947S猫头猫function useSheetsBase() {
433740e3947S猫头猫    return useAtomValue(musicSheetsBaseAtom);
434740e3947S猫头猫}
435740e3947S猫头猫
436740e3947S猫头猫// sheetId should not change
437740e3947S猫头猫function useSheetItem(sheetId: string) {
438740e3947S猫头猫    const sheetsBase = useAtomValue(musicSheetsBaseAtom);
439740e3947S猫头猫
440740e3947S猫头猫    const [sheetItem, setSheetItem] = useState<IMusic.IMusicSheetItem>({
441740e3947S猫头猫        ...(sheetsBase.find(it => it.id === sheetId) ||
442740e3947S猫头猫            ({} as IMusic.IMusicSheetItemBase)),
443740e3947S猫头猫        musicList: musicListMap.get(sheetId)?.musicList || [],
444740e3947S猫头猫    });
445740e3947S猫头猫
446740e3947S猫头猫    useEffect(() => {
447740e3947S猫头猫        const onUpdateMusicList = ({sheetId: updatedSheetId}) => {
448740e3947S猫头猫            if (updatedSheetId !== sheetId) {
449740e3947S猫头猫                return;
450740e3947S猫头猫            }
451740e3947S猫头猫            setSheetItem(prev => ({
452740e3947S猫头猫                ...prev,
453740e3947S猫头猫                musicList: musicListMap.get(sheetId)?.musicList || [],
454740e3947S猫头猫            }));
455740e3947S猫头猫        };
456756bc302S猫头猫
457756bc302S猫头猫        const onUpdateSheetBasic = ({sheetId: updatedSheetId}) => {
458756bc302S猫头猫            if (updatedSheetId !== sheetId) {
459756bc302S猫头猫                return;
460756bc302S猫头猫            }
461756bc302S猫头猫            setSheetItem(prev => ({
462756bc302S猫头猫                ...prev,
463756bc302S猫头猫                ...(getDefaultStore()
464756bc302S猫头猫                    .get(musicSheetsBaseAtom)
465756bc302S猫头猫                    .find(it => it.id === sheetId) || {}),
466756bc302S猫头猫            }));
467756bc302S猫头猫        };
468740e3947S猫头猫        ee.on('UpdateMusicList', onUpdateMusicList);
469756bc302S猫头猫        ee.on('UpdateSheetBasic', onUpdateSheetBasic);
470740e3947S猫头猫
471740e3947S猫头猫        return () => {
472740e3947S猫头猫            ee.off('UpdateMusicList', onUpdateMusicList);
473756bc302S猫头猫            ee.off('UpdateSheetBasic', onUpdateSheetBasic);
474740e3947S猫头猫        };
475740e3947S猫头猫    }, []);
476740e3947S猫头猫
477740e3947S猫头猫    return sheetItem;
478740e3947S猫头猫}
479740e3947S猫头猫
480740e3947S猫头猫function useFavorite(musicItem: IMusic.IMusicItem | null) {
481740e3947S猫头猫    const [fav, setFav] = useState(false);
482740e3947S猫头猫
483740e3947S猫头猫    useEffect(() => {
484740e3947S猫头猫        const onUpdateMusicList = ({sheetId: updatedSheetId, updateType}) => {
485740e3947S猫头猫            if (updatedSheetId !== defaultSheet.id || updateType === 'resort') {
486740e3947S猫头猫                return;
487740e3947S猫头猫            }
488740e3947S猫头猫            setFav(musicListMap.get(defaultSheet.id)?.has(musicItem) || false);
489740e3947S猫头猫        };
490740e3947S猫头猫        ee.on('UpdateMusicList', onUpdateMusicList);
491740e3947S猫头猫
492740e3947S猫头猫        setFav(musicListMap.get(defaultSheet.id)?.has(musicItem) || false);
493740e3947S猫头猫        return () => {
494740e3947S猫头猫            ee.off('UpdateMusicList', onUpdateMusicList);
495740e3947S猫头猫        };
496740e3947S猫头猫    }, [musicItem]);
497740e3947S猫头猫
498740e3947S猫头猫    return fav;
499740e3947S猫头猫}
500740e3947S猫头猫
501740e3947S猫头猫async function setupStarredMusicSheets() {
502740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] =
503740e3947S猫头猫        storage.getStarredSheets() || [];
504740e3947S猫头猫    getDefaultStore().set(starredMusicSheetsAtom, starredSheets);
505740e3947S猫头猫}
506740e3947S猫头猫
507740e3947S猫头猫async function starMusicSheet(musicSheet: IMusic.IMusicSheetItem) {
508740e3947S猫头猫    const store = getDefaultStore();
509740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] = store.get(
510740e3947S猫头猫        starredMusicSheetsAtom,
511740e3947S猫头猫    );
512740e3947S猫头猫
513740e3947S猫头猫    const newVal = [musicSheet, ...starredSheets];
514740e3947S猫头猫
515740e3947S猫头猫    store.set(starredMusicSheetsAtom, newVal);
516740e3947S猫头猫    await storage.setStarredSheets(newVal);
517740e3947S猫头猫}
518740e3947S猫头猫
519740e3947S猫头猫async function unstarMusicSheet(musicSheet: IMusic.IMusicSheetItemBase) {
520740e3947S猫头猫    const store = getDefaultStore();
521740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] = store.get(
522740e3947S猫头猫        starredMusicSheetsAtom,
523740e3947S猫头猫    );
524740e3947S猫头猫
525740e3947S猫头猫    const newVal = starredSheets.filter(
526740e3947S猫头猫        it =>
527740e3947S猫头猫            !isSameMediaItem(
528740e3947S猫头猫                it as ICommon.IMediaBase,
529740e3947S猫头猫                musicSheet as ICommon.IMediaBase,
530740e3947S猫头猫            ),
531740e3947S猫头猫    );
532740e3947S猫头猫    store.set(starredMusicSheetsAtom, newVal);
533740e3947S猫头猫    await storage.setStarredSheets(newVal);
534740e3947S猫头猫}
535740e3947S猫头猫
536740e3947S猫头猫function useSheetIsStarred(
537740e3947S猫头猫    musicSheet: IMusic.IMusicSheetItem | null | undefined,
538740e3947S猫头猫) {
539740e3947S猫头猫    // TODO: 类型有问题
540740e3947S猫头猫    const musicSheets = useAtomValue(starredMusicSheetsAtom);
541740e3947S猫头猫    return useMemo(() => {
542740e3947S猫头猫        if (!musicSheet) {
543740e3947S猫头猫            return false;
544740e3947S猫头猫        }
545740e3947S猫头猫        return (
546740e3947S猫头猫            musicSheets.findIndex(it =>
547740e3947S猫头猫                isSameMediaItem(
548740e3947S猫头猫                    it as ICommon.IMediaBase,
549740e3947S猫头猫                    musicSheet as ICommon.IMediaBase,
550740e3947S猫头猫                ),
551740e3947S猫头猫            ) !== -1
552740e3947S猫头猫        );
553740e3947S猫头猫    }, [musicSheet, musicSheets]);
554740e3947S猫头猫}
555740e3947S猫头猫
556740e3947S猫头猫function useStarredSheets() {
557740e3947S猫头猫    return useAtomValue(starredMusicSheetsAtom);
558740e3947S猫头猫}
559740e3947S猫头猫
560740e3947S猫头猫/********* MusicSheet Meta ****************/
561740e3947S猫头猫
562740e3947S猫头猫const MusicSheet = {
563740e3947S猫头猫    setup,
564740e3947S猫头猫    addSheet,
565740e3947S猫头猫    defaultSheet,
566740e3947S猫头猫    addMusic,
567740e3947S猫头猫    removeSheet,
568740e3947S猫头猫    backupSheets,
569740e3947S猫头猫    resumeSheets,
570740e3947S猫头猫    removeMusicByIndex,
571740e3947S猫头猫    removeMusic,
572740e3947S猫头猫    starMusicSheet,
573740e3947S猫头猫    unstarMusicSheet,
574740e3947S猫头猫    useFavorite,
575740e3947S猫头猫    useSheetsBase,
576740e3947S猫头猫    useSheetItem,
577740e3947S猫头猫    setSortType,
578740e3947S猫头猫    useSheetIsStarred,
579740e3947S猫头猫    useStarredSheets,
580740e3947S猫头猫    updateMusicSheetBase,
581740e3947S猫头猫    manualSort,
582740e3947S猫头猫    getSheetMeta: storage.getSheetMeta,
583740e3947S猫头猫};
584740e3947S猫头猫
585740e3947S猫头猫export default MusicSheet;
586