diff --git a/README.md b/README.md index eb19b8c8..d0b45496 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,10 @@ run con ``` fvm flutter run -t lib/main_play.dart --flavor play ``` - +se vuoi salvare tutto l'output in un file e cmq vederlo +``` +fvm flutter run -t lib/main_play.dart --flavor play 2>&1 | tee output.log +``` i files nuovi sono ``` @@ -38,8 +41,97 @@ e questo modificato ``` lib/widgets/home/home_page.dart ``` +salvare il DB +``` +adb exec-out run-as deckers.thibault.aves.debug cat /data/data/deckers.thibault.aves.debug/databases/metadata.db > metadata.db +``` +verifica che il db sia quello giusto +ci devono essere entry address metadata album +``` +sqlite3 metadata.db ".tables" +address dateTaken favourites vaults +android_metadata dynamicAlbums metadata videoPlayback +covers entry trash +``` + +verifica delke colonne, i campi +``` +sqlite3 metadata.db "PRAGMA table_info(entry);" +``` +risposta +``` +0|id|INTEGER|0||1 +1|contentId|INTEGER|0||0 +2|uri|TEXT|0||0 +3|path|TEXT|0||0 +4|sourceMimeType|TEXT|0||0 +5|width|INTEGER|0||0 +6|height|INTEGER|0||0 +7|sourceRotationDegrees|INTEGER|0||0 +8|sizeBytes|INTEGER|0||0 +9|title|TEXT|0||0 +10|dateAddedSecs|INTEGER|0|strftime('%s','now')|0 +11|dateModifiedMillis|INTEGER|0||0 +12|sourceDateTakenMillis|INTEGER|0||0 +13|durationMillis|INTEGER|0||0 +14|trashed|INTEGER|0|0|0 +15|origin|INTEGER|0|0|0 +16|provider|TEXT|0||0 +17|remoteId|TEXT|0||0 +18|remotePath|TEXT|0||0 +19|remoteThumb1|TEXT|0||0 +20|remoteThumb2|TEXT|0||0 +21|latitude|REAL|0||0 +22|longitude|REAL|0||0 +23|altitude|REAL|0||0 +``` +Verifica 1 — Quante foto remote sono state salvate +``` +sqlite3 metadata.db "SELECT COUNT(*) FROM entry WHERE origin=1;" +99 +``` + +Verifica 2 — Controllare che le foto remote abbiano GPS e path corretti +``` +sqlite3 metadata.db " +SELECT id, title, remoteId, remotePath, latitude, longitude, altitude +FROM entry +WHERE origin=1 +LIMIT 20; +" +``` +risposta +``` +6974|IMG_0123.JPG|d9fb0263ed0bc9945d2d6fde3822377d63ed7a62df20e2a1339d77a058b0e5a0|photos/Fabio/original/2017Irlanda19-29ago/IMG_0123.JPG|53.3419416666667|-6.28671666666667|23.6626344086022 +6975|IMG_0124.JPG|a48db6ef8efee410190ff59bcb223fece468837d0c39bb408cce911213e5e36c|photos/Fabio/original/2017Irlanda19-29ago/IMG_0124.JPG|53.341975|-6.28675277777778|23.8189509306261 +``` +cartelle possibili +``` +sqlite3 metadata.db "SELECT remotePath FROM entry WHERE origin=1;" \ + | awk -F'/' '{$NF=""; sub(/\/$/,""); print}' \ + | sort -u +``` +risposta +``` +photos Fabio original 2017Irlanda19-29ago +``` +controlla se ci sono tabelke album +``` +sqlite3 metadata.db " +SELECT name FROM sqlite_master +WHERE type='table' AND name LIKE '%album%'; +" +``` +risposta +``` +dynamicAlbums +``` +controlla negli albums +``` +sqlite3 metadata.db "SELECT * FROM dynamicAlbums LIMIT 20;" +``` ## Features Aves can handle all sorts of images and videos, including your typical JPEGs and MP4s, but also more exotic things like **multi-page TIFFs, SVGs, old AVIs and more**! diff --git a/lib/remote/remote_repository.dart b/lib/remote/remote_repository.dart index 25f1c84a..aa008baf 100644 --- a/lib/remote/remote_repository.dart +++ b/lib/remote/remote_repository.dart @@ -1,4 +1,4 @@ -// lib/remote/remote_repository.dart +import 'package:flutter/foundation.dart' show debugPrint; import 'package:sqflite/sqflite.dart'; import 'remote_models.dart'; @@ -6,69 +6,143 @@ class RemoteRepository { final Database db; RemoteRepository(this.db); - Future upsertAll(List items) async { - await db.transaction((txn) async { - for (final it in items) { - // cerca se esiste già una entry per quel remoteId - final existing = await txn.query( - 'entry', - columns: ['id'], - where: 'remoteId = ?', - whereArgs: [it.id], - limit: 1, - ); - - final int? existingId = existing.isNotEmpty ? (existing.first['id'] as int?) : null; - - final row = { - 'id': existingId, // se esiste sostituiamo, altrimenti INSERT nuovo - 'contentId': null, - 'uri': null, - 'path': null, - 'sourceMimeType': it.mimeType, - 'width': it.width, - 'height': it.height, - 'sourceRotationDegrees': null, - 'sizeBytes': it.sizeBytes, - 'title': it.name, - 'dateAddedSecs': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'dateModifiedMillis': null, - 'sourceDateTakenMillis': it.takenAtUtc?.millisecondsSinceEpoch, - 'durationMillis': it.durationMillis, // <-- ora valorizzato anche per i video - 'trashed': 0, - 'origin': 1, - 'provider': 'json@patachina', - 'remoteId': it.id, - 'remotePath': it.path, - 'remoteThumb1': it.thub1, - 'remoteThumb2': it.thub2, - }; - - // INSERT OR REPLACE (se 'id' è valorizzato, sostituisce; se null, crea nuovo) - final newId = await txn.insert( - 'entry', - row, - conflictAlgorithm: ConflictAlgorithm.replace, - ); - - // opzionale: salva indirizzo (se il backend lo fornisce) - if (it.location != null) { - final addr = { - 'id': newId, - 'addressLine': it.location!.address, - 'countryCode': null, // county_code != country code - 'countryName': it.location!.country, - 'adminArea': it.location!.region, - 'locality': it.location!.city, - }; - await txn.insert( - 'address', - addr, - conflictAlgorithm: ConflictAlgorithm.replace, - ); + /// Assicura che le colonne GPS esistano nella tabella `entry`. + /// Se mancano, prova ad aggiungerle con ALTER TABLE. + Future _ensureGpsColumns(DatabaseExecutor dbExec) async { + try { + final rows = await dbExec.rawQuery('PRAGMA table_info(entry);'); + final names = rows.map((r) => r['name'] as String).toSet(); + final stmts = []; + if (!names.contains('latitude')) stmts.add('ALTER TABLE entry ADD COLUMN latitude REAL;'); + if (!names.contains('longitude')) stmts.add('ALTER TABLE entry ADD COLUMN longitude REAL;'); + if (!names.contains('altitude')) stmts.add('ALTER TABLE entry ADD COLUMN altitude REAL;'); + for (final s in stmts) { + try { + await dbExec.execute(s); + debugPrint('[RemoteRepository] executed: $s'); + } catch (e, st) { + debugPrint('[RemoteRepository] failed to execute $s: $e\n$st'); } } - }); + } catch (e, st) { + debugPrint('[RemoteRepository] _ensureGpsColumns error: $e\n$st'); + } + } + + /// Inserisce o aggiorna tutti gli elementi remoti. + /// Difensivo: assicura colonne GPS, logga, e in caso di errore riprova senza i campi GPS. + Future upsertAll(List items) async { + debugPrint('RemoteRepository.upsertAll: items=${items.length}'); + try { + await db.transaction((txn) async { + // Assicuriamoci che le colonne GPS esistano prima di inserire + await _ensureGpsColumns(txn); + + for (final it in items) { + debugPrint('RemoteRepository: processing remoteId=${it.id} lat=${it.lat} lng=${it.lng}'); + + final existing = await txn.query( + 'entry', + columns: ['id'], + where: 'remoteId = ?', + whereArgs: [it.id], + limit: 1, + ); + + final int? existingId = existing.isNotEmpty ? (existing.first['id'] as int?) : null; + + final row = { + 'id': existingId, + 'contentId': null, + 'uri': null, + 'path': it.path, + 'sourceMimeType': it.mimeType, + 'width': it.width, + 'height': it.height, + 'sourceRotationDegrees': null, + 'sizeBytes': it.sizeBytes, + 'title': it.name, + 'dateAddedSecs': DateTime.now().millisecondsSinceEpoch ~/ 1000, + 'dateModifiedMillis': null, + 'sourceDateTakenMillis': it.takenAtUtc?.millisecondsSinceEpoch, + 'durationMillis': it.durationMillis, + 'trashed': 0, + 'origin': 1, + 'provider': 'json@patachina', + // campi GPS (possono essere null) + 'latitude': it.lat, + 'longitude': it.lng, + 'altitude': it.alt, + // campi remoti + 'remoteId': it.id, + 'remotePath': it.path, + 'remoteThumb1': it.thub1, + 'remoteThumb2': it.thub2, + }; + + try { + final newId = await txn.insert( + 'entry', + row, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + + if (it.location != null) { + final addr = { + 'id': newId, + 'addressLine': it.location!.address, + 'countryCode': null, + 'countryName': it.location!.country, + 'adminArea': it.location!.region, + 'locality': it.location!.city, + }; + await txn.insert( + 'address', + addr, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + } on DatabaseException catch (e, st) { + debugPrint('[RemoteRepository] insert failed for remoteId=${it.id}: $e\n$st'); + // Fallback: riprova senza i campi GPS (utile se ALTER TABLE non è riuscito) + final rowNoGps = Map.from(row) + ..remove('latitude') + ..remove('longitude') + ..remove('altitude'); + try { + final newId = await txn.insert( + 'entry', + rowNoGps, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + + if (it.location != null) { + final addr = { + 'id': newId, + 'addressLine': it.location!.address, + 'countryCode': null, + 'countryName': it.location!.country, + 'adminArea': it.location!.region, + 'locality': it.location!.city, + }; + await txn.insert( + 'address', + addr, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + debugPrint('[RemoteRepository] insert succeeded without GPS for remoteId=${it.id}'); + } catch (e2, st2) { + debugPrint('[RemoteRepository] retry without GPS failed for remoteId=${it.id}: $e2\n$st2'); + rethrow; + } + } + } + }); + } catch (e, st) { + debugPrint('[RemoteRepository] upsertAll ERROR: $e\n$st'); + rethrow; + } } Future countRemote() async { diff --git a/lib/remote/remote_repository.dart.old b/lib/remote/remote_repository.dart.old new file mode 100644 index 00000000..47c3928d --- /dev/null +++ b/lib/remote/remote_repository.dart.old @@ -0,0 +1,89 @@ +import 'package:sqflite/sqflite.dart'; +import 'remote_models.dart'; + +class RemoteRepository { + final Database db; + RemoteRepository(this.db); + + Future upsertAll(List items) async { + await db.transaction((txn) async { + for (final it in items) { + // cerca se esiste già una entry per quel remoteId + final existing = await txn.query( + 'entry', + columns: ['id'], + where: 'remoteId = ?', + whereArgs: [it.id], + limit: 1, + ); + + final int? existingId = + existing.isNotEmpty ? (existing.first['id'] as int?) : null; + + final row = { + // se esiste sostituiamo, altrimenti INSERT nuovo + 'id': existingId, + 'contentId': null, + 'uri': null, + 'path': null, + 'sourceMimeType': it.mimeType, + 'width': it.width, + 'height': it.height, + 'sourceRotationDegrees': null, + 'sizeBytes': it.sizeBytes, + 'title': it.name, + 'dateAddedSecs': + DateTime.now().millisecondsSinceEpoch ~/ 1000, + 'dateModifiedMillis': null, + 'sourceDateTakenMillis': + it.takenAtUtc?.millisecondsSinceEpoch, + 'durationMillis': it.durationMillis, + 'trashed': 0, + 'origin': 1, + 'provider': 'json@patachina', + + // ⭐ AGGIUNTA: GPS direttamente nel DB di Aves + 'latitude': it.lat, + 'longitude': it.lng, + 'altitude': it.alt, + + 'remoteId': it.id, + 'remotePath': it.path, + 'remoteThumb1': it.thub1, + 'remoteThumb2': it.thub2, + }; + + // INSERT OR REPLACE (se 'id' è valorizzato, sostituisce; se null, crea nuovo) + final newId = await txn.insert( + 'entry', + row, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + + // opzionale: salva indirizzo (se il backend lo fornisce) + if (it.location != null) { + final addr = { + 'id': newId, + 'addressLine': it.location!.address, + 'countryCode': null, // county_code != country code + 'countryName': it.location!.country, + 'adminArea': it.location!.region, + 'locality': it.location!.city, + }; + + await txn.insert( + 'address', + addr, + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + } + }); + } + + Future countRemote() async { + final rows = await db + .rawQuery('SELECT COUNT(1) AS c FROM entry WHERE origin=1'); + return (rows.first['c'] as int?) ?? 0; + } +} diff --git a/metadata.db b/metadata.db new file mode 100644 index 00000000..50655518 Binary files /dev/null and b/metadata.db differ diff --git a/remote_paths.txt b/remote_paths.txt new file mode 100644 index 00000000..e24159e6 --- /dev/null +++ b/remote_paths.txt @@ -0,0 +1,99 @@ +photos/Fabio/original/2017Irlanda19-29ago/IMG_0092.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0099.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0100.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0102.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0103.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0104.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0106.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0107.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0108.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0109.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0110.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0112.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0113.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0114.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0116.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0119.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0120.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0122.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0123.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0124.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0125.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0126.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0133.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0134.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0135.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0136.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0137.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0138.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0139.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0140.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0141.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0143.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0145.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0146.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0147.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0148.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0149.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0150.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0152.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0153.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0154.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0155.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0156.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0157.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0160.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0162.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0163.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0164.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0165.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0166.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0167.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0170.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0171.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0172.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0174.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0175.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0176.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0177.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0178.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0179.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0180.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0182.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0183.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0185.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0188.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0190.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0193.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0203.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0204.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0206.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0207.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0208.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0209.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0211.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0212.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0214.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0215.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0216.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0217.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0218.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0223.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0227.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0228.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0229.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0232.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0233.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0234.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0235.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0237.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0241.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0242.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0243.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0244.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0245.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0246.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0247.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0248.JPG +photos/Fabio/original/2017Irlanda19-29ago/IMG_0249.JPG +photos/Fabio/original/2017Irlanda19-29ago/VID_20260221_095917.mp4