1import {pluginManager, usePlugins} from '@/common/pluginManager'; 2import produce from 'immer'; 3import {useAtom, useSetAtom} from 'jotai'; 4import {useCallback} from 'react'; 5import {PageStatus, pageStatusAtom, searchResultsAtom} from '../store/atoms'; 6 7export default function useSearch() { 8 const setPageStatus = useSetAtom(pageStatusAtom); 9 const [searchResults, setSearchResults] = useAtom(searchResultsAtom); 10 11 const search = useCallback( 12 async function ( 13 query?: string, 14 platformHash = 'all', 15 queryPage = undefined, 16 ) { 17 // 如果没有搜索结果缓存,那就是没有搜过 18 const installedPlugins = pluginManager.getValidPlugins(); 19 const plugins = 20 platformHash === 'all' 21 ? installedPlugins 22 : [installedPlugins.find(_ => _.hash === platformHash)]; 23 plugins.forEach(async plugin => { 24 const _platform = plugin?.instance.platform; 25 const _hash = plugin?.hash; 26 if (!plugin || !_platform || !_hash) { 27 // 没有插件,此时直接进入结果页 28 setPageStatus(PageStatus.RESULT); 29 return; 30 } 31 const _prevResult = searchResults[_hash] ?? {}; 32 if (_prevResult.state === 'pending' || _prevResult.state === 'done') { 33 return; 34 } 35 36 const newSearch = 37 query || _prevResult?.currentPage === undefined || queryPage === 1; 38 query = query ?? _prevResult?.query ?? ''; 39 const page = 40 queryPage ?? newSearch ? 1 : (_prevResult.currentPage ?? 0) + 1; 41 42 try { 43 setSearchResults(prevState => 44 produce(prevState, draft => { 45 const prev = draft[_hash] ?? {}; 46 prev.query = query; 47 prev.state = 'pending'; 48 prev.result = newSearch ? {} : prev.result 49 draft[_hash] = prev; 50 }), 51 ); 52 // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。 53 const result = await plugin?.instance?.search?.(query, page); 54 setPageStatus(PageStatus.RESULT); 55 if (!result) { 56 throw new Error(); 57 } 58 setSearchResults( 59 produce(draft => { 60 const prev = draft[_hash] ?? {}; 61 if (result._isEnd === false) { 62 prev.state = 'resolved'; 63 } else { 64 prev.state = 'done'; 65 } 66 prev.result = newSearch 67 ? mergeResult(result, {}, _platform) 68 : mergeResult(prev.result ?? {}, result ?? {}, _platform); 69 draft[_hash] = { 70 state: prev.state, 71 result: prev.result, 72 query: query, 73 currentPage: page, 74 }; 75 return draft; 76 }), 77 ); 78 } catch (e) { 79 console.log('SEARCH ERROR', e); 80 setSearchResults( 81 produce(draft => { 82 const prev = draft[_hash] ?? {}; 83 prev.state = 'resolved'; 84 draft[_hash] = prev; 85 }), 86 ); 87 } 88 }); 89 }, 90 [searchResults], 91 ); 92 93 return search; 94} 95 96// todo: 去重 97const resultKeys: (keyof IPlugin.ISearchResult)[] = ['album', 'music']; 98function mergeResult( 99 obj1: Record<string, any>, 100 obj2: Record<string, any>, 101 platform: string, 102): IPlugin.ISearchResult { 103 const result: Record<string, any> = {}; 104 for (let k of resultKeys) { 105 result[k] = (obj1[k] ?? []) 106 .map((_: any) => 107 produce(_, (_: any) => { 108 _.platform = platform; 109 }), 110 ) 111 .concat( 112 (obj2[k] ?? []).map((_: any) => 113 produce(_, (_: any) => { 114 _.platform = platform; 115 }), 116 ), 117 ); 118 } 119 return result; 120} 121