mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-03-19 21:58:54 +01:00
389 lines
10 KiB
Dart
389 lines
10 KiB
Dart
import 'dart:io' as io;
|
|
|
|
import 'package:equatable/equatable.dart';
|
|
import 'package:logging/logging.dart';
|
|
import 'package:np_codegen/np_codegen.dart';
|
|
import 'package:np_common/or_null.dart';
|
|
import 'package:np_common/type.dart';
|
|
import 'package:np_datetime/np_datetime.dart';
|
|
import 'package:np_db/src/entity.dart';
|
|
import 'package:np_db_sqlite/np_db_sqlite.dart';
|
|
import 'package:to_string/to_string.dart';
|
|
|
|
part 'api.g.dart';
|
|
|
|
typedef NpDbComputeCallback<T, U> = Future<U> Function(NpDb db, T message);
|
|
|
|
/// A data structure that identify a File in db
|
|
@ToString(ignoreNull: true)
|
|
class DbFileKey {
|
|
const DbFileKey({
|
|
this.fileId,
|
|
this.relativePath,
|
|
}) : assert(fileId != null || relativePath != null);
|
|
|
|
const DbFileKey.byId(int fileId) : this(fileId: fileId);
|
|
|
|
const DbFileKey.byPath(String relativePath)
|
|
: this(relativePath: relativePath);
|
|
|
|
@override
|
|
String toString() => _$toString();
|
|
|
|
bool compareIdentity(DbFileKey other) =>
|
|
fileId == other.fileId || relativePath == other.relativePath;
|
|
|
|
final int? fileId;
|
|
final String? relativePath;
|
|
}
|
|
|
|
class DbSyncResult {
|
|
const DbSyncResult({
|
|
required this.insert,
|
|
required this.delete,
|
|
required this.update,
|
|
});
|
|
|
|
final int insert;
|
|
final int delete;
|
|
final int update;
|
|
}
|
|
|
|
@toString
|
|
class DbLocationGroup with EquatableMixin {
|
|
const DbLocationGroup({
|
|
required this.place,
|
|
required this.countryCode,
|
|
required this.count,
|
|
required this.latestFileId,
|
|
required this.latestDateTime,
|
|
});
|
|
|
|
@override
|
|
String toString() => _$toString();
|
|
|
|
@override
|
|
List<Object?> get props => [
|
|
place,
|
|
countryCode,
|
|
count,
|
|
latestFileId,
|
|
latestDateTime,
|
|
];
|
|
|
|
final String place;
|
|
final String countryCode;
|
|
final int count;
|
|
final int latestFileId;
|
|
final DateTime latestDateTime;
|
|
}
|
|
|
|
@toString
|
|
class DbLocationGroupResult {
|
|
const DbLocationGroupResult({
|
|
required this.name,
|
|
required this.admin1,
|
|
required this.admin2,
|
|
required this.countryCode,
|
|
});
|
|
|
|
@override
|
|
String toString() => _$toString();
|
|
|
|
final List<DbLocationGroup> name;
|
|
final List<DbLocationGroup> admin1;
|
|
final List<DbLocationGroup> admin2;
|
|
final List<DbLocationGroup> countryCode;
|
|
}
|
|
|
|
@npLog
|
|
abstract class NpDb {
|
|
factory NpDb() => NpDbSqlite();
|
|
|
|
/// Initialize the db for the main isolate
|
|
///
|
|
/// If running on android, you must pass the current SDK int to [androidSdk].
|
|
/// If running on other platforms, this value will be ignored, you can pass
|
|
/// null in such case
|
|
Future<void> initMainIsolate({
|
|
required int? androidSdk,
|
|
});
|
|
|
|
/// Initialize the db for a background isolate
|
|
///
|
|
/// If running on android, you must pass the current SDK int to [androidSdk].
|
|
/// If running on other platforms, this value will be ignored, you can pass
|
|
/// null in such case
|
|
Future<void> initBackgroundIsolate({
|
|
required int? androidSdk,
|
|
});
|
|
|
|
/// Dispose the db
|
|
///
|
|
/// After disposing, you must not call any methods defined here anymore. This
|
|
/// is typically used before stopping a background isolate
|
|
Future<void> dispose();
|
|
|
|
Future<io.File> export(io.Directory dir);
|
|
|
|
/// Start an isolate with a [NpDb] instance provided to you
|
|
Future<U> compute<T, U>(NpDbComputeCallback<T, U> callback, T args);
|
|
|
|
/// Insert [accounts] to db
|
|
Future<void> addAccounts(List<DbAccount> accounts);
|
|
|
|
/// Clear all data in the database and insert [accounts]
|
|
///
|
|
/// WARNING: ALL data will be dropped!
|
|
Future<void> clearAndInitWithAccounts(List<DbAccount> accounts);
|
|
|
|
Future<void> deleteAccount(DbAccount account);
|
|
|
|
Future<List<DbAlbum>> getAlbumsByAlbumFileIds({
|
|
required DbAccount account,
|
|
required List<int> fileIds,
|
|
});
|
|
|
|
Future<void> syncAlbum({
|
|
required DbAccount account,
|
|
required DbFile albumFile,
|
|
required DbAlbum album,
|
|
});
|
|
|
|
/// Return all faces provided by the Face Recognition app
|
|
Future<List<DbFaceRecognitionPerson>> getFaceRecognitionPersons({
|
|
required DbAccount account,
|
|
});
|
|
|
|
/// Return faces provided by the Face Recognition app with loosely matched
|
|
/// [name]
|
|
Future<List<DbFaceRecognitionPerson>> searchFaceRecognitionPersonsByName({
|
|
required DbAccount account,
|
|
required String name,
|
|
});
|
|
|
|
/// Replace all recognized people for [account]
|
|
Future<DbSyncResult> syncFaceRecognitionPersons({
|
|
required DbAccount account,
|
|
required List<DbFaceRecognitionPerson> persons,
|
|
});
|
|
|
|
/// Return files located inside [dir]
|
|
Future<List<DbFile>> getFilesByDirKey({
|
|
required DbAccount account,
|
|
required DbFileKey dir,
|
|
});
|
|
|
|
Future<List<DbFile>> getFilesByDirKeyAndLocation({
|
|
required DbAccount account,
|
|
required String dirRelativePath,
|
|
required String? place,
|
|
required String countryCode,
|
|
});
|
|
|
|
/// Return [DbFile]s by their corresponding file ids
|
|
///
|
|
/// No error will be thrown even if a file in [fileIds] is not found, it is
|
|
/// thus the responsibility of the caller to decide how to handle such case.
|
|
/// Returned files are NOT guaranteed to be sorted as [fileIds]
|
|
Future<List<DbFile>> getFilesByFileIds({
|
|
required DbAccount account,
|
|
required List<int> fileIds,
|
|
});
|
|
|
|
/// Return [DbFile]s by their date time value
|
|
Future<List<DbFile>> getFilesByTimeRange({
|
|
required DbAccount account,
|
|
required List<String> dirRoots,
|
|
required TimeRange range,
|
|
});
|
|
|
|
/// Update one or more file properties of a single file
|
|
Future<void> updateFileByFileId({
|
|
required DbAccount account,
|
|
required int fileId,
|
|
String? relativePath,
|
|
OrNull<bool>? isFavorite,
|
|
OrNull<bool>? isArchived,
|
|
OrNull<DateTime>? overrideDateTime,
|
|
DateTime? bestDateTime,
|
|
OrNull<DbImageData>? imageData,
|
|
OrNull<DbLocation>? location,
|
|
});
|
|
|
|
/// Batch update one or more file properties of multiple files
|
|
///
|
|
/// Only a subset of properties can be updated in batch
|
|
Future<void> updateFilesByFileIds({
|
|
required DbAccount account,
|
|
required List<int> fileIds,
|
|
OrNull<bool>? isFavorite,
|
|
OrNull<bool>? isArchived,
|
|
});
|
|
|
|
/// Add or replace files in db
|
|
Future<void> syncDirFiles({
|
|
required DbAccount account,
|
|
required DbFileKey dirFile,
|
|
required List<DbFile> files,
|
|
});
|
|
|
|
/// Replace a file in db
|
|
Future<void> syncFile({
|
|
required DbAccount account,
|
|
required DbFile file,
|
|
});
|
|
|
|
/// Add or replace nc albums in db
|
|
Future<DbSyncResult> syncFavoriteFiles({
|
|
required DbAccount account,
|
|
required List<int> favoriteFileIds,
|
|
});
|
|
|
|
/// Return number of files without metadata
|
|
Future<int> countFilesByFileIdsMissingMetadata({
|
|
required DbAccount account,
|
|
required List<int> fileIds,
|
|
required List<String> mimes,
|
|
});
|
|
|
|
/// Delete a file or dir from db
|
|
Future<void> deleteFile({
|
|
required DbAccount account,
|
|
required DbFileKey file,
|
|
});
|
|
|
|
/// Return a map of file id to etags for all dirs and sub dirs located under
|
|
/// [relativePath], including the path itself
|
|
Future<Map<int, String>> getDirFileIdToEtagByLikeRelativePath({
|
|
required DbAccount account,
|
|
required String relativePath,
|
|
});
|
|
|
|
/// Remove all children of a dir
|
|
Future<void> truncateDir({
|
|
required DbAccount account,
|
|
required DbFileKey dir,
|
|
});
|
|
|
|
/// Return [DbFileDescriptor]s
|
|
///
|
|
/// Limit results by their corresponding file ids if [fileIds] is not null. No
|
|
/// error will be thrown even if a file in [fileIds] is not found, it is thus
|
|
/// the responsibility of the caller to decide how to handle such case
|
|
///
|
|
/// [includeRelativeRoots] define paths to be included; [excludeRelativeRoots]
|
|
/// define paths to be excluded. Paths in both lists are matched as prefix
|
|
///
|
|
/// Limit type of files to be returned by specifying [mimes]. The mime types
|
|
/// are matched as is
|
|
///
|
|
/// Returned files are sorted by [DbFileDescriptor.bestDateTime] in descending
|
|
/// order
|
|
Future<List<DbFileDescriptor>> getFileDescriptors({
|
|
required DbAccount account,
|
|
List<int>? fileIds,
|
|
List<String>? includeRelativeRoots,
|
|
List<String>? excludeRelativeRoots,
|
|
List<String>? relativePathKeywords,
|
|
String? location,
|
|
bool? isFavorite,
|
|
List<String>? mimes,
|
|
int? limit,
|
|
});
|
|
|
|
Future<DbLocationGroupResult> groupLocations({
|
|
required DbAccount account,
|
|
List<String>? includeRelativeRoots,
|
|
List<String>? excludeRelativeRoots,
|
|
});
|
|
|
|
Future<List<DbNcAlbum>> getNcAlbums({
|
|
required DbAccount account,
|
|
});
|
|
|
|
Future<void> addNcAlbum({
|
|
required DbAccount account,
|
|
required DbNcAlbum album,
|
|
});
|
|
|
|
Future<void> deleteNcAlbum({
|
|
required DbAccount account,
|
|
required DbNcAlbum album,
|
|
});
|
|
|
|
/// Add or replace nc albums in db
|
|
Future<DbSyncResult> syncNcAlbums({
|
|
required DbAccount account,
|
|
required List<DbNcAlbum> albums,
|
|
});
|
|
|
|
Future<List<DbNcAlbumItem>> getNcAlbumItemsByParent({
|
|
required DbAccount account,
|
|
required DbNcAlbum parent,
|
|
});
|
|
|
|
/// Add or replace nc album items in db
|
|
Future<DbSyncResult> syncNcAlbumItems({
|
|
required DbAccount account,
|
|
required DbNcAlbum album,
|
|
required List<DbNcAlbumItem> items,
|
|
});
|
|
|
|
/// Return all faces provided by the Recognize app
|
|
Future<List<DbRecognizeFace>> getRecognizeFaces({
|
|
required DbAccount account,
|
|
});
|
|
|
|
Future<List<DbRecognizeFaceItem>> getRecognizeFaceItemsByFaceLabel({
|
|
required DbAccount account,
|
|
required String label,
|
|
});
|
|
|
|
Future<Map<String, List<DbRecognizeFaceItem>>>
|
|
getRecognizeFaceItemsByFaceLabels({
|
|
required DbAccount account,
|
|
required List<String> labels,
|
|
ErrorWithValueHandler<String>? onError,
|
|
});
|
|
|
|
Future<Map<String, DbRecognizeFaceItem>>
|
|
getLatestRecognizeFaceItemsByFaceLabels({
|
|
required DbAccount account,
|
|
required List<String> labels,
|
|
ErrorWithValueHandler<String>? onError,
|
|
});
|
|
|
|
/// Replace all recognized faces for [account]
|
|
///
|
|
/// Return true if any of the faces or items are changed
|
|
Future<bool> syncRecognizeFacesAndItems({
|
|
required DbAccount account,
|
|
required Map<DbRecognizeFace, List<DbRecognizeFaceItem>> data,
|
|
});
|
|
|
|
/// Return all tags
|
|
Future<List<DbTag>> getTags({
|
|
required DbAccount account,
|
|
});
|
|
|
|
/// Return the tag matching [displayName]
|
|
Future<DbTag?> getTagByDisplayName({
|
|
required DbAccount account,
|
|
required String displayName,
|
|
});
|
|
|
|
/// Replace all tags for [account]
|
|
Future<DbSyncResult> syncTags({
|
|
required DbAccount account,
|
|
required List<DbTag> tags,
|
|
});
|
|
|
|
/// Migrate to app v55
|
|
Future<void> migrateV55(void Function(int current, int count)? onProgress);
|
|
|
|
/// Run vacuum statement on a database backed by sqlite
|
|
///
|
|
/// This method is not necessarily supported by all implementations
|
|
Future<void> sqlVacuum();
|
|
}
|