xref: /MusicFree/src/pages/searchPage/hooks/useSearch.ts (revision d139abf142067550444f19228dea857c8dd9b95d)
1import {pluginManager, usePlugins} from '@/common/pluginManager';
2import produce from 'immer';
3import {useAtom, useSetAtom} from 'jotai';
4import {useCallback} 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  const search = useCallback(async function (
12    query?: string,
13    platformHash = 'all',
14    queryPage = undefined,
15  ) {
16    // 如果没有搜索结果缓存,那就是没有搜过
17    const installedPlugins = pluginManager.getValidPlugins();
18    console.log('HASH', platformHash);
19    const plugins =
20      platformHash === 'all'
21        ? installedPlugins
22        : [installedPlugins.find(_ => _.hash === platformHash)];
23    plugins.forEach(async plugin => {
24      const _platform = plugin?.instance.platform;
25      const _hash = plugin?.hash;
26      if (!plugin || !_platform || !_hash) {
27        // 没有插件,此时直接进入结果页
28        setPageStatus(PageStatus.RESULT);
29        return;
30      }
31      const _prevResult = searchResults[_hash] ?? {};
32      if (_prevResult.state === 'pending' || _prevResult.state === 'done') {
33        return;
34      }
35
36      const newSearch =
37        query || _prevResult?.currentPage === undefined || queryPage === 1;
38      query = query ?? _prevResult?.query ?? '';
39      const page =
40        queryPage ?? newSearch ? 1 : (_prevResult.currentPage ?? 0) + 1;
41
42      const rand = Math.random();
43      console.log('RANDOM', rand);
44
45      try {
46        setSearchResults(prevState =>
47          produce(prevState, draft => {
48            const prev = draft[_hash] ?? {};
49            prev.query = query;
50            prev.state = 'pending';
51            draft[_hash] = prev;
52          }),
53        );
54        // !! jscore的promise有问题,改成hermes就好了,可能和JIT
55        const result = await plugin?.instance?.search?.(query, page);
56        setPageStatus(PageStatus.RESULT);
57        if (!result) {
58          throw new Error();
59        }
60        setSearchResults(
61          produce(draft => {
62            const prev = draft[_hash] ?? {};
63            console.log('SAVED PAGE', page, prev, rand);
64            if (result._isEnd === false) {
65              prev.state = 'resolved';
66            } else {
67              prev.state = 'done';
68            }
69            prev.result = newSearch
70              ? mergeResult(result, {}, _platform)
71              : mergeResult(prev.result ?? {}, result ?? {}, _platform);
72            draft[_hash] = {
73              state: prev.state,
74              result: prev.result,
75              query: query,
76              currentPage: page,
77            };
78            return draft;
79          }),
80        );
81      } catch (e) {
82        console.log('SEARCH ERROR', e);
83        setSearchResults(
84          produce(draft => {
85            const prev = draft[_hash] ?? {};
86            prev.state = 'resolved';
87            draft[_hash] = prev;
88          }),
89        );
90      }
91    });
92  },
93  []);
94
95  return search;
96}
97
98const resultKeys: (keyof IPlugin.ISearchResult)[] = ['album', 'music'];
99function mergeResult(
100  obj1: Record<string, any>,
101  obj2: Record<string, any>,
102  platform: string,
103): IPlugin.ISearchResult {
104  const result: Record<string, any> = {};
105  for (let k of resultKeys) {
106    result[k] = (obj1[k] ?? [])
107      .map((_: any) =>
108        produce(_, (_: any) => {
109          _.platform = platform;
110        }),
111      )
112      .concat(
113        (obj2[k] ?? []).map((_: any) =>
114          produce(_, (_: any) => {
115            _.platform = platform;
116          }),
117        ),
118      );
119  }
120  return result;
121}
122
123// export default function useSearch() {
124//   const setSearchResult = useSetAtom(searchResultAtom);
125//   const setPageStatus = useSetAtom(pageStatusAtom);
126
127//   async function search(query: string, page: number) {
128//     const plugins = pluginManager.getPlugins();
129//     console.log('1', Date.now());
130//     const _rawResults = await allSettled(
131//       // @ts-ignore
132//       plugins.map(plugin =>
133//         plugin.instance?.search?.(query, page)?.then(res => {
134//           console.log('1.1', Date.now());
135//           return res;
136//         }),
137//       ),
138//     );
139//     console.log('2', Date.now());
140//     for (let i = 0; i < plugins.length; ++i) {
141//       const _rr = _rawResults[i];
142//       setSearchResult(prevResult =>
143//         produce(page === 1 ? {} : prevResult, draft => {
144//           // merge data
145//           // @ts-ignore
146//           const _result = _rr.status === 'fulfilled' ? _rr.value ?? {} : {};
147//           // 合并搜索结果
148//           mergeData(draft, _result, 'music', plugins[i].instance.platform);
149//           mergeData(draft, _result, 'album', plugins[i].instance.platform);
150//         }),
151//       );
152//     }
153//     setPageStatus(PageStatus.RESULT);
154//   }
155//   return search;
156// }
157