xref: /MusicFree/src/pages/searchPage/hooks/useSearch.ts (revision 92a7e801f72a65b76b504a3522c1189ab5a67ed3)
1import {pluginManager, usePlugins} from '@/common/pluginManager';
2import produce from 'immer';
3import {useAtom, useSetAtom} from 'jotai';
4import {useCallback, useRef} from 'react';
5import {PageStatus, pageStatusAtom, searchResultsAtom} from '../store/atoms';
6
7export default function useSearch() {
8  const setPageStatus = useSetAtom(pageStatusAtom);
9  const [searchResults, setSearchResults] = useAtom(searchResultsAtom);
10
11  // 当前正在搜索
12  const currentQueryRef = useRef<string>('');
13
14  const search = useCallback(
15    async function (
16      query?: string,
17      platformHash = 'all',
18      queryPage = undefined,
19    ) {
20      const installedPlugins = pluginManager.getValidPlugins();
21      const plugins =
22        platformHash === 'all'
23          ? installedPlugins
24          : [installedPlugins.find(_ => _.hash === platformHash)];
25      // 使用选中插件搜素
26      plugins.forEach(async plugin => {
27        const _platform = plugin?.instance.platform;
28        const _hash = plugin?.hash;
29        if (!plugin || !_platform || !_hash) {
30          // 没有插件,此时直接进入结果页
31          setPageStatus(PageStatus.RESULT);
32          return;
33        }
34        const _prevResult = searchResults[_hash] ?? {};
35        if (
36          (_prevResult.state === 'pending' || _prevResult.state === 'done') &&
37          undefined === query
38        ) {
39          return;
40        }
41
42        // 是否是一次新的搜索
43        const newSearch =
44          query || _prevResult?.currentPage === undefined || queryPage === 1;
45
46        // 搜索关键词
47        currentQueryRef.current = query = query ?? _prevResult?.query ?? '';
48
49        /** 搜索的页码 */
50        const page =
51          queryPage ?? newSearch ? 1 : (_prevResult.currentPage ?? 0) + 1;
52
53        try {
54          setSearchResults(
55            produce(draft => {
56              const prev = draft[_hash] ?? {};
57              draft[_hash] = {
58                state: 'pending',
59                result: newSearch ? {} : prev.result,
60                query: query,
61                currentPage: page,
62              };
63              return draft;
64            }),
65          );
66          // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。
67          const result = await plugin?.instance?.search?.(query, page);
68          if (currentQueryRef.current !== query) {
69            return;
70          }
71          setPageStatus(PageStatus.RESULT);
72          if (!result) {
73            throw new Error();
74          }
75          setSearchResults(
76            produce(draft => {
77              const prev = draft[_hash] ?? {};
78              if (result._isEnd === false) {
79                prev.state = 'resolved';
80              } else {
81                prev.state = 'done';
82              }
83              prev.result = newSearch
84                ? mergeResult(result, {}, _platform)
85                : mergeResult(prev.result ?? {}, result ?? {}, _platform);
86              draft[_hash] = {
87                state: prev.state,
88                result: prev.result,
89                query: query,
90                currentPage: page,
91              };
92              return draft;
93            }),
94          );
95        } catch (e) {
96          console.log('SEARCH ERROR', e);
97          setSearchResults(
98            produce(draft => {
99              const prev = draft[_hash] ?? {};
100              prev.state = 'resolved';
101              draft[_hash] = prev;
102            }),
103          );
104        }
105      });
106    },
107    [searchResults],
108  );
109
110  return search;
111}
112
113// todo: 去重
114const resultKeys: (keyof IPlugin.ISearchResult)[] = ['album', 'music'];
115function mergeResult(
116  obj1: Record<string, any>,
117  obj2: Record<string, any>,
118  platform: string,
119): IPlugin.ISearchResult {
120  const result: Record<string, any> = {};
121  for (let k of resultKeys) {
122    result[k] = (obj1[k] ?? [])
123      .map((_: any) =>
124        produce(_, (_: any) => {
125          _.platform = platform;
126        }),
127      )
128      .concat(
129        (obj2[k] ?? []).map((_: any) =>
130          produce(_, (_: any) => {
131            _.platform = platform;
132          }),
133        ),
134      );
135  }
136  return result;
137}
138