import songlistState, { type TagInfo, type ListDetailInfo, type ListInfo, type ListInfoItem } from '@/store/songlist/state' import songlistActions from '@/store/songlist/action' import { deduplicationList, toNewMusicInfo } from '@/utils' import musicSdk from '@/utils/musicSdk' interface DetailPageCache { data: ListDetailInfo, sourcePage: number } type LimitDetailCache = Map type CacheValue = LimitDetailCache | ListInfo const cache = new Map() const LIST_LOAD_LIMIT = 30 /** * 设置要打开的歌单详情信息 * @param source * @returns */ export const setSelectListInfo = (info: ListInfoItem) => { songlistActions.clearListDetail() songlistActions.setSelectListInfo(info) } /** * 获取排序列表 * @param source * @returns */ export const getSortList = (source: LX.OnlineSource) => { return songlistState.sortList[source]! } /** * 获取标签列表 * @param source * @returns */ export const getTags = async(source: T) => { if (songlistState.tags[source]) return songlistState.tags[source] as TagInfo const info = await (musicSdk[source]?.songList.getTags() as Promise>) songlistActions.setTags(info, source) return info } /** * 设置列表加载加载前的基本信息(用于加载失败后的重新加载) * @param source * @param tagId * @param sortId */ export const setListInfo: typeof songlistActions.setListInfo = (source, tagId, sortId) => { clearList() songlistActions.setListInfo(source, tagId, sortId) } /** * 设置列表信息 * @param result * @param tagId * @param sortId * @param page * @returns */ export const setList: typeof songlistActions.setList = (result, tagId, sortId, page) => { return songlistActions.setList(result, tagId, sortId, page) } export const clearList = () => { songlistActions.clearList() } /** * 获取歌单列表 * @param source 歌单源 * @param tabId 类型id * @param sortId 排序 * @param page 页数 * @param isRefresh 是否跳过缓存 * @returns */ export const getList = async(source: LX.OnlineSource, tabId: string, sortId: string, page: number, isRefresh = false): Promise => { let pageKey = `slist__${source}__${sortId}__${tabId}__${page}` let listCache = cache.get(pageKey) as ListInfo if (listCache) { if (isRefresh) cache.delete(pageKey) else return listCache } return musicSdk[source]?.songList.getList(sortId, tabId, page).then((result: ListInfo) => { cache.set(pageKey, result) return result // if (pageKey != listInfo.key) return // setList(result, tabId, sortId, page) }) } /** * 获取歌单详情内单页分页歌曲(用于在本地控制每页大小) * @param source 源 * @param id 歌单id * @param page 页数 * @returns */ const getListDetailLimit = async(source: LX.OnlineSource, id: string, page: number): Promise => { const listKey = `sdetail__${source}__${id}` const prevPageKey = `sdetail__${source}__${id}__${page - 1}` const tempListKey = `sdetail__${source}__${id}__temp` let listCache = cache.get(listKey) as LimitDetailCache if (!listCache) cache.set(listKey, listCache = new Map()) let sourcePage = 0 { const prevPageData = listCache.get(prevPageKey) as DetailPageCache if (prevPageData) sourcePage = prevPageData.sourcePage } return musicSdk[source]?.songList.getListDetail(id, sourcePage + 1).then((result: ListDetailInfo) => { if (listCache !== cache.get(listKey)) return result.list = deduplicationList(result.list.map(m => toNewMusicInfo(m)) as LX.Music.MusicInfoOnline[]) let p = page const tempList = listCache.get(tempListKey) as ListDetailInfo['list'] if (tempList) { listCache.delete(tempListKey) listCache.set(`sdetail__${source}__${id}__${p}`, { data: { ...result, list: [...tempList, ...result.list.splice(0, LIST_LOAD_LIMIT - tempList.length)], page: p, limit: LIST_LOAD_LIMIT, }, sourcePage, }) p++ } sourcePage++ do { if (result.list.length < LIST_LOAD_LIMIT && sourcePage < Math.ceil(result.total / result.limit)) { listCache.set(tempListKey, result.list.splice(0, LIST_LOAD_LIMIT)) break } listCache.set(`sdetail__${source}__${id}__${p}`, { data: { ...result, list: result.list.splice(0, LIST_LOAD_LIMIT), page: p, limit: LIST_LOAD_LIMIT, }, sourcePage, }) p++ } while (result.list.length > 0) return (listCache.get(`sdetail__${source}__${id}__${page}`) as DetailPageCache).data }) ?? Promise.reject(new Error('source not found')) } /** * 设置列表加载加载前的基本信息(用于加载失败后的重新加载) * @param source * @param tagId * @param sortId */ export const setListDetailInfo: typeof songlistActions.setListDetailInfo = (source, id) => { clearListDetail() songlistActions.setListDetailInfo(source, id) } export const setListDetail: typeof songlistActions.setListDetail = (result, id, page) => { return songlistActions.setListDetail(result, id, page) } export const clearListDetail = () => { songlistActions.clearListDetail() } /** * 获取歌单内单页歌曲 * @param id 歌单id * @param source 歌单源 * @param isRefresh 是否跳过缓存 * @returns */ export const getListDetail = async(id: string, source: LX.OnlineSource, page: number, isRefresh = false): Promise => { const listKey = `sdetail__${source}__${id}` const pageKey = `sdetail__${source}__${id}__${page}` let listCache = cache.get(listKey) as LimitDetailCache if (!listCache || isRefresh) { cache.set(listKey, listCache = new Map()) } let pageCache = listCache.get(pageKey) as DetailPageCache if (pageCache) return pageCache.data return getListDetailLimit(source, id, page) } /** * 获取歌单内全部歌曲 * @param id 歌单id * @param source 歌单源 * @param isRefresh 是否跳过缓存 * @returns */ export const getListDetailAll = async(source: LX.OnlineSource, id: string, isRefresh = false): Promise => { // console.log(tabId) const listKey = `sdetail__${source}__${id}` let listCache = cache.get(listKey) as LimitDetailCache if (!listCache || isRefresh) { cache.set(listKey, listCache = new Map()) } const loadData = async(page: number): Promise => { const pageKey = `sdetail__${source}__${id}__${page}` let pageCache = listCache.get(pageKey) as DetailPageCache if (pageCache) return pageCache.data return getListDetailLimit(source, id, page) } return loadData(1).then(async result => { if (result.total <= result.limit) return result.list let maxPage = Math.ceil(result.total / result.limit) const loadDetail = async(loadPage = 2): Promise => { return loadPage == maxPage ? loadData(loadPage).then(result => result.list) // eslint-disable-next-line @typescript-eslint/promise-function-async : loadData(loadPage).then(result1 => loadDetail(++loadPage).then(result2 => [...result1.list, ...result2])) } return loadDetail().then(result2 => [...result.list, ...result2]) }).then(list => deduplicationList(list)) }