dart_rip_log
A pure Dart library that parses CD rip log files from the major CD-ripping tools (EAC, XLD) into structured, JSON-serialisable quality data. Extracts AccurateRip verification status, CRC-32 checksums, peak levels, track quality, and per-track error statistics.
Zero runtime dependencies beyond the Dart SDK.
Features
- Auto-detects the log format from the log content.
- EAC (Exact Audio Copy) — full parser, including:
- Header: tool version, extraction date, drive, read mode, read offset, overread, gap handling, media type.
- Per track: filename, peak level, track quality, test/copy CRCs, Copy OK.
- AccurateRip:
verified(with confidence, v1 CRC and optional v2 signature),mismatch,notInDatabase. - Full error-statistics block (read / skip / edge jitter / atom jitter / drift / dropped bytes / duplicated bytes / inconsistency).
- Footer: summary line and log checksum.
- Range-rip logs (single-track whole-disc extractions).
- XLD (X Lossless Decoder) — full parser, including per-track AR v1/v2
signatures and the
Statisticsblock. - CUERipper, whipper, dBpoweramp — format detection and scaffolded parsers (tool version captured; full per-track parsing pending real-world sample logs).
- Tolerant of malformed input: truncated files, garbled lines, CRLF/LF/mixed
line endings, and missing fields return a best-effort
RipLograther than throwing. toJson()on every model for easy serialisation.- Command-line tool (
bin/riplog.dart) for quick inspection.
Installing
Add to your pubspec.yaml:
dependencies:
dart_rip_log: ^0.0.1
Then:
dart pub get
Quick start
import 'dart:io';
import 'package:dart_rip_log/dart_rip_log.dart';
Future<void> main(List<String> args) async {
final log = await parseRipLogFile(args.first);
print('Format: ${log.logFormat.name}');
print('Tool: ${log.toolVersion}');
print('Tracks: ${log.tracks.length}');
print('Verified: ${isFullyVerified(log)}');
for (final track in tracksWithArMismatch(log)) {
print(' ! Track ${track.trackNumber} did not verify against AccurateRip');
}
}
Parsing from a string
final log = parseRipLog(logContent);
if (log.logFormat == RipLogFormat.unknown) {
// Format could not be identified — handle gracefully.
}
Convenience helpers
-
isFullyVerified(log)—truewhen every track has AccurateRip statusverified. -
tracksWithErrors(log)— tracks whoseTrackErrors.hasErrorsis true. -
tracksWithArMismatch(log)— tracks whose AccurateRip check failed. -
toJson(log)— JSON-compatibleMap<String, dynamic>. -
RipLog.fromJson(map)— inverse oftoJson. All models support round-trip serialisation. -
compareRipLogs(a, b)— structured per-field diff between two logs, useful for verifying re-rips:final diff = compareRipLogs(oldLog, newLog); for (final e in diff.trackDifferences) { print('${e.path}: ${e.left} → ${e.right}'); }
Command-line tool
Install globally:
dart pub global activate dart_rip_log
Then:
riplog --format json my_rip.log # pretty-printed JSON (default)
riplog --format text my_rip.log # human-readable
riplog --format ndjson *.log # one JSON per line (jq-friendly)
riplog --summary my_rip.log # one line per track
riplog -q *.log # tab-separated one line per file
riplog -r ~/music/rips/ # walk directory for *.log
riplog --filter problems log.log # only mismatch / errored tracks
riplog --fail-on mismatch -q *.log # exit 1 only on AR mismatch
riplog --color always log.log | less -R # keep colour through pagers
cat my_rip.log | riplog -q - # read from stdin
riplog --help # full usage
Exit-code policy is controlled by --fail-on:
| Policy | Exits 1 when… |
|---|---|
any |
default — any AR mismatch or track error counts |
mismatch |
any AR mismatch |
errors |
any track error counts |
never |
never (always exits 0 on successful parse) |
2 is always returned for bad arguments or I/O errors. With multiple files
the JSON output is an array (one entry per file); ndjson emits one object
per line; text / --summary each file is prefixed with # <path>.
Colour output respects NO_COLOR and stdout.hasTerminal by default.
Data model
| Class | Purpose |
|---|---|
RipLog |
Top-level result — header fields + tracks. |
RipLogTrack |
Per-track quality data (unified across formats). |
TrackErrors |
Per-track error counters. |
DriveInfo |
Optical drive name, read offset, adapter. |
LogSource |
Lineage metadata: byte size, line count, parser, timestamp. |
RipLogFormat (enum) |
eac, xld, cueRipper, whipper, dbPoweramp, unknown. |
AccurateRipStatus (enum) |
verified, mismatch, notInDatabase, notChecked. |
RipLogQuality (enum) |
allVerified, partiallyVerified, mismatches, errors, unknown. |
RipLog.quality returns a single-value summary of the whole log. Precedence
(most severe first): errors > mismatches > partiallyVerified >
allVerified > unknown.
Error tolerance
The library never throws on malformed content. It may still throw at the
file-I/O layer — for example, parseRipLogFile will throw a
FileSystemException when given a non-UTF-8 binary file. On truncated,
garbled, or partially-unknown input the parser returns a RipLog with
whatever it could extract; any parsing warnings are collected in
RipLog.errors.
JSON shape
Calling toJson(log) (or log.toJson()) returns a stable, JSON-compatible
Map<String, dynamic>. The shape is pinned by golden tests in
test/fixtures/*.expected.json — any intentional change requires regenerating
the goldens. Top-level keys:
logFormat, toolVersion, extractionDate, drive, readMode, readOffset,
overread, gapHandling, mediaType, tracks[], accurateRipSummary,
integrityHash, errors[]
Each track includes: trackNumber, filename, peakLevel, trackQuality, copyCrc, testCrc, accurateRipStatus, accurateRipCrcV1, accurateRipCrcV2, accurateRipConfidence, copyOk, errors{}, logFormat. Numeric peak/quality
values are fractions in [0.0, 1.0]. Dates are ISO-8601 strings. Optional
fields are omitted when null.
Running the tests
dart test # full suite (unit + CLI integration)
dart test --exclude-tags cli # fast: skip shell-out tests
The test suite covers header/track/footer parsing, AccurateRip variants, per-track error statistics, line-ending tolerance, Unicode filenames (Latin accents, CJK, emoji), a 500-track performance smoke, CLI behaviour, and JSON-shape golden tests.
Contributing
Issues and pull requests welcome on GitHub. Additional real-world log samples from CUERipper, whipper, and dBpoweramp would be especially valuable for finishing those parsers.
Licence
Apache-2.0. See LICENSE.
Libraries
- dart_rip_log
- A pure Dart library that parses CD rip log files from EAC, XLD, and other rippers into structured, JSON-serialisable quality data.