refactor(search): optimize sorting logic for season filter options

This commit is contained in:
InfinityPacer
2024-10-06 17:37:01 +08:00
parent fc61060b7f
commit d703909177
2 changed files with 218 additions and 52 deletions

View File

@@ -71,37 +71,120 @@ function initOptions(data: Context) {
// 对季过滤选项进行排序
const sortSeasonFilterOptions = computed(() => {
return seasonFilterOptions.value.sort((a, b) => {
// 按季,集降序排序
// 预解析所有选项
const parsedOptions = seasonFilterOptions.value.map((option, index) => {
const parseSeasonEpisode = (str: string) => {
const seasonRangeMatch = str.match(/S(\d+)(?:-S(\d+))?/)
const episodeRangeMatch = str.match(/E(\d+)(?:-E(\d+))?/)
const match = str.match(/^S(\d+)(?:-S(\d+))?(?:\s*E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 如果字符串格式不正确,返回默认值
return {
original: str,
seasonStart: 0,
seasonEnd: 0,
episodeStart: 0,
episodeEnd: 0,
maxSeason: 0,
maxEpisode: 0,
index,
}
}
const seasonStart = match[1] ? parseInt(match[1], 10) : 0
const seasonEnd = match[2] ? parseInt(match[2], 10) : 0
const episodeStart = match[3] ? parseInt(match[3], 10) : 0
const episodeEnd = match[4] ? parseInt(match[4], 10) : 0
const maxSeason = seasonEnd > 0 ? seasonEnd : seasonStart
const maxEpisode = episodeEnd > 0 ? episodeEnd : episodeStart
return {
seasonStart: seasonRangeMatch?.[1] ? parseInt(seasonRangeMatch[1]) : 0,
seasonEnd: seasonRangeMatch?.[2] ? parseInt(seasonRangeMatch[2]) : 0,
episodeStart: episodeRangeMatch?.[1] ? parseInt(episodeRangeMatch[1]) : 0,
episodeEnd: episodeRangeMatch?.[2] ? parseInt(episodeRangeMatch[2]) : 0,
original: str,
seasonStart,
seasonEnd,
episodeStart,
episodeEnd,
maxSeason,
maxEpisode,
index,
}
}
const parsedA = parseSeasonEpisode(a)
const parsedB = parseSeasonEpisode(b)
// 先按季降序排序
if (parsedB.seasonStart !== parsedA.seasonStart) {
return parsedB.seasonStart - parsedA.seasonStart
}
if (parsedB.seasonEnd !== parsedA.seasonEnd) {
return parsedB.seasonEnd - parsedA.seasonEnd
}
// 按集降序排序
if (parsedB.episodeStart !== parsedA.episodeStart) {
return parsedB.episodeStart - parsedA.episodeStart
}
if (parsedB.episodeEnd !== parsedA.episodeEnd) {
return parsedB.episodeEnd - parsedA.episodeEnd
}
// 兜底
return b.localeCompare(a)
return parseSeasonEpisode(option)
})
// 定义判断是否为整季或季范围的函数
const isWholeSeason = (parsed: (typeof parsedOptions)[0]) =>
parsed.seasonStart > 0 &&
(parsed.seasonEnd === 0 || parsed.seasonEnd > parsed.seasonStart) &&
parsed.episodeStart === 0 &&
parsed.episodeEnd === 0
// 定义判断是否包含集数的函数
const hasEpisodes = (parsed: (typeof parsedOptions)[0]) => parsed.episodeStart > 0 || parsed.episodeEnd > 0
// 排序逻辑
parsedOptions.sort((a, b) => {
const aIsWhole = isWholeSeason(a)
const bIsWhole = isWholeSeason(b)
const aHasEpisodes = hasEpisodes(a)
const bHasEpisodes = hasEpisodes(b)
// 优先级1整季和季范围选项优先于带有集数的选项
if (aIsWhole && !bIsWhole) return -1
if (!aIsWhole && bIsWhole) return 1
// 优先级2如果都是整季或季范围选项按 maxSeason 降序排列
if (aIsWhole && bIsWhole) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
// 如果 maxSeason 相同,则按原始索引
return a.index - b.index
}
// 优先级3如果都是带有集数的选项先按 maxSeason 降序,再按 maxEpisode 降序
if (aHasEpisodes && bHasEpisodes) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
if (b.maxEpisode !== a.maxEpisode) {
return b.maxEpisode - a.maxEpisode
}
// 如果 maxSeason 和 maxEpisode 相同,则按原始索引
return a.index - b.index
}
// 优先级4如果一个有集数一个没有优先有集数的选项
if (aHasEpisodes && !bHasEpisodes) return -1
if (!aHasEpisodes && bHasEpisodes) return 1
// 优先级5对于没有集数且不是整季的选项按 seasonStart 和 seasonEnd 降序排序
if (b.seasonStart !== a.seasonStart) {
return b.seasonStart - a.seasonStart
}
if (b.seasonEnd !== a.seasonEnd) {
return b.seasonEnd - a.seasonEnd
}
// 优先级6按 episodeStart 和 episodeEnd 降序排序
if (b.episodeStart !== a.episodeStart) {
return b.episodeStart - a.episodeStart
}
if (b.episodeEnd !== a.episodeEnd) {
return b.episodeEnd - a.episodeEnd
}
// 优先级7兜底按字母降序排列
if (a.original !== b.original) {
return b.original.localeCompare(a.original)
}
// 优先级8如果所有条件都相同则按原始索引
return a.index - b.index
})
// 返回排序后的原始字符串数组
return parsedOptions.map(option => option.original)
})
// 计算分组后的列表

View File

@@ -81,37 +81,120 @@ function initOptions(data: Context) {
// 对季过滤选项进行排序
const sortSeasonFilterOptions = computed(() => {
return seasonFilterOptions.value.sort((a, b) => {
// 按季,集降序排序
// 预解析所有选项
const parsedOptions = seasonFilterOptions.value.map((option, index) => {
const parseSeasonEpisode = (str: string) => {
const seasonRangeMatch = str.match(/S(\d+)(?:-S(\d+))?/)
const episodeRangeMatch = str.match(/E(\d+)(?:-E(\d+))?/)
const match = str.match(/^S(\d+)(?:-S(\d+))?(?:\s*E(\d+)(?:-E(\d+))?)?$/)
if (!match) {
// 如果字符串格式不正确,返回默认值
return {
original: str,
seasonStart: 0,
seasonEnd: 0,
episodeStart: 0,
episodeEnd: 0,
maxSeason: 0,
maxEpisode: 0,
index,
}
}
const seasonStart = match[1] ? parseInt(match[1], 10) : 0
const seasonEnd = match[2] ? parseInt(match[2], 10) : 0
const episodeStart = match[3] ? parseInt(match[3], 10) : 0
const episodeEnd = match[4] ? parseInt(match[4], 10) : 0
const maxSeason = seasonEnd > 0 ? seasonEnd : seasonStart
const maxEpisode = episodeEnd > 0 ? episodeEnd : episodeStart
return {
seasonStart: seasonRangeMatch?.[1] ? parseInt(seasonRangeMatch[1]) : 0,
seasonEnd: seasonRangeMatch?.[2] ? parseInt(seasonRangeMatch[2]) : 0,
episodeStart: episodeRangeMatch?.[1] ? parseInt(episodeRangeMatch[1]) : 0,
episodeEnd: episodeRangeMatch?.[2] ? parseInt(episodeRangeMatch[2]) : 0,
original: str,
seasonStart,
seasonEnd,
episodeStart,
episodeEnd,
maxSeason,
maxEpisode,
index,
}
}
const parsedA = parseSeasonEpisode(a)
const parsedB = parseSeasonEpisode(b)
// 先按季降序排序
if (parsedB.seasonStart !== parsedA.seasonStart) {
return parsedB.seasonStart - parsedA.seasonStart
}
if (parsedB.seasonEnd !== parsedA.seasonEnd) {
return parsedB.seasonEnd - parsedA.seasonEnd
}
// 按集降序排序
if (parsedB.episodeStart !== parsedA.episodeStart) {
return parsedB.episodeStart - parsedA.episodeStart
}
if (parsedB.episodeEnd !== parsedA.episodeEnd) {
return parsedB.episodeEnd - parsedA.episodeEnd
}
// 兜底
return b.localeCompare(a)
return parseSeasonEpisode(option)
})
// 定义判断是否为整季或季范围的函数
const isWholeSeason = (parsed: (typeof parsedOptions)[0]) =>
parsed.seasonStart > 0 &&
(parsed.seasonEnd === 0 || parsed.seasonEnd > parsed.seasonStart) &&
parsed.episodeStart === 0 &&
parsed.episodeEnd === 0
// 定义判断是否包含集数的函数
const hasEpisodes = (parsed: (typeof parsedOptions)[0]) => parsed.episodeStart > 0 || parsed.episodeEnd > 0
// 排序逻辑
parsedOptions.sort((a, b) => {
const aIsWhole = isWholeSeason(a)
const bIsWhole = isWholeSeason(b)
const aHasEpisodes = hasEpisodes(a)
const bHasEpisodes = hasEpisodes(b)
// 优先级1整季和季范围选项优先于带有集数的选项
if (aIsWhole && !bIsWhole) return -1
if (!aIsWhole && bIsWhole) return 1
// 优先级2如果都是整季或季范围选项按 maxSeason 降序排列
if (aIsWhole && bIsWhole) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
// 如果 maxSeason 相同,则按原始索引
return a.index - b.index
}
// 优先级3如果都是带有集数的选项先按 maxSeason 降序,再按 maxEpisode 降序
if (aHasEpisodes && bHasEpisodes) {
if (b.maxSeason !== a.maxSeason) {
return b.maxSeason - a.maxSeason
}
if (b.maxEpisode !== a.maxEpisode) {
return b.maxEpisode - a.maxEpisode
}
// 如果 maxSeason 和 maxEpisode 相同,则按原始索引
return a.index - b.index
}
// 优先级4如果一个有集数一个没有优先有集数的选项
if (aHasEpisodes && !bHasEpisodes) return -1
if (!aHasEpisodes && bHasEpisodes) return 1
// 优先级5对于没有集数且不是整季的选项按 seasonStart 和 seasonEnd 降序排序
if (b.seasonStart !== a.seasonStart) {
return b.seasonStart - a.seasonStart
}
if (b.seasonEnd !== a.seasonEnd) {
return b.seasonEnd - a.seasonEnd
}
// 优先级6按 episodeStart 和 episodeEnd 降序排序
if (b.episodeStart !== a.episodeStart) {
return b.episodeStart - a.episodeStart
}
if (b.episodeEnd !== a.episodeEnd) {
return b.episodeEnd - a.episodeEnd
}
// 优先级7兜底按字母降序排列
if (a.original !== b.original) {
return b.original.localeCompare(a.original)
}
// 优先级8如果所有条件都相同则按原始索引
return a.index - b.index
})
// 返回排序后的原始字符串数组
return parsedOptions.map(option => option.original)
})
// 排序