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