feat: persist codec format and bitrate in download history

Bump the history schema on both the Kotlin finalizer and the Dart database to v9, adding bitrate (kbps) and format (codec label) columns, and let the download flow fill them from backend/probe metadata so lossy downloads keep a 'AAC 256kbps' label instead of falling back to the stored placeholder. Library filtering and the track metadata screen now read format/bitrate directly from those columns, which also fixes mis-tagged quality badges after re-downloading a track at a different format.

Additional fixes bundled in: EditFileMetadata now routes ReplayGain writes through the M4A path whenever the file starts with ftyp (fixing .flac files that actually hold MP4 containers); GetM4AQuality falls back to the first trak/mdia/mdhd duration when mvhd is zero so EAC3 streams no longer report 0s; and both Kotlin and Dart reject bitrate values below 16 kbps to prevent probe noise from surfacing as '0 kbps' labels. New unit tests cover the EAC3 mdhd fallback and the mis-named M4A replaygain path.
This commit is contained in:
zarzet
2026-05-10 23:18:32 +07:00
parent d664d46ca4
commit 8e605cbd0f
11 changed files with 451 additions and 57 deletions
+11 -1
View File
@@ -84,7 +84,7 @@ class HistoryDatabase {
return await openDatabase(
path,
version: 8,
version: 9,
onConfigure: (db) async {
await db.rawQuery('PRAGMA journal_mode = WAL');
await db.execute('PRAGMA synchronous = NORMAL');
@@ -124,6 +124,8 @@ class HistoryDatabase {
quality TEXT,
bit_depth INTEGER,
sample_rate INTEGER,
bitrate INTEGER,
format TEXT,
genre TEXT,
composer TEXT,
label TEXT,
@@ -203,6 +205,10 @@ class HistoryDatabase {
await _backfillNormalizedColumns(db);
await _createNormalizedIndexes(db);
}
if (oldVersion < 9) {
await _addColumnIfMissing(db, 'history', 'bitrate', 'INTEGER');
await _addColumnIfMissing(db, 'history', 'format', 'TEXT');
}
}
static String normalizeLookupText(String? value) {
@@ -507,6 +513,8 @@ class HistoryDatabase {
'quality': json['quality'],
'bit_depth': json['bitDepth'],
'sample_rate': json['sampleRate'],
'bitrate': json['bitrate'],
'format': json['format'],
'genre': json['genre'],
'composer': json['composer'],
'label': json['label'],
@@ -550,6 +558,8 @@ class HistoryDatabase {
'quality': row['quality'],
'bitDepth': row['bit_depth'],
'sampleRate': row['sample_rate'],
'bitrate': row['bitrate'],
'format': row['format'],
'genre': row['genre'],
'composer': row['composer'],
'label': row['label'],
+5 -3
View File
@@ -1029,8 +1029,8 @@ class LibraryDatabase {
NULL AS cover_path,
NULL AS scanned_at,
NULL AS file_mod_time,
NULL AS bitrate,
NULL AS format,
h.bitrate,
h.format,
LOWER(h.track_name) AS sort_track,
LOWER(h.artist_name) AS sort_artist,
LOWER(h.album_name) AS sort_album,
@@ -1299,7 +1299,7 @@ class LibraryDatabase {
args,
request,
filePathExpr: 'h.file_path',
formatExpr: null,
formatExpr: 'h.format',
qualityExpr: 'h.quality',
bitDepthExpr: 'h.bit_depth',
artistExpr: 'h.artist_name',
@@ -1544,6 +1544,8 @@ class LibraryDatabase {
'quality': row['quality'],
'bitDepth': row['bit_depth'],
'sampleRate': row['sample_rate'],
'bitrate': row['bitrate'],
'format': row['format'],
'genre': row['genre'],
'composer': row['composer'],
'label': row['label'],