xref: /MusicFree/src/core/musicSheet/index.ts (revision 756bc302d40f6f21e72cdfca8580b52a8341d658)
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';
16740e3947S猫头猫import {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);
139*756bc302S猫头猫    ee.emit('UpdateSheetBasic', {
140*756bc302S猫头猫        sheetId,
141*756bc302S猫头猫    });
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[],
190740e3947S猫头猫    overwrite?: boolean,
191740e3947S猫头猫) {
192740e3947S猫头猫    // 1. 分离默认歌单和其他歌单
193740e3947S猫头猫    const defaultSheetIndex = sheets.findIndex(it => it.id === defaultSheet.id);
194740e3947S猫头猫
195740e3947S猫头猫    let exportedDefaultSheet: IMusic.IMusicSheetItem | null = null;
196740e3947S猫头猫
197740e3947S猫头猫    if (defaultSheetIndex !== -1) {
198740e3947S猫头猫        exportedDefaultSheet = sheets.splice(defaultSheetIndex, 1)[0];
199740e3947S猫头猫    }
200740e3947S猫头猫
201740e3947S猫头猫    // 逆序恢复,最新创建的在最上方
202740e3947S猫头猫    for (let i = sheets.length - 1; i >= 0; --i) {
203740e3947S猫头猫        const newSheetId = await addSheet(sheets[i].title || '');
204740e3947S猫头猫        await addMusic(newSheetId, sheets[i].musicList || []);
205740e3947S猫头猫    }
206740e3947S猫头猫
207740e3947S猫头猫    if (overwrite) {
208740e3947S猫头猫        await addMusic(defaultSheet.id, exportedDefaultSheet?.musicList || []);
209740e3947S猫头猫    } else {
210740e3947S猫头猫        const newSheetId = await addSheet(
211740e3947S猫头猫            exportedDefaultSheet?.title || defaultSheet.title!,
212740e3947S猫头猫        );
213740e3947S猫头猫        await addMusic(newSheetId, exportedDefaultSheet?.musicList || []);
214740e3947S猫头猫    }
215740e3947S猫头猫}
216740e3947S猫头猫
217740e3947S猫头猫function backupSheets() {
218740e3947S猫头猫    const allSheets = getDefaultStore().get(musicSheetsBaseAtom);
219740e3947S猫头猫    return allSheets.map(it => ({
220740e3947S猫头猫        ...it,
221740e3947S猫头猫        musicList: musicListMap.get(it.id)?.musicList || [],
222740e3947S猫头猫    })) as IMusic.IMusicSheetItem[];
223740e3947S猫头猫}
224740e3947S猫头猫
225740e3947S猫头猫/**
226740e3947S猫头猫 * 删除歌单
227740e3947S猫头猫 * @param sheetId 歌单id
228740e3947S猫头猫 */
229740e3947S猫头猫async function removeSheet(sheetId: string) {
230740e3947S猫头猫    // 只能删除非默认歌单
231740e3947S猫头猫    if (sheetId === defaultSheet.id) {
232740e3947S猫头猫        return;
233740e3947S猫头猫    }
234740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
235740e3947S猫头猫
236740e3947S猫头猫    // 删除后的歌单
237740e3947S猫头猫    const newSheets = musicSheets.filter(item => item.id !== sheetId);
238740e3947S猫头猫
239740e3947S猫头猫    // 写入存储
240740e3947S猫头猫    storage.removeMusicList(sheetId);
241740e3947S猫头猫    await storage.setSheets(newSheets);
242740e3947S猫头猫
243740e3947S猫头猫    // 修改状态
244740e3947S猫头猫    getDefaultStore().set(musicSheetsBaseAtom, newSheets);
245740e3947S猫头猫    musicListMap.delete(sheetId);
246740e3947S猫头猫}
247740e3947S猫头猫
248740e3947S猫头猫/**
249740e3947S猫头猫 * 向歌单内添加音乐
250740e3947S猫头猫 * @param sheetId 歌单id
251740e3947S猫头猫 * @param musicItem 音乐
252740e3947S猫头猫 */
253740e3947S猫头猫async function addMusic(
254740e3947S猫头猫    sheetId: string,
255740e3947S猫头猫    musicItem: IMusic.IMusicItem | Array<IMusic.IMusicItem>,
256740e3947S猫头猫) {
257740e3947S猫头猫    const now = Date.now();
258740e3947S猫头猫    if (!Array.isArray(musicItem)) {
259740e3947S猫头猫        musicItem = [musicItem];
260740e3947S猫头猫    }
261740e3947S猫头猫    const taggedMusicItems = musicItem.map((it, index) => ({
262740e3947S猫头猫        ...it,
263740e3947S猫头猫        $timestamp: now,
264740e3947S猫头猫        $sortIndex: musicItem.length - index,
265740e3947S猫头猫    }));
266740e3947S猫头猫
267740e3947S猫头猫    let musicList = getSortedMusicListBySheetId(sheetId);
268740e3947S猫头猫
269740e3947S猫头猫    const addedCount = musicList.add(taggedMusicItems);
270740e3947S猫头猫
271740e3947S猫头猫    // Update
272740e3947S猫头猫    if (!addedCount) {
273740e3947S猫头猫        return;
274740e3947S猫头猫    }
275740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
276740e3947S猫头猫    if (
277740e3947S猫头猫        !musicSheets
278740e3947S猫头猫            .find(_ => _.id === sheetId)
279740e3947S猫头猫            ?.coverImg?.startsWith('file://')
280740e3947S猫头猫    ) {
281740e3947S猫头猫        await updateMusicSheetBase(sheetId, {
282740e3947S猫头猫            coverImg: musicList.at(0)?.artwork,
283740e3947S猫头猫        });
284740e3947S猫头猫    }
285740e3947S猫头猫
286740e3947S猫头猫    // 更新音乐数量
287740e3947S猫头猫    getDefaultStore().set(
288740e3947S猫头猫        musicSheetsBaseAtom,
289740e3947S猫头猫        produce(draft => {
290740e3947S猫头猫            const musicSheet = draft.find(it => it.id === sheetId);
291740e3947S猫头猫            if (musicSheet) {
292740e3947S猫头猫                musicSheet.worksNum = musicList.length;
293740e3947S猫头猫            }
294740e3947S猫头猫        }),
295740e3947S猫头猫    );
296740e3947S猫头猫
297740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
298740e3947S猫头猫    ee.emit('UpdateMusicList', {
299740e3947S猫头猫        sheetId,
300740e3947S猫头猫        updateType: 'length',
301740e3947S猫头猫    });
302740e3947S猫头猫}
303740e3947S猫头猫
304740e3947S猫头猫async function removeMusicByIndex(sheetId: string, indices: number | number[]) {
305740e3947S猫头猫    if (!Array.isArray(indices)) {
306740e3947S猫头猫        indices = [indices];
307740e3947S猫头猫    }
308740e3947S猫头猫
309740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
310740e3947S猫头猫
311740e3947S猫头猫    musicList.removeByIndex(indices);
312740e3947S猫头猫
313740e3947S猫头猫    // Update
314740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
315740e3947S猫头猫    if (
316740e3947S猫头猫        !musicSheets
317740e3947S猫头猫            .find(_ => _.id === sheetId)
318740e3947S猫头猫            ?.coverImg?.startsWith('file://')
319740e3947S猫头猫    ) {
320740e3947S猫头猫        await updateMusicSheetBase(sheetId, {
321740e3947S猫头猫            coverImg: musicList.at(0)?.artwork,
322740e3947S猫头猫        });
323740e3947S猫头猫    }
324740e3947S猫头猫    // 更新音乐数量
325740e3947S猫头猫    getDefaultStore().set(
326740e3947S猫头猫        musicSheetsBaseAtom,
327740e3947S猫头猫        produce(draft => {
328740e3947S猫头猫            const musicSheet = draft.find(it => it.id === sheetId);
329740e3947S猫头猫            if (musicSheet) {
330740e3947S猫头猫                musicSheet.worksNum = musicList.length;
331740e3947S猫头猫            }
332740e3947S猫头猫        }),
333740e3947S猫头猫    );
334740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
335740e3947S猫头猫    ee.emit('UpdateMusicList', {
336740e3947S猫头猫        sheetId,
337740e3947S猫头猫        updateType: 'length',
338740e3947S猫头猫    });
339740e3947S猫头猫}
340740e3947S猫头猫
341740e3947S猫头猫async function removeMusic(
342740e3947S猫头猫    sheetId: string,
343740e3947S猫头猫    musicItems: IMusic.IMusicItem | IMusic.IMusicItem[],
344740e3947S猫头猫) {
345740e3947S猫头猫    if (!Array.isArray(musicItems)) {
346740e3947S猫头猫        musicItems = [musicItems];
347740e3947S猫头猫    }
348740e3947S猫头猫
349740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
350740e3947S猫头猫    musicList.remove(musicItems);
351740e3947S猫头猫
352740e3947S猫头猫    // Update
353740e3947S猫头猫    const musicSheets = getDefaultStore().get(musicSheetsBaseAtom);
354915d90f1S猫头猫
355915d90f1S猫头猫    let patchData: Partial<IMusic.IMusicSheetItemBase> = {};
356740e3947S猫头猫    if (
357740e3947S猫头猫        !musicSheets
358740e3947S猫头猫            .find(_ => _.id === sheetId)
359740e3947S猫头猫            ?.coverImg?.startsWith('file://')
360740e3947S猫头猫    ) {
361915d90f1S猫头猫        patchData.coverImg = musicList.at(0)?.artwork;
362915d90f1S猫头猫    }
363915d90f1S猫头猫    patchData.worksNum = musicList.length;
364740e3947S猫头猫    await updateMusicSheetBase(sheetId, {
365740e3947S猫头猫        coverImg: musicList.at(0)?.artwork,
366740e3947S猫头猫    });
367915d90f1S猫头猫
368740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
369740e3947S猫头猫    ee.emit('UpdateMusicList', {
370740e3947S猫头猫        sheetId,
371740e3947S猫头猫        updateType: 'length',
372740e3947S猫头猫    });
373740e3947S猫头猫}
374740e3947S猫头猫
375740e3947S猫头猫async function setSortType(sheetId: string, sortType: SortType) {
376740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
377740e3947S猫头猫    musicList.setSortType(sortType);
378740e3947S猫头猫
379740e3947S猫头猫    // update
380740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
381740e3947S猫头猫    storage.setSheetMeta(sheetId, 'sort', sortType);
382740e3947S猫头猫    ee.emit('UpdateMusicList', {
383740e3947S猫头猫        sheetId,
384740e3947S猫头猫        updateType: 'resort',
385740e3947S猫头猫    });
386740e3947S猫头猫}
387740e3947S猫头猫
388740e3947S猫头猫async function manualSort(
389740e3947S猫头猫    sheetId: string,
390740e3947S猫头猫    musicListAfterSort: IMusic.IMusicItem[],
391740e3947S猫头猫) {
392740e3947S猫头猫    const musicList = getSortedMusicListBySheetId(sheetId);
393740e3947S猫头猫    musicList.manualSort(musicListAfterSort);
394740e3947S猫头猫
395740e3947S猫头猫    // update
396740e3947S猫头猫    await storage.setMusicList(sheetId, musicList.musicList);
397740e3947S猫头猫    storage.setSheetMeta(sheetId, 'sort', SortType.None);
398740e3947S猫头猫
399740e3947S猫头猫    ee.emit('UpdateMusicList', {
400740e3947S猫头猫        sheetId,
401740e3947S猫头猫        updateType: 'resort',
402740e3947S猫头猫    });
403740e3947S猫头猫}
404740e3947S猫头猫
405740e3947S猫头猫function useSheetsBase() {
406740e3947S猫头猫    return useAtomValue(musicSheetsBaseAtom);
407740e3947S猫头猫}
408740e3947S猫头猫
409740e3947S猫头猫// sheetId should not change
410740e3947S猫头猫function useSheetItem(sheetId: string) {
411740e3947S猫头猫    const sheetsBase = useAtomValue(musicSheetsBaseAtom);
412740e3947S猫头猫
413740e3947S猫头猫    const [sheetItem, setSheetItem] = useState<IMusic.IMusicSheetItem>({
414740e3947S猫头猫        ...(sheetsBase.find(it => it.id === sheetId) ||
415740e3947S猫头猫            ({} as IMusic.IMusicSheetItemBase)),
416740e3947S猫头猫        musicList: musicListMap.get(sheetId)?.musicList || [],
417740e3947S猫头猫    });
418740e3947S猫头猫
419740e3947S猫头猫    useEffect(() => {
420740e3947S猫头猫        const onUpdateMusicList = ({sheetId: updatedSheetId}) => {
421740e3947S猫头猫            if (updatedSheetId !== sheetId) {
422740e3947S猫头猫                return;
423740e3947S猫头猫            }
424740e3947S猫头猫            setSheetItem(prev => ({
425740e3947S猫头猫                ...prev,
426740e3947S猫头猫                musicList: musicListMap.get(sheetId)?.musicList || [],
427740e3947S猫头猫            }));
428740e3947S猫头猫        };
429*756bc302S猫头猫
430*756bc302S猫头猫        const onUpdateSheetBasic = ({sheetId: updatedSheetId}) => {
431*756bc302S猫头猫            if (updatedSheetId !== sheetId) {
432*756bc302S猫头猫                return;
433*756bc302S猫头猫            }
434*756bc302S猫头猫            setSheetItem(prev => ({
435*756bc302S猫头猫                ...prev,
436*756bc302S猫头猫                ...(getDefaultStore()
437*756bc302S猫头猫                    .get(musicSheetsBaseAtom)
438*756bc302S猫头猫                    .find(it => it.id === sheetId) || {}),
439*756bc302S猫头猫            }));
440*756bc302S猫头猫        };
441740e3947S猫头猫        ee.on('UpdateMusicList', onUpdateMusicList);
442*756bc302S猫头猫        ee.on('UpdateSheetBasic', onUpdateSheetBasic);
443740e3947S猫头猫
444740e3947S猫头猫        return () => {
445740e3947S猫头猫            ee.off('UpdateMusicList', onUpdateMusicList);
446*756bc302S猫头猫            ee.off('UpdateSheetBasic', onUpdateSheetBasic);
447740e3947S猫头猫        };
448740e3947S猫头猫    }, []);
449740e3947S猫头猫
450740e3947S猫头猫    return sheetItem;
451740e3947S猫头猫}
452740e3947S猫头猫
453740e3947S猫头猫function useFavorite(musicItem: IMusic.IMusicItem | null) {
454740e3947S猫头猫    const [fav, setFav] = useState(false);
455740e3947S猫头猫
456740e3947S猫头猫    useEffect(() => {
457740e3947S猫头猫        const onUpdateMusicList = ({sheetId: updatedSheetId, updateType}) => {
458740e3947S猫头猫            if (updatedSheetId !== defaultSheet.id || updateType === 'resort') {
459740e3947S猫头猫                return;
460740e3947S猫头猫            }
461740e3947S猫头猫            setFav(musicListMap.get(defaultSheet.id)?.has(musicItem) || false);
462740e3947S猫头猫        };
463740e3947S猫头猫        ee.on('UpdateMusicList', onUpdateMusicList);
464740e3947S猫头猫
465740e3947S猫头猫        setFav(musicListMap.get(defaultSheet.id)?.has(musicItem) || false);
466740e3947S猫头猫        return () => {
467740e3947S猫头猫            ee.off('UpdateMusicList', onUpdateMusicList);
468740e3947S猫头猫        };
469740e3947S猫头猫    }, [musicItem]);
470740e3947S猫头猫
471740e3947S猫头猫    return fav;
472740e3947S猫头猫}
473740e3947S猫头猫
474740e3947S猫头猫async function setupStarredMusicSheets() {
475740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] =
476740e3947S猫头猫        storage.getStarredSheets() || [];
477740e3947S猫头猫    getDefaultStore().set(starredMusicSheetsAtom, starredSheets);
478740e3947S猫头猫}
479740e3947S猫头猫
480740e3947S猫头猫async function starMusicSheet(musicSheet: IMusic.IMusicSheetItem) {
481740e3947S猫头猫    const store = getDefaultStore();
482740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] = store.get(
483740e3947S猫头猫        starredMusicSheetsAtom,
484740e3947S猫头猫    );
485740e3947S猫头猫
486740e3947S猫头猫    const newVal = [musicSheet, ...starredSheets];
487740e3947S猫头猫
488740e3947S猫头猫    store.set(starredMusicSheetsAtom, newVal);
489740e3947S猫头猫    await storage.setStarredSheets(newVal);
490740e3947S猫头猫}
491740e3947S猫头猫
492740e3947S猫头猫async function unstarMusicSheet(musicSheet: IMusic.IMusicSheetItemBase) {
493740e3947S猫头猫    const store = getDefaultStore();
494740e3947S猫头猫    const starredSheets: IMusic.IMusicSheetItem[] = store.get(
495740e3947S猫头猫        starredMusicSheetsAtom,
496740e3947S猫头猫    );
497740e3947S猫头猫
498740e3947S猫头猫    const newVal = starredSheets.filter(
499740e3947S猫头猫        it =>
500740e3947S猫头猫            !isSameMediaItem(
501740e3947S猫头猫                it as ICommon.IMediaBase,
502740e3947S猫头猫                musicSheet as ICommon.IMediaBase,
503740e3947S猫头猫            ),
504740e3947S猫头猫    );
505740e3947S猫头猫    store.set(starredMusicSheetsAtom, newVal);
506740e3947S猫头猫    await storage.setStarredSheets(newVal);
507740e3947S猫头猫}
508740e3947S猫头猫
509740e3947S猫头猫function useSheetIsStarred(
510740e3947S猫头猫    musicSheet: IMusic.IMusicSheetItem | null | undefined,
511740e3947S猫头猫) {
512740e3947S猫头猫    // TODO: 类型有问题
513740e3947S猫头猫    const musicSheets = useAtomValue(starredMusicSheetsAtom);
514740e3947S猫头猫    return useMemo(() => {
515740e3947S猫头猫        if (!musicSheet) {
516740e3947S猫头猫            return false;
517740e3947S猫头猫        }
518740e3947S猫头猫        return (
519740e3947S猫头猫            musicSheets.findIndex(it =>
520740e3947S猫头猫                isSameMediaItem(
521740e3947S猫头猫                    it as ICommon.IMediaBase,
522740e3947S猫头猫                    musicSheet as ICommon.IMediaBase,
523740e3947S猫头猫                ),
524740e3947S猫头猫            ) !== -1
525740e3947S猫头猫        );
526740e3947S猫头猫    }, [musicSheet, musicSheets]);
527740e3947S猫头猫}
528740e3947S猫头猫
529740e3947S猫头猫function useStarredSheets() {
530740e3947S猫头猫    return useAtomValue(starredMusicSheetsAtom);
531740e3947S猫头猫}
532740e3947S猫头猫
533740e3947S猫头猫/********* MusicSheet Meta ****************/
534740e3947S猫头猫
535740e3947S猫头猫const MusicSheet = {
536740e3947S猫头猫    setup,
537740e3947S猫头猫    addSheet,
538740e3947S猫头猫    defaultSheet,
539740e3947S猫头猫    addMusic,
540740e3947S猫头猫    removeSheet,
541740e3947S猫头猫    backupSheets,
542740e3947S猫头猫    resumeSheets,
543740e3947S猫头猫    removeMusicByIndex,
544740e3947S猫头猫    removeMusic,
545740e3947S猫头猫    starMusicSheet,
546740e3947S猫头猫    unstarMusicSheet,
547740e3947S猫头猫    useFavorite,
548740e3947S猫头猫    useSheetsBase,
549740e3947S猫头猫    useSheetItem,
550740e3947S猫头猫    setSortType,
551740e3947S猫头猫    useSheetIsStarred,
552740e3947S猫头猫    useStarredSheets,
553740e3947S猫头猫    updateMusicSheetBase,
554740e3947S猫头猫    manualSort,
555740e3947S猫头猫    getSheetMeta: storage.getSheetMeta,
556740e3947S猫头猫};
557740e3947S猫头猫
558740e3947S猫头猫export default MusicSheet;
559