xref: /MusicFree/src/pages/searchPage/hooks/useSearch.ts (revision 6704747af84cebd842b258efac7143542722fac5)
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