feat(search): 筛选选项只列结果里有的值,季集合并成一个维度放最前
对照 MP useTorrentFilter:分面选项按实际结果生成,计数为 0 的不再列出(已选的值仍列出,可删除); 新增季集维度 seasonEpisode(MP season_episode 写法 `S01` / `S01-S02` / `S02 E14` / `S01 E25-E48`), 整季在前、单集在后、季号新的在前,在筛选条最前。旧的季 / 集维度保留(旧链接仍生效,以标签列出)。 搜索结果页与站点资源 Tab 共用这套口径。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
18ee466664
commit
f6d976a963
7 files changed
+181
-91
No files matched your search
@@ -2,12 +2,14 @@ import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
applyFacets,
|
||||
audioBuckets,
|
||||
compareSeasonEpisode,
|
||||
type FacetInput,
|
||||
formatFacetParam,
|
||||
parseFacetParam,
|
||||
parseRelease,
|
||||
promotionBuckets,
|
||||
releaseTypeBucket,
|
||||
seasonEpisodeValue,
|
||||
seedersBucket,
|
||||
sizeBucket,
|
||||
subtitleBuckets,
|
||||
@@ -76,8 +78,9 @@ describe("release-facets", () => {
|
||||
expect(counts(r.facets.videoCodec)).toEqual({ "H.265": 2, "H.264": 1, AV1: 1, other: 1 });
|
||||
expect(counts(r.facets.releaseType)).toEqual({ disc: 1, remux: 1, encode: 1, webdl: 1, hdtv: 1 });
|
||||
expect(r.facets.releaseType.map((o) => o.label)).toEqual(["原盘", "Remux", "蓝光压制", "WEB-DL", "HDTV"]);
|
||||
expect(counts(r.facets.hdr)).toEqual({ DV: 1, HDR10: 2, "HDR10+": 0, SDR: 3 });
|
||||
expect(counts(r.facets.promotion)).toEqual({ free: 2, "2x": 1, "50%": 0, none: 3 });
|
||||
// 结果里没有的档位不列出(HDR10+、50%)
|
||||
expect(counts(r.facets.hdr)).toEqual({ DV: 1, HDR10: 2, SDR: 3 });
|
||||
expect(counts(r.facets.promotion)).toEqual({ free: 2, "2x": 1, none: 3 });
|
||||
expect(r.facets.site).toEqual([
|
||||
{ value: "a", label: "站 A", count: 3 },
|
||||
{ value: "b", label: "站 B", count: 2 },
|
||||
@@ -88,24 +91,25 @@ describe("release-facets", () => {
|
||||
{ value: "FraMeSToR", label: "FraMeSToR", count: 1 },
|
||||
]);
|
||||
expect(r.facets.season).toEqual([]);
|
||||
expect(r.facets.seasonEpisode).toEqual([]);
|
||||
});
|
||||
|
||||
it("同维度 OR、不同维度 AND;计数按其它维度的已选条件", () => {
|
||||
const r = run({ resolution: ["2160p", "1080p"], videoCodec: ["H.265"] });
|
||||
expect(ids(r)).toEqual(["1", "2"]);
|
||||
// 分辨率的计数只受编码条件影响:1080p 在 H.265 下没有结果 → 0
|
||||
expect(counts(r.facets.resolution)).toEqual({ "2160p": 2, "1080p": 0, "720p": 0, other: 0 });
|
||||
// 编码计数只受分辨率条件影响
|
||||
expect(counts(r.facets.videoCodec)).toEqual({ "H.265": 2, "H.264": 1, AV1: 0, other: 0 });
|
||||
// 其它维度按全部条件
|
||||
expect(counts(r.facets.releaseType)).toMatchObject({ remux: 1, webdl: 1, encode: 0 });
|
||||
// 分辨率的计数只受编码条件影响:1080p 在 H.265 下没有结果,但已选,仍列出(计数 0);720p / 其他不列
|
||||
expect(counts(r.facets.resolution)).toEqual({ "2160p": 2, "1080p": 0 });
|
||||
// 编码计数只受分辨率条件影响:在 2160p / 1080p 下没有 AV1 / 其他,不列
|
||||
expect(counts(r.facets.videoCodec)).toEqual({ "H.265": 2, "H.264": 1 });
|
||||
// 其它维度按全部条件:计数为 0 的档位不列
|
||||
expect(counts(r.facets.releaseType)).toEqual({ remux: 1, webdl: 1 });
|
||||
expect(ids(run({ site: ["b"], releaseType: ["disc", "webdl"] }))).toEqual(["2", "5"]);
|
||||
expect(ids(run({ releaseGroup: ["flux"] }))).toEqual(["2", "3"]);
|
||||
expect(ids(run({ hdr: ["SDR"] }))).toEqual(["3", "4", "5"]);
|
||||
expect(ids(run({ promotion: ["2x"] }))).toEqual(["4"]);
|
||||
});
|
||||
|
||||
it("H&R 三态分面:缺省按未知;未知档只在有资源时列出", () => {
|
||||
it("H&R 三态分面:缺省按未知;只列有资源的档", () => {
|
||||
const hrItems = [mk("y", { hr: true }), mk("n", { hr: false }), mk("n2", { hr: false }), mk("u")];
|
||||
const r = applyFacets(hrItems, (x) => x, {}, { now: NOW });
|
||||
expect(r.facets.hr).toEqual([
|
||||
@@ -115,7 +119,7 @@ describe("release-facets", () => {
|
||||
]);
|
||||
expect(ids(applyFacets(hrItems, (x) => x, { hr: ["no", "unknown"] }, { now: NOW }))).toEqual(["n", "n2", "u"]);
|
||||
const known = applyFacets([mk("y", { hr: true })], (x) => x, {}, { now: NOW });
|
||||
expect(known.facets.hr.map((o) => o.value)).toEqual(["yes", "no"]);
|
||||
expect(known.facets.hr.map((o) => o.value)).toEqual(["yes"]);
|
||||
});
|
||||
|
||||
it("已选但没有结果的值仍列出(计数 0)", () => {
|
||||
@@ -150,14 +154,56 @@ describe("release-facets", () => {
|
||||
{ value: "2", label: "S02", count: 1 },
|
||||
{ value: "3", label: "S03", count: 1 },
|
||||
]);
|
||||
expect(r.facets.episode).toEqual([
|
||||
{ value: "pack", label: "整季", count: 1 },
|
||||
{ value: "2", label: "E02", count: 0 },
|
||||
{ value: "3", label: "E03", count: 0 },
|
||||
]);
|
||||
// 在 S02 下单集没有结果,不列
|
||||
expect(r.facets.episode).toEqual([{ value: "pack", label: "整季", count: 1 }]);
|
||||
expect(ids(applyFacets(tv, (x) => x, { season: ["1"], episode: ["3"] }, { now: NOW }))).toEqual(["s1e2"]);
|
||||
});
|
||||
|
||||
it("季集(MP season_episode):一个维度,整季在前、单集在后,季号新的在前", () => {
|
||||
const tv = [
|
||||
mk("s1", { season: 1, episodes: null }),
|
||||
mk("s1b", { season: 1, episodes: null }),
|
||||
mk("s2", { season: 2, episodes: null }),
|
||||
mk("s1-3", { season: 1, seasonEnd: 3, episodes: null }),
|
||||
mk("s1e25", { season: 1, episodes: { start: 25, end: 48 } }),
|
||||
mk("s2e14", { season: 2, episodes: { start: 14, end: 14 } }),
|
||||
mk("s2e1", { season: 2, episodes: { start: 1, end: 1 } }),
|
||||
mk("s2e14-15", { season: 2, episodes: { start: 14, end: 15 } }),
|
||||
mk("movie"),
|
||||
];
|
||||
const r = applyFacets(tv, (x) => x, {}, { now: NOW });
|
||||
expect(r.facets.seasonEpisode.map((o) => [o.value, o.count])).toEqual([
|
||||
["S02", 1],
|
||||
["S01", 2],
|
||||
["S01-S03", 1],
|
||||
["S02 E14-E15", 1],
|
||||
["S02 E14", 1],
|
||||
["S02 E01", 1],
|
||||
["S01 E25-E48", 1],
|
||||
]);
|
||||
expect(r.facets.seasonEpisode[0]?.label).toBe("S02");
|
||||
expect(ids(applyFacets(tv, (x) => x, { seasonEpisode: ["S01", "S02 E14"] }, { now: NOW }))).toEqual([
|
||||
"s1",
|
||||
"s1b",
|
||||
"s2e14",
|
||||
]);
|
||||
// 计数按其它维度已选条件;在其它条件下为 0 的不列
|
||||
const free = applyFacets(
|
||||
tv.map((t) => (t.id === "s2" ? { ...t, promotion: { ...none, type: "free", downloadFactor: 0 } } : t)),
|
||||
(x) => x,
|
||||
{ promotion: ["free"] },
|
||||
{ now: NOW },
|
||||
);
|
||||
expect(free.facets.seasonEpisode).toEqual([{ value: "S02", label: "S02", count: 1 }]);
|
||||
expect(seasonEpisodeValue({ season: null, episodes: { start: 1, end: 2 } })).toBeNull();
|
||||
expect(["S01 E02", "bogus", "S10", "S02 E10-E12"].sort(compareSeasonEpisode)).toEqual([
|
||||
"S10",
|
||||
"S02 E10-E12",
|
||||
"S01 E02",
|
||||
"bogus",
|
||||
]);
|
||||
});
|
||||
|
||||
it("促销与版本类型档位", () => {
|
||||
expect(promotionBuckets({ type: "2x50%", downloadFactor: 0.5, uploadFactor: 2, expiresAt: null }, NOW)).toEqual([
|
||||
"2x",
|
||||
@@ -227,10 +273,7 @@ describe("release-facets", () => {
|
||||
Atmos: 1,
|
||||
TrueHD: 1,
|
||||
"DTS-HD": 1,
|
||||
DTS: 0,
|
||||
DDP: 1,
|
||||
DD: 0,
|
||||
AAC: 0,
|
||||
unknown: 1,
|
||||
});
|
||||
expect(r.facets.audioCodec.find((o) => o.value === "DDP")?.label).toBe("DD+");
|
||||
@@ -246,16 +289,8 @@ describe("release-facets", () => {
|
||||
["电影", 2],
|
||||
["剧集", 1],
|
||||
]);
|
||||
expect(counts(r.facets.size)).toEqual({
|
||||
lt1: 0,
|
||||
"1-5": 1,
|
||||
"5-10": 1,
|
||||
"10-20": 0,
|
||||
"20-50": 0,
|
||||
"50+": 1,
|
||||
unknown: 1,
|
||||
});
|
||||
expect(counts(r.facets.seeders)).toEqual({ "0": 1, "1-9": 0, "10-49": 1, "50+": 1, unknown: 1 });
|
||||
expect(counts(r.facets.size)).toEqual({ "1-5": 1, "5-10": 1, "50+": 1, unknown: 1 });
|
||||
expect(counts(r.facets.seeders)).toEqual({ "0": 1, "10-49": 1, "50+": 1, unknown: 1 });
|
||||
});
|
||||
|
||||
it("新维度组合:同维度 OR、跨维度 AND,计数按其它维度已选条件", () => {
|
||||
|
||||
Reference in new issue
Block a user