xref: /MusicFree/src/pages/searchPage/hooks/useSearch.ts (revision 3a76c6afd27eed7f26450535667a4fb0439f5713)
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          console.log('RESULT', result);
69          if (currentQueryRef.current !== query) {
70            return;
71          }
72          setPageStatus(PageStatus.RESULT);
73          if (!result) {
74            throw new Error();
75          }
76          setSearchResults(
77            produce(draft => {
78              const prev = draft[_hash] ?? {};
79              if (result._isEnd === false) {
80                prev.state = 'resolved';
81              } else {
82                prev.state = 'done';
83              }
84              prev.result = newSearch
85                ? mergeResult(result, {}, _platform)
86                : mergeResult(prev.result ?? {}, result ?? {}, _platform);
87              draft[_hash] = {
88                state: prev.state,
89                result: prev.result,
90                query: query,
91                currentPage: page,
92              };
93              return draft;
94            }),
95          );
96        } catch (e) {
97          console.log('SEARCH ERROR', e);
98          setSearchResults(
99            produce(draft => {
100              const prev = draft[_hash] ?? {};
101              prev.state = 'resolved';
102              draft[_hash] = prev;
103            }),
104          );
105        }
106      });
107    },
108    [searchResults],
109  );
110
111  return search;
112}
113
114// todo: 去重
115const resultKeys: (keyof IPlugin.ISearchResult)[] = ['album', 'music', 'artist'];
116function mergeResult(
117  obj1: Record<string, any>,
118  obj2: Record<string, any>,
119  platform: string,
120): IPlugin.ISearchResult {
121  const result: Record<string, any> = {};
122  for (let k of resultKeys) {
123    result[k] = (obj1[k] ?? [])
124      .map((_: any) =>
125        produce(_, (_: any) => {
126          _.platform = platform;
127        }),
128      )
129      .concat(
130        (obj2[k] ?? []).map((_: any) =>
131          produce(_, (_: any) => {
132            _.platform = platform;
133          }),
134        ),
135      );
136  }
137  return result;
138}
139