优化排序

This commit is contained in:
truewhile
2026-09-09 22:24:45 +08:00
parent 18e6cb40fd
commit 8f2551a1b6
5 changed files with 50 additions and 61 deletions
+3 -3
View File
@@ -3,7 +3,7 @@ import { Check, Film, ListVideo, Play, Search, X } from 'lucide-react'
import { imageURL } from '../api/client' import { imageURL } from '../api/client'
import type { Media } from '../types' import type { Media } from '../types'
import { seriesTitleFromPath } from '../utils/groupSeries' import { seasonLabel, seasonSortOrder, seriesTitleFromPath } from '../utils/groupSeries'
export type SeasonGroup = { export type SeasonGroup = {
season: number season: number
@@ -42,7 +42,7 @@ export function PlayerPlaylistPanel({
list.sort((a, b) => (a.episode_num || 0) - (b.episode_num || 0)) list.sort((a, b) => (a.episode_num || 0) - (b.episode_num || 0))
} }
return Array.from(seasonsMap.entries()) return Array.from(seasonsMap.entries())
.sort(([a], [b]) => a - b) .sort(([a], [b]) => seasonSortOrder(a) - seasonSortOrder(b))
.map(([season, list]) => ({ season, episodes: list })) .map(([season, list]) => ({ season, episodes: list }))
}, [episodes]) }, [episodes])
@@ -128,7 +128,7 @@ export function PlayerPlaylistPanel({
: 'bg-white/5 text-white/70 hover:bg-white/10 hover:text-white' : 'bg-white/5 text-white/70 hover:bg-white/10 hover:text-white'
}`} }`}
> >
<span>{season === 0 ? '特别篇' : `第 ${season} 季`}</span> <span>{seasonLabel(season)}</span>
<span className="text-[10px] opacity-75">({sesEps.length})</span> <span className="text-[10px] opacity-75">({sesEps.length})</span>
{isPlayingThisSeason && !isSelected && ( {isPlayingThisSeason && !isSelected && (
<span className="h-1.5 w-1.5 rounded-full bg-rose-400" /> <span className="h-1.5 w-1.5 rounded-full bg-rose-400" />
+1 -28
View File
@@ -5,17 +5,8 @@ import { imageURL } from '../api/client'
import { ExternalPlayerButton } from '../components/ExternalPlayerButton' import { ExternalPlayerButton } from '../components/ExternalPlayerButton'
import type { Media } from '../types' import type { Media } from '../types'
import { import {
BONUS_SEASON,
EXTRA_SEASON,
isTheatricalFeature, isTheatricalFeature,
NCED_SEASON, seasonLabel,
NCOP_SEASON,
OAD_SEASON,
OMAKE_SEASON,
ONA_SEASON,
OVA_SEASON,
OVD_SEASON,
PICTURE_DRAMA_SEASON,
seriesTitleFromPath, seriesTitleFromPath,
THEATRICAL_SEASON, THEATRICAL_SEASON,
} from '../utils/groupSeries' } from '../utils/groupSeries'
@@ -148,24 +139,6 @@ export function LibrarySeriesEpisodes({
) )
} }
function seasonLabel(season: number): string {
switch (season) {
case 0: return '特别篇'
case THEATRICAL_SEASON: return '剧场版'
case OVA_SEASON: return 'OVA'
case OAD_SEASON: return 'OAD'
case OVD_SEASON: return 'OVD'
case ONA_SEASON: return 'ONA'
case EXTRA_SEASON: return 'Extra'
case BONUS_SEASON: return 'Bonus'
case OMAKE_SEASON: return 'Omake'
case PICTURE_DRAMA_SEASON: return 'Picture Drama'
case NCOP_SEASON: return 'NCOP'
case NCED_SEASON: return 'NCED'
default: return `第 ${season} 季`
}
}
function episodeDisplayTitle(ep: Media, siblings: Media[]): string { function episodeDisplayTitle(ep: Media, siblings: Media[]): string {
let mainTitle = '' let mainTitle = ''
const epTitle = ep.episode_title?.trim() const epTitle = ep.episode_title?.trim()
+1 -29
View File
@@ -2,20 +2,10 @@ import { useEffect, useMemo } from 'react'
import type { Media } from '../types' import type { Media } from '../types'
import { import {
BONUS_SEASON,
EXTRA_SEASON,
getSeriesKey, getSeriesKey,
isTheatricalFeature, isTheatricalFeature,
NCED_SEASON, seasonSortOrder,
NCOP_SEASON,
OAD_SEASON,
OMAKE_SEASON,
ONA_SEASON,
OVA_SEASON,
OVD_SEASON,
PICTURE_DRAMA_SEASON,
specialSectionForMedia, specialSectionForMedia,
THEATRICAL_SEASON,
type SeriesCard, type SeriesCard,
} from '../utils/groupSeries' } from '../utils/groupSeries'
@@ -146,21 +136,3 @@ export function useLibrarySeriesSelection({
clearSelectedSeries, clearSelectedSeries,
} }
} }
function seasonSortOrder(season: number): number {
switch (season) {
case 0: return 0
case OVA_SEASON: return 1
case OAD_SEASON: return 2
case OVD_SEASON: return 3
case ONA_SEASON: return 4
case EXTRA_SEASON: return 5
case BONUS_SEASON: return 6
case OMAKE_SEASON: return 7
case PICTURE_DRAMA_SEASON: return 8
case NCOP_SEASON: return 9
case NCED_SEASON: return 10
case THEATRICAL_SEASON: return 11
default: return 100 + season
}
}
+2 -1
View File
@@ -8,6 +8,7 @@ import { playbackAPI } from '../api/playback'
import { confirmActionResult } from '../components/confirmAction' import { confirmActionResult } from '../components/confirmAction'
import { useEpisodeArtworkPreference } from '../hooks/useEpisodeArtworkPreference' import { useEpisodeArtworkPreference } from '../hooks/useEpisodeArtworkPreference'
import type { Media } from '../types' import type { Media } from '../types'
import { seasonSortOrder } from '../utils/groupSeries'
import { mediaLibraryBackTarget } from './MediaDetailPageModel' import { mediaLibraryBackTarget } from './MediaDetailPageModel'
interface MediaDetailPageStateParams { interface MediaDetailPageStateParams {
@@ -77,7 +78,7 @@ export function useMediaDetailPageState({ id, navigate }: MediaDetailPageStatePa
list.sort((a, b) => (a.episode_num || 0) - (b.episode_num || 0)) list.sort((a, b) => (a.episode_num || 0) - (b.episode_num || 0))
} }
return Array.from(seasons.entries()) return Array.from(seasons.entries())
.sort(([a], [b]) => a - b) .sort(([a], [b]) => seasonSortOrder(a) - seasonSortOrder(b))
.map(([season, list]) => ({ season, episodes: list })) .map(([season, list]) => ({ season, episodes: list }))
}, [episodes]) }, [episodes])
+43
View File
@@ -151,6 +151,49 @@ export function specialSectionForMedia(media: Media): number | null {
return null return null
} }
/**
* 季按钮显示顺序:第一季、第二季 … 第 XX 季 → 特别篇 → 剧场版 → OVA → OAD → 其余特典。
*
* 正片季(季号 > 0)按季号升序排最前;特殊分区(0 / 负数季)按固定优先级排在后面。
* 各季分组页(剧集库 / 详情页 / 播放器选集)共用这一顺序,避免三处各排各的。
*/
export function seasonSortOrder(season: number): number {
if (season > 0) return season
switch (season) {
case 0: return 1000 // 特别篇紧随正片
case THEATRICAL_SEASON: return 1001 // 剧场版
case OVA_SEASON: return 1002
case OAD_SEASON: return 1003
case OVD_SEASON: return 1004
case ONA_SEASON: return 1005
case EXTRA_SEASON: return 1006
case BONUS_SEASON: return 1007
case OMAKE_SEASON: return 1008
case PICTURE_DRAMA_SEASON: return 1009
case NCOP_SEASON: return 1010
case NCED_SEASON: return 1011
default: return 2000 // 未知季兜底,排最后
}
}
export function seasonLabel(season: number): string {
switch (season) {
case 0: return '特别篇'
case THEATRICAL_SEASON: return '剧场版'
case OVA_SEASON: return 'OVA'
case OAD_SEASON: return 'OAD'
case OVD_SEASON: return 'OVD'
case ONA_SEASON: return 'ONA'
case EXTRA_SEASON: return 'Extra'
case BONUS_SEASON: return 'Bonus'
case OMAKE_SEASON: return 'Omake'
case PICTURE_DRAMA_SEASON: return 'Picture Drama'
case NCOP_SEASON: return 'NCOP'
case NCED_SEASON: return 'NCED'
default: return `第 ${season} 季`
}
}
export function isSeriesCard(card: SeriesCard): boolean { export function isSeriesCard(card: SeriesCard): boolean {
return ( return (
card.count > 1 || card.count > 1 ||