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