fix: 修复特殊字符标题搜索匹配失败 (#337)
* fix: 修复特殊字符标题搜索匹配失败 改动详情: - 使用 URL.searchParams 构造内部 /search/anime 搜索地址 - 避免标题中的 & 等特殊字符被当作查询参数分隔符截断 - 补充回归测试,验证 keyword、season、episode 参数保持正确 * refactor: 简化搜索地址构造调用
This commit is contained in:
1 parent
aad97a0f88
commit
81a320177e
2 files changed
+37
-3
No files matched your search
@@ -1402,6 +1402,21 @@ export async function extractTitleSeasonEpisode(cleanFileName) {
|
||||
return {title, season, episode, year};
|
||||
}
|
||||
|
||||
export function buildSearchAnimeUrl(baseUrl, keyword, season, episode) {
|
||||
const searchUrl = new URL(baseUrl);
|
||||
const apiPrefix = searchUrl.pathname.replace(/\/(?:match|search\/episodes)$/, '');
|
||||
searchUrl.pathname = `${apiPrefix}/search/anime`;
|
||||
searchUrl.search = '';
|
||||
searchUrl.searchParams.set('keyword', keyword || '');
|
||||
if (season !== undefined) {
|
||||
searchUrl.searchParams.set('season', season || '');
|
||||
}
|
||||
if (episode !== undefined) {
|
||||
searchUrl.searchParams.set('episode', episode || '');
|
||||
}
|
||||
return searchUrl;
|
||||
}
|
||||
|
||||
// Extracted function for POST /api/v2/match
|
||||
export async function matchAnime(url, req, clientIp) {
|
||||
try {
|
||||
@@ -1460,7 +1475,7 @@ export async function matchAnime(url, req, clientIp) {
|
||||
const targetPlatform = dynamicPlatformOrder.length > 0 ? dynamicPlatformOrder[0] : null;
|
||||
|
||||
const requestAnimeDetailsMap = new Map();
|
||||
let originSearchUrl = new URL(req.url.replace("/match", `/search/anime?keyword=${title}&season=${season || ''}&episode=${episode || ''}`));
|
||||
let originSearchUrl = buildSearchAnimeUrl(req.url, title, season, episode);
|
||||
const searchRes = await searchAnime(originSearchUrl, preferAnimeId, preferSource, requestAnimeDetailsMap, targetPlatform);
|
||||
const searchData = await searchRes.json();
|
||||
log("info", `[system] [Match] searchData: ${searchData.animes}`);
|
||||
@@ -1564,7 +1579,7 @@ export async function searchEpisodes(url) {
|
||||
}
|
||||
|
||||
// 先搜索动漫
|
||||
let searchUrl = new URL(`/search/anime?keyword=${anime}`, url.origin);
|
||||
let searchUrl = buildSearchAnimeUrl(url, anime);
|
||||
const requestAnimeDetailsMap = new Map();
|
||||
|
||||
const searchRes = await searchAnime(searchUrl, null, null, requestAnimeDetailsMap);
|
||||
|
||||
@@ -5,7 +5,7 @@ dotenv.config();
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert';
|
||||
import { handleRequest } from './worker.js';
|
||||
import { extractTitleSeasonEpisode, getBangumi, getComment, matchAnime, searchAnime } from "./apis/dandan-api.js";
|
||||
import { extractTitleSeasonEpisode, getBangumi, getComment, matchAnime, searchAnime, buildSearchAnimeUrl } from "./apis/dandan-api.js";
|
||||
import { getRedisKey, pingRedis, setRedisKey, setRedisKeyWithExpiry } from "./utils/redis-util.js";
|
||||
import { getLocalRedisKey, setLocalRedisKey, setLocalRedisKeyWithExpiry } from "./utils/local-redis-util.js";
|
||||
import { getImdbepisodes } from "./utils/imdb-util.js";
|
||||
@@ -206,6 +206,25 @@ test('worker.js API endpoints', async (t) => {
|
||||
assert.equal(seenRedirectMode, 'manual');
|
||||
});
|
||||
|
||||
await t.test('buildSearchAnimeUrl should preserve special characters in keyword', async () => {
|
||||
const searchUrl = buildSearchAnimeUrl(`${urlPrefix}/api/v2/match`, 'Love & Death', 1, 2);
|
||||
|
||||
assert.equal(searchUrl.pathname, '/api/v2/search/anime');
|
||||
assert.equal(searchUrl.searchParams.get('keyword'), 'Love & Death');
|
||||
assert.equal(searchUrl.searchParams.get('season'), '1');
|
||||
assert.equal(searchUrl.searchParams.get('episode'), '2');
|
||||
assert.equal(searchUrl.searchParams.has(' Death'), false);
|
||||
});
|
||||
|
||||
await t.test('buildSearchAnimeUrl should derive /search/anime from /search/episodes requests', async () => {
|
||||
const searchUrl = buildSearchAnimeUrl(`${urlPrefix}/api/v2/search/episodes?anime=Love%20%26%20Death&episode=2`, 'Love & Death');
|
||||
|
||||
assert.equal(searchUrl.pathname, '/api/v2/search/anime');
|
||||
assert.equal(searchUrl.searchParams.get('keyword'), 'Love & Death');
|
||||
assert.equal(searchUrl.searchParams.has('season'), false);
|
||||
assert.equal(searchUrl.searchParams.has('episode'), false);
|
||||
});
|
||||
|
||||
// 测试标题解析
|
||||
await t.test('PARSE TitleSeasonEpisode', async () => {
|
||||
let title, season, episode;
|
||||
|
||||
Reference in new issue
Block a user