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