fixed parsing & db save on startup
This commit is contained in:
parent
e4da59a624
commit
27bf3f4dad
5 changed files with 87 additions and 61 deletions
|
@ -147,9 +147,11 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
||||||
|
|
||||||
private void getCatalogMetadata(MethodCall call, MethodChannel.Result result) {
|
private void getCatalogMetadata(MethodCall call, MethodChannel.Result result) {
|
||||||
String path = call.argument("path");
|
String path = call.argument("path");
|
||||||
|
String mimeType = call.argument("mimeType");
|
||||||
try (InputStream is = new FileInputStream(path)) {
|
try (InputStream is = new FileInputStream(path)) {
|
||||||
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
|
||||||
Map<String, Object> metadataMap = new HashMap<>();
|
Map<String, Object> metadataMap = new HashMap<>();
|
||||||
|
if (!Constants.MIME_MP2TS.equalsIgnoreCase(mimeType)) {
|
||||||
|
Metadata metadata = ImageMetadataReader.readMetadata(is);
|
||||||
|
|
||||||
// EXIF Sub-IFD
|
// EXIF Sub-IFD
|
||||||
ExifSubIFDDirectory exifSubDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
|
ExifSubIFDDirectory exifSubDir = metadata.getFirstDirectoryOfType(ExifSubIFDDirectory.class);
|
||||||
|
@ -187,6 +189,7 @@ public class MetadataHandler implements MethodChannel.MethodCallHandler {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isVideo(call.argument("mimeType"))) {
|
if (isVideo(call.argument("mimeType"))) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -10,6 +10,7 @@ public class Constants {
|
||||||
|
|
||||||
public static final String MIME_VIDEO = "video";
|
public static final String MIME_VIDEO = "video";
|
||||||
public static final String MIME_GIF = "image/gif";
|
public static final String MIME_GIF = "image/gif";
|
||||||
|
public static final String MIME_MP2TS = "video/mp2ts";
|
||||||
|
|
||||||
// video metadata keys, from android.media.MediaMetadataRetriever
|
// video metadata keys, from android.media.MediaMetadataRetriever
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:aves/model/image_decode_service.dart';
|
import 'package:aves/model/image_decode_service.dart';
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
|
import 'package:aves/model/image_metadata.dart';
|
||||||
import 'package:aves/model/metadata_db.dart';
|
import 'package:aves/model/metadata_db.dart';
|
||||||
import 'package:aves/widgets/album/all_collection_page.dart';
|
import 'package:aves/widgets/album/all_collection_page.dart';
|
||||||
import 'package:aves/widgets/common/fake_app_bar.dart';
|
import 'package:aves/widgets/common/fake_app_bar.dart';
|
||||||
|
@ -47,10 +48,11 @@ class _HomePageState extends State<HomePage> {
|
||||||
|
|
||||||
eventChannel.receiveBroadcastStream().cast<Map>().listen(
|
eventChannel.receiveBroadcastStream().cast<Map>().listen(
|
||||||
(entryMap) => setState(() => entries.add(ImageEntry.fromMap(entryMap))),
|
(entryMap) => setState(() => entries.add(ImageEntry.fromMap(entryMap))),
|
||||||
onDone: () {
|
onDone: () async {
|
||||||
debugPrint('mediastore stream done');
|
debugPrint('mediastore stream done');
|
||||||
setState(() {});
|
setState(() {});
|
||||||
catalogEntries();
|
await catalogEntries();
|
||||||
|
await locateEntries();
|
||||||
},
|
},
|
||||||
onError: (error) => debugPrint('mediastore stream error=$error'),
|
onError: (error) => debugPrint('mediastore stream error=$error'),
|
||||||
);
|
);
|
||||||
|
@ -68,20 +70,36 @@ class _HomePageState extends State<HomePage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
catalogEntries() async {
|
catalogEntries() async {
|
||||||
debugPrint('$runtimeType catalogEntries cataloging start');
|
debugPrint('$runtimeType catalogEntries start');
|
||||||
await Future.forEach<ImageEntry>(entries, (entry) async {
|
final start = DateTime.now();
|
||||||
|
final uncataloguedEntries = entries.where((entry) => !entry.isCataloged);
|
||||||
|
final newMetadata = List<CatalogMetadata>();
|
||||||
|
await Future.forEach<ImageEntry>(uncataloguedEntries, (entry) async {
|
||||||
await entry.catalog();
|
await entry.catalog();
|
||||||
|
newMetadata.add(entry.catalogMetadata);
|
||||||
});
|
});
|
||||||
debugPrint('$runtimeType catalogEntries cataloging complete');
|
debugPrint('$runtimeType catalogEntries complete in ${DateTime.now().difference(start).inSeconds}s with ${newMetadata.length} new entries');
|
||||||
|
|
||||||
// sort with more accurate date
|
// sort with more accurate date
|
||||||
entries.sort((a, b) => b.bestDate.compareTo(a.bestDate));
|
entries.sort((a, b) => b.bestDate.compareTo(a.bestDate));
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
|
||||||
debugPrint('$runtimeType catalogEntries locating start');
|
metadataDb.saveMetadata(List.unmodifiable(newMetadata));
|
||||||
await Future.forEach<ImageEntry>(entries, (entry) async {
|
}
|
||||||
|
|
||||||
|
locateEntries() async {
|
||||||
|
debugPrint('$runtimeType locateEntries start');
|
||||||
|
final start = DateTime.now();
|
||||||
|
final unlocatedEntries = entries.where((entry) => !entry.isLocated);
|
||||||
|
final newAddresses = List<AddressDetails>();
|
||||||
|
await Future.forEach<ImageEntry>(unlocatedEntries, (entry) async {
|
||||||
await entry.locate();
|
await entry.locate();
|
||||||
|
newAddresses.add(entry.addressDetails);
|
||||||
|
if (newAddresses.length >= 50) {
|
||||||
|
metadataDb.saveAddresses(List.unmodifiable(newAddresses));
|
||||||
|
newAddresses.clear();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
debugPrint('$runtimeType catalogEntries locating done');
|
debugPrint('$runtimeType locateEntries complete in ${DateTime.now().difference(start).inSeconds}s with ${newAddresses.length} new addresses');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,14 +51,18 @@ class MetadataDb {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertMetadata(CatalogMetadata metadata) async {
|
saveMetadata(Iterable<CatalogMetadata> metadataEntries) async {
|
||||||
// debugPrint('$runtimeType insertMetadata metadata=$metadata');
|
if (metadataEntries == null || metadataEntries.isEmpty) return;
|
||||||
|
final start = DateTime.now();
|
||||||
final db = await _database;
|
final db = await _database;
|
||||||
await db.insert(
|
final batch = db.batch();
|
||||||
|
metadataEntries.where((metadata) => metadata != null).forEach((metadata) => batch.insert(
|
||||||
metadataTable,
|
metadataTable,
|
||||||
metadata.toMap(),
|
metadata.toMap(),
|
||||||
conflictAlgorithm: ConflictAlgorithm.replace,
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||||
);
|
));
|
||||||
|
await batch.commit(noResult: true);
|
||||||
|
debugPrint('$runtimeType saveMetadata complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${metadataEntries.length} entries');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<AddressDetails>> getAllAddresses() async {
|
Future<List<AddressDetails>> getAllAddresses() async {
|
||||||
|
@ -78,13 +82,17 @@ class MetadataDb {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertAddress(AddressDetails metadata) async {
|
saveAddresses(Iterable<AddressDetails> addresses) async {
|
||||||
// debugPrint('$runtimeType insertAddress metadata=$metadata');
|
if (addresses == null || addresses.isEmpty) return;
|
||||||
|
final start = DateTime.now();
|
||||||
final db = await _database;
|
final db = await _database;
|
||||||
await db.insert(
|
final batch = db.batch();
|
||||||
|
addresses.where((address) => address != null).forEach((address) => batch.insert(
|
||||||
addressTable,
|
addressTable,
|
||||||
metadata.toMap(),
|
address.toMap(),
|
||||||
conflictAlgorithm: ConflictAlgorithm.replace,
|
conflictAlgorithm: ConflictAlgorithm.replace,
|
||||||
);
|
));
|
||||||
|
await batch.commit(noResult: true);
|
||||||
|
debugPrint('$runtimeType saveAddresses complete in ${DateTime.now().difference(start).inMilliseconds}ms with ${addresses.length} entries');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import 'package:aves/model/image_entry.dart';
|
import 'package:aves/model/image_entry.dart';
|
||||||
import 'package:aves/model/image_metadata.dart';
|
import 'package:aves/model/image_metadata.dart';
|
||||||
import 'package:aves/model/metadata_db.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
@ -22,7 +21,6 @@ class MetadataService {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<CatalogMetadata> getCatalogMetadata(ImageEntry entry) async {
|
static Future<CatalogMetadata> getCatalogMetadata(ImageEntry entry) async {
|
||||||
CatalogMetadata metadata;
|
|
||||||
try {
|
try {
|
||||||
// return map with:
|
// return map with:
|
||||||
// 'dateMillis': date taken in milliseconds since Epoch (long)
|
// 'dateMillis': date taken in milliseconds since Epoch (long)
|
||||||
|
@ -34,9 +32,7 @@ class MetadataService {
|
||||||
'path': entry.path,
|
'path': entry.path,
|
||||||
}) as Map;
|
}) as Map;
|
||||||
result['contentId'] = entry.contentId;
|
result['contentId'] = entry.contentId;
|
||||||
metadata = CatalogMetadata.fromMap(result);
|
return CatalogMetadata.fromMap(result);
|
||||||
metadataDb.insertMetadata(metadata);
|
|
||||||
return metadata;
|
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
debugPrint('getCatalogMetadata failed with exception=${e.message}');
|
debugPrint('getCatalogMetadata failed with exception=${e.message}');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue