From 0fc87aa0228cdf5ddf65e58f5d970b15735cab64 Mon Sep 17 00:00:00 2001 From: Hitonabi Date: Sat, 12 Sep 2026 21:48:38 +0200 Subject: [PATCH] =?UTF-8?q?feat(v5):=204K-UHD=20nach=20der=20Leistung=20?= =?UTF-8?q?=E2=80=94=20Grafikkarte=20mit=204K-Preset=20komprimiert,=20nur?= =?UTF-8?q?=20CPU=20bleibt=20verlustfrei?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WAS: presetEmpfehlung liefert für UHD das 4K-Preset der gemessenen Grafikkarten-Familie (VCN/NVENC/QSV) — sonst PRESET_KEINE (verlustfrei); komprimierenFuer folgt der Empfehlung, wenn der Typ auf „automatisch" steht. Eigene Wahl schlägt beides. Fenster: Kachel, Kompressions-Karte und Erst-Einrichtung sagen „(8 Bit)" bzw. „verlustfrei — nur CPU-Encoder". Gemessen am 12.09.2026 (HandBrake 1.11.2, RX 9070 XT, Akira-UHD-Abbild): die 4K-Hardware-Presets sind 8-Bit (vce_h265, Profil main); der 10-Bit- HEVC-Encoder vce_h265_10bit stürzt beim Start ab (Segfault, mit Profil auto und main10); AV1 10-Bit („AV1 VCN 2160p 4K", vce_av1_10bit) läuft — steht als eigene Wahl in der Liste, mit dem Hinweis auf AV1-fähige Abspielgeräte. WARUM: Durchsicht 12.09.2026, A4 — Commander-Entscheid: „Rippy analysiert doch die Performance des PCs, könnten wir das nicht davon abhängig machen?" Vorher rechnete der CPU-Default 4K auf 1080p klein, tagelang. Co-Authored-By: Claude Opus 5 --- .../fenster/einrichtung/ErstEinrichtung.tsx | 4 +- .../src/fenster/einstellungen/Karten.tsx | 7 +-- .../src/fenster/uebersicht/LaufwerkKachel.tsx | 8 ++-- .../src/gemeinsam/preset-empfehlung.ts | 33 +++++++++++-- rippy-windows/src/kern/ablauf/ablegen.ts | 2 +- .../src/kern/komprimieren/presets.ts | 16 +++---- rippy-windows/test/vierk-regel.test.ts | 47 +++++++++++++++++++ 7 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 rippy-windows/test/vierk-regel.test.ts diff --git a/rippy-windows/src/fenster/einrichtung/ErstEinrichtung.tsx b/rippy-windows/src/fenster/einrichtung/ErstEinrichtung.tsx index 6b387f2..7a4bbd9 100644 --- a/rippy-windows/src/fenster/einrichtung/ErstEinrichtung.tsx +++ b/rippy-windows/src/fenster/einrichtung/ErstEinrichtung.tsx @@ -7,7 +7,7 @@ // Werkzeuge mit Durchsuchen, Kompression mit Sprach-Auswahl, TMDb, // Benachrichtigung, Automatik und Roh-Regel. Dazu der Poster-Hintergrund. import { useEffect, useState } from 'react' -import { DEFAULT_HB_PRESET, presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' +import { DEFAULT_HB_PRESET, empfehlungText, presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' import { Badge, FELD_KLASSE, Feld, KNOPF_GOLD, KNOPF_LEISE, PfadFeld, Schalter, gbKurz } from '../bausteine' import { SprachAuswahl } from '../einstellungen/SprachAuswahl' import { benachrichtigungTesten, einstellungSetzen, posterLaden, speicherLaden, type Verbindung } from '../kernverbindung' @@ -167,7 +167,7 @@ export function ErstEinrichtung({ verbindung }: { verbindung: Verbindung }) { {EMPFEHLUNGEN.map(([name, typ]) => (

{name}

-

{presetEmpfehlung(typ, backends, presets) || DEFAULT_HB_PRESET}

+

{empfehlungText(typ, presetEmpfehlung(typ, backends, presets) || DEFAULT_HB_PRESET)}

))} diff --git a/rippy-windows/src/fenster/einstellungen/Karten.tsx b/rippy-windows/src/fenster/einstellungen/Karten.tsx index f11e67a..5d3fe09 100644 --- a/rippy-windows/src/fenster/einstellungen/Karten.tsx +++ b/rippy-windows/src/fenster/einstellungen/Karten.tsx @@ -4,7 +4,7 @@ // einstellungSetzen in die EINE Quelle (§ 6.7). import { useState } from 'react' import type { GeraeteInfo, HauptStatus, VorgangEintrag } from '../../gemeinsam/nachrichten' -import { presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' +import { empfehlungText, presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' import { Badge, FELD_KLASSE, @@ -127,7 +127,7 @@ export function KompressionKarte({ verbindung }: { verbindung: Verbindung }) { const werte = verbindung.einstellungen const presets = verbindung.werkzeuge?.presets ?? [] const backends = verbindung.werkzeuge?.backends ?? [] - const empfehlungFuer = (typ: string): string => presetEmpfehlung(typ, backends, presets) + const empfehlungFuer = (typ: string): string => empfehlungText(typ, presetEmpfehlung(typ, backends, presets)) return (

„automatisch" nimmt die Empfehlung aus der gemessenen Liste deines HandBrake — auf dieser Maschine die Grafikkarte, wo es sie gibt. Eine eigene Wahl - schlägt die Empfehlung immer. + schlägt die Empfehlung immer. 4K-UHD wird nur mit Grafikkarten-Encoder komprimiert (8 Bit); ohne bleibt es verlustfrei. Wer HDR in 10 Bit will, wählt + „AV1 VCN 2160p 4K" — die Abspielgeräte müssen dann AV1 können.

0) return eigene const empfehlung = presetEmpfehlung(typ, verbindung.werkzeuge?.backends ?? [], verbindung.werkzeuge?.presets ?? []) - const gewaehlt = eigene.length > 0 ? eigene : empfehlung.length > 0 ? empfehlung : DEFAULT_HB_PRESET - return gewaehlt === 'keine' ? 'ohne Kompression' : gewaehlt + if (empfehlung === PRESET_KEINE) return typ === 'uhd' ? 'verlustfrei (nur CPU-Encoder)' : 'ohne Kompression' + return empfehlungText(typ, empfehlung.length > 0 ? empfehlung : DEFAULT_HB_PRESET) } export function LaufwerkKachel({ diff --git a/rippy-windows/src/gemeinsam/preset-empfehlung.ts b/rippy-windows/src/gemeinsam/preset-empfehlung.ts index 90ba9a3..041c0c4 100644 --- a/rippy-windows/src/gemeinsam/preset-empfehlung.ts +++ b/rippy-windows/src/gemeinsam/preset-empfehlung.ts @@ -18,6 +18,11 @@ export const DEFAULT_HB_PRESET = 'H.265 MKV 1080p30' +// Reservierter Wert: „diesen Typ NICHT komprimieren". Kein echtes +// HandBrake-Preset heißt so (gegen alle 107 aus --preset-list geprüft). +// Lebt seit 5.7.0 hier, weil die Empfehlung ihn liefern kann. +export const PRESET_KEINE = 'keine' + const FAMILIEN: ReadonlyArray = [ ['vce', 'VCN'], ['nvenc', 'NVENC'], @@ -25,7 +30,19 @@ const FAMILIEN: ReadonlyArray ] /** Das empfohlene Preset für diesen Disc-Typ — aus den GEMESSENEN - * Backends und Preset-Namen. Fällt auf den CPU-Default zurück. */ + * Backends und Preset-Namen. DVD und Blu-ray fallen auf den CPU-Default + * zurück. + * + * 4K-UHD seit 5.7.0 nach der Leistung (Commander-Entscheid 12.09.2026): + * Gibt es einen Grafikkarten-Encoder UND dessen 4K-Preset, wird damit + * komprimiert; gibt es nur CPU-Encoder, bleibt UHD verlustfrei + * (PRESET_KEINE) — ein 4K-Encode auf der CPU dauert Tage, und der alte + * CPU-Default „1080p30" rechnete 4K klein. Gemessen am 12.09.2026: Die + * 4K-Hardware-Presets („H.265 VCN 2160p 4K" usw.) sind 8-Bit; der + * 10-Bit-HEVC-Encoder der AMD-Karte (vce_h265_10bit) stürzt in HandBrake + * 1.11.2 beim Start ab, 10-Bit-AV1 („AV1 VCN 2160p 4K") läuft — wer HDR + * in 10 Bit will, wählt das AV1-Preset selbst (Abspielgeräte müssen AV1 + * können). */ export function presetEmpfehlung( discTyp: string, backends: readonly string[], @@ -36,9 +53,19 @@ export function presetEmpfehlung( if (!backends.includes(backend)) continue const treffer = presets.find((p) => p.startsWith('H.265 ') && p.includes(kennung) && p.includes(gewuenscht)) if (treffer !== undefined) return treffer - // 4K-Familie ohne 4K-Preset: das 1080p-Pendant ist besser als CPU. + // Eine 4K-Disc ohne 4K-Preset der Familie: nicht klein rechnen — + // verlustfrei lassen (unten). Bei DVD/Blu-ray ist das 1080p-Pendant + // besser als CPU. + if (discTyp === 'uhd') continue const kleiner = presets.find((p) => p.startsWith('H.265 ') && p.includes(kennung)) if (kleiner !== undefined) return kleiner } - return DEFAULT_HB_PRESET + return discTyp === 'uhd' ? PRESET_KEINE : DEFAULT_HB_PRESET +} + +/** Klartext zur Empfehlung fürs Fenster (5.7.0). */ +export function empfehlungText(discTyp: string, empfehlung: string): string { + if (empfehlung === PRESET_KEINE) return discTyp === 'uhd' ? 'verlustfrei lassen — nur CPU-Encoder gemessen' : 'verlustfrei lassen' + if (discTyp === 'uhd' && /2160p/.test(empfehlung)) return `${empfehlung} (8 Bit)` + return empfehlung } diff --git a/rippy-windows/src/kern/ablauf/ablegen.ts b/rippy-windows/src/kern/ablauf/ablegen.ts index 46f7098..fd828c7 100644 --- a/rippy-windows/src/kern/ablauf/ablegen.ts +++ b/rippy-windows/src/kern/ablauf/ablegen.ts @@ -121,7 +121,7 @@ export async function komprimierenUndAblegen( ): Promise { const einstellungen = umgebung.einstellungen() const handbrake = umgebung.handbrake() - const soll = komprimierenFuer(auftrag.discTyp, einstellungen) + const soll = komprimierenFuer(auftrag.discTyp, einstellungen, umgebung.presetEmpfehlung?.(auftrag.discTyp) ?? '') const komprimiert = soll && handbrake.length > 0 const preset = auftrag.preset.length > 0 diff --git a/rippy-windows/src/kern/komprimieren/presets.ts b/rippy-windows/src/kern/komprimieren/presets.ts index 9de0e06..ae3f829 100644 --- a/rippy-windows/src/kern/komprimieren/presets.ts +++ b/rippy-windows/src/kern/komprimieren/presets.ts @@ -2,9 +2,9 @@ // mit den Befunden vom 25.07.2026 begründet: EIN Preset für alles rechnete // 4K auf 1080p herunter und DVDs hinauf. -import { DEFAULT_HB_PRESET, presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' +import { DEFAULT_HB_PRESET, PRESET_KEINE, presetEmpfehlung } from '../../gemeinsam/preset-empfehlung' -export { DEFAULT_HB_PRESET, presetEmpfehlung } +export { DEFAULT_HB_PRESET, PRESET_KEINE, presetEmpfehlung } /** Einstellungs-Schlüssel je Disc-Typ. */ export const PRESET_SCHLUESSEL: Record = { @@ -13,15 +13,12 @@ export const PRESET_SCHLUESSEL: Record = { uhd: 'transcodePresetUhd', } -// Reservierter Wert: „diesen Typ NICHT komprimieren". Kein echtes -// HandBrake-Preset heißt so (gegen alle 90 aus --preset-list geprüft). -// Grund: 4K verlustfrei durchreichen, DVDs trotzdem schrumpfen. -export const PRESET_KEINE = 'keine' - export type Einstellungen = Record -/** Soll dieser Disc-Typ nach dem Rip komprimiert werden? (pur) */ -export function komprimierenFuer(discTyp: string, einstellungen: Einstellungen): boolean { +/** Soll dieser Disc-Typ nach dem Rip komprimiert werden? (pur) + * 5.7.0: Steht der Typ auf „automatisch" und die gemessene Empfehlung + * sagt „keine" (4K ohne Grafikkarten-Encoder), bleibt es verlustfrei. */ +export function komprimierenFuer(discTyp: string, einstellungen: Einstellungen, empfehlung = ''): boolean { if (einstellungen['transcodeEnabled'] === false || einstellungen['transcodeEnabled'] === 'false') { return false } @@ -29,6 +26,7 @@ export function komprimierenFuer(discTyp: string, einstellungen: Einstellungen): if (schluessel.length > 0) { const wert = String(einstellungen[schluessel] ?? '').trim() if (wert === PRESET_KEINE) return false + if (wert.length === 0 && empfehlung === PRESET_KEINE) return false } return true } diff --git a/rippy-windows/test/vierk-regel.test.ts b/rippy-windows/test/vierk-regel.test.ts new file mode 100644 index 0000000..1653acf --- /dev/null +++ b/rippy-windows/test/vierk-regel.test.ts @@ -0,0 +1,47 @@ +// 5.7.0 — 4K nach der Leistung (Commander-Entscheid 12.09.2026): Grafik- +// karten-Encoder plus 4K-Preset → komprimieren; nur CPU → verlustfrei. +// Preset-Namen und Encoder am mitgelieferten HandBrake 1.11.2 gemessen +// (--preset-list, --help; vce_h265_10bit stürzt ab, AV1 10-Bit läuft). +import { describe, expect, it } from 'vitest' +import { DEFAULT_HB_PRESET, PRESET_KEINE, empfehlungText, presetEmpfehlung } from '../src/gemeinsam/preset-empfehlung' +import { komprimierenFuer, presetFuer } from '../src/kern/komprimieren/presets' + +const PRESETS = ['H.265 MKV 1080p30', 'H.265 MKV 2160p60 4K', 'AV1 VCN 2160p 4K', 'H.265 VCN 2160p 4K', 'H.265 VCN 1080p', 'H.265 NVENC 1080p'] +const NUR_CPU = ['cpu-x264', 'cpu-x265', 'cpu-av1'] +const AMD = [...NUR_CPU, 'vce', 'vce-av1'] +const NVIDIA_OHNE_4K = [...NUR_CPU, 'nvenc'] + +describe('presetEmpfehlung für 4K-UHD', () => { + it('Grafikkarte mit 4K-Preset → das 4K-Preset (8 Bit im Klartext)', () => { + expect(presetEmpfehlung('uhd', AMD, PRESETS)).toBe('H.265 VCN 2160p 4K') + expect(empfehlungText('uhd', 'H.265 VCN 2160p 4K')).toBe('H.265 VCN 2160p 4K (8 Bit)') + }) + it('nur CPU → verlustfrei lassen, nie das 1080p-CPU-Preset', () => { + expect(presetEmpfehlung('uhd', NUR_CPU, PRESETS)).toBe(PRESET_KEINE) + expect(empfehlungText('uhd', PRESET_KEINE)).toContain('verlustfrei') + }) + it('Grafikkarte ohne 4K-Preset → verlustfrei, nicht klein rechnen', () => { + expect(presetEmpfehlung('uhd', NVIDIA_OHNE_4K, PRESETS)).toBe(PRESET_KEINE) + }) + it('DVD und Blu-ray wie bisher: Grafikkarte, sonst CPU-Default', () => { + expect(presetEmpfehlung('bluray', AMD, PRESETS)).toBe('H.265 VCN 1080p') + expect(presetEmpfehlung('dvd', NUR_CPU, PRESETS)).toBe(DEFAULT_HB_PRESET) + expect(presetEmpfehlung('bluray', NVIDIA_OHNE_4K, PRESETS)).toBe('H.265 NVENC 1080p') + }) +}) + +describe('komprimierenFuer mit Empfehlung', () => { + it('automatisch + Empfehlung „keine" → nicht komprimieren', () => { + expect(komprimierenFuer('uhd', {}, PRESET_KEINE)).toBe(false) + expect(komprimierenFuer('uhd', { transcodePresetUhd: '' }, PRESET_KEINE)).toBe(false) + }) + it('eigene Wahl schlägt die Empfehlung — in beide Richtungen', () => { + expect(komprimierenFuer('uhd', { transcodePresetUhd: 'AV1 VCN 2160p 4K' }, PRESET_KEINE)).toBe(true) + expect(komprimierenFuer('uhd', { transcodePresetUhd: PRESET_KEINE }, 'H.265 VCN 2160p 4K')).toBe(false) + expect(presetFuer('uhd', { transcodePresetUhd: 'AV1 VCN 2160p 4K' }, PRESET_KEINE)).toBe('AV1 VCN 2160p 4K') + }) + it('Blu-ray bleibt unberührt', () => { + expect(komprimierenFuer('bluray', {}, 'H.265 VCN 1080p')).toBe(true) + expect(komprimierenFuer('bluray', {}, '')).toBe(true) + }) +})