Compare commits
24 Commits
smart-albu
...
server_rev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1a1d8f873 | ||
|
|
da7edac292 | ||
|
|
daaf73664a | ||
|
|
17127b8f0e | ||
|
|
b9c8fdb080 | ||
|
|
98868dd76f | ||
|
|
b58aeddeba | ||
|
|
e9ef9d55a4 | ||
|
|
968f04c04a | ||
|
|
59cb3f091e | ||
|
|
630f5a2706 | ||
|
|
4a743be322 | ||
|
|
c2db1f7da9 | ||
|
|
843e956a8a | ||
|
|
c2d1c66888 | ||
|
|
e2aabfb95a | ||
|
|
dbf88c7bed | ||
|
|
a06a5be983 | ||
|
|
3bba125f1c | ||
|
|
1718e5d1d6 | ||
|
|
b16c9af36b | ||
|
|
1cc3499019 | ||
|
|
4260c3c769 | ||
|
|
209291e09a |
@@ -1295,6 +1295,10 @@
|
||||
"PAYDAY 3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"title": "Startmail",
|
||||
"slug": "startmail"
|
||||
},
|
||||
{
|
||||
"title": "STRATO",
|
||||
"hex": "FF8800"
|
||||
|
||||
15
mobile/apps/auth/assets/custom-icons/icons/startmail.svg
Executable file
15
mobile/apps/auth/assets/custom-icons/icons/startmail.svg
Executable file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 27.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Слой_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="500px" height="500px" viewBox="0 0 500 500" style="enable-background:new 0 0 500 500;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#6573FF;}
|
||||
.st1{fill:#202945;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st0" d="M500,47.2C500,20.9,478.6,0,452.9,0H47.7C21.4-0.5,0,20.9,0,47.2v43.9c0,0,186.4,180.6,250.5,180.6
|
||||
C319.6,271.7,500,92.2,500,92.2S500,56.5,500,47.2z"/>
|
||||
<path class="st1" d="M0,452.8C0,479.1,21.4,500,47.2,500h405.6c26.3,0,47.2-21.4,47.2-47.2V142.7c0,0-159.2,184.4-249.7,184.4
|
||||
C160.8,327.1,0,178.4,0,178.4C0,236.6,0,395.2,0,452.8z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 843 B |
@@ -979,6 +979,29 @@ class FilesDB with SqlDbBase {
|
||||
return result;
|
||||
}
|
||||
|
||||
// remove references for local files which are either already uploaded
|
||||
// or queued for upload but not yet uploaded
|
||||
Future<int> removeQueuedLocalFiles(Set<String> localIDs) async {
|
||||
final db = await instance.sqliteAsyncDB;
|
||||
final inParam = localIDs.map((id) => "'$id'").join(',');
|
||||
final r = await db.execute(
|
||||
'''
|
||||
DELETE FROM $filesTable
|
||||
WHERE $columnLocalID IN ($inParam) and (collectionID IS NULL || collectionID = -1)
|
||||
and ($columnUploadedFileID IS NULL OR $columnUploadedFileID = -1);
|
||||
''',
|
||||
);
|
||||
if (r.isNotEmpty) {
|
||||
_logger.warning(
|
||||
"Removed ${r.length} potential dups for already queued local files",
|
||||
);
|
||||
} else {
|
||||
_logger.finest("No duplicate id found for queued/uploaded files");
|
||||
}
|
||||
|
||||
return r.length;
|
||||
}
|
||||
|
||||
Future<Set<String>> getLocalFileIDsForCollection(int collectionID) async {
|
||||
final db = await instance.sqliteAsyncDB;
|
||||
final rows = await db.getAll(
|
||||
|
||||
@@ -383,8 +383,12 @@ class MLDataDB with SqlDbBase implements IMLDataDB<int> {
|
||||
}
|
||||
}
|
||||
if (personID == null && clusterID == null) {
|
||||
_logger.severe("personID and clusterID cannot be null both");
|
||||
throw Exception("personID and clusterID cannot be null");
|
||||
}
|
||||
_logger.severe(
|
||||
"Something went wrong finding a face from `getCoverFaceForPerson` (personID: $personID, clusterID: $clusterID)",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1427,12 +1427,20 @@ class CollectionsService {
|
||||
}
|
||||
// group files by collectionID
|
||||
final Map<int, List<EnteFile>> filesByCollection = {};
|
||||
final Map<int, Set<int>> fileSeenByCollection = {};
|
||||
for (final file in filesToCopy) {
|
||||
if (filesByCollection.containsKey(file.collectionID!)) {
|
||||
filesByCollection[file.collectionID!]!.add(file.copyWith());
|
||||
} else {
|
||||
filesByCollection[file.collectionID!] = [file.copyWith()];
|
||||
fileSeenByCollection.putIfAbsent(file.collectionID!, () => <int>{});
|
||||
if (fileSeenByCollection[file.collectionID]!
|
||||
.contains(file.uploadedFileID)) {
|
||||
_logger.warning(
|
||||
"skip copy, duplicate ID: ${file.uploadedFileID} in collection "
|
||||
"${file.collectionID}",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
filesByCollection
|
||||
.putIfAbsent(file.collectionID!, () => [])
|
||||
.add(file.copyWith());
|
||||
}
|
||||
for (final entry in filesByCollection.entries) {
|
||||
final srcCollectionID = entry.key;
|
||||
@@ -1579,9 +1587,6 @@ class CollectionsService {
|
||||
params["files"] = [];
|
||||
for (final batchFile in batch) {
|
||||
final fileKey = getFileKey(batchFile);
|
||||
_logger.info(
|
||||
"srcCollection : $srcCollectionID file: ${batchFile.uploadedFileID} key: ${CryptoUtil.bin2base64(fileKey)} ",
|
||||
);
|
||||
final encryptedKeyData =
|
||||
CryptoUtil.encryptSync(fileKey, getCollectionKey(dstCollectionID));
|
||||
batchFile.encryptedKey =
|
||||
@@ -1643,17 +1648,27 @@ class CollectionsService {
|
||||
);
|
||||
final List<EnteFile> filesToCopy = [];
|
||||
final List<EnteFile> filesToAdd = [];
|
||||
final Set<int> seenForAdd = {};
|
||||
final Set<int> seenForCopy = {};
|
||||
|
||||
for (final EnteFile file in othersFile) {
|
||||
if (hashToUserFile.containsKey(file.hash ?? '')) {
|
||||
final userFile = hashToUserFile[file.hash]!;
|
||||
if (userFile.fileType == file.fileType) {
|
||||
filesToAdd.add(userFile);
|
||||
} else {
|
||||
filesToCopy.add(file);
|
||||
}
|
||||
} else {
|
||||
filesToCopy.add(file);
|
||||
final userFile = hashToUserFile[file.hash ?? ''];
|
||||
final bool shouldAdd =
|
||||
userFile != null && userFile.fileType == file.fileType;
|
||||
final targetList = shouldAdd ? filesToAdd : filesToCopy;
|
||||
final seenSet = shouldAdd ? seenForAdd : seenForCopy;
|
||||
final fileToProcess = shouldAdd ? userFile : file;
|
||||
final uploadID = fileToProcess.uploadedFileID;
|
||||
|
||||
if (seenSet.contains(uploadID)) {
|
||||
final action = shouldAdd ? "adding" : "copying";
|
||||
_logger.warning(
|
||||
"skip $action file $uploadID as it is already ${action}ed",
|
||||
);
|
||||
continue;
|
||||
}
|
||||
targetList.add(fileToProcess);
|
||||
seenSet.add(uploadID!);
|
||||
}
|
||||
return (filesToAdd, filesToCopy);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ import "package:ml_linalg/dtype.dart";
|
||||
import "package:ml_linalg/vector.dart";
|
||||
import "package:photos/generated/protos/ente/common/vector.pb.dart";
|
||||
import "package:photos/models/base/id.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_clustering/face_db_info_for_clustering.dart";
|
||||
import "package:photos/services/machine_learning/face_ml/face_filtering/face_filtering_constants.dart";
|
||||
import "package:photos/services/machine_learning/ml_result.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
|
||||
class FaceInfo {
|
||||
final String faceID;
|
||||
@@ -507,7 +507,8 @@ ClusteringResult _runCompleteClustering(Map args) {
|
||||
EVector.fromBuffer(entry.value).values,
|
||||
dtype: DType.float32,
|
||||
),
|
||||
fileCreationTime: fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
fileCreationTime:
|
||||
fileIDToCreationTime?[getFileIdFromFaceId<int>(entry.key)],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data' show Uint8List;
|
||||
|
||||
import "package:computer/computer.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/ml/face/box.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/utils/image_ml_util.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
|
||||
final Computer _computer = Computer.shared();
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
class FaceThumbnailGenerator extends SuperIsolate {
|
||||
@override
|
||||
Logger get logger => _logger;
|
||||
@@ -37,20 +35,30 @@ class FaceThumbnailGenerator extends SuperIsolate {
|
||||
String imagePath,
|
||||
List<FaceBox> faceBoxes,
|
||||
) async {
|
||||
final List<Map<String, dynamic>> faceBoxesJson =
|
||||
faceBoxes.map((box) => box.toJson()).toList();
|
||||
final List<Uint8List> faces = await runInIsolate(
|
||||
IsolateOperation.generateFaceThumbnails,
|
||||
{
|
||||
'imagePath': imagePath,
|
||||
'faceBoxesList': faceBoxesJson,
|
||||
},
|
||||
).then((value) => value.cast<Uint8List>());
|
||||
final compressedFaces =
|
||||
await compressFaceThumbnails({'listPngBytes': faces});
|
||||
_logger.fine(
|
||||
"Compressed face thumbnails from sizes ${faces.map((e) => e.length / 1024).toList()} to ${compressedFaces.map((e) => e.length / 1024).toList()} kilobytes",
|
||||
);
|
||||
return compressedFaces;
|
||||
try {
|
||||
_logger.info(
|
||||
"Generating face thumbnails for ${faceBoxes.length} face boxes in $imagePath",
|
||||
);
|
||||
final List<Map<String, dynamic>> faceBoxesJson =
|
||||
faceBoxes.map((box) => box.toJson()).toList();
|
||||
final List<Uint8List> faces = await runInIsolate(
|
||||
IsolateOperation.generateFaceThumbnails,
|
||||
{
|
||||
'imagePath': imagePath,
|
||||
'faceBoxesList': faceBoxesJson,
|
||||
},
|
||||
).then((value) => value.cast<Uint8List>());
|
||||
_logger.info("Generated face thumbnails");
|
||||
final compressedFaces =
|
||||
await compressFaceThumbnails({'listPngBytes': faces});
|
||||
_logger.fine(
|
||||
"Compressed face thumbnails from sizes ${faces.map((e) => e.length / 1024).toList()} to ${compressedFaces.map((e) => e.length / 1024).toList()} kilobytes",
|
||||
);
|
||||
return compressedFaces;
|
||||
} catch (e, s) {
|
||||
_logger.severe("Failed to generate face thumbnails", e, s);
|
||||
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import 'dart:async';
|
||||
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/models/ml/vector.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import "package:photos/services/machine_learning/ml_constants.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/clip/clip_text_encoder.dart";
|
||||
import "package:photos/services/machine_learning/semantic_search/query_result.dart";
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
class MLComputer extends SuperIsolate {
|
||||
|
||||
@@ -2,14 +2,14 @@ import "dart:async";
|
||||
|
||||
import "package:flutter/foundation.dart" show debugPrint;
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/services/isolate_service.dart";
|
||||
import 'package:photos/services/machine_learning/face_ml/face_detection/face_detection_service.dart';
|
||||
import 'package:photos/services/machine_learning/face_ml/face_embedding/face_embedding_service.dart';
|
||||
import "package:photos/services/machine_learning/ml_models_overview.dart";
|
||||
import 'package:photos/services/machine_learning/ml_result.dart';
|
||||
import "package:photos/services/machine_learning/semantic_search/clip/clip_image_encoder.dart";
|
||||
import "package:photos/services/remote_assets_service.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:photos/utils/isolate/super_isolate.dart";
|
||||
import "package:photos/utils/ml_util.dart";
|
||||
import "package:photos/utils/network_util.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
@@ -371,6 +371,9 @@ class RemoteSyncService {
|
||||
final Set<String> alreadyClaimedLocalIDs =
|
||||
await _db.getLocalIDsMarkedForOrAlreadyUploaded(ownerID);
|
||||
localIDsToSync.removeAll(alreadyClaimedLocalIDs);
|
||||
if (alreadyClaimedLocalIDs.isNotEmpty) {
|
||||
await _db.removeQueuedLocalFiles(alreadyClaimedLocalIDs);
|
||||
}
|
||||
}
|
||||
|
||||
if (localIDsToSync.isEmpty) {
|
||||
|
||||
@@ -21,6 +21,7 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
final String? clusterID;
|
||||
final bool useFullFile;
|
||||
final VoidCallback? onErrorCallback;
|
||||
final bool keepAlive;
|
||||
|
||||
// PersonFaceWidget constructor checks that both personId and clusterID are not null
|
||||
// and that the file is not null
|
||||
@@ -29,6 +30,7 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
this.clusterID,
|
||||
this.useFullFile = true,
|
||||
this.onErrorCallback,
|
||||
this.keepAlive = false,
|
||||
super.key,
|
||||
}) : assert(
|
||||
personId != null || clusterID != null,
|
||||
@@ -39,12 +41,16 @@ class PersonFaceWidget extends StatefulWidget {
|
||||
State<PersonFaceWidget> createState() => _PersonFaceWidgetState();
|
||||
}
|
||||
|
||||
class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
class _PersonFaceWidgetState extends State<PersonFaceWidget>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
Future<Uint8List?>? faceCropFuture;
|
||||
EnteFile? fileForFaceCrop;
|
||||
|
||||
bool get isPerson => widget.personId != null;
|
||||
|
||||
@override
|
||||
bool get wantKeepAlive => widget.keepAlive;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -64,6 +70,10 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(
|
||||
context,
|
||||
); // Calling super.build for AutomaticKeepAliveClientMixin
|
||||
|
||||
return FutureBuilder<Uint8List?>(
|
||||
future: faceCropFuture,
|
||||
builder: (context, snapshot) {
|
||||
@@ -163,7 +173,7 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
}
|
||||
}
|
||||
if (fileForFaceCrop == null) {
|
||||
_logger.warning(
|
||||
_logger.severe(
|
||||
"No suitable file found for face crop for person: ${widget.personId} or cluster: ${widget.clusterID}",
|
||||
);
|
||||
return null;
|
||||
@@ -176,7 +186,7 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
clusterID: widget.clusterID,
|
||||
);
|
||||
if (face == null) {
|
||||
debugPrint(
|
||||
_logger.severe(
|
||||
"No cover face for person: ${widget.personId} or cluster ${widget.clusterID} and fileID ${fileForFaceCrop.uploadedFileID!}",
|
||||
);
|
||||
return null;
|
||||
@@ -188,7 +198,13 @@ class _PersonFaceWidgetState extends State<PersonFaceWidget> {
|
||||
personOrClusterID: personOrClusterId,
|
||||
useTempCache: false,
|
||||
);
|
||||
return cropMap?[face.faceID];
|
||||
final result = cropMap?[face.faceID];
|
||||
if (result == null) {
|
||||
_logger.severe(
|
||||
"Null cover face crop for person: ${widget.personId} or cluster ${widget.clusterID} and fileID ${fileForFaceCrop.uploadedFileID!}",
|
||||
);
|
||||
}
|
||||
return result;
|
||||
} catch (e, s) {
|
||||
_logger.severe(
|
||||
"Error getting cover face for person: ${widget.personId} or cluster ${widget.clusterID}",
|
||||
|
||||
@@ -95,12 +95,14 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
final GenericSearchResult searchResult;
|
||||
final double size;
|
||||
final SelectedPeople selectedPeople;
|
||||
final bool isDefaultFace;
|
||||
|
||||
const SelectablePersonSearchExample({
|
||||
super.key,
|
||||
required this.searchResult,
|
||||
required this.selectedPeople,
|
||||
this.size = 102,
|
||||
this.isDefaultFace = false,
|
||||
});
|
||||
|
||||
void _handleTap(BuildContext context) {
|
||||
@@ -192,7 +194,10 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
searchResult.previewThumbnail()!,
|
||||
shouldShowSyncStatus: false,
|
||||
)
|
||||
: FaceSearchResult(searchResult);
|
||||
: FaceSearchResult(
|
||||
searchResult,
|
||||
isDefaultFace: isDefaultFace,
|
||||
);
|
||||
} else {
|
||||
child = const NoThumbnailWidget(
|
||||
addBorder: false,
|
||||
@@ -301,8 +306,13 @@ class SelectablePersonSearchExample extends StatelessWidget {
|
||||
|
||||
class FaceSearchResult extends StatelessWidget {
|
||||
final SearchResult searchResult;
|
||||
final bool isDefaultFace;
|
||||
|
||||
const FaceSearchResult(this.searchResult, {super.key});
|
||||
const FaceSearchResult(
|
||||
this.searchResult, {
|
||||
super.key,
|
||||
this.isDefaultFace = false,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -313,6 +323,7 @@ class FaceSearchResult extends StatelessWidget {
|
||||
key: params.containsKey(kPersonWidgetKey)
|
||||
? ValueKey(params[kPersonWidgetKey])
|
||||
: ValueKey(params[kPersonParamID] ?? params[kClusterParamId]),
|
||||
keepAlive: isDefaultFace,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -486,6 +497,7 @@ class _PeopleSectionAllWidgetState extends State<PeopleSectionAllWidget> {
|
||||
searchResult: normalFaces[index],
|
||||
size: itemSize,
|
||||
selectedPeople: widget.selectedPeople!,
|
||||
isDefaultFace: true,
|
||||
)
|
||||
: PersonSearchExample(
|
||||
searchResult: normalFaces[index],
|
||||
@@ -525,6 +537,7 @@ class _PeopleSectionAllWidgetState extends State<PeopleSectionAllWidget> {
|
||||
searchResult: extraFaces[index],
|
||||
size: itemSize,
|
||||
selectedPeople: widget.selectedPeople!,
|
||||
isDefaultFace: false,
|
||||
)
|
||||
: PersonSearchExample(
|
||||
searchResult: extraFaces[index],
|
||||
|
||||
@@ -136,7 +136,7 @@ Future<Map<String, Uint8List>?> getCachedFaceCrops(
|
||||
facesWithoutCrops[face.faceID] = face.detection.box;
|
||||
}
|
||||
} catch (e, s) {
|
||||
_logger.severe(
|
||||
_logger.warning(
|
||||
"Error reading cached face crop for faceID ${face.faceID} from file ${faceCropCacheFile.path}",
|
||||
e,
|
||||
s,
|
||||
@@ -212,7 +212,7 @@ Future<Map<String, Uint8List>?> getCachedFaceCrops(
|
||||
milliseconds: 100 * pow(2, fetchAttempt + 1).toInt(),
|
||||
);
|
||||
await Future.delayed(backoff);
|
||||
_logger.warning(
|
||||
_logger.fine(
|
||||
"Error getting face crops for faceIDs: ${faces.map((face) => face.faceID).toList()}, retrying (attempt ${fetchAttempt + 1}) in ${backoff.inMilliseconds} ms",
|
||||
e,
|
||||
s,
|
||||
@@ -225,13 +225,13 @@ Future<Map<String, Uint8List>?> getCachedFaceCrops(
|
||||
useTempCache: useTempCache,
|
||||
);
|
||||
}
|
||||
_logger.severe(
|
||||
_logger.warning(
|
||||
"Error getting face crops for faceIDs: ${faces.map((face) => face.faceID).toList()}",
|
||||
e,
|
||||
s,
|
||||
);
|
||||
} else {
|
||||
_logger.info(
|
||||
_logger.severe(
|
||||
"Stopped getting face crops for faceIDs: ${faces.map((face) => face.faceID).toList()} due to $e",
|
||||
);
|
||||
}
|
||||
@@ -334,12 +334,14 @@ Future<Map<String, Uint8List>?> _getFaceCrops(
|
||||
if (useFullFile && file.fileType != FileType.video) {
|
||||
final File? ioFile = await getFile(file);
|
||||
if (ioFile == null) {
|
||||
_logger.severe("Failed to get file for face crop generation");
|
||||
return null;
|
||||
}
|
||||
imagePath = ioFile.path;
|
||||
} else {
|
||||
final thumbnail = await getThumbnailForUploadedFile(file);
|
||||
if (thumbnail == null) {
|
||||
_logger.severe("Failed to get thumbnail for face crop generation");
|
||||
return null;
|
||||
}
|
||||
imagePath = thumbnail.path;
|
||||
|
||||
@@ -7,9 +7,10 @@ import "package:flutter/services.dart";
|
||||
import "package:logging/logging.dart";
|
||||
import "package:photos/core/error-reporting/isolate_logging.dart";
|
||||
import "package:photos/models/base/id.dart";
|
||||
import "package:photos/services/isolate_functions.dart";
|
||||
import "package:photos/utils/isolate/isolate_operations.dart";
|
||||
import "package:synchronized/synchronized.dart";
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
abstract class SuperIsolate {
|
||||
Logger get logger;
|
||||
|
||||
@@ -80,6 +81,8 @@ abstract class SuperIsolate {
|
||||
if (rootToken != null) {
|
||||
BackgroundIsolateBinaryMessenger.ensureInitialized(rootToken);
|
||||
}
|
||||
final logger = Logger('SuperIsolate');
|
||||
logger.info('IsolateMain started');
|
||||
|
||||
receivePort.listen((message) async {
|
||||
final taskID = message[0] as String;
|
||||
@@ -87,6 +90,7 @@ abstract class SuperIsolate {
|
||||
final function = IsolateOperation.values[functionIndex];
|
||||
final args = message[2] as Map<String, dynamic>;
|
||||
final sendPort = message[3] as SendPort;
|
||||
logger.info("Starting isolate operation $function in isolate");
|
||||
|
||||
late final Object data;
|
||||
try {
|
||||
@@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
|
||||
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "72.0.0"
|
||||
version: "76.0.0"
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -21,7 +21,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: dart
|
||||
source: sdk
|
||||
version: "0.3.2"
|
||||
version: "0.3.3"
|
||||
adaptive_theme:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -34,10 +34,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
|
||||
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.7.0"
|
||||
version: "6.11.0"
|
||||
android_intent_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -130,10 +130,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
version: "2.12.0"
|
||||
battery_info:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -155,10 +155,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
version: "2.1.2"
|
||||
brotli:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -268,10 +268,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -301,10 +301,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.1.2"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -317,10 +317,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
version: "1.19.1"
|
||||
computer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -619,10 +619,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
version: "1.3.2"
|
||||
fast_base58:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -668,10 +668,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||
sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
version: "7.0.1"
|
||||
file_saver:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1416,18 +1416,18 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
|
||||
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.5"
|
||||
version: "10.0.8"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
|
||||
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.5"
|
||||
version: "3.0.9"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1536,10 +1536,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: macros
|
||||
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
|
||||
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.2-main.4"
|
||||
version: "0.1.3-main.0"
|
||||
maps_launcher:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -1552,10 +1552,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
version: "0.12.17"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1645,10 +1645,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.15.0"
|
||||
version: "1.16.0"
|
||||
mgrs_dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -1859,10 +1859,10 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
version: "1.9.1"
|
||||
path_drawing:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2019,10 +2019,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.5"
|
||||
version: "3.1.6"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2068,10 +2068,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
|
||||
sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.2"
|
||||
version: "5.0.3"
|
||||
proj4dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2309,7 +2309,7 @@ packages:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
version: "0.0.0"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2346,10 +2346,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
version: "1.10.1"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2434,10 +2434,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
version: "1.12.1"
|
||||
step_progress_indicator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2450,10 +2450,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
version: "2.1.4"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2466,10 +2466,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.4.1"
|
||||
styled_text:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2522,34 +2522,34 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
version: "1.2.2"
|
||||
test:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: test
|
||||
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
|
||||
sha256: "301b213cd241ca982e9ba50266bd3f5bd1ea33f1455554c5abb85d1be0e2d87e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.25.7"
|
||||
version: "1.25.15"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
|
||||
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
version: "0.7.4"
|
||||
test_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_core
|
||||
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
|
||||
sha256: "84d17c3486c8dfdbe5e12a50c8ae176d15e2a771b96909a9442b40173649ccaa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.4"
|
||||
version: "0.6.8"
|
||||
thermal:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -2813,10 +2813,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "14.2.5"
|
||||
version: "14.3.1"
|
||||
volume_controller:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2877,10 +2877,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: webdriver
|
||||
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
|
||||
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.3"
|
||||
version: "3.0.4"
|
||||
webkit_inspection_protocol:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -2978,5 +2978,5 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
sdks:
|
||||
dart: ">=3.5.0 <4.0.0"
|
||||
dart: ">=3.7.0-0 <4.0.0"
|
||||
flutter: ">=3.24.0"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE trash RESET (
|
||||
autovacuum_analyze_scale_factor,
|
||||
autovacuum_vacuum_scale_factor,
|
||||
autovacuum_analyze_threshold,
|
||||
autovacuum_vacuum_threshold
|
||||
);
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE trash SET (
|
||||
autovacuum_analyze_scale_factor = 0.01, -- Trigger ANALYZE after 1% of rows change
|
||||
autovacuum_vacuum_scale_factor = 0.02, -- Trigger VACUUM after 2% of rows change
|
||||
autovacuum_analyze_threshold = 1000,
|
||||
autovacuum_vacuum_threshold = 1000
|
||||
);
|
||||
3
server/migrations/103_single_file_url.down.sql
Normal file
3
server/migrations/103_single_file_url.down.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
DROP TABLE IF EXISTS public_file_tokens_access_history;
|
||||
DROP TABLE IF EXISTS public_file_tokens;
|
||||
46
server/migrations/103_single_file_url.up.sql
Normal file
46
server/migrations/103_single_file_url.up.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public_file_tokens
|
||||
(
|
||||
id text primary key,
|
||||
file_id bigint NOT NULL,
|
||||
owner_id bigint NOT NULL,
|
||||
app text NOT NULL,
|
||||
access_token text not null,
|
||||
valid_till bigint not null DEFAULT 0,
|
||||
device_limit int not null DEFAULT 0,
|
||||
is_disabled bool not null DEFAULT FALSE,
|
||||
enable_download bool not null DEFAULT TRUE,
|
||||
pw_hash TEXT,
|
||||
pw_nonce TEXT,
|
||||
mem_limit BIGINT,
|
||||
ops_limit BIGINT,
|
||||
created_at bigint NOT NULL DEFAULT now_utc_micro_seconds(),
|
||||
updated_at bigint NOT NULL DEFAULT now_utc_micro_seconds()
|
||||
);
|
||||
|
||||
|
||||
CREATE OR REPLACE TRIGGER update_public_file_tokens_updated_at
|
||||
BEFORE UPDATE
|
||||
ON public_file_tokens
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE
|
||||
trigger_updated_at_microseconds_column();
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS public_file_tokens_access_history
|
||||
(
|
||||
id text NOT NULL,
|
||||
ip text not null,
|
||||
user_agent text not null,
|
||||
created_at bigint NOT NULL DEFAULT now_utc_micro_seconds(),
|
||||
CONSTRAINT unique_access_id_ip_ua UNIQUE (id, ip, user_agent),
|
||||
CONSTRAINT fk_public_file_history_token_id
|
||||
FOREIGN KEY (id)
|
||||
REFERENCES public_file_tokens (id)
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS public_file_token_unique_idx ON public_file_tokens (access_token) WHERE is_disabled = FALSE;
|
||||
CREATE INDEX IF NOT EXISTS public_file_tokens_owner_id_updated_at_idx ON public_file_tokens (owner_id, updated_at);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS public_active_file_link_unique_idx ON public_file_tokens (file_id, is_disabled) WHERE is_disabled = FALSE;
|
||||
@@ -404,10 +404,7 @@ const Footer: React.FC = () => {
|
||||
return (
|
||||
<Stack sx={{ my: "4rem", gap: 2, alignItems: "center" }}>
|
||||
<Typography>{t("auth_download_mobile_app")}</Typography>
|
||||
<a
|
||||
href="https://github.com/ente-io/ente/tree/main/auth#-download"
|
||||
download
|
||||
>
|
||||
<a href="https://ente.io/auth/#download-auth" download>
|
||||
<Button color="accent">{t("download")}</Button>
|
||||
</a>
|
||||
</Stack>
|
||||
|
||||
Reference in New Issue
Block a user