feat: download version picker with smart series matching

close #767
This commit is contained in:
edde746
2026-03-31 04:46:09 +02:00
parent 8eb716505d
commit 1a96d2b418
41 changed files with 442 additions and 85 deletions
+9 -1
View File
@@ -17,7 +17,7 @@ class AppDatabase extends _$AppDatabase {
AppDatabase() : super(_openConnection());
@override
int get schemaVersion => 8; // Added bgTaskId column to DownloadedMedia
int get schemaVersion => 9; // Added mediaIndex column to DownloadedMedia
@override
MigrationStrategy get migration {
@@ -38,6 +38,14 @@ class AppDatabase extends _$AppDatabase {
appLogger.w('bgTaskId column may already exist: $e');
}
}
if (from < 9) {
appLogger.i('Adding mediaIndex column to DownloadedMedia (v9 migration)');
try {
await m.addColumn(downloadedMedia, downloadedMedia.mediaIndex);
} catch (e) {
appLogger.w('mediaIndex column may already exist: $e');
}
}
},
);
}
+72 -3
View File
@@ -198,6 +198,18 @@ class $DownloadedMediaTable extends DownloadedMedia
type: DriftSqlType.string,
requiredDuringInsert: false,
);
static const VerificationMeta _mediaIndexMeta = const VerificationMeta(
'mediaIndex',
);
@override
late final GeneratedColumn<int> mediaIndex = GeneratedColumn<int>(
'media_index',
aliasedName,
false,
type: DriftSqlType.int,
requiredDuringInsert: false,
defaultValue: const Constant(0),
);
@override
List<GeneratedColumn> get $columns => [
id,
@@ -217,6 +229,7 @@ class $DownloadedMediaTable extends DownloadedMedia
errorMessage,
retryCount,
bgTaskId,
mediaIndex,
];
@override
String get aliasedName => _alias ?? actualTableName;
@@ -357,6 +370,12 @@ class $DownloadedMediaTable extends DownloadedMedia
bgTaskId.isAcceptableOrUnknown(data['bg_task_id']!, _bgTaskIdMeta),
);
}
if (data.containsKey('media_index')) {
context.handle(
_mediaIndexMeta,
mediaIndex.isAcceptableOrUnknown(data['media_index']!, _mediaIndexMeta),
);
}
return context;
}
@@ -434,6 +453,10 @@ class $DownloadedMediaTable extends DownloadedMedia
DriftSqlType.string,
data['${effectivePrefix}bg_task_id'],
),
mediaIndex: attachedDatabase.typeMapping.read(
DriftSqlType.int,
data['${effectivePrefix}media_index'],
)!,
);
}
@@ -462,6 +485,7 @@ class DownloadedMediaItem extends DataClass
final String? errorMessage;
final int retryCount;
final String? bgTaskId;
final int mediaIndex;
const DownloadedMediaItem({
required this.id,
required this.serverId,
@@ -480,6 +504,7 @@ class DownloadedMediaItem extends DataClass
this.errorMessage,
required this.retryCount,
this.bgTaskId,
required this.mediaIndex,
});
@override
Map<String, Expression> toColumns(bool nullToAbsent) {
@@ -517,6 +542,7 @@ class DownloadedMediaItem extends DataClass
if (!nullToAbsent || bgTaskId != null) {
map['bg_task_id'] = Variable<String>(bgTaskId);
}
map['media_index'] = Variable<int>(mediaIndex);
return map;
}
@@ -555,6 +581,7 @@ class DownloadedMediaItem extends DataClass
bgTaskId: bgTaskId == null && nullToAbsent
? const Value.absent()
: Value(bgTaskId),
mediaIndex: Value(mediaIndex),
);
}
@@ -583,6 +610,7 @@ class DownloadedMediaItem extends DataClass
errorMessage: serializer.fromJson<String?>(json['errorMessage']),
retryCount: serializer.fromJson<int>(json['retryCount']),
bgTaskId: serializer.fromJson<String?>(json['bgTaskId']),
mediaIndex: serializer.fromJson<int>(json['mediaIndex']),
);
}
@override
@@ -606,6 +634,7 @@ class DownloadedMediaItem extends DataClass
'errorMessage': serializer.toJson<String?>(errorMessage),
'retryCount': serializer.toJson<int>(retryCount),
'bgTaskId': serializer.toJson<String?>(bgTaskId),
'mediaIndex': serializer.toJson<int>(mediaIndex),
};
}
@@ -627,6 +656,7 @@ class DownloadedMediaItem extends DataClass
Value<String?> errorMessage = const Value.absent(),
int? retryCount,
Value<String?> bgTaskId = const Value.absent(),
int? mediaIndex,
}) => DownloadedMediaItem(
id: id ?? this.id,
serverId: serverId ?? this.serverId,
@@ -651,6 +681,7 @@ class DownloadedMediaItem extends DataClass
errorMessage: errorMessage.present ? errorMessage.value : this.errorMessage,
retryCount: retryCount ?? this.retryCount,
bgTaskId: bgTaskId.present ? bgTaskId.value : this.bgTaskId,
mediaIndex: mediaIndex ?? this.mediaIndex,
);
DownloadedMediaItem copyWithCompanion(DownloadedMediaCompanion data) {
return DownloadedMediaItem(
@@ -687,6 +718,9 @@ class DownloadedMediaItem extends DataClass
? data.retryCount.value
: this.retryCount,
bgTaskId: data.bgTaskId.present ? data.bgTaskId.value : this.bgTaskId,
mediaIndex: data.mediaIndex.present
? data.mediaIndex.value
: this.mediaIndex,
);
}
@@ -709,7 +743,8 @@ class DownloadedMediaItem extends DataClass
..write('downloadedAt: $downloadedAt, ')
..write('errorMessage: $errorMessage, ')
..write('retryCount: $retryCount, ')
..write('bgTaskId: $bgTaskId')
..write('bgTaskId: $bgTaskId, ')
..write('mediaIndex: $mediaIndex')
..write(')'))
.toString();
}
@@ -733,6 +768,7 @@ class DownloadedMediaItem extends DataClass
errorMessage,
retryCount,
bgTaskId,
mediaIndex,
);
@override
bool operator ==(Object other) =>
@@ -754,7 +790,8 @@ class DownloadedMediaItem extends DataClass
other.downloadedAt == this.downloadedAt &&
other.errorMessage == this.errorMessage &&
other.retryCount == this.retryCount &&
other.bgTaskId == this.bgTaskId);
other.bgTaskId == this.bgTaskId &&
other.mediaIndex == this.mediaIndex);
}
class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
@@ -775,6 +812,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
final Value<String?> errorMessage;
final Value<int> retryCount;
final Value<String?> bgTaskId;
final Value<int> mediaIndex;
const DownloadedMediaCompanion({
this.id = const Value.absent(),
this.serverId = const Value.absent(),
@@ -793,6 +831,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
this.errorMessage = const Value.absent(),
this.retryCount = const Value.absent(),
this.bgTaskId = const Value.absent(),
this.mediaIndex = const Value.absent(),
});
DownloadedMediaCompanion.insert({
this.id = const Value.absent(),
@@ -812,6 +851,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
this.errorMessage = const Value.absent(),
this.retryCount = const Value.absent(),
this.bgTaskId = const Value.absent(),
this.mediaIndex = const Value.absent(),
}) : serverId = Value(serverId),
ratingKey = Value(ratingKey),
globalKey = Value(globalKey),
@@ -835,6 +875,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
Expression<String>? errorMessage,
Expression<int>? retryCount,
Expression<String>? bgTaskId,
Expression<int>? mediaIndex,
}) {
return RawValuesInsertable({
if (id != null) 'id': id,
@@ -855,6 +896,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
if (errorMessage != null) 'error_message': errorMessage,
if (retryCount != null) 'retry_count': retryCount,
if (bgTaskId != null) 'bg_task_id': bgTaskId,
if (mediaIndex != null) 'media_index': mediaIndex,
});
}
@@ -876,6 +918,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
Value<String?>? errorMessage,
Value<int>? retryCount,
Value<String?>? bgTaskId,
Value<int>? mediaIndex,
}) {
return DownloadedMediaCompanion(
id: id ?? this.id,
@@ -895,6 +938,7 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
errorMessage: errorMessage ?? this.errorMessage,
retryCount: retryCount ?? this.retryCount,
bgTaskId: bgTaskId ?? this.bgTaskId,
mediaIndex: mediaIndex ?? this.mediaIndex,
);
}
@@ -954,6 +998,9 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
if (bgTaskId.present) {
map['bg_task_id'] = Variable<String>(bgTaskId.value);
}
if (mediaIndex.present) {
map['media_index'] = Variable<int>(mediaIndex.value);
}
return map;
}
@@ -976,7 +1023,8 @@ class DownloadedMediaCompanion extends UpdateCompanion<DownloadedMediaItem> {
..write('downloadedAt: $downloadedAt, ')
..write('errorMessage: $errorMessage, ')
..write('retryCount: $retryCount, ')
..write('bgTaskId: $bgTaskId')
..write('bgTaskId: $bgTaskId, ')
..write('mediaIndex: $mediaIndex')
..write(')'))
.toString();
}
@@ -2504,6 +2552,7 @@ typedef $$DownloadedMediaTableCreateCompanionBuilder =
Value<String?> errorMessage,
Value<int> retryCount,
Value<String?> bgTaskId,
Value<int> mediaIndex,
});
typedef $$DownloadedMediaTableUpdateCompanionBuilder =
DownloadedMediaCompanion Function({
@@ -2524,6 +2573,7 @@ typedef $$DownloadedMediaTableUpdateCompanionBuilder =
Value<String?> errorMessage,
Value<int> retryCount,
Value<String?> bgTaskId,
Value<int> mediaIndex,
});
class $$DownloadedMediaTableFilterComposer
@@ -2619,6 +2669,11 @@ class $$DownloadedMediaTableFilterComposer
column: $table.bgTaskId,
builder: (column) => ColumnFilters(column),
);
ColumnFilters<int> get mediaIndex => $composableBuilder(
column: $table.mediaIndex,
builder: (column) => ColumnFilters(column),
);
}
class $$DownloadedMediaTableOrderingComposer
@@ -2714,6 +2769,11 @@ class $$DownloadedMediaTableOrderingComposer
column: $table.bgTaskId,
builder: (column) => ColumnOrderings(column),
);
ColumnOrderings<int> get mediaIndex => $composableBuilder(
column: $table.mediaIndex,
builder: (column) => ColumnOrderings(column),
);
}
class $$DownloadedMediaTableAnnotationComposer
@@ -2791,6 +2851,11 @@ class $$DownloadedMediaTableAnnotationComposer
GeneratedColumn<String> get bgTaskId =>
$composableBuilder(column: $table.bgTaskId, builder: (column) => column);
GeneratedColumn<int> get mediaIndex => $composableBuilder(
column: $table.mediaIndex,
builder: (column) => column,
);
}
class $$DownloadedMediaTableTableManager
@@ -2847,6 +2912,7 @@ class $$DownloadedMediaTableTableManager
Value<String?> errorMessage = const Value.absent(),
Value<int> retryCount = const Value.absent(),
Value<String?> bgTaskId = const Value.absent(),
Value<int> mediaIndex = const Value.absent(),
}) => DownloadedMediaCompanion(
id: id,
serverId: serverId,
@@ -2865,6 +2931,7 @@ class $$DownloadedMediaTableTableManager
errorMessage: errorMessage,
retryCount: retryCount,
bgTaskId: bgTaskId,
mediaIndex: mediaIndex,
),
createCompanionCallback:
({
@@ -2885,6 +2952,7 @@ class $$DownloadedMediaTableTableManager
Value<String?> errorMessage = const Value.absent(),
Value<int> retryCount = const Value.absent(),
Value<String?> bgTaskId = const Value.absent(),
Value<int> mediaIndex = const Value.absent(),
}) => DownloadedMediaCompanion.insert(
id: id,
serverId: serverId,
@@ -2903,6 +2971,7 @@ class $$DownloadedMediaTableTableManager
errorMessage: errorMessage,
retryCount: retryCount,
bgTaskId: bgTaskId,
mediaIndex: mediaIndex,
),
withReferenceMapper: (p0) => p0
.map((e) => (e.readTable(table), BaseReferences(db, table, e)))
+2
View File
@@ -14,6 +14,7 @@ extension DownloadDatabaseOperations on AppDatabase {
String? parentRatingKey,
String? grandparentRatingKey,
required int status,
int mediaIndex = 0,
}) async {
await into(downloadedMedia).insert(
DownloadedMediaCompanion.insert(
@@ -24,6 +25,7 @@ extension DownloadDatabaseOperations on AppDatabase {
parentRatingKey: Value(parentRatingKey),
grandparentRatingKey: Value(grandparentRatingKey),
status: status,
mediaIndex: Value(mediaIndex),
),
mode: InsertMode.insertOrReplace,
);
+1
View File
@@ -48,6 +48,7 @@ class DownloadedMedia extends Table {
TextColumn get errorMessage => text().nullable()();
IntColumn get retryCount => integer().withDefault(const Constant(0))();
TextColumn get bgTaskId => text().nullable()();
IntColumn get mediaIndex => integer().withDefault(const Constant(0))();
}
/// Queue for offline watch progress and manual watch actions.