Ampel / ampel (push) Failing after 1m18s
komprimieren/: handbrake.ts traegt ALLE bezahlten Fallen aus dem Docker-Zweig — --aencoder statt --audio-codec (mit Anti-Regressions- Wächter im Test: der alte Test hatte den Fehler FESTGESCHRIEBEN), --format aus der Endung (Container kommt sonst aus dem Preset), Fortschritt NUR aus der Encoding-Zeile (Scan-99%-Falle), letzte 12 Zeilen fuer den Fehlerfall, unknown-option-Erkennung VOR allem anderen (kommt mit Rueckgabewert 0!), Datei-daneben-Suche, CR-Zeilentrennung mit 0x81-Kodierungsfalle. encoder.ts misst statt behauptet (--help, --preset-list, Familien statt Sammelbegriff). presets.ts: je Disc-Typ, PRESET_KEINE, Sprachlisten. ablage/: struktur.ts (sichere Namen, '<Titel> (Jahr)', Season NN, Episoden-Zuordnung NUR bei Eindeutigkeit), nfo.ts (Kodi-Schema), medienserver.ts (Jellyfin/Emby/Kodi-Refresh, wirft nie). ablauf/pipeline.ts ERSETZT rippen.ts: Rip → Kompression → Ablage als EINE Kette; Kompressions-Fehler laesst den verlustfreien Rip STEHEN und nennt den Ort; Lesefehler ueberleben bis in die Fertig-Meldung. Roh wird in dieser Etappe grundsaetzlich behalten (Loeschen erst mit W-5-UI). GEMESSEN am echten System (30.08.2026): - Encoder: 22 Stueck, Backends cpu-x264/x265/av1 + vce + vce-av1 (RX 9070 XT als VCE-Familie — nicht unter Intel-Namen), 107 Presets. - Probe-Encode 5 s Material: success in 45,5 s. - VOLLBEWEIS: Spartacus-Rohschnitt (17,71 GB — die Datei, die in rc11 am falschen Schalter starb) mit Preset 'H.265 VCN 1080p' in 2,1 min auf 1,17 GB komprimiert und nach Jellyfin-Schema abgelegt: E:\Rippy-v5-Beweis\Filme\Spartacus - Gods of the Arena - Disc 2 (2011)\ mit movie.nfo. - Nebenbefund: Der Evangelion-Roh-Rip vom 29.08. traegt 'This file was not properly finalized' im Kopf — 23,5 GB, die wie fertig aussehen und es nicht sind (der abgebrochene rc11-Rip). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
82 lines
3.6 KiB
TypeScript
82 lines
3.6 KiB
TypeScript
// DER W-3-BEWEIS: kompletter Encode einer echten Roh-MKV plus Ablage in
|
|
// echter Jellyfin-Struktur (Ordner „<Titel> (Jahr)" + movie.nfo). Läuft
|
|
// nur auf Verlangen und dauert je nach Material 20 min bis Stunden:
|
|
//
|
|
// RIPPY_MESSUNG_ENCODE=1 RIPPY_MESSUNG_MKV=<roh.mkv> \
|
|
// RIPPY_MESSUNG_ABLAGE=<basis> RIPPY_MESSUNG_TITEL=<titel> \
|
|
// RIPPY_MESSUNG_JAHR=<jahr> [RIPPY_MESSUNG_PRESET=<preset>] \
|
|
// npx vitest run test/messung.encode-voll.test.ts --reporter=verbose
|
|
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
|
|
import { win32 as pfad } from 'node:path'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const messen = process.env.RIPPY_MESSUNG_ENCODE === '1' && process.platform === 'win32'
|
|
const rohMkv = process.env.RIPPY_MESSUNG_MKV ?? ''
|
|
const ablageBasis = process.env.RIPPY_MESSUNG_ABLAGE ?? ''
|
|
const titel = process.env.RIPPY_MESSUNG_TITEL ?? 'Unbenannt'
|
|
const jahr = process.env.RIPPY_MESSUNG_JAHR ?? ''
|
|
const preset = process.env.RIPPY_MESSUNG_PRESET ?? 'H.265 MKV 1080p30'
|
|
|
|
describe.skipIf(!messen)('Voller Encode + Ablage am echten System', () => {
|
|
it('komprimiert und legt nach Jellyfin-Schema ab', { timeout: 8 * 60 * 60 * 1000 }, async () => {
|
|
expect(rohMkv.length, 'RIPPY_MESSUNG_MKV fehlt').toBeGreaterThan(0)
|
|
expect(existsSync(rohMkv), `${rohMkv} fehlt`).toBe(true)
|
|
expect(ablageBasis.length, 'RIPPY_MESSUNG_ABLAGE fehlt').toBeGreaterThan(0)
|
|
|
|
const { finden } = await import('../src/kern/werkzeuge/katalog')
|
|
const { komprimieren } = await import('../src/kern/komprimieren/handbrake')
|
|
const { zielordner } = await import('../src/kern/ablage/struktur')
|
|
const { baueNfo } = await import('../src/kern/ablage/nfo')
|
|
|
|
const programm = finden('handbrake')
|
|
expect(programm.length).toBeGreaterThan(0)
|
|
|
|
const ordner = zielordner(ablageBasis, titel, jahr.length > 0 ? jahr : null, 'v5-beweis')
|
|
mkdirSync(ordner, { recursive: true })
|
|
const ausgabe = pfad.join(ordner, pfad.basename(ordner) + '.mkv')
|
|
|
|
console.log(`ENCODE-START ${rohMkv} → ${ausgabe} · Preset „${preset}"`)
|
|
const start = Date.now()
|
|
let letzteStufe = -5
|
|
const ergebnis = await komprimieren({
|
|
programm,
|
|
eingabe: rohMkv,
|
|
ausgabe,
|
|
preset,
|
|
audioSprachen: ['deu', 'eng'],
|
|
aufFortschritt: (prozent) => {
|
|
if (prozent >= letzteStufe + 5) {
|
|
letzteStufe = prozent
|
|
console.log(`ENCODE-FORTSCHRITT ${prozent}% nach ${((Date.now() - start) / 60000).toFixed(1)}min`)
|
|
}
|
|
},
|
|
})
|
|
const minuten = ((Date.now() - start) / 60000).toFixed(1)
|
|
|
|
if (ergebnis.status !== 'success') {
|
|
console.log(`ENCODE-ERGEBNIS ${ergebnis.status} nach ${minuten}min: ${'fehler' in ergebnis ? ergebnis.fehler : ''}`)
|
|
}
|
|
expect(ergebnis.status).toBe('success')
|
|
if (ergebnis.status !== 'success') return
|
|
|
|
const rohGb = statSync(rohMkv).size / 1e9
|
|
const fertigGb = statSync(ergebnis.ausgabe).size / 1e9
|
|
console.log(
|
|
`ENCODE-ERGEBNIS success nach ${minuten}min · ${rohGb.toFixed(2)} GB → ${fertigGb.toFixed(2)} GB` +
|
|
(ergebnis.hinweis !== undefined ? ` · ${ergebnis.hinweis}` : ''),
|
|
)
|
|
|
|
const nfoPfad = pfad.join(ordner, 'movie.nfo')
|
|
writeFileSync(nfoPfad, baueNfo({ quelle: 'Rippy v5 W-3-Beweis' }, titel, jahr.length > 0 ? jahr : null))
|
|
console.log(`ABLAGE-FERTIG ${ordner} (movie.nfo + ${pfad.basename(ergebnis.ausgabe)})`)
|
|
expect(existsSync(nfoPfad)).toBe(true)
|
|
expect(fertigGb).toBeGreaterThan(0.05)
|
|
})
|
|
})
|
|
|
|
describe.skipIf(messen)('Encode-Messung übersprungen', () => {
|
|
it('läuft nur mit RIPPY_MESSUNG_ENCODE=1 unter Windows', () => {
|
|
expect(true).toBe(true)
|
|
})
|
|
})
|