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 = type ?? plugin.instance.defaultSearchType ?? 'music'; 50 // 上一份搜索结果 51 const prevPluginResult = searchResults[searchType][plugin.hash]; 52 /** 上一份搜索还没返回/已经结束 */ 53 if ( 54 (prevPluginResult?.state === RequestStateCode.PENDING || 55 prevPluginResult?.state === RequestStateCode.FINISHED) && 56 undefined === query 57 ) { 58 return; 59 } 60 61 // 是否是一次新的搜索 62 const newSearch = 63 query || prevPluginResult?.page === undefined || queryPage === 1; 64 65 // 本次搜索关键词 66 currentQueryRef.current = query = 67 query ?? prevPluginResult?.query ?? ''; 68 69 /** 搜索的页码 */ 70 const page = 71 queryPage ?? newSearch ? 1 : (prevPluginResult?.page ?? 0) + 1; 72 73 trace('开始搜索', { 74 _platform, 75 query, 76 page, 77 searchType, 78 }); 79 80 try { 81 setSearchResults( 82 produce(draft => { 83 const prevMediaResult: any = draft[searchType]; 84 prevMediaResult[_hash] = { 85 state: newSearch 86 ? RequestStateCode.PENDING_FP 87 : RequestStateCode.PENDING, 88 // @ts-ignore 89 data: newSearch ? [] : prevMediaResult[_hash]?.data ?? [], 90 query: query, 91 page, 92 }; 93 }), 94 ); 95 // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。 96 const result = await plugin?.methods?.search?.( 97 query, 98 page, 99 searchType, 100 ); 101 /** 如果搜索结果不是本次结果 */ 102 if (currentQueryRef.current !== query) { 103 return; 104 } 105 /** 切换到结果页 */ 106 setPageStatus(PageStatus.RESULT); 107 if (!result) { 108 throw new Error('搜索结果为空'); 109 } 110 setSearchResults( 111 produce(draft => { 112 const prevMediaResult = draft[searchType]; 113 const prevPluginResult: any = prevMediaResult[_hash] ?? { 114 data: [], 115 }; 116 const currResult = result.data ?? []; 117 118 prevMediaResult[_hash] = { 119 state: 120 result?.isEnd === false && result?.data?.length 121 ? RequestStateCode.PARTLY_DONE 122 : RequestStateCode.FINISHED, 123 query, 124 page, 125 data: newSearch 126 ? currResult 127 : (prevPluginResult.data ?? []).concat(currResult), 128 }; 129 return draft; 130 }), 131 ); 132 } catch (e) { 133 errorLog('', e); 134 setPageStatus(PageStatus.RESULT); 135 setSearchResults( 136 produce(draft => { 137 const prevMediaResult = draft[searchType]; 138 const prevPluginResult = prevMediaResult[_hash] ?? {data: []}; 139 140 prevPluginResult.state = RequestStateCode.PARTLY_DONE; 141 return draft; 142 }), 143 ); 144 } 145 }); 146 }, 147 [searchResults], 148 ); 149 150 return search; 151} 152 153