1import {devLog, errorLog, trace} from '@/utils/log'; 2import {RequestStateCode} from '@/constants/commonConst'; 3import {produce} from 'immer'; 4import {getDefaultStore, 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.getSearchablePlugins(); 37 } 38 if (plugins.length === 0) { 39 setPageStatus(PageStatus.NO_PLUGIN); 40 return; 41 } 42 // 使用选中插件搜素 43 plugins.forEach(async plugin => { 44 const _platform = plugin.instance.platform; 45 const _hash = plugin.hash; 46 if (!_platform || !_hash) { 47 // 插件无效,此时直接进入结果页 48 setPageStatus(PageStatus.RESULT); 49 return; 50 } 51 52 const searchType = 53 type ?? plugin.instance.defaultSearchType ?? 'music'; 54 // 上一份搜索结果 55 const prevPluginResult = searchResults[searchType][plugin.hash]; 56 /** 上一份搜索还没返回/已经结束 */ 57 if ( 58 (prevPluginResult?.state === 59 RequestStateCode.PENDING_REST_PAGE || 60 prevPluginResult?.state === 61 RequestStateCode.FINISHED) && 62 undefined === query 63 ) { 64 return; 65 } 66 67 // 是否是一次新的搜索 68 const newSearch = 69 query || 70 prevPluginResult?.page === undefined || 71 queryPage === 1; 72 73 // 本次搜索关键词 74 currentQueryRef.current = query = 75 query ?? prevPluginResult?.query ?? ''; 76 77 /** 搜索的页码 */ 78 const page = 79 queryPage ?? newSearch 80 ? 1 81 : (prevPluginResult?.page ?? 0) + 1; 82 83 trace('开始搜索', { 84 _platform, 85 query, 86 page, 87 searchType, 88 }); 89 90 try { 91 setSearchResults( 92 produce(draft => { 93 const prevMediaResult: any = draft[searchType]; 94 prevMediaResult[_hash] = { 95 state: newSearch 96 ? RequestStateCode.PENDING_FIRST_PAGE 97 : RequestStateCode.PENDING_REST_PAGE, 98 // @ts-ignore 99 data: newSearch 100 ? [] 101 : prevMediaResult[_hash]?.data ?? [], 102 query: query, 103 page, 104 }; 105 }), 106 ); 107 // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。 108 const result = await plugin?.methods?.search?.( 109 query, 110 page, 111 searchType, 112 ); 113 /** 如果搜索结果不是本次结果 */ 114 if (currentQueryRef.current !== query) { 115 return; 116 } 117 /** 切换到结果页 */ 118 setPageStatus(PageStatus.RESULT); 119 if (!result) { 120 throw new Error('搜索结果为空'); 121 } 122 setSearchResults( 123 produce(draft => { 124 const prevMediaResult = draft[searchType]; 125 const prevPluginResult: any = prevMediaResult[ 126 _hash 127 ] ?? { 128 data: [], 129 }; 130 const currResult = result.data ?? []; 131 132 prevMediaResult[_hash] = { 133 state: 134 result?.isEnd === false && 135 result?.data?.length 136 ? RequestStateCode.PARTLY_DONE 137 : RequestStateCode.FINISHED, 138 query, 139 page, 140 data: newSearch 141 ? currResult 142 : (prevPluginResult.data ?? []).concat( 143 currResult, 144 ), 145 }; 146 return draft; 147 }), 148 ); 149 } catch (e: any) { 150 errorLog('搜索失败', e?.message); 151 devLog( 152 'error', 153 '搜索失败', 154 `Plugin: ${plugin.name} Query: ${query} Page: ${page}`, 155 e, 156 e?.message, 157 ); 158 const currentPageStatus = 159 getDefaultStore().get(pageStatusAtom); 160 if (currentPageStatus !== PageStatus.EDITING) { 161 setPageStatus(PageStatus.RESULT); 162 } 163 setSearchResults( 164 produce(draft => { 165 const prevMediaResult = draft[searchType]; 166 const prevPluginResult = prevMediaResult[_hash] ?? { 167 data: [], 168 }; 169 170 prevPluginResult.state = 171 RequestStateCode.PARTLY_DONE; 172 return draft; 173 }), 174 ); 175 } 176 }); 177 }, 178 [searchResults], 179 ); 180 181 return search; 182} 183