1import {devLog, 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.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 === RequestStateCode.PENDING || 59 prevPluginResult?.state === 60 RequestStateCode.FINISHED) && 61 undefined === query 62 ) { 63 return; 64 } 65 66 // 是否是一次新的搜索 67 const newSearch = 68 query || 69 prevPluginResult?.page === undefined || 70 queryPage === 1; 71 72 // 本次搜索关键词 73 currentQueryRef.current = query = 74 query ?? prevPluginResult?.query ?? ''; 75 76 /** 搜索的页码 */ 77 const page = 78 queryPage ?? newSearch 79 ? 1 80 : (prevPluginResult?.page ?? 0) + 1; 81 82 trace('开始搜索', { 83 _platform, 84 query, 85 page, 86 searchType, 87 }); 88 89 try { 90 setSearchResults( 91 produce(draft => { 92 const prevMediaResult: any = draft[searchType]; 93 prevMediaResult[_hash] = { 94 state: newSearch 95 ? RequestStateCode.PENDING_FP 96 : RequestStateCode.PENDING, 97 // @ts-ignore 98 data: newSearch 99 ? [] 100 : prevMediaResult[_hash]?.data ?? [], 101 query: query, 102 page, 103 }; 104 }), 105 ); 106 // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。 107 const result = await plugin?.methods?.search?.( 108 query, 109 page, 110 searchType, 111 ); 112 /** 如果搜索结果不是本次结果 */ 113 if (currentQueryRef.current !== query) { 114 return; 115 } 116 /** 切换到结果页 */ 117 setPageStatus(PageStatus.RESULT); 118 if (!result) { 119 throw new Error('搜索结果为空'); 120 } 121 setSearchResults( 122 produce(draft => { 123 const prevMediaResult = draft[searchType]; 124 const prevPluginResult: any = prevMediaResult[ 125 _hash 126 ] ?? { 127 data: [], 128 }; 129 const currResult = result.data ?? []; 130 131 prevMediaResult[_hash] = { 132 state: 133 result?.isEnd === false && 134 result?.data?.length 135 ? RequestStateCode.PARTLY_DONE 136 : RequestStateCode.FINISHED, 137 query, 138 page, 139 data: newSearch 140 ? currResult 141 : (prevPluginResult.data ?? []).concat( 142 currResult, 143 ), 144 }; 145 return draft; 146 }), 147 ); 148 } catch (e: any) { 149 errorLog('搜索失败', e?.message); 150 devLog( 151 'error', 152 '搜索失败', 153 `Plugin: ${plugin.name} Query: ${query} Page: ${page}`, 154 e, 155 e?.message, 156 ); 157 158 setPageStatus(PageStatus.RESULT); 159 setSearchResults( 160 produce(draft => { 161 const prevMediaResult = draft[searchType]; 162 const prevPluginResult = prevMediaResult[_hash] ?? { 163 data: [], 164 }; 165 166 prevPluginResult.state = 167 RequestStateCode.PARTLY_DONE; 168 return draft; 169 }), 170 ); 171 } 172 }); 173 }, 174 [searchResults], 175 ); 176 177 return search; 178} 179