Ampel / ampel (push) Failing after 1m22s
rip/parser.ts: die reine Textverarbeitung mit allen bezahlten Fallen aus dem Docker-Zweig — quelle() (dev:G: statt dev:\.\G:, der 404-Verwandte), textVon() (UTF-8 streng, sonst cp1252 — nie wieder 'Öffnen'), parseMsg (Regex statt split — Meldungen mit Komma), PRGV (-1 vs. echtes 0 %), TINFO/SINFO (Sprache aus Attr 3/4, NICHT 28/29), laengsterTitel mit Play-All-Schutz, episodenTitel, KRITISCHE_CODES (sprachfeste NUMMERN). rip/makemkv.ts: Kommandobau + Lauf — ZeilenLeser (binaer, halbe Zeilen, je Zeile dekodiert), RipAuswertung (pur), rippen() mit AbortSignal, Lesefehler-Flag AUCH bei Rueckgabewert 0. werkzeuge/katalog.ts: die Suchreihenfolge samt %VAR%-Gross/Klein-Falle und Registry-Rueckfall. ablauf/rippen.ts: ein Rip je Laufwerk, Status-Push, 'erst nachsehen, dann rippen' (unbekannt heisst trotzdem rippen). Fenster: Rippen-Knopf, Fortschrittsbalken, Abbrechen; Auswurf waehrend des Rips abgelehnt. Gemessen am echten System (30.08.2026): Katalog findet makemkvcon64 (Program Files x86), HandBrakeCLI und flac (beide im rc11-Werkzeugordner LOCALAPPDATA\Rippy\tools). NEUER BEFUND: Nach dem abgebrochenen rc11-Rip vom Mittag sieht MakeMKV GAR KEIN Laufwerk mehr (MSG 5042, leere DRV-Liste, mit und ohne --noscan), waehrend die Storage-IOCTLs sauber antworten — MakeMKV spricht SCSI direkt. 5042 ist jetzt ein KRITISCHER_CODE mit Klartext-Abhilfe. Der volle Rip-Beweis (messung.rip.test.ts liegt bereit) braucht deshalb erst eine Hand am Geraet: Disc neu einlegen oder USB ab-/anstecken. 96 Tests gruen, Smoke gruen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
75 lines
2.8 KiB
TypeScript
75 lines
2.8 KiB
TypeScript
// Tests der Rip-Lauf-Bausteine: Zeilenzerlegung (binär, halbe Zeilen)
|
|
// und die Auswertung (Fortschritt, Lesefehler, kritische Ursachen) —
|
|
// alles ohne echtes makemkvcon.
|
|
import { describe, expect, it } from 'vitest'
|
|
import { buildInfoArgs, buildRipArgs, RipAuswertung, ZeilenLeser } from '../src/kern/rip/makemkv'
|
|
|
|
describe('Kommandobau', () => {
|
|
it('info: Robot-Mode ohne Geräte-Scan', () => {
|
|
expect(buildInfoArgs('\\\\.\\G:')).toEqual(['-r', '--noscan', 'info', 'dev:G:'])
|
|
})
|
|
it('mkv: Fortschritt in denselben Strom', () => {
|
|
expect(buildRipArgs('\\\\.\\G:', 'C:\\ziel', 'all')).toEqual([
|
|
'-r',
|
|
'--noscan',
|
|
'--progress=-same',
|
|
'mkv',
|
|
'dev:G:',
|
|
'all',
|
|
'C:\\ziel',
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('ZeilenLeser — binär, halbe Zeilen bleiben liegen', () => {
|
|
it('setzt Zeilen über Stück-Grenzen zusammen', () => {
|
|
const leser = new ZeilenLeser()
|
|
expect(leser.hinzu(Buffer.from('PRGV:1,2,'))).toEqual([])
|
|
expect(leser.hinzu(Buffer.from('65536\r\nMSG:1,0,0,"a"\nRest'))).toEqual([
|
|
'PRGV:1,2,65536',
|
|
'MSG:1,0,0,"a"',
|
|
])
|
|
expect(leser.schluss()).toEqual(['Rest'])
|
|
})
|
|
it('dekodiert jede Zeile einzeln — auch cp1252 mitten im Strom', () => {
|
|
const leser = new ZeilenLeser()
|
|
const zeilen = leser.hinzu(
|
|
Buffer.concat([Buffer.from('MSG:5010,0,0,"Das '), Buffer.from('Öffnen', 'latin1'), Buffer.from('"\n')]),
|
|
)
|
|
expect(zeilen).toEqual(['MSG:5010,0,0,"Das Öffnen"'])
|
|
})
|
|
})
|
|
|
|
describe('RipAuswertung', () => {
|
|
it('meldet Fortschritt nur bei Änderung', () => {
|
|
const a = new RipAuswertung()
|
|
expect(a.verarbeite('PRGV:0,32768,65536')).toEqual({ prozent: 50 })
|
|
expect(a.verarbeite('PRGV:0,32769,65536')).toEqual({})
|
|
expect(a.verarbeite('PRGV:0,45876,65536')).toEqual({ prozent: 70 })
|
|
})
|
|
|
|
it('erkennt Lesefehler an der sprachfesten URL — auch auf Deutsch', () => {
|
|
const a = new RipAuswertung()
|
|
a.verarbeite(
|
|
'MSG:2003,0,3,"Encountered 29 errors of type \'Read Error\' - see http://www.makemkv.com/errors/read/","f"',
|
|
)
|
|
expect(a.lesefehler).toBe(true)
|
|
})
|
|
|
|
it('sammelt kritische URSACHEN über die Nummer, nicht den Text', () => {
|
|
const a = new RipAuswertung()
|
|
a.verarbeite('MSG:5051,0,0,"Der Testzeitraum ist abgelaufen. Erwerben Sie bitte einen Schlüssel"')
|
|
a.verarbeite('MSG:5010,0,0,"Das Öffnen der Disk schlug fehl"')
|
|
const fehler = a.fehlerText(11, false)
|
|
expect(fehler).toContain('Code 11')
|
|
expect(fehler).toContain('nicht freigeschaltet')
|
|
expect(fehler).toContain('keine MKV-Datei entstanden')
|
|
})
|
|
|
|
it('englische Textmuster bleiben als Rückfall', () => {
|
|
const a = new RipAuswertung()
|
|
a.verarbeite('MSG:9999,0,0,"AACS volume key is unknown for this disc"')
|
|
expect(a.kritischeMeldungen).toHaveLength(1)
|
|
})
|
|
})
|