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