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