xref: /MusicFree/src/pages/searchPage/hooks/useSearch.ts (revision 2aa881935ca35b8fb1abc4206e0dc35149231456)
1import {devLog, 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.getSearchablePlugins();
37            }
38            if (plugins.length === 0) {
39                setPageStatus(PageStatus.NO_PLUGIN);
40                return;
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 =
53                    type ?? plugin.instance.defaultSearchType ?? 'music';
54                // 上一份搜索结果
55                const prevPluginResult = searchResults[searchType][plugin.hash];
56                /** 上一份搜索还没返回/已经结束 */
57                if (
58                    (prevPluginResult?.state === RequestStateCode.PENDING ||
59                        prevPluginResult?.state ===
60                            RequestStateCode.FINISHED) &&
61                    undefined === query
62                ) {
63                    return;
64                }
65
66                // 是否是一次新的搜索
67                const newSearch =
68                    query ||
69                    prevPluginResult?.page === undefined ||
70                    queryPage === 1;
71
72                // 本次搜索关键词
73                currentQueryRef.current = query =
74                    query ?? prevPluginResult?.query ?? '';
75
76                /** 搜索的页码 */
77                const page =
78                    queryPage ?? newSearch
79                        ? 1
80                        : (prevPluginResult?.page ?? 0) + 1;
81
82                trace('开始搜索', {
83                    _platform,
84                    query,
85                    page,
86                    searchType,
87                });
88
89                try {
90                    setSearchResults(
91                        produce(draft => {
92                            const prevMediaResult: any = draft[searchType];
93                            prevMediaResult[_hash] = {
94                                state: newSearch
95                                    ? RequestStateCode.PENDING_FP
96                                    : RequestStateCode.PENDING,
97                                // @ts-ignore
98                                data: newSearch
99                                    ? []
100                                    : prevMediaResult[_hash]?.data ?? [],
101                                query: query,
102                                page,
103                            };
104                        }),
105                    );
106                    // !! jscore的promise有问题,改成hermes就好了,可能和JIT有关,不知道。
107                    const result = await plugin?.methods?.search?.(
108                        query,
109                        page,
110                        searchType,
111                    );
112                    /** 如果搜索结果不是本次结果 */
113                    if (currentQueryRef.current !== query) {
114                        return;
115                    }
116                    /** 切换到结果页 */
117                    setPageStatus(PageStatus.RESULT);
118                    if (!result) {
119                        throw new Error('搜索结果为空');
120                    }
121                    setSearchResults(
122                        produce(draft => {
123                            const prevMediaResult = draft[searchType];
124                            const prevPluginResult: any = prevMediaResult[
125                                _hash
126                            ] ?? {
127                                data: [],
128                            };
129                            const currResult = result.data ?? [];
130
131                            prevMediaResult[_hash] = {
132                                state:
133                                    result?.isEnd === false &&
134                                    result?.data?.length
135                                        ? RequestStateCode.PARTLY_DONE
136                                        : RequestStateCode.FINISHED,
137                                query,
138                                page,
139                                data: newSearch
140                                    ? currResult
141                                    : (prevPluginResult.data ?? []).concat(
142                                          currResult,
143                                      ),
144                            };
145                            return draft;
146                        }),
147                    );
148                } catch (e: any) {
149                    errorLog('搜索失败', e?.message);
150                    devLog(
151                        'error',
152                        '搜索失败',
153                        `Plugin: ${plugin.name} Query: ${query} Page: ${page}`,
154                        e,
155                        e?.message,
156                    );
157
158                    setPageStatus(PageStatus.RESULT);
159                    setSearchResults(
160                        produce(draft => {
161                            const prevMediaResult = draft[searchType];
162                            const prevPluginResult = prevMediaResult[_hash] ?? {
163                                data: [],
164                            };
165
166                            prevPluginResult.state =
167                                RequestStateCode.PARTLY_DONE;
168                            return draft;
169                        }),
170                    );
171                }
172            });
173        },
174        [searchResults],
175    );
176
177    return search;
178}
179