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