nc-photos/lib/entity/album/upgrader.dart

196 lines
5.6 KiB
Dart
Raw Normal View History

2021-06-24 16:54:41 +02:00
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/entity/exif.dart';
import 'package:nc_photos/iterable_extension.dart';
2021-08-06 19:11:00 +02:00
import 'package:nc_photos/type.dart';
import 'package:tuple/tuple.dart';
2021-06-24 16:54:41 +02:00
abstract class AlbumUpgrader {
2021-08-06 19:11:00 +02:00
JsonObj? call(JsonObj json);
2021-06-24 16:54:41 +02:00
}
/// Upgrade v1 Album to v2
class AlbumUpgraderV1 implements AlbumUpgrader {
AlbumUpgraderV1({
this.logFilePath,
});
2021-07-23 22:05:57 +02:00
@override
2021-08-06 19:11:00 +02:00
call(JsonObj json) {
2021-06-24 16:54:41 +02:00
// v1 album items are corrupted in one of the updates, drop it
_log.fine("[call] Upgrade v1 Album for file: $logFilePath");
2021-08-06 19:11:00 +02:00
final result = JsonObj.from(json);
2021-06-24 16:54:41 +02:00
result["items"] = [];
return result;
}
/// File path for logging only
2021-07-23 22:05:57 +02:00
final String? logFilePath;
2021-06-24 16:54:41 +02:00
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV1");
}
2021-06-24 18:26:56 +02:00
/// Upgrade v2 Album to v3
class AlbumUpgraderV2 implements AlbumUpgrader {
AlbumUpgraderV2({
this.logFilePath,
});
2021-07-23 22:05:57 +02:00
@override
2021-08-06 19:11:00 +02:00
call(JsonObj json) {
2021-06-24 18:26:56 +02:00
// move v2 items to v3 provider
_log.fine("[call] Upgrade v2 Album for file: $logFilePath");
2021-08-06 19:11:00 +02:00
final result = JsonObj.from(json);
2021-06-24 18:26:56 +02:00
result["provider"] = <String, dynamic>{
"type": "static",
"content": <String, dynamic>{
"items": result["items"],
}
};
result.remove("items");
2021-06-26 13:51:13 +02:00
// add the auto cover provider
result["coverProvider"] = <String, dynamic>{
"type": "auto",
"content": {},
};
2021-06-24 18:26:56 +02:00
return result;
}
/// File path for logging only
2021-07-23 22:05:57 +02:00
final String? logFilePath;
2021-06-24 18:26:56 +02:00
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV2");
}
2021-07-07 20:40:43 +02:00
/// Upgrade v3 Album to v4
class AlbumUpgraderV3 implements AlbumUpgrader {
AlbumUpgraderV3({
this.logFilePath,
});
2021-07-23 22:05:57 +02:00
@override
2021-08-06 19:11:00 +02:00
call(JsonObj json) {
2021-07-07 20:40:43 +02:00
// move v3 items to v4 provider
_log.fine("[call] Upgrade v3 Album for file: $logFilePath");
2021-08-06 19:11:00 +02:00
final result = JsonObj.from(json);
2021-07-07 20:40:43 +02:00
// add the descending time sort provider
result["sortProvider"] = <String, dynamic>{
"type": "time",
"content": {
"isAscending": false,
},
};
return result;
}
/// File path for logging only
2021-07-23 22:05:57 +02:00
final String? logFilePath;
2021-07-07 20:40:43 +02:00
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV3");
}
/// Upgrade v4 Album to v5
class AlbumUpgraderV4 implements AlbumUpgrader {
AlbumUpgraderV4({
this.logFilePath,
});
@override
call(JsonObj json) {
_log.fine("[call] Upgrade v4 Album for file: $logFilePath");
final result = JsonObj.from(json);
try {
if (result["provider"]["type"] != "static") {
return result;
}
final latestItem = (result["provider"]["content"]["items"] as List)
.map((e) => e.cast<String, dynamic>())
.where((e) => e["type"] == "file")
.map((e) => e["content"]["file"] as JsonObj)
.map((e) {
final overrideDateTime = e["overrideDateTime"] == null
? null
: DateTime.parse(e["overrideDateTime"]);
final String? dateTimeOriginalStr =
e["metadata"]?["exif"]?["DateTimeOriginal"];
final dateTimeOriginal =
dateTimeOriginalStr == null || dateTimeOriginalStr.isEmpty
? null
: Exif.dateTimeFormat.parse(dateTimeOriginalStr).toUtc();
final lastModified = e["lastModified"] == null
? null
: DateTime.parse(e["lastModified"]);
final latestItemTime =
overrideDateTime ?? dateTimeOriginal ?? lastModified;
// remove metadata
e.remove("metadata");
if (latestItemTime != null) {
return Tuple2(latestItemTime, e);
} else {
return null;
}
})
.whereType<Tuple2<DateTime, JsonObj>>()
.sorted((a, b) => a.item1.compareTo(b.item1))
.lastOrNull;
if (latestItem != null) {
// save the latest item time
result["provider"]["content"]["latestItemTime"] =
latestItem.item1.toIso8601String();
if (result["coverProvider"]["type"] == "auto") {
// save the cover
result["coverProvider"]["content"]["coverFile"] =
Map.of(latestItem.item2);
}
}
} catch (e, stackTrace) {
// this upgrade is not a must, if it failed then just leave it and it'll
// be upgraded the next time the album is saved
_log.shout("[call] Failed while upgrade", e, stackTrace);
}
return result;
}
/// File path for logging only
final String? logFilePath;
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV4");
}
/// Upgrade v5 Album to v6
class AlbumUpgraderV5 implements AlbumUpgrader {
const AlbumUpgraderV5(
this.account, {
this.logFilePath,
});
@override
call(JsonObj json) {
_log.fine("[call] Upgrade v5 Album for file: $logFilePath");
final result = JsonObj.from(json);
try {
if (result["provider"]["type"] != "static") {
return result;
}
for (final item in (result["provider"]["content"]["items"] as List)) {
item["addedBy"] = result["albumFile"]["ownerId"] ?? account.username;
item["addedAt"] = result["lastUpdated"];
}
} catch (e, stackTrace) {
// this upgrade is not a must, if it failed then just leave it and it'll
// be upgraded the next time the album is saved
_log.shout("[call] Failed while upgrade", e, stackTrace);
}
return result;
}
final Account account;
/// File path for logging only
final String? logFilePath;
static final _log = Logger("entity.album.upgrader.AlbumUpgraderV5");
}