Add preferred format settings and release preference sorting

This commit is contained in:
2026-05-27 21:52:36 +00:00
parent fe71e1be8b
commit 1383fc8da3
4 changed files with 300 additions and 2 deletions
+156
View File
@@ -0,0 +1,156 @@
import { reactive, watch } from "vue"
import type { Torrent } from "../types"
export type ResolutionPreference = "r2" | "r3" | "r4" | "rmax"
export type HdrPreference = "none" | "hdr10plus" | "dovi"
export interface MediaHiveSettings {
preferredResolution: ResolutionPreference
preferredHdr: HdrPreference
}
const STORAGE_KEY = "MediaHive"
const RESOLUTION_PRIORITY: Record<string, number> = {
"8K": 5,
"4K": 4,
"FHD": 3,
"HD": 2,
"SD": 1,
}
// Max resolution priority allowed for each preference level
const RESOLUTION_CAP: Record<ResolutionPreference, number> = {
r2: 2,
r3: 3,
r4: 4,
rmax: 999,
}
const RESOLUTION_VALUES = ["r2", "r3", "r4", "rmax"] as const
const HDR_VALUES = ["none", "hdr10plus", "dovi"] as const
function isResolutionPreference(value: unknown): value is ResolutionPreference {
return typeof value === "string" && RESOLUTION_VALUES.includes(value as ResolutionPreference)
}
function isHdrPreference(value: unknown): value is HdrPreference {
return typeof value === "string" && HDR_VALUES.includes(value as HdrPreference)
}
function loadSettings(): MediaHiveSettings {
try {
const raw = localStorage.getItem(STORAGE_KEY)
if (raw) {
const parsed = JSON.parse(raw) as Partial<MediaHiveSettings>
return {
preferredResolution: isResolutionPreference(parsed.preferredResolution)
? parsed.preferredResolution
: "rmax",
preferredHdr: isHdrPreference(parsed.preferredHdr) ? parsed.preferredHdr : "none",
}
}
} catch {
// ignore parse errors
}
return { preferredResolution: "rmax", preferredHdr: "none" }
}
const settings = reactive<MediaHiveSettings>(loadSettings())
watch(
() => ({ ...settings }),
(value) => {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(value))
} catch {
// ignore
}
},
{ deep: true },
)
export function useSettings() {
return settings
}
/**
* Sort a list of Torrent objects according to the current format preferences.
*
* Algorithm:
* 1. Compute the "effective priority" = min(actual priority, cap).
* Releases exceeding the cap receive the capped priority.
* 2. Higher effective priority wins.
* 3. For equal effective priority, prefer HDR flavor per `preferredHdr`.
* 4. Equal in all above: fall back to raw resolution priority (larger is better)
* then size.
*/
export function sortTorrentsByPreference(torrents: Torrent[]): Torrent[] {
const cap = RESOLUTION_CAP[settings.preferredResolution]
function effectivePriority(t: Torrent): number {
const raw = RESOLUTION_PRIORITY[t.resolution ?? ""] ?? 0
return Math.min(raw, cap)
}
type HdrProfile = "sdr" | "hdr10" | "hdr10plus" | "dovi"
function detectHdrProfile(t: Torrent): HdrProfile {
const text = [t.title, t.quality, t.codec, t.audio].filter(Boolean).join(" ")
const hasDovi = t.has_dolby_vision || /dolby\s*vision|dovi|\bdv\b/i.test(text)
const hasHdr10Plus = /hdr10\+|hdr10plus/i.test(text)
const hasAnyHdr = t.is_hdr || hasHdr10Plus || hasDovi || /\bhdr\b/i.test(text)
if (hasDovi) return "dovi"
if (hasHdr10Plus) return "hdr10plus"
if (hasAnyHdr) return "hdr10"
return "sdr"
}
function scoreForPreference(profile: HdrProfile): number {
if (settings.preferredHdr === "none") {
// Prefer no HDR; HDR variants after SDR.
if (profile === "sdr") return 4
if (profile === "hdr10") return 3
if (profile === "hdr10plus") return 2
return 1
}
if (settings.preferredHdr === "hdr10plus") {
// Requested behavior: HDR10+ best, HDR10 next, SDR then, DoVi last.
if (profile === "hdr10plus") return 4
if (profile === "hdr10") return 3
if (profile === "sdr") return 2
return 1
}
if (profile === "dovi") return 4
if (profile === "hdr10plus") return 3
if (profile === "hdr10") return 2
return 1
}
function hdrPreferenceScore(t: Torrent): number {
return scoreForPreference(detectHdrProfile(t))
}
return [...torrents].sort((a, b) => {
const epA = effectivePriority(a)
const epB = effectivePriority(b)
if (epB !== epA) return epB - epA
// Same effective resolution bucket - apply HDR format preference
const hdrScoreA = hdrPreferenceScore(a)
const hdrScoreB = hdrPreferenceScore(b)
if (hdrScoreB !== hdrScoreA) {
return hdrScoreB - hdrScoreA
}
// Fall back to raw resolution priority then size
const rawA = RESOLUTION_PRIORITY[a.resolution ?? ""] ?? 0
const rawB = RESOLUTION_PRIORITY[b.resolution ?? ""] ?? 0
if (rawB !== rawA) return rawB - rawA
return (b.size ?? 0) - (a.size ?? 0)
})
}