// ── Auswahl: WAS soll gerippt werden? (§ 6.2) ─────────────────────────── // Bis zum 01.09.2026 rippte Rippy IMMER alles — Trailer, Werbung und // Alterskennzeichen inklusive. Der Info-Lauf dauert 20–120 s, deshalb // beginnt er erst hier und nicht schon beim Einlegen. // 5.4.0: Sprachen je Titel, Staffel/Folge von Hand, Zielpfad-Vorschau. // 5.5.0: Platz-Prüfung vor dem Rip und der Serien-Merker (Folge von Disc 1 // zählt auf Disc 2 weiter). // 5.6.0 (Commander): Je Extra WELCHE Untertitel-Spur beim Abspielen // vorgewählt ist (weiche Spur, nie eingebrannt, immer optional) — und je // Titel „anderer Film …": Double Feature, Trilogie-Disc, Bonus-Film bekommen // eigenen Roh-Ordner, Vorgang und Zielordner. // 5.7.0 (Commander, 12.09.2026): JEDE Spur einzeln anhaken — „Deutsch · // DTS-HD MA · 5.1" und „Deutsch · DD · 2.0 (Kommentar)" getrennt, Untertitel // genauso. Die Sprach-Chips bleiben nur als Rückfall, wenn ein Titel keine // einzelnen Spuren meldet. import { useState } from 'react' import { sichererName, zielVorschau } from '../../gemeinsam/ablagepfad' import { platzUrteil } from '../../gemeinsam/platz' import type { DiscInfoStand, DiscTitelVorschlag, GeraeteInfo, MetaVorschlag, SpeicherStand, SprachEintrag, SpurAngabe, TitelRolle, TitelStand, } from '../../gemeinsam/nachrichten' import { angeboten, sprachenDerSpuren, spurenVorbelegt, spurLabel } from '../../gemeinsam/spuren' import { DialogRahmen, IconDisc, KNOPF_GOLD, datumKurz, dauerText, gb, gbKurz, posterUrlKlein, sprachenVorbelegt } from '../bausteine' import { metadatenSuchen, ripStarten, titelAbbrechen } from '../kernverbindung' /** Sprach-Chips eines Titels — anklickbar, außerhalb des Auswahl-Labels * (ein Knopf IM Label würde die Checkbox mit umschalten). */ function SprachChips({ name, vorhanden, gewaehlt, aufWechsel, }: { name: string vorhanden: readonly SprachEintrag[] gewaehlt: readonly string[] aufWechsel: (lang: string) => void }) { if (vorhanden.length === 0) return null return ( {name} {vorhanden.map((s) => { const an = gewaehlt.includes(s.lang) return ( ) })} ) } /** Spur-Zeilen eines Titels (5.7.0): jede Ton- bzw. Untertitelspur einzeln * anhaken, mit Codec und Kanälen, wie MakeMKV sie gemessen hat. Außerhalb * des Auswahl-Labels (ein Haken IM Label würde den Titel mit umschalten). */ function SpurZeilen({ name, art, vorhanden, gewaehlt, aufWechsel, }: { name: string art: 'audio' | 'untertitel' vorhanden: readonly SpurAngabe[] gewaehlt: readonly number[] aufWechsel: (nr: number) => void }) { const zeilen = vorhanden.filter((s) => angeboten(s, art)) if (zeilen.length === 0) return null return (
Rippy liest die Titel der Disc … meist dauert das ein bis zwei Minuten. Solange dreht das Laufwerk.
{/* 5.7.0 (Kandidat 2): Ab der zweiten Minute sagt der Kern, wie lange es schon läuft und wo die Grenze liegt. */} {stand !== undefined && stand.einordnung.length > 0 &&{stand.einordnung}
}✗ {stand.fehler}
) : ( <>{stand.unsicher ? '⚠ ' : ''} {stand.einordnung}
Noch keine Treffer — Titel eingeben und suchen (braucht den TMDb-Schlüssel).
) : (Die Disc gab keine Titel her.
}{merkerGilt && merker !== null ? `Serien-Merker: Die vorige Disc dieser Serie endete mit Folge ${merker.naechsteFolge - 1} (${datumKurz(merker.wann).slice(0, 10)}) — Rippy zählt ab ${merker.naechsteFolge} weiter. Stimmt das nicht, ändere die Zahl.` : 'Leer heißt: Rippy ordnet die Folgen über die TMDb-Laufzeiten zu, und nur, wenn es eindeutig ist. Weißt du es besser („auf Disc 2 sind die Folgen 3 und 4"), trag es hier ein — dann zählt Rippy fortlaufend in Disc-Reihenfolge.'} {info !== undefined && info.discNr !== null && ` Die Disc nennt sich selbst Disc ${info.discNr}.`}
LANDET IN
{eigeneTitel.length > 0 && ( <>{vorschau[0]}
{vorschau[1]}
> )} {[...andereFilme.values()].map(({ film, titel }) => ({`${ablage.replace(/[\\/]+$/, '')}\\Filme\\${sichererName(film.titel, film.jahr) || film.titel}\\`} {' '} — {titel} {titel === 1 ? 'Titel' : 'Titel'}, eigener Vorgang mit Poster und Infodatei
))}0 ? 'text-warn' : 'text-nebel'}`}> {platz.text.length > 0 ? `${platz.hart ? '✗' : '⚠'} ${platz.text}` : `Platz: ${gbKurz(speicher.arbeit.freiBytes)} frei im Arbeitsordner — reicht für ${gb(gesamtBytes)} verlustfrei${komprimiert ? ' plus Kompression' : ''}.`}
)}{aktiv.size} von {alle.length} gewählt · zusammen {gb(gesamtBytes)} verlustfrei {regel.length > 0 ? ` · ${regel}` : ''}
{alsSerie ? 'Folgen landen unter Serien/… /Season NN. Ohne Vorgabe setzt Rippy die Episoden-Nummern nur, wenn die Laufzeiten eindeutig passen — sonst behalten die Dateien ihre Namen.' : 'Der Hauptfilm landet in seinem eigenen Ordner, Extras daneben im Unterordner „extras" — so lesen Jellyfin, Emby und Kodi sie als Zugaben.'}{' '} Das Laufwerk ist frei, sobald die Roh-Dateien liegen — die Kompression läuft danach im Hintergrund.
> )}