1import {errorLog, trace} from '@/utils/log'; 2import {RequestStateCode} from '@/constants/commonConst'; 3import produce from 'immer'; 4import {useAtom, useSetAtom} from 'jotai'; 5import {useCallback, useRef} from 'react'; 6import {PageStatus, pageStatusAtom, searchResultsAtom} from '../store/atoms'; 7import PluginManager, {Plugin} from '@/core/pluginManager'; 8 9export default function useSearch() { 10 const setPageStatus = useSetAtom(pageStatusAtom); 11 const [searchResults, setSearchResults] = useAtom(searchResultsAtom); 12 13 // 当前正在搜索 14 const currentQueryRef = useRef<string>(''); 15 16 /** 17 * query: 搜索词 18 * queryPage: 搜索页码 19 * type: 搜索类型 20 * pluginHash: 搜索条件 21 */ 22 const search = useCallback( 23 async function ( 24 query?: string, 25 queryPage?: number, 26 type?: ICommon.SupportMediaType, 27 pluginHash?: string, 28 ) { 29 /** 如果没有指定插件,就用所有插件搜索 */ 30 31 let plugins: Plugin[] = []; 32 if (pluginHash) { 33 const tgtPlugin = PluginManager.getByHash(pluginHash); 34 tgtPlugin && (plugins = [tgtPlugin]); 35 } else { 36 plugins = PluginManager.getValidPlugins(); 37 } 38 39 // 使用选中插件搜素 40 plugins.forEach(async plugin => { 41 const _platform = plugin.instance.platform; 42 const _hash = plugin.hash; 43 if (!_platform || !_hash) { 44 // 插件无效,此时直接进入结果页 45 setPageStatus(PageStatus.RESULT); 46 return; 47 } 48 49 const searchType = 50 type ?? plugin.instance.defaultSearchType ?? 'music'; 51 // 上一份搜索结果 52 const prevPluginResult = searchResults[searchType][plugin.hash]; 53 /** 上一份搜索还没返回/已经结束 */ 54 if ( 55 (prevPluginResult?.state === RequestStateCode.PENDING || 56 prevPluginResult?.state === 57 RequestStateCode.FINISHED) && 58 undefined === query 59 ) { 60 return; 61 } 62 63 // 是否是一次新的搜索 64 const newSearch = 65 query || 66 prevPluginResult?.page === undefined || 67 queryPage === 1; 68 69 // 本次搜索关键词 70 currentQueryRef.current = query = 71 query ?? prevPluginResult?.query ?? ''; 72 73 /** 搜索的页码 */ 74 const page = 75 queryPage ?? newSearch 76 ? 1 77 : (prevPluginResult?.page ?? 0) + 1; 78 79 trace('开始搜索', { 80 _platform, 81 query, 82 page, 83 searchType, 84 }); 85 86 try { 87 setSearchResults( 88 produce(draft => { 89 const prevMediaResult: any = draft[searchType]; 90 prevMediaResult[_hash] = { 91 state: newSearch 92 ? RequestStateCode.PENDING_FP 93 : RequestStateCode.PENDING, 94 // @ts-ignore 95 data: newSearch 96 ? [] 97 : prevMediaResult[_hash]?.data ?? [], 98 query: query, 99 page, 100 }; 101 }), 102 ); 103 // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。 104 const result = await plugin?.methods?.search?.( 105 query, 106 page, 107 searchType, 108 ); 109 /** 如果搜索结果不是本次结果 */ 110 if (currentQueryRef.current !== query) { 111 return; 112 } 113 /** 切换到结果页 */ 114 setPageStatus(PageStatus.RESULT); 115 if (!result) { 116 throw new Error('搜索结果为空'); 117 } 118 setSearchResults( 119 produce(draft => { 120 const prevMediaResult = draft[searchType]; 121 const prevPluginResult: any = prevMediaResult[ 122 _hash 123 ] ?? { 124 data: [], 125 }; 126 const currResult = result.data ?? []; 127 128 prevMediaResult[_hash] = { 129 state: 130 result?.isEnd === false && 131 result?.data?.length 132 ? RequestStateCode.PARTLY_DONE 133 : RequestStateCode.FINISHED, 134 query, 135 page, 136 data: newSearch 137 ? currResult 138 : (prevPluginResult.data ?? []).concat( 139 currResult, 140 ), 141 }; 142 return draft; 143 }), 144 ); 145 } catch (e) { 146 errorLog('', e); 147 setPageStatus(PageStatus.RESULT); 148 setSearchResults( 149 produce(draft => { 150 const prevMediaResult = draft[searchType]; 151 const prevPluginResult = prevMediaResult[_hash] ?? { 152 data: [], 153 }; 154 155 prevPluginResult.state = 156 RequestStateCode.PARTLY_DONE; 157 return draft; 158 }), 159 ); 160 } 161 }); 162 }, 163 [searchResults], 164 ); 165 166 return search; 167} 168