From a32c0cf0f072916f702f075074557ba6c2f1e1fb Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 10 Mar 2025 23:08:23 +0100 Subject: [PATCH 1/4] #1471 DB sanitizing to mitigate v1.12.4 upgrade issue --- lib/model/db/db_sqflite.dart | 2 +- lib/model/db/db_sqflite_upgrade.dart | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/model/db/db_sqflite.dart b/lib/model/db/db_sqflite.dart index 409045db1..66bc79d6c 100644 --- a/lib/model/db/db_sqflite.dart +++ b/lib/model/db/db_sqflite.dart @@ -117,7 +117,7 @@ class SqfliteLocalMediaDb implements LocalMediaDb { ')'); }, onUpgrade: LocalMediaDbUpgrader.upgradeDb, - version: 14, + version: 15, ); final maxIdRows = await _db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable'); diff --git a/lib/model/db/db_sqflite_upgrade.dart b/lib/model/db/db_sqflite_upgrade.dart index 173d5bed9..3d8923489 100644 --- a/lib/model/db/db_sqflite_upgrade.dart +++ b/lib/model/db/db_sqflite_upgrade.dart @@ -50,6 +50,8 @@ class LocalMediaDbUpgrader { await _upgradeFrom12(db); case 13: await _upgradeFrom13(db); + case 14: + await _upgradeFrom14(db); } oldVersion++; } @@ -479,4 +481,23 @@ class LocalMediaDbUpgrader { await db.execute('ALTER TABLE $newEntryTable RENAME TO $entryTable;'); }); } + + static Future _upgradeFrom14(Database db) async { + debugPrint('upgrading DB from v14'); + + // no schema changes, but v1.12.4 may have corrupted the DB, so we sanitize it + + // clear rebuildable tables + await db.delete(dateTakenTable, where: '1'); + await db.delete(metadataTable, where: '1'); + await db.delete(addressTable, where: '1'); + await db.delete(trashTable, where: '1'); + await db.delete(videoPlaybackTable, where: '1'); + + // remove rows referencing future entry IDs + final maxIdRows = await db.rawQuery('SELECT MAX(id) AS maxId FROM $entryTable'); + final lastId = (maxIdRows.firstOrNull?['maxId'] as int?) ?? 0; + await db.delete(favouriteTable, where: 'id > ?', whereArgs: [lastId]); + await db.delete(coverTable, where: 'entryId > ?', whereArgs: [lastId]); + } } From f646639055013b9eb58219dccacfee47b99c3919 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 10 Mar 2025 23:09:32 +0100 Subject: [PATCH 2/4] #1471 allow rescan of trashed items --- lib/widgets/collection/entry_set_action_delegate.dart | 2 +- lib/widgets/viewer/action/entry_action_delegate.dart | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/widgets/collection/entry_set_action_delegate.dart b/lib/widgets/collection/entry_set_action_delegate.dart index 884b5fe0d..cd359dc26 100644 --- a/lib/widgets/collection/entry_set_action_delegate.dart +++ b/lib/widgets/collection/entry_set_action_delegate.dart @@ -97,7 +97,7 @@ class EntrySetActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAware case EntrySetAction.stats: return isMain; case EntrySetAction.rescan: - return isMain && isSelecting && !isTrash && !useTvLayout; + return isMain && isSelecting && !useTvLayout; // selecting case EntrySetAction.share: case EntrySetAction.toggleFavourite: diff --git a/lib/widgets/viewer/action/entry_action_delegate.dart b/lib/widgets/viewer/action/entry_action_delegate.dart index 9d169ead7..a29b52863 100644 --- a/lib/widgets/viewer/action/entry_action_delegate.dart +++ b/lib/widgets/viewer/action/entry_action_delegate.dart @@ -61,7 +61,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix case EntryAction.restore: return true; case EntryAction.debug: - return kDebugMode; + return !kReleaseMode; default: return false; } @@ -138,7 +138,7 @@ class EntryActionDelegate with FeedbackMixin, PermissionAwareMixin, SizeAwareMix action: action, ); case EntryAction.debug: - return kDebugMode; + return !kReleaseMode; } } } From dcd42b7048a177ef09503dd90f1bfd670da54cb1 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 11 Mar 2025 00:24:03 +0100 Subject: [PATCH 3/4] #1471 check file length after metadata editing via PixyMeta --- .../thibault/aves/metadata/PixyMetaHelper.kt | 1 + .../aves/model/provider/ImageProvider.kt | 26 +++++++++++++++---- .../info/metadata/metadata_section.dart | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt index 04e5365ef..e1d11786e 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/PixyMetaHelper.kt @@ -92,6 +92,7 @@ object PixyMetaHelper { fun getXmp(input: InputStream): XMP? = Metadata.readMetadata(input)[MetadataType.XMP] as XMP? + // PixyMeta may fail with just a log, and write nothing to the output fun setXmp( input: InputStream, output: OutputStream, diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt index 39fbf091d..9d36f1812 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/provider/ImageProvider.kt @@ -680,18 +680,19 @@ abstract class ImageProvider { try { edit(ExifInterface(editableFile)) + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing Exif yielded an empty file")) + return false + } + val editedMimeType = detectMimeType(context, Uri.fromFile(editableFile), mimeType) if (editedMimeType != mimeType) { throw Exception("editing Exif changes mimeType=$mimeType -> $editedMimeType for uri=$uri path=$path") } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - // 1) as of androidx.exifinterface:exifinterface:1.3.6, editing some specific WEBP - // makes them undecodable by some decoders (including Android's and Chrome's) - // even though `BitmapFactory` successfully decodes their bounds, + // editing may corrupt the file for various reasons, // so we check whether decoding it throws an exception - // 2) some users have reported corruption when editing JPEG as well, - // but conditions are unknown (specific image, custom ROM, low storage, race condition, etc.) ImageDecoder.decodeBitmap(ImageDecoder.createSource(editableFile)) } @@ -781,6 +782,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing IPTC yielded an empty file")) + return false + } + if (trailerVideoBytes != null) { // append trailer video, if any editableFile.appendBytes(trailerVideoBytes!!) @@ -917,6 +923,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("editing XMP yielded an empty file")) + return false + } + try { // copy the edited temporary file back to the original editableFile.transferTo(outputStream(context, mimeType, uri, path)) @@ -1330,6 +1341,11 @@ abstract class ImageProvider { } } + if (editableFile.length() == 0L) { + callback.onFailure(Exception("removing metadata yielded an empty file")) + return + } + try { // copy the edited temporary file back to the original editableFile.transferTo(outputStream(context, mimeType, uri, path)) diff --git a/lib/widgets/viewer/info/metadata/metadata_section.dart b/lib/widgets/viewer/info/metadata/metadata_section.dart index bd0d34c34..00f24d51f 100644 --- a/lib/widgets/viewer/info/metadata/metadata_section.dart +++ b/lib/widgets/viewer/info/metadata/metadata_section.dart @@ -144,8 +144,8 @@ class _MetadataSectionSliverState extends State { } Future _getMetadata() async { - if (!mounted) return; final titledDirectories = await entry.getMetadataDirectories(context); + if (!mounted) return; metadataNotifier.value = Map.fromEntries(titledDirectories); _expandedDirectoryNotifier.value = null; } From 403ccac5c2b02a0037ec04fc09fdf27e0398fb1f Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 11 Mar 2025 00:30:57 +0100 Subject: [PATCH 4/4] version bump --- CHANGELOG.md | 7 +++++++ fastlane/metadata/android/en-US/changelogs/146.txt | 4 ++++ fastlane/metadata/android/en-US/changelogs/14601.txt | 4 ++++ pubspec.yaml | 2 +- whatsnew/whatsnew-en-US | 2 +- 5 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/146.txt create mode 100644 fastlane/metadata/android/en-US/changelogs/14601.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index bb9e51b43..7caed7dff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +## [v1.12.6] - 2025-03-11 + +### Fixed + +- data loss when editing metadata of items with incorrect mime types +- metadata inconsistency in the DB due to v1.12.4 upgrade + ## [v1.12.5] - 2025-03-07 ### Added diff --git a/fastlane/metadata/android/en-US/changelogs/146.txt b/fastlane/metadata/android/en-US/changelogs/146.txt new file mode 100644 index 000000000..c6133101c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/146.txt @@ -0,0 +1,4 @@ +In v1.12.6: +- play more kinds of motion photos +- enjoy the app in Galician +Full changelog available on GitHub \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/14601.txt b/fastlane/metadata/android/en-US/changelogs/14601.txt new file mode 100644 index 000000000..c6133101c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/14601.txt @@ -0,0 +1,4 @@ +In v1.12.6: +- play more kinds of motion photos +- enjoy the app in Galician +Full changelog available on GitHub \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 09310d938..31c35cdbf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -7,7 +7,7 @@ repository: https://github.com/deckerst/aves # - play changelog: /whatsnew/whatsnew-en-US # - izzy changelog: /fastlane/metadata/android/en-US/changelogs/XXX01.txt # - libre changelog: /fastlane/metadata/android/en-US/changelogs/XXX.txt -version: 1.12.5+145 +version: 1.12.6+146 publish_to: none environment: diff --git a/whatsnew/whatsnew-en-US b/whatsnew/whatsnew-en-US index 139cfbdfd..c6133101c 100644 --- a/whatsnew/whatsnew-en-US +++ b/whatsnew/whatsnew-en-US @@ -1,4 +1,4 @@ -In v1.12.5: +In v1.12.6: - play more kinds of motion photos - enjoy the app in Galician Full changelog available on GitHub \ No newline at end of file