Compare commits

..

1176 Commits

Author SHA1 Message Date
Vishnu Mohandas
0717d12d65 [docs] Update general.md 2025-06-05 15:30:39 +05:30
Manav Rathi
5ab0299751 [web] Crypto API cleanup (non functional) (#6173) 2025-06-05 11:28:52 +05:30
Neeraj
f1097a93f7 [mob] Fix: Handle already linked email err (#6172)
## Description
While linking contact to a person, we were not gracefully handling the
error where email id is already mapped to another person. And when such
person doesn't have any face attached, they don't have any way to unlink
the email from that person entity.
## Tests
2025-06-05 11:26:56 +05:30
Manav Rathi
7bce2e358b Conv 2025-06-05 11:18:23 +05:30
Manav Rathi
75b3d2354f Simplify 2025-06-05 11:14:31 +05:30
Manav Rathi
52ee86af18 Proxy 2025-06-05 11:06:52 +05:30
Manav Rathi
462aae8f34 Fwd 2025-06-05 11:01:40 +05:30
Manav Rathi
e864ea367a Rename 2025-06-05 10:30:08 +05:30
Neeraj Gupta
45cf130375 Perf: remove redundant async 2025-06-05 10:24:23 +05:30
Manav Rathi
e6fd962c75 Del 2025-06-05 10:23:02 +05:30
Manav Rathi
f5aefb445d Conv 2025-06-05 10:22:18 +05:30
Neeraj Gupta
917ce21b35 Fix: Handle already linked email err 2025-06-05 10:19:07 +05:30
Manav Rathi
0241e41f0d Tweak 2025-06-05 10:13:44 +05:30
Manav Rathi
65982b6f82 Del 2025-06-05 09:58:16 +05:30
Manav Rathi
69756d5733 Conv 2025-06-05 09:56:11 +05:30
Manav Rathi
594671d96c Conv 2025-06-05 09:44:22 +05:30
Manav Rathi
fa1719e3ca Conv 2025-06-05 09:43:10 +05:30
Manav Rathi
6ba7841632 Conv 2025-06-05 09:39:57 +05:30
Manav Rathi
37b52b5cb5 Reduce API surface 2025-06-05 09:28:28 +05:30
Manav Rathi
2e98d8b652 Ret 3 2025-06-05 09:17:22 +05:30
Manav Rathi
ea4d6c5cf1 consistent 2025-06-05 09:15:30 +05:30
Manav Rathi
413f5479ef ret 2 2025-06-05 09:14:13 +05:30
Manav Rathi
92b3da1198 return type consistency 1 2025-06-05 08:53:16 +05:30
Neeraj
88b95da04f [mob] widget customizations (+ new widgets) (#5882) 2025-06-04 20:57:22 +05:30
Manav Rathi
32707e2909 [desktop] macOS folder watch EMFILE workaround (#6170) 2025-06-04 20:18:41 +05:30
Manav Rathi
e28ee8ca66 [desktop] macOS folder watch EMFILE workaround 2025-06-04 20:15:19 +05:30
Manav Rathi
751d107518 [web] One less nit (#6169) 2025-06-04 20:09:50 +05:30
Manav Rathi
439dfcab58 One less nit 2025-06-04 19:36:17 +05:30
Manav Rathi
3f9f0d6d10 [web] General code improvements (#6168) 2025-06-04 19:15:25 +05:30
Manav Rathi
506b915f65 conv 2025-06-04 19:02:55 +05:30
Manav Rathi
65a8923799 Conv 2025-06-04 18:53:14 +05:30
Manav Rathi
e6707d9fcb Move 2025-06-04 18:43:05 +05:30
Manav Rathi
3dbc336687 Doc 2025-06-04 18:36:49 +05:30
Manav Rathi
8441aafe81 Inline 2025-06-04 18:26:53 +05:30
Manav Rathi
5d3f431ee0 Doc 2025-06-04 18:25:28 +05:30
Manav Rathi
ce591e6267 Conv 2025-06-04 18:11:28 +05:30
Prateek Sunal
132a7862fe fix: clear directory on log out 2025-06-04 17:50:21 +05:30
Prateek Sunal
f4167be4b4 fix: update people changed debouncer to 1500 2025-06-04 17:42:46 +05:30
Prateek Sunal
4e17a861dc fix: separate asset resources 2025-06-04 17:41:22 +05:30
Manav Rathi
86f282bb06 Scope 2025-06-04 17:36:50 +05:30
Manav Rathi
334a996357 Scope 2025-06-04 17:27:46 +05:30
Manav Rathi
9a5bac774e Unused 2025-06-04 17:24:08 +05:30
Manav Rathi
04ae02c130 [meta] Issue template (#6166) 2025-06-04 17:13:41 +05:30
Manav Rathi
31232390e8 [meta] Issue template 2025-06-04 17:07:03 +05:30
Prateek Sunal
7d4ea8092a chore: readd thermal 2025-06-04 16:49:46 +05:30
Manav Rathi
e80f91ca92 [web] General refactoring (#6164) 2025-06-04 16:42:28 +05:30
Manav Rathi
523d1961b7 other dep 2025-06-04 16:32:08 +05:30
Manav Rathi
6091a0d446 Lockfile updates 2025-06-04 16:28:33 +05:30
Manav Rathi
12d84d0dbe Avoid exceptions for flow control 2025-06-04 16:27:24 +05:30
Manav Rathi
a244140348 tweak 2025-06-04 16:27:24 +05:30
Manav Rathi
2715bd81b0 vis 2025-06-04 16:27:24 +05:30
Manav Rathi
d65424cef2 Document and move 2025-06-04 16:27:24 +05:30
Manav Rathi
a07d39512b Prune ids 2025-06-04 16:27:24 +05:30
Manav Rathi
223ed36d61 Conv 2025-06-04 16:27:24 +05:30
Neeraj
3e893a7b39 [mob] Use file stream to improve hashing speed (#6163)
## Description

## Tests
For 3.38 GB file on iPhone 11
Old Hashing took 24792 ms
Hashing v2 took 10365 ms

Also tested it on a smaller file

```dart
// Returns the hash for a given file, chunking it in batches of hashChunkSize
Future<Uint8List> cryptoGenericHash(Map<String, dynamic> args) async {
  final int startTime = DateTime.now().millisecondsSinceEpoch;
  final sourceFile = File(args["sourceFilePath"]);
  final sourceFileLength = await sourceFile.length();
  final inputFile = sourceFile.openSync(mode: FileMode.read);
  final state =
      Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
  var bytesRead = 0;
  bool isDone = false;
  while (!isDone) {
    var chunkSize = hashChunkSize;
    if (bytesRead + chunkSize >= sourceFileLength) {
      chunkSize = sourceFileLength - bytesRead;
      isDone = true;
    }
    final buffer = await inputFile.read(chunkSize);
    bytesRead += chunkSize;
    Sodium.cryptoGenerichashUpdate(state, buffer);
  }
  await inputFile.close();
  final hash =
      Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax);

  final int endTime = DateTime.now().millisecondsSinceEpoch;
  final hash2 = await cryptoGenericHashV2(args);
  final endTime2 = DateTime.now().millisecondsSinceEpoch;
  if (hash.length != hash2.length) {
    throw Exception(
      "Hash length mismatch: ${hash.length} != ${hash2.length}",
    );
  }
  if (!const ListEquality().equals(hash, hash2)) {
    throw Exception("not equal: hash");
  }
  print("Hashing took ${endTime2 - startTime} ms");
  print("Hashing v2 took ${endTime2 - endTime} ms");
  return hash;
}

Future<Uint8List> cryptoGenericHashV2(Map<String, dynamic> args) async {
  final file = File(args["sourceFilePath"]);
  final state =
      Sodium.cryptoGenerichashInit(null, Sodium.cryptoGenerichashBytesMax);
  await for (final chunk in file.openRead()) {
    Sodium.cryptoGenerichashUpdate(state, Uint8List.fromList(chunk));
  }
  return Sodium.cryptoGenerichashFinal(state, Sodium.cryptoGenerichashBytesMax);
}
```
2025-06-04 14:33:47 +05:30
Neeraj
eea70db1fd Avoid redundant copy
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-04 14:31:51 +05:30
Neeraj Gupta
85c14b884b [mob] Use file stream to improve hashing speed 2025-06-04 13:43:01 +05:30
Prateek Sunal
884b3716ba fix: add debouncer 2025-06-04 12:52:48 +05:30
Prateek Sunal
6f3ee24ac1 chore: update lock files 2025-06-04 12:46:27 +05:30
Prateek Sunal
292ed5fd6d Merge remote-tracking branch 'origin/main' into widget-superpowered 2025-06-04 12:45:21 +05:30
Prateek Sunal
54d2040f2b fix: remove .fvm 2025-06-04 12:43:35 +05:30
Neeraj
15954ce396 [mob] Remember last scroll offset while adding assets from device (#6159)
## Description
Also increased the items in grid, as there's no scrollbar (pkg does not
support it yet afaik)

## Tests
2025-06-04 12:24:32 +05:30
Laurens Priem
86a9e5ec86 [mob][photos] Compute controller (#6158)
## Description

Refactored MLController (now ComputeController) so that ML and Streaming
both first have to ask for its permission to run.

## Tests
2025-06-04 12:02:57 +05:30
Manav Rathi
52c9a15c2c [web] Migrate to zod v4 (#6162) 2025-06-04 11:58:00 +05:30
Manav Rathi
3c514476c2 Reintroduce with new zod 2025-06-04 11:53:49 +05:30
laurenspriem
31b26a1b26 Reduce logs 2025-06-04 11:52:33 +05:30
Manav Rathi
5e26a895d3 passthrough => looseObject
https://zod.dev/v4/changelog?id=deprecates-strict-and-passthrough
2025-06-04 11:45:12 +05:30
Manav Rathi
4b4d9d0fd8 Migrate
https://zod.dev/v4/changelog
2025-06-04 11:45:12 +05:30
laurenspriem
a4f49b8e84 Try trigger streaming when ML is done 2025-06-04 11:11:21 +05:30
Neeraj
1722277141 [mobile] New translations (#6125)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-06-04 11:02:00 +05:30
Manav Rathi
6a6547a984 Up 2025-06-04 11:01:41 +05:30
Manav Rathi
4c78d1ab78 [web] Convert more cases of deprecated single input form (#6160) 2025-06-04 10:58:03 +05:30
Neeraj
8cd87b964a [photos][mob] Trim whitespace from search query (#6153)
## Description

Previously, when searching for e.g. `test ` would not find an album
called `test`. That's because the trailing whitespace is not ignored. On
mobile this can be especially annoying because sometimes auto-completion
automatically inserts whitespace after a word.

This patch trims whitespace of the search query in two places:
* When searching for an album name when moving photos to an album.
* When using the global search.

## Tests
2025-06-04 10:52:40 +05:30
Manav Rathi
68844eb790 Try to retain similar DOM structure as before 2025-06-04 10:52:18 +05:30
Neeraj Gupta
b24b0d340b Remember last scrollOffset while picking asset from device 2025-06-04 10:50:06 +05:30
Neeraj Gupta
47e8ccd5d8 Update asset_picker pkg 2025-06-04 10:49:41 +05:30
Manav Rathi
e0ae9eb911 vis 2025-06-04 10:48:12 +05:30
laurenspriem
c8d53faa5d Don't queue streaming if controller doesn't allow 2025-06-04 10:44:44 +05:30
laurenspriem
b494dc8cad Allow multiple request calls 2025-06-04 10:44:19 +05:30
Manav Rathi
5d3acca7ed Conv 2025-06-04 10:39:40 +05:30
laurenspriem
d6ea8d4ec3 less loging 2025-06-04 10:30:22 +05:30
Manav Rathi
1850aa1aec ref uploader name 2025-06-04 10:15:11 +05:30
laurenspriem
42239fe30d don't stop on force 2025-06-04 10:14:14 +05:30
Neeraj
35f6dc2361 [mob] Switch to exif_reader (#6154) 2025-06-04 10:01:35 +05:30
Manav Rathi
bbfae3731a Swap 2025-06-04 09:21:35 +05:30
Manav Rathi
d99b3e422b Change default to the more frequently needed value 2025-06-04 09:14:52 +05:30
Manav Rathi
5fe497df3b Swap 2025-06-04 09:06:28 +05:30
Manav Rathi
2e5deda9ae [web] Reset cast dialog view on reopen (#6157) 2025-06-04 08:54:05 +05:30
Manav Rathi
c4fc03d933 Reset cast dialog view on reopen 2025-06-04 08:40:40 +05:30
Prateek Sunal
a1c180485d Merge remote-tracking branch 'origin/main' into widget-superpowered 2025-06-04 01:18:56 +05:30
Prateek Sunal
c865e263e5 fix: remove shrink wrap and use casting for GenericSearchResult 2025-06-04 01:06:09 +05:30
Prateek Sunal
4b72acf3c0 chore: add lock files 2025-06-04 01:05:34 +05:30
Manav Rathi
083eb0516a [web] LP and video playback tweaks (#6156) 2025-06-03 21:15:45 +05:30
Manav Rathi
c5f993571e vid tweaks 2025-06-03 21:11:21 +05:30
Manav Rathi
5b698a926e z 2025-06-03 21:05:52 +05:30
Manav Rathi
760cc4b8e0 Take 2 2025-06-03 21:01:01 +05:30
Manav Rathi
5f722f50e6 Reset 2025-06-03 20:29:23 +05:30
Manav Rathi
ddef5a565f 4 2025-06-03 20:06:28 +05:30
laurenspriem
75042010e8 Integrate computeController requests 2025-06-03 19:43:50 +05:30
Manav Rathi
730746781c 3 2025-06-03 19:43:34 +05:30
laurenspriem
eeadc1d0d3 requesting to computeController methods 2025-06-03 19:43:01 +05:30
Manav Rathi
5b7c112c9a 2 2025-06-03 19:39:41 +05:30
Manav Rathi
c0d57c72bf LP tweaks 2025-06-03 19:33:03 +05:30
Manav Rathi
65abbb4126 [web] General improvements to code dealing with keys (#6155)
(Non functional)
2025-06-03 17:28:26 +05:30
Manav Rathi
113b820451 Same name 2025-06-03 16:54:17 +05:30
Neeraj Gupta
c17a8d4c38 Fix fr arb 2025-06-03 16:23:16 +05:30
Neeraj Gupta
0202cd1447 Switch to exif_reader 2025-06-03 16:23:08 +05:30
Manav Rathi
6ce7921a16 Inline 2025-06-03 16:16:08 +05:30
Manav Rathi
2d7689a6da Consolidate and move 2025-06-03 16:03:51 +05:30
Manav Rathi
f0aac696ca Conv 2025-06-03 15:50:43 +05:30
Manav Rathi
7112e96c75 Swap 2025-06-03 15:46:15 +05:30
Manav Rathi
f4ff63ec0a Swap 2025-06-03 15:41:47 +05:30
Manav Rathi
48dc3a6b69 Redirect 2025-06-03 15:38:23 +05:30
Jacques Lucke
1b62dbbb78 also trim in album search 2025-06-03 12:08:00 +02:00
laurenspriem
d9a4ffd8f7 rename to ComputeController 2025-06-03 15:32:47 +05:30
Jacques Lucke
f749e1ee22 trim search query 2025-06-03 11:59:02 +02:00
Manav Rathi
78669a8550 Match mobile and architecture docs
From libsodium source

crypto_secretbox_keygen(unsigned char k[crypto_secretbox_KEYBYTES])
{
    randombytes_buf(k, crypto_secretbox_KEYBYTES);
}

crypto_kdf_keygen(unsigned char k[crypto_kdf_KEYBYTES])
{
    randombytes_buf(k, crypto_kdf_KEYBYTES);
}
2025-06-03 15:20:20 +05:30
laurenspriem
3d5c53b041 Simplify 2025-06-03 15:04:56 +05:30
laurenspriem
e493702c64 Integrate thermal state in check 2025-06-03 14:59:23 +05:30
Manav Rathi
7cdef46385 Update 2025-06-03 14:44:20 +05:30
Manav Rathi
97314b7dc1 conv 2025-06-03 14:15:15 +05:30
Manav Rathi
9d9ed0f01f Refactor API 2025-06-03 14:09:08 +05:30
Manav Rathi
5df1b12ef5 use new api 2025-06-03 14:02:33 +05:30
Manav Rathi
25cadce651 Vars 2025-06-03 13:56:41 +05:30
Manav Rathi
0e0044693c Remove unnecessary roundtrip 2025-06-03 13:56:41 +05:30
Vishnu Mohandas
32bffcb80b [docs] Update deduplicate.md 2025-06-03 13:50:40 +05:30
Manav Rathi
241577739a doc 2025-06-03 13:21:18 +05:30
Manav Rathi
8c99a3e5af Other way 2025-06-03 13:11:54 +05:30
Manav Rathi
c92141b9dc Use 2025-06-03 13:01:52 +05:30
Manav Rathi
54b5100e89 Use 2025-06-03 13:01:52 +05:30
Manav Rathi
d6060e1194 Extract 2025-06-03 13:01:52 +05:30
Vishnu Mohandas
d895e6a0c3 [server] Fix migration index (#6150) 2025-06-03 12:42:54 +05:30
vishnukvmd
55fd87face [server] Fix migration index 2025-06-03 12:42:25 +05:30
Manav Rathi
6e8acbab1a [infra] Forward headers from workers + ditto cast (#6149) 2025-06-03 10:42:51 +05:30
Manav Rathi
9dd8cd3558 up 2025-06-03 10:27:52 +05:30
Manav Rathi
a227e8541d + range for files 2025-06-03 10:12:40 +05:30
Neeraj
f4f6f2906c [photos][mob] Fix: Close input dialog after album creation (#6148)
## Description

There is an annoyingly flashing dialog when creating exiting a newly
created album. The solution is to close the new-album-dialog before
entering the album so that it is not visible anymore when leaving the
album again.

The dialog is closed after the album is created and before routing to
the album. An alternative is to close it directly when tapping on the
Create button, but then the dialog disappears and it might take a while
until the album is opened which feels worse.

Old (note how the dialog is still open when leaving the album):


https://github.com/user-attachments/assets/e57d27af-2339-4ba7-a5d8-be052aede99c

New (note how there is no dialog when leaving the album):


https://github.com/user-attachments/assets/874164a3-9550-4fc3-9144-342b5888dbb7

## Tests

I don't know how to add tests for this.
2025-06-03 09:47:17 +05:30
Prateek Sunal
265bad28b0 fix: people selection logic as well 2025-06-03 09:45:02 +05:30
Prateek Sunal
9ee52b5dee fix: don't depend on FaceFilter for fetching personId 2025-06-03 09:43:06 +05:30
Prateek Sunal
1d7baf9dd6 chore: remove unwanted author copyright 2025-06-03 09:38:38 +05:30
Manav Rathi
a5f266421a Also from cast 2025-06-03 09:35:57 +05:30
Manav Rathi
dbbcd44f5b Fwd headers 2025-06-03 09:26:52 +05:30
Manav Rathi
38798e92a3 [web][desktop] Routine dep updates (#6146)
feat. MUI v7
2025-06-03 09:04:26 +05:30
Manav Rathi
fda4f47cba disabled is not a color
lint errors on ci
2025-06-03 08:52:12 +05:30
Jacques Lucke
d0ddce2803 Avoid flashing dialog when leaving newly created album 2025-06-02 20:16:12 +02:00
Manav Rathi
4bfc495f39 Fix errors on ci
[eslint] /home/runner/work/ente/ente/web/packages/new/photos/components/ImageEditorOverlay.tsx
[eslint]   1313:41  error  This assertion is unnecessary since it does not change the type of the expression  @typescript-eslint/no-unnecessary-type-assertion
[eslint]   1325:39  error  This assertion is unnecessary since it does not change the type of the expression  @typescript-eslint/no-unnecessary-type-assertion
[eslint]   1338:35  error  This assertion is unnecessary since it does not change the type of the expression  @typescript-eslint/no-unnecessary-type-assertion
[eslint]   1350:41  error  This assertion is unnecessary since it does not change the type of the expression  @typescript-eslint/no-unnecessary-type-assertion
2025-06-02 19:58:49 +05:30
Manav Rathi
7cbc80adc6 Stick to non-private imports 2025-06-02 19:49:30 +05:30
Manav Rathi
414265de4a mui update 2025-06-02 19:28:55 +05:30
Manav Rathi
a2c032e77b desktop deps 2025-06-02 19:27:11 +05:30
Manav Rathi
b567dddfc3 routine dep update 2025-06-02 19:26:47 +05:30
Manav Rathi
dea77b5dd0 [web] Fix trash open (#6144) 2025-06-02 19:02:28 +05:30
Manav Rathi
1b8a8a2717 [web] Fix trash open 2025-06-02 18:58:34 +05:30
Keerthana
549cd74537 [docs]: lint and refactor navigation and overview structure (#6132)
## Description
This PR introduces the following changes in the documentation:
- Restructuring of sidebar for intuitive navigation for
overview/introduction. **Note:** The content covered by the section
along with rest of the documentation is still under major revision and
the skeleton of the documentation is being provided for easier access to
end-users.
- Updation of information regarding lack of availability of Bucket CORS
for MinIO community edition that's used by compose clusters by default.
- Linting for documentation for consistency with prettier.
2025-06-02 18:21:13 +05:30
Keerthana
2d6c754c15 [docs][actions] add lint checks for PRs 2025-06-02 18:18:35 +05:30
Keerthana
5fe0e424cd [docs] refactor community and help pages in overview 2025-06-02 18:16:58 +05:30
Neeraj
991bfbb7ef [mob] Enable resumable upload for all (#6141)
## Description

## Tests
2025-06-02 17:48:52 +05:30
Laurens Priem
3292ab2d95 [mob][photos] Face thumbnails refactor (#6128)
## Description

- Refactored PersonFaceWidget into separate FileFaceWidget and
PersonFaceWidget. PersonFaceWidget now only requires a person or cluster
ID, no longer is any file needed
- Face thumbnail choice is now made based on highest face score instead
of recency, meaning less changes in face thumbnails and less re-computes
- More aggressive caching of face thumbnails in memory
- Added option to change person cover from top menu
- Fixed issue with decoding HEIC for face thumbnails on Android

## Tests

Tested in debug mode on my pixel 8.
2025-06-02 16:58:18 +05:30
Neeraj Gupta
8eddf3ff4e Upload videos along with photos 2025-06-02 16:21:15 +05:30
Neeraj Gupta
2dca25778b Enable multipart upload for everyone 2025-06-02 16:18:14 +05:30
Manav Rathi
2316f6323e [web] New translations (#6135)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-06-02 16:05:46 +05:30
Neeraj
d15c11cc26 [server] Defer file data replication for 10min (#6139)
## Description

## Tests
2025-06-02 16:04:48 +05:30
Manav Rathi
f32c712c72 [meta] fr => enhancements (#6137) 2025-06-02 16:04:26 +05:30
Vishnu Mohandas
9060eaa0e5 [server] Update first-upload copy (#6138) 2025-06-02 16:01:02 +05:30
vishnukvmd
3a9d507c35 Update copy 2025-06-02 15:59:33 +05:30
Ashil
ed0c1a1ebc [mob][photos] Fix missing 'Added by' indicator in gallery file element and file info for when opening public links via deeplink (#6136)
## Description

User avatar in gallery file element and 'added by' field in file info
were missing for files in public links opened via deeplink. This PR
fixes this issue.
2025-06-02 15:58:30 +05:30
Manav Rathi
6e1b959a61 [meta] fr => enhancements 2025-06-02 15:57:41 +05:30
ashilkn
95a9baa4e2 Show avatar in gallery file element and 'added by' in file info for public links opened via deeplink 2025-06-02 15:53:05 +05:30
ashilkn
0ccc333dad chore 2025-06-02 15:52:25 +05:30
Crowdin Bot
a5224628b7 New Crowdin translations by GitHub Action 2025-06-02 10:11:04 +00:00
Manav Rathi
4d4d961628 [desktop] Post release toggles (#6134) 2025-06-02 15:40:13 +05:30
Manav Rathi
e22f74d653 bg ml and export 2025-06-02 15:33:31 +05:30
Neeraj Gupta
b4fdf441ec Defer filedata replication for 10min 2025-06-02 15:30:31 +05:30
Vishnu Mohandas
e798ac02c6 [server] Check in with paid customers (#6106)
## Description
Update the `subscriptions` table to store the time at which
subscriptions were upgraded (`upgraded_at`).

Reach out to customers who upgraded 7 days ago to make sure all is well.
<img width="628" alt="Screenshot 2025-05-31 at 1 41 09 PM"
src="https://github.com/user-attachments/assets/7d1e970a-c7fa-4666-8d4f-db13ba7c105d"
/>

Store this information within `notification_history` so they are not
contacted again (in case of admin interventions).

> Note: We will not be back-filling data for existing subscriptions.

## Tests
- [x] Tested locally to make sure only customers who upgraded 7 days ago
were pinged.
2025-06-02 15:25:23 +05:30
Manav Rathi
6c41f575c3 fav cast 2025-06-02 15:22:23 +05:30
Manav Rathi
15e211b3a5 typo 2025-06-02 15:18:33 +05:30
Manav Rathi
9ce3fe7756 post rel 2025-06-02 15:18:17 +05:30
Manav Rathi
215bb43f39 [web] FS limit test (#6133) 2025-06-02 15:17:47 +05:30
Manav Rathi
793ee58e2b fs limit test 2025-06-02 15:14:39 +05:30
Manav Rathi
a6ae092839 [desktop] Make video upload retries idempotent (#6131) 2025-06-02 14:33:33 +05:30
Keerthana
088afe7f2a [fix]: dead links in overview 2025-06-02 14:32:53 +05:30
Manav Rathi
d212d55dca Make retries idempotent 2025-06-02 14:12:37 +05:30
Manav Rathi
bc88a378b0 Note 2025-06-02 14:00:07 +05:30
Keerthana
b0bb5fc916 [docs]: lint and refactor navigation and structure for overview 2025-06-02 13:58:49 +05:30
Neeraj
b3b3f8445a [auth] New translations (#6126) 2025-06-02 12:28:10 +05:30
laurenspriem
9d87b8f303 Rename to clarify Android 2025-06-02 11:43:21 +05:30
Alexander
15e7d9658c [auth] Add new custom icons in auth (#6114)
New icons added:

- CSSBuy
- uollet
2025-06-02 11:38:33 +05:30
Neeraj
fb262c7dc4 [auth] fix: rename GIRAD icon to GERID (#6107)
Made a typo in the previous PR 😅. This PR changes it to the correct name
(GIRAD -> GERID)
2025-06-02 11:37:58 +05:30
Laurens Priem
3080859593 timeout on this day notification android at eod (#6130)
## Description

Auto dismiss 'On this day' notification at the end of the day. Only on
Android since there's no API for this on iOS.

## Tests

Tested in debug mode on my pixel 8 phone.
2025-06-02 11:25:31 +05:30
laurenspriem
9ea70c70d5 timeout on this day notification android at eod 2025-06-02 11:21:01 +05:30
Manav Rathi
a6291f34f9 [web] New translations (#6124)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-06-02 10:25:04 +05:30
Crowdin Bot
40a8449ea5 New Crowdin translations by GitHub Action 2025-06-02 01:17:53 +00:00
Crowdin Bot
765b0982ed New Crowdin translations by GitHub Action 2025-06-02 01:05:16 +00:00
Crowdin Bot
199f4acccc New Crowdin translations by GitHub Action 2025-06-02 00:41:26 +00:00
laurenspriem
026f9a2bb8 Fix heic decoding issue for face thumbnails 2025-06-01 17:58:55 +05:30
Sven
571995bbd9 fix: rename GIRAD icon to GERID 2025-05-31 12:44:54 +02:00
vishnukvmd
a15084374b Setup cron 2025-05-31 13:45:55 +05:30
vishnukvmd
c0ceb68dc6 Say hello to paid customers 2025-05-31 13:45:51 +05:30
vishnukvmd
0b87152057 Hello email 2025-05-31 13:45:27 +05:30
vishnukvmd
feb6a82755 Mark upgrades 2025-05-31 13:44:55 +05:30
vishnukvmd
85c418c9f6 Update query 2025-05-31 13:44:32 +05:30
vishnukvmd
cc68189004 Update model 2025-05-31 13:44:25 +05:30
vishnukvmd
21c1328428 Add column to store upgraded-at timestamps 2025-05-31 13:42:13 +05:30
vishnukvmd
1375b4df12 Fix typo 2025-05-31 13:06:52 +05:30
Neeraj
7f0eeece9c [auth] Bump auth version 4.4.0 (#6103)
## Description

## Tests
2025-05-31 10:14:13 +05:30
Neeraj Gupta
7fb30ed477 Add release 4.4.0 to appdata.xml 2025-05-31 10:13:23 +05:30
Neeraj Gupta
91ea5763fb Bump auth version: 4.4.0 2025-05-31 10:13:07 +05:30
Neeraj
f29f9f2a94 [auth] Sign windows binary using trust store (#6102)
## Description

## Tests
2025-05-31 10:12:23 +05:30
Neeraj Gupta
5138898d73 Sign auth windows binary using trust store 2025-05-31 10:11:13 +05:30
Neeraj Gupta
171be22113 Fix typo 2025-05-31 10:08:51 +05:30
Neeraj
6a3575feb4 [auth] Add GIRAD icon (#6100)
Add GIRAD custom icon, as requested here:
https://github.com/ente-io/ente/issues/6075
2025-05-31 09:53:35 +05:30
Neeraj Gupta
4e80c82a6f Revert "Avoid building for testing sign"
This reverts commit 0c0acd9592.
2025-05-31 09:36:56 +05:30
Neeraj Gupta
0c0acd9592 Avoid building for testing sign 2025-05-31 09:34:03 +05:30
Neeraj Gupta
26384513f2 Mention absolute path 2025-05-31 08:45:53 +05:30
Neeraj
acd05e0a55 [meta] Workflow to test windows sign (#6101)
## Description

## Tests
2025-05-31 08:12:55 +05:30
Neeraj Gupta
91a48943b7 Rename worflow 2025-05-31 08:10:58 +05:30
Neeraj Gupta
a8111eab04 Add workflow for testing trust signing 2025-05-31 08:09:37 +05:30
Sven
0084a3cf59 Add GIRAD icon and entry to custom icons list 2025-05-30 19:10:18 +02:00
Manav Rathi
82e1fd3b0a [web] Convert more uses of older single input form (#6099)
Only a handful left to go.
2025-05-30 18:36:51 +05:30
Manav Rathi
d57c68188c Update for new API methods 2025-05-30 18:32:46 +05:30
Manav Rathi
65a7a49d07 Swap 2025-05-30 18:25:52 +05:30
Manav Rathi
631c46681d Nicer animation 2025-05-30 18:12:50 +05:30
Manav Rathi
023d8ab8b3 Format 2025-05-30 18:07:50 +05:30
Manav Rathi
a1e3cdd5d2 Remove inconsistent trim in one direction
- No other password inputs are trimmed
- The code was trimming here, but not when verifying it
2025-05-30 18:00:13 +05:30
laurenspriem
2df9041e34 Set cover sheet in people app bar 2025-05-30 17:55:11 +05:30
Manav Rathi
b1051bbd47 Swap 2025-05-30 17:51:45 +05:30
laurenspriem
f869483c68 Change icon and reorder 2025-05-30 17:41:40 +05:30
Manav Rathi
8682e3338b Rename 2025-05-30 17:40:51 +05:30
Manav Rathi
ee96b44b74 Use 2025-05-30 17:38:14 +05:30
Manav Rathi
e992db4846 augment 2025-05-30 17:30:30 +05:30
laurenspriem
0d95f8c5a2 Remove redundant 2025-05-30 17:09:10 +05:30
laurenspriem
4b9f6619b5 Rename 2025-05-30 17:02:59 +05:30
laurenspriem
9e30d08fae Don't remove faceAvatar 2025-05-30 17:01:45 +05:30
laurenspriem
2c50b84e30 Better update in memory cache 2025-05-30 16:55:48 +05:30
Neeraj
686d04339d [auth] Fix: handle incorrect device time during code generation (#6096)
## Description

## Tests
2025-05-30 16:50:56 +05:30
Neeraj Gupta
5d0a86c248 Fix progress bar when local time is incorrect 2025-05-31 16:23:06 +05:30
Manav Rathi
2a375e56c3 [web] Update uses of deprecated collection namer (#6098) 2025-05-30 16:43:02 +05:30
laurenspriem
ba468d32f5 Refactor remove redundant method 2025-05-30 16:40:02 +05:30
Manav Rathi
ce3b6b1c1f Remove unnecessary dep 2025-05-30 16:38:26 +05:30
Manav Rathi
52451cd0af Update 2025-05-30 16:35:19 +05:30
Manav Rathi
03a25c2625 Unused 2025-05-30 16:33:51 +05:30
Manav Rathi
f425dc6eaf Use 2025-05-30 16:33:51 +05:30
Manav Rathi
26d111da42 Tweak 2025-05-30 16:33:51 +05:30
Manav Rathi
7b100e8dae Use 2025-05-30 16:33:51 +05:30
Manav Rathi
b5d059c61b Use 2025-05-30 16:33:51 +05:30
Manav Rathi
70c3c1d541 [web] New translations (#6097)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-30 16:33:11 +05:30
Crowdin Bot
01b05d243d New Crowdin translations by GitHub Action 2025-05-30 10:59:57 +00:00
Neeraj Gupta
b560e5b71a Fix: handle incorrect device time during code generation 2025-05-30 16:24:43 +05:30
laurenspriem
3354416543 Query typo 2025-05-30 16:15:03 +05:30
laurenspriem
cfeca1f564 Integrate new PersonFaceWidget everywhere 2025-05-30 15:52:06 +05:30
Manav Rathi
625b562229 [web] [auth] Automatic handling of browsers with incorrect time (#6093) 2025-05-30 15:16:24 +05:30
Manav Rathi
c8d31b3a7e Mention version 2025-05-30 15:12:48 +05:30
laurenspriem
3f212aa1d1 Refactor face thumbnail caching logic 2025-05-30 14:43:59 +05:30
Neeraj
026669b0d0 [Server] Return epochTime in microSeconds (#6094)
## Description

## Tests
2025-05-30 14:21:55 +05:30
Neeraj Gupta
741aed7565 return utc epochTime in auth diff 2025-05-30 14:19:33 +05:30
Neeraj
6ee58b8e0f [mob] Video stream generation refactor (#6085)
## Description

- Avoid checking stream generation for file is duration or size
information is not available. Size information is almost always present,
and duration was missing for files uploaded via Desktop/Web until
recently. As anyways we are processing local only files, it made sense
to simplify the check and completely avoid processing such files.

**Previously, for such files where duration was missing, if my
understanding is correct, we were always downloading it to getProps
info, even for files larger than 500 MB.**

- Pause video streaming generation if ML is running
- Added delay before queuing files for video streaming immediately after
diff sync.
## Tests
2025-05-30 13:48:08 +05:30
Neeraj Gupta
61df740c01 Limit preview cache for preview with size < 50MB 2025-05-30 13:30:43 +05:30
Neeraj Gupta
3b3b41d55f Remove unused imports 2025-05-30 13:26:55 +05:30
Neeraj
0633582c7e [mob][photos] Update contacts section on PeopleChangedEvent (#6088) 2025-05-30 12:52:17 +05:30
Manav Rathi
1acd1f81f4 Use 2025-05-30 12:49:17 +05:30
Manav Rathi
2b35677227 faq 2025-05-30 12:34:33 +05:30
Manav Rathi
2b390b60c4 Handle browsers with incorrect time 2025-05-30 12:27:17 +05:30
Manav Rathi
a33af20944 [web] MUI - Don't override non-elevated backgrounds (#6092) 2025-05-30 11:10:56 +05:30
Manav Rathi
e8643c662e Alert 2025-05-30 11:04:57 +05:30
Ashil
aea57dd212 [mob][photos] Add uncategorized album in album vertical sheet (#6086)
## Description

- Show Uncategorized album on collection actions (except for collection
actions over hidden items)
- Show Uncategorized album on top

Closes #5833 


![simulator_screenshot_07BA6109-B6FA-45BF-9E75-43205697D0A7](https://github.com/user-attachments/assets/c0dc834b-c676-4cde-9006-1c77216141d0)
2025-05-30 11:04:32 +05:30
Manav Rathi
fe33469a79 Don't override non-elevated backgrounds
In particular, don't apply our shadow to variant "outlined"
2025-05-30 10:46:22 +05:30
Manav Rathi
d660f71f56 Update 2025-05-30 07:49:57 +05:30
Manav Rathi
61eb7c0e99 Swap 2025-05-30 07:49:57 +05:30
ashilkn
e438e35ccd Update contacts section on PeopleChangedEvent 2025-05-29 18:29:08 +05:30
Manav Rathi
d01348414c [desktop] Next release train (#6087) 2025-05-29 16:52:49 +05:30
Manav Rathi
2faa616cab [desktop] Next release train 2025-05-29 16:49:33 +05:30
ashilkn
78bad4e5a5 Show uncategorized album option for all CollectionActionTypes other than for hidden collection actions 2025-05-29 16:42:57 +05:30
ashilkn
466bb40a30 Show uncategorized album as the first option in collection action sheet 2025-05-29 16:34:00 +05:30
Neeraj Gupta
e55dcff9a5 Add delay before queuing files for streaming 2025-05-29 16:22:39 +05:30
Neeraj Gupta
8904916770 Pause streaming if ML is running 2025-05-29 16:22:26 +05:30
Manav Rathi
f3d19155a0 photosd-v1.7.13 (#6084) 2025-05-29 16:20:04 +05:30
Manav Rathi
75440e7c05 photosd-v1.7.13 2025-05-29 16:18:53 +05:30
Neeraj Gupta
7a7a50901f Rename 2025-05-29 16:17:44 +05:30
Neeraj Gupta
09ff43a1ef Simplify check for checking preview req 2025-05-29 16:07:53 +05:30
Neeraj Gupta
7cf4c7bf74 Avoid duplicate preview creation check 2025-05-29 15:35:40 +05:30
ashilkn
a3341202a7 Remove unused CollectionActionType 2025-05-29 15:33:07 +05:30
Neeraj Gupta
c87b2b7542 Only process files with known duration & size 2025-05-29 15:32:00 +05:30
Manav Rathi
2665d98681 [web] Tweak info panel titlebar (#6082)
Fixes https://github.com/ente-io/ente/issues/6081
2025-05-29 15:21:34 +05:30
Manav Rathi
8dd6e7d8ed Fix 6081 2025-05-29 15:17:13 +05:30
Neeraj Gupta
594c18db79 Use service locator 2025-05-29 14:56:33 +05:30
Vishnu Mohandas
320376e98d [docs] Update video-streaming.md 2025-05-29 14:28:17 +05:30
Manav Rathi
dbca5222e5 [desktop] Pre-release touchups (#6080) 2025-05-29 13:06:04 +05:30
Manav Rathi
d06c9174ac Use same constants for both 2025-05-29 13:00:31 +05:30
Manav Rathi
962fa33b04 +fav 2025-05-29 12:56:08 +05:30
Manav Rathi
c163c8ae71 [web] New translations (#6079)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-29 12:55:50 +05:30
Crowdin Bot
29720b350c New Crowdin translations by GitHub Action 2025-05-29 07:15:52 +00:00
Manav Rathi
b70cfe1309 [web] Split interactive and background requests (#6078) 2025-05-29 12:45:03 +05:30
Manav Rathi
cc5b2697d9 Use for HLS gen 2025-05-29 12:25:42 +05:30
Manav Rathi
1a49770e0b Outline 2025-05-29 11:38:58 +05:30
Neeraj
98137e87ab [mob] Fix: Treat sandbox file as unique file during upload (#6024) 2025-05-29 11:38:52 +05:30
Neeraj Gupta
fa0c70d633 Avoid mixing upload with preview generation to save cpu 2025-05-29 09:32:15 +05:30
Neeraj Gupta
909695ffaa Mark previewIDs as not nullable 2025-05-29 09:28:51 +05:30
Neeraj Gupta
b679d0213f Use hashMap to dedupe for uploadID 2025-05-29 09:19:19 +05:30
Neeraj Gupta
995342bbdb Clean up unused event 2025-05-29 09:05:45 +05:30
Manav Rathi
0786a355ca [desktop] Update Electron (#6077) 2025-05-29 07:46:48 +05:30
Manav Rathi
9683888d82 [web] General refactoring (#6076) 2025-05-29 07:38:13 +05:30
Manav Rathi
3ecaf9a0dc [desktop] Update Electron 2025-05-29 07:35:01 +05:30
Manav Rathi
c985fe9882 pk 2025-05-28 19:56:27 +05:30
Manav Rathi
9b5dcc9a95 custom error 2025-05-28 19:34:42 +05:30
Manav Rathi
17d6860faa optional 2025-05-28 19:21:18 +05:30
Manav Rathi
63a3edd053 [web] Convert deprecated titlebar uses (#6074) 2025-05-28 17:32:15 +05:30
Manav Rathi
2764256a02 Conv 2025-05-28 17:23:58 +05:30
Manav Rathi
bcc0403eb6 Last one 2025-05-28 17:19:55 +05:30
laurenspriem
ebfc1103fe Rename to fileFaceWidget 2025-05-28 17:02:31 +05:30
laurenspriem
db07fb35d2 face widget cropping functionality 2025-05-28 17:01:08 +05:30
Manav Rathi
da0d9dfdab Tweak visually 2025-05-28 16:23:51 +05:30
Manav Rathi
5171518d9b Replace 2025-05-28 16:14:59 +05:30
Manav Rathi
27d0c8a838 Pattern 2025-05-28 16:09:09 +05:30
Manav Rathi
76d7f039ea Swap 2025-05-28 16:05:31 +05:30
laurenspriem
7519ed5e15 Use new face widget in file info 2025-05-28 15:51:31 +05:30
Manav Rathi
1afc2e31bf Inline 2025-05-28 15:51:07 +05:30
Manav Rathi
d5a75707f3 Update 2025-05-28 15:47:57 +05:30
Manav Rathi
923a2a60fe re 2025-05-28 15:37:44 +05:30
Manav Rathi
d47c96aa3f Use 2025-05-28 15:22:23 +05:30
Manav Rathi
13ed68c79e Use right 2025-05-28 15:20:12 +05:30
Manav Rathi
79f5d6763c Use 2025-05-28 15:15:33 +05:30
Manav Rathi
68aaedc2d9 abstraction 2025-05-28 14:59:39 +05:30
laurenspriem
97a174ff75 Merge branch 'main' into face_thumbnails 2025-05-28 14:42:00 +05:30
Manav Rathi
2455d34553 Simplify 2025-05-28 14:34:46 +05:30
Neeraj
f045dc8e04 [server] Update limit (#6073)
## Description

## Tests
2025-05-28 14:13:30 +05:30
Neeraj Gupta
7986563443 Update limit 2025-05-28 14:00:43 +05:30
Neeraj
114dfb1f41 [server] Prefer second hot bucket for export (#6071)
## Description

## Tests
2025-05-28 13:15:40 +05:30
Manav Rathi
7ef65568d0 [web] General refactoring (#6072) 2025-05-28 13:15:12 +05:30
Manav Rathi
5a241a8153 Handle error from new fetch stack 2025-05-28 12:54:08 +05:30
Manav Rathi
cbc7c936f7 Inline 2025-05-28 12:46:39 +05:30
Neeraj Gupta
e14510f46e Remove log 2025-05-28 12:46:05 +05:30
Neeraj
f5478c7396 [mobile] New translations (#6034)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-28 12:45:21 +05:30
Neeraj Gupta
ea1319b13b Prefer second hot bucket for export 2025-05-28 12:44:38 +05:30
Manav Rathi
b45e270475 Unused 2025-05-28 12:31:38 +05:30
Manav Rathi
cdd82707f7 Conv 2025-05-28 12:03:17 +05:30
Manav Rathi
db33e61af9 Conv 2025-05-28 11:58:46 +05:30
Manav Rathi
36dda95b41 fv 2025-05-28 11:53:45 +05:30
Manav Rathi
61b15ba3ef Simplify 2025-05-28 11:48:05 +05:30
Manav Rathi
0690a32d59 Simplify 2025-05-28 11:42:56 +05:30
Neeraj
463ce4964b [mob] Enable resumable download for internal users (#6022)
## Description
- Enabled for internal users
- Download happens in chunk of 40MB, if individual chunk download fails,
we download that chunk from scratch (we can optimise it resume even the
chunk download, but i felt it would add redundant complexity.
- Download pauses automatically when user moves to next video/image (The
exact behaviour is yet to be decided, may be it should continue download
if on unmetered connection or always download with option to pause the
download on UI)

## Tests
Tested on simulator
2025-05-28 11:36:45 +05:30
Neeraj Gupta
ed05269a42 Merge remote-tracking branch 'origin/main' into resumableDownload 2025-05-28 11:32:04 +05:30
laurenspriem
903366a42c Refactor to simplify 2025-05-28 11:22:21 +05:30
Manav Rathi
d537b8f00b Props 2025-05-28 10:47:53 +05:30
Manav Rathi
84912c1a0e Fix missing negation
and simplify usage
2025-05-28 10:47:53 +05:30
Manav Rathi
15f427ef37 This was a no-op for disabled buttons 2025-05-28 10:47:53 +05:30
Neeraj
89837b79e8 [server] Fix: Typo in bucket name for filedata multipart url (#6070)
## Description

## Tests
2025-05-28 10:38:51 +05:30
Neeraj Gupta
7afb305dbb Fix: Typo in bucket name for filedata multipart url 2025-05-28 10:36:38 +05:30
Manav Rathi
8e6ff3b96c [web] General ref + Uploader name web only until next release (#6068) 2025-05-28 07:19:11 +05:30
Manav Rathi
deb6cfe03a Move 2025-05-28 07:12:56 +05:30
Manav Rathi
dbec318f7b for next release train 2025-05-28 07:03:18 +05:30
Manav Rathi
6f24109669 Conv 2025-05-28 06:29:58 +05:30
Manav Rathi
beda124d3f rf 2025-05-28 06:29:58 +05:30
ashilkn
87fae3e6d9 Resolve merge conflicts and merge main 2025-05-27 19:16:31 +05:30
Ashil
89cd360f93 [mob][photos] Bump up to v1.1.0 (#6065) 2025-05-27 19:15:03 +05:30
ashilkn
f1274afdd4 Bump up to v1.1.0 2025-05-27 19:09:55 +05:30
ashilkn
0a5005d064 Add scrollbar for album widget settings screen 2025-05-27 19:06:16 +05:30
ashilkn
b54fe20520 chore 2025-05-27 18:46:18 +05:30
ashilkn
204a046e0a Merge branch 'main' into widget-superpowered 2025-05-27 18:44:52 +05:30
Ashil
4f21f1e94e [mob][photos] All albums screen UI/UX and performance improvements (#6060)
<img
src="https://github.com/user-attachments/assets/c9ca2050-9e5c-48c5-b01e-7ed89885bc6b"
width="200" height="450" alt="Image 1">
<img
src="https://github.com/user-attachments/assets/39aeda32-9f68-4d2f-b156-7b9312578435"
width="200" height="450" alt="Image 2">

Plus some improvements from @ashilkn
2025-05-27 18:43:40 +05:30
ashilkn
039866cf3b Chore: fix lint warning 2025-05-27 18:42:39 +05:30
ashilkn
c4b860a8fe Use SliverPrototypeExtentList instead of just SliverList for improved (scrolling?) performance 2025-05-27 18:35:56 +05:30
ashilkn
1d1e01898f Add scrollbar to all on ente albums page 2025-05-27 18:19:04 +05:30
ashilkn
53f947b5f0 Update arrow icon size 2025-05-27 18:10:17 +05:30
laurenspriem
015321fa0d Rename widget 2025-05-27 17:51:15 +05:30
Manav Rathi
1e3a112c35 [desktop] Tweak changelog entry (#6064) 2025-05-27 17:51:15 +05:30
Manav Rathi
3dc23092a4 tweak 2025-05-27 17:48:47 +05:30
Manav Rathi
fd65e81079 [desktop] Enable stream generation for non-internal users (#6063) 2025-05-27 17:40:12 +05:30
Manav Rathi
eec0480618 [web] New translations (#6062)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-27 17:35:48 +05:30
Manav Rathi
fac5ab5079 [desktop] Enable stream generation for non-internal users 2025-05-27 17:34:13 +05:30
Ashil
051ce42ae6 [mob][photos] Home widget improvements (#6059)
## Description

See commits
2025-05-27 17:32:17 +05:30
laurenspriem
3e1a01c1f3 Move person_face_widget 2025-05-27 17:26:14 +05:30
laurenspriem
351cf50f73 Rename for clarity 2025-05-27 17:19:09 +05:30
Crowdin Bot
297d4bdbf5 New Crowdin translations by GitHub Action 2025-05-27 11:39:57 +00:00
Manav Rathi
9f9ad19d4b [web] Show full uploader name (#6061) 2025-05-27 17:09:22 +05:30
ashilkn
4d26de8ffd Add safety check 2025-05-27 17:05:46 +05:30
Manav Rathi
f16846b82e Added by 2025-05-27 16:49:08 +05:30
ashilkn
b44ef9f68a Prevent infinite loops 2025-05-27 16:45:37 +05:30
AmanRajSinghMourya
cf28fddfb3 Fix popup sheet background color 2025-05-27 16:17:42 +05:30
ashilkn
6c3b2ee25e Randomize memories and files shown in memories widget 2025-05-27 15:58:04 +05:30
Manav Rathi
2d8310460b [web] Use path prefix as context when collating metadata and live photos (#6058)
Fixes: 
- https://github.com/ente-io/ente/discussions/5920
- https://github.com/ente-io/ente/discussions/5950
2025-05-27 15:52:44 +05:30
Manav Rathi
0d5363c7a1 Fix typo 2025-05-27 15:48:14 +05:30
Manav Rathi
2f277bbffc lf 2025-05-27 15:38:16 +05:30
Manav Rathi
cbf3340bf2 Handle lp retry 2025-05-27 15:19:16 +05:30
Neeraj Gupta
29f9a64bfb Undo testing change 2025-05-27 15:16:16 +05:30
Manav Rathi
de918f42e6 Retain metadata 2025-05-27 15:05:37 +05:30
Manav Rathi
6bd1547e09 Impl 2025-05-27 15:05:37 +05:30
Manav Rathi
aa70b2a437 spl 2025-05-27 15:05:37 +05:30
Manav Rathi
13b74f387f reuse 2025-05-27 15:05:37 +05:30
Manav Rathi
d52e3894d8 Move 2025-05-27 15:05:37 +05:30
Manav Rathi
780c2c2493 Outline 2025-05-27 15:05:37 +05:30
Manav Rathi
405c4d1258 [web] New translations (#6057)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-27 15:05:15 +05:30
Crowdin Bot
5f498b01ee New Crowdin translations by GitHub Action 2025-05-27 09:33:56 +00:00
Manav Rathi
af5020e62c [web] General refactoring (#6056) 2025-05-27 15:03:10 +05:30
Manav Rathi
7ddf0f6fe1 lf 2025-05-27 14:54:15 +05:30
ashilkn
5fa951ad4b Refactor people widget settings screen 2025-05-27 14:51:23 +05:30
ashilkn
e9ceb705f6 Sort album widget settings screen's albums, showing selected ones on top. Note that sorting doesn't happen when selection is modified on the screen and only once when it's built 2025-05-27 14:38:08 +05:30
ashilkn
9dcd9d63b2 Avoid using shrinkWrap 2025-05-27 13:43:49 +05:30
ashilkn
129e9f8f49 Avoid adding empty albums in _getAlbumsWithFiles() 2025-05-27 12:32:39 +05:30
ashilkn
6f02df19c6 Improve UI of widget's empty state 2025-05-27 12:31:59 +05:30
ashilkn
c8efc1a590 Randomize albums and files shown in album widget 2025-05-27 12:02:07 +05:30
ashilkn
8b1a659d68 Avoid sorting on selecting albums in album widget settings 2025-05-27 11:47:39 +05:30
Manav Rathi
9114fbca27 Update 2025-05-27 10:55:01 +05:30
Manav Rathi
e25d71a7d4 cb 2025-05-27 10:25:18 +05:30
Manav Rathi
1018765f7c [web] General refactoring (#6054) 2025-05-27 10:00:26 +05:30
Manav Rathi
0fb984d031 missing dep 2025-05-27 09:53:16 +05:30
Manav Rathi
4ad3560387 Move 2025-05-27 08:49:00 +05:30
Manav Rathi
482b175324 Move 2025-05-27 08:40:10 +05:30
Manav Rathi
894d7382e8 inline 2025-05-27 08:29:11 +05:30
Manav Rathi
53cc78d3e3 Inline 2025-05-27 08:25:29 +05:30
Manav Rathi
a634500e55 Inline 2025-05-27 08:20:53 +05:30
Manav Rathi
ee8ecd456c [web] General refactoring (#6052) 2025-05-27 08:18:07 +05:30
Manav Rathi
d69a22a73e Fix 2025-05-27 08:08:44 +05:30
Manav Rathi
8b1af42cf0 Conv 2025-05-27 08:04:42 +05:30
Manav Rathi
41e7d0056b Swap 2025-05-27 07:48:30 +05:30
Manav Rathi
d170789446 Update 2025-05-27 07:42:33 +05:30
Manav Rathi
afbbde5f2b Update 2025-05-27 07:31:29 +05:30
Manav Rathi
4e3112a4f6 Conv 2025-05-27 07:25:31 +05:30
Manav Rathi
a4950ece53 Tweak vis 2025-05-27 07:21:36 +05:30
Manav Rathi
1a01d759b0 Fix ellipsis 2025-05-27 07:19:18 +05:30
Manav Rathi
175b51fdb3 Improve visual look 2025-05-27 07:01:18 +05:30
Manav Rathi
a4ba2edc54 Update 2025-05-27 06:31:44 +05:30
Manav Rathi
1a8a26e9e4 Update 2025-05-27 05:49:27 +05:30
Laurens Priem
a2ddcfd34f [mob][photos] Minor ML improvements (#6043)
## Description

- Expose flag for when ML and Memories is running
- UI fix for deleting all files in cluster 
- Log times ML models are loaded

## Tests

Tested in debug mode on my pixel 8.
2025-05-26 21:44:33 +05:30
Manav Rathi
95700f52f6 [web] General refactoring (#6047) 2025-05-26 20:15:45 +05:30
Manav Rathi
fc16638bfe Redo 2025-05-26 19:47:16 +05:30
Manav Rathi
5d375eb837 Move 2025-05-26 19:42:24 +05:30
Ashil
fe86d3bb34 [mob][photos] Make widget settings pages less confusing on their empty states (#6046) 2025-05-26 19:37:53 +05:30
Manav Rathi
77956d0f67 Rename 2025-05-26 19:37:04 +05:30
ashilkn
53a22a8d58 chore 2025-05-26 19:32:21 +05:30
ashilkn
a5b178d283 Extract strings 2025-05-26 19:30:54 +05:30
Manav Rathi
e651c1e328 inline 3 2025-05-26 19:24:36 +05:30
ashilkn
9069975bf0 Avoid confusion on empty widget settings pages 2025-05-26 19:22:51 +05:30
Manav Rathi
5938e755ae wip 2 2025-05-26 18:38:18 +05:30
Manav Rathi
6f7b3738b3 inline wip 1 2025-05-26 18:32:24 +05:30
Manav Rathi
4ee9f45b3a Inline 2025-05-26 18:15:45 +05:30
Manav Rathi
c835a3d009 Tweak 2025-05-26 18:11:06 +05:30
Manav Rathi
6d3e55a6d9 Inline 2025-05-26 18:08:11 +05:30
Ashil
08b7986d70 [mob][photos] Randomize people and file shown in people widget (#6044) 2025-05-26 18:06:17 +05:30
Manav Rathi
067c8b2a76 Tweak 2025-05-26 18:03:47 +05:30
Manav Rathi
d355d18acb Inline 2025-05-26 17:57:19 +05:30
ashilkn
0e2a0388ff Randomize people and thier files shown in people widget 2025-05-26 17:56:48 +05:30
Manav Rathi
2baf3a3dd7 Tweak 2025-05-26 17:54:56 +05:30
Manav Rathi
854610dd48 Inline 2025-05-26 17:53:11 +05:30
laurenspriem
61be57fef5 Log loading of ML models events 2025-05-26 17:39:04 +05:30
Manav Rathi
8d59d7e254 Update 2025-05-26 17:32:42 +05:30
Manav Rathi
1bcf728b3a Conv 2025-05-26 17:24:51 +05:30
Manav Rathi
5797be3460 Update 2025-05-26 17:17:27 +05:30
Manav Rathi
20f50e4816 Update 2025-05-26 17:11:18 +05:30
Manav Rathi
5064ebf4d3 Update 2025-05-26 17:01:15 +05:30
laurenspriem
eb783f0fff Remove redundant method 2025-05-26 16:44:06 +05:30
laurenspriem
ca8f310868 Fix duplicate notification issue 2025-05-26 16:43:15 +05:30
Neeraj
2e0a2802e7 [mob] Add change log (#6042)
## Description

## Tests
2025-05-26 16:33:47 +05:30
Neeraj Gupta
7868c2e16e Remove unused entries 2025-05-26 16:31:34 +05:30
Neeraj Gupta
ace5dc04e2 Add change log 2025-05-26 16:30:11 +05:30
laurenspriem
4249491730 More logging 2025-05-26 16:16:53 +05:30
laurenspriem
a958380a1d More logging 2025-05-26 15:56:23 +05:30
Manav Rathi
b0d940e65b [web] New translations (#6039)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-26 15:54:30 +05:30
Crowdin Bot
5b8472b5a9 New Crowdin translations by GitHub Action 2025-05-26 10:23:27 +00:00
Manav Rathi
6bb7627d47 [web] Minor loose ends (#6038) 2025-05-26 15:52:52 +05:30
laurenspriem
b00c406b09 Extract string 2025-05-26 15:52:45 +05:30
laurenspriem
ff9494d438 Setting to disable memories notifications 2025-05-26 15:51:59 +05:30
Neeraj
b24b5893ae [mob] Fix: Hide both shared and collect files (#6023) 2025-05-26 15:46:46 +05:30
Manav Rathi
9716ff80c4 tr 2025-05-26 15:34:37 +05:30
Manav Rathi
2808f72233 yes 2025-05-26 15:00:37 +05:30
Manav Rathi
5dd097ee09 ditto 2025-05-26 14:58:34 +05:30
Ashil
be9fddf1d4 [mob][photos] Avoid reordering selected faces (#6037) 2025-05-26 14:43:15 +05:30
ashilkn
f9b3f6e9eb Avoid reordering selected faces 2025-05-26 14:39:16 +05:30
laurenspriem
dcb73abdec Log time of scheduled notificaiton 2025-05-26 14:33:39 +05:30
ashilkn
a14c6f4d26 Merge branch 'main' into widget-superpowered 2025-05-26 14:24:35 +05:30
laurenspriem
7afdfe6ed9 Fix delete all files from person 2025-05-26 14:16:59 +05:30
Manav Rathi
8ff8981b76 Fix close button color on download failure notification 2025-05-26 13:54:02 +05:30
Manav Rathi
b89f247f42 Reduce unhandled exception logspam on transient network issues 2025-05-26 13:40:42 +05:30
Neeraj
c3e5a037c0 [auth] New translations (#6035)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-05-26 11:46:16 +05:30
Neeraj
70a1894071 [mob] Explicitly exclude app data during D2D backup/transfer (#6028)
As it breaks ente photos anyway because of KeyStore AFAICT 
Tries to fix #6027
2025-05-26 11:44:41 +05:30
Neeraj
42453675b2 [auth] Add new icons & change Mistral icon (#6014)
## Description

- Add [AR24](https://www.ar24.fr/) icon
- Add [Finary](https://finary.com/) icon
- Change [Mistral](https://mistral.ai/) icon
2025-05-26 11:40:48 +05:30
laurenspriem
bdd09e12d8 More logs 2025-05-26 10:27:46 +05:30
laurenspriem
407ad41520 Test clearing with payload 2025-05-26 10:09:52 +05:30
Manav Rathi
185759d234 [infra] Allowlist x-client-version (#6036) 2025-05-26 09:54:07 +05:30
Manav Rathi
860760784a Update doc 2025-05-26 09:33:54 +05:30
Manav Rathi
de10292a84 [infra] Allowlist x-client-version 2025-05-26 09:31:29 +05:30
Manav Rathi
95f10e5a45 [web] New translations (#6033)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-26 08:38:45 +05:30
Crowdin Bot
eabacf24ad New Crowdin translations by GitHub Action 2025-05-26 03:06:46 +00:00
Crowdin Bot
61ffcfdc93 New Crowdin translations by GitHub Action 2025-05-26 01:17:57 +00:00
Crowdin Bot
f73fbf4b60 New Crowdin translations by GitHub Action 2025-05-26 01:05:08 +00:00
LucasMZ
0ade0a2807 Try to not allow backup from the system in D2D
As it breaks ente photos anyway because of KeyStore AFAICT
Tries to fix #6027
2025-05-25 08:51:36 -03:00
Neeraj
1e2fb13908 [auth] Add Oracle Cloud icon (#6020)
- Added Oracle Cloud SVG icon.
- Updated custom-icons.json to include the new icon.
2025-05-24 09:02:11 +05:30
Neeraj Gupta
8ab01aefe5 Fix lint + add todo 2025-05-24 09:00:52 +05:30
Neeraj Gupta
fa33a1afd9 Fix: Treat sandbox file as unique file during upload 2025-05-24 08:20:02 +05:30
Neeraj Gupta
856e126bc8 Fix: Hide both shared and collect files 2025-05-24 08:04:19 +05:30
Neeraj Gupta
0f7aae2017 Show resumable download progress for mediaKit 2025-05-24 07:42:19 +05:30
Neeraj Gupta
c1ddb863ad Refactor 2025-05-24 07:38:22 +05:30
Burak
845d014945 [auth] add Oracle Cloud icon
- Added Oracle Cloud SVG icon.
- Updated custom-icons.json to include the new icon.
2025-05-23 19:46:44 +03:00
Ashil
d8b54f5211 [mob][photos] Add files to multiple collections at once (#6019) 2025-05-23 20:37:17 +05:30
Ashil
bc059c861f Merge branch 'widget-superpowered' into collection_sheet_batch_operation 2025-05-23 20:34:06 +05:30
ashilkn
b52ee5bbfb bump up build number to 1052 2025-05-23 20:33:11 +05:30
ashilkn
93c85a57e4 Do remote sync irrespective of error when adding files to multiple collections 2025-05-23 20:23:08 +05:30
ashilkn
e01826217d Refactor 2025-05-23 20:11:44 +05:30
Aman Raj Singh Mourya
b79b7ff3ef Refactor addToMultipleCollections to improve error handling 2025-05-23 19:40:49 +05:30
Manav Rathi
7d52e3d852 [desktop] HLS - Avoid upscaling (#6018)
https://trac.ffmpeg.org/wiki/Scaling#AvoidingUpscaling
2025-05-23 18:29:20 +05:30
Laurens Priem
9a647d6f78 [mob][photos] Fixed crashes on 200MP photos (#6017)
## Description

- Fixed crashes on 200MP photos by decoding them at lower resolution (at
trade-off of zoom)
- Fixed a text overflow issue

## Tests

Tested on a separate build with multiple 200MP photos on my pixel 8.
2025-05-23 17:59:47 +05:30
laurenspriem
6e99206523 Merge branch 'main' into some_fixes 2025-05-23 17:44:50 +05:30
laurenspriem
d7af21aa84 Fix crashes on 200MP photos 2025-05-23 17:37:22 +05:30
Manav Rathi
ced1f6e164 Avoid upscaling
https://trac.ffmpeg.org/wiki/Scaling#AvoidingUpscaling
2025-05-23 17:19:54 +05:30
Neeraj Gupta
7391f27967 Auto pause download when user move away from video 2025-05-23 17:13:54 +05:30
Manav Rathi
4ea3989a33 [desktop][web] Dependency updates (#6016)
\+ Electron 36 workaround
2025-05-23 16:57:05 +05:30
Vishnu Mohandas
641a99b823 [docs] Update export.md 2025-05-23 16:55:04 +05:30
Manav Rathi
7b48dbc1ad Dep updates 2025-05-23 16:47:54 +05:30
Manav Rathi
54c69e7aa5 Add workaround 2025-05-23 16:44:11 +05:30
Manav Rathi
f8bd8c9955 Dep 2025-05-23 16:40:04 +05:30
Neeraj Gupta
f7bb9d5974 Remove db to track download tasks 2025-05-23 16:31:28 +05:30
Manav Rathi
60246be861 [desktop] Multipart HLS video uploads (#6015) 2025-05-23 15:47:49 +05:30
Neeraj Gupta
e3b72fc929 Show part storage breakup under pending sync 2025-05-23 15:35:09 +05:30
Neeraj Gupta
92dae44a0a Refactor 2025-05-23 15:34:55 +05:30
Manav Rathi
d71016500a Equal sized parts (except last) 2025-05-23 15:33:29 +05:30
Aman Raj Singh Mourya
f44c2d14c7 Enable drag functionality in pick cover photo, person avatar, and center point widget. 2025-05-23 15:31:56 +05:30
Neeraj
9c26f4040a [server] Add multipart upload support for preview data (#5992)
## Description

## Tests
2025-05-23 15:31:11 +05:30
Manav Rathi
79e048b4b7 logout 2025-05-23 15:07:12 +05:30
Tanguy
5c0ce038d1 Change Mistral AI icon 2025-05-23 11:36:59 +02:00
Aman Raj Singh Mourya
2903388c94 Refactor CollectionActionSheet and improve UX 2025-05-23 14:48:36 +05:30
Tanguy
331a65d2a0 Add AR24 and Finary icons 2025-05-23 11:14:33 +02:00
Vishnu Mohandas
6c6ab8f463 [mob] Minor UI patch (#6013)
## Description
Increase the width of the container to prevent text overflow

## Tests
- [x] Tested on emulator
2025-05-23 14:03:22 +05:30
vishnukvmd
441a884314 Increase the width of the text container 2025-05-23 14:01:30 +05:30
Manav Rathi
3372d83c5d impl 2025-05-23 12:52:44 +05:30
Manav Rathi
0cf50513cc get 1 2025-05-23 12:39:54 +05:30
Neeraj
7ccf473190 [mob] Trust the user trust store (Android) (#5999)
## Description

It's currently not possible to use a server that has a CA that is
trusted by the _user_ trust store in Android.
This is generally due to a missing configuration of the
`networkSecurityConfig` (by default only system-level CAs are accepted).
  
With this change, the app should be able to reach out to servers that do
not use a publicly trusted CA (but that are still trusted by the user).

## Tests

None

## Remarks

I wasn't able to test my changes as the Flutter build fails with:


```
warning: [options] source value 8 is obsolete and will be removed in a future release
warning: [options] target value 8 is obsolete and will be removed in a future release
warning: [options] To suppress warnings about obsolete options, use -Xlint:-options.
$HOME/.pub-cache/git/ffmpeg-kit-6d5d27a8c259eda6292f204a27fba53da70af20e/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java:157: error: cannot find symbol
    public static void registerWith(final io.flutter.plugin.common.PluginRegistry.Registrar registrar) {
                                                                                 ^
  symbol:   class Registrar
  location: interface PluginRegistry
$HOME/.pub-cache/git/ffmpeg-kit-6d5d27a8c259eda6292f204a27fba53da70af20e/flutter/flutter/android/src/main/java/com/arthenica/ffmpegkit/flutter/FFmpegKitFlutterPlugin.java:651: error: cannot find symbol
    protected void init(final BinaryMessenger messenger, final Context context, final Activity activity, final io.flutter.plugin.common.PluginRegistry.Registrar registrar, final ActivityPluginBinding activityBinding) {
                                                                                                                ^
  symbol:   class Registrar
  location: interface PluginRegistry
2 errors
3 warnings

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':ffmpeg_kit_flutter:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

* Try:
> Run with --info option to get more log output.
> Run with --scan to get full insights.

BUILD FAILED in 59s
```
2025-05-23 12:36:40 +05:30
laurenspriem
c1f7a01ed2 Fix text overflow issue 2025-05-23 12:31:46 +05:30
Aman Raj Singh Mourya
256243e273 Enable drag functionality in collection action sheet 2025-05-23 12:30:27 +05:30
Aman Raj Singh Mourya
dc9dc5d8f9 Single tap selection to select albums 2025-05-23 12:28:24 +05:30
Manav Rathi
6969385089 sketch 2 2025-05-23 12:27:54 +05:30
Manav Rathi
87a1c9417e sketch 1 wip 2025-05-23 12:04:34 +05:30
Manav Rathi
6d13ff5151 ver 2025-05-23 11:31:29 +05:30
Manav Rathi
0b5317867f ue 2025-05-23 11:22:20 +05:30
Neeraj Gupta
6c9107301c Add support for resumable download 2025-05-23 11:21:48 +05:30
Manav Rathi
a32c8116a2 Use 2025-05-23 11:16:10 +05:30
Manav Rathi
d8cd81c702 desktop zod
we'll need it for parsing responses for requests we'll make subsequently
2025-05-23 11:11:33 +05:30
laurenspriem
18e7bbd1ed Extract strings for i18n for existing notifications 2025-05-23 10:41:27 +05:30
laurenspriem
63850df06a Change copy and extract string 2025-05-23 10:33:58 +05:30
Manav Rathi
886ab6d106 Tweak 2025-05-23 10:07:27 +05:30
Manav Rathi
d17296216c retry enhancements 2025-05-23 09:17:37 +05:30
Manav Rathi
55ee8b90b9 more conservative to prevent unforeseen loops 2025-05-23 08:45:04 +05:30
Prateek Sunal
634561347f chore: bump version 2025-05-22 23:52:05 +05:30
Prateek Sunal
575abdb8eb Merge remote-tracking branch 'origin/widget-superpowered' into widget-superpowered 2025-05-22 23:50:22 +05:30
Prateek Sunal
e998502b53 fix: add a status key to check if partial sync was did but a full is required now
(like previously widget was not their so it was fine to sync only 5 images but now since widget is there a full sync is compulsory)
2025-05-22 23:50:07 +05:30
laurenspriem
2ada68e837 Merge remote-tracking branch 'origin/widget-superpowered' into widget-superpowered 2025-05-22 22:41:04 +05:30
laurenspriem
28822a8dc1 Swallow notification scheduling issues 2025-05-22 22:38:24 +05:30
laurenspriem
deaa9a703d Bump for internal release 2025-05-22 22:26:02 +05:30
laurenspriem
4510edf8bd Update notification dependency 2025-05-22 22:24:59 +05:30
laurenspriem
7af59a1ecf Schedule test notifications 2025-05-22 22:24:40 +05:30
Denys Vitali
e003c783f5 fix: use only system CA for ente.io 2025-05-22 18:54:12 +02:00
Denys Vitali
379d2487bd Merge branch 'main' into feature/user-trust-store-android 2025-05-22 18:53:08 +02:00
Manav Rathi
8cdbb737dc Fix 2025-05-22 21:05:39 +05:30
Prateek Sunal
d528d97a0f fix: add got all widget logic 2025-05-22 21:00:48 +05:30
Prateek Sunal
682e4a913f fix: ui stuff 2025-05-22 20:52:13 +05:30
Manav Rathi
a72041b8ba cpkg 2025-05-22 20:29:29 +05:30
Prateek Sunal
ab1a8aa592 fix: don't repeat 2025-05-22 20:21:48 +05:30
Prateek Sunal
c37a0339d2 fix: default state ui 2025-05-22 20:18:41 +05:30
Manav Rathi
3b60f4954b Impl 2025-05-22 20:05:56 +05:30
Manav Rathi
b2ea248a5c Sketch 2025-05-22 19:58:39 +05:30
Prateek Sunal
1bda14fb6f fix: redirect with correct context 2025-05-22 19:57:08 +05:30
Manav Rathi
54e8d6392d Scaffold 2025-05-22 19:46:00 +05:30
Manav Rathi
afa9e03743 ref 2025-05-22 19:39:13 +05:30
Manav Rathi
a4eaf04a33 Extract 2025-05-22 19:34:39 +05:30
Manav Rathi
d30f0fba04 pc estimate 2025-05-22 19:27:57 +05:30
Prateek Sunal
b2855cfd72 fix: rank selected first 2025-05-22 19:20:16 +05:30
Prateek Sunal
06d260f40a fix: only allow selection 2025-05-22 19:04:21 +05:30
Manav Rathi
fb16346b0d Forward 2025-05-22 18:31:05 +05:30
Manav Rathi
41b1638838 Outline 2025-05-22 18:31:05 +05:30
Manav Rathi
702b3a8868 [desktop] Split x-client-package and x-client-version to match mobile (#6008) 2025-05-22 17:49:20 +05:30
Manav Rathi
3572c4328d str 2025-05-22 17:46:08 +05:30
Manav Rathi
1c2b8061dc Include "X-Client-Version" where applicable 2025-05-22 17:41:51 +05:30
Manav Rathi
a9edcead06 [desktop] Don't add version to x-client-package 2025-05-22 17:26:28 +05:30
laurenspriem
5a574c69d3 log debug notification options 2025-05-22 16:48:01 +05:30
Neeraj Gupta
372af94da4 Merge remote-tracking branch 'origin/main' into resumableDownload 2025-05-22 16:41:21 +05:30
Manav Rathi
192905b21e [web] Multipart changes - Finish (#6007)
Finishes the set of changes from
https://github.com/ente-io/ente/pull/5997 and
https://github.com/ente-io/ente/pull/6002.
2025-05-22 16:23:38 +05:30
Manav Rathi
52a533a1e1 Fin 2025-05-22 16:08:07 +05:30
Manav Rathi
0314e94359 Up 2 2025-05-22 15:56:00 +05:30
Neeraj Gupta
cbef1a9145 ios build changes 2025-05-22 15:53:59 +05:30
Aman Raj Singh Mourya
822c33940e Skip single tap action when selection mode is enabled 2025-05-22 15:53:06 +05:30
Manav Rathi
eb29c48f0e Up 1 2025-05-22 15:50:55 +05:30
Aman Raj Singh Mourya
c77b4f176c Refactor AlbumColumnItemWidget to improve selection handling and UI layout 2025-05-22 15:49:49 +05:30
Neeraj Gupta
8bc701d104 Download by individual chunks 2025-05-22 15:35:45 +05:30
Aman Raj Singh Mourya
afcc7b1e46 Add selection functionality and action buttons to collection action sheet 2025-05-22 15:26:49 +05:30
Manav Rathi
84dda89e15 up 2025-05-22 15:26:26 +05:30
Aman Raj Singh Mourya
4bbc0d1f46 Implement addToMultipleCollections method for batch adding files to collections 2025-05-22 15:26:07 +05:30
laurenspriem
aa6d6f4e77 Bump for internal release 2025-05-22 15:04:50 +05:30
Manav Rathi
ff26dd5652 Simplify 2025-05-22 15:04:37 +05:30
Manav Rathi
b68d95d481 normal put 2025-05-22 14:50:00 +05:30
laurenspriem
ec1b54cbb1 Merge branch 'main' into widget-superpowered 2025-05-22 14:46:00 +05:30
laurenspriem
459540fe7a Flag for ML running 2025-05-22 14:38:17 +05:30
Neeraj
2255ea1b92 [meta] Update mobile-internal-release.yml (#6005)
Include branch name

## Description

## Tests
2025-05-22 14:04:25 +05:30
Neeraj
ac704f1082 Update mobile-internal-release.yml
Include branch name
2025-05-22 14:04:04 +05:30
Laurens Priem
4db2e42ee3 [mob][photos] On this day memories + notification + fix (#5998)
## Description

- Added 'On this day' memory similar to [user
request](https://github.com/ente-io/ente/discussions/5852)
- 'On this day' memory gives a notification in the morning
- Fixed [other memories
issue](https://github.com/ente-io/ente/issues/5965)


## Tests

Tested in debug mode on my pixel 8:
- No caching issues
- 'On this day' memories are computed correctly
- Scheduled notifications come at correct time
- Tapping on notification directs to the memory
2025-05-22 13:17:06 +05:30
Manav Rathi
f5949f5bd4 [web] Multipart upload tweaks (#6002)
Refactoring this now before starting on the work on porting some of it
to desktop side.
2025-05-22 12:18:53 +05:30
Manav Rathi
c4feb4b764 in body 2025-05-22 12:13:37 +05:30
Manav Rathi
29bab5705b Sep 2025-05-22 11:40:50 +05:30
Manav Rathi
2ebeed3b6f Unused 2025-05-22 11:35:44 +05:30
Manav Rathi
a0dbcd3dbe Prune 2025-05-22 11:31:12 +05:30
Neeraj
81137652d4 Fix: Return correct status code for maxPassKey err (#6001)
## Description

## Tests
2025-05-22 11:29:55 +05:30
Manav Rathi
4e1418b11a package 2025-05-22 11:29:22 +05:30
Neeraj Gupta
91268341be Fix: Return correct status code for maxPassKey err 2025-05-22 11:27:31 +05:30
Manav Rathi
fb8fc051a9 wrkr 2025-05-22 11:15:28 +05:30
Manav Rathi
d99914c4e9 off by 1 2025-05-22 11:03:30 +05:30
Manav Rathi
736b3fc613 Upload progress 2025-05-22 09:08:52 +05:30
Manav Rathi
ef7f45aa3d Alt 2025-05-22 08:56:09 +05:30
Denys Vitali
4dc741151b fix(mobile): trust the user trust store (Android) 2025-05-22 02:14:11 +02:00
Manav Rathi
e4471af4cb Pass 2025-05-21 21:04:43 +05:30
Manav Rathi
057df349b7 Move retry to service 2025-05-21 20:47:28 +05:30
Manav Rathi
24c7b49132 custom 2025-05-21 19:39:36 +05:30
Manav Rathi
5df009c7c7 Revert because of ERR_H2_OR_QUIC_REQUIRED
Chrome throws ERR_H2_OR_QUIC_REQUIRED when we try to use a stream body on a
non-TLS HTTP request. This will break both dev setups on localhost, and perhaps
some self hosting setups, so is not a feasible path forward for an essential
endpoint to the use of the app.
2025-05-21 19:29:12 +05:30
Manav Rathi
1d276c795c transform 1 2025-05-21 17:56:09 +05:30
Manav Rathi
bc762b972f take 1 2025-05-21 17:39:58 +05:30
laurenspriem
36e4c06dd6 Merge branch 'main' into on_this_day 2025-05-21 17:15:55 +05:30
laurenspriem
ceb3d3fe42 Fix hidden persons in memories 2025-05-21 16:59:50 +05:30
laurenspriem
1dc806d270 Don't await on page route 2025-05-21 16:58:22 +05:30
laurenspriem
8d03df5c36 Remove old debug options 2025-05-21 16:57:56 +05:30
laurenspriem
a1ef8d33d3 Simplify notification ID 2025-05-21 16:56:51 +05:30
Manav Rathi
4f347c1afd [web] Remove unnecessary sax dependency by reworking multipart uploads (#5997) 2025-05-21 16:39:35 +05:30
laurenspriem
8171d56168 Route notification to memory 2025-05-21 16:35:57 +05:30
Manav Rathi
7e7751b5be Nicer 2025-05-21 16:27:25 +05:30
Manav Rathi
d19a0fccda Remove dependency 2025-05-21 16:22:52 +05:30
Manav Rathi
5b38ef394b More debug info 2025-05-21 16:10:27 +05:30
Manav Rathi
ad87470c25 2 2025-05-21 16:10:26 +05:30
Manav Rathi
67140fe7f2 s2 2025-05-21 16:10:26 +05:30
Manav Rathi
b372ba47ba Swap 2025-05-21 16:10:26 +05:30
Manav Rathi
24c66a9b6b impl 2025-05-21 16:10:26 +05:30
Manav Rathi
201ef60f07 Outline 2025-05-21 16:10:26 +05:30
Manav Rathi
89294f2a76 Outline 2025-05-21 16:10:26 +05:30
Manav Rathi
4772557f7a Tweak 2025-05-21 16:10:26 +05:30
Manav Rathi
073d2c5684 2 2025-05-21 16:10:26 +05:30
Manav Rathi
e022e7ae5b 1 2025-05-21 16:10:26 +05:30
Manav Rathi
2cdeb88b4d Outline 2025-05-21 16:10:26 +05:30
Neeraj Gupta
78e70a1c05 Merge branch 'main' into resumableDownload 2025-05-21 16:03:58 +05:30
Neeraj
ca319e501e [mob][auth] Update copy for change email dialog (#5996)
## Description

## Tests
2025-05-21 15:32:05 +05:30
Neeraj Gupta
05898dfbe2 Update copy for change email dialog 2025-05-21 15:28:01 +05:30
Neeraj
c129cc15b5 [server] Increase file size limit 5 -> 10 GiB (#5995)
## Description

## Tests
2025-05-21 15:26:31 +05:30
Neeraj Gupta
a683883733 Increase file size limit 5 -> 10 GiB 2025-05-21 15:20:12 +05:30
laurenspriem
69b575cc66 Log cache update due to caching issue 2025-05-21 14:39:12 +05:30
laurenspriem
63a4972839 Fix caching issue 2025-05-21 14:37:38 +05:30
Neeraj
6188578d18 [docs] Update example config (#5951)
## Description
In my testing web apps only worked with https:// in front of them.
## Tests
2025-05-21 13:38:56 +05:30
laurenspriem
5a4d8950af Integrate notifications to OnThisDay memories 2025-05-21 12:36:04 +05:30
Neeraj
5007204944 [server] Change file_data.obj_size column type (#5994)
## Description

## Tests
Tested locally
2025-05-21 11:24:52 +05:30
Neeraj Gupta
4a19fc077e Change file_data.obj_size column type 2025-05-21 11:13:05 +05:30
Ashil
2b29f55587 [mob][photos] Album UI Revamp (#5661)
## Description
This update introduces a redesigned user interface for album management,
featuring a new layout for albums. Improve user experience by providing
intuitive navigation and efficient batch operations.

## Tests
1. A new grid & list layout for the album screen. The first cell is
dedicated to quickly adding new albums.
2. App Bar Enhancements
    - Sort Options: Organize albums by name, latest, or time.
    - View Toggle: Switch between grid and list views with ease.
    - Search Functionality: Quickly find albums using the search icon.
3. Long-press to select albums for batch actions. A bottom sheet
provides options to delete, share, hide, or pin selected albums.
2025-05-21 11:01:48 +05:30
laurenspriem
4cc8ff2fb1 Notification scheduling working 2025-05-21 10:57:49 +05:30
Aman Raj Singh Mourya
de29246304 move the collection.type == CollectionType.favorites check before isEmptyCollection check to handle the case where favourite collection is empty 2025-05-21 10:47:01 +05:30
laurenspriem
8deb52301a Android permissions for notifications 2025-05-21 10:30:01 +05:30
Manav Rathi
16a20e8b0d [web] Hash functions - Document and namespace (#5993)
No functional changes.
2025-05-21 08:56:29 +05:30
Manav Rathi
3824bfbdd5 namespace 2025-05-21 08:51:22 +05:30
Prateek Sunal
c996c794fd fix: launch people page before launching the file previewer 2025-05-21 08:47:03 +05:30
Manav Rathi
ef245e5c02 outline 2025-05-21 08:36:34 +05:30
Neeraj Gupta
4dc6890afc Add multipart upload support for preview data 2025-05-21 08:14:53 +05:30
Prateek Sunal
87195f3801 chore: fix incorrect widget count 2025-05-21 04:15:57 +05:30
Prateek Sunal
8ce45a4fa8 chore: bump version 2025-05-21 04:06:02 +05:30
Prateek Sunal
520e5d4ae7 fix: update routing 2025-05-21 04:01:37 +05:30
Prateek Sunal
2a8e167e42 fix: don't listen to collection route 2025-05-21 03:51:20 +05:30
Prateek Sunal
2f7bde36bd chore: bump version to 1.0.17 2025-05-21 03:27:49 +05:30
Prateek Sunal
ace375b7f6 fix: get effective selected people code 2025-05-21 03:27:38 +05:30
Prateek Sunal
cde6ebfa39 fix: pass and parse mainKey correctly 2025-05-21 03:12:19 +05:30
Prateek Sunal
a1e56a457f fix: update people default illustration 2025-05-21 03:04:21 +05:30
Prateek Sunal
a4ebf972e1 fix: count home widget for android 2025-05-21 02:56:32 +05:30
Prateek Sunal
7d5bed0493 fix: iOS build 2025-05-21 02:20:43 +05:30
Prateek Sunal
d449bd0f90 chore: update version 2025-05-21 02:16:48 +05:30
Prateek Sunal
5d14ca8439 fix: handle PeopleChangedEvent, add better limit for files, better behavior on save 2025-05-21 02:15:23 +05:30
Prateek Sunal
619f6795e2 fix: don't show un-named person 2025-05-21 01:44:12 +05:30
Prateek Sunal
04cd1d3bb3 fix: update code to look clean 2025-05-21 01:28:14 +05:30
Prateek Sunal
0960f189ce Merge remote-tracking branch 'origin/main' into widget-superpowered 2025-05-21 01:11:56 +05:30
Prateek Sunal
734b836a7a chore: update locals 2025-05-21 01:11:48 +05:30
Prateek Sunal
91447cdc77 fix: widgets code 2025-05-21 01:11:40 +05:30
Manav Rathi
961501a6fb [desktop] HLS newlines - Take 2 (#5990) 2025-05-20 20:07:22 +05:30
Manav Rathi
914893eae6 Fix 2025-05-20 20:01:44 +05:30
Manav Rathi
7a10f4c145 Note results of tests and add extra checks 2025-05-20 19:58:10 +05:30
ashilkn
092f64c3ca Refactor CollectionsFlexiGridViewWidget 2025-05-20 17:44:27 +05:30
laurenspriem
bdecb04398 Add timezone package for finding OS timezone 2025-05-20 17:38:04 +05:30
Neeraj
e25418e5a6 [server] Fix err handling during stream upload (#5986)
## Description

## Tests
2025-05-20 16:37:29 +05:30
Neeraj Gupta
a062c1ccc3 Fix err handling 2025-05-20 16:35:22 +05:30
Aman Raj Singh Mourya
d1ae4d52dd refactor: update padding and width to make sure thumbnail is perfect square 2025-05-20 16:04:53 +05:30
Manav Rathi
3c532cd4f4 [desktop] Fix HLS regex for Windows (#5984)
`$` eol should match both `\r\n` (windows) and `\n` (rest)
2025-05-20 16:02:56 +05:30
Manav Rathi
013389c696 Fix regex for Windows 2025-05-20 15:57:41 +05:30
Neeraj
9ca418d915 [auth] Script to creating tag & modifying flatback metadata (#5983)
## Description

## Tests
Tested locally
2025-05-20 14:57:09 +05:30
Neeraj Gupta
a52a3e5e57 Remove unused variable 2025-05-20 14:54:27 +05:30
Neeraj Gupta
2d739ef4de [auth] Bump version 4.3.8 2025-05-20 14:47:30 +05:30
Neeraj Gupta
300300a8b9 Add script to add tag 2025-05-20 14:47:10 +05:30
Neeraj Gupta
be00cbaa51 Add release 4.3.8 to appdata.xml 2025-05-20 14:44:53 +05:30
Neeraj Gupta
43641b0b9e Add script to validate & create release tag 2025-05-20 14:31:54 +05:30
Aman Raj Singh Mourya
43cdd10e85 Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-20 14:25:30 +05:30
Aman Raj Singh Mourya
539145d38d refactor: simplify layout calculations in flex grid view 2025-05-20 14:25:16 +05:30
Neeraj Gupta
a5ccae4390 Merge branch 'main' into resumableDownload 2025-05-20 14:21:27 +05:30
Neeraj
08bb2f25fb [mob] Fix: Switch to original video playback for android (#5982)
## Description
Bug: When filePath was not null due to preview playlist, we kept playing
the preview video, and where not showing any progress indicator for
video download.

## Tests
Tested locally on physical device.
2025-05-20 14:07:34 +05:30
Neeraj Gupta
55264445b2 Fix: Switch to original video playback 2025-05-20 13:59:05 +05:30
Manav Rathi
bdadf8dc9c [desktop] Avoid stdout max buffer error when converting very large videos (#5981) 2025-05-20 12:41:16 +05:30
Manav Rathi
1c3428d89d Avoid stdout max buffer error when converting very large videos 2025-05-20 12:35:14 +05:30
Neeraj Gupta
34b53f8443 Show download progress for internal users 2025-05-20 12:29:17 +05:30
Neeraj Gupta
8448be6c68 move model out + clean up 2025-05-20 12:01:13 +05:30
ashilkn
6e4a856ea4 Use better colors 2025-05-20 11:57:19 +05:30
ashilkn
40ff361af1 Add Todo comment 2025-05-20 11:28:59 +05:30
Neeraj
11fae5e87c [server] Whitelist range header (#5978) 2025-05-20 10:48:25 +05:30
Neeraj Gupta
465e69b254 Whitelist range header 2025-05-20 10:13:12 +05:30
laurenspriem
63b0cee589 Add timezone dependency for scheduling notifications 2025-05-20 09:13:56 +05:30
Prateek Sunal
574eea58fc fix: add robust logic for album home widget service 2025-05-20 07:06:57 +05:30
Manav Rathi
f848fe0938 [web] Minor notes and null checks (#5974) 2025-05-19 20:04:32 +05:30
Prateek Sunal
138310b8f8 fix: update get collection by id function 2025-05-19 19:54:24 +05:30
Prateek Sunal
3d63ded84d fix: blockers, getter function for albums hw service 2025-05-19 19:54:09 +05:30
Manav Rathi
b7cd55aec3 ctx
"OwnerEmail currently is always present for shared collection but missing for owned collection."
2025-05-19 19:53:31 +05:30
Manav Rathi
aadab316f6 + 2025-05-19 19:26:06 +05:30
Manav Rathi
8bad8b87b1 more context from chat 2025-05-19 19:23:37 +05:30
Prateek Sunal
2ff69f661e Merge branch 'main' into widget-superpowered 2025-05-19 19:20:26 +05:30
Prateek Sunal
10c65f13c8 fix: update get total function for memory home widget 2025-05-19 19:19:30 +05:30
Prateek Sunal
761c976d7e Merge remote-tracking branch 'origin/on_this_day' into widget-superpowered 2025-05-19 19:13:47 +05:30
Prateek Sunal
423a7eec37 fix: show on this day to both ml & non-ml users 2025-05-19 19:10:29 +05:30
Manav Rathi
1f7e74131b + 2025-05-19 19:05:37 +05:30
Prateek Sunal
c8b23f80e2 feat: add selection and save/get from db for people widget settings 2025-05-19 18:53:41 +05:30
Manav Rathi
191db47d79 type 2025-05-19 18:22:27 +05:30
Manav Rathi
34621dd00f notes 2025-05-19 18:21:06 +05:30
Prateek Sunal
d127199ade feat: complete save and selection logic for memories and albums settings 2025-05-19 17:35:33 +05:30
Aman Raj Singh Mourya
f44e90801f refractor: revert back copy of sort options 2025-05-19 17:23:25 +05:30
Aman Raj Singh Mourya
ded497d421 fix: make album sqaure and show file count 2025-05-19 17:22:08 +05:30
Neeraj
a3e48706de [mob] Refactor download url lookup (#5968)
## Description

## Tests
2025-05-19 16:58:54 +05:30
Neeraj Gupta
7f3d4db9a5 Add scaffold (llm) for resumable download 2025-05-19 16:57:41 +05:30
Neeraj Gupta
2709f69f2a Remove unused import 2025-05-19 15:26:53 +05:30
Neeraj Gupta
2b32cd4277 Refactor 2025-05-19 15:25:11 +05:30
Neeraj Gupta
57934f612e Refactor 2025-05-19 15:11:34 +05:30
Neeraj Gupta
eae5e12c71 Clean up 2025-05-19 15:07:20 +05:30
Neeraj Gupta
aef50f3f95 Rename & move downloadQueue 2025-05-19 14:41:56 +05:30
Neeraj
6772027c27 [mob] Fix: Clean up origin file for hard upload failures (#5954)
## Description
The value of this variable was incorrectly set to `false` (as as initial
value).

## Tests
2025-05-19 14:26:35 +05:30
Neeraj
f386a0a72e [cli] Specify ott purpose (#5966)
## Description

## Tests
2025-05-19 14:25:58 +05:30
Neeraj Gupta
9c94bcffaa [cli] Specify ott purpose 2025-05-19 14:21:52 +05:30
Manav Rathi
6b703e9601 [web] Add more CSP cases (#5964) 2025-05-19 14:18:22 +05:30
Prateek Sunal
22bae0292d feat: add new widget services 2025-05-19 14:04:42 +05:30
Prateek Sunal
4c7121fd6c chore: update generated messages 2025-05-19 14:04:19 +05:30
Prateek Sunal
f53745bbb0 Merge remote-tracking branch 'origin/album_UI_revamp' into widget-superpowered 2025-05-19 14:00:13 +05:30
ashilkn
1c6e343994 Use StatelessWidget instead of helper method 2025-05-19 13:51:52 +05:30
Manav Rathi
949807bc97 rep-endp
https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Reporting-Endpoints
2025-05-19 13:48:34 +05:30
Manav Rathi
fea46532f9 Example 2025-05-19 13:37:51 +05:30
Manav Rathi
8824df29d4 They're POST 2025-05-19 11:51:10 +05:30
Manav Rathi
2da2616ec1 Update deps 2025-05-19 11:39:01 +05:30
laurenspriem
2144f57ee0 remove null check 2025-05-19 11:08:00 +05:30
laurenspriem
476fe1b624 Assign IDs to memories 2025-05-19 11:06:39 +05:30
Manav Rathi
fb7fc53263 csp-rep 2025-05-19 10:06:03 +05:30
Neeraj
a842cdfe4e [auth] add Cryptee icon (#5959)
I added the Cryptee icon. Cryptee is similar to Ente, as it is also a
secure photo service
2025-05-19 10:03:32 +05:30
Neeraj
d5de1b5ce2 [auth] New translations (#5963)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-05-19 09:57:11 +05:30
Neeraj
a1801435bd [mobile] New translations (#5962)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-19 09:55:12 +05:30
Manav Rathi
bc02238fd8 video streaming 2025-05-19 09:53:40 +05:30
Manav Rathi
49ef8a693b [web] New translations (#5961)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-19 08:31:15 +05:30
Crowdin Bot
6f585c3ad0 New Crowdin translations by GitHub Action 2025-05-19 01:18:00 +00:00
Crowdin Bot
18f9f0048a New Crowdin translations by GitHub Action 2025-05-19 01:04:58 +00:00
Crowdin Bot
6a7ba4156f New Crowdin translations by GitHub Action 2025-05-19 00:41:15 +00:00
UmmIt
30995b3b73 [auth] add Cryptee icon 2025-05-19 01:14:53 +08:00
laurenspriem
ff705280c7 Rename variable 2025-05-18 11:58:42 +05:30
laurenspriem
6ff6594a81 Include onThisDay in widget api 2025-05-18 11:40:23 +05:30
laurenspriem
69f12125ec Merge branch 'memories_widget_api' into on_this_day 2025-05-18 11:26:53 +05:30
laurenspriem
862b11c530 Calc onThisDay even when ML is off 2025-05-18 11:23:05 +05:30
laurenspriem
e40afac212 Rename for clarity 2025-05-18 11:09:48 +05:30
Neeraj Gupta
8c66d9dac0 Fix: Clean up origin file for hard upload failures 2025-05-18 10:48:10 +05:30
Ferdinand Saurenbach
a880726f16 Update museum.md 2025-05-17 16:43:36 +02:00
Manav Rathi
b2ab0679b4 [web] Handle shared favorites (#5947) 2025-05-16 21:46:41 +05:30
Manav Rathi
d63ecf518e Tweak 2025-05-16 21:42:34 +05:30
Manav Rathi
c5cdaf3e0b fix warning 2025-05-16 21:27:32 +05:30
Manav Rathi
61f1cd6952 Fix mui warnings 2025-05-16 21:24:29 +05:30
Manav Rathi
e6d4a779c5 int 2025-05-16 20:50:15 +05:30
Manav Rathi
14087ec5e9 more cases 2025-05-16 20:38:48 +05:30
Manav Rathi
15daa9e453 case 2025-05-16 20:15:14 +05:30
Manav Rathi
73728e60e0 dep 2025-05-16 20:01:57 +05:30
Manav Rathi
5c925c4265 fav 2025-05-16 19:39:39 +05:30
Manav Rathi
83bf336101 [web] Minor code improvements (#5945) 2025-05-16 19:39:01 +05:30
Manav Rathi
d5b9a0a92b [web] Unicode search (#5944)
Fixes: https://github.com/ente-io/ente/issues/5942
2025-05-16 19:35:47 +05:30
Manav Rathi
40d84f10a8 [web] Unicode search
Fixes: https://github.com/ente-io/ente/issues/5942
2025-05-16 19:29:52 +05:30
Prateek Sunal
bffd4d83a5 fix: update the deep link 2025-05-16 18:41:21 +05:30
Aman Raj Singh Mourya
59a534225c [mob][photos] Refactor add participant page (#5940) 2025-05-16 17:49:02 +05:30
ashilkn
810ee3d9fe Merge album_UI_revamp after resolving merge conflicts 2025-05-16 16:19:45 +05:30
ashilkn
9605637e50 Refactor add participants page 2025-05-16 16:15:53 +05:30
laurenspriem
9016394ccc Integrate on this day into gallery memories 2025-05-16 15:08:40 +05:30
Prateek Sunal
a518bbd608 fix(home-widget): update default image caption & rename totalMemories 2025-05-16 15:07:45 +05:30
Aman Raj Singh Mourya
1c4ebcccb1 fix: allow to leave favourite albums 2025-05-16 14:44:48 +05:30
Aman Raj Singh Mourya
793fd5ba39 fix: avoid poping of delete dialog to avoid poping of main screen 2025-05-16 14:39:56 +05:30
Prateek Sunal
9b1eacf736 fix: update the preview images 2025-05-16 14:37:33 +05:30
Aman Raj Singh Mourya
cae9988c9a fix: avoid poping of delete dialog as it pop the main screen 2025-05-16 14:37:02 +05:30
Prateek Sunal
538a5df32d feat: add preview images for both android & iOS 2025-05-16 14:30:13 +05:30
laurenspriem
853b916cf1 Exclude certain collections 2025-05-16 14:25:31 +05:30
Aman Raj Singh Mourya
93d6f58660 fix: code refractor 2025-05-16 14:22:53 +05:30
Neeraj Gupta
7b145f0898 Bump version code 2025-05-16 14:15:30 +05:30
Neeraj Gupta
add09a601d Merge branch 'main' into album_UI_revamp 2025-05-16 14:15:06 +05:30
Neeraj
cab711d88e [mob] Fix: Duration computation from playlist (#5939)
## Description

## Tests
2025-05-16 14:14:35 +05:30
Neeraj Gupta
c392bd2fd2 Fix: Duration computation from playlist 2025-05-16 14:12:21 +05:30
laurenspriem
5dda596544 Max of 20 photos spread across years 2025-05-16 13:52:05 +05:30
Neeraj Gupta
8101bee2fd Update intl_pt.arb 2025-05-16 12:50:13 +05:30
Neeraj Gupta
c234bc7be8 Fix lint 2025-05-16 12:45:41 +05:30
Neeraj Gupta
27fd372d62 Bump version v1.0.14 2025-05-16 12:42:58 +05:30
laurenspriem
66f23283c1 Only memories spread across multiple years 2025-05-16 12:42:00 +05:30
Neeraj Gupta
8d7bc81c20 Merge branch 'main' into album_UI_revamp 2025-05-16 12:40:56 +05:30
Neeraj
5e3ebd4a60 [mob][Fix] Fallback to email forname if personService init is pending (#5938)
## Description

## Tests
2025-05-16 12:39:31 +05:30
Neeraj Gupta
f4a4f71135 [mob][Fix] Fallback to email for userName if personService init is pending 2025-05-16 12:36:38 +05:30
Aman Raj Singh Mourya
41e870f7a0 [mob][photos] Contacts section performance improvements (#5923)
## Description

- Defer the initial load until the Shared Collection tab is in view to
avoid unnecessary work at app startup.
- Remove the computation previously done for the Search tab sections
that was intended for the Contacts section, as it is no longer present.
2025-05-16 11:59:14 +05:30
Aman Raj Singh Mourya
0342e1ef56 Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-16 11:57:33 +05:30
Aman Raj Singh Mourya
efed42ce4a refractor: used better code format 2025-05-16 11:56:55 +05:30
Neeraj
185c5f5c43 [mob] Fix seekBar duration for videos with missing duration in metadata (#5937)
## Description

## Tests
Tested locally
2025-05-16 11:40:30 +05:30
Neeraj Gupta
6f5b33ea01 Fix lint 2025-05-16 11:36:33 +05:30
Aman Raj Singh Mourya
ef9d925686 fix: alignment of icons 2025-05-16 11:34:37 +05:30
Neeraj Gupta
d6a8373e5d Clean up 2025-05-16 11:33:14 +05:30
laurenspriem
e84f46f435 correct translation use 2025-05-16 11:31:47 +05:30
laurenspriem
c1193be61c Extract strings 2025-05-16 11:31:23 +05:30
laurenspriem
9b460ca1dc Init onThisDay method 2025-05-16 11:30:44 +05:30
Neeraj Gupta
bd0ad0d1b4 Fix seekBar duration for preview videos with missing duration in metadata 2025-05-16 11:26:06 +05:30
Manav Rathi
d19322c1ae Remove column dependency
And add a dev canary
2025-05-16 11:16:52 +05:30
Manav Rathi
e71f5cecc7 alt 2025-05-16 11:16:52 +05:30
Manav Rathi
622a368b45 swap 2025-05-16 11:16:52 +05:30
Manav Rathi
72aec4bc5a swap 2025-05-16 11:16:52 +05:30
Manav Rathi
c899725ed1 Fix warning 2025-05-16 11:16:52 +05:30
Neeraj
e15eb8d7c7 [auth] Add cronetHttpNoPlay flag for playstore builds (#5932)
## Description

Fixes https://github.com/ente-io/ente/issues/5901

## Tests
2025-05-16 11:03:26 +05:30
Neeraj Gupta
b38c49502b Fix seekBar color at other places 2025-05-16 10:33:57 +05:30
Neeraj
0fdee342eb [mobile] New translations (#5935)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-16 10:30:10 +05:30
Crowdin Bot
0641ce389d New Crowdin translations by GitHub Action 2025-05-16 04:56:56 +00:00
Manav Rathi
f34ac356e9 [infra] Increase backup wait (#5931) 2025-05-16 07:45:33 +05:30
Neeraj Gupta
120f9cef4d [auth] Add cronetHttpNoPlay flag for playstore builds 2025-05-16 07:43:31 +05:30
Manav Rathi
9b4247680a [infra] Increase backup wait 2025-05-16 07:43:00 +05:30
Neeraj
5d69376b54 [mob] Change seekBar color for video to backgroundElevatedLight (#5929)
## Description
![Uploading image.png…]()


## Tests
2025-05-16 07:22:16 +05:30
Bl4ckspell
64260896a0 [auth] fix bonify icon (#5930)
## Description
Icon was not displaying.

| before | after |
| --- | --- |
|![Screenshot From 2025-05-16
02-40-15](https://github.com/user-attachments/assets/59d84c64-3bc5-4b03-8704-ccabb4dc80af)|![Screenshot
From 2025-05-16
03-01-49](https://github.com/user-attachments/assets/ade3df70-043a-4ac8-abca-d0f2d8cf4f59)|
2025-05-16 06:41:08 +05:30
Neeraj Gupta
2af46f62c8 Fix lint 2025-05-16 06:40:28 +05:30
Neeraj Gupta
a53701bc41 Copy update 2025-05-16 05:49:59 +05:30
Neeraj Gupta
7a408a6242 Change video seekBar color to backgroundElevatedLight 2025-05-16 05:48:51 +05:30
Manav Rathi
6b9885c5d7 [web] New translations (#5927)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-15 20:32:54 +05:30
Crowdin Bot
caa453d49d New Crowdin translations by GitHub Action 2025-05-15 15:01:14 +00:00
Manav Rathi
dd80acd4f4 [web] General code improvements (#5926) 2025-05-15 20:30:29 +05:30
Manav Rathi
5aa7682812 lf 2025-05-15 20:25:01 +05:30
Manav Rathi
cb9a88e636 tr 2025-05-15 20:25:01 +05:30
Manav Rathi
3a32659dd4 [desktop] Update to Electron 36.2.1 (#5925)
Regular dep update. Also update a minor dev dep.
2025-05-15 20:15:36 +05:30
Manav Rathi
d5b5a26d9a [desktop] Use a tighter HDR check (#5924)
Otherwise video conversion fails with

[Parsed_zscale_2 @ 0x12de1b040] code 3074: no path between colorspaces

Some sample video stream lines of videos where it failed:

- `Stream #0:0[0x1](und): Video: mpeg4 (Simple Profile) (mp4v /
0x7634706D), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 2204 kb/s, 30 fps, 30
tbr, 30 tbn (default)`
- `Stream #0:1[0x1e0]: Video: mpeg1video, yuv420p(tv), 640x480 [SAR 1:1
DAR 4:3], 104857 kb/s, 25 fps, 25 tbr, 90k tbn`
- `Stream #0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D),
yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 15379 kb/s, 30 fps, 30
tbr, 30 tbn`
- `Stream #0:0[0x1](eng): Video: h263 (s263 / 0x33363273), yuv420p,
176x144 [SAR 12:11 DAR 4:3], 96 kb/s, 15.27 fps, 15.42 tbr, 15750 tbn
(default)`
2025-05-15 20:03:01 +05:30
Manav Rathi
d2980abb7a [desktop] Update to Electron 36.2.1
Regular dep update. Also update a minor dev dep.
2025-05-15 20:01:48 +05:30
Manav Rathi
1a2f606d94 Use a tighter check
Otherwise video conversion fails with

    [Parsed_zscale_2 @ 0x12de1b040] code 3074: no path between colorspaces

Some sample video stream lines of videos where it failed:

- `Stream #0:0[0x1](und): Video: mpeg4 (Simple Profile) (mp4v / 0x7634706D), yuv420p, 640x480 [SAR 1:1 DAR 4:3], 2204 kb/s, 30 fps, 30 tbr, 30 tbn (default)`
- `Stream #0:1[0x1e0]: Video: mpeg1video, yuv420p(tv), 640x480 [SAR 1:1 DAR 4:3], 104857 kb/s, 25 fps, 25 tbr, 90k tbn`
- `Stream #0:0: Video: mjpeg (Baseline) (MJPG / 0x47504A4D), yuvj422p(pc, bt470bg/unknown/unknown), 640x480, 15379 kb/s, 30 fps, 30 tbr, 30 tbn`
- `Stream #0:0[0x1](eng): Video: h263 (s263 / 0x33363273), yuv420p, 176x144 [SAR 12:11 DAR 4:3], 96 kb/s, 15.27 fps, 15.42 tbr, 15750 tbn (default)`
2025-05-15 19:44:37 +05:30
ashilkn
a101dba6cd Defer loading of contacts section in shared collections tab until the tab is in view for atleast 500ms. This is to avoid work at app start 2025-05-15 19:11:30 +05:30
Prateek Sunal
491de296ca feat: similar UI's for all the widgets 2025-05-15 18:18:42 +05:30
Laurens Priem
ab2719a79c [mob][photos] Show detected faces with lower score on UI (#5922)
## Description

## Tests
2025-05-15 17:35:27 +05:30
ashilkn
a614636789 Avoid computing data for contacts section for the search tab since it has been moved temporarily to the shared collections tab 2025-05-15 17:23:35 +05:30
laurenspriem
48e9032ac1 Better align widget 2025-05-15 17:20:59 +05:30
Manav Rathi
1d2e18444c sync 2025-05-15 17:10:30 +05:30
laurenspriem
7f9e01a841 Clearly log low face scores from file info 2025-05-15 16:58:40 +05:30
laurenspriem
6933c77f36 Clearly mark face info as debug only 2025-05-15 16:50:41 +05:30
laurenspriem
61cacdddc0 Set face score limit for UI to 0.7 2025-05-15 16:49:09 +05:30
Manav Rathi
936d578093 Rename 2025-05-15 16:41:50 +05:30
Manav Rathi
167a81f121 Swap 2025-05-15 16:39:14 +05:30
Manav Rathi
b550ee6b15 Alt 2025-05-15 16:39:14 +05:30
Manav Rathi
54feb7b2f9 sv 2025-05-15 16:39:14 +05:30
Manav Rathi
f9dad575ec keep both types of checks 2025-05-15 16:39:14 +05:30
Manav Rathi
a39948ccc3 Move 2025-05-15 16:39:14 +05:30
Manav Rathi
dfabd648d5 Alt 2025-05-15 16:39:14 +05:30
Manav Rathi
21e5bbb0fd Outline 2025-05-15 16:39:14 +05:30
Manav Rathi
10a0165a0f check 2025-05-15 16:39:13 +05:30
Aman Raj Singh Mourya
07c640cf90 refractor: extract string + code refractor and improvements 2025-05-15 16:33:16 +05:30
Prateek Sunal
9fa13508b8 feat: add iOS widgets 2025-05-15 16:26:16 +05:30
Aman Raj Singh Mourya
1c099a60e8 refactor: use params to store resultCollections 2025-05-15 16:25:52 +05:30
Ashil
efbdaef9ce [mob] Fix: Enable delinking email from person with no face (#5897)
## Description

When email is is linked to person that doesn't contain any file, there's
no way to unlink the email from that person.
Instead of showing generic error, added an option to edit the other
person so that users can delink the email id.

## Tests
Tested locally.
2025-05-15 15:36:22 +05:30
Manav Rathi
65ddea0f7f [desktop] Use correct unit for bitrate (#5919) 2025-05-15 15:27:20 +05:30
Neeraj
ed15b47f1b [mobile] New translations (#5918)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-15 15:26:56 +05:30
Crowdin Bot
6496660718 New Crowdin translations by GitHub Action 2025-05-15 09:54:04 +00:00
Neeraj Gupta
691d31d0a9 Fix lint 2025-05-15 15:21:42 +05:30
Manav Rathi
1f40901fd1 [desktop] Use correct unit for bitrate 2025-05-15 15:21:18 +05:30
Neeraj Gupta
4982c1209e Extract strings 2025-05-15 15:14:18 +05:30
laurenspriem
9170c80b26 Fix constructor 2025-05-15 14:18:46 +05:30
Neeraj Gupta
1b4cb2ed99 Handle existing link error for person update 2025-05-15 13:51:13 +05:30
Neeraj Gupta
45fe850afc Merge branch 'main' into emailAlreadyRegistered 2025-05-15 13:49:38 +05:30
Neeraj Gupta
6ae8abb492 Bump version v1.0.13 2025-05-15 10:47:45 +05:30
Neeraj Gupta
f077213c62 Merge branch 'main' into album_UI_revamp 2025-05-15 10:46:26 +05:30
Neeraj
92a8db53bd [mob][auth] Fix: respect system locale preference (#5916)
## Description
Fixes https://github.com/ente-io/ente/issues/5655
## Tests
2025-05-15 10:34:53 +05:30
Neeraj Gupta
c812b80887 [mob][auth] Fix: respect system local preference 2025-05-15 10:22:48 +05:30
Aman Raj Singh Mourya
62c1f0c6ac fix: merge conflict 2025-05-15 10:17:53 +05:30
Aman Raj Singh Mourya
cc486983ab Merge branch 'main' into album_UI_revamp 2025-05-15 10:14:40 +05:30
Ashil
a103bd4cca [mob][photos] Wrap EnteLoadingWidget with RepaintBoundary to avoid unnecessary repaints (#5915) 2025-05-15 09:11:29 +05:30
ashilkn
c56d9b312d Wrap EnteLoadingWidget with RepaintBoundary to avoid unnecessary repaints 2025-05-15 08:39:47 +05:30
Manav Rathi
6dda5d8762 [web] [desktop] Routine dependency updates (#5914) 2025-05-15 08:25:32 +05:30
Manav Rathi
3e9d78c866 Routine dependency updates 2025-05-15 08:19:21 +05:30
Manav Rathi
c3eb55b258 [desktop] Enable HLS generation for internal users (#5913) 2025-05-15 07:49:41 +05:30
Manav Rathi
0666bf56df [desktop] Enable HLS generation for internal users 2025-05-15 07:45:39 +05:30
Manav Rathi
fcd8298e10 [web] Handle video durations - WIP (#5910)
The change is complete, but currently only enabled for internal users.
2025-05-14 19:57:39 +05:30
Manav Rathi
62bd2d13d6 Match the web behaviour for sub seconds ceil 2025-05-14 18:55:30 +05:30
Manav Rathi
4263906c61 node impl 2025-05-14 18:40:56 +05:30
Manav Rathi
72acefadd4 node 2 2025-05-14 17:04:39 +05:30
Manav Rathi
2be8db783c node 1 2025-05-14 16:54:45 +05:30
Manav Rathi
f8e90e765f web side 2025-05-14 16:46:47 +05:30
Manav Rathi
9424d26f55 Show 2025-05-14 16:21:01 +05:30
Manav Rathi
bb352f3266 mobile compat 2025-05-14 15:43:32 +05:30
Neeraj
85d55c7d26 [mob] Fix: Show switch stream options for shared video files (#5908)
## Description
- This change also fixes the issue where switch stream option wasn't
available when local video streaming was disabled.
- Also cleaned up the widget by removing queue/processing relate state
from the widget.

## Tests
2025-05-14 15:42:42 +05:30
Manav Rathi
6062c20251 Attach 2025-05-14 15:29:52 +05:30
Neeraj Gupta
8861e0562f rename 2025-05-14 15:24:06 +05:30
Manav Rathi
5e4de0793a json
a sample file (ElephantsDream.mp4, might be obtainable online) was causing the
string based duration format to fail, but is working with the json variant
2025-05-14 15:23:35 +05:30
Neeraj Gupta
80d36b5a91 Show switch stream options for shared files 2025-05-14 15:22:51 +05:30
Prateek Sunal
f22ad9611f feat: populate people as well 2025-05-14 15:14:11 +05:30
Neeraj
8e038dda14 [mob] Show person's name for shared fav collection (#5905)
## Description

## Tests
2025-05-14 14:42:22 +05:30
Prateek Sunal
9cafa72ae3 fix: add color scheme based icon 2025-05-14 14:01:25 +05:30
Neeraj
a5eba40f29 [mob] Increase resumable upload rollout 20 -> 50% (#5907)
## Description

## Tests
2025-05-14 13:57:05 +05:30
Prateek Sunal
0c9d7321eb fix: nominal display limit count & disable show create album 2025-05-14 13:52:13 +05:30
Neeraj Gupta
d98d220019 Increase resumable upload rollout 20 -> 50% 2025-05-14 13:51:45 +05:30
Prateek Sunal
5fc5d0ef48 feat: add initial album grid and save button 2025-05-14 13:48:08 +05:30
Neeraj Gupta
ce6b0da630 Show person's name for shared fav collection 2025-05-14 12:51:15 +05:30
Manav Rathi
d1d91338af Dur 1 2025-05-14 12:47:09 +05:30
Manav Rathi
790c022730 Impl 2025-05-14 12:39:28 +05:30
Manav Rathi
be65f0fba8 tailored log
inputPath is a random id in this context and doesn't provide any extra info
2025-05-14 12:20:21 +05:30
Manav Rathi
3677d53ea9 Sketch 2025-05-14 12:14:48 +05:30
Prateek Sunal
84017c7397 Merge remote-tracking branch 'origin/memories_widget_api' into widget-superpowered 2025-05-14 12:13:06 +05:30
Manav Rathi
f92101eaf8 Outline 2025-05-14 11:57:57 +05:30
mangesh
1d3ca81308 [docs] clarifying instructions about admin actions for CLI (#5848) 2025-05-14 11:55:12 +05:30
Manav Rathi
e9f22cff93 case 2025-05-14 11:31:48 +05:30
Prateek Sunal
e250759999 Merge remote-tracking branch 'origin/album_grid_UI' into widget-superpowered 2025-05-14 11:21:50 +05:30
Neeraj
d5740c4b66 [server] Version check support during ml data put (#5895)
## Description

## Tests
2025-05-14 10:56:36 +05:30
Manav Rathi
07bd28381d [web] Use wasm workerfs to directly mount blob instead of reading it in memory (#5904)
https://emscripten.org/docs/api_reference/Filesystem-API.html#workerfs
2025-05-14 10:45:48 +05:30
Manav Rathi
8c8c9d7ffa Use workerfs to directly mount blob instead of reading it in memory 2025-05-14 10:27:37 +05:30
Neeraj Gupta
d06016dddc Update status code 2025-05-14 10:02:54 +05:30
Manav Rathi
f4531ef088 [desktop] Don't mark indexing failures on 409s (#5903) 2025-05-14 10:01:45 +05:30
Manav Rathi
56772521e0 Don't mark failures on 409s 2025-05-14 09:49:52 +05:30
Neeraj Gupta
244ec87a9a Rename 2025-05-14 09:40:57 +05:30
Manav Rathi
043d0936ef [desktop] Incorporate mldata version check (#5900)
Ref: https://github.com/ente-io/ente/pull/5895
2025-05-14 09:07:44 +05:30
Manav Rathi
9129910981 [web] Potential fix for pin order not being maintained (#5902) 2025-05-13 19:41:40 +05:30
Manav Rathi
4194c53d08 [web] Potential fix for pin order not being maintained 2025-05-13 19:32:07 +05:30
Manav Rathi
9d5960c6fe [desktop] Incorporate mldata version check 2025-05-13 18:35:45 +05:30
Aman Raj Singh Mourya
f088c24abe refactor: remove debug print statements 2025-05-13 18:15:35 +05:30
Aman Raj Singh Mourya
e197423c1d fix: fixed album list opening scrolled down & increase bottom padding 2025-05-13 18:10:38 +05:30
Neeraj Gupta
b22bc93e57 Send updatedAt along with fileData 2025-05-13 18:01:19 +05:30
Manav Rathi
236301dc16 [desktop] Video generation integration - WIP Part x/x (#5896) 2025-05-13 17:22:22 +05:30
Manav Rathi
b4a60fd2f4 empty state 2025-05-13 17:17:38 +05:30
Neeraj Gupta
079ac37d1f Fix lint 2025-05-13 17:15:30 +05:30
Neeraj Gupta
3deb138b77 Fix: Enable delinking email from person with no face 2025-05-13 17:04:11 +05:30
Manav Rathi
5b9b328c99 Tweak 2025-05-13 16:51:33 +05:30
Manav Rathi
e541f0522d skip case 2025-05-13 16:44:55 +05:30
Manav Rathi
93413687c9 hs 2025-05-13 16:11:14 +05:30
Neeraj
48ef4df187 [mob] Fix date-formatting as per device locale (#5894)
## Description
- For language only match, instead of returning supported locale which
many times doesn't have country code, we are now falling back to system
locale. So for en_GB, the auto-detected locale will be `en_GB` instead
of just `en`.

Fixes https://github.com/ente-io/ente/issues/5120


## Tests
- Verified that the app was translated in Spanish with `es_US`.
- Verified that date-formatting is as per device locale (at least on
birthday date picker & edit time dialog)
2025-05-13 15:20:35 +05:30
Manav Rathi
96d748dc87 status 2025-05-13 15:17:52 +05:30
Neeraj Gupta
9d28fa99a3 Version check support during ml data put 2025-05-13 15:09:55 +05:30
Neeraj Gupta
f9cce787f7 Remove log 2025-05-13 14:26:54 +05:30
Manav Rathi
dcc02db296 init 2025-05-13 14:26:53 +05:30
Neeraj Gupta
c0fd71a668 Fix: fallback to device locale on language only match 2025-05-13 14:25:20 +05:30
Manav Rathi
116f22a853 vis 2025-05-13 13:57:14 +05:30
Neeraj
501b541134 [mob] Cache video streams for shared files (#5892)
## Description
Title

## Tests
- Verified from logs that shared stream videos are getting cached
correctly.
2025-05-13 13:52:44 +05:30
laurenspriem
1785baf4af method for memories widget 2025-05-13 13:33:31 +05:30
Neeraj Gupta
b08d8de1c8 Fix date formatting in edit time 2025-05-13 13:25:46 +05:30
Manav Rathi
0284287c9c toggle 2025-05-13 13:14:14 +05:30
Manav Rathi
be2665f57f Set sv = 1 for files that are skipped 2025-05-13 12:29:17 +05:30
Neeraj Gupta
b721a84889 Fix date format in birthday date-picker 2025-05-13 12:28:34 +05:30
Manav Rathi
442d6526be sopt color
something (I'm not sure what, but I think react-select itself) overrides the
color for the option's root element to white when displaying the search bar on
the search results screen itself. as a workaround, provide a explicit color to
the text.

steps to reproduce (light mode):
- search for something (all options look normal)
- select an option
- search for something on this results screen itself
- note how the search options titles are in white
2025-05-13 11:47:54 +05:30
Manav Rathi
08346e5bcd it was already revoking 2025-05-13 11:36:00 +05:30
Manav Rathi
e35b4eac40 Refill queue even after first refill 2025-05-13 11:29:50 +05:30
Manav Rathi
7c6da77c21 [desktop] Video generation integration - WIP Part x/x (#5891) 2025-05-13 11:17:14 +05:30
Neeraj Gupta
ab59a15769 Remove internal user flag 2025-05-13 11:07:53 +05:30
Neeraj Gupta
45e07f3be0 Improve video caching + cache shared videos 2025-05-13 11:00:40 +05:30
Manav Rathi
a2df4fb48a impl 2025-05-13 10:57:43 +05:30
Manav Rathi
5a2ba82fff return current state instead of original state on errors
this should be a more graceful behaviour on errors
2025-05-13 10:46:29 +05:30
Manav Rathi
6a907d0f7d wip 1 2025-05-13 10:43:05 +05:30
Manav Rathi
20dfec2e67 Outline 2025-05-13 10:32:06 +05:30
Manav Rathi
96c3880e38 filter files in trash 2025-05-13 10:20:42 +05:30
Manav Rathi
2adabc1e24 fix hydration warning 2025-05-13 10:20:42 +05:30
Manav Rathi
a6ca7a5792 stop unnecessary reindexing on addedSymlink 2025-05-13 10:20:42 +05:30
Manav Rathi
6abea7ae6d Note 2025-05-13 10:20:42 +05:30
Manav Rathi
429b6be368 to db 2025-05-13 10:20:42 +05:30
Manav Rathi
ed9af710fe doc 2025-05-13 10:20:42 +05:30
Manav Rathi
f8ef263e6d own 2025-05-13 10:20:42 +05:30
Manav Rathi
fae47f102e mark 2025-05-13 10:20:42 +05:30
Manav Rathi
240bfdd296 ret 2025-05-13 10:20:41 +05:30
Neeraj Gupta
672123d746 Remove duplicate logic 2025-05-13 10:06:59 +05:30
Aman Raj Singh Mourya
51d55ee92b feat: Add new album row item widget and update collections grid view 2025-05-12 22:06:19 +05:30
Manav Rathi
cc3f20831a [server] 204 minor fix (#5886)
- Sibling of https://github.com/ente-io/ente/pull/5880
- Tested using https://github.com/ente-io/ente/pull/5885
2025-05-12 21:58:33 +05:30
Manav Rathi
a282f82909 [web] Use new 204 facility for playlist existence (#5885) 2025-05-12 20:49:57 +05:30
Manav Rathi
2fde22272e [web] Use new 204 facility for playlist existence 2025-05-12 20:45:37 +05:30
Manav Rathi
d63da04392 [server] 204 tweak
- Sibling of https://github.com/ente-io/ente/pull/5880
- Tested using https://github.com/ente-io/ente/pull/5885
2025-05-12 20:42:12 +05:30
Aman Raj Singh Mourya
7cd3f8e2ac [mob][photos] feat: show albums shared by contact in contact section 2025-05-12 20:12:45 +05:30
Manav Rathi
9517514396 [web] Add workaround for Safari live photo download (#5884)
Tested on Safari (obv) and Chrome.
2025-05-12 19:46:24 +05:30
Manav Rathi
41a4f3d286 [web] Add workaround for Safari live photo download 2025-05-12 19:39:19 +05:30
Prateek Sunal
91fefa7eb9 feat: memories leading icons 2025-05-12 19:12:46 +05:30
Prateek Sunal
63b9a09a2d feat: init widgets settings and default states
Next: Add Grid, make things dynamic, Add sync logic and native code
2025-05-12 19:07:58 +05:30
Neeraj
d1a2efff0e [server] Sending 204 instead of 404 for no data (#5880)
## Description

## Tests
2025-05-12 16:59:44 +05:30
Laurens Priem
00d723ca7c [infra] github actions internal release with rust (#5879)
## Description

Add Github Action for mobile release that includes the use of rust
2025-05-12 16:54:25 +05:30
Neeraj Gupta
47b2e0d0ab Sending 204 instead of 404 for no data 2025-05-12 16:53:24 +05:30
laurenspriem
ac9dbd4ee1 github actions internal release with rust 2025-05-12 16:50:49 +05:30
Prateek Sunal
8b6f6346be [workflow](auth-release) separate checksum as *-linux & *-apk (#5878)
## Description

After last change the checksum name also need to changed to suffice the
new files and the unified ubuntu workflow. Here I am modifying the
checksum so that there are two different versions, one for linux related
binaries and another for the solo apk file.

## Tests
2025-05-12 15:13:33 +05:30
Prateek Sunal
73ad6b45fb fix(workflow): separate checksum to two 2025-05-12 15:07:45 +05:30
Neeraj
020f8cea23 [mob] Play streamable video whenever available (#5877)
## Description
- This PR removes the check for local streaming video settings
- [Internal users] added support for playing video stream for shared
files.
In order to cache the playlist and encrypted video stream, we will need
make backend API changes. Once those are done, we will remove the
internal user flag.
## Tests
2025-05-12 15:07:32 +05:30
Prateek Sunal
d52accdcc9 fix: typo 2025-05-12 15:04:54 +05:30
Neeraj Gupta
975c7ae8d1 Fix typo 2025-05-12 15:03:30 +05:30
Neeraj Gupta
c4463d6251 Fix lint 2025-05-12 15:00:47 +05:30
Neeraj Gupta
e96888d2c9 Reduce ffprobe log noise in debugMode 2025-05-12 14:51:38 +05:30
Neeraj Gupta
03df804868 Restrict shared file preview playback to internal users 2025-05-12 14:49:25 +05:30
Neeraj Gupta
685e0099c8 Support for playing preview of shared files 2025-05-12 14:32:47 +05:30
Neeraj Gupta
4a924a7296 Remove check for local setting 2025-05-12 13:41:27 +05:30
Neeraj Gupta
1f4beab764 Copy update 2025-05-12 13:39:04 +05:30
Neeraj Gupta
4fd121adf1 Play video stream regardless of generate setting 2025-05-12 13:36:52 +05:30
Manav Rathi
a942e68d27 [web] Support Turkish translations (#5875) 2025-05-12 13:23:35 +05:30
Neeraj
ece63f7a8d [server] Improve handling of errors (#5860)
## Description

## Tests
2025-05-12 13:18:01 +05:30
Neeraj
dcdc26e4e8 [auth] New translations (#5873)
New translations from
[Crowdin](https://crowdin.com/project/ente-authenticator-app)
2025-05-12 13:16:39 +05:30
Neeraj
ffa8ccd0d3 [mobile] New translations (#5872)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-12 13:16:19 +05:30
Manav Rathi
01f612e450 [web] Support Turkish translations 2025-05-12 10:58:42 +05:30
Vishnu Mohandas
70f80c7b57 [auth] Auth reorder widgets (#5869)
![image](https://github.com/user-attachments/assets/60752fe9-7c3d-402f-a92f-7a454c191b79)
2025-05-12 10:01:44 +05:30
Manav Rathi
ab875683ed [web] New translations (#5874)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-12 09:39:20 +05:30
Crowdin Bot
638108a819 New Crowdin translations by GitHub Action 2025-05-12 03:38:14 +00:00
Manav Rathi
dec193599f [web] Tweak error message (#5854) 2025-05-12 09:07:37 +05:30
Manav Rathi
4913746a31 [web] New translations (#5871)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-web)
2025-05-12 09:07:09 +05:30
Crowdin Bot
0966ab7d19 New Crowdin translations by GitHub Action 2025-05-12 01:17:45 +00:00
Crowdin Bot
83ae436008 New Crowdin translations by GitHub Action 2025-05-12 01:05:08 +00:00
Crowdin Bot
8f2a2caac1 New Crowdin translations by GitHub Action 2025-05-12 00:41:04 +00:00
Aman Raj Singh Mourya
7cc6319d5f feat: Extract strings 2025-05-12 00:50:01 +05:30
Aman Raj Singh Mourya
eabe213207 fix: Reorder advance option widget 2025-05-12 00:41:04 +05:30
Bl4ckspell
5b7f821a26 [auth] Add Bitazza icon (#5866)
## Description
New PR with updated icon for #5757 - Add Bitazza icon

<img
src="https://github.com/user-attachments/assets/085830d4-9ed6-4ddc-95f4-434412f8f045"
width="100" />
2025-05-11 10:29:32 +05:30
Neeraj
939ab4398c [mob] Enable sharing for fav collection (#5863)
## Description

## Tests
2025-05-10 08:12:13 +05:30
Neeraj Gupta
c4effd4ef4 Enable sharing for fav collection 2025-05-10 08:11:32 +05:30
Neeraj
bcf1a044cc [server] Enable sharing for fav (#5861)
## Description

## Tests
2025-05-10 07:34:33 +05:30
Neeraj Gupta
2dd9a080c6 Enable sharing for fav 2025-05-10 07:34:06 +05:30
Neeraj Gupta
57a4e6dd15 Update err copy 2025-05-10 07:26:44 +05:30
Neeraj Gupta
93cd2d30e4 Improve handling for ott errors 2025-05-10 07:22:28 +05:30
Neeraj Gupta
f65db123f2 Refactor 2025-05-10 07:12:01 +05:30
Neeraj Gupta
d697f22896 Improve SRP response 2025-05-10 07:01:39 +05:30
Neeraj Gupta
65faa98621 Move to util 2025-05-10 06:27:25 +05:30
Manav Rathi
e4a0125f1c [desktop] Streaming video generation - WIP Part x/x (#5857) 2025-05-09 19:08:38 +05:30
Manav Rathi
98d06f975c f2 2025-05-09 19:03:03 +05:30
Manav Rathi
d0ebe65af4 f1 2025-05-09 18:54:22 +05:30
Manav Rathi
08d936be45 1 2025-05-09 18:42:50 +05:30
Manav Rathi
71596ebd8e update 2025-05-09 18:05:14 +05:30
Manav Rathi
8ededf54c7 sync 2025-05-09 17:58:02 +05:30
Manav Rathi
0520fcd7ec outline 2025-05-09 17:58:02 +05:30
Manav Rathi
b6173d6c1b sync 2025-05-09 17:58:02 +05:30
Manav Rathi
6fa07e12db pag 2025-05-09 17:58:02 +05:30
Manav Rathi
804dacef91 diff 1 2025-05-09 17:58:02 +05:30
Manav Rathi
97350005c9 Outline 2025-05-09 17:58:02 +05:30
Manav Rathi
5f36a23f4e Remove double replenish 2025-05-09 17:58:02 +05:30
Vishnu Mohandas
d336541d2c [docs] Fix typo (#5856) 2025-05-09 16:28:35 +05:30
Vishnu Mohandas
780ea55ca8 [docs] Fix typo 2025-05-09 16:28:20 +05:30
Neeraj Gupta
38663088b1 Move to util 2025-05-09 15:49:20 +05:30
Neeraj
eb9987d2c0 [server] Reduce alert noise (#5855)
## Description

## Tests
2025-05-09 14:37:20 +05:30
Neeraj Gupta
cf4084380c Throttle discord alerts 2025-05-09 14:28:22 +05:30
Manav Rathi
691469ef5e scope 2025-05-09 14:04:50 +05:30
Manav Rathi
8106bc6940 [web] Tweak error message 2025-05-09 14:04:50 +05:30
Neeraj
deb68d5cfc [server] Improve logs (#5853)
## Description

## Tests
2025-05-09 14:02:59 +05:30
mngshm
f4e158dab6 clarifying instructions about admin actions for CLI 2025-05-08 17:45:57 +05:30
Manav Rathi
e8b0d9c25b [web] Fix duplicate display of neighbour when deleting slide (#5847) 2025-05-08 16:53:13 +05:30
Manav Rathi
43ce9edb95 Make it work when deleting the last slide in the list 2025-05-08 16:47:56 +05:30
Manav Rathi
3b4c7095c4 [web] Fix duplicate display of neighbour when deleting slide 2025-05-08 16:32:22 +05:30
Manav Rathi
d95bb0785f [desktop] Move ffmpeg processing to a (node) worker (#5846)
Smoother app during HLS gen
2025-05-08 15:15:00 +05:30
Manav Rathi
d53281500b prune 2025-05-08 15:05:56 +05:30
Manav Rathi
44199093f0 Enable 2025-05-08 15:02:07 +05:30
Manav Rathi
18442e25fc Move upload to utility process
Attempt to further lighten the load on the main thread
2025-05-08 14:53:05 +05:30
Neeraj
0fa7245144 [server] Fix invalid 5xx error for bad requests (#5842)
## Description

## Tests
Tested locally
2025-05-08 13:52:15 +05:30
Neeraj
4fc7347cb7 docs-edit file limit (#5844)
## Edit file constraints

## Tests
2025-05-08 13:11:38 +05:30
Jay
4840a44c4d docs-edit file limit 2025-05-08 13:08:23 +05:30
Prateek Sunal
109ac573c9 [mob] remove NativeAdapter to support big file upload (#5843)
## Description

Big file uploads fail when using NativeAdapter, this PR:
- [x] Removes NativeAdapter http client adapter

## Tests
2025-05-08 12:45:53 +05:30
Prateek Sunal
23559252e6 chore: bump version 2025-05-08 12:45:22 +05:30
Prateek Sunal
31b31b1a52 chore: lint update 2025-05-08 12:45:11 +05:30
Prateek Sunal
8333e2ad7b fix: not remove it for enteDio 2025-05-08 12:42:59 +05:30
Prateek Sunal
cb5c9f3170 chore: lint fix 2025-05-08 12:38:58 +05:30
Prateek Sunal
7b2e6cb1bd fix(network): remove NativeAdapter to support big file upload 2025-05-08 12:38:42 +05:30
Neeraj
d18d939489 [mob] Navigate to BackupSettings when tapping "Waiting for network" status (#5835)
## Description

## Tests
2025-05-08 11:28:59 +05:30
Neeraj Gupta
b3376f27aa Fixed typo 2025-05-08 11:27:01 +05:30
Neeraj Gupta
327bda5b30 Log validationErr details as warning 2025-05-08 11:20:53 +05:30
Neeraj Gupta
c3b1da2a7e Fix handling of unwrapped error 2025-05-08 11:19:57 +05:30
Vishnu Mohandas
f238b55df3 [docs] env, ports and more docs in /self-hosting (#5823) 2025-05-07 19:10:54 +05:30
mngshm
d15a034869 consistency (2) 2025-05-07 19:09:07 +05:30
mngshm
7b3ae417e8 consistency 2025-05-07 18:56:00 +05:30
Manav Rathi
d35f898b70 better way of dealing with undefs
Electron postMessage wants an empty array and balks at undefined
2025-05-07 18:10:18 +05:30
Manav Rathi
6730c0c682 take 1 - fix sporadic unhandled exception
With extra logging, this is it:

    adapter postMessage {
      id: '12c1c688f6f7b4-4e5fd44d3b9bc-f746fb2a0beda-1b0c26213b6237',
      type: 'RELEASE'
    } undefined
    [error] Unhandled rejection: TypeError: transferables must be an array of MessagePorts
    TypeError: transferables must be an array of MessagePorts
        at MessagePortMain.postMessage (node:electron/js2c/browser_init:2:111057)
        at Object.postMessage (...desktop/app/main/utils/comlink.js:21:16)
        at .../desktop/node_modules/comlink/dist/umd/comlink.js:353:16
        at new Promise (<anonymous>)
        at requestResponseMessage (../desktop/node_modules/comlink/dist/umd/comlink.js:347:16)
        at releaseEndpoint (.../desktop/node_modules/comlink/dist/umd/comlink.js:199:16)
        at proxyFinalizers (.../desktop/node_modules/comlink/dist/umd/comlink.js:211:17)
2025-05-07 17:51:42 +05:30
Manav Rathi
c2c7ac8b23 Tweak 2025-05-07 17:08:09 +05:30
Neeraj Gupta
e322958b25 Navigate to BackupSettings when tapping "Waiting for network" status 2025-05-07 16:53:02 +05:30
Neeraj
0d660f239f [mob] Bump version v1.0.9 (#5834)
## Description

Bumping version to prepare for next release.

## Tests
2025-05-07 16:24:46 +05:30
Prateek Sunal
c4a50fc9fb chore: bump version to 1039 2025-05-07 16:15:41 +05:30
Manav Rathi
2f670e316b conv 2025-05-07 14:04:41 +05:30
Manav Rathi
f47a6f7b42 rendezvous 2025-05-07 13:48:23 +05:30
mngshm
8856ad1520 Sidebar 2025-05-07 13:30:40 +05:30
Manav Rathi
3513b51477 trampoline 2025-05-07 13:29:19 +05:30
Manav Rathi
bd8fc08b7c rework 1
temp files will need to be handled on main process
2025-05-07 12:36:55 +05:30
Manav Rathi
ae925a240e fix 2025-05-07 11:58:13 +05:30
Manav Rathi
adf1379b9e node 1 2025-05-07 11:23:28 +05:30
mangesh
e8158ef45a [staff] show family member storage quota (#5770) 2025-05-07 10:55:02 +05:30
Manav Rathi
71d6aed1aa web side 1 2025-05-07 10:30:20 +05:30
Aman Raj Singh Mourya
6627f77d92 [mob][photos] fix: increase bottom padding 2025-05-06 20:36:44 +05:30
Manav Rathi
4fa0bf76e8 [desktop] Generisize the creation of utility processes (#5829)
ffmpeg code about to become one
2025-05-06 18:58:41 +05:30
Manav Rathi
92a9b34836 Generisize 2025-05-06 18:52:03 +05:30
Manav Rathi
10d7162d6e Rename 2025-05-06 18:00:10 +05:30
Manav Rathi
2a1b8ae18e Generalize 2025-05-06 17:39:48 +05:30
Manav Rathi
5abf2cb35e Extract 2025-05-06 17:24:03 +05:30
Manav Rathi
367170be95 [desktop] Video stream generation - WIP Part x/x (#5827) 2025-05-06 17:05:48 +05:30
Manav Rathi
4d7cfee60f Fix slowness 2025-05-06 16:03:13 +05:30
Prateek Sunal
29152d1f85 [mob] bump to 1038 (#5817)
## Description

Bump version to 1038

## Tests
2025-05-06 15:39:25 +05:30
Neeraj
6b4ffa4822 [mob][photos] Fix share to Ente (#5821)
## Description

Fix [issue with sharing to
Ente](https://github.com/ente-io/ente/discussions/5755)

## Tests
2025-05-06 15:38:32 +05:30
Manav Rathi
2883f4bed6 Tweak 2025-05-06 15:08:52 +05:30
laurenspriem
c96275cdd1 Update load message 2025-05-06 14:48:57 +05:30
Manav Rathi
9db8324ffd Sketch 2025-05-06 14:42:23 +05:30
mngshm
0c664b94b9 Make storageLimit nullable and display 'NA' 2025-05-06 14:41:42 +05:30
Manav Rathi
c087e419d5 Outline 2025-05-06 13:00:41 +05:30
mngshm
5ba5cae5ef mark redirection info as IMPORTANT in doc 2025-05-06 12:50:27 +05:30
Manav Rathi
4ea211d923 Sketch interruptible loop 2025-05-06 12:32:57 +05:30
mngshm
8d8202adab Env and Ports 2025-05-06 12:13:48 +05:30
mngshm
267f93e41e Merge branch 'main' into fam 2025-05-06 11:05:10 +05:30
Manav Rathi
260ec952b4 Not needed 2025-05-06 10:14:28 +05:30
Prateek Sunal
5e311c2813 fix: bump to 1038 2025-05-05 20:53:51 +05:30
Prateek Sunal
1d3268916f [mob] fix ffmpeg-kit android compilation (#5813)
## Description

- [x] Fix failing android build
- [x] Don't redirect to Backup Status screen when "Preview Failed"
status is pressed.

## Tests

- [x] Test if app works and everything is fine
2025-05-05 20:23:22 +05:30
Prateek Sunal
73192cd0fd fix: remove unused import and simplify navigation logic in PreviewStatusWidget 2025-05-05 20:21:55 +05:30
Prateek Sunal
9c886b3fa3 fix: update ffmpeg kit resolved reference in pubspec.lock 2025-05-05 20:01:39 +05:30
Prateek Sunal
017832f11e feat: update ffmpeg kit source 2025-05-05 18:38:49 +05:30
Prateek Sunal
67e76bc42f chore: update locals 2025-05-05 18:38:37 +05:30
laurenspriem
9a6579c55c Refactor 2025-05-05 17:30:12 +05:30
laurenspriem
17c0cdef14 Fix backup share issue 2025-05-05 17:21:39 +05:30
mngshm
dd0cc71f36 Minor 2025-05-05 16:37:29 +05:30
mangesh
21fd6ab463 [staff] match title casing to key in the UserData interface (#5812) 2025-05-05 16:36:43 +05:30
mngshm
6e2142c605 match title casing to key in the UserData interface 2025-05-05 16:28:23 +05:30
Manav Rathi
16338682ed [docs] Mention UNC path workaround to create network drive (#5811) 2025-05-05 15:58:05 +05:30
Manav Rathi
a7e8d3dfa6 [docs] Mention UNC path workaround to create network drive 2025-05-05 15:51:03 +05:30
Manav Rathi
6e9014b915 [desktop] Tweak the backfill behaviour in case of transients (#5809) 2025-05-05 15:34:24 +05:30
Neeraj
b5e7a3f83f [mob] Bump version v1.0.7 (#5810)
## Description

## Tests
2025-05-05 15:24:19 +05:30
Neeraj Gupta
d8d76f452d Bump version v1.0.7 2025-05-05 15:23:14 +05:30
Laurens Priem
c2e475c666 Face thumbnail logging (#5808)
## Description

Change logging flow for face thumbnail generation
2025-05-05 15:03:06 +05:30
Manav Rathi
9a4bc898f0 [desktop] Tweak the backfill behaviour in case of transients 2025-05-05 15:02:28 +05:30
laurenspriem
ca92aa8c62 Include delay 2025-05-05 14:59:53 +05:30
laurenspriem
56c6d7ed3c Remove redundant reset 2025-05-05 14:49:57 +05:30
mangesh
6ee4bce676 Merge branch 'main' into fam 2025-05-05 14:47:44 +05:30
laurenspriem
ff3f01af56 Increase queue size 2025-05-05 14:47:05 +05:30
Laurens Priem
b5ba81e22b [mob][photos] Fix memories update regression (#5807)
## Description

Fixed regression in memories update scheme.
2025-05-05 14:23:04 +05:30
laurenspriem
d5aab7c6df Fix memories update regression 2025-05-05 14:18:58 +05:30
Manav Rathi
2749457611 [web] Ensure copy as PNG option is reset when we get the original (#5806)
Fixes: https://github.com/ente-io/ente/discussions/5802
2025-05-05 14:02:22 +05:30
Manav Rathi
883b14e96a [web] Ensure copy as PNG option is reset when we get the original
Fixes: https://github.com/ente-io/ente/discussions/5802
2025-05-05 13:58:13 +05:30
Neeraj
59d7e0acac [mobile] New translations (#5799)
New translations from
[Crowdin](https://crowdin.com/project/ente-photos-app)
2025-05-05 13:39:10 +05:30
Neeraj
68ac3503ed [server] Use access ctrl for verifying access (#5801)
## Description

## Tests
2025-05-05 13:33:26 +05:30
mngshm
58649db181 fix Linters in UpdateSubscription Component 2025-05-05 13:25:21 +05:30
mangesh
92ca4eeb15 [staff] consolidate and separate interfaces (#5765)
The codebase was too cluttered with interfaces spread all over the
codebase. Separated all the commonly usable types into a single
`types/index.ts` file. Some types which are only usable in that
particular component are left untouched.

P.S: Inspiration from families codebase.
2025-05-05 13:21:12 +05:30
Manav Rathi
d3e06e6cc9 [web] Ensure ellipsizing of caption (#5805)
`text-align: right` causes the ellipsizing to sometimes work, sometimes
not, depending on the exact contents of the line (tested in current
Chrome). Tweak the design to work with the normal text align to try and
ensure the elision is always ellipsized.
2025-05-05 13:19:22 +05:30
Manav Rathi
3cef3e9bdc [web] Ensure ellipsizing of caption
`text-align: right` causes the ellipsizing to sometimes work, sometimes not,
depending on the exact contents of the line (tested in current Chrome). Tweak
the design to work with the normal text align to try and ensure the ellision is
always ellipsized.
2025-05-05 13:12:58 +05:30
mangesh
d318952feb [quickstart] Gracefully handle case when docker compose is not present (#5804)
When docker is present but docker compose is not present, the `docker
compose` invocation would fail. We want the early exit (`set -e`), so
instead do a fallback to set dcv to an empty string so that it later
fails in the `test -z dcv` case below and prints the intended error
message.
2025-05-05 13:08:49 +05:30
Manav Rathi
6d8051dfa0 [quickstart] Gracefully handle case when docker compose is not present
When docker is present but docker compose is not present, the `docker compose`
invocation would fail. We want the early exit (`set -e`), so instead do a
fallback to set dcv to an empty string so that it later fails in the `test -z
dcv` case below and prints the intended error message.
2025-05-05 12:37:48 +05:30
Neeraj Gupta
d198f0c273 Use access ctrl for verifying access 2025-05-05 10:01:33 +05:30
Crowdin Bot
a88249de09 New Crowdin translations by GitHub Action 2025-05-05 01:05:08 +00:00
Aman Raj Singh Mourya
14b70ce66e Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-05-01 10:15:12 +05:30
Aman Raj Singh Mourya
d9a5fbfe00 [mob][photos] implemented new sorting order for contact section 2025-05-01 10:14:54 +05:30
mngshm
0a3abb20a1 making linters happy 2025-04-30 20:10:29 +05:30
mngshm
9f9288a5c0 show family member storage quota 2025-04-30 19:59:11 +05:30
mngshm
100c1d3803 use nullish coalescing to avoid optional chaining 2025-04-30 15:57:24 +05:30
mngshm
408cc05f7c fix: usage conversion import 2025-04-30 15:28:36 +05:30
mngshm
9f70aab9b5 refactor: consolidate and separate interfaces 2025-04-30 15:24:51 +05:30
Neeraj Gupta
f816166743 Fix translation file 2025-04-28 09:26:57 +05:30
Neeraj Gupta
3aba4fad47 Bump version for droid internal release 2025-04-28 09:25:15 +05:30
Neeraj Gupta
60137585d1 Merge remote-tracking branch 'origin/main' into album_UI_revamp 2025-04-28 09:24:37 +05:30
Aman Raj Singh Mourya
59316c263f [mob][photos] fix: Reduce main axis spacing from 4px -> 2px 2025-04-25 22:39:20 +05:30
Aman Raj Singh Mourya
44682404ff Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-25 21:48:57 +05:30
Aman Raj Singh Mourya
83c864df2b [mob][photos] minor fix 2025-04-25 21:41:06 +05:30
Neeraj Gupta
184882fae2 Bump version for droid internal release 2025-04-25 16:16:10 +05:30
Neeraj Gupta
e59e600a35 Merge branch 'album_UI_revamp' of https://github.com/ente-io/auth into album_UI_revamp 2025-04-25 16:14:57 +05:30
Neeraj Gupta
6f5c5a0b06 Merge branch 'main' into album_UI_revamp 2025-04-25 16:14:32 +05:30
Aman Raj Singh Mourya
3d4ff93e65 [mob][photos] Move Contacts section from search tab to shared tab 2025-04-25 16:11:02 +05:30
Aman Raj Singh Mourya
d88621ab5a [mob][photos] feat: implement ascending/descending sort direction 2025-04-25 15:52:09 +05:30
Aman Raj Singh Mourya
95e6a86b10 [mob][photos] feat: update sharing functionality improve UI flow 2025-04-25 15:45:38 +05:30
Aman Raj Singh Mourya
e5d63fe9e7 [mob][photos] feat: enable selection on album screen itself 2025-04-25 12:57:27 +05:30
Aman Raj Singh Mourya
1265002d5a Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-24 02:32:20 +05:30
Aman Raj Singh Mourya
c7aecc9b30 [mob][photos] minor fix 2025-04-24 02:31:24 +05:30
Aman Raj Singh Mourya
dba837c62c [mob][photos] refactor: allow favourite album selection for better UX 2025-04-24 02:31:10 +05:30
Aman Raj Singh Mourya
e5bdd74fa9 [mob][photos] refractor: update icon colors to use blurStrokePressed 2025-04-24 01:14:33 +05:30
Aman Raj Singh Mourya
0f31278965 [mob][photos] refactor: remove create album option and update item limit count 2025-04-23 22:24:49 +05:30
Neeraj Gupta
be3e434bec Bump version 2025-04-23 14:46:54 +05:30
Aman Raj Singh Mourya
9d9a7b548d [mob][photos] minor fix 2025-04-23 13:53:54 +05:30
Aman Raj Singh Mourya
3708819e6b Merge branch 'album_UI_revamp' of https://github.com/ente-io/ente into album_UI_revamp 2025-04-23 13:32:30 +05:30
Aman Raj Singh Mourya
389220357e [mob][photos] feat: enable album selection actions for incoming collections 2025-04-23 13:31:56 +05:30
Neeraj Gupta
d9925f29d8 Merge branch 'main' into album_UI_revamp 2025-04-23 13:14:58 +05:30
Aman Raj Singh Mourya
0dab15b703 [mpb][photos] feat: collections and optimize grid/list item rendering 2025-04-22 13:02:04 +05:30
Aman Raj Singh Mourya
2449dbe0cd [mob][photos] feat: update selection logic to exclude favorite collections from actions 2025-04-22 12:42:40 +05:30
Aman Raj Singh Mourya
7f96a11e07 [mob][photos] refactor: remove debug print statements and update parameter naming 2025-04-21 10:18:44 +05:30
Aman Raj Singh Mourya
d7cb5c29cf [mob][photos] feat: reflect SelectAll action change on UI 2025-04-21 10:18:05 +05:30
Aman Raj Singh Mourya
399ecdfd7d [mob][photos] feat: support for multiple selected albums and add SelectAllAlbumsButton 2025-04-21 10:17:12 +05:30
Aman Raj Singh Mourya
f4580c8fdf [mob][photos] feat: add support for sharing and deleting multiple collections with action sheets 2025-04-19 21:45:49 +05:30
Aman Raj Singh Mourya
13f78ecc19 [mob][photos] feat: enhance AddParticipantPage to support multiple collections and update album selection actions 2025-04-19 21:43:01 +05:30
Aman Raj Singh Mourya
9267c4012b feat: integrate album selection management into collection list and flex grid views 2025-04-19 00:14:54 +05:30
Aman Raj Singh Mourya
a8e80717aa [mob][photos] fix: use selected albums for showing selected/unselected state 2025-04-19 00:14:34 +05:30
Aman Raj Singh Mourya
8e552c57bb [mob][photos] feat: implement album selection management and action overlay components 2025-04-19 00:13:10 +05:30
Aman Raj Singh Mourya
28f03d3514 [mob][photos] feat: add searchable app bar and enhance collection filtering 2025-04-16 00:27:10 +05:30
Aman Raj Singh Mourya
c7047ab964 [mob][photos] feat: support album sorting by name and newest photo for shared albums 2025-04-15 22:40:25 +05:30
Aman Raj Singh Mourya
daa3fcd354 [mob][photos] fix: hide "add new album" options when any album is selected 2025-04-15 19:17:02 +05:30
Aman Raj Singh Mourya
0057e71e02 [mob][photos] fix: use "strokeFaint" instead of "strokeFainter" for better visibility 2025-04-15 19:16:01 +05:30
Aman Raj Singh Mourya
50fabee1e0 [mob][photos] feat: enhance AlbumRowItemWidget with selection handling 2025-04-09 00:13:19 +05:30
Aman Raj Singh Mourya
227d76db29 [mob][photos] feat: enhance CollectionsFlexiGridViewWidget with selection mode and album creation options 2025-04-09 00:12:50 +05:30
Aman Raj Singh Mourya
9207b0c7b8 [mob][photos] feat: add album view type settings 2025-04-09 00:12:08 +05:30
Aman Raj Singh Mourya
9b8c48ca6e [mob][photos] feat: implement AlbumListItemWidget for displaying album in vertical layout 2025-04-09 00:10:30 +05:30
Aman Raj Singh Mourya
dc05e254cb [mob][photos] feat: add NewAlbumRowItemWidget for creating new albums in grid view 2025-04-09 00:09:44 +05:30
Aman Raj Singh Mourya
f047757c63 [mob][photos] changes: make SectionOptions tappable for incoming, outgoing, and quick links 2025-04-05 21:23:13 +05:30
Aman Raj Singh Mourya
f9711e09a1 [mob][photos] fix: show "Add new" album for "On ente" section only 2025-04-05 21:04:56 +05:30
Aman Raj Singh Mourya
a5644f292e [mob][photos] changes: add new album icon to flex grid view 2025-04-05 20:27:09 +05:30
Aman Raj Singh Mourya
f3a88dc3fa [mob][photos] changes: adjust thumbnail size and gap for 3x3 layout 2025-04-05 19:57:14 +05:30
Aman Raj Singh Mourya
9ef2a5fc62 [mob][photos] changes: move sort option into full screen view of "On ente" section & remove "View all" section 2025-04-05 00:37:01 +05:30
Aman Raj Singh Mourya
36ab2f05df [mob][photos] changes: make the complete SectionOptions tappable 2025-04-05 00:34:34 +05:30
Aman Raj Singh Mourya
723511540c [mob][photos] Show 3 albums in a row and max 3 rows i.e _kOnEnteItemLimitCount = 9 (3*3) 2025-04-04 20:40:01 +05:30
761 changed files with 34650 additions and 18684 deletions

View File

@@ -1,24 +1,21 @@
name: Report a bug
description: Let us know if something's not working the way you expected.
description: For regressions only (things that were working earlier)
labels: []
body:
- type: markdown
attributes:
value: |
Before opening a new bug report, please ensure
1. you are on the latest version (it might've already been fixed),
2. you've searched for existing issues (please add your observations as a comment there instead of creating a duplicate).
If you are self hosting, please create a community [Q&A](https://github.com/ente-io/ente/discussions/categories/q-a) instead.
Before opening a new issue, **please** ensure
1. You are on the latest version,
2. You've searched for existing issues,
3. It was working earlier (otherwise use [this](https://github.com/ente-io/ente/discussions/categories/enhancements))
4. It is not about self hosting (otherwise use [this](https://github.com/ente-io/ente/discussions/categories/q-a))
- type: textarea
attributes:
label: Description
description: >
Please describe the bug. If possible, also include the steps to
reproduce the behaviour, and the expected behaviour (sometimes
bugs are just expectation mismatches, in which case this would be
a good fit for [feature
requests](https://github.com/ente-io/ente/discussions/categories/feature-requests)).
Describe the bug and steps to reproduce the behaviour, and how it
differs from the previously working behaviour.
validations:
required: true
- type: input
@@ -30,15 +27,12 @@ body:
attributes:
label: Last working version
description: >
The version where the feature was last known to be working. It is
fine if you don't remember the exact version (mention roughly
then), but if there just isn't a last known working version, then
it is likely that what is being reported is not an issue but a
feature request. The difference between the two categories is not
just semantic - feature requests use GitHub discussions and so can
be [upvoted by the
community](https://github.com/ente-io/ente/discussions/categories/feature-requests)
(issues can't be).
The version where things were last known to be working. It is fine
if you don't remember the exact version (mention roughly then),
but **if there just isn't a last working version, then please file
it as an
[enhancement](https://github.com/ente-io/ente/discussions/categories/enhancements))**
(where the community upvotes can be used to help prioritize).
placeholder: e.g. v1.2.3
- type: dropdown
attributes:

View File

@@ -1,5 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: Feature requests and questions
- name: Enhacements, feature requests, feedback and questions
url: https://github.com/ente-io/ente/discussions
about: Please use Discussions for everything apart from the above.

View File

@@ -83,7 +83,7 @@ jobs:
# disable this step if release tag contains nightly or beta
if: startsWith(github.ref, 'refs/tags/auth-v') && !contains(github.ref, 'nightly') && !contains(github.ref, 'beta')
run: |
flutter build appbundle --release --flavor playstore --dart-define=app.flavor=playstore
flutter build appbundle --release --flavor playstore --dart-define=app.flavor=playstore --dart-define=cronetHttpNoPlay=true
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_auth_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
@@ -117,7 +117,9 @@ jobs:
mv dist/**/*-*-linux.deb artifacts/ente-${{ github.ref_name }}-x86_64.deb
- name: Generate checksums
run: sha256sum artifacts/ente-* >> artifacts/sha256sum-rpm-appimage
run: |
sha256sum artifacts/ente-auth-*.apk >> artifacts/sha256sum-apk
sha256sum artifacts/ente-auth-*.deb artifacts/ente-auth-*.rpm artifacts/ente-auth-*.AppImage >> artifacts/sha256sum-linux
- name: Create a draft GitHub release
uses: ncipollo/release-action@v1
@@ -139,6 +141,7 @@ jobs:
build-windows:
runs-on: windows-latest
environment: "auth-win-build"
defaults:
run:
@@ -172,14 +175,22 @@ jobs:
- name: Retain Windows EXE and DLLs
run: cp -r build/windows/x64/runner/Release ente-${{ github.ref_name }}-windows
- name: Code sign Windows installer and EXE
uses: dlemstra/code-sign-action@v1
- name: Sign files with Trusted Signing
uses: azure/trusted-signing-action@v0
with:
certificate: "${{ secrets.WINDOWS_CERTIFICATE }}"
password: "${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}"
files: |
auth/artifacts/ente-${{ github.ref_name }}-installer.exe
auth/ente-${{ github.ref_name }}-windows/auth.exe
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: ${{ secrets.AZURE_ENDPOINT }}
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
files: |
${{ github.workspace }}/auth/artifacts/ente-${{ github.ref_name }}-installer.exe
${{ github.workspace }}/auth/ente-${{ github.ref_name }}-windows/auth.exe
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Zip Windows EXE and DLLs
run: tar.exe -a -c -f artifacts/ente-${{ github.ref_name }}-windows.zip ente-${{ github.ref_name }}-windows

70
.github/workflows/auth-win-sign.yml vendored Normal file
View File

@@ -0,0 +1,70 @@
name: "Windows build & Sign (auth)"
on:
workflow_dispatch: # Allow manually running the action
env:
FLUTTER_VERSION: "3.24.3"
permissions:
contents: write
jobs:
build-windows:
runs-on: windows-latest
environment: "auth-win-build"
defaults:
run:
working-directory: auth
steps:
- name: Checkout code and submodules
uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Flutter ${{ env.FLUTTER_VERSION }}
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Create artifacts directory
run: mkdir artifacts
- name: Build Windows installer
run: |
flutter config --enable-windows-desktop
# dart pub global activate flutter_distributor
dart pub global activate --source git https://github.com/ente-io/flutter_distributor_fork --git-ref develop --git-path packages/flutter_distributor
make innoinstall
flutter_distributor package --platform=windows --targets=exe --skip-clean
mv dist/**/*-windows-setup.exe artifacts/ente-${{ github.ref_name }}-installer.exe
- name: Retain Windows EXE and DLLs
run: cp -r build/windows/x64/runner/Release ente-${{ github.ref_name }}-windows
- name: Sign files with Trusted Signing
uses: azure/trusted-signing-action@v0
with:
azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
endpoint: ${{ secrets.AZURE_ENDPOINT }}
trusted-signing-account-name: ${{ secrets.AZURE_CODE_SIGNING_NAME }}
certificate-profile-name: ${{ secrets.AZURE_CERT_PROFILE_NAME }}
files: |
${{ github.workspace }}/auth/artifacts/ente-${{ github.ref_name }}-installer.exe
${{ github.workspace }}/auth/ente-${{ github.ref_name }}-windows/auth.exe
file-digest: SHA256
timestamp-rfc3161: http://timestamp.acs.microsoft.com
timestamp-digest: SHA256
- name: Zip Windows EXE and DLLs
run: tar.exe -a -c -f artifacts/ente-${{ github.ref_name }}-windows.zip ente-${{ github.ref_name }}-windows
- name: Generate checksums
run: sha256sum artifacts/ente-* > artifacts/sha256sum-windows

32
.github/workflows/docs-lint.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: "Lint (docs)"
on:
# Run on every pull request (open or push to it) that changes docs/
pull_request:
paths:
- "docs/**"
- ".github/workflows/docs-lint.yml"
permissions:
contents: read
jobs:
lint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: docs
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup node and enable yarn caching
uses: actions/setup-node@v4
with:
node-version: 22
cache: "yarn"
cache-dependency-path: "web/yarn.lock"
- run: yarn install
- run: yarn pretty:check

View File

@@ -0,0 +1,77 @@
name: "Internal release (photos)"
on:
workflow_dispatch: # Allow manually running the action
env:
FLUTTER_VERSION: "3.24.3"
RUST_VERSION: "1.85.1"
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: mobile
steps:
- name: Checkout code and submodules
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup JDK 17
uses: actions/setup-java@v1
with:
java-version: 17
- name: Install Flutter ${{ env.FLUTTER_VERSION }}
uses: subosito/flutter-action@v2
with:
channel: "stable"
flutter-version: ${{ env.FLUTTER_VERSION }}
cache: true
- name: Install Rust ${{ env.RUST_VERSION }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ env.RUST_VERSION }}
- name: Install Flutter Rust Bridge
run: cargo install flutter_rust_bridge_codegen
- name: Setup keys
uses: timheuer/base64-to-file@v1
with:
fileName: "keystore/ente_photos_key.jks"
encodedString: ${{ secrets.SIGNING_KEY_PHOTOS }}
- name: Build PlayStore AAB
run: |
flutter build appbundle --dart-define=cronetHttpNoPlay=true --release --flavor playstore
env:
SIGNING_KEY_PATH: "/home/runner/work/_temp/keystore/ente_photos_key.jks"
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS_PHOTOS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD_PHOTOS }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD_PHOTOS }}
- name: Upload AAB to PlayStore
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: io.ente.photos
releaseFiles: mobile/build/app/outputs/bundle/playstoreRelease/app-playstore-release.aab
track: internal
- name: Notify Discord
uses: sarisia/actions-status-discord@v1
with:
webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
nodetail: true
title: "🏆 Internal release available for Photos"
description: "[Download](https://play.google.com/store/apps/details?id=io.ente.photos)"
color: 0x00ff00

View File

@@ -63,6 +63,6 @@ jobs:
with:
webhook: ${{ secrets.DISCORD_INTERNAL_RELEASE_WEBHOOK }}
nodetail: true
title: "🏆 Internal release available for Photos"
title: "🏆 Internal release Photos (Branch: ${{ github.ref_name }})"
description: "[Download](https://play.google.com/store/apps/details?id=io.ente.photos)"
color: 0x00ff00

View File

@@ -23,7 +23,7 @@ Just hang around, enjoy the vibe. Answer someone's query on our
[Discord](https://discord.gg/z2YVKkycX3), or pile on in the sporadic #off-topic
rants there. Chuckle (or wince!) at our [Twitter](https://twitter.com/enteio)
memes. Suggest a new feature in our [Github
Discussions](https://github.com/ente-io/ente/discussions/new?category=feature-requests),
Discussions](https://github.com/ente-io/ente/discussions/new?category=enhancements),
or upvote the existing ones that you feel we should focus on first. Provide your
opinion on existing threads.
@@ -68,8 +68,8 @@ best to start small. Consider some well-scoped changes, say like adding more
Each of the individual product/platform specific directories in this repository
have instructions on setting up a dev environment.
For anything beyond trivial bug fixes, please use [features requests and
discussions](https://github.com/ente-io/ente/discussions) instead of performing
For anything beyond trivial bug fixes, please use
[discussions](https://github.com/ente-io/ente/discussions) instead of performing
code changes directly.
> [!TIP]

View File

@@ -43,7 +43,13 @@
"title": "Anycoin Direct",
"slug": "anycoindirect"
},
{
{
"title": "AR24",
"altNames": [
"Docaposte AR24"
]
},
{
"title": "Aruba",
"slug": "aruba",
"hex": "ef8a33"
@@ -132,6 +138,10 @@
"Binance US"
]
},
{
"title": "Bitazza",
"slug": "bitazza"
},
{
"title": "Bitkub",
"slug": "bitkub"
@@ -188,7 +198,11 @@
"slug": "blue_sky"
},
{
"title": "bonify"
"title": "bonify",
"slug": "bonify",
"altNames": [
"bonify.de"
]
},
{
"title": "Booking",
@@ -292,6 +306,15 @@
{
"title": "CSAM"
},
{
"title": "CSSBuy",
"slug": "cssbuy",
"altNames": [
"CSS Buy",
"CSS-Buy",
"cssbuy.com"
]
},
{
"title": "CSFloat"
},
@@ -299,6 +322,10 @@
"title": "CSGORoll",
"slug": "csgoroll"
},
{
"title": "Cryptee",
"slug": "cryptee"
},
{
"title": "Cwallet",
"altNames": [
@@ -431,6 +458,9 @@
"title": "Finanzfluss",
"slug": "finanzfluss"
},
{
"title": "Finary"
},
{
"title": "Firefox",
"slug": "mozilla"
@@ -452,6 +482,9 @@
"title": "Gate.io",
"slug": "gateio.svg"
},
{
"title": "GERID"
},
{
"title": "GitHub"
},
@@ -733,6 +766,7 @@
{
"title": "Mistral",
"altNames": [
"Le Chat",
"Mistral AI",
"MistralAI"
]
@@ -877,11 +911,15 @@
"欧易"
]
},
{
{
"title": "OnShape",
"slug": "onshape",
"hex": "7abb5e"
},
{
"title": "Oracle Cloud",
"slug": "oracle_cloud"
},
{
"title": "Parqet",
"slug": "parqet"
@@ -1001,7 +1039,7 @@
"title": "RealMe",
"slug": "realme"
},
{
{
"title": "RealVNC",
"slug": "realvnc",
"hex": "488aec"
@@ -1268,6 +1306,14 @@
"title": "US Mobile",
"slug": "us_mobile"
},
{
"title": "uollet",
"slug": "uollet",
"altNames": [
"UOLLET",
"uollet.com.br"
]
},
{
"title": "Vikunja"
},
@@ -1355,4 +1401,4 @@
"title": "CoinSpot"
}
]
}
}

View File

@@ -0,0 +1,6 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="#0000FF" xmlns="http://www.w3.org/2000/svg">
<path d="M139.63 306.55H125.64C123.41 306.55 121.53 306.5 119.99 306.39C118.45 306.28 117.13 305.99 116.01 305.51C114.9 305.04 113.92 304.32 113.08 303.36C112.22 302.41 111.38 301.09 110.53 299.39L103.85 286.35H35.47L25.29 306.55H0L58.37 194.11H81.26L139.63 306.55ZM93.2 265.36L69.66 218.6L46.12 265.36H93.2Z"/>
<path d="M265.23 306.55H245.67C241.96 306.55 238.93 306.07 236.6 305.12C234.27 304.16 232.31 302.68 230.72 300.67L206.17 270.76H177.48V306.55H153.95V195.23C156.92 195.12 160.16 195.04 163.66 194.99C167.17 194.93 170.77 194.86 174.5 194.75C178.21 194.64 181.92 194.57 185.64 194.51C189.36 194.46 192.86 194.43 196.15 194.43C209.74 194.43 220.97 195.41 229.84 197.37C238.71 199.34 246 202.91 251.74 208.1C258.11 214.04 261.3 222.1 261.3 232.28C261.3 237.37 260.61 241.85 259.23 245.72C257.84 249.59 255.88 252.96 253.33 255.81C250.78 258.68 247.7 261.09 244.09 263.05C240.49 265.02 236.45 266.63 231.99 267.9L265.23 306.55ZM196.25 250.25C199.75 250.25 203.27 250.22 206.82 250.17C210.38 250.12 213.74 249.88 216.93 249.45C220.1 249.03 223.02 248.36 225.67 247.46C228.32 246.55 230.5 245.24 232.19 243.54C233.67 241.94 234.82 240.29 235.61 238.59C236.4 236.89 236.81 234.7 236.81 232.03C236.81 230.23 236.45 228.47 235.77 226.77C235.08 225.06 234.15 223.62 232.99 222.45C231.4 220.85 229.44 219.6 227.11 218.7C224.77 217.79 222.1 217.12 219.07 216.7C216.05 216.27 212.63 216.03 208.81 215.98C205 215.93 200.81 215.9 196.25 215.9H187.18C183.58 215.9 180.34 215.95 177.48 216.06V250.1C180.34 250.2 183.58 250.25 187.18 250.25H196.25Z"/>
<path d="M324.59 213.35C318.34 213.35 312.61 215.03 307.41 218.37C302.22 221.7 297.93 225.65 294.54 230.22L276.09 217.97C282.13 210.65 289.36 204.66 297.79 200C306.22 195.33 315.47 193 325.55 193C332.33 193 338.53 193.87 344.15 195.62C349.77 197.37 354.59 199.84 358.63 203.02C362.65 206.2 365.78 210.07 368.01 214.63C370.23 219.19 371.35 224.27 371.35 229.89C371.35 235.2 370.36 239.86 368.4 243.89C366.44 247.92 363.85 251.6 360.61 254.94C357.38 258.28 353.69 261.38 349.56 264.25C345.42 267.11 341.18 269.97 336.84 272.84L317.27 285.72H370.87V306.55H279.42V286.04L318.39 260.27C322.2 257.73 325.86 255.32 329.36 253.03C332.86 250.76 335.93 248.42 338.58 246.04C341.24 243.65 343.35 241.13 344.95 238.48C346.54 235.83 347.33 232.91 347.33 229.74C347.33 227.41 346.72 225.23 345.5 223.22C344.28 221.2 342.64 219.45 340.57 217.97C338.51 216.49 336.09 215.35 333.34 214.55C330.58 213.75 327.66 213.35 324.59 213.35Z"/>
<path d="M457.22 306.55V283.49H388.84V259.95L455.47 195.23H480.12V263.77H500V283.49H480.12V306.55L457.22 306.55ZM413.17 263.77H457.22V220.35L413.17 263.77Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="836.84424" height="914.80933">
<defs>
<clipPath id="a">
<path stroke-linecap="round" d="M-186.41-125.66h372.816v351.267H-186.41Z"/>
</clipPath>
<clipPath id="b">
<path stroke-linecap="round" d="M-186.41-95.22h372.816v351.267H-186.41Z"/>
</clipPath>
<clipPath id="c">
<path stroke-linecap="round" d="M-160.08-140.83h372.816v351.267H-160.08Z"/>
</clipPath>
<clipPath id="d">
<path stroke-linecap="round" d="M-212.74-140.83h372.816v351.267H-212.74Z"/>
</clipPath>
</defs>
<g clip-path="url(#a)" transform="translate(418.40805 457.4024)scale(3.64)">
<path d="m298.246 129.84-6.486-4.585 6.486-4.586c12.26215-8.68661 19.24883-23.025924 18.53269-38.036075-.71613-15.010151-9.03624-28.619172-22.06969-36.098925l-.568-.349c-12.19994-7.033047-27.02434-7.819595-39.9-2.117l-7.053 3.144-.83-7.687c-1.51376-14.021838-9.62342-26.481265-21.832-33.542l-.2-.087C217.64616 2.0246361 210.0606-.00958995 202.34 0c-8.04957.00100343-15.94637 2.1978633-22.84 6.354l-1.114.677c-11.58345 7.090871-19.28369 19.094034-20.9 32.579l-.917 7.6-6.967-3.1c-12.8836-5.747507-27.74063-4.976398-39.96 2.074l-.7.394c-13.604075 7.890873-21.986349 22.420072-22.008 38.147v.787c.02516 14.283035 6.954274 27.67261 18.6 35.942L112 126.04l-6.463 4.586c-12.260313 8.67436-19.255033 22.99852-18.556462 38.00091.698572 15.00239 8.994121 28.61458 22.007462 36.11209l.633.393c12.22088 7.0137 27.04998 7.79342 39.939 2.1l7.054-3.123.807 7.687c1.51242 13.97659 9.57745 26.40246 21.727 33.475l.284.153c13.92748 8.0385 31.12909 7.84683 44.874-.5l1.092-.655c11.59433-7.07976 19.29833-19.08878 20.9-32.579l.9-7.6 6.987 3.123c12.9143 5.73028 27.78955 4.94317 40.027-2.118l.611-.372c13.60439-7.88085 21.98922-22.40383 22.012-38.126v-.808c-.0274-14.27871-6.94846-27.66532-18.583-35.943M292 166.591c-.0145 6.86067-3.67326 13.19693-9.608 16.639l-.654.394c-5.96032 3.4063-13.27768 3.4063-19.238 0l-17.884-10.351-22.841 13.211v20.133c-.0194 6.70609-3.51599 12.92214-9.237 16.421l-1.114.677c-5.99641 3.62641-13.48927 3.70989-19.565.218l-.24-.153c-5.94051-3.43919-9.60731-9.7748-9.63-16.639v-20.657l-22.841-13.211-17.884 10.351c-5.9447 3.40734-13.2503 3.40734-19.195 0l-.677-.415c-5.92257-3.40301-9.59053-9.69703-9.63171-16.52753-.0412-6.83049 3.5506-13.16829 9.43171-16.64247l18.648-11.027-.153-26.313-18.3-10.569c-5.94649-3.42296-9.61685-9.756715-9.63-16.618v-.787c.0184-6.865358 3.68634-13.20295 9.63-16.639l.655-.415c5.9528-3.406398 13.2642-3.406398 19.217 0l17.884 10.351 22.841-13.189V44.7c.0433-6.705114 3.54343-12.913272 9.258-16.421l1.114-.677c5.98556-3.637575 13.47843-3.721536 19.544-.219l.24.131c5.95616 3.434267 9.62726 9.785677 9.63 16.661v20.658l22.841 13.189L262.5 67.671c5.96032-3.406299 13.27768-3.406299 19.238 0l.654.415c5.91101 3.411809 9.56893 9.702792 9.61008 16.527659.0412 6.824866-3.54064 13.159502-9.41008 16.642341l-18.67 11.027.153 26.313 18.321 10.569c5.93573 3.43032 9.59519 9.76235 9.604 16.618z" style="opacity:1;fill:#10f48b;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" transform="translate(-201.88 -125.66)" vector-effect="non-scaling-stroke"/>
</g>
<g clip-path="url(#b)" transform="translate(418.40805 346.6008)scale(3.64)">
<path d="m255.89 111.218-37.166 21.432-37.165-21.432 37.165-21.463Z" style="opacity:1;fill:#10f48b;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" transform="translate(-218.72 -111.2)" vector-effect="non-scaling-stroke"/>
</g>
<g clip-path="url(#c)" transform="translate(322.56685 512.6212)scale(3.64)">
<path d="M209.3 153.613v42.927l-37.166-21.463v-42.9z" style="opacity:1;fill:#10f48b;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" transform="translate(-190.72 -164.36)" vector-effect="non-scaling-stroke"/>
</g>
<g clip-path="url(#d)" transform="translate(514.24925 512.6212)scale(3.64)">
<path d="M273.357 132.181v42.9l-37.166 21.459v-42.927z" style="opacity:1;fill:#10f48b;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0" transform="translate(-254.77 -164.36)" vector-effect="non-scaling-stroke"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@@ -1,29 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="logosandtypes_com" data-name="logosandtypes com" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 150 150">
<defs>
<style>
.cls-1 {
fill: #101010;
}
.cls-2 {
fill: none;
}
.cls-3 {
fill: url(#linear-gradient);
}
</style>
<linearGradient id="linear-gradient" x1="186.97" y1="96.04" x2="45.7" y2="96.04" gradientTransform="translate(0 150.11) scale(1 -1)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#165cc3"/>
<stop offset="1" stop-color="#3ddabb"/>
</linearGradient>
</defs>
<g id="Layer_3" data-name="Layer 3">
<g id="Layer_2" data-name="Layer 2">
<path id="Layer_3-2" data-name="Layer 3-2" class="cls-2" d="M0,0H150V150H0V0Z"/>
</g>
</g>
<path class="cls-1" d="M111.63,75.01c.06,.86,.08,1.72,.08,2.59,0,20.52-16.62,37.16-37.14,37.16-20.52,0-37.16-16.62-37.16-37.14,0-20.52,16.62-37.16,37.14-37.16,0,0,.02,0,.02,0,1.61,0,3.22,.1,4.82,.32l12.7-17.11C62.3,14,30.31,30.3,20.63,60.09c-9.68,29.79,6.62,61.78,36.41,71.47,29.79,9.68,61.78-6.62,71.47-36.41,4.29-13.2,3.59-27.52-1.97-40.24l-14.9,20.11Z"/>
<polygon class="cls-3" points="120.26 4.82 74.49 66.53 62.93 53.99 45.67 69.89 76.4 103.32 149.5 4.82 120.26 4.82"/>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150">
<defs>
<linearGradient id="a" x1="186.97" x2="45.7" y1="96.04" y2="96.04"
gradientTransform="matrix(1 0 0 -1 0 150.11)" gradientUnits="userSpaceOnUse">
<stop offset="0" stop-color="#165cc3" />
<stop offset="1" stop-color="#3ddabb" />
</linearGradient>
</defs>
<path
d="M111.63 75.01c.06.86.08 1.72.08 2.59 0 20.52-16.62 37.16-37.14 37.16S37.41 98.14 37.41 77.62s16.62-37.16 37.14-37.16h.02c1.61 0 3.22.1 4.82.32l12.7-17.11C62.3 14 30.31 30.3 20.63 60.09s6.62 61.78 36.41 71.47c29.79 9.68 61.78-6.62 71.47-36.41 4.29-13.2 3.59-27.52-1.97-40.24l-14.9 20.11Z"
style="fill:#EFEFEF; mix-blend-mode: difference" />
<path d="M120.26 4.82 74.49 66.53 62.93 53.99l-17.26 15.9 30.73 33.43 73.1-98.5z"
style="fill:url(#a)" />
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 876 B

View File

@@ -0,0 +1 @@
<svg width="1400" height="1400" xmlns="http://www.w3.org/2000/svg"><path d="M699.914 0C1004.659 0 1263.915 194.786 1360 466.662l-399.246-.003C896.674 395.059 803.556 350 699.914 350c-193.276 0-349.957 156.7-349.957 350s156.681 350 349.957 350c103.641 0 196.76-45.059 260.84-116.658L1360 933.34C1263.915 1205.214 1004.659 1400 699.914 1400 313.362 1400 0 1086.6 0 700S313.362 0 699.914 0zm347.087 747.002L1398 747a696.274 696.274 0 0 1-12.453 93H1021a345.75 345.75 0 0 0 26.001-92.998zM1385.547 560A696.301 696.301 0 0 1 1398 653l-351-.002A345.762 345.762 0 0 0 1021 560h364.547z" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 608 B

View File

@@ -0,0 +1,9 @@
<svg width="145" height="39" viewBox="0 0 145 39" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="145" height="39" fill="url(#pattern0_2030_2)"/>
<defs>
<pattern id="pattern0_2030_2" patternContentUnits="objectBoundingBox" width="1" height="1">
<use xlink:href="#image0_2030_2" transform="scale(0.00689655 0.025641)"/>
</pattern>
<image id="image0_2030_2" width="145" height="39" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJEAAAAnCAMAAAA4lVp5AAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAERUExURQAAAGy8Kmy8Kmy9Kmy8Km28KWy9Km2/Lmy8Kmu8Kmu8Kmy8KWy7KGy9Kmu9KWu8Km27K3C/KGy8Kmy8KW29K2y8Kmy8K3C/MGy9Kmy7LGy8KWu8LGy7Kmy9KnDCKWy8KWy7Km28Kmy7Kmy8Kmu5Km29Km26KGq6Kmu8Kmy9Kmu7Kmy8Kmy8Kmy8Kmy8Kmy8Km69KWy9K2u8KoC/IG28Km27Kmy7Kmy5K2y8Km2+LGi3KGq6Kmu8KWy9Kmq8K2y6Kmy7Kmy8Kn7ERazZh9ruyv///+Py177ioYjJUpHNX+335LXdlHXAN9HqvKPVecjmr5rRbfb78qPVerbeldvuyuTz2O335cjmsK3ZiNHqvb/iok0+o7UAAABBdFJOUwD359fHm1UcxmbMv0B/cN+PIKOgj9CQEMBA8EyA1BlQkrDb4DdgPzCkyE/v7c+2r12QnwjDMeJC9VIgYFiXSGh4PBaO/QAAAAFiS0dERY6zqFcAAAAHdElNRQfpBR8TLQ+T8HIEAAAAAW9yTlQBz6J3mgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyNS0wNS0zMVQxOTo0NToxNSswMDowMFaVqvwAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjUtMDUtMzFUMTk6NDU6MTUrMDA6MDAnyBJAAAAAKHRFWHRkYXRlOnRpbWVzdGFtcAAyMDI1LTA1LTMxVDE5OjQ1OjE1KzAwOjAwcN0znwAAAFplWElmTU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAAITAAMAAAABAAEAAAAAAAAAAABIAAAAAQAAAEgAAAABH1L3NAAABF9JREFUWMPNV3lf2kAQpbWXUlFKOUJpFSnQ1tqD3tYeGxIgEJRww/f/IN3ZczYE/QlqnT8kzmY3L++9md3EyEpx5+7GvfsPHsauI1ZDJOLR5m1DRMjW1WNaExEh8ce3DREh2xHLJuTgTnw3eeOIyJPFZVMXQb5eROTpwrJpYzyzFiK77jhuw2m2UM5rOm3H6dgq4de7NNM9XcZCluZyFo1EJg/jlxEujOfMleFIAL4jU02R6QUi0Za4n5mrWjSVEOCArsLKiPouioA/zm/o1Fn4LnEPef7CWLVAU5a43gO+VkU0cI0IfEgyhoLhkKX6oCG7Gg3HjCUxdd9YtUgzhoIrIuLvPun5xO4zXSY02YKLKQg6ohdDejEDPMDNFIZ6fO6BsWqJkDRGdBlrYw8BisAT5oHnuzbnbcjHIUN/4YffNaFXAzH7JVo0iUGU6T9l7q5KRVq8WqlUeKaip0EyixHB+q4qsZYQaaafOpsNemJAOHw4mUr/43LbUyAoRTuE5Dkgmt0T2RxXsojrEMZLGJHvojeG54/mAG8OZYe19TVHOF6FjF0VgOIKRwI9XtRfWdckkxrKwXQR97IRzCxdG2WYuKfh+14jRJQBUoF4s3uo6SpKsqg+AibIW0SvkTF8NBNWDoXPe8+ZZoVXZLtuon+7rIBLluZAPr0s6UqrokxyzfDkoSjucMjuo3jipl/gCTkUp4+kUFmiO2VK0pUhsnHl5JUphkeiIAVmNyT+zGiYC4jK5vyytrukKy3pqgqp2BxengdqorsMEfEHHFOg3OTxfunOIxHBi2f5Awt5haOgssrYNOj4ERBI/Zbno+8MRD0SHf507Jo281ivcO0oRJSBEi7puJQljZKW0g8cBT+iM+wbPkLv3AG+Wp1uY6DNQ7eMetMJkL+mUYiItjD3h2QjJXIJTRdvXRaa8kCtODeqvwfVxMpqrhLQGOGvuGlk9q8YpkVv9tK74BjZeoqaxCzDUlKa8YzQAXu1FbDNo6f3UoFoqIlpLEGUQBbWNVRG2ZKmC8YPC1ozGu/VkiNd452A7yi+RglHgJlg0lNv0ItAlML/gGVJyNiYLnki1zLHPqglW+IU5ogDEVDB/Ntudjptsc3ZvDd16uxoN46qNbzxM3hFiaiqRNMkJtlkpRnER7WmcV7j/vHHKMNKbYrvaUUgAh9ITbI1Ip9eIOoIYNYBbGdIMxqfPqtF1WmVKiP0kA0aAPkh3IHRLLCxa2xT266BZAIepA+rUiZNIrN+MWbEl6+67ww4gNFAb1p9npqp7mlPGHHjgbmxyeUKxIwU5mLniCf1oZL1xvCXwbfvaAHf87zwCaDlhZo5vckO3aMQ5YxsSelRzUuIOYyoiG2u4scOWT/kYnmVSedS2B9J9lmZ3othRMu+C45rV4fovLCskD6RmvH4uXUTiBYiWjMRm2tiWgXQRd9yJ782bhbROZqpOP598ufv9kqxAqLMeZr9j7DI5b52rz3gS05udbc5/gHZ/BLSJh/eDgAAAABJRU5ErkJggg=="/>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -0,0 +1,3 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="#F1C086" xmlns="http://www.w3.org/2000/svg">
<path d="M166.67 62C74.62 62 0 136.62 0 228.67H333.33C425.38 228.67 500 154.05 500 62H166.67ZM166.67 270.33C74.62 270.33 0 344.95 0 437H154.76C246.81 437 321.43 362.38 321.43 270.33H166.67Z"/>
</svg>

After

Width:  |  Height:  |  Size: 302 B

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generator: https://ezgif.com/png-to-svg -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="195" height="195">
<path d="M0,0 L44,0 L70,2 L94,6 L98,8 L98,39 L95,75 L91,98 L85,114 L76,131 L65,145 L58,153 L55,154 L55,144 L51,131 L42,121 L38,118 L38,98 L34,98 L33,29 L28,27 L26,26 L26,89 L22,89 L22,25 L20,25 L20,89 L13,89 L12,29 L11,30 L11,98 L6,98 L6,118 L-3,125 L-9,135 L-11,143 L-11,154 L-15,152 L-25,141 L-35,126 L-43,110 L-48,95 L-52,69 L-54,44 L-55,8 L-50,6 L-26,2 Z " fill="#046097" transform="translate(75,8)"/>
<path d="M0,0 L44,0 L70,2 L94,6 L98,8 L98,39 L95,75 L91,98 L85,114 L76,131 L65,145 L58,153 L55,154 L55,144 L51,131 L42,121 L38,118 L38,98 L34,98 L33,29 L28,27 L26,26 L26,89 L22,89 L22,25 L20,24 L22,24 L22,1 L0,1 Z " fill="#0495C0" transform="translate(75,8)"/>
<path d="M0,0 L8,0 L13,3 L15,7 L15,15 L6,21 L0,20 L-7,16 L-8,10 L-5,3 Z " fill="#0A669B" transform="translate(93,165)"/>
<path d="M0,0 L6,1 L10,5 L11,7 L11,15 L2,21 L-2,20 L0,20 Z " fill="#0D99C1" transform="translate(97,165)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,15 +1,7 @@
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<g style="mix-blend-mode:difference">
<path fill-rule="evenodd" clip-rule="evenodd" d="M363.636 23H409.091V477.545H363.636V23ZM0 23H45.4545V477.545H0V23ZM227.273 295.727H181.818V386.636H227.273V295.727ZM272.727 113.909H318.182V204.818H272.727V113.909Z" fill="white"/>
</g>
<path d="M136.364 386.636H45.4545V477.545H136.364V386.636Z" fill="#EA3326"/>
<path d="M500 386.636H409.091V477.545H500V386.636Z" fill="#EA3326"/>
<path d="M136.364 295.727H45.4545V386.636H136.364V295.727Z" fill="#EB5829"/>
<path d="M318.182 295.727H227.273V386.636H318.182V295.727Z" fill="#EB5829"/>
<path d="M500 295.727H409.091V386.636H500V295.727Z" fill="#EB5829"/>
<path d="M136.364 23H45.4545V113.909H136.364V23Z" fill="#F7D046"/>
<path d="M500 23H409.091V113.909H500V23Z" fill="#F7D046"/>
<path d="M227.273 113.909H45.4545V204.818H227.273V113.909Z" fill="#F2A73B"/>
<path d="M500 113.909H318.182V204.818H500V113.909Z" fill="#F2A73B"/>
<path d="M500 204.818H45.4545V295.727H500V204.818Z" fill="#EE792F"/>
</svg>
<svg width="500" height="500" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<path d="M71.41 73H142.83V143.75H71.41V73ZM357.12 73H428.54V143.75H357.12V73Z" fill="#FFD800"/>
<path d="M71.41 143.75H214.25V214.5H71.41V143.75ZM285.7 143.75H428.54V214.5H285.7V143.75Z" fill="#FFAF00"/>
<path d="M71.41 214.5H428.54V285.25H71.41V214.5Z" fill="#FF8205"/>
<path d="M71.41 285.27H142.83V356.02H71.41V285.27ZM214.27 285.27H285.69V356.02H214.27V285.27ZM357.12 285.27H428.54V356.02H357.12V285.27Z" fill="#FA500F"/>
<path d="M0 356.06H214.3V426.82H0V356.06ZM285.7 356.06H500V426.82H285.7V356.06Z" fill="#E10500"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 628 B

View File

@@ -0,0 +1 @@
<svg height="2100" viewBox="0 0 32 21" width="3200" xmlns="http://www.w3.org/2000/svg"><path d="m9.9 20.1c-5.5 0-9.9-4.4-9.9-9.9s4.4-9.9 9.9-9.9h11.6c5.5 0 9.9 4.4 9.9 9.9s-4.4 9.9-9.9 9.9zm11.3-3.5c3.6 0 6.4-2.9 6.4-6.4 0-3.6-2.9-6.4-6.4-6.4h-11c-3.6 0-6.4 2.9-6.4 6.4s2.9 6.4 6.4 6.4z" fill="#c74634"/></svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@@ -0,0 +1,15 @@
<svg width="500" height="404" viewBox="0 0 500 404" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M232.61 401.571C220.894 398.642 214.011 395.42 204.052 388.39C199.219 384.876 154.991 341.672 105.783 292.172C37.244 223.34 15.1299 200.347 11.1757 193.61C-3.03008 169.006 -3.61588 146.16 8.97892 121.263C14.6905 109.987 26.6995 96.806 75.0284 48.4771C115.303 8.20299 118.378 6.00622 139.321 1.46623C151.33 -1.02344 160.41 -0.437633 174.176 3.9559C188.235 8.20299 197.901 15.5256 224.262 41.7403C237.443 54.7745 249.013 65.4654 250.038 65.4654C250.916 65.4654 251.649 66.7835 251.649 68.3945C251.649 70.0054 251.063 71.3235 250.331 71.3235C249.745 71.3235 243.887 76.5957 237.443 83.0396C224.409 95.9273 216.647 109.108 215.329 120.385C214.596 127.561 217.525 144.549 219.576 144.549C220.308 144.549 220.894 145.867 220.894 147.478C220.894 151.725 240.811 171.203 248.72 174.865C252.381 176.475 258.532 178.672 262.34 179.697C268.93 181.455 269.955 181.308 279.914 177.501C285.772 175.157 291.044 172.521 291.63 171.35C292.216 170.325 293.241 169.446 293.973 169.446C294.559 169.446 304.664 159.926 316.527 148.21C336.59 128.586 338.494 126.975 343.62 126.975C348.746 126.975 350.943 128.879 386.091 164.027C406.301 184.237 422.997 201.812 422.997 202.837C422.997 203.715 423.582 204.594 424.315 204.594C424.9 204.594 427.39 208.695 429.733 213.821C433.102 221.29 433.98 225.39 434.42 237.253C435.006 249.555 434.713 251.459 432.662 251.459C431.344 251.459 430.319 252.337 430.319 253.362C430.319 254.388 400.15 285.289 363.391 321.902C303.492 381.507 295.145 389.123 286.065 393.809C267.465 403.328 250.184 405.818 232.61 401.571ZM2.24217 152.311C1.94926 149.968 1.65636 151.579 1.65636 155.533C1.65636 159.634 1.94926 161.391 2.24217 159.634C2.53507 157.73 2.53507 154.508 2.24217 152.311Z" fill="#461EC5"/>
<path d="M430.319 233.152C430.319 231.981 429.733 230.955 429.001 230.955C428.269 230.955 427.976 229.637 428.415 228.026C429.733 222.901 433.248 224.512 433.248 230.223C433.248 233.006 432.662 235.349 431.784 235.349C431.052 235.349 430.319 234.324 430.319 233.152Z" fill="#36198A"/>
<path d="M421.386 210.745C417.138 205.766 416.846 203.13 420.8 203.13C424.022 203.13 424.461 203.715 424.461 208.255C424.461 214.113 424.315 214.26 421.386 210.745Z" fill="#36198A"/>
<path d="M252.527 182.48C247.695 180.869 241.104 177.647 237.736 175.304C228.949 169.299 212.4 150.407 215.768 150.407C216.354 150.407 215.622 149.382 214.45 148.064C213.132 146.892 212.4 145.135 212.839 144.403C213.425 143.671 212.986 143.085 212.107 143.085C211.082 143.085 210.789 141.913 211.375 140.156C211.814 138.545 211.814 137.227 211.082 137.227C210.496 137.227 209.91 131.662 209.91 124.778C209.91 117.895 210.496 112.33 211.228 112.33C211.814 112.33 212.107 111.305 211.521 110.133C211.082 108.962 211.375 107.936 212.253 107.936C213.132 107.936 213.571 106.911 212.986 105.74C212.546 104.568 212.839 103.543 213.718 103.543C214.597 103.543 214.889 102.957 214.45 102.225C214.011 101.493 214.597 100.467 215.915 100.028C217.233 99.5887 217.965 98.1242 217.526 97.099C217.086 95.9274 217.672 94.6094 218.844 94.17C220.015 93.7306 220.748 92.8519 220.601 92.2661C220.162 90.8016 244.18 66.9301 246.084 66.9301C246.816 66.9301 246.962 66.1978 246.377 65.3191C245.791 64.2939 246.377 64.001 248.134 64.5868C250.331 65.3191 256.921 59.4611 278.01 38.665C307.007 9.96053 311.694 6.7386 330.732 1.75926C347.721 -2.78073 370.714 1.90571 385.505 12.7431C392.242 17.7224 440.571 65.3191 440.571 67.0765C440.571 67.6623 441.45 68.541 442.475 68.8339C443.353 69.2733 438.374 69.5662 431.052 69.5662C420.946 69.4197 416.406 70.0055 411.72 72.2023C404.69 75.4242 348.16 129.904 351.821 129.904C353.432 129.904 354.165 131.222 354.165 134.298C354.165 138.252 354.604 138.691 358.558 138.691C362.659 138.691 362.952 139.131 362.952 144.11V149.529L353.579 140.302C344.938 131.808 343.767 131.076 341.423 132.98C339.959 134.151 330 143.817 319.163 154.508C308.325 165.052 298.953 173.839 298.367 173.839C297.781 173.839 296.609 174.718 296.023 175.743C295.438 176.915 290.458 179.551 284.893 181.601C273.177 186.288 264.683 186.581 252.527 182.48ZM288.847 141.913C297.342 134.737 299.538 127.414 295.731 119.067C292.069 110.865 287.529 107.204 278.596 105.007C271.859 103.543 270.395 103.689 265.562 106.033C261.315 108.229 259.557 110.573 256.775 117.309C253.406 125.511 253.406 125.95 255.749 132.394C258.386 139.423 263.951 144.549 271.42 147.039C276.253 148.65 283.429 146.6 288.847 141.913Z" fill="#36198A"/>
<path d="M383.455 170.178L378.476 165.052H383.894C389.167 165.052 389.313 165.199 389.313 170.178C389.313 172.961 389.167 175.304 388.874 175.304C388.581 175.304 386.238 172.961 383.455 170.178Z" fill="#36198A"/>
<path d="M430.026 239.157C429.44 228.612 428.561 225.097 424.021 216.017C419.335 206.498 414.649 201.372 382.136 168.714C361.926 148.65 345.084 130.929 344.498 129.465C343.327 125.95 398.392 71.9093 407.326 67.6622C412.012 65.6119 416.552 64.8796 426.218 64.8796H438.959L459.023 84.5041C480.698 105.886 488.899 116.87 492.854 129.758C494.318 134.298 495.929 138.398 496.661 138.838C497.394 139.423 497.54 141.181 497.101 142.792C496.515 144.403 496.808 146.16 497.686 146.746C499.59 147.918 499.59 161.684 497.54 163.002C496.661 163.441 496.222 165.199 496.661 166.663C497.101 168.128 496.075 171.789 494.611 174.865C493.146 177.794 491.828 181.601 491.828 183.066C491.828 186.434 485.97 197.272 484.213 197.272C483.627 197.272 483.041 198.15 483.041 199.175C483.041 201.372 434.419 251.459 432.223 251.459C431.344 251.459 430.465 246.333 430.026 239.157Z" fill="#2B146D"/>
<path d="M266.586 151.432C260.435 149.089 251.355 141.913 252.38 140.009C252.966 139.277 252.527 138.691 251.648 138.691C250.77 138.691 250.477 138.105 250.916 137.227C251.355 136.494 251.209 135.762 250.33 135.762C249.451 135.762 249.159 134.737 249.598 133.565C250.184 132.394 249.891 131.368 249.159 131.368C248.426 131.368 247.84 128.732 247.987 125.51C247.987 122.289 248.426 119.652 248.866 119.652C250.33 119.652 253.259 112.183 252.38 110.719C251.795 109.987 252.234 109.401 252.966 109.401C253.845 109.401 254.431 108.669 254.138 107.643C253.991 106.765 256.481 104.421 259.703 102.664C267.026 98.417 275.959 96.806 278.742 99.1492C279.913 100.028 281.524 100.467 282.257 100.028C282.989 99.4421 284.014 99.735 284.6 100.614C285.186 101.492 286.064 101.785 286.797 101.346C288.847 100.028 297.341 108.229 300.124 114.527C303.638 122.289 303.638 124.046 299.684 124.046C297.195 124.046 295.73 122.581 293.973 118.334C291.044 111.451 282.257 104.568 276.691 104.714C271.566 104.861 260.582 110.133 259.41 113.062C258.971 114.234 257.36 115.259 255.895 115.259C253.552 115.259 253.113 116.43 253.113 121.849C253.113 125.657 254.138 130.49 255.31 132.687C257.946 137.812 265.415 144.256 270.101 145.428C272.591 146.014 273.616 147.332 273.616 149.821C273.616 153.776 273.323 153.776 266.586 151.432Z" fill="#2B146D"/>
<path d="M275.081 149.821C275.081 147.039 276.106 146.014 279.621 145.281C285.186 144.11 293.973 135.03 295.145 129.611C295.731 126.536 296.756 125.51 299.392 125.51C303.346 125.51 303.493 126.682 301.442 134.444C299.538 141.034 293.827 147.039 286.065 150.554C277.864 154.361 275.081 154.068 275.081 149.821Z" fill="#2B146D"/>
<path d="M265.561 150.114C257.507 146.014 254.578 143.231 251.502 136.494C247.841 128.44 247.987 122.289 252.381 113.794C260.143 98.2705 281.818 94.9022 293.241 107.204C299.978 114.38 301.003 115.845 300.27 117.895C299.978 118.774 300.417 119.652 301.296 119.652C302.174 119.652 302.907 121.996 302.907 124.778C302.907 127.561 302.174 129.904 301.296 129.904C300.417 129.904 299.978 131.222 300.417 132.833C300.856 134.444 300.563 135.762 299.685 135.762C298.952 135.762 298.659 136.348 299.099 137.08C299.538 137.812 298.952 138.838 297.634 139.277C296.316 139.863 295.584 140.595 296.17 141.181C296.609 141.62 295.584 142.792 293.68 143.817C291.923 144.696 290.605 146.16 290.751 147.039C290.898 147.918 288.408 148.943 285.332 149.528C282.11 149.968 279.474 151.139 279.474 151.872C279.474 154.215 271.859 153.19 265.561 150.114Z" fill="#1F0E4E"/>
<rect x="1.21729" y="150.407" width="4.39354" height="10.2516" fill="#461EC5"/>
<path d="M462.539 88.1654C506.161 130.726 511.237 166.488 480.113 203.13L462.539 88.1654Z" fill="#2B146D"/>
<circle cx="275.081" cy="125.51" r="27.8257" fill="#1F0E4E"/>
<path d="M222.359 89.6299C196.86 117.609 199.757 132.937 221.627 159.926L222.359 89.6299Z" fill="#36198A"/>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -11,7 +11,7 @@ const String roadmapURL = "https://roadmap.ente.io";
const String kAccountsUrl = "https://accounts.ente.io";
const String githubFeatureRequestUrl =
"https://github.com/ente-io/ente/discussions/categories/feature-requests?discussions_q=is%3Aopen+category%3A%22Feature+requests%22+label%3A%22-+auth%22+sort%3Atop";
"https://github.com/ente-io/ente/discussions/categories/enhancements?discussions_q=is%3Aopen%+label%3A%22-+auth%22+sort%3Atop";
const int microSecondsInDay = 86400000000;
const int android11SDKINT = 30;
const int galleryLoadStartTime = -8000000000000000; // Wednesday, March 6, 1748

View File

@@ -73,7 +73,10 @@ class AuthenticatorGateway {
);
}
Future<List<AuthEntity>> getDiff(int sinceTime, {int limit = 500}) async {
Future<(List<AuthEntity>, int?)> getDiff(
int sinceTime, {
int limit = 500,
}) async {
try {
final response = await _enteDio.get(
"/authenticator/entity/diff",
@@ -84,11 +87,12 @@ class AuthenticatorGateway {
);
final List<AuthEntity> authEntities = <AuthEntity>[];
final diff = response.data["diff"] as List;
final int? unixTimeInMicroSeconds = response.data["timestamp"] as int?;
for (var entry in diff) {
final AuthEntity entity = AuthEntity.fromMap(entry);
authEntities.add(entity);
}
return authEntities;
return (authEntities, unixTimeInMicroSeconds);
} catch (e) {
if (e is DioException && e.response?.statusCode == 401) {
throw UnauthorizedError();

View File

@@ -47,7 +47,7 @@
"saveAction": "حفظ",
"nextTotpTitle": "التالي",
"deleteCodeTitle": "حذف الرمز؟",
"deleteCodeMessage": "هل أنت متأكد من أنك تريد حذف هذه الشيفرة؟ هذا الإجراء لا رجعة فيه.",
"deleteCodeMessage": "هل أنت متيقِّن من أنك تريد حذف هذه الشيفرة؟ هذا الإجراء لا رجعة فيه.",
"trashCode": "حذف الكود؟",
"trashCodeMessage": "هل أنت متيقِّن أنك تريد حذف الكود الخاص بـ {account}؟",
"trash": "سلة المهملات",
@@ -173,6 +173,7 @@
"invalidQRCode": "شيفرة استجابة سريعة غير صالحة",
"noRecoveryKeyTitle": "لا يوجد مفتاح استرجاع؟",
"enterEmailHint": "أدخل عنوان البريد الإلكتروني الخاص بك",
"enterNewEmailHint": "أدخل عنوان بريدك الإلكتروني الجديد",
"invalidEmailTitle": "عنوان البريد الإلكتروني غير صالح",
"invalidEmailMessage": "الرجاء إدخال بريد إلكتروني صالح.",
"deleteAccount": "إزالة الحساب",
@@ -513,5 +514,10 @@
"free5GB": "5GB مجانًا على <bold-green>ente</bold-green> صور",
"loginWithAuthAccount": "سجّل الدخول باستخدام حساب المُصادقة",
"freeStorageOffer": "خَصْم 10٪ على صور <bold-green>ente</bold-green>",
"freeStorageOfferDescription": "استخدم الكود \"AUTH\" وأحصل على 10٪ خَصْم في السنة الأولى"
"freeStorageOfferDescription": "استخدم الكود \"AUTH\" وأحصل على 10٪ خَصْم في السنة الأولى",
"advanced": "متقدم",
"algorithm": "الخوارزمية",
"type": "النوع",
"period": "المدّة",
"digits": "الأرقام"
}

View File

@@ -88,6 +88,8 @@
"useRecoveryKey": "Použít obnovovací klíč",
"incorrectPasswordTitle": "Nesprávné heslo",
"welcomeBack": "Vítejte zpět!",
"emailAlreadyRegistered": "E-mail je již registrován.",
"emailNotRegistered": "E-mail není registrován.",
"madeWithLoveAtPrefix": "vyrobeno s ❤️ v ",
"supportDevs": "Předplaťte si <bold-green>ente</bold-green>, abyste nás podpořili",
"supportDiscount": "Použijte kód \"AUTH\" pro získání 10% slevy na první rok",
@@ -495,9 +497,18 @@
"appLockOfflineModeWarning": "Zvolili jste si pokračování bez zálohování. Pokud zapomenete heslo do aplikace, přístup k datům bude uzamčen.",
"duplicateCodes": "Duplikovat kódy",
"noDuplicates": "✨ Žádné duplikáty",
"youveNoDuplicateCodesThatCanBeCleared": "Nemáte žádné duplicitní kódy k odstranění",
"deduplicateCodes": "Deduplikovat kódy",
"deselectAll": "Zrušit výběr všech položek",
"selectAll": "Vybrat vše",
"deleteDuplicates": "Odstranit duplikáty",
"plainHTML": "Prosté HTML"
"plainHTML": "Prosté HTML",
"tellUsWhatYouThink": "Sdělte nám svůj názor",
"dropReviewiOS": "Zanechat recenzi na App Store",
"dropReviewAndroid": "Zanechat recenzi na Play Store",
"supportEnte": "Podpořte <bold-green>ente</bold-green>",
"giveUsAStarOnGithub": "Dejte nám hvězdu na Githubu",
"free5GB": "5GB zdarma na <bold-green>ente</bold-green> Fotky",
"freeStorageOffer": "10% sleva na <bold-green>ente</bold-green> fotky",
"freeStorageOfferDescription": "Použijte kód \"AUTH\" pro získání 10% slevy na první rok"
}

View File

@@ -91,39 +91,39 @@
"emailAlreadyRegistered": "E-Mail ist bereits registriert.",
"emailNotRegistered": "E-Mail-Adresse nicht registriert.",
"madeWithLoveAtPrefix": "gemacht mit ❤️ bei ",
"supportDevs": "Bei <bold-green>ente</bold-green> registrieren, um das Projekt zu unterstützen",
"supportDevs": "Abonnieren Sie <bold-green>ente</bold-green>, um das Projekt zu unterstützen",
"supportDiscount": "Benutzen Sie den Rabattcode \"AUTH\" für 10 % Rabatt im ersten Jahr",
"changeEmail": "E-Mail ändern",
"changePassword": "Passwort ändern",
"data": "Datei",
"data": "Daten",
"importCodes": "Codes importieren",
"importTypePlainText": "Klartext",
"importTypeEnteEncrypted": "Verschlüsselter Ente-Export",
"passwordForDecryptingExport": "Passwort um den Export zu entschlüsseln",
"passwordEmptyError": "Passwort kann nicht leer sein",
"importFromApp": "Importiere Codes von {appName}",
"importGoogleAuthGuide": "Exportiere deine Accounts von Google Authenticator zu einem QR-Code, durch die \"Konten übertragen\" Option. Scanne den QR-Code danach mit einem anderen Gerät.\n\nTipp: Du kannst die Kamera eines Laptops verwenden, um ein Foto den dem QR-Code zu erstellen.",
"importSelectJsonFile": "Wähle eine JSON-Datei",
"importFromApp": "Importieren Sie Codes von {appName}",
"importGoogleAuthGuide": "Exportieren Sie Ihre Accounts von Google Authenticator zu einem QR-Code, mithilfe der \"Konten übertragen\" Option. Scanne den QR-Code danach mit einem anderen Gerät.\n\nTipp: Sie können die Kamera eines Laptops verwenden, um ein Foto vom QR-Code zu erstellen.",
"importSelectJsonFile": "Wählen Sie eine JSON-Datei",
"importSelectAppExport": "{appName} Exportdatei auswählen",
"importEnteEncGuide": "Wähle die von Ente exportierte, verschlüsselte JSON-Datei",
"importRaivoGuide": "Verwenden Sie die Option \"Export OTPs to Zip archive\" in den Raivo-Einstellungen.\n\nEntpacken Sie die Zip-Datei und importieren Sie die JSON-Datei.",
"importEnteEncGuide": "Wählen Sie die von Ente exportierte, verschlüsselte JSON-Datei",
"importRaivoGuide": "Verwenden Sie die Option \"Export OTPs to Zip archive\" in den Einstellungen von Raivo.\n\nEntpacken Sie die Zip-Datei und importieren Sie die JSON-Datei.",
"importBitwardenGuide": "Verwenden Sie die Option \"Tresor exportieren\" innerhalb der Bitwarden Tools und importieren Sie die unverschlüsselte JSON-Datei.",
"importAegisGuide": "Verwenden Sie die Option \"Tresor exportieren\" in den Aegis-Einstellungen.\n\nFalls Ihr Tresor verschlüsselt ist, müssen Sie das Passwort für den Tresor eingeben, um ihn zu entschlüsseln.",
"importAegisGuide": "Verwenden Sie die Option \"Tresor exportieren\" in den Einstellungen von Aegis.\n\nFalls Ihr Tresor verschlüsselt ist, müssen Sie das Passwort für den Tresor eingeben, um ihn zu entschlüsseln.",
"import2FasGuide": "Verwenden Sie unter \"Einstellungen → Backup\" die Option \"Exportieren\" in 2FAS.\n\nFalls Ihr Backup verschlüsselt ist, müssen Sie das Passwort eingeben, um das Backup zu entschlüsseln.",
"importLastpassGuide": "Verwenden Sie die Option \"Konten übertragen → Konten in Datei exportieren\" in den Lastpass Authenticator Einstellungen. \nImportieren Sie anschließend die heruntergeladene JSON-Datei.",
"exportCodes": "Codes exportieren",
"importLabel": "Importieren",
"importInstruction": "Bitte wählen sie eine Datei die Codes in folgendem Format beinhaltet",
"importCodeDelimiterInfo": "Codes können in einer neuen Zeile stehen oder durch Kommata getrennt sein",
"importInstruction": "Bitte wählen Sie eine Datei die Codes in folgendem Format beinhaltet",
"importCodeDelimiterInfo": "Codes können in einer neuen Zeile stehen oder durch ein Komma getrennt sein",
"selectFile": "Datei auswählen",
"emailVerificationToggle": "E-Mail-Verifizierung",
"emailVerificationEnableWarning": "Stellen Sie sicher, eine Kopie Ihrer Zwei-Faktor-Authentifizierung an anderer Stelle zu speichern, um zu vermeiden, dass Sie sich versehentlich aus Ihrem Account aussperren.",
"authToChangeEmailVerificationSetting": "Bitte Authentifizieren um die E-Mail Bestätigung zu ändern",
"emailVerificationEnableWarning": "Um zu vermeiden, versehentlich aus Ihrem Konto ausgesperrt zu werden, stellen Sie sicher, dass Sie den Zwei-Faktor-Authentifizierungscode für Ihr E-Mail-Konto außerhalb von Ente Auth speichern, bevor Sie die E-Mail-Verifizierung aktivieren.",
"authToChangeEmailVerificationSetting": "Bitte authentifizieren, um die E-Mail Bestätigung zu ändern",
"authenticateGeneric": "Bitte authentifizieren",
"authToViewYourRecoveryKey": "Bitte authentifizieren um ihren Wiederherstellungscode anzuzeigen",
"authToChangeYourEmail": "Bitte authentifizieren um ihre Emailadresse zu ändern",
"authToChangeYourPassword": "Bitte authentifizieren um ihr Passwort zu ändern",
"authToViewSecrets": "Bitte authentifizieren Sie sich, um ihren Wiederherstellungscode anzuzeigen",
"authToViewYourRecoveryKey": "Bitte authentifizieren, um Ihren Wiederherstellungscode anzuzeigen",
"authToChangeYourEmail": "Bitte authentifizieren, um Ihre E-Mail-Adresse zu ändern",
"authToChangeYourPassword": "Bitte authentifizieren, um Ihr Passwort zu ändern",
"authToViewSecrets": "Bitte authentifizieren, um Ihren Wiederherstellungscode anzuzeigen",
"authToInitiateSignIn": "Bitte authentifizieren, um die Anmeldung zum Backup zu starten.",
"ok": "Ok",
"cancel": "Abbrechen",
@@ -140,18 +140,18 @@
"delete": "Löschen",
"enterYourPasswordHint": "Geben Sie Ihr Passwort ein",
"forgotPassword": "Passwort vergessen",
"oops": "Hopla",
"oops": "Hoppla",
"suggestFeatures": "Features vorschlagen",
"faq": "FAQ",
"somethingWentWrongMessage": "Ein Fehler ist aufgetreten, bitte versuchen Sie es erneut",
"leaveFamily": "Familie verlassen",
"leaveFamilyMessage": "Sind Sie sicher, dass Sie den Familien-Plan verlassen wollen?",
"inFamilyPlanMessage": "Sie haben einen Familien-Plan!",
"hintForMobile": "Lange drücken, um den Code zu bearbeiten oder zu entfernen.",
"hintForMobile": "Lange auf einen Code drücken, um ihn zu bearbeiten oder zu entfernen.",
"hintForDesktop": "Klicken Sie mit der rechten Maustaste auf einen Code zum Bearbeiten oder Entfernen.",
"scan": "Scannen",
"scanACode": "Scan einen Code",
"verify": "Überprüfen Sie",
"verify": "Verifizieren",
"verifyEmail": "E-Mail-Adresse verifizieren",
"enterCodeHint": "Geben Sie den 6-stelligen Code \naus Ihrer Authentifikator-App ein.",
"lostDeviceTitle": "Gerät verloren?",
@@ -172,9 +172,10 @@
},
"invalidQRCode": "Ungültiger QR-Code",
"noRecoveryKeyTitle": "Kein Wiederherstellungsschlüssel?",
"enterEmailHint": "Geben Sie Ihre E-Mail Adresse ein",
"invalidEmailTitle": "Ungültige E-Mail Adresse",
"invalidEmailMessage": "Bitte geben Sie eine gültige E-Mail Adresse ein.",
"enterEmailHint": "Geben Sie Ihre E-Mail-Adresse ein",
"enterNewEmailHint": "Gib deine neue E-Mail-Adresse ein",
"invalidEmailTitle": "Ungültige E-Mail-Adresse",
"invalidEmailMessage": "Bitte geben Sie eine gültige E-Mail-Adresse ein.",
"deleteAccount": "Konto löschen",
"deleteAccountQuery": "Es tut uns leid, dass Sie gehen. Haben Sie ein Problem?",
"yesSendFeedbackAction": "Ja, Feedback senden",
@@ -187,7 +188,7 @@
"moderateStrength": "Mittel",
"confirmPassword": "Bestätigen Sie das Passwort",
"close": "Schließen",
"oopsSomethingWentWrong": "Ups, da ist etwas schief gelaufen.",
"oopsSomethingWentWrong": "Hoppla, da ist etwas schiefgelaufen.",
"selectLanguage": "Sprache auswählen",
"language": "Sprache",
"social": "Social",
@@ -203,26 +204,26 @@
"noResult": "Kein Ergebnis",
"addCode": "Code hinzufügen",
"scanAQrCode": "QR-Code scannen",
"enterDetailsManually": "Details manuell hinzufügen",
"enterDetailsManually": "Daten manuell hinzufügen",
"edit": "Editieren",
"share": "Teilen",
"shareCodes": "Codes teilen",
"shareCodesDuration": "Wählen Sie die Dauer aus, für die Sie die Codes teilen möchten.",
"restore": "Wiederherstellen",
"copiedToClipboard": "In die Zwischenablage kopieren",
"copiedNextToClipboard": "Nächster Code wurde in die Zwischenablage kopiert",
"copiedToClipboard": "In die Zwischenablage kopiert",
"copiedNextToClipboard": "Nächster Code in die Zwischenablage kopiert",
"error": "Fehler",
"recoveryKeyCopiedToClipboard": "Wiederherstellungsschlüssel in die Zwischenablage kopiert",
"recoveryKeyOnForgotPassword": "Sollten sie ihr Passwort vergessen, dann ist dieser Schlüssel die einzige Möglichkeit ihre Daten wiederherzustellen.",
"recoveryKeySaveDescription": "Wir speichern diesen Schlüssel nicht. Sichern sie dieses diesen Schlüssel bestehend aus 24 Wörtern an einem sicheren Platz.",
"recoveryKeySaveDescription": "Wir speichern diesen Schlüssel nicht. Sichern Sie diesen Schlüssel bestehend aus 24 Wörtern an einem sicheren Platz.",
"doThisLater": "Auf später verschieben",
"saveKey": "Schlüssel speichern",
"save": "Speichern",
"send": "Senden",
"saveOrSendDescription": "Möchtest du dies in deinem Speicher (standardmäßig im Ordner Downloads) oder an andere Apps senden?",
"saveOrSendDescription": "Möchtest du dies in deinem Speicher (standardmäßig im Ordner Downloads) speichern oder an andere Apps senden?",
"saveOnlyDescription": "Möchtest du dies in deinem Speicher (standardmäßig im Ordner Downloads) speichern?",
"back": "Zurück",
"createAccount": "Account erstellen",
"createAccount": "Konto erstellen",
"passwordStrength": "Passwortstärke: {passwordStrengthValue}",
"@passwordStrength": {
"description": "Text to indicate the password strength",
@@ -244,17 +245,17 @@
"changePasswordTitle": "Passwort ändern",
"resetPasswordTitle": "Passwort zurücksetzen",
"encryptionKeys": "Verschlüsselungsschlüssel",
"passwordWarning": "Wir speichern dieses Passwort nicht. Wenn du es vergisst, <underline>können wir deine Daten nicht entschlüsseln</underline>",
"enterPasswordToEncrypt": "Gib ein Passwort ein, mit dem wir deine Daten verschlüsseln können",
"enterNewPasswordToEncrypt": "Gib ein neues Passwort ein, mit dem wir deine Daten verschlüsseln können",
"passwordWarning": "Wir speichern dieses Passwort nicht. Wenn Sie es vergessen, <underline>können wir Ihre Daten nicht entschlüsseln</underline>",
"enterPasswordToEncrypt": "Geben Sie ein Passwort ein, mit dem wir Ihre Daten verschlüsseln können",
"enterNewPasswordToEncrypt": "Geben Sie ein neues Passwort ein, mit dem wir Ihre Daten verschlüsseln können",
"passwordChangedSuccessfully": "Passwort erfolgreich geändert",
"generatingEncryptionKeys": "Generierung von Verschlüsselungsschlüsseln...",
"continueLabel": "Weiter",
"insecureDevice": "Unsicheres Gerät",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Es tut uns leid, wir konnten keine sicheren Schlüssel auf diesem Gerät generieren.\n\nBitte registrieren Sie sich auf einem anderen Gerät.",
"howItWorks": "So funktioniert's",
"ackPasswordLostWarning": "Ich verstehe, dass der Verlust meines Passworts zum Verlust meiner Daten führen kann, denn diese ist <underline>Ende-zu-Ende verschlüsselt</underline>.",
"loginTerms": "Durch das Klicken auf den Login-Button, stimme ich <u-terms>den Nutzungsbedingungen</u-terms> und den <u-policy>Datenschutzbestimmungen</u-policy> zu",
"ackPasswordLostWarning": "Ich verstehe, dass der Verlust meines Passworts zum Verlust meiner Daten führen kann, denn diese sind <underline>Ende-zu-Ende verschlüsselt</underline>.",
"loginTerms": "Durch das Klicken auf den Login-Button, stimme ich den <u-terms> Nutzungsbedingungen</u-terms> und den <u-policy>Datenschutzbestimmungen</u-policy> zu",
"logInLabel": "Einloggen",
"logout": "Ausloggen",
"areYouSureYouWantToLogout": "Sind sie sicher, dass sie sich ausloggen möchten?",
@@ -266,7 +267,7 @@
"systemTheme": "System",
"verifyingRecoveryKey": "Verifiziere Wiederherstellungsschlüssel...",
"recoveryKeyVerified": "Wiederherstellungsschlüssel verifiziert",
"recoveryKeySuccessBody": "Großartig! Ihr Wiederherstellungsschlüssel ist gültig. Vielen Dank für die Verifizierung.\n\nBitte denken sie daran, dass sie ihren Wiederherstellungsschlüssel sicher aufbewahren.",
"recoveryKeySuccessBody": "Großartig! Ihr Wiederherstellungsschlüssel ist gültig. Vielen Dank für die Verifizierung.\n\nBitte denken Sie daran, den Wiederherstellungsschlüssel sicher aufzubewahren.",
"invalidRecoveryKey": "Der eingegebene Wiederherstellungsschlüssel ist nicht gültig. Bitte stellen sie sicher, dass er aus 24 Wörtern besteht und prüfen sie die Schreibweise eines jeden.\n\nSollten sie einen Wiederherstellungsschlüssel im alten Format eingegeben haben vergewissern sie sich, dass er 64 Zeichen lang ist und prüfen sie jedes dieser Zeichen.",
"recreatePasswordTitle": "Neues Passwort erstellen",
"recreatePasswordBody": "Das benutzte Gerät ist nicht leistungsfähig genug das Passwort zu prüfen. Wir können es aber neu erstellen damit es auf jedem Gerät funktioniert. \n\nBitte loggen sie sich mit ihrem Wiederherstellungsschlüssel ein und erstellen sie ein neues Passwort (Sie können das selbe Passwort wieder verwenden, wenn sie möchten).",
@@ -277,15 +278,15 @@
"recoveryKeyVerifyReason": "Ihr Wiederherstellungsschlüssel ist der einzige Weg ihre Fotos wiederherzustellen sollten, sie ihr Passwort vergessen. Sie finden ihren Wiederherstellungsschlüssel unter Einstellungen > Account.\n\nBitte tragen sie ihren Wiederherstellungsschlüssel hier ein um zu prüfen ob sie in korrekt abgespeichert haben.",
"confirmYourRecoveryKey": "Wiederherstellungsschlüssel bestätigen",
"confirm": "Bestätigen",
"emailYourLogs": "Email mit Logs senden",
"emailYourLogs": "E-Mail mit Logs senden",
"pleaseSendTheLogsTo": "Bitte Logs an {toEmail} senden",
"copyEmailAddress": "Emailadresse kopieren",
"copyEmailAddress": "E-Mail-Adresse kopieren",
"exportLogs": "Logs exportieren",
"enterYourRecoveryKey": "Wiederherstellungsschlüssel eingeben",
"tempErrorContactSupportIfPersists": "Etwas ist schiefgelaufen. Bitte versuchen sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren sie unser Supportteam.",
"tempErrorContactSupportIfPersists": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren sie unser Supportteam.",
"networkHostLookUpErr": "Ente ist im Moment nicht erreichbar. Bitte überprüfen Sie Ihre Netzwerkeinstellungen. Sollte das Problem bestehen bleiben, wenden Sie sich bitte an den Support.",
"networkConnectionRefusedErr": "Ente ist im Moment nicht erreichbar. Bitte versuchen Sie es später erneut. Sollte das Problem bestehen bleiben, wenden Sie sich bitte an den Support.",
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Etwas ist schiefgelaufen. Bitte versuchen sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren sie unser Supportteam.",
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Etwas ist schiefgelaufen. Bitte versuchen Sie es später noch einmal. Sollte der Fehler weiter bestehen, kontaktieren Sie unser Supportteam.",
"about": "Über uns",
"weAreOpenSource": "Wir sind Opensource!",
"privacy": "Datenschutz",
@@ -316,10 +317,10 @@
}
}
},
"sorry": "Entschuldigen sie",
"importFailureDesc": "Ausgewählte Datei ließ sich nicht verarbeiten.\nBitte wenden sie sich an support@ente.io für Hilfe!",
"sorry": "Entschuldigen Sie",
"importFailureDesc": "Ausgewählte Datei ließ sich nicht verarbeiten.\nBitte wenden Sie sich an support@ente.io für Hilfe!",
"pendingSyncs": "Warnung",
"pendingSyncsWarningBody": "Einige Codes wurden nicht gesichert.\n\nBitte gehen sie sicher, dass sie einen Backupcode für diese Codes haben bevor sie sich ausloggen.",
"pendingSyncsWarningBody": "Einige Codes wurden nicht gesichert.\n\nBitte gehen Sie sicher, dass Sie einen Backupcode für diese Codes haben bevor Sie sich ausloggen.",
"checkInboxAndSpamFolder": "Bitte überprüfe deinen E-Mail-Posteingang (und Spam), um die Verifizierung abzuschließen",
"tapToEnterCode": "Antippen, um den Code einzugeben",
"resendEmail": "E-Mail erneut senden",
@@ -339,10 +340,10 @@
"mostFrequentlyUsed": "Häufig verwendet",
"mostRecentlyUsed": "Zuletzt verwendet",
"activeSessions": "Aktive Sitzungen",
"somethingWentWrongPleaseTryAgain": "Ein Fehler ist aufgetreten, bitte versuche es erneut",
"thisWillLogYouOutOfThisDevice": "Dadurch wirst du von diesem Gerät abgemeldet!",
"thisWillLogYouOutOfTheFollowingDevice": "Dadurch wirst du von folgendem Gerät abgemeldet:",
"terminateSession": "Sitzungen beenden?",
"somethingWentWrongPleaseTryAgain": "Ein Fehler ist aufgetreten, bitte erneut versuchen",
"thisWillLogYouOutOfThisDevice": "Dadurch werden Sie von diesem Gerät abgemeldet!",
"thisWillLogYouOutOfTheFollowingDevice": "Dadurch werden Sie vom folgendem Gerät abgemeldet:",
"terminateSession": "Sitzung beenden?",
"terminate": "Beenden",
"thisDevice": "Dieses Gerät",
"toResetVerifyEmail": "Um Ihr Passwort zurückzusetzen, verifizieren Sie bitte zuerst Ihre E-Mail-Adresse.",
@@ -352,7 +353,7 @@
"incorrectCode": "Falscher Code",
"sorryTheCodeYouveEnteredIsIncorrect": "Leider ist der eingegebene Code falsch",
"emailChangedTo": "E-Mail-Adresse geändert zu {newEmail}",
"authenticationFailedPleaseTryAgain": "Authentifizierung fehlgeschlagen, versuchen Sie es bitte erneut",
"authenticationFailedPleaseTryAgain": "Authentifizierung fehlgeschlagen, bitte erneut versuchen",
"authenticationSuccessful": "Authentifizierung erfolgreich!",
"twofactorAuthenticationSuccessfullyReset": "Zwei-Faktor-Authentifizierung (2FA) erfolgreich zurückgesetzt",
"incorrectRecoveryKey": "Falscher Wiederherstellungs-Schlüssel",
@@ -365,22 +366,22 @@
"passwordToEncryptExport": "Passwort zum Verschlüssen des Exports",
"export": "Export",
"useOffline": "Ohne Backup verwenden",
"signInToBackup": "Melde dich an, um deine Codes zu sichern",
"signInToBackup": "Melden Sie sich an, um Ihre Codes zu sichern",
"singIn": "Anmelden",
"sigInBackupReminder": "Bitte exportieren Sie Ihre Codes, um sicherzustellen, dass Sie ein Backup haben, aus dem Sie wiederherstellen können.",
"sigInBackupReminder": "Bitte exportieren Sie Ihre Codes, um sicherzustellen, dass Sie ein Backup haben, das Sie wiederherstellen können.",
"offlineModeWarning": "Sie haben sich dafür entschieden, ohne Sicherungen fortzufahren. Bitte führen Sie manuelle Sicherungen durch, um sicherzustellen, dass Ihre Codes sicher sind.",
"showLargeIcons": "Große Symbole anzeigen",
"compactMode": "Kompaktmodus",
"shouldHideCode": "Codes ausblenden",
"doubleTapToViewHiddenCode": "Sie können auf einen Eintrag doppelt tippen, um den Code anzuzeigen",
"focusOnSearchBar": "Suche bei App-Start automatisch öffnen",
"confirmUpdatingkey": "Sind Sie sich sicher, dass Sie den Secret Key bearbeiten wollen?",
"focusOnSearchBar": "Suche beim App-Start fokussieren",
"confirmUpdatingkey": "Sind Sie sich sicher, dass Sie den geheimen Schlüssel bearbeiten wollen?",
"minimizeAppOnCopy": "Beim Kopieren App minimieren",
"editCodeAuthMessage": "Authentifizieren, um Code zu bearbeiten",
"deleteCodeAuthMessage": "Authentifizieren, um Code zu löschen",
"showQRAuthMessage": "Authentifizieren, um QR-Code anzuzeigen",
"confirmAccountDeleteTitle": "Kontolöschung bestätigen",
"confirmAccountDeleteMessage": "Dieses Konto ist mit anderen Ente-Apps verknüpft, falls du welche verwendest.\n\nDeine hochgeladenen Daten werden in allen Ente-Apps zur Löschung vorgemerkt und dein Konto wird endgültig gelöscht.",
"confirmAccountDeleteMessage": "Dieses Konto ist mit anderen Ente-Apps verknüpft, falls Sie welche verwenden.\n\nIhre hochgeladenen Daten werden in allen Ente-Apps zur Löschung vorgemerkt und Ihr Konto wird endgültig gelöscht.",
"androidBiometricHint": "Identität bestätigen",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
@@ -417,7 +418,7 @@
"@goToSettings": {
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
},
"androidGoToSettingsDescription": "Auf Ihrem Gerät ist keine biometrische Authentifizierung eingerichtet. Gehen Sie Einstellungen > Sicherheit, um die biometrische Authentifizierung hinzuzufügen.",
"androidGoToSettingsDescription": "Auf Ihrem Gerät ist keine biometrische Authentifizierung eingerichtet. Gehen Sie zu 'Einstellungen > Sicherheit', um die biometrische Authentifizierung hinzuzufügen.",
"@androidGoToSettingsDescription": {
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
},
@@ -434,9 +435,9 @@
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
},
"noInternetConnection": "Keine Internetverbindung",
"pleaseCheckYourInternetConnectionAndTryAgain": "Bitte überprüfe deine Internetverbindung und versuche es erneut.",
"pleaseCheckYourInternetConnectionAndTryAgain": "Bitte überprüfen Sie Ihre Internetverbindung und versuchen Sie erneut.",
"signOutFromOtherDevices": "Von anderen Geräten abmelden",
"signOutOtherBody": "Falls du denkst, dass jemand dein Passwort kennen könnte, kannst du alle anderen Geräte von deinem Account abmelden.",
"signOutOtherBody": "Falls Sie denken, dass jemand Ihr Passwort kennen könnte, können Sie alle anderen Geräte forcieren, sich von Ihrem Konto abzumelden.",
"signOutOtherDevices": "Andere Geräte abmelden",
"doNotSignOut": "Nicht abmelden",
"hearUsWhereTitle": "Wie hast du von Ente erfahren? (optional)",
@@ -458,7 +459,7 @@
"pinText": "Anpinnen",
"unpinText": "Lösen",
"pinnedCodeMessage": "{code} wurde angepinnt",
"unpinnedCodeMessage": "{code} wird nicht weiter angepinnt",
"unpinnedCodeMessage": "{code} wurde losgelöst",
"pinned": "Angeheftet",
"tags": "Tags",
"createNewTag": "Neuen Tag erstellen",
@@ -474,7 +475,7 @@
"rawCodeData": "Rohcode Daten",
"appLock": "App-Sperre",
"noSystemLockFound": "Keine Systemsperre gefunden",
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Um die App-Sperre zu aktivieren, konfiguriere bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen.",
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Um die App-Sperre zu aktivieren, konfigurieren Sie bitte den Gerätepasscode oder die Bildschirmsperre in den Systemeinstellungen.",
"autoLock": "Automatisches Sperren",
"immediately": "Sofort",
"reEnterPassword": "Passwort erneut eingeben",
@@ -494,23 +495,29 @@
"setNewPin": "Neue PIN festlegen",
"importFailureDescNew": "Die ausgewählte Datei konnte nicht verarbeitet werden.",
"appLockNotEnabled": "App-Sperre nicht aktiviert",
"appLockNotEnabledDescription": "Bitte aktivieren Sie die App-Sperre über Security > App-Sperre",
"authToViewPasskey": "Bitte authentifizieren, um deinen Passkey zu sehen",
"duplicateCodes": "Doppelte Codes",
"appLockNotEnabledDescription": "Bitte aktivieren Sie die App-Sperre über Sicherheit > App-Sperre",
"authToViewPasskey": "Bitte authentifizieren, um Ihren Passkey zu sehen",
"appLockOfflineModeWarning": "Sie haben sich dazu entschieden, ohne Sicherungen fortzufahren. Wenn Sie Ihre App-Sperre vergessen, können Sie nicht mehr auf Ihre Daten zugreifen.",
"duplicateCodes": "Codes duplizieren",
"noDuplicates": "✨ Keine Duplikate",
"youveNoDuplicateCodesThatCanBeCleared": "Du hast keine doppelten Codes, die bereinigt werden können",
"deduplicateCodes": "Codes deduplizieren",
"deselectAll": "Alle abwählen",
"selectAll": "Alles auswählen",
"selectAll": "Alle auswählen",
"deleteDuplicates": "Duplikate löschen",
"plainHTML": "Reines HTML",
"tellUsWhatYouThink": "Sagen Sie uns, was Sie denken",
"dropReviewiOS": "Hinterlasse eine Rezension im App Store",
"dropReviewAndroid": "Hinterlasse eine Rezension im Google Play Store",
"supportEnte": "Support <bold-green>ente</bold-green>",
"dropReviewiOS": "Hinterlassen Sie eine Rezension im App Store",
"dropReviewAndroid": "Hinterlassen Sie eine Rezension im Google Play Store",
"supportEnte": "Unterstütze <bold-green>ente</bold-green>",
"giveUsAStarOnGithub": "Gib uns einen Stern auf Github",
"free5GB": "5GB kostenlos auf <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Mit Ihrem Auth Account anmelden",
"freeStorageOffer": "10% Rabatt für <bold-green>ente</bold-green> Photos",
"freeStorageOfferDescription": "Verwende den Code \"AUTH\", um 10% im 1. Jahr zu sparen"
"freeStorageOfferDescription": "Verwende den Code \"AUTH\", um 10% im ersten Jahr zu sparen",
"advanced": "Erweitert",
"algorithm": "Algorithmus",
"type": "Typ",
"period": "Periode",
"digits": "Ziffern"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Invalid QR code",
"noRecoveryKeyTitle": "No recovery key?",
"enterEmailHint": "Enter your email address",
"enterNewEmailHint": "Enter your new email address",
"invalidEmailTitle": "Invalid email address",
"invalidEmailMessage": "Please enter a valid email address.",
"deleteAccount": "Delete account",
@@ -513,5 +514,10 @@
"free5GB": "5GB free on <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Login with your Auth account",
"freeStorageOffer": "10% off on <bold-green>ente</bold-green> photos",
"freeStorageOfferDescription": "Use code \"AUTH\" to get 10% off first year"
"freeStorageOfferDescription": "Use code \"AUTH\" to get 10% off first year",
"advanced": "Advanced",
"algorithm": "Algorithm",
"type": "Type",
"period": "Period",
"digits": "Digits"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "QR code non valide",
"noRecoveryKeyTitle": "Pas de clé de récupération ?",
"enterEmailHint": "Entrez votre adresse e-mail",
"enterNewEmailHint": "Saisissez votre nouvelle adresse email",
"invalidEmailTitle": "Adresse e-mail invalide",
"invalidEmailMessage": "Veuillez saisir une adresse e-mail valide.",
"deleteAccount": "Supprimer le compte",
@@ -513,5 +514,10 @@
"free5GB": "5 Go gratuits sur <bold-green>Ente</bold-green> Photos",
"loginWithAuthAccount": "Connectez-vous avec votre compte Auth",
"freeStorageOffer": "10% de réduction sur <bold-green>Ente</bold-green> Photos",
"freeStorageOfferDescription": "Utilisez le code coupon \"AUTH\" pour obtenir 10% de réduction la première année"
"freeStorageOfferDescription": "Utilisez le code coupon \"AUTH\" pour obtenir 10% de réduction la première année",
"advanced": "Avancé",
"algorithm": "Algorithme",
"type": "Type",
"period": "Période",
"digits": "Chiffres"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Érvénytelen QR-kód",
"noRecoveryKeyTitle": "Nincs helyreállítási kulcs?",
"enterEmailHint": "Adja meg az e-mail címét",
"enterNewEmailHint": "Add meg az új e-mail címed",
"invalidEmailTitle": "Érvénytelen e-mail cím",
"invalidEmailMessage": "Kérjük, adjon meg egy érvényes e-mail címet.",
"deleteAccount": "Fiók törlése",
@@ -513,5 +514,6 @@
"free5GB": "5GB ingyen <bold-green>ente <bold-green> Photos",
"loginWithAuthAccount": "Jelentkezzen be Auth fiókjával",
"freeStorageOffer": "10% kedvezmény on <bold-green>ente<bold-green> photos",
"freeStorageOfferDescription": "Használja az \"AUTH\" kódot, hogy 10% kedvezményt kapjon az első évben"
"freeStorageOfferDescription": "Használja az \"AUTH\" kódot, hogy 10% kedvezményt kapjon az első évben",
"type": "Típus"
}

View File

@@ -88,6 +88,8 @@
"useRecoveryKey": "Gunakan kunci pemulihan",
"incorrectPasswordTitle": "Kata sandi salah",
"welcomeBack": "Selamat datang kembali!",
"emailAlreadyRegistered": "Email sudah terdaftar.",
"emailNotRegistered": "Email belum terdaftar.",
"madeWithLoveAtPrefix": "dibuat dengan ❤️ di ",
"supportDevs": "Berlangganan <bold-green>ente</bold-green> untuk mendukung kami",
"supportDiscount": "Gunakan kode kupon \"AUTH\" untuk mendapatkan potongan 10% untuk tahun pertama",
@@ -171,6 +173,7 @@
"invalidQRCode": "Kode QR tidak valid",
"noRecoveryKeyTitle": "Tidak punya kunci pemulihan?",
"enterEmailHint": "Masukkan alamat email Anda",
"enterNewEmailHint": "Masukkan alamat email baru anda",
"invalidEmailTitle": "Alamat email tidak valid",
"invalidEmailMessage": "Harap masukkan alamat email yang valid.",
"deleteAccount": "Hapus akun",
@@ -501,5 +504,12 @@
"deselectAll": "Batalkan semua pilihan",
"selectAll": "Pilih semua",
"deleteDuplicates": "Hapus duplikat",
"plainHTML": "HTML Sederhana"
"plainHTML": "HTML Sederhana",
"tellUsWhatYouThink": "Berikan pendapatmu",
"dropReviewAndroid": "Berikan ulasan di Play Store",
"advanced": "Lanjutan",
"algorithm": "Algoritma",
"type": "Tipe",
"period": "Periode",
"digits": "Digit"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Codice QR non valido",
"noRecoveryKeyTitle": "Nessuna chiave di recupero?",
"enterEmailHint": "Inserisci il tuo indirizzo email",
"enterNewEmailHint": "Inserisci il tuo nuovo indirizzo email",
"invalidEmailTitle": "Indirizzo email non valido",
"invalidEmailMessage": "Inserisci un indirizzo email valido.",
"deleteAccount": "Elimina account",
@@ -513,5 +514,10 @@
"free5GB": "5GB gratis su <bold-green>ente</bold-green> Foto",
"loginWithAuthAccount": "Accedi con il tuo account Auth",
"freeStorageOffer": "10% di sconto su <bold-green>ente</bold-green> Foto",
"freeStorageOfferDescription": "Utilizzare il codice \"AUTH\" per ottenere il 10% di sconto al primo anno"
"freeStorageOfferDescription": "Utilizzare il codice \"AUTH\" per ottenere il 10% di sconto al primo anno",
"advanced": "Avanzate",
"algorithm": "Algoritmo",
"type": "Tipo",
"period": "Periodo",
"digits": "Cifre"
}

View File

@@ -508,9 +508,15 @@
"tellUsWhatYouThink": "Pasakykite mums, ką manote",
"dropReviewiOS": "Rašyti apžvalgą parduotuvėje „App Store“",
"dropReviewAndroid": "Rašyti apžvalgą parduotuvėje „Play“ parduotuvė“",
"supportEnte": "Paremti „<bold-green>ente</bold-green>“",
"giveUsAStarOnGithub": "Suteikite mums žvaigždutę platformoje „Github“",
"free5GB": "5 GB nemokami programai „<bold-green>ente</bold-green>“ nuotraukos",
"loginWithAuthAccount": "Prisijungti su jūsų „Auth“ paskyra",
"freeStorageOffer": "10 % nuolaida programai „<bold-green>ente</bold-green>“ nuotraukos",
"freeStorageOfferDescription": "Naudokite kodą „AUTH“, kad gautumėte 10 % nuolaida pirmiesiems metams. "
"freeStorageOfferDescription": "Naudokite kodą „AUTH“, kad gautumėte 10 % nuolaida pirmiesiems metams. ",
"advanced": "Išplėstiniai",
"algorithm": "Algoritmas",
"type": "Tipas",
"period": "Laikotarpis",
"digits": "Skaitmenys"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Ongeldige QR-code",
"noRecoveryKeyTitle": "Geen herstelsleutel?",
"enterEmailHint": "Voer je e-mailadres in",
"enterNewEmailHint": "Voer uw nieuwe e-mailadres in",
"invalidEmailTitle": "Ongeldig e-mailadres",
"invalidEmailMessage": "Voer een geldig e-mailadres in.",
"deleteAccount": "Account verwijderen",
@@ -513,5 +514,10 @@
"free5GB": "5GB gratis op <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Log in met je Auth account",
"freeStorageOffer": "10% korting op <bold-green>ente</bold-green> photos",
"freeStorageOfferDescription": "Gebruik de code \"AUTH\" voor 10% korting op je eerste jaar"
"freeStorageOfferDescription": "Gebruik de code \"AUTH\" voor 10% korting op je eerste jaar",
"advanced": "Geavanceerd",
"algorithm": "Algoritme",
"type": "Type",
"period": "Periode",
"digits": "Cijfers"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "Nieprawidłowy kod QR",
"noRecoveryKeyTitle": "Brak klucza odzyskiwania?",
"enterEmailHint": "Wprowadź adres e-mail",
"enterNewEmailHint": "Wprowadź nowy adres e-mail",
"invalidEmailTitle": "Nieprawidłowy adres e-mail",
"invalidEmailMessage": "Prosimy podać prawidłowy adres e-mail.",
"deleteAccount": "Usuń konto",
@@ -513,5 +514,10 @@
"free5GB": "5 GB za darmo na zdjęcia <bold-green>ente</bold-green>",
"loginWithAuthAccount": "Zaloguj się przy użyciu konta Auth",
"freeStorageOffer": "10% zniżki na zdjęcia <bold-green>ente</bold-green>",
"freeStorageOfferDescription": "Użyj kodu „AUTH”, aby uzyskać 10% zniżki na pierwszy rok"
"freeStorageOfferDescription": "Użyj kodu „AUTH”, aby uzyskać 10% zniżki na pierwszy rok",
"advanced": "Zaawansowane",
"algorithm": "Algorytm",
"type": "Rodzaj",
"period": "Okres",
"digits": "Cyfry"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "QR Code inválido",
"noRecoveryKeyTitle": "Sem chave de recuperação?",
"enterEmailHint": "Insira o endereço de e-mail",
"enterNewEmailHint": "Insira seu novo e-mail",
"invalidEmailTitle": "Endereço de e-mail inválido",
"invalidEmailMessage": "Insira um endereço de e-mail válido.",
"deleteAccount": "Excluir conta",
@@ -513,5 +514,10 @@
"free5GB": "5GB grátis no <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Registrar-se com sua conta Auth",
"freeStorageOffer": "10% de desconto no <bold-green>ente</bold-green> photos",
"freeStorageOfferDescription": "Use o cupom \"AUTH\" para obter 10% de desconto no primeiro ano"
"freeStorageOfferDescription": "Use o cupom \"AUTH\" para obter 10% de desconto no primeiro ano",
"advanced": "Avançado",
"algorithm": "Algoritmo",
"type": "Tipo",
"period": "Período",
"digits": "Dígitos"
}

View File

@@ -0,0 +1,523 @@
{
"account": "Налог",
"unlock": "Откључај",
"recoveryKey": "Резервни Кључ",
"counterAppBarTitle": "Бројач",
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "Сигурносно правити копију 2ФА кôдова",
"onBoardingGetStarted": "Почети",
"setupFirstAccount": "Подесити свој први налог",
"importScanQrCode": "Скенирај QR кôд",
"qrCode": "QR кôд",
"importEnterSetupKey": "Унети кључ за подешавање",
"importAccountPageTitle": "Унети детаље налога",
"secretCanNotBeEmpty": "Тајна не може бити празна",
"bothIssuerAndAccountCanNotBeEmpty": "И издавалац и рачун не могу бити празни",
"incorrectDetails": "Погрешни детаљи",
"pleaseVerifyDetails": "Проверите детаље и покушајте поново",
"codeIssuerHint": "Издавач",
"codeSecretKeyHint": "Тајни кључ",
"secret": "Тајна",
"all": "Све",
"notes": "Белешке",
"notesLengthLimit": "Белешке могу имати највише {count} знакова",
"@notesLengthLimit": {
"description": "Text to indicate the maximum number of characters allowed for notes",
"placeholders": {
"count": {
"description": "The maximum number of characters allowed for notes",
"type": "int",
"example": "100"
}
}
},
"codeAccountHint": "Налог (you@domain.com)",
"codeTagHint": "Ознака",
"accountKeyType": "Тип кључа",
"sessionExpired": "Сесија је истекла",
"@sessionExpired": {
"description": "Title of the dialog when the users current session is invalid/expired"
},
"pleaseLoginAgain": "Молимо да се поново пријавите",
"loggingOut": "Одјављивање...",
"timeBasedKeyType": "Временски (TOTP)",
"counterBasedKeyType": "На основу бројања (HOTP)",
"saveAction": "Сачувај",
"nextTotpTitle": "следеће",
"deleteCodeTitle": "Обрисати кôд?",
"deleteCodeMessage": "Сигурно желите да избришете овај кôд? Ова акција је неповратна.",
"trashCode": "Кôд у смеће?",
"trashCodeMessage": "Сигурно желите да поставите кôд у смеће за {account}?",
"trash": "Смеће",
"viewLogsAction": "Прегледај извештаје",
"sendLogsDescription": "Ово ће делите ваше записе како би нам помогли да вам исправимо проблем. Док преузмемо мере предострожности да осигурамо да осетљиве информације нису пријављене, охрабрујемо вас да прегледате ове записе пре него што их делите.",
"preparingLogsTitle": "Спремање извештаја...",
"emailLogsTitle": "Имејловати извештаје",
"emailLogsMessage": "Пошаљите извештаје на {email}",
"@emailLogsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"copyEmailAction": "Копирати имејл",
"exportLogsAction": "Извези изештаје",
"reportABug": "Пријави грешку",
"crashAndErrorReporting": "Пријављивање дања и грешке",
"reportBug": "Пријaви грешку",
"emailUsMessage": "Пошаљите нам имејл на {email}",
"@emailUsMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"contactSupport": "Контактирати подршку",
"rateUsOnStore": "Оцените нас на {storeName}",
"blog": "Блог",
"merchandise": "Роба",
"verifyPassword": "Верификујте лозинку",
"pleaseWait": "Молимо сачекајте...",
"generatingEncryptionKeysTitle": "Генерисање кључева за шифровање...",
"recreatePassword": "Поново креирати лозинку",
"recreatePasswordMessage": "Тренутни уређај није довољно моћан да потврди вашу лозинку, тако да је морамо да регенеришемо једном на начин који ради са свим уређајима. \n\nПријавите се помоћу кључа за опоравак и обновите своју лозинку (можете поново користити исту ако желите).",
"useRecoveryKey": "Користите кључ за опоравак",
"incorrectPasswordTitle": "Неисправна лозинка",
"welcomeBack": "Добродошли назад!",
"emailAlreadyRegistered": "Имејл је већ регистрован.",
"emailNotRegistered": "Имејл није регистрован.",
"madeWithLoveAtPrefix": "урађено са ❤️ на ",
"supportDevs": "Претплатити се на <bold-green>ente</bold-green> да би нас подржали",
"supportDiscount": "Употребите купон \"AUTH\" да би добили попуст од 10% прве године",
"changeEmail": "Промени имејл",
"changePassword": "Промени лозинку",
"data": "Подаци",
"importCodes": "Увоз кôдова",
"importTypePlainText": "Обичан текст",
"importTypeEnteEncrypted": "Ente шифрован извоз",
"passwordForDecryptingExport": "Лозинка за дешифровање извоза",
"passwordEmptyError": "Лозинка не може да буде празна",
"importFromApp": "Увоз кôдова од {appName}",
"importGoogleAuthGuide": "Извезите своје рачуне од Google Authenticator на QR кôд помоћу опције \"Трансфер налоге\". Затим помоћу другог уређаја скенирајте QR кôд.\n\nСавет: можете користити веб камеру вашег лаптопа да бисте снимили слику QR кôда.",
"importSelectJsonFile": "Одабрати JSON датотеку",
"importSelectAppExport": "Одабрати извозну датотеку {appName}-а",
"importEnteEncGuide": "Одабрати шифровану извозну JSON датотеку од Ente",
"importRaivoGuide": "Употребите \"Export OTPs to Zip archive\" опцију из подешавања Raivo-а.\n\nИздвојите zip датотеку и увезите JSON датотеку.",
"importBitwardenGuide": "Употребите \"Извоз Сефа\" из Bitwarden и увезите нешифровану JSON датотеку.",
"importAegisGuide": "Употребити \"Export the vault\" из Aegis-а.\n\nАко је сеф шифрован, мораћете унети лозинку сефа да би га дешифровали.",
"import2FasGuide": "Употребити \"Settings->Backup -Export\" из 2FAS-а.\n\nАко је ваша копија шифрирана, мораћете да унесете лозинку за дешифрирање копије",
"importLastpassGuide": "Употребити \"Transfer accounts\" из Lastpass Authenticator и стисните \"Export accounts to file\". Унесите преузет JSON.",
"exportCodes": "Извоз кôдова",
"importLabel": "Увоз",
"importInstruction": "Изаберите датотеку која садржи списак ваших кôдова у следећем формату",
"importCodeDelimiterInfo": "Кôдови се могу одвојити зарезом или новом линијом",
"selectFile": "Изаберите датотеку",
"emailVerificationToggle": "Имејл провера",
"emailVerificationEnableWarning": "Да бисте избегли да се закључате са свог рачуна, обавезно чувајте копију 2ФА имејла ван Ente Auth пре него што омогућите имејл верификацију.",
"authToChangeEmailVerificationSetting": "Потврдите аутентичност да промените верификацији имејл",
"authenticateGeneric": "Молимо потврдите аутентичност",
"authToViewYourRecoveryKey": "Аутентификујте се да бисте погледали кључ за опоравак",
"authToChangeYourEmail": "Аутентификујте се да бисте променили имејл",
"authToChangeYourPassword": "Аутентификујте се да бисте променили лозинку",
"authToViewSecrets": "Аутентификујте се да бисте прегледали Ваше тајне",
"authToInitiateSignIn": "Аутентификујте се да бисте почели пријављивање за копију.",
"ok": "У реду",
"cancel": "Откажи",
"yes": "Да",
"no": "Не",
"email": "Имејл",
"support": "Подршка",
"general": "Опште",
"settings": "Подешавања",
"copied": "Копирано",
"pleaseTryAgain": "Пробајте поново",
"existingUser": "Постојећи корисник",
"newUser": "Нов у Ente",
"delete": "Обриши",
"enterYourPasswordHint": "Унесите лозинку",
"forgotPassword": "Заборавио сам лозинку",
"oops": "Упс",
"suggestFeatures": "Предложи карактеристике",
"faq": "Питања",
"somethingWentWrongMessage": "Нешто је пошло наопако, покушајте поново",
"leaveFamily": "Напусти family претплату",
"leaveFamilyMessage": "Јесте ли сигурни да желите да напустите family чланство?",
"inFamilyPlanMessage": "Имате family чланство!",
"hintForMobile": "Дуго притисните кôд за уређивање или уклањање.",
"hintForDesktop": "Десни клик на кôд за уређивање или уклањање.",
"scan": "Скенирај",
"scanACode": "Скенирај кôд",
"verify": "Верификуј",
"verifyEmail": "Потврди имејл",
"enterCodeHint": "Унесите 6-цифрени кôд из\nапликације за аутентификацију",
"lostDeviceTitle": "Узгубили сте уређај?",
"twoFactorAuthTitle": "Дво-факторска аутентификација",
"passkeyAuthTitle": "Верификација сигурносном кључем",
"verifyPasskey": "Проверите сигурносни кључ",
"loginWithTOTP": "Пријава са TOTP",
"recoverAccount": "Опоравак налога",
"enterRecoveryKeyHint": "Унети кључ за опоравак",
"recover": "Опорави",
"contactSupportViaEmailMessage": "Послати имејл на {email} са регистрованог имејла",
"@contactSupportViaEmailMessage": {
"placeholders": {
"email": {
"type": "String"
}
}
},
"invalidQRCode": "Неважећи QR кôд",
"noRecoveryKeyTitle": "Немате кључ за опоравак?",
"enterEmailHint": "Унесите Ваш имејл",
"enterNewEmailHint": "Унесите Ваш нови имејл",
"invalidEmailTitle": "Погрешна имејл адреса",
"invalidEmailMessage": "Унесите важећи имејл.",
"deleteAccount": "Избриши налог",
"deleteAccountQuery": "Жао нам је што одлазите. Да ли се суочавате са неком грешком?",
"yesSendFeedbackAction": "Да, послати повратне информације",
"noDeleteAccountAction": "Не, избрисати налог",
"initiateAccountDeleteTitle": "Молимо вас да се аутентификујете за брисање рачуна",
"sendEmail": "Шаљи имејл",
"createNewAccount": "Креирај нови налог",
"weakStrength": "Слабо",
"strongStrength": "Јако",
"moderateStrength": "Умерено",
"confirmPassword": "Потврдите лозинку",
"close": "Затвори",
"oopsSomethingWentWrong": "Нешто није у реду.",
"selectLanguage": "Изабери језик",
"language": "Језик",
"social": "Друштвене мреже",
"security": "Безбедност",
"lockscreen": "Закључавање екрана",
"authToChangeLockscreenSetting": "Аутентификујте се да бисте променили закључавање екрана",
"deviceLockEnablePreSteps": "Да бисте омогућили закључавање уређаја, молимо вас да подесите шифру уређаја или закључавање екрана у системским подешавањима.",
"viewActiveSessions": "Видети активне сесије",
"authToViewYourActiveSessions": "Аутентификујте се да бисте преглеадали активне сесије",
"searchHint": "Претрага...",
"search": "Претрага",
"sorryUnableToGenCode": "Извините, не могу да генеришем кôд за {issuerName}",
"noResult": "Нема резултата",
"addCode": "Додај кôд",
"scanAQrCode": "Скенирај QR кôд",
"enterDetailsManually": "Ручно унети детеље",
"edit": "Уреди",
"share": "Подели",
"shareCodes": "Дели кôдове",
"shareCodesDuration": "Изаберите трајање за које желите да поделите кôдове.",
"restore": "Врати",
"copiedToClipboard": "Копирано у оставу",
"copiedNextToClipboard": "Копирали следећи кôд у остави",
"error": "Грешка",
"recoveryKeyCopiedToClipboard": "Кључ за опоравак копирано у остави",
"recoveryKeyOnForgotPassword": "Ако заборавите лозинку, једини начин на који можете повратити податке је са овим кључем.",
"recoveryKeySaveDescription": "Не чувамо овај кључ, молимо да сачувате кључ од 24 речи на сигурном месту.",
"doThisLater": "Уради то касније",
"saveKey": "Сачувај кључ",
"save": "Сачувај",
"send": "Пошаљи",
"saveOrSendDescription": "Да ли желите да ово сачувате у складиште (фасцикли за преузимање подразумевано) или да га пошаљете другим апликацијама?",
"saveOnlyDescription": "Да ли желите да ово сачувате у складиште (фасцикли за преузимање подразумевано)?",
"back": "Назад",
"createAccount": "Направи налог",
"passwordStrength": "Снага лозинке: {passwordStrengthValue}",
"@passwordStrength": {
"description": "Text to indicate the password strength",
"placeholders": {
"passwordStrengthValue": {
"description": "The strength of the password as a string",
"type": "String",
"example": "Weak or Moderate or Strong"
}
},
"message": "Password Strength: {passwordStrengthText}"
},
"password": "Лозинка",
"signUpTerms": "Прихватам <u-terms>услове сервиса</u-terms> и <u-policy>политику приватности</u-policy>",
"privacyPolicyTitle": "Политика приватности",
"termsOfServicesTitle": "Услови",
"encryption": "Шифровање",
"setPasswordTitle": "Постави лозинку",
"changePasswordTitle": "Промени лозинку",
"resetPasswordTitle": "Ресетуј лозинку",
"encryptionKeys": "Кључеве шифровања",
"passwordWarning": "Не чувамо ову лозинку, па ако је заборавите, <underline>не можемо дешифрирати ваше податке</underline>",
"enterPasswordToEncrypt": "Унесите лозинку за употребу за шифровање ваших података",
"enterNewPasswordToEncrypt": "Унесите нову лозинку за употребу за шифровање ваших података",
"passwordChangedSuccessfully": "Лозинка је успешно промењена",
"generatingEncryptionKeys": "Генерисање кључева за шифровање...",
"continueLabel": "Настави",
"insecureDevice": "Уређај није сигуран",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Извините, не можемо да генеришемо сигурне кључеве на овом уређају.\n\nМолимо пријавите се са другог уређаја.",
"howItWorks": "Како то функционише",
"ackPasswordLostWarning": "Разумем да ако изгубим лозинку, могу изгубити своје податке пошто су <underline>шифрирани од краја до краја</underline>.",
"loginTerms": "Кликом на пријаву, прихватам <u-terms>услове сервиса</u-terms> и <u-policy>политику приватности</u-policy>",
"logInLabel": "Пријави се",
"logout": "Одјави ме",
"areYouSureYouWantToLogout": "Да ли сте сигурни да се одјавите?",
"yesLogout": "Да, одјави ме",
"exit": "Излаз",
"theme": "Тема",
"lightTheme": "Светла",
"darkTheme": "Tamna",
"systemTheme": "Систем",
"verifyingRecoveryKey": "Провера кључа за опоравак...",
"recoveryKeyVerified": "Кључ за опоравак је проверен",
"recoveryKeySuccessBody": "Сјајно! Ваш кључ за опоравак важи. Хвала за проверу.\n\nИмајте на уму да задржите кључ за опоравак на сигрном.",
"invalidRecoveryKey": "Кључ за опоравак који сте унели није валидан. Молимо вас да будете сигурни да садржи 24 речи и проверите правопис сваког.\n\nАко сте унели старији кôд за опоравак, проверите да ли је дугачак 64 знака и проверите сваки од њих.",
"recreatePasswordTitle": "Поново креирати лозинку",
"recreatePasswordBody": "Тренутни уређај није довољно моћан да потврди вашу лозинку, али можемо регенерирати на начин који ради са свим уређајима.\n\nПријавите се помоћу кључа за опоравак и обновите своју лозинку (можете поново користити исту ако желите).",
"invalidKey": "Неисправан кључ",
"tryAgain": "Покушај поново",
"viewRecoveryKey": "Видети кључ за опоравак",
"confirmRecoveryKey": "Потврдити кључ за опоравак",
"recoveryKeyVerifyReason": "Ваш кључ за опоравак је једини начин да се врате фотографије ако заборавите лозинку. Можете пронаћи свој кључ за опоравак у Подешавања> Рачун.\n\nОвдје унесите кључ за опоравак да бисте проверили да ли сте га исправно сачували.",
"confirmYourRecoveryKey": "Потврдити кључ за опоравак",
"confirm": "Потврди",
"emailYourLogs": "Имејлирајте извештаје",
"pleaseSendTheLogsTo": "Пошаљите извештаје на \n{toEmail}",
"copyEmailAddress": "Копирати имејл адресу",
"exportLogs": "Извези изештаје",
"enterYourRecoveryKey": "Унети кључ за опоравак",
"tempErrorContactSupportIfPersists": "Изгледа да је нешто погрешно. Покушајте поново након неког времена. Ако грешка настави, обратите се нашем тиму за подршку.",
"networkHostLookUpErr": "Није могуће повезивање са Ente-ом, молимо вас да проверите мрежне поставке и контактирајте подршку ако грешка и даље постоји.",
"networkConnectionRefusedErr": "Није могуће повезивање са Ente-ом, покушајте поново мало касније. Ако грешка настави, обратите се подршци.",
"itLooksLikeSomethingWentWrongPleaseRetryAfterSome": "Изгледа да је нешто погрешно. Покушајте поново након неког времена. Ако грешка настави, обратите се нашем тиму за подршку.",
"about": "О програму",
"weAreOpenSource": "Користимо отворени извор!",
"privacy": "Приватност",
"terms": "Услови",
"checkForUpdates": "Провери ажурирања",
"checkStatus": "Провери статус",
"downloadUpdate": "Преузми",
"criticalUpdateAvailable": "Критично ажурирање је доступно",
"updateAvailable": "Доступно ажурирање",
"update": "Ажурирај",
"checking": "Провера...",
"youAreOnTheLatestVersion": "Користите најновију верзију",
"warning": "Упозорење",
"exportWarningDesc": "Извозна датотека садржи осетљиве информације. Молимо вас да је чувате на сигурно.",
"iUnderStand": "Разумем",
"@iUnderStand": {
"description": "Text for the button to confirm the user understands the warning"
},
"authToExportCodes": "Аутентификујте се да бисте извезли кôдове",
"importSuccessTitle": "Jeeee!",
"importSuccessDesc": "Увели сте {count} кôдова!",
"@importSuccessDesc": {
"placeholders": {
"count": {
"description": "The number of codes imported",
"type": "int",
"example": "1"
}
}
},
"sorry": "Жао ми је",
"importFailureDesc": "Нисам могао да анализирам изабрану датотеку.\nПишите на support@ente.io ако вам је потребна помоћ!",
"pendingSyncs": "Упозорење",
"pendingSyncsWarningBody": "Неки од ваших кôдова нису сачувани.\n\nМолимо вас осигурајте да имате резервну копију за ове кôдове пре него што се одјавите.",
"checkInboxAndSpamFolder": "Молимо вас да проверите примљену пошту (и нежељену пошту) да бисте довршили верификацију",
"tapToEnterCode": "Пипните да бисте унели кôд",
"resendEmail": "Поново послати имејл",
"weHaveSendEmailTo": "Послали смо имејл на <green>{email}</green>",
"@weHaveSendEmailTo": {
"description": "Text to indicate that we have sent a mail to the user",
"placeholders": {
"email": {
"description": "The email address of the user",
"type": "String",
"example": "example@ente.io"
}
}
},
"manualSort": "Прилагођено",
"editOrder": "Уреди поредак",
"mostFrequentlyUsed": "Често коришћено",
"mostRecentlyUsed": "Недавно коришћено",
"activeSessions": "Активне сесије",
"somethingWentWrongPleaseTryAgain": "Нешто је пошло наопако. Покушајте поново",
"thisWillLogYouOutOfThisDevice": "Ово ће вас одјавити из овог уређаја!",
"thisWillLogYouOutOfTheFollowingDevice": "Ово ће вас одјавити из овог уређаја:",
"terminateSession": "Прекинути сесију?",
"terminate": "Прекини",
"thisDevice": "Овај уређај",
"toResetVerifyEmail": "Да бисте ресетовали лозинку, прво потврдите свој имејл.",
"thisEmailIsAlreadyInUse": "Овај имејл је већ у употреби",
"verificationFailedPleaseTryAgain": "Неуспешна верификација, покушајте поново",
"yourVerificationCodeHasExpired": "Ваш верификациони кôд је истекао",
"incorrectCode": "Погрешан кôд",
"sorryTheCodeYouveEnteredIsIncorrect": "Унет кôд није добар",
"emailChangedTo": "Имејл промењен на {newEmail}",
"authenticationFailedPleaseTryAgain": "Аутентификација није успела, покушајте поново",
"authenticationSuccessful": "Успешна аутентификација!",
"twofactorAuthenticationSuccessfullyReset": "Двофакторска аутентификација успешно рисетирана",
"incorrectRecoveryKey": "Нетачан кључ за опоравак",
"theRecoveryKeyYouEnteredIsIncorrect": "Унети кључ за опоравак је натачан",
"enterPassword": "Унеси лозинку",
"selectExportFormat": "Изабрати формат извоза",
"exportDialogDesc": "Шифровани извоз ће бити заштићен лозинком по вашем избору.",
"encrypted": "Шифровано",
"plainText": "Обичан текст",
"passwordToEncryptExport": "Лозинка за шифровање извоза",
"export": "Извези",
"useOffline": "Користите без резервних копија",
"signInToBackup": "Пријавите се да бисте сачували кôдове",
"singIn": "Пријавите се",
"sigInBackupReminder": "Извезите кôдове да бисте имали резервну копију од које можете да их вратите.",
"offlineModeWarning": "Одлучили сте да наставите без резервних копија. Молимо примите ручне резервне копије да бисте били сигурни да су ваше кодове на сигурном.",
"showLargeIcons": "Прикажи велике иконе",
"compactMode": "Компактни режим",
"shouldHideCode": "Сакриј кодове",
"doubleTapToViewHiddenCode": "Можете да двапут додирнете унос да бисте видели кôд",
"focusOnSearchBar": "Фокус на претрагу на покретање",
"confirmUpdatingkey": "Јесте ли сигурни да желите да ажурирате тајну кључ?",
"minimizeAppOnCopy": "Умањи апликацију после копије",
"editCodeAuthMessage": "Аутентификуј се за уред кôда",
"deleteCodeAuthMessage": "Аутентификуј се за брсање кôда",
"showQRAuthMessage": "Аутентификуј се за приказ QR кôда",
"confirmAccountDeleteTitle": "Потврда брисања рачуна",
"confirmAccountDeleteMessage": "Овај налог је повезан са другим Ente апликацијама, ако користите било коју.\n\nВаши преношени подаци, на свим Ente апликацијама биће заказани за брисање, и ваш рачун ће се трајно избрисати.",
"androidBiometricHint": "Потврдите идентитет",
"@androidBiometricHint": {
"description": "Hint message advising the user how to authenticate with biometrics. It is used on Android side. Maximum 60 characters."
},
"androidBiometricNotRecognized": "Нисмо препознали. Покушати поново.",
"@androidBiometricNotRecognized": {
"description": "Message to let the user know that authentication was failed. It is used on Android side. Maximum 60 characters."
},
"androidBiometricSuccess": "Успех",
"@androidBiometricSuccess": {
"description": "Message to let the user know that authentication was successful. It is used on Android side. Maximum 60 characters."
},
"androidCancelButton": "Откажи",
"@androidCancelButton": {
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on Android side. Maximum 30 characters."
},
"androidSignInTitle": "Потребна аутентификација",
"@androidSignInTitle": {
"description": "Message showed as a title in a dialog which indicates the user that they need to scan biometric to continue. It is used on Android side. Maximum 60 characters."
},
"androidBiometricRequiredTitle": "Потребна је биометрија",
"@androidBiometricRequiredTitle": {
"description": "Message showed as a title in a dialog which indicates the user has not set up biometric authentication on their device. It is used on Android side. Maximum 60 characters."
},
"androidDeviceCredentialsRequiredTitle": "Потребни су акредитиви уређаја",
"@androidDeviceCredentialsRequiredTitle": {
"description": "Message showed as a title in a dialog which indicates the user has not set up credentials authentication on their device. It is used on Android side. Maximum 60 characters."
},
"androidDeviceCredentialsSetupDescription": "Потребни су акредитиви уређаја",
"@androidDeviceCredentialsSetupDescription": {
"description": "Message advising the user to go to the settings and configure device credentials on their device. It shows in a dialog on Android side."
},
"goToSettings": "Иди на поставке",
"@goToSettings": {
"description": "Message showed on a button that the user can click to go to settings pages from the current dialog. It is used on both Android and iOS side. Maximum 30 characters."
},
"androidGoToSettingsDescription": "Биометријска аутентификација није постављена на вашем уређају. Идите на \"Подешавања> Сигурност\" да бисте додали биометријску аутентификацију.",
"@androidGoToSettingsDescription": {
"description": "Message advising the user to go to the settings and configure biometric on their device. It shows in a dialog on Android side."
},
"iOSLockOut": "Биометријска аутентификација је онемогућена. Закључајте и откључите екран да бисте је омогућили.",
"@iOSLockOut": {
"description": "Message advising the user to re-enable biometrics on their device. It shows in a dialog on iOS side."
},
"iOSGoToSettingsDescription": "Биометријска аутентификација није постављена на вашем уређају. Молимо или омогућите Touch ID или Face ID.",
"@iOSGoToSettingsDescription": {
"description": "Message advising the user to go to the settings and configure Biometrics for their device. It shows in a dialog on iOS side."
},
"iOSOkButton": "У реду",
"@iOSOkButton": {
"description": "Message showed on a button that the user can click to leave the current dialog. It is used on iOS side. Maximum 30 characters."
},
"noInternetConnection": "Нема интернет везе",
"pleaseCheckYourInternetConnectionAndTryAgain": "Провери своју везу са интернетом и покушај поново.",
"signOutFromOtherDevices": "Одјави се из других уређаја",
"signOutOtherBody": "Ако мислиш да неко може знати твоју лозинку, можеш приморати одјављивање све остале уређаје које користе твој налог.",
"signOutOtherDevices": "Одјави друге уређаје",
"doNotSignOut": "Не одјави",
"hearUsWhereTitle": "Како сте чули о Ente? (опционо)",
"hearUsExplanation": "Не пратимо инсталацију апликације. Помогло би да нам кажеш како си нас нашао!",
"recoveryKeySaved": "Кључ за опоравак сачуван у фасцикли за преузимање!",
"waitingForBrowserRequest": "Чека се захтев за претраживач...",
"waitingForVerification": "Чека се верификација...",
"passkey": "Кључ за приступ",
"passKeyPendingVerification": "Верификација је још у току",
"loginSessionExpired": "Сесија је истекла",
"loginSessionExpiredDetails": "Ваша сесија је истекла. Молимо пријавите се поново.",
"developerSettingsWarning": "Сигурно желиш да промениш подешавања за програмере?",
"developerSettings": "Подешавања за програмере",
"serverEndpoint": "Крајња тачка сервера",
"invalidEndpoint": "Погрешна крајња тачка",
"invalidEndpointMessage": "Извини, крајња тачка коју си унео је неважећа. Унеси важећу крајњу тачку и покушај поново.",
"endpointUpdatedMessage": "Крајна тачка успешно ажурирана",
"customEndpoint": "Везано за {endpoint}",
"pinText": "Закачи",
"unpinText": "Откачи",
"pinnedCodeMessage": "{code} је прикачен",
"unpinnedCodeMessage": "{code} је одкачен",
"pinned": "Прикачено",
"tags": "Ознаке",
"createNewTag": "Креирај нову ознаку",
"tag": "Ознака",
"create": "Направи",
"editTag": "Уреди ознаку",
"deleteTagTitle": "Обрисати ознаку?",
"deleteTagMessage": "Сигурно желите да избришете ову ознаку? Ова акција је неповратна.",
"somethingWentWrongParsingCode": "Нисмо били у стању да рашчланимо {x} кôдова.",
"updateNotAvailable": "Ажурирање није доступно",
"viewRawCodes": "Погледајте сирове кôдове",
"rawCodes": "Сирове кôдове",
"rawCodeData": "Податак сировог кôда",
"appLock": "Закључавање апликације",
"noSystemLockFound": "Није пронађено ниједно закључавање система",
"toEnableAppLockPleaseSetupDevicePasscodeOrScreen": "Да бисте омогућили закључавање апликације, молимо вас да подесите шифру уређаја или закључавање екрана у системским подешавањима.",
"autoLock": "Ауто-закључавање",
"immediately": "Одмах",
"reEnterPassword": "Поново унеси лозинку",
"reEnterPin": "Поново унеси ПИН",
"next": "Следеће",
"tooManyIncorrectAttempts": "Превише погрешних покушаја",
"tapToUnlock": "Додирните да бисте откључали",
"setNewPassword": "Постави нову лозинку",
"deviceLock": "Закључавање уређаја",
"hideContent": "Сакриј садржај",
"hideContentDescriptionAndroid": "Сакрива садржај апликације у пребацивање апликација и онемогућује снимке екрана",
"hideContentDescriptioniOS": "Сакрива садржај апликације у пребацивање апликација",
"autoLockFeatureDescription": "Време након којег се апликација блокира након што је постављенеа у позадину",
"appLockDescription": "Изаберите између заданог закључавање екрана вашег уређаја и прилагођени екран за закључавање са ПИН-ом или лозинком.",
"pinLock": "ПИН клокирање",
"enterPin": "Унеси ПИН",
"setNewPin": "Постави нови ПИН",
"importFailureDescNew": "Није могао да анализира изабрану датотеку.",
"appLockNotEnabled": "Блокирање апликације није упаљено",
"appLockNotEnabledDescription": "Молимо упалие блокирање апликације на Безбедност > Блокирај апликацију",
"authToViewPasskey": "Аутентификујте се да бисте прегледали кључ",
"appLockOfflineModeWarning": "Одлучили сте да наставите без резервних копија. Ако заборавите лозинку, нећете моћи да приступите својим подацима.",
"duplicateCodes": "Дупликатни кодови",
"noDuplicates": "✨ Нема дупликата",
"youveNoDuplicateCodesThatCanBeCleared": "Немате дупликатне кодове који се могу очистити",
"deduplicateCodes": "Дедуплицирај кодове",
"deselectAll": "Поништи избор свега",
"selectAll": "Изабери све",
"deleteDuplicates": "Обриши дупликате",
"plainHTML": "HTML",
"tellUsWhatYouThink": "Реци нам шта мислиш",
"dropReviewiOS": "Напиши мишљење на App Store",
"dropReviewAndroid": "Напиши мишљење на Play Store",
"supportEnte": "Подржи <bold-green>ente</bold-green>",
"giveUsAStarOnGithub": "Дај нам звездицу на Github",
"free5GB": "5GB бесплатно на <bold-green>ente</bold-green> Photos",
"loginWithAuthAccount": "Пријави се са твојим Auth налогом",
"freeStorageOffer": "Попуст од 10% на <bold-green>ente</bold-green> photos",
"freeStorageOfferDescription": "Употребите кôд \"AUTH\" да би добили попуст од 10% прве године",
"advanced": "Напредно",
"algorithm": "Алгоритам",
"type": "Тип",
"period": "Период",
"digits": "Цифре"
}

View File

@@ -6,10 +6,10 @@
"@counterAppBarTitle": {
"description": "Text shown in the AppBar of the Counter Page"
},
"onBoardingBody": "2 Faktörlü Kimlik Doğrulama kodlarınızı koruyun",
"onBoardingBody": "2FA kodlarınızı güvenli bir şekilde yedekleyin",
"onBoardingGetStarted": "Başlayın",
"setupFirstAccount": "İlk hesabınızı ekleyin",
"importScanQrCode": "Karekod tara",
"importScanQrCode": "QR kod tara",
"qrCode": "QR Kodu",
"importEnterSetupKey": "Kurulum anahtarını giriniz",
"importAccountPageTitle": "Hesap bilgilerinizi girin",
@@ -51,11 +51,11 @@
"trashCode": "Kod çöpe atılsın mı?",
"trashCodeMessage": "{account} için kodu çöpe atmak istediğinize emin misiniz?",
"trash": "Çöp",
"viewLogsAction": "Günlüğü görüntüle",
"sendLogsDescription": "Günlüğünüz hatanızı çözmemize yardımcı olacaktır. Hassas bilginin kaydedilmediğine dikkat etsek de bu günlükleri paylaşmadan önce kontrol etmenizi isteriz.",
"preparingLogsTitle": "Günlük hazırlanıyor...",
"emailLogsTitle": "Günlüğü e-posta olarak gönder",
"emailLogsMessage": "Lütfen günlüğünüzü {email} adresine gönderin",
"viewLogsAction": "Kayıtları görüntüle",
"sendLogsDescription": "Kayıtlarınız hatanızı çözmemize yardımcı olacaktır. Hassas bilginin kaydedilmediğine dikkat etsek de bu günlükleri paylaşmadan önce kontrol etmenizi isteriz.",
"preparingLogsTitle": "Kayıtlar hazırlanıyor...",
"emailLogsTitle": "Kayıtları e-posta olarak gönder",
"emailLogsMessage": "Lütfen kayıtlarınızı {email} adresine gönderin",
"@emailLogsMessage": {
"placeholders": {
"email": {
@@ -64,7 +64,7 @@
}
},
"copyEmailAction": "E-postayı Kopyala",
"exportLogsAction": "Günlüğü dışa aktar",
"exportLogsAction": "Kayıtları dışa aktar",
"reportABug": "Hata bildirin",
"crashAndErrorReporting": "Çökme ve hata bildirimi",
"reportBug": "Hata bildir",
@@ -90,7 +90,7 @@
"welcomeBack": "Tekrar hoş geldiniz!",
"emailAlreadyRegistered": "E-posta zaten kayıtlı.",
"emailNotRegistered": "E-posta kayıtlı değil.",
"madeWithLoveAtPrefix": "❤️ ile şurada yapılmıştır ",
"madeWithLoveAtPrefix": "❤️ ile yapılmıştır ",
"supportDevs": "Bu projeyi desteklemek için <bold-green>ente</bold-green> kanalına abone olun",
"supportDiscount": "İlk yılda %10 indirim için \"AUTH\" kupon kodunu kullanın",
"changeEmail": "E-posta adresini değiştir",
@@ -173,10 +173,11 @@
"invalidQRCode": "Geçersiz QR kodu",
"noRecoveryKeyTitle": "Kurtarma anahtarınız yok mu?",
"enterEmailHint": "E-posta adresinizi girin",
"enterNewEmailHint": "Yeni e-posta adresinizi girin",
"invalidEmailTitle": "Geçersiz e-posta adresi",
"invalidEmailMessage": "Lütfen geçerli bir e-posta adresi girin.",
"deleteAccount": "Hesabı sil",
"deleteAccountQuery": "Sizin gitmenizi görmekten üzüleceğiz. Bazı problemlerle mi karşılaşıyorsunuz?",
"deleteAccountQuery": "Sizin gittiğinizi görmekten üzüleceğiz. Bazı problemlerle mi karşılaşıyorsunuz?",
"yesSendFeedbackAction": "Evet, geri bildirimi gönder",
"noDeleteAccountAction": "Hayır, hesabı sil",
"initiateAccountDeleteTitle": "Hesap silme işlemini yapabilmek için lütfen kimliğinizi doğrulayın",
@@ -253,8 +254,8 @@
"insecureDevice": "Güvenli olmayan cihaz",
"sorryWeCouldNotGenerateSecureKeysOnThisDevicennplease": "Üzgünüz, bu cihazda güvenli anahtarlar oluşturamadık.\n\nlütfen farklı bir cihazdan kaydolun.",
"howItWorks": "Nasıl çalışır",
"ackPasswordLostWarning": "Eğer şifremi kaybedersem, verilerim <underline>uçtan uca şifrelendiğinden</underline> verilerimi kaybedebileceğimi anladım.",
"loginTerms": "Giriş yaparak, <u-terms>kullanım şartları</u-terms>nı ve <u-policy>gizlilik politikası</u-policy>nı onaylıyorum",
"ackPasswordLostWarning": "Eğer şifremi kaybedersem, verilerim <underline> uçtan uca şifrelendiğinden </underline> verilerimi kaybedebileceğimi anladım.",
"loginTerms": "Giriş yaparak, <u-terms> kullanım şartları </u-terms>nı ve <u-policy> gizlilik politikası </u-policy>nı onaylıyorum",
"logInLabel": "Giriş yapın",
"logout": "Çıkış yap",
"areYouSureYouWantToLogout": "Çıkış yapmak istediğinize emin misiniz?",
@@ -277,10 +278,10 @@
"recoveryKeyVerifyReason": "Kurtarma anahtarınız, şifrenizi unutmanız durumunda fotoğraflarınızı kurtarmanın tek yoludur. Kurtarma anahtarınızı Ayarlar > Hesap bölümünde bulabilirsiniz.\n\nDoğru kaydettiğinizi doğrulamak için lütfen kurtarma anahtarınızı buraya girin.",
"confirmYourRecoveryKey": "Kurtarma anahtarınızı doğrulayın",
"confirm": "Doğrula",
"emailYourLogs": "Günlüklerinizi e-postayla gönderin",
"pleaseSendTheLogsTo": "Lütfen günlükleri şu adrese gönderin\n{toEmail}",
"emailYourLogs": "Kayıtlarınızı e-postayla gönderin",
"pleaseSendTheLogsTo": "Lütfen kayıtları şu adrese gönderin\n{toEmail}",
"copyEmailAddress": "E-posta adresini kopyala",
"exportLogs": "Günlüğü dışa aktar",
"exportLogs": "Kayıtları dışa aktar",
"enterYourRecoveryKey": "Kurtarma anahtarınızı girin",
"tempErrorContactSupportIfPersists": "Bir şeyler ters gitmiş gibi görünüyor. Lütfen bir süre sonra tekrar deneyin. Hata devam ederse, lütfen destek ekibimizle iletişime geçin.",
"networkHostLookUpErr": "Ente'ye bağlanılamıyor, lütfen ağ ayarlarınızı kontrol edin ve hata devam ederse desteğe başvurun.",
@@ -499,10 +500,24 @@
"appLockOfflineModeWarning": "Yedekleme olmadan devam etmeyi seçtiniz. Eğer uygulama parolanızı unutursanız, verilerinize erişiminiz engellenir.",
"duplicateCodes": "Yinelenen kodlar",
"noDuplicates": "✨ Yinelenen yok",
"youveNoDuplicateCodesThatCanBeCleared": "Temizlenebilecek herhangi bir yinelenen kodunuz yok",
"deduplicateCodes": "Kodları tekilleştir",
"deselectAll": "Tümünün seçimini kaldır",
"selectAll": "Tümünü seç",
"deleteDuplicates": "Yinelenenleri sil",
"plainHTML": "Sade HTML",
"supportEnte": "<bold-Green>Ente</bold-Green>'yi destekle"
"tellUsWhatYouThink": "Bize ne düşündüğünü söyle",
"dropReviewiOS": "App Store'da bir inceleme bırakın",
"dropReviewAndroid": "Play Store'da bir inceleme bırakın",
"supportEnte": "<bold-Green>Ente</bold-Green>'yi destekle",
"giveUsAStarOnGithub": "Github'da bize bir yıldız verin",
"free5GB": "<bold-green>ente</bold-green> Fotoğraflarında 5GB ücretsiz",
"loginWithAuthAccount": "Kimlik Doğrulama hesabınızla giriş yapın",
"freeStorageOffer": "<bold-green>ente</bold-green> fotoğraflarında %10 indirim",
"freeStorageOfferDescription": "İlk yılda %10 indirim almak için \"AUTH\" kodunu kullanın",
"advanced": "Gelişmiş",
"algorithm": "Algoritma",
"type": "Tür",
"period": "Zaman Aralığı",
"digits": "Uzunluk"
}

View File

@@ -173,6 +173,7 @@
"invalidQRCode": "二维码无效",
"noRecoveryKeyTitle": "没有恢复密钥吗?",
"enterEmailHint": "请输入您的电子邮件地址",
"enterNewEmailHint": "请输入您的新电子邮件地址",
"invalidEmailTitle": "无效的电子邮件地址",
"invalidEmailMessage": "请输入一个有效的电子邮件地址。",
"deleteAccount": "删除账户",
@@ -513,5 +514,10 @@
"free5GB": "<bold-green>ente</bold-green> Photos 上 5GB 可用空间",
"loginWithAuthAccount": "使用您的认证账户登录",
"freeStorageOffer": "购买 <bold-green>ente</bold-green> Photos 可享受 10% 优惠",
"freeStorageOfferDescription": "使用优惠码“AUTH”可享受首年 10% 折扣"
"freeStorageOfferDescription": "使用优惠码“AUTH”可享受首年 10% 折扣",
"advanced": "高级",
"algorithm": "算法",
"type": "类型",
"period": "周期",
"digits": "数字"
}

View File

@@ -513,5 +513,10 @@
"free5GB": "<bold-green>ente</bold-green> Photos 上 5GB 可用空間",
"loginWithAuthAccount": "使用您的認證帳戶登錄",
"freeStorageOffer": "購買 <bold-green>ente</bold-green> Photos 可享受 10% 優惠",
"freeStorageOfferDescription": "使用優惠碼“AUTH”可享受首年 10% 折扣"
"freeStorageOfferDescription": "使用優惠碼“AUTH”可享受首年 10% 折扣",
"advanced": "進階",
"algorithm": "演算法",
"type": "類型",
"period": "期間",
"digits": "數位"
}

View File

@@ -38,28 +38,28 @@ const List<Locale> appSupportedLocales = <Locale>[
];
Locale? autoDetectedLocale;
Locale localResolutionCallBack(locales, supportedLocales) {
Locale? languageCodeMatch;
final Map<String, Locale> languageCodeToLocale = {
for (Locale supportedLocale in appSupportedLocales)
supportedLocale.languageCode: supportedLocale,
};
for (Locale locale in locales) {
// This function takes device locales and supported locales as input
// and returns the best matching locale.
// The device locales are sorted by priority, so the first one is the most preferred.
Locale localResolutionCallBack(onDeviceLocales, supportedLocales) {
final Set<String> languageSupport = {};
for (Locale supportedLocale in appSupportedLocales) {
languageSupport.add(supportedLocale.languageCode);
}
for (Locale locale in onDeviceLocales) {
// check if exact local is supported, if yes, return it
if (appSupportedLocales.contains(locale)) {
autoDetectedLocale = locale;
return locale;
}
if (languageCodeMatch == null &&
languageCodeToLocale.containsKey(locale.languageCode)) {
languageCodeMatch = languageCodeToLocale[locale.languageCode];
autoDetectedLocale = languageCodeMatch;
// check if language code is supported, if yes, return it
if (languageSupport.contains(locale.languageCode)) {
autoDetectedLocale = locale;
return locale;
}
}
// Return the first language code match or default to 'en'
return languageCodeMatch ?? const Locale('en');
return autoDetectedLocale ?? const Locale('en');
}
Future<Locale?> getLocale({

View File

@@ -293,10 +293,6 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
],
),
const SizedBox(height: 12),
widget.code == null
? advanceOptionWidget()
: const SizedBox.shrink(),
const SizedBox(height: 12),
Wrap(
spacing: 12,
alignment: WrapAlignment.start,
@@ -343,6 +339,10 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
),
],
),
const SizedBox(height: 12),
widget.code == null
? advanceOptionWidget()
: const SizedBox.shrink(),
const SizedBox(height: 40),
SizedBox(
width: 400,
@@ -525,6 +525,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
}
Widget advanceOptionWidget() {
final l10n = context.l10n;
return Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Column(
@@ -537,9 +538,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
'Advanced',
),
Text(l10n.advanced),
ValueListenableBuilder<bool>(
valueListenable: showAdvancedOptions,
builder: (context, isExpanded, child) {
@@ -583,7 +582,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const FieldLabel("Algorithm", width: 60),
FieldLabel(l10n.algorithm, width: 60),
AlgorithmSelectorWidget(
currentAlgorithm: _algorithm,
onSelected: (newAlgorithm) async {
@@ -597,7 +596,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const FieldLabel("Type", width: 60),
FieldLabel(l10n.type, width: 60),
ToptSelectorWidget(
currentTopt: _type,
onSelected: (newTopt) async {
@@ -610,7 +609,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
),
Row(
children: [
const FieldLabel("Period", width: 60),
FieldLabel(l10n.period, width: 60),
Expanded(
child: TextFormField(
keyboardType: TextInputType.number,
@@ -639,7 +638,7 @@ class _SetupEnterSecretKeyPageState extends State<SetupEnterSecretKeyPage> {
),
Row(
children: [
const FieldLabel("Digits", width: 60),
FieldLabel(l10n.digits, width: 60),
Expanded(
child: TextFormField(
keyboardType: TextInputType.number,

View File

@@ -13,6 +13,7 @@ import 'package:ente_auth/models/authenticator/auth_entity.dart';
import 'package:ente_auth/models/authenticator/auth_key.dart';
import 'package:ente_auth/models/authenticator/entity_result.dart';
import 'package:ente_auth/models/authenticator/local_auth_entity.dart';
import 'package:ente_auth/services/preference_service.dart';
import 'package:ente_auth/store/authenticator_db.dart';
import 'package:ente_auth/store/offline_authenticator_db.dart';
import 'package:ente_crypto_dart/ente_crypto_dart.dart';
@@ -194,8 +195,13 @@ class AuthenticatorService {
final int lastSyncTime = _prefs.getInt(_lastEntitySyncTime) ?? 0;
_logger.info("Current sync is $lastSyncTime");
const int fetchLimit = 500;
final List<AuthEntity> result =
late final List<AuthEntity> result;
late final int? epochTimeInMicroseconds;
(result, epochTimeInMicroseconds) =
await _gateway.getDiff(lastSyncTime, limit: fetchLimit);
PreferenceService.instance
.computeAndStoreTimeOffset(epochTimeInMicroseconds);
_logger.info("${result.length} entries fetched from remote");
if (result.isEmpty) {
return;

View File

@@ -18,6 +18,7 @@ class PreferenceService {
late final SharedPreferences _prefs;
static const kHasShownCoachMarkKey = "has_shown_coach_mark_v2";
static const kLocalTimeOffsetKey = "local_time_offset";
static const kShouldShowLargeIconsKey = "should_show_large_icons";
static const kShouldHideCodesKey = "should_hide_codes";
static const kShouldAutoFocusOnSearchBar = "should_auto_focus_on_search_bar";
@@ -114,4 +115,24 @@ class PreferenceService {
return installedTimeinMillis;
}
}
// localEpochOffsetInMilliSecond returns the local epoch offset in milliseconds.
// This is used to adjust the time for TOTP calculations when device local time is not in sync with actual time.
int timeOffsetInMilliSeconds() {
return _prefs.getInt(kLocalTimeOffsetKey) ?? 0;
}
void computeAndStoreTimeOffset(
int? epochTimeInMicroseconds,
) {
if (epochTimeInMicroseconds == null) {
_prefs.remove(kLocalTimeOffsetKey);
return;
}
int serverEpochTimeInMilliSecond = epochTimeInMicroseconds ~/ 1000;
int localEpochTimeInMilliSecond = DateTime.now().millisecondsSinceEpoch;
int localEpochOffset =
serverEpochTimeInMilliSecond - localEpochTimeInMilliSecond;
_prefs.setInt(kLocalTimeOffsetKey, localEpochOffset);
}
}

View File

@@ -18,7 +18,7 @@ class _ChangeEmailDialogState extends State<ChangeEmailDialog> {
Widget build(BuildContext context) {
final l10n = context.l10n;
return AlertDialog(
title: Text(l10n.enterEmailHint),
title: Text(l10n.enterNewEmailHint),
content: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,

View File

@@ -7,10 +7,12 @@ import 'package:flutter/material.dart';
class CodeTimerProgress extends StatefulWidget {
final int period;
final bool isCompactMode;
final int timeOffsetInMilliseconds;
const CodeTimerProgress({
super.key,
required this.period,
this.isCompactMode = false,
this.timeOffsetInMilliseconds = 0,
});
@override
@@ -20,7 +22,7 @@ class CodeTimerProgress extends StatefulWidget {
class _CodeTimerProgressState extends State<CodeTimerProgress> {
late final Timer _timer;
late final ValueNotifier<double> _progress;
late final int _periodInMicros;
late final int _periodInMilii;
// Reduce update frequency
final int _updateIntervalMs =
@@ -29,29 +31,30 @@ class _CodeTimerProgressState extends State<CodeTimerProgress> {
@override
void initState() {
super.initState();
_periodInMicros = widget.period * 1000000;
_periodInMilii = widget.period * 1000;
_progress = ValueNotifier<double>(0.0);
_updateTimeRemaining(DateTime.now().microsecondsSinceEpoch);
_updateTimeRemaining(DateTime.now().millisecondsSinceEpoch);
_timer = Timer.periodic(Duration(milliseconds: _updateIntervalMs), (timer) {
final now = DateTime.now().microsecondsSinceEpoch;
final now = DateTime.now().millisecondsSinceEpoch;
_updateTimeRemaining(now);
});
}
void _updateTimeRemaining(int currentMicros) {
void _updateTimeRemaining(int currentMilliSeconds) {
// More efficient time calculation using modulo
final elapsed = (currentMicros) % _periodInMicros;
final timeRemaining = _periodInMicros - elapsed;
_progress.value = timeRemaining / _periodInMicros;
final elapsed = (currentMilliSeconds + widget.timeOffsetInMilliseconds) %
_periodInMilii;
final timeRemaining = _periodInMilii - elapsed;
_progress.value = timeRemaining / _periodInMilii;
}
@override
void didUpdateWidget(covariant CodeTimerProgress oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.period != widget.period) {
_periodInMicros = widget.period * 1000000;
_updateTimeRemaining(DateTime.now().microsecondsSinceEpoch);
_periodInMilii = widget.period * 1000;
_updateTimeRemaining(DateTime.now().millisecondsSinceEpoch);
}
}

View File

@@ -152,6 +152,8 @@ class _CodeWidgetState extends State<CodeWidget> {
key: ValueKey('period_${widget.code.period}'),
period: widget.code.period,
isCompactMode: widget.isCompactMode,
timeOffsetInMilliseconds:
PreferenceService.instance.timeOffsetInMilliSeconds(),
),
widget.isCompactMode
? const SizedBox(height: 4)

View File

@@ -1,8 +1,14 @@
import 'package:ente_auth/models/code.dart';
import 'package:ente_auth/services/preference_service.dart';
import 'package:flutter/foundation.dart';
import 'package:otp/otp.dart' as otp;
import 'package:steam_totp/steam_totp.dart';
int millisecondsSinceEpoch() {
return DateTime.now().millisecondsSinceEpoch +
PreferenceService.instance.timeOffsetInMilliSeconds();
}
String getOTP(Code code) {
if (code.type == Type.steam || code.issuer.toLowerCase() == 'steam') {
return _getSteamCode(code);
@@ -12,7 +18,7 @@ String getOTP(Code code) {
}
return otp.OTP.generateTOTPCodeString(
getSanitizedSecret(code.secret),
DateTime.now().millisecondsSinceEpoch,
millisecondsSinceEpoch(),
length: code.digits,
interval: code.period,
algorithm: _getAlgorithm(code),
@@ -34,7 +40,7 @@ String _getSteamCode(Code code, [bool isNext = false]) {
final SteamTOTP steamtotp = SteamTOTP(secret: code.secret);
return steamtotp.generate(
DateTime.now().millisecondsSinceEpoch ~/ 1000 + (isNext ? code.period : 0),
millisecondsSinceEpoch() ~/ 1000 + (isNext ? code.period : 0),
);
}
@@ -44,7 +50,7 @@ String getNextTotp(Code code) {
}
return otp.OTP.generateTOTPCodeString(
getSanitizedSecret(code.secret),
DateTime.now().millisecondsSinceEpoch + code.period * 1000,
millisecondsSinceEpoch() + code.period * 1000,
length: code.digits,
interval: code.period,
algorithm: _getAlgorithm(code),
@@ -56,9 +62,7 @@ String getNextTotp(Code code) {
// It returns the start time and a list of future codes.
(int, List<String>) generateFutureTotpCodes(Code code, int count) {
final int startTime =
((DateTime.now().millisecondsSinceEpoch ~/ 1000) ~/ code.period) *
code.period *
1000;
((millisecondsSinceEpoch() ~/ 1000) ~/ code.period) * code.period * 1000;
final String secret = getSanitizedSecret(code.secret);
final List<String> codes = [];
if (code.type == Type.steam || code.issuer.toLowerCase() == 'steam') {

View File

@@ -18,6 +18,8 @@
</screenshot>
</screenshots>
<releases>
<release version="4.4.0" date="2025-05-31" />
<release version="4.3.8" date="2025-05-20" />
<release version="4.2.4" date="2025-01-11" />
<release version="4.0.3" date="2024-10-08" />
</releases>
@@ -33,4 +35,4 @@
<color type="primary" scheme_preference="light">#ffffff</color>
<color type="primary" scheme_preference="dark">#000000</color>
</branding>
</component>
</component>

View File

@@ -5,15 +5,15 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
url: "https://pub.dev"
source: hosted
version: "76.0.0"
version: "72.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.3"
version: "0.3.2"
adaptive_theme:
dependency: "direct main"
description:
@@ -26,10 +26,10 @@ packages:
dependency: transitive
description:
name: analyzer
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
url: "https://pub.dev"
source: hosted
version: "6.11.0"
version: "6.7.0"
ansicolor:
dependency: transitive
description:
@@ -90,10 +90,10 @@ packages:
dependency: transitive
description:
name: async
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.12.0"
version: "2.11.0"
auto_size_text:
dependency: "direct main"
description:
@@ -130,10 +130,10 @@ packages:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.1"
build:
dependency: transitive
description:
@@ -202,10 +202,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.4.0"
version: "1.3.0"
checked_yaml:
dependency: transitive
description:
@@ -234,10 +234,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.2"
version: "1.1.1"
code_builder:
dependency: transitive
description:
@@ -250,10 +250,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.19.1"
version: "1.18.0"
confetti:
dependency: "direct main"
description:
@@ -435,10 +435,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
version: "1.3.1"
ffi:
dependency: "direct main"
description:
@@ -944,18 +944,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.8"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.9"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
@@ -1024,18 +1024,18 @@ packages:
dependency: transitive
description:
name: macros
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
url: "https://pub.dev"
source: hosted
version: "0.1.3-main.0"
version: "0.1.2-main.4"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.17"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
@@ -1056,10 +1056,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.16.0"
version: "1.15.0"
mime:
dependency: transitive
description:
@@ -1168,10 +1168,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.9.0"
path_drawing:
dependency: transitive
description:
@@ -1472,7 +1472,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
version: "0.0.99"
sodium:
dependency: transitive
description:
@@ -1509,10 +1509,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
version: "1.10.0"
sprintf:
dependency: transitive
description:
@@ -1566,10 +1566,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
version: "1.11.1"
steam_totp:
dependency: "direct main"
description:
@@ -1590,10 +1590,10 @@ packages:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.2"
stream_transform:
dependency: transitive
description:
@@ -1606,10 +1606,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.2.0"
styled_text:
dependency: "direct main"
description:
@@ -1630,18 +1630,18 @@ packages:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.4"
version: "0.7.2"
timezone:
dependency: transitive
description:
@@ -1806,10 +1806,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.3.1"
version: "14.2.5"
watcher:
dependency: transitive
description:
@@ -1899,5 +1899,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.7.0-0 <4.0.0"
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View File

@@ -1,7 +1,7 @@
name: ente_auth
description: ente two-factor authenticator
version: 4.3.6+437
version: 4.4.0+440
publish_to: none
environment:

70
auth/scripts/release_tag.sh Executable file
View File

@@ -0,0 +1,70 @@
#!/bin/bash
# Function to display usage
usage() {
echo "Usage: $0 tag"
exit 1
}
# Ensure a tag was provided
[[ $# -eq 0 ]] && usage
# Exit immediately if a command exits with a non-zero status
set -e
# Go to the project root directory
cd "$(dirname "$0")/.."
# Get the tag from the command line argument
TAG=$1
# Define the appdata file path - use absolute path to avoid directory navigation issues
PROJECT_ROOT=$(pwd)
APPDATA_FILE="${PROJECT_ROOT}/linux/packaging/enteauth.appdata.xml"
# Get the version from the pubspec.yaml file and cut everything after the +
VERSION=$(grep "^version:" pubspec.yaml | awk '{ print $2 }' | cut -d '+' -f 1)
PREFIX="auth-v"
# Ensure the tag has the correct prefix
if [[ $TAG != $PREFIX* ]]; then
echo "Invalid tag. tags must start with '$PREFIX'."
exit 1
fi
# Ensure the tag version is in the pubspec.yaml file
if [[ $TAG != *$VERSION ]]; then
echo "Invalid tag."
echo "The version $VERSION in pubspec doesn't match the version in tag $TAG"
exit 1
fi
# Extract version number from the tag (remove prefix)
TAG_VERSION=${TAG#$PREFIX}
# Check if this version is already in the releases section of the appdata.xml file
if ! grep -q "<release version=\"$TAG_VERSION\"" "$APPDATA_FILE"; then
echo "Adding release entry for version $TAG_VERSION to appdata.xml"
# Get today's date in YYYY-MM-DD format
TODAY=$(date +%Y-%m-%d)
# Use a more reliable approach with awk instead of sed for cross-platform compatibility
echo "Creating temporary file with updated content..."
awk '/<releases>/{print $0; print " <release version=\"'"$TAG_VERSION"'\" date=\"'"$TODAY"'\" />"; next}1' "$APPDATA_FILE" > "${APPDATA_FILE}.tmp"
mv "${APPDATA_FILE}.tmp" "$APPDATA_FILE"
echo "Added release entry for version $TAG_VERSION with date $TODAY"
# Stage and commit the updated appdata.xml file
git add "$APPDATA_FILE"
git commit -m "Add release $TAG_VERSION to appdata.xml"
echo "Committed appdata.xml changes for version $TAG_VERSION"
fi
# If all checks pass, create the tag
git tag $TAG
echo "Tag $TAG created."
exit 0

View File

@@ -83,13 +83,14 @@ func (c *Client) VerifySRPSession(
return &res, nil
}
func (c *Client) SendEmailOTP(
func (c *Client) SendLoginOTP(
ctx context.Context,
email string,
) error {
var res AuthorizationResponse
payload := map[string]interface{}{
"email": email,
"email": email,
"purpose": "login",
}
r, err := c.restClient.R().
SetContext(ctx).

View File

@@ -167,7 +167,7 @@ func (c *ClICtrl) verifyPassKey(ctx context.Context, authResp *api.Authorization
}
func (c *ClICtrl) validateEmail(ctx context.Context, email string) (*api.AuthorizationResponse, error) {
err := c.Client.SendEmailOTP(ctx, email)
err := c.Client.SendLoginOTP(ctx, email)
if err != nil {
return nil, err
}

View File

@@ -1,9 +1,18 @@
# CHANGELOG
## v1.7.13 (Unreleased)
## v1.7.14 (Unreleased)
- .
## v1.7.13
- Generate streams for videos (beta)
> Streamable videos can be enabled in Preferences. For more details, see the
> [video streaming FAQ](https://help.ente.io/photos/faq/video-streaming).
- Support Turkish translations.
## v1.7.12
- Improved video player with streaming support (for already processed videos).

View File

@@ -1,6 +1,6 @@
{
"name": "ente",
"version": "1.7.13-beta",
"version": "1.7.14-beta",
"private": true,
"description": "Desktop client for Ente Photos",
"repository": "github:ente-io/photos-desktop",
@@ -38,25 +38,26 @@
"lru-cache": "^11.1.0",
"next-electron-server": "^1.0.0",
"node-stream-zip": "^1.15.0",
"onnxruntime-node": "^1.20.1"
"onnxruntime-node": "^1.20.1",
"zod": "^3.25.51"
},
"devDependencies": {
"@eslint/js": "^9.25.1",
"@tsconfig/node22": "^22.0.1",
"@eslint/js": "^9.28.0",
"@tsconfig/node22": "^22.0.2",
"@types/auto-launch": "^5.0.5",
"@types/ffmpeg-static": "^3.0.3",
"ajv": "^8.17.1",
"concurrently": "^9.1.2",
"cross-env": "^7.0.3",
"electron": "^36.1.0",
"electron": "^36.4.0",
"electron-builder": "^26.0.14",
"eslint": "^9",
"prettier": "3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.10",
"shx": "^0.3.4",
"prettier-plugin-packagejson": "^2.5.15",
"shx": "^0.4.0",
"typescript": "^5.8.3",
"typescript-eslint": "^8.31.1"
"typescript-eslint": "^8.33.1"
},
"packageManager": "yarn@1.22.22",
"productName": "ente"

View File

@@ -78,6 +78,14 @@ export const allowWindowClose = (): void => {
* We call this at the end of this file.
*/
const main = () => {
// Workaround for Electron 36 not launching on some Linux distros. Remove
// once fixed or otherwise mitigated upstream.
//
// https://github.com/electron/electron/issues/46538#issuecomment-2808806722
if (process.platform == "linux") {
app.commandLine.appendSwitch("gtk-version", "3");
}
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
app.quit();

View File

@@ -16,6 +16,7 @@ import type {
FFmpegCommand,
FolderWatch,
PendingUploads,
UtilityProcessType,
ZipItem,
} from "../types/ipc";
import { logToDisk } from "./log";
@@ -31,7 +32,7 @@ import {
openLogDirectory,
selectDirectory,
} from "./services/dir";
import { ffmpegExec } from "./services/ffmpeg";
import { ffmpegDetermineVideoDuration, ffmpegExec } from "./services/ffmpeg";
import {
fsExists,
fsFindFiles,
@@ -47,7 +48,6 @@ import {
} from "./services/fs";
import { convertToJPEG, generateImageThumbnail } from "./services/image";
import { logout } from "./services/logout";
import { createMLWorker } from "./services/ml";
import {
lastShownChangelogVersion,
masterKeyB64,
@@ -70,6 +70,7 @@ import {
watchUpdateIgnoredFiles,
watchUpdateSyncedFiles,
} from "./services/watch";
import { triggerCreateUtilityProcess } from "./services/workers";
/**
* Listen for IPC events sent/invoked by the renderer process, and route them to
@@ -181,10 +182,10 @@ export const attachIPCHandlers = () => {
"generateImageThumbnail",
(
_,
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
maxDimension: number,
maxSize: number,
) => generateImageThumbnail(dataOrPathOrZipItem, maxDimension, maxSize),
) => generateImageThumbnail(pathOrZipItem, maxDimension, maxSize),
);
ipcMain.handle(
@@ -192,9 +193,15 @@ export const attachIPCHandlers = () => {
(
_,
command: FFmpegCommand,
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
outputFileExtension: string,
) => ffmpegExec(command, dataOrPathOrZipItem, outputFileExtension),
) => ffmpegExec(command, pathOrZipItem, outputFileExtension),
);
ipcMain.handle(
"ffmpegDetermineVideoDuration",
(_, pathOrZipItem: string | ZipItem) =>
ffmpegDetermineVideoDuration(pathOrZipItem),
);
// - Upload
@@ -233,9 +240,11 @@ export const attachIPCHandlers = () => {
* the main window to do their thing.
*/
export const attachMainWindowIPCHandlers = (mainWindow: BrowserWindow) => {
// - ML
// - Utility processes
ipcMain.on("createMLWorker", () => createMLWorker(mainWindow));
ipcMain.on("triggerCreateUtilityProcess", (_, type: UtilityProcessType) =>
triggerCreateUtilityProcess(type, mainWindow),
);
};
/**

View File

@@ -0,0 +1,59 @@
/**
* A object that behaves similar to the default export of "./log", except this
* can be used from within a utility process.
*
* ---
*
* We cannot directly do
*
* import log from "../log";
*
* because that requires the Electron APIs that are not available to a utility
* process (See: [Note: Using Electron APIs in UtilityProcess]).
*
* But even if that were to work, logging will still be problematic since we'd
* try opening the log file from two different Node.js processes (this one, and
* the main one), and I didn't find any indication in the electron-log
* repository that the log file's integrity would be maintained in such cases.
*
* So instead we provide this proxy log object that uses the
* `process.parentPort` to transport the logs over to the main process, where
* the {@link processUtilityProcessLogMessage} function in the main process is
* expected to handle these (sending them to the actual log).
*/
export default {
error: (s: string, e?: unknown) =>
mainProcess("log.errorString", messageWithError(s, e)),
warn: (s: string, e?: unknown) =>
mainProcess("log.warnString", messageWithError(s, e)),
info: (...ms: unknown[]) => mainProcess("log.info", ms),
/**
* Unlike the real {@link log.debug}, this is (a) eagerly evaluated, and (b)
* accepts only strings.
*/
debugString: (s: string) => mainProcess("log.debugString", s),
};
/**
* Send a message to the main process using a barebones RPC protocol.
*/
const mainProcess = (method: string, param: unknown) =>
process.parentPort.postMessage({ method, p: param });
// Duplicated verbatim from ./log.ts
const messageWithError = (message: string, e?: unknown) => {
if (!e) return message;
let es: string;
if (e instanceof Error) {
// In practice, we expect ourselves to be called with Error objects, so
// this is the happy path so to say.
es = [`${e.name}: ${e.message}`, e.stack].filter((x) => x).join("\n");
} else {
// For the rest rare cases, use the default string serialization of e.
// eslint-disable-next-line @typescript-eslint/no-base-to-string
es = String(e);
}
return `${message}: ${es}`;
};

View File

@@ -83,6 +83,56 @@ const logDebug = (param: () => unknown) => {
}
};
/**
* Handle log messages posted from the utility process in the main process.
*
* See: [Note: Using Electron APIs in UtilityProcess]
*
* @param message The arbitrary message that was received as an argument to the
* "message" event invoked on a {@link UtilityProcess}.
*
* @returns true if the message was recognized and handled, and false otherwise.
*/
export const processUtilityProcessLogMessage = (
logTag: string,
message: unknown,
) => {
const m = message; /* shorter alias */
if (m && typeof m == "object" && "method" in m && "p" in m) {
const p = m.p;
switch (m.method) {
case "log.errorString":
if (typeof p == "string") {
logError(`${logTag} ${p}`);
return true;
}
break;
case "log.warnString":
if (typeof p == "string") {
logWarn(`${logTag} ${p}`);
return true;
}
break;
case "log.info":
if (Array.isArray(p)) {
// Need to cast from any[] to unknown[]
logInfo(logTag, ...(p as unknown[]));
return true;
}
break;
case "log.debugString":
if (typeof p == "string") {
logDebug(() => `${logTag} ${p}`);
return true;
}
break;
default:
break;
}
}
return false;
};
/**
* Ente's logger.
*

File diff suppressed because it is too large Load Diff

View File

@@ -1,678 +1,77 @@
import pathToFfmpeg from "ffmpeg-static";
import { randomBytes } from "node:crypto";
/**
* @file A bridge to the ffmpeg utility process. This code runs in the main
* process.
*/
import { wrap } from "comlink";
import fs from "node:fs/promises";
import path, { basename } from "node:path";
import type { FFmpegCommand, ZipItem } from "../../types/ipc";
import log from "../log";
import { execAsync } from "../utils/electron";
import {
deleteTempFileIgnoringErrors,
makeFileForDataOrStreamOrPathOrZipItem,
makeFileForStreamOrPathOrZipItem,
makeTempFilePath,
} from "../utils/temp";
/* Ditto in the web app's code (used by the Wasm FFmpeg invocation). */
const ffmpegPathPlaceholder = "FFMPEG";
const inputPathPlaceholder = "INPUT";
const outputPathPlaceholder = "OUTPUT";
import type { FFmpegUtilityProcess } from "./ffmpeg-worker";
import { ffmpegUtilityProcessEndpoint } from "./workers";
/**
* Run a FFmpeg command
*
* [Note: FFmpeg in Electron]
*
* There is a Wasm build of FFmpeg, but that is currently 10-20 times slower
* that the native build. That is slow enough to be unusable for our purposes.
* https://ffmpegwasm.netlify.app/docs/performance
*
* So the alternative is to bundle a FFmpeg executable binary with our app. e.g.
*
* yarn add fluent-ffmpeg ffmpeg-static ffprobe-static
*
* (we only use ffmpeg-static, the rest are mentioned for completeness' sake).
*
* Interestingly, Electron already bundles an binary FFmpeg library (it comes
* from the ffmpeg fork maintained by Chromium).
* https://chromium.googlesource.com/chromium/third_party/ffmpeg
* https://stackoverflow.com/questions/53963672/what-version-of-ffmpeg-is-bundled-inside-electron
*
* This can be found in (e.g. on macOS) at
*
* $ file ente.app/Contents/Frameworks/Electron\ Framework.framework/Versions/Current/Libraries/libffmpeg.dylib
* .../libffmpeg.dylib: Mach-O 64-bit dynamically linked shared library arm64
*
* But I'm not sure if our code is supposed to be able to use it, and how.
* Return a handle to the ffmpeg utility process, starting it if needed.
*/
export const ffmpegUtilityProcess = () =>
ffmpegUtilityProcessEndpoint().then((port) =>
wrap<FFmpegUtilityProcess>(port),
);
/**
* Implement the IPC "ffmpegExec" contract, writing the input and output to
* temporary files as needed, and then forward to the {@link ffmpegExec} running
* in the utility process.
*/
export const ffmpegExec = async (
command: FFmpegCommand,
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
outputFileExtension: string,
): Promise<Uint8Array> => {
): Promise<Uint8Array> =>
withInputFile(pathOrZipItem, async (worker, inputFilePath) => {
const outputFilePath = await makeTempFilePath(outputFileExtension);
try {
await worker.ffmpegExec(command, inputFilePath, outputFilePath);
return await fs.readFile(outputFilePath);
} finally {
await deleteTempFileIgnoringErrors(outputFilePath);
}
});
export const withInputFile = async <T>(
pathOrZipItem: string | ZipItem,
f: (worker: FFmpegUtilityProcess, inputFilePath: string) => Promise<T>,
): Promise<T> => {
const worker = await ffmpegUtilityProcess();
const {
path: inputFilePath,
isFileTemporary: isInputFileTemporary,
writeToTemporaryFile: writeToTemporaryInputFile,
} = await makeFileForDataOrStreamOrPathOrZipItem(dataOrPathOrZipItem);
} = await makeFileForStreamOrPathOrZipItem(pathOrZipItem);
const outputFilePath = await makeTempFilePath(outputFileExtension);
try {
await writeToTemporaryInputFile();
let resolvedCommand: string[];
if (Array.isArray(command)) {
resolvedCommand = command;
} else {
const isHDR = await isHDRVideo(inputFilePath);
log.debug(() => [basename(inputFilePath), { isHDR }]);
resolvedCommand = isHDR ? command.hdr : command.default;
}
const cmd = substitutePlaceholders(
resolvedCommand,
inputFilePath,
outputFilePath,
);
await execAsync(cmd);
return await fs.readFile(outputFilePath);
return await f(worker, inputFilePath);
} finally {
if (isInputFileTemporary)
await deleteTempFileIgnoringErrors(inputFilePath);
await deleteTempFileIgnoringErrors(outputFilePath);
}
};
const substitutePlaceholders = (
command: string[],
inputFilePath: string,
outputFilePath: string,
) =>
command.map((segment) => {
if (segment == ffmpegPathPlaceholder) {
return ffmpegBinaryPath();
} else if (segment == inputPathPlaceholder) {
return inputFilePath;
} else if (segment == outputPathPlaceholder) {
return outputFilePath;
} else {
return segment;
}
});
/**
* Return the path to the `ffmpeg` binary.
*
* At runtime, the FFmpeg binary is present in a path like (macOS example):
* `ente.app/Contents/Resources/app.asar.unpacked/node_modules/ffmpeg-static/ffmpeg`
* Implement the IPC "ffmpegDetermineVideoDuration" contract, writing the input
* to temporary files as needed, and then forward to the
* {@link ffmpegDetermineVideoDuration} running in the utility process.
*/
const ffmpegBinaryPath = () => {
// This substitution of app.asar by app.asar.unpacked is suggested by the
// ffmpeg-static library author themselves:
// https://github.com/eugeneware/ffmpeg-static/issues/16
return pathToFfmpeg!.replace("app.asar", "app.asar.unpacked");
};
/**
* A variant of {@link ffmpegExec} adapted to work with streams so that it can
* handle the MP4 conversion of large video files.
*
* @param inputFilePath The path to a file on the user's local file system. This
* is the video we want to convert.
*
* @param outputFilePath The path to a file on the user's local file system where
* we should write the converted MP4 video.
*/
export const ffmpegConvertToMP4 = async (
inputFilePath: string,
outputFilePath: string,
): Promise<void> => {
const command = [
ffmpegPathPlaceholder,
"-i",
inputPathPlaceholder,
"-preset",
"ultrafast",
outputPathPlaceholder,
];
const cmd = substitutePlaceholders(command, inputFilePath, outputFilePath);
await execAsync(cmd);
};
export interface FFmpegGenerateHLSPlaylistAndSegmentsResult {
playlistPath: string;
videoPath: string;
dimensions: { width: number; height: number };
videoSize: number;
}
/**
* A bespoke variant of {@link ffmpegExec} for generation of HLS playlists for
* videos.
*
* Overview of the cases:
*
* H.264, <= 10 MB - Skip
* H.264, <= 4000 kb/s bitrate - Don't re-encode video stream
* BT.709, <= 2000 kb/s bitrate - Don't apply the scale+fps filter
* !BT.709 - Apply tonemap (zscale+tonemap+zscale)
*
* Example invocation:
*
* ffmpeg -i in.mov -vf 'scale=-2:720,fps=30,zscale=transfer=linear,tonemap=tonemap=hable:desat=0,zscale=primaries=709:transfer=709:matrix=709,format=yuv420p' -c:v libx264 -c:a aac -f hls -hls_key_info_file out.m3u8.info -hls_list_size 0 -hls_flags single_file out.m3u8
*
* See: [Note: Preview variant of videos]
*
* @param inputFilePath The path to a file on the user's local file system. This
* is the video we want to generate an streamable HLS playlist for.
*
* @param outputPathPrefix The path to unique, unused and temporary prefix on
* the user's local file system. This function will write the generated HLS
* playlist and video segments under this prefix.
*
* @returns The paths to two files on the user's local file system - one
* containing the generated HLS playlist, and the other containing the
* transcoded and encrypted video segments that the HLS playlist refers to.
*
* If the video is such that it doesn't require stream generation, then this
* function returns `undefined`.
*/
export const ffmpegGenerateHLSPlaylistAndSegments = async (
inputFilePath: string,
outputPathPrefix: string,
): Promise<FFmpegGenerateHLSPlaylistAndSegmentsResult | undefined> => {
const { isH264, isBT709, bitrate } =
await detectVideoCharacteristics(inputFilePath);
log.debug(() => [basename(inputFilePath), { isH264, isBT709, bitrate }]);
// If the video is smaller than 10 MB, and already H.264 (the codec we are
// going to use for the conversion), then a streaming variant is not much
// use. Skip such cases.
//
// ---
//
// [Note: HEVC/H.265 issues]
//
// We've observed two issues out in the wild with HEVC videos:
//
// 1. On Linux, HEVC video streams don't play. However, since the audio
// stream plays, the browser tells us that the "video" itself is
// playable, but the user sees a blank screen with only audio.
//
// 2. HEVC + HDR videos taken on an iPhone have a rotation (`Side data:
// displaymatrix` in the ffmpeg output) that Chrome (and thus Electron)
// doesn't take into account, so these play upside down.
//
// Not fully related to this case, but mentioning here as to why both the
// size and codec need to be checked before skipping stream generation.
if (isH264) {
const inputVideoSize = await fs
.stat(inputFilePath)
.then((st) => st.size);
if (inputVideoSize <= 10 * 1024 * 1024 /* 10 MB */) {
return undefined;
}
}
// If the video is already H.264 with a bitrate less than 4000 kbps, then we
// do not need to reencode the video stream (by _far_ the costliest part of
// the HLS stream generation).
const reencodeVideo = !(isH264 && bitrate && bitrate <= 4000 * 1000);
// If the bitrate is not too high, then we don't need to rescale the video
// when generating the video stream. This is not a performance optimization,
// but more for avoiding making the video size smaller unnecessarily.
const rescaleVideo = !(bitrate && bitrate <= 2000 * 1000);
// [Note: Tonemapping HDR to HD]
//
// BT.709 ("HD") is a standard that describes things like how color is
// encoded, the range of values, and their "meaning" - i.e. how to map the
// values in the video to the pixels on the screen.
//
// It is not the only such standard, there are three common examples:
//
// - BT.601 ("Standard-Definition" or SD)
// - BT.709 ("High-Definition" or HD)
// - BT.2020 ("Ultra-High-Definition" or UHD, aka HDR^).
//
// ^ HDR ("High-Dynamic-Range") is an addendum to BT.2020, but for our
// purpose here we can treat it as as alias.
//
// BT.709 is the most common amongst these for older files out stored on
// computers, and they conform mostly to the standard (one notable exception
// is that the BT.709 standard also recommends using the yuv422p pixel
// format, but de facto yuv420p is used because many video players only
// support yuv420p).
//
// Since BT.709 is the most widely supported standard, we use it when
// generating the HLS playlist so to allow playback across the widest
// possible hardware/OS/browser combinations.
//
// If we convert HDR to HD without naively, then the colors look washed out
// compared to the original. To resolve this, we use a ffmpeg filterchain
// that uses the tonemap filter.
//
// However applying this tonemap to videos that are already HD leads to a
// brightness drop. So we conditionally apply this filter chain only if the
// colorspace is not already BT.709.
//
// See also: [Note: Alternative FFmpeg command for HDR videos], although
// that uses a allow-list based check (while here we use deny-list).
//
// Reference:
// - https://trac.ffmpeg.org/wiki/colorspace
const tonemap = !isBT709;
// We want the generated playlist to refer to the chunks as "output.ts".
//
// So we arrange things accordingly: We use the `outputPathPrefix` as our
// working directory, and then ask ffmpeg to generate a playlist with the
// name "output.m3u8".
//
// ffmpeg will automatically place the segments in a file with the same base
// name as the playlist, but with a ".ts" extension. And since we use the
// "single_file" option, all the segments will be placed in a file named
// "output.ts".
await fs.mkdir(outputPathPrefix);
const playlistPath = path.join(outputPathPrefix, "output.m3u8");
const videoPath = path.join(outputPathPrefix, "output.ts");
// Generate a cryptographically secure random key (16 bytes).
const keyBytes = randomBytes(16);
const keyB64 = keyBytes.toString("base64");
// Convert it to a data: URI that will be added to the playlist.
const keyURI = `data:text/plain;base64,${keyB64}`;
// Determine two paths - one where we will write the key itself, and where
// we will write the "key info" that provides ffmpeg the `keyURI` and the
// `keyPath;.
const keyPath = playlistPath + ".key";
const keyInfoPath = playlistPath + ".key-info";
// Generate a "key info":
//
// - the first line specifies the key URI that is written into the playlist.
// - the second line specifies the path to the local file system file from
// where ffmpeg should read the key.
const keyInfo = [keyURI, keyPath].join("\n");
// Overview:
//
// - Video H.264 HD 720p 30fps.
// - Audio AAC 128kbps.
// - Encrypted HLS playlist with a single file containing all the chunks.
//
// Reference:
// - `man ffmpeg-all`
// - https://trac.ffmpeg.org/wiki/Encode/H.264
//
const command = [
ffmpegBinaryPath(),
// Reduce the amount of output lines we have to parse.
["-hide_banner"],
// Input file. We don't need any extra options that apply to the input file.
"-i",
inputFilePath,
// The remaining options apply to the next output file (`playlistPath`).
reencodeVideo
? [
// `-vf` creates a filter graph for the video stream. It is a
// comma separated list of filters chained together, e.g.
// `filter1=key=value:key=value.filter2=key=value`.
"-vf",
[
// Do the rescaling to even number of pixels always if the
// tonemapping is going to be applied subsequently,
// otherwise the tonemapping will fail with "image
// dimensions must be divisible by subsampling factor".
//
// While we add the extra condition here for completeness,
// it won't usually matter since a non-BT.709 video is
// likely using a new codec, and as such would've a high
// enough bitrate to require rescaling anyways.
rescaleVideo || tonemap
? [
// Scales the video to maximum 720p height,
// keeping aspect ratio and the calculated
// dimension divisible by 2 (some of the other
// operations require an even pixel count).
"scale=-2:720",
// Convert the video to a constant 30 fps,
// duplicating or dropping frames as necessary.
"fps=30",
]
: [],
// Convert the colorspace if the video is not in the HD
// color space (bt709). Before conversion, tone map colors
// so that they work the same across the change in the
// dyamic range.
//
// 1. The tonemap filter only works linear light, so we
// first use zscale with transfer=linear to linearize
// the input.
//
// 2. Then we use the tonemap, with the hable option that
// is best for preserving details. desat=0 turns off
// the default desaturation.
//
// 3. Use zscale again to "convert to BT.709" by asking it
// to set the all three of color primaries, transfer
// characteristics and colorspace matrix to 709 (Note:
// the constants specified in the tonemap filter help
// do not include the "bt" prefix)
//
// See: https://ffmpeg.org/ffmpeg-filters.html#tonemap-1
//
// See: [Note: Tonemapping HDR to HD]
tonemap
? [
"zscale=transfer=linear",
"tonemap=tonemap=hable:desat=0",
"zscale=primaries=709:transfer=709:matrix=709",
]
: [],
// Output using the well supported pixel format: 8-bit YUV
// planar color space with 4:2:0 chroma subsampling.
"format=yuv420p",
]
.flat()
.join(","),
]
: [],
reencodeVideo
? // Video codec H.264
//
// - `-c:v libx264` converts the video stream to the H.264 codec.
//
// - We don't supply a bitrate, instead it uses the default CRF
// ("23") as recommended in the ffmpeg trac.
//
// - We don't supply a preset, it'll use the default ("medium").
["-c:v", "libx264"]
: // Keep the video stream unchanged
["-c:v", "copy"],
// Audio codec AAC
//
// - `-c:a aac` converts the audio stream to use the AAC codec
//
// - We don't supply a bitrate, it'll use the AAC default 128k bps.
["-c:a", "aac"],
// Generate a HLS playlist.
["-f", "hls"],
// Tell ffmpeg where to find the key, and the URI for the key to write
// into the generated playlist. Implies "-hls_enc 1".
["-hls_key_info_file", keyInfoPath],
// Generate as many playlist entries as needed (default limit is 5).
["-hls_list_size", "0"],
// Place all the video segments within the same .ts file (with the same
// path as the playlist file but with a ".ts" extension).
["-hls_flags", "single_file"],
// Output path where the playlist should be generated.
playlistPath,
].flat();
let dimensions: ReturnType<typeof detectVideoDimensions>;
let videoSize: number;
try {
// Write the key and the keyInfo to their desired paths.
await Promise.all([
fs.writeFile(keyPath, keyBytes),
fs.writeFile(keyInfoPath, keyInfo, { encoding: "utf8" }),
]);
// Run the ffmpeg command to generate the HLS playlist and segments.
//
// Note: Depending on the size of the input file, this may take long!
const { stderr: conversionStderr } = await execAsync(command);
// Determine the dimensions of the generated video from the stderr
// output produced by ffmpeg during the conversion.
dimensions = detectVideoDimensions(conversionStderr);
// Find the size of the generated video segments by reading the size of
// the generated .ts file.
videoSize = await fs.stat(videoPath).then((st) => st.size);
} catch (e) {
log.error("HLS generation failed", e);
await Promise.all([
deleteTempFileIgnoringErrors(playlistPath),
deleteTempFileIgnoringErrors(videoPath),
]);
throw e;
} finally {
await Promise.all([
deleteTempFileIgnoringErrors(keyInfoPath),
deleteTempFileIgnoringErrors(keyPath),
// ffmpeg writes a /path/output.ts.tmp, clear it out too.
deleteTempFileIgnoringErrors(videoPath + ".tmp"),
]);
}
return { playlistPath, videoPath, dimensions, videoSize };
};
/**
* A regex that matches the first line of the form
*
* Stream #0:0: Video: h264 (High 10) ([27][0][0][0] / 0x001B), yuv420p10le(tv, bt2020nc/bt2020/arib-std-b67), 1920x1080, 30 fps, 30 tbr, 90k tbn
*
* The part after Video: is the first capture group.
*
* Another example:
*
* Stream #0:1[0x2](und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(progressive), 480x270 [SAR 1:1 DAR 16:9], 539 kb/s, 29.97 fps, 29.97 tbr, 30k tbn (default)
*/
const videoStreamLineRegex = /Stream #.+: Video:(.+)\n/;
/** {@link videoStreamLineRegex}, but global. */
const videoStreamLinesRegex = /Stream #.+: Video:(.+)\n/g;
/**
* A regex that matches "<digits> kb/s" preceded by a space. See
* {@link videoStreamLineRegex} for the context in which it is used.
*/
const videoBitrateRegex = / ([1-9]\d*) kb\/s/;
/**
* A regex that matches <digits>x<digits> pair preceded by a space. See
* {@link videoStreamLineRegex} for the context in which it is used.
*
* We constrain the digit sequence not to begin with 0 to exclude hexadecimal
* representations of various constants that ffmpeg prints on this line (e.g.
* "avc1 / 0x31637661").
*/
const videoDimensionsRegex = / ([1-9]\d*)x([1-9]\d*)/;
interface VideoCharacteristics {
isH264: boolean;
isBT709: boolean;
bitrate: number | undefined;
}
/**
* Heuristically determine information about the video at the given
* {@link inputFilePath}:
*
* - If is encoded using H.264 codec.
* - If it uses the BT.709 colorspace.
* - Its bitrate.
*
* The defaults are tailored for the cases in which these conditions are used,
* so that even if we get the detection wrong we'll only end up encoding videos
* that could've possibly been skipped as an optimization.
*
* [Note: Parsing CLI output might break on ffmpeg updates]
*
* This function tries to determine the these bits of information about the
* given video by scanning the ffmpeg info output for the video stream line, and
* doing various string matches and regex extractions.
*
* Needless to say, while this works currently, this is liable to break in the
* future. So if something stops working after updating ffmpeg, look here!
*
* Ideally, we'd have done this using `ffprobe`, but we don't have the ffprobe
* binary at hand, so we make do by grepping the log output of ffmpeg.
*
* For reference,
*
* - codec and colorspace are printed by the `avcodec_string` function in the
* ffmpeg source:
* https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/avcodec.c
*
* - bitrate is printed by the `dump_stream_format` function in `dump.c`.
*/
const detectVideoCharacteristics = async (inputFilePath: string) => {
const videoInfo = await pseudoFFProbeVideo(inputFilePath);
const videoStreamLine = videoStreamLineRegex.exec(videoInfo)?.at(1)?.trim();
// Since the checks are heuristic, start with defaults that would cause the
// codec conversion to happen, even if it is unnecessary.
const res: VideoCharacteristics = {
isH264: false,
isBT709: false,
bitrate: undefined,
};
if (!videoStreamLine) return res;
res.isH264 = videoStreamLine.startsWith("h264 ");
res.isBT709 = videoStreamLine.includes("bt709");
// The regex matches "\d kb/s", but there can be other units for the
// bitrate. However, (a) "kb/s" is the most common for videos out in the
// wild, and (b) even if we guess wrong it we'll just do "-v:c x264" instead
// of "-v:c copy", so only unnecessary processing but no change in output.
const brs = videoBitrateRegex.exec(videoStreamLine)?.at(0);
if (brs) {
const br = parseInt(brs, 10);
if (br) res.bitrate = br;
}
return res;
};
/**
* Heuristically detect the dimensions of the given video from the log output of
* the ffmpeg invocation during the HLS playlist generation.
*
* This function tries to determine the width and height of the generated video
* from the output log written by ffmpeg on its stderr during the generation
* process, scanning it for the last video stream line, and trying to match a
* "<digits>x<digits>" regex.
*
* See: [Note: Parsing CLI output might break on ffmpeg updates].
*/
const detectVideoDimensions = (conversionStderr: string) => {
// There is a nicer way to do it - by running `pseudoFFProbeVideo` on the
// generated playlist. However, that playlist includes a data URL that
// specifies the encryption info, and ffmpeg refuses to read that unless we
// specify the "-allowed_extensions ALL" or something to that effect.
//
// Unfortunately, our current ffmpeg binary (5.x) does not support that
// option. So we instead parse the conversion output itself.
//
// This is also nice, since it saves on an extra ffmpeg invocation. But we
// now need to be careful to find the right video stream line, since the
// conversion output includes both the input and output video stream lines.
//
// To match the right (output) video stream line, we use a global regex, and
// use the last match since that'd correspond to the single video stream
// written in the output.
const videoStreamLine = Array.from(
conversionStderr.matchAll(videoStreamLinesRegex),
)
.at(-1) /* Last Stream...: Video: line in the output */
?.at(1); /* First capture group */
if (videoStreamLine) {
const [, ws, hs] = videoDimensionsRegex.exec(videoStreamLine) ?? [];
if (ws && hs) {
const w = parseInt(ws, 10);
const h = parseInt(hs, 10);
if (w && h) {
return { width: w, height: h };
}
}
}
throw new Error(
`Unable to detect video dimensions from stream line [${videoStreamLine ?? ""}]`,
export const ffmpegDetermineVideoDuration = async (
pathOrZipItem: string | ZipItem,
): Promise<number> =>
withInputFile(pathOrZipItem, async (worker, inputFilePath) =>
worker.ffmpegDetermineVideoDuration(inputFilePath),
);
};
/**
* Heuristically detect if the file at given path is a HDR video.
*
* This is similar to {@link detectVideoCharacteristics}, and see that
* function's documentation for all the caveats. However, this function uses an
* allow-list instead, and considers any file with color transfer "smpte2084" or
* "arib-std-b67" to be HDR. While this is in some sense a more exact check, it
* comes with different caveats:
*
* - These particular constants are not guaranteed to be correct; these are just
* what I saw on the internet as being used / recommended for detecting HDR.
*
* - Since we don't have ffprobe, we're not checking the color space value
* itself but a substring of the stream line in the ffmpeg stderr output.
*
* In particular, we use this more exact check for places where we have less
* leeway. e.g. when generating thumbnails, if we apply the tonemapping to any
* non-BT.709 file (as the HLS stream generation does), we start getting the
* "code 3074: no path between colorspaces" error during the JPEG conversion
* (this is not a problem in the H.264 conversion).
*
* - See: [Note: Alternative FFmpeg command for HDR videos]
* - See: [Note: Tonemapping HDR to HD]
*
* @param inputFilePath The path to a video file on the user's machine.
*
* @returns `true` if this file is likely a HDR video. Exceptions are treated as
* `false` to make this function safe to invoke without breaking the happy path.
*/
const isHDRVideo = async (inputFilePath: string) => {
try {
const videoInfo = await pseudoFFProbeVideo(inputFilePath);
const vs = videoStreamLineRegex.exec(videoInfo)?.at(1);
if (!vs) return false;
return vs.includes("smpte2084") || vs.includes("arib-std-b67");
} catch (e) {
log.warn(`Could not detect HDR status of ${inputFilePath}`, e);
return false;
}
};
/**
* Return the stderr of ffmpeg in an attempt to gain information about the video
* at the given {@link inputFilePath}.
*
* We don't have the ffprobe binary at hand, which is why we need to use this
* alternative. See: [Note: Parsing CLI output might break on ffmpeg updates]
*
* @returns the stderr of ffmpeg after running it on the input file. The exact
* command we run is:
*
* ffmpeg -i in.mov -an -frames:v 0 -f null - 2>info.txt
*
* And the returned string is the contents of the `info.txt` thus produced.
*/
const pseudoFFProbeVideo = async (inputFilePath: string) => {
const command = [
ffmpegPathPlaceholder,
// Reduce the amount of output lines we have to parse.
["-hide_banner"],
["-i", inputPathPlaceholder],
"-an",
["-frames:v", "0"],
["-f", "null"],
"-",
].flat();
const cmd = substitutePlaceholders(command, inputFilePath, /* NA */ "");
const { stderr } = await execAsync(cmd);
return stderr;
};

View File

@@ -6,7 +6,7 @@ import { type ZipItem } from "../../types/ipc";
import { execAsync, isDev } from "../utils/electron";
import {
deleteTempFileIgnoringErrors,
makeFileForDataOrStreamOrPathOrZipItem,
makeFileForStreamOrPathOrZipItem,
makeTempFilePath,
} from "../utils/temp";
@@ -61,7 +61,7 @@ const vipsPath = () =>
);
export const generateImageThumbnail = async (
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
maxDimension: number,
maxSize: number,
): Promise<Uint8Array> => {
@@ -69,7 +69,7 @@ export const generateImageThumbnail = async (
path: inputFilePath,
isFileTemporary: isInputFileTemporary,
writeToTemporaryFile: writeToTemporaryInputFile,
} = await makeFileForDataOrStreamOrPathOrZipItem(dataOrPathOrZipItem);
} = await makeFileForStreamOrPathOrZipItem(pathOrZipItem);
const outputFilePath = await makeTempFilePath("jpeg");

View File

@@ -3,6 +3,7 @@ import log from "../log";
import { clearPendingVideoResults } from "../stream";
import { clearStores } from "./store";
import { watchReset } from "./watch";
import { terminateUtilityProcesses } from "./workers";
import { clearOpenZipCache } from "./zip";
/**
@@ -36,4 +37,9 @@ export const logout = (watcher: FSWatcher) => {
} catch (e) {
ignoreError("zip cache", e);
}
try {
terminateUtilityProcesses();
} catch (e) {
ignoreError("utility processes", e);
}
};

View File

@@ -15,47 +15,16 @@ import { existsSync } from "fs";
import fs from "node:fs/promises";
import path from "node:path";
import * as ort from "onnxruntime-node";
import { z } from "zod/v4";
import log from "../log-worker";
import { messagePortMainEndpoint } from "../utils/comlink";
import { wait } from "../utils/common";
import { writeStream } from "../utils/stream";
import { fsStatMtime } from "./fs";
/**
* We cannot do
*
* import log from "../log";
*
* because that requires the Electron APIs that are not available to a utility
* process (See: [Note: Using Electron APIs in UtilityProcess]). But even if
* that were to work, logging will still be problematic since we'd try opening
* the log file from two different Node.js processes (this one, and the main
* one), and I didn't find any indication in the electron-log repository that
* the log file's integrity would be maintained in such cases.
*
* So instead we create this proxy log object that uses `process.parentPort` to
* transport the logs over to the main process.
*/
const log = {
/**
* Unlike the real {@link log.error}, this accepts only the first string
* argument, not the second optional error one.
*/
errorString: (s: string) => mainProcess("log.errorString", s),
info: (...ms: unknown[]) => mainProcess("log.info", ms),
/**
* Unlike the real {@link log.debug}, this is (a) eagerly evaluated, and (b)
* accepts only strings.
*/
debugString: (s: string) => mainProcess("log.debugString", s),
};
log.debugString("Started ML utility process");
/**
* Send a message to the main process using a barebones RPC protocol.
*/
const mainProcess = (method: string, param: unknown) =>
process.parentPort.postMessage({ method, p: param });
log.debugString(`Started ML worker process`);
process.on("uncaughtException", (e, origin) => log.error(origin, e));
process.parentPort.once("message", (e) => {
// Initialize ourselves with the data we got from our parent.
@@ -84,17 +53,10 @@ let _userDataPath: string | undefined;
/** Equivalent to app.getPath("userData") */
const userDataPath = () => _userDataPath!;
const MLWorkerInitData = z.object({ userDataPath: z.string() });
const parseInitData = (data: unknown) => {
if (
data &&
typeof data == "object" &&
"userDataPath" in data &&
typeof data.userDataPath == "string"
) {
_userDataPath = data.userDataPath;
} else {
log.errorString("Unparseable initialization data");
}
_userDataPath = MLWorkerInitData.parse(data).userDataPath;
};
/**
@@ -161,7 +123,7 @@ const modelPathDownloadingIfNeeded = async (
} else {
const size = (await fs.stat(modelPath)).size;
if (size !== expectedByteSize) {
log.errorString(
log.error(
`The size ${size} of model ${modelName} does not match the expected size, downloading again`,
);
await downloadModel(modelPath, modelName);

View File

@@ -1,147 +0,0 @@
/**
* @file ML related functionality. This code runs in the main process.
*/
import {
MessageChannelMain,
type BrowserWindow,
type UtilityProcess,
} from "electron";
import { app, utilityProcess } from "electron/main";
import path from "node:path";
import log from "../log";
/** The active ML worker (utility) process, if any. */
let _child: UtilityProcess | undefined;
/**
* Create a new ML worker process, terminating the older ones (if any).
*
* [Note: ML IPC]
*
* The primary reason for doing ML tasks in the Node.js layer is so that we can
* use the binary ONNX runtime, which is 10-20x faster than the Wasm one that
* can be used directly on the web layer.
*
* For this to work, the main and renderer process need to communicate with each
* other. Further, in the web layer the ML indexing runs in a web worker (so as
* to not get in the way of the main thread). So the communication has 2 hops:
*
* Node.js main <-> Renderer main <-> Renderer web worker
*
* This naive way works, but has a problem. The Node.js main process is in the
* code path for delivering user events to the renderer process. The ML tasks we
* do take in the order of 100-300 ms (possibly more) for each individual
* inference. Thus, the Node.js main process is busy for those 100-300 ms, and
* does not forward events to the renderer, causing the UI to jitter.
*
* The solution for this is to spawn an Electron UtilityProcess, which we can
* think of a regular Node.js child process. This frees up the Node.js main
* process, and would remove the jitter.
* https://www.electronjs.org/docs/latest/tutorial/process-model
*
* It would seem that this introduces another hop in our IPC
*
* Node.js utility process <-> Node.js main <-> ...
*
* but here we can use the special bit about Electron utility processes that
* separates them from regular Node.js child processes: their support for
* message ports. https://www.electronjs.org/docs/latest/tutorial/message-ports
*
* As a brief summary, a MessagePort is a web feature that allows two contexts
* to communicate. A pair of message ports is called a message channel. The cool
* thing about these is that we can pass these ports themselves over IPC.
*
* > One caveat here is that the message ports can only be passed using the
* > `postMessage` APIs, not the usual send/invoke APIs.
*
* So we
*
* 1. In the utility process create a message channel.
* 2. Spawn a utility process, and send one port of the pair to it.
* 3. Send the other port of the pair to the renderer.
*
* The renderer will forward that port to the web worker that is coordinating
* the ML indexing on the web layer. Thereafter, the utility process and web
* worker can directly talk to each other!
*
* Node.js utility process <-> Renderer web worker
*
* The RPC protocol is handled using comlink on both ends. The port itself needs
* to be relayed using `postMessage`.
*/
export const createMLWorker = (window: BrowserWindow) => {
if (_child) {
log.debug(() => "Terminating previous ML worker process");
_child.kill();
_child = undefined;
}
const { port1, port2 } = new MessageChannelMain();
const child = utilityProcess.fork(path.join(__dirname, "ml-worker.js"));
const userDataPath = app.getPath("userData");
child.postMessage({ userDataPath }, [port1]);
window.webContents.postMessage("createMLWorker/port", undefined, [port2]);
handleMessagesFromUtilityProcess(child);
_child = child;
};
/**
* Handle messages posted from the utility process.
*
* [Note: Using Electron APIs in UtilityProcess]
*
* Only a small subset of the Electron APIs are available to a UtilityProcess.
* As of writing (Jul 2024, Electron 30), only the following are available:
*
* - net
* - systemPreferences
*
* In particular, `app` is not available.
*
* We structure our code so that it doesn't need anything apart from `net`.
*
* For the other cases,
*
* - Additional parameters to the utility process are passed alongwith the
* initial message where we provide it the message port.
*
* - When we need to communicate from the utility process to the main process,
* we use the `parentPort` in the utility process.
*/
const handleMessagesFromUtilityProcess = (child: UtilityProcess) => {
const logTag = "[ml-worker]";
child.on("message", (m: unknown) => {
if (m && typeof m == "object" && "method" in m && "p" in m) {
const p = m.p;
switch (m.method) {
case "log.errorString":
if (typeof p == "string") {
log.error(`${logTag} ${p}`);
return;
}
break;
case "log.info":
if (Array.isArray(p)) {
// Need to cast from any[] to unknown[]
log.info(logTag, ...(p as unknown[]));
return;
}
break;
case "log.debugString":
if (typeof p == "string") {
log.debug(() => `${logTag} ${p}`);
return;
}
break;
default:
break;
}
}
log.info("Ignoring unknown message from ML worker", m);
});
};

View File

@@ -28,6 +28,13 @@ export const createWatcher = (mainWindow: BrowserWindow) => {
// Ask the watcher to wait for a the file size to stabilize before
// telling us about a new file. By default, it waits for 2 seconds.
awaitWriteFinish: true,
// On macOS we start getting "EMFILE: too many open files" when watching
// large folders. This is a known regression in Chokidar v4:
// https://github.com/paulmillr/chokidar/issues/1385
//
// The recommended workaround for now is to enable usePolling. Since it
// comes at a performance cost, we only do it where needed (macOS).
...(process.platform == "darwin" ? { usePolling: true } : {}),
});
watcher

View File

@@ -0,0 +1,241 @@
/**
* @file This main process code and interface for dealing with the various
* utility processes that we create.
*/
import type { Endpoint } from "comlink";
import {
MessageChannelMain,
type BrowserWindow,
type UtilityProcess,
} from "electron";
import { app, utilityProcess } from "electron/main";
import path from "node:path";
import type { UtilityProcessType } from "../../types/ipc";
import log, { processUtilityProcessLogMessage } from "../log";
import { messagePortMainEndpoint } from "../utils/comlink";
/**
* Terminate any existing utility processes if they're running.
*
* This function is called during the logout sequence.
*/
export const terminateUtilityProcesses = () => {
terminateMLProcessIfRunning();
terminateFFmpegProcessIfRunning();
};
/** The active ML utility process, if any. */
let _utilityProcessML: UtilityProcess | undefined;
/** The active FFmpeg utility process, if any. */
let _utilityProcessFFmpeg: UtilityProcess | undefined;
/**
* A promise to a comlink {@link Endpoint} that can be used to communicate with
* the active ffmpeg utility process (if any).
*/
let _utilityProcessFFmpegEndpoint: Promise<Endpoint> | undefined;
/**
* Create a new utility process of the given {@link type}, terminating the older
* ones (if any).
*
* Currently the only type is "ml". The following note explains the reasoning
* why utility processes were used for the first workload (ML) that was handled
* this way. Similar reasoning applies to subsequent workloads (ffmpeg) that
* have been offloaded to utility processes in a slightly different manner to
* avoid stutter in the UI.
*
* [Note: ML IPC]
*
* The primary reason for doing ML tasks in the Node.js layer is so that we can
* use the binary ONNX runtime, which is 10-20x faster than the Wasm one that
* can be used directly on the web layer.
*
* For this to work, the main and renderer process need to communicate with each
* other. Further, in the web layer the ML indexing runs in a web worker (so as
* to not get in the way of the main thread). So the communication has 2 hops:
*
* Node.js main <-> Renderer main <-> Renderer web worker
*
* This naive way works, but has a problem. The Node.js main process is in the
* code path for delivering user events to the renderer process. The ML tasks we
* do take in the order of 100-300 ms (possibly more) for each individual
* inference. Thus, the Node.js main process is busy for those 100-300 ms, and
* does not forward events to the renderer, causing the UI to jitter.
*
* The solution for this is to spawn an Electron UtilityProcess, which we can
* think of a regular Node.js child process. This frees up the Node.js main
* process, and would remove the jitter.
* https://www.electronjs.org/docs/latest/tutorial/process-model
*
* It would seem that this introduces another hop in our IPC
*
* Node.js utility process <-> Node.js main <-> ...
*
* but here we can use the special bit about Electron utility processes that
* separates them from regular Node.js child processes: their support for
* message ports. https://www.electronjs.org/docs/latest/tutorial/message-ports
*
* As a brief summary, a MessagePort is a web feature that allows two contexts
* to communicate. A pair of message ports is called a message channel. The cool
* thing about these is that we can pass these ports themselves over IPC.
*
* > One caveat here is that the message ports can only be passed using the
* > `postMessage` APIs, not the usual send/invoke APIs.
*
* So we
*
* 1. In the utility process create a message channel.
* 2. Spawn a utility process, and send one port of the pair to it.
* 3. Send the other port of the pair to the renderer.
*
* The renderer will forward that port to the web worker that is coordinating
* the ML indexing on the web layer. Thereafter, the utility process and web
* worker can directly talk to each other!
*
* Node.js utility process <-> Renderer web worker
*
* The RPC protocol is handled using comlink on both ends. The port itself needs
* to be relayed using `postMessage`.
*/
export const triggerCreateUtilityProcess = (
type: UtilityProcessType,
window: BrowserWindow,
) => triggerCreateMLUtilityProcess(window);
const terminateMLProcessIfRunning = () => {
if (_utilityProcessML) {
log.debug(() => "Terminating running ML utility process");
_utilityProcessML.kill();
_utilityProcessML = undefined;
}
};
export const triggerCreateMLUtilityProcess = (window: BrowserWindow) => {
terminateMLProcessIfRunning();
const { port1, port2 } = new MessageChannelMain();
const child = utilityProcess.fork(path.join(__dirname, "ml-worker.js"));
const userDataPath = app.getPath("userData");
child.postMessage(/* MLWorkerInitData */ { userDataPath }, [port1]);
window.webContents.postMessage("utilityProcessPort/ml", undefined, [port2]);
handleMessagesFromMLUtilityProcess(child);
_utilityProcessML = child;
};
/**
* Handle messages posted from the utility process.
*
* [Note: Using Electron APIs in UtilityProcess]
*
* Only a small subset of the Electron APIs are available to a UtilityProcess.
* As of writing (Jul 2024, Electron 30), only the following are available:
*
* - net
* - systemPreferences
*
* In particular, `app` is not available.
*
* We structure our code so that it doesn't need anything apart from `net`.
*
* For the other cases,
*
* - Additional parameters to the utility process are passed alongwith the
* initial message where we provide it the message port.
*
* - When we need to communicate from the utility process to the main process,
* we use the `parentPort` in the utility process.
*/
const handleMessagesFromMLUtilityProcess = (child: UtilityProcess) => {
child.on("message", (m: unknown) => {
if (processUtilityProcessLogMessage("[ml-worker]", m)) {
return;
}
log.info("Ignoring unknown message from ML utility process", m);
});
};
/**
* A comlink endpoint that can be used to communicate with the ffmpeg utility
* process. If there is no ffmpeg utility process, a new one is created on
* demand.
*
* See [Note: ML IPC] for a general outline of why utility processes are needed
* (tl;dr; to avoid stutter on the UI).
*
* In the case of ffmpeg, the IPC flow is a bit different: the utility process
* is not exposed to the web layer, and is internal to the node layer. The
* reason for this difference is that we need to create temporary files etc, and
* doing it a utility process requires access to the `app` module which are not
* accessible (See: [Note: Using Electron APIs in UtilityProcess]).
*
* There could've been possible reasonable workarounds, but the architecture
* we've adopted of three layers:
*
* Renderer (web) <-> Node.js main <-> Node.js ffmpeg utility process
*
* The temporary file creation etc is handled in the Node.js main process, and
* paths to the files are forwarded to the ffmpeg utility process to act on.
*
* @returns an endpoint that can be used to communicate with the utility
* process. The utility process is expected to expose an object that conforms to
* the {@link ElectronFFmpegWorkerNode} interface on this endpoint.
*/
export const ffmpegUtilityProcessEndpoint = () =>
(_utilityProcessFFmpegEndpoint ??= createFFmpegUtilityProcessEndpoint());
const terminateFFmpegProcessIfRunning = () => {
if (_utilityProcessFFmpeg) {
log.debug(() => "Terminating running FFmpeg utility process");
_utilityProcessFFmpeg.kill();
_utilityProcessFFmpeg = undefined;
_utilityProcessFFmpegEndpoint = undefined;
}
};
const createFFmpegUtilityProcessEndpoint = () => {
if (_utilityProcessFFmpeg) {
throw new Error("FFmpeg utility process is already running");
}
// Promise.withResolvers is currently in the node available to us.
let resolve: ((endpoint: Endpoint) => void) | undefined;
const promise = new Promise<Endpoint>((r) => (resolve = r));
const { port1, port2 } = new MessageChannelMain();
const child = utilityProcess.fork(path.join(__dirname, "ffmpeg-worker.js"));
// Send a handle to the port (one end of the message channel) to the utility
// process (alongwith any other init data). The utility process will reply
// with an "ack" when it get it.
const appVersion = app.getVersion();
child.postMessage(/* FFmpegWorkerInitData */ { appVersion }, [port1]);
child.on("message", (m: unknown) => {
if (m && typeof m == "object" && "method" in m) {
switch (m.method) {
case "ack":
resolve!(messagePortMainEndpoint(port2));
return;
}
}
if (processUtilityProcessLogMessage("[ffmpeg-worker]", m)) {
return;
}
log.info("Ignoring unknown message from ffmpeg utility process", m);
});
_utilityProcessFFmpeg = child;
// Resolve with the other end of the message channel (once we get an "ack"
// from the utility process).
return promise;
};

View File

@@ -3,23 +3,18 @@
*/
import { net, protocol } from "electron/main";
import { randomUUID } from "node:crypto";
import fs_ from "node:fs";
import fs from "node:fs/promises";
import { Readable, Writable } from "node:stream";
import { Writable } from "node:stream";
import { pathToFileURL } from "node:url";
import log from "./log";
import {
ffmpegConvertToMP4,
ffmpegGenerateHLSPlaylistAndSegments,
type FFmpegGenerateHLSPlaylistAndSegmentsResult,
} from "./services/ffmpeg";
import { ffmpegUtilityProcess } from "./services/ffmpeg";
import { type FFmpegGenerateHLSPlaylistAndSegmentsResult } from "./services/ffmpeg-worker";
import { markClosableZip, openZip } from "./services/zip";
import { wait } from "./utils/common";
import { writeStream } from "./utils/stream";
import {
deleteTempFile,
deleteTempFileIgnoringErrors,
makeFileForDataOrStreamOrPathOrZipItem,
makeFileForStreamOrPathOrZipItem,
makeTempFilePath,
} from "./utils/temp";
@@ -234,12 +229,14 @@ export const clearPendingVideoResults = () => pendingVideoResults.clear();
* See also: [Note: IPC streams]
*/
const handleConvertToMP4Write = async (request: Request) => {
const worker = await ffmpegUtilityProcess();
const inputTempFilePath = await makeTempFilePath();
await writeStream(inputTempFilePath, request.body!);
const outputTempFilePath = await makeTempFilePath("mp4");
try {
await ffmpegConvertToMP4(inputTempFilePath, outputTempFilePath);
await worker.ffmpegConvertToMP4(inputTempFilePath, outputTempFilePath);
} catch (e) {
log.error("Conversion to MP4 failed", e);
await deleteTempFileIgnoringErrors(outputTempFilePath);
@@ -280,9 +277,9 @@ const handleVideoDone = async (token: string) => {
*
* The difference here is that we the conversion generates two streams^ - one
* for the HLS playlist itself, and one for the file containing the encrypted
* and transcoded video chunks. The video stream we write to the objectUploadURL
* (provided via {@link params}), and then we return a JSON object containing
* the token for the playlist, and other metadata for use by the renderer.
* and transcoded video chunks. The video stream we write to the pre-signed
* object upload URL(s), and then we return a JSON object containing the token
* for the playlist, and other metadata for use by the renderer.
*
* ^ if the video doesn't require a stream to be generated (e.g. it is very
* small and already uses a compatible codec) then a HTT 204 is returned and
@@ -292,10 +289,12 @@ const handleGenerateHLSWrite = async (
request: Request,
params: URLSearchParams,
) => {
const objectUploadURL = params.get("objectUploadURL");
if (!objectUploadURL) throw new Error("Missing objectUploadURL");
const fileID = parseInt(params.get("fileID") ?? "", 10);
const fetchURL = params.get("fetchURL");
const authToken = params.get("authToken");
if (!fileID || !fetchURL || !authToken) throw new Error("Missing params");
let inputItem: Parameters<typeof makeFileForDataOrStreamOrPathOrZipItem>[0];
let inputItem: Parameters<typeof makeFileForStreamOrPathOrZipItem>[0];
const path = params.get("path");
if (path) {
inputItem = path;
@@ -311,20 +310,25 @@ const handleGenerateHLSWrite = async (
}
}
const worker = await ffmpegUtilityProcess();
const {
path: inputFilePath,
isFileTemporary: isInputFileTemporary,
writeToTemporaryFile: writeToTemporaryInputFile,
} = await makeFileForDataOrStreamOrPathOrZipItem(inputItem);
} = await makeFileForStreamOrPathOrZipItem(inputItem);
const outputFilePathPrefix = await makeTempFilePath();
let result: FFmpegGenerateHLSPlaylistAndSegmentsResult | undefined;
try {
await writeToTemporaryInputFile();
result = await ffmpegGenerateHLSPlaylistAndSegments(
result = await worker.ffmpegGenerateHLSPlaylistAndSegments(
inputFilePath,
outputFilePathPrefix,
fileID,
fetchURL,
authToken,
);
if (!result) {
@@ -332,94 +336,22 @@ const handleGenerateHLSWrite = async (
return new Response(null, { status: 204 });
}
const { playlistPath, videoPath } = result;
try {
await uploadVideoSegments(videoPath, objectUploadURL);
const { playlistPath, dimensions, videoSize, videoObjectID } = result;
const playlistToken = randomUUID();
pendingVideoResults.set(playlistToken, playlistPath);
const playlistToken = randomUUID();
pendingVideoResults.set(playlistToken, playlistPath);
const { dimensions, videoSize } = result;
return new Response(
JSON.stringify({ playlistToken, dimensions, videoSize }),
{ status: 200 },
);
} catch (e) {
await deleteTempFileIgnoringErrors(playlistPath);
throw e;
} finally {
await deleteTempFileIgnoringErrors(videoPath);
}
return new Response(
JSON.stringify({
playlistToken,
dimensions,
videoSize,
videoObjectID,
}),
{ status: 200 },
);
} finally {
if (isInputFileTemporary)
await deleteTempFileIgnoringErrors(inputFilePath);
}
};
/**
* Upload the file at the given {@link videoFilePath} to the provided presigned
* {@link objectUploadURL} using a HTTP PUT request.
*
* In case on non-HTTP-4xx errors, retry up to 3 times with exponential backoff.
*
* See: [Note: Upload HLS video segment from node side].
*
* ---
*
* This is an inlined but bespoke reimplementation of `retryEnsuringHTTPOkOr4xx`
* from `web/packages/base/http.ts` (we don't have the rest of the scaffolding
* used by that function, which is why it is inlined bespoked).
*
* It handles the specific use case of uploading videos since generating the HLS
* stream is a fairly expensive operation, so a retry to discount transient
* network issues is called for. There are only 2 retries for a total of 3
* attempts, and the retry gaps are more spaced out.
*/
export const uploadVideoSegments = async (
videoFilePath: string,
objectUploadURL: string,
) => {
const waitTimeBeforeNextTry = [5000, 20000];
while (true) {
let abort = false;
try {
const nodeStream = fs_.createReadStream(videoFilePath);
const webStream = Readable.toWeb(nodeStream);
const res = await net.fetch(objectUploadURL, {
method: "PUT",
// The duplex option is required since we're passing a stream.
//
// @ts-expect-error TypeScript's libdom.d.ts does not include
// the "duplex" parameter, e.g. see
// https://github.com/node-fetch/node-fetch/issues/1769.
duplex: "half",
body: webStream,
});
if (res.ok) {
// Success.
return;
}
if (res.status >= 400 && res.status < 500) {
// HTTP 4xx.
abort = true;
}
throw new Error(
`Failed to upload generated HLS video: HTTP ${res.status} ${res.statusText}`,
);
} catch (e) {
if (abort) {
throw e;
}
const t = waitTimeBeforeNextTry.shift();
if (!t) {
throw e;
} else {
log.warn("Will retry potentially transient request failure", e);
}
await wait(t);
}
}
};

View File

@@ -19,7 +19,7 @@ export const messagePortMainEndpoint = (mp: MessagePortMain): Endpoint => {
const listeners = new WeakMap<NL, EL>();
return {
postMessage: (message, transfer) => {
mp.postMessage(message, transfer as unknown as MessagePortMain[]);
mp.postMessage(message, (transfer ?? []) as MessagePortMain[]);
},
addEventListener: (_, eh) => {
const l: EL = (data) =>

View File

@@ -15,3 +15,11 @@
*/
export const wait = (ms: number) =>
new Promise((resolve) => setTimeout(resolve, ms));
/**
* Convert `null` to `undefined`, passthrough everything else unchanged.
*
* Duplicated from `web/packages/utils/transform.ts`.
*/
export const nullToUndefined = <T>(v: T | null | undefined): T | undefined =>
v === null ? undefined : v;

View File

@@ -0,0 +1,23 @@
import shellescape from "any-shell-escape";
import { exec } from "node:child_process";
import { promisify } from "node:util";
import log from "../log-worker";
/**
* Run a shell command asynchronously (utility process edition).
*
* This is an almost verbatim copy of {@link execAsync} from `electron.ts`,
* except it is meant to be usable from a utility process where only a subset of
* imports are available. See [Note: Using Electron APIs in UtilityProcess].
*/
export const execAsyncWorker = async (command: string | string[]) => {
const escapedCommand = Array.isArray(command)
? shellescape(command)
: command;
const startTime = Date.now();
const result = await execAsync_(escapedCommand);
log.debugString(`${escapedCommand} (${Date.now() - startTime} ms)`);
return result;
};
const execAsync_ = promisify(exec);

View File

@@ -0,0 +1,31 @@
export const clientPackageName = "io.ente.photos.desktop";
/**
* Reimplementation of {@link publicRequestHeaders} from the web source.
*
* @param desktopAppVersion The desktop app's version. This will get passed on
* as the "X-Client-Version" header.
*
* We cannot directly use `app.getVersion()` to obtain this value since the
* {@link app} module is not accessible to Electron utility processes which also
* calls this function.
*/
export const publicRequestHeaders = (desktopAppVersion: string) => ({
"X-Client-Package": clientPackageName,
"X-Client-Version": desktopAppVersion,
});
/**
* Reimplementation of {@link authenticatedRequestHeaders} from the web source.
*
* This builds on top of {@link publicRequestHeaders} and takes the same
* parameters, and additionally also requires the {@link authToken} that will be
* passed as the "X-Auth-Token" header.
*/
export const authenticatedRequestHeaders = (
desktopAppVersion: string,
authToken: string,
) => ({
...publicRequestHeaders(desktopAppVersion),
"X-Auth-Token": authToken,
});

View File

@@ -80,8 +80,8 @@ export const deleteTempFileIgnoringErrors = async (tempFilePath: string) => {
}
};
/** The result of {@link makeFileForDataOrStreamOrPathOrZipItem}. */
interface FileForDataOrPathOrZipItem {
/** The result of {@link makeFileForStreamOrPathOrZipItem}. */
interface FileForStreamOrPathOrZipItem {
/**
* The path to the file (possibly temporary).
*/
@@ -107,13 +107,13 @@ interface FileForDataOrPathOrZipItem {
* that needs to be deleted after processing, and a function to write the given
* {@link item} into that temporary file if needed.
*
* @param item The contents of the file (bytes), or a {@link ReadableStream}
* with the contents of the file, or the path to an existing file, or a (path to
* a zip file, name of an entry within that zip file) tuple.
* @param item A {@link ReadableStream} with the contents of the file, or the
* path to an existing file, or a (path to a zip file, name of an entry within
* that zip file) tuple.
*/
export const makeFileForDataOrStreamOrPathOrZipItem = async (
item: Uint8Array | ReadableStream | string | ZipItem,
): Promise<FileForDataOrPathOrZipItem> => {
export const makeFileForStreamOrPathOrZipItem = async (
item: ReadableStream | string | ZipItem,
): Promise<FileForStreamOrPathOrZipItem> => {
let path: string;
let isFileTemporary: boolean;
let writeToTemporaryFile = async () => {
@@ -126,9 +126,7 @@ export const makeFileForDataOrStreamOrPathOrZipItem = async (
} else {
path = await makeTempFilePath();
isFileTemporary = true;
if (item instanceof Uint8Array) {
writeToTemporaryFile = () => fs.writeFile(path, item);
} else if (item instanceof ReadableStream) {
if (item instanceof ReadableStream) {
writeToTemporaryFile = () => writeStream(path, item);
} else {
writeToTemporaryFile = async () => {

View File

@@ -69,6 +69,7 @@ import type {
FFmpegCommand,
FolderWatch,
PendingUploads,
UtilityProcessType,
ZipItem,
} from "./types/ipc";
@@ -192,41 +193,45 @@ const convertToJPEG = (imageData: Uint8Array) =>
ipcRenderer.invoke("convertToJPEG", imageData);
const generateImageThumbnail = (
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
maxDimension: number,
maxSize: number,
) =>
ipcRenderer.invoke(
"generateImageThumbnail",
dataOrPathOrZipItem,
pathOrZipItem,
maxDimension,
maxSize,
);
const ffmpegExec = (
command: FFmpegCommand,
dataOrPathOrZipItem: Uint8Array | string | ZipItem,
pathOrZipItem: string | ZipItem,
outputFileExtension: string,
) =>
ipcRenderer.invoke(
"ffmpegExec",
command,
dataOrPathOrZipItem,
pathOrZipItem,
outputFileExtension,
);
// - ML
const ffmpegDetermineVideoDuration = (pathOrZipItem: string | ZipItem) =>
ipcRenderer.invoke("ffmpegDetermineVideoDuration", pathOrZipItem);
const createMLWorker = () => {
// - Utility processes
const triggerCreateUtilityProcess = (type: UtilityProcessType) => {
const portEvent = `utilityProcessPort/${type}`;
const l = (event: IpcRendererEvent) => {
void windowLoaded.then(() => {
// "*"" is the origin to send to.
window.postMessage("createMLWorker/port", "*", event.ports);
ipcRenderer.off("createMLWorker/port", l);
window.postMessage(portEvent, "*", event.ports);
ipcRenderer.off(portEvent, l);
});
};
ipcRenderer.on("createMLWorker/port", l);
ipcRenderer.send("createMLWorker");
ipcRenderer.on(portEvent, l);
ipcRenderer.send("triggerCreateUtilityProcess", type);
};
// - Watch
@@ -390,10 +395,11 @@ contextBridge.exposeInMainWorld("electron", {
convertToJPEG,
generateImageThumbnail,
ffmpegExec,
ffmpegDetermineVideoDuration,
// - ML
createMLWorker,
triggerCreateUtilityProcess,
// - Watch

View File

@@ -5,6 +5,8 @@
* See [Note: types.ts <-> preload.ts <-> ipc.ts]
*/
export type UtilityProcessType = "ml";
export interface AppUpdate {
autoUpdatable: boolean;
version: string;

View File

@@ -136,13 +136,20 @@
minimatch "^9.0.3"
plist "^3.1.0"
"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
"@eslint-community/eslint-utils@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59"
integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==
dependencies:
eslint-visitor-keys "^3.3.0"
"@eslint-community/eslint-utils@^4.7.0":
version "4.7.0"
resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a"
integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==
dependencies:
eslint-visitor-keys "^3.4.3"
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0":
version "4.11.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.0.tgz#b0ffd0312b4a3fd2d6f77237e7248a5ad3a680ae"
@@ -177,10 +184,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.9.1.tgz#4a97e85e982099d6c7ee8410aacb55adaa576f06"
integrity sha512-xIDQRsfg5hNBqHz04H1R3scSVwmI+KUbqjsQKHKQ1DAUSaUjYPReZZmS/5PNiKu1fUvzDd6H7DEDKACSEhu+TQ==
"@eslint/js@^9.25.1":
version "9.25.1"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.25.1.tgz#25f5c930c2b68b5ebe7ac857f754cbd61ef6d117"
integrity sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==
"@eslint/js@^9.28.0":
version "9.28.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.28.0.tgz#7822ccc2f8cae7c3cd4f902377d520e9ae03f844"
integrity sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==
"@eslint/object-schema@^2.1.4":
version "2.1.4"
@@ -268,10 +275,10 @@
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
"@pkgr/core@^0.1.0":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
"@pkgr/core@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c"
integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw==
"@sindresorhus/is@^4.0.0":
version "4.6.0"
@@ -290,10 +297,10 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
"@tsconfig/node22@^22.0.1":
version "22.0.1"
resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.1.tgz#27e3ee9b359e31e5b94690bf2bad5a923c1d57d0"
integrity sha512-VkgOa3n6jvs1p+r3DiwBqeEwGAwEvnVCg/hIjiANl5IEcqP3G0u5m8cBJspe1t9qjZRlZ7WFgqq5bJrGdgAKMg==
"@tsconfig/node22@^22.0.2":
version "22.0.2"
resolved "https://registry.yarnpkg.com/@tsconfig/node22/-/node22-22.0.2.tgz#1e04e2c5cc946dac787d69bb502462a851ae51b6"
integrity sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==
"@types/auto-launch@^5.0.5":
version "5.0.5"
@@ -385,85 +392,101 @@
dependencies:
"@types/node" "*"
"@typescript-eslint/eslint-plugin@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz#62f1befe59647524994e89de4516d8dcba7a850a"
integrity sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==
"@typescript-eslint/eslint-plugin@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz#532641b416ed2afd5be893cddb2a58e9cd1f7a3e"
integrity sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==
dependencies:
"@eslint-community/regexpp" "^4.10.0"
"@typescript-eslint/scope-manager" "8.31.1"
"@typescript-eslint/type-utils" "8.31.1"
"@typescript-eslint/utils" "8.31.1"
"@typescript-eslint/visitor-keys" "8.31.1"
"@typescript-eslint/scope-manager" "8.33.1"
"@typescript-eslint/type-utils" "8.33.1"
"@typescript-eslint/utils" "8.33.1"
"@typescript-eslint/visitor-keys" "8.33.1"
graphemer "^1.4.0"
ignore "^5.3.1"
ignore "^7.0.0"
natural-compare "^1.4.0"
ts-api-utils "^2.0.1"
ts-api-utils "^2.1.0"
"@typescript-eslint/parser@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.31.1.tgz#e9b0ccf30d37dde724ee4d15f4dbc195995cce1b"
integrity sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==
"@typescript-eslint/parser@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.33.1.tgz#ef9a5ee6aa37a6b4f46cc36d08a14f828238afe2"
integrity sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==
dependencies:
"@typescript-eslint/scope-manager" "8.31.1"
"@typescript-eslint/types" "8.31.1"
"@typescript-eslint/typescript-estree" "8.31.1"
"@typescript-eslint/visitor-keys" "8.31.1"
"@typescript-eslint/scope-manager" "8.33.1"
"@typescript-eslint/types" "8.33.1"
"@typescript-eslint/typescript-estree" "8.33.1"
"@typescript-eslint/visitor-keys" "8.33.1"
debug "^4.3.4"
"@typescript-eslint/scope-manager@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz#1eb52e76878f545e4add142e0d8e3e97e7aa443b"
integrity sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==
"@typescript-eslint/project-service@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz#c85e7d9a44d6a11fe64e73ac1ed47de55dc2bf9f"
integrity sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==
dependencies:
"@typescript-eslint/types" "8.31.1"
"@typescript-eslint/visitor-keys" "8.31.1"
"@typescript-eslint/type-utils@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz#be0f438fb24b03568e282a0aed85f776409f970c"
integrity sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==
dependencies:
"@typescript-eslint/typescript-estree" "8.31.1"
"@typescript-eslint/utils" "8.31.1"
"@typescript-eslint/tsconfig-utils" "^8.33.1"
"@typescript-eslint/types" "^8.33.1"
debug "^4.3.4"
ts-api-utils "^2.0.1"
"@typescript-eslint/types@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.1.tgz#478ed6f7e8aee1be7b63a60212b6bffe1423b5d4"
integrity sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==
"@typescript-eslint/typescript-estree@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz#37792fe7ef4d3021c7580067c8f1ae66daabacdf"
integrity sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==
"@typescript-eslint/scope-manager@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz#d1e0efb296da5097d054bc9972e69878a2afea73"
integrity sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==
dependencies:
"@typescript-eslint/types" "8.31.1"
"@typescript-eslint/visitor-keys" "8.31.1"
"@typescript-eslint/types" "8.33.1"
"@typescript-eslint/visitor-keys" "8.33.1"
"@typescript-eslint/tsconfig-utils@8.33.1", "@typescript-eslint/tsconfig-utils@^8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz#7836afcc097a4657a5ed56670851a450d8b70ab8"
integrity sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==
"@typescript-eslint/type-utils@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz#d73ee1a29d8a0abe60d4abbff4f1d040f0de15fa"
integrity sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==
dependencies:
"@typescript-eslint/typescript-estree" "8.33.1"
"@typescript-eslint/utils" "8.33.1"
debug "^4.3.4"
ts-api-utils "^2.1.0"
"@typescript-eslint/types@8.33.1", "@typescript-eslint/types@^8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.33.1.tgz#b693111bc2180f8098b68e9958cf63761657a55f"
integrity sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==
"@typescript-eslint/typescript-estree@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz#d271beed470bc915b8764e22365d4925c2ea265d"
integrity sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==
dependencies:
"@typescript-eslint/project-service" "8.33.1"
"@typescript-eslint/tsconfig-utils" "8.33.1"
"@typescript-eslint/types" "8.33.1"
"@typescript-eslint/visitor-keys" "8.33.1"
debug "^4.3.4"
fast-glob "^3.3.2"
is-glob "^4.0.3"
minimatch "^9.0.4"
semver "^7.6.0"
ts-api-utils "^2.0.1"
ts-api-utils "^2.1.0"
"@typescript-eslint/utils@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.1.tgz#5628ea0393598a0b2f143d0fc6d019f0dee9dd14"
integrity sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==
"@typescript-eslint/utils@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.33.1.tgz#ea22f40d3553da090f928cf17907e963643d4b96"
integrity sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
"@typescript-eslint/scope-manager" "8.31.1"
"@typescript-eslint/types" "8.31.1"
"@typescript-eslint/typescript-estree" "8.31.1"
"@eslint-community/eslint-utils" "^4.7.0"
"@typescript-eslint/scope-manager" "8.33.1"
"@typescript-eslint/types" "8.33.1"
"@typescript-eslint/typescript-estree" "8.33.1"
"@typescript-eslint/visitor-keys@8.31.1":
version "8.31.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz#6742b0e3ba1e0c1e35bdaf78c03e759eb8dd8e75"
integrity sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==
"@typescript-eslint/visitor-keys@8.33.1":
version "8.33.1"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz#6c6e002c24d13211df3df851767f24dfdb4f42bc"
integrity sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==
dependencies:
"@typescript-eslint/types" "8.31.1"
"@typescript-eslint/types" "8.33.1"
eslint-visitor-keys "^4.2.0"
"@xmldom/xmldom@^0.8.8":
@@ -1007,6 +1030,17 @@ cross-env@^7.0.3:
dependencies:
cross-spawn "^7.0.1"
cross-spawn@^6.0.0:
version "6.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.6.tgz#30d0efa0712ddb7eb5a76e1e8721bffafa6b5d57"
integrity sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==
dependencies:
nice-try "^1.0.4"
path-key "^2.0.1"
semver "^5.5.0"
shebang-command "^1.2.0"
which "^1.2.9"
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.6:
version "7.0.6"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
@@ -1087,7 +1121,7 @@ detect-libc@^2.0.1:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
detect-newline@^4.0.0:
detect-newline@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23"
integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==
@@ -1216,10 +1250,10 @@ electron-updater@^6.6.3:
semver "^7.6.3"
tiny-typed-emitter "^2.1.0"
electron@^36.1.0:
version "36.1.0"
resolved "https://registry.yarnpkg.com/electron/-/electron-36.1.0.tgz#9919b77e61cd1400acc6dd24f9db8451fba5f8eb"
integrity sha512-gnp3BnbKdGsVc7cm1qlEaZc8pJsR08mIs8H/yTo8gHEtFkGGJbDTVZOYNAfbQlL0aXh+ozv+CnyiNeDNkT1Upg==
electron@^36.4.0:
version "36.4.0"
resolved "https://registry.yarnpkg.com/electron/-/electron-36.4.0.tgz#9463bf5fa7565ae7be3a274f7f6a46359bcfe74d"
integrity sha512-LLOOZEuW5oqvnjC7HBQhIqjIIJAZCIFjQxltQGLfEC7XFsBoZgQ3u3iFj+Kzw68Xj97u1n57Jdt7P98qLvUibQ==
dependencies:
"@electron/get" "^2.0.0"
"@types/node" "^22.7.7"
@@ -1289,7 +1323,7 @@ eslint-scope@^8.0.2:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-visitor-keys@^3.3.0:
eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
@@ -1372,6 +1406,19 @@ esutils@^2.0.2:
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
execa@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
dependencies:
cross-spawn "^6.0.0"
get-stream "^4.0.0"
is-stream "^1.1.0"
npm-run-path "^2.0.0"
p-finally "^1.0.0"
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exponential-backoff@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6"
@@ -1438,10 +1485,10 @@ fd-slicer@~1.1.0:
dependencies:
pend "~1.2.0"
fdir@^6.4.2:
version "6.4.2"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.2.tgz#ddaa7ce1831b161bc3657bb99cb36e1622702689"
integrity sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==
fdir@^6.4.4:
version "6.4.4"
resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.4.tgz#1cfcf86f875a883e19a8fab53622cfe992e8d2f9"
integrity sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==
ffmpeg-static@^5.2.0:
version "5.2.0"
@@ -1589,10 +1636,12 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
has-symbols "^1.0.3"
hasown "^2.0.0"
get-stdin@^9.0.0:
version "9.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.1.0:
version "5.2.0"
@@ -1601,10 +1650,10 @@ get-stream@^5.1.0:
dependencies:
pump "^3.0.0"
git-hooks-list@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc"
integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==
git-hooks-list@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-4.1.1.tgz#ae340b82a9312354c73b48007f33840bbd83d3c0"
integrity sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==
glob-parent@^5.1.2:
version "5.1.2"
@@ -1632,7 +1681,7 @@ glob@^10.3.12, glob@^10.3.7:
package-json-from-dist "^1.0.0"
path-scurry "^1.11.1"
glob@^7.0.0, glob@^7.1.3, glob@^7.1.6:
glob@^7.1.3, glob@^7.1.6:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -1830,11 +1879,16 @@ ieee754@^1.1.13:
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^5.2.0, ignore@^5.3.1:
ignore@^5.2.0:
version "5.3.2"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
ignore@^7.0.0:
version "7.0.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.4.tgz#a12c70d0f2607c5bf508fb65a40c75f037d7a078"
integrity sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==
import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -1945,6 +1999,11 @@ is-plain-obj@^4.1.0:
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
is-stream@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
is-unicode-supported@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
@@ -2244,7 +2303,7 @@ minimatch@^9.0.3, minimatch@^9.0.4:
dependencies:
brace-expansion "^2.0.1"
minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
@@ -2363,6 +2422,11 @@ next-electron-server@^1.0.0:
resolved "https://registry.yarnpkg.com/next-electron-server/-/next-electron-server-1.0.0.tgz#03e133ed64a5ef671b6c6409f908c4901b1828cb"
integrity sha512-fTUaHwT0Jry2fbdUSIkAiIqgDAInI5BJFF4/j90/okvZCYlyx6yxpXB30KpzmOG6TN/ESwyvsFJVvS2WHT8PAA==
nice-try@^1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
node-abi@^3.45.0:
version "3.67.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.67.0.tgz#1d159907f18d18e18809dbbb5df47ed2426a08df"
@@ -2399,6 +2463,13 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==
dependencies:
path-key "^2.0.0"
object-keys@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
@@ -2463,6 +2534,11 @@ p-cancelable@^2.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==
p-limit@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
@@ -2535,6 +2611,11 @@ path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
@@ -2599,13 +2680,13 @@ prettier-plugin-organize-imports@^4.1.0:
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-4.1.0.tgz#f3d3764046a8e7ba6491431158b9be6ffd83b90f"
integrity sha512-5aWRdCgv645xaa58X8lOxzZoiHAldAPChljr/MT0crXVOWTZ+Svl4hIWlz+niYSlO6ikE5UXkN1JrRvIP2ut0A==
prettier-plugin-packagejson@^2.5.10:
version "2.5.10"
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.10.tgz#f47068d0aa12efcdddb802189d8adae874ba00e7"
integrity sha512-LUxATI5YsImIVSaaLJlJ3aE6wTD+nvots18U3GuQMJpUyClChaZlQrqx3dBnbhF20OnKWZyx8EgyZypQtBDtgQ==
prettier-plugin-packagejson@^2.5.15:
version "2.5.15"
resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.5.15.tgz#7ea880d4bb1681b5331ea7044efd3d653776f469"
integrity sha512-2QSx6y4IT6LTwXtCvXAopENW5IP/aujC8fobEM2pDbs0IGkiVjW/ipPuYAHuXigbNe64aGWF7vIetukuzM3CBw==
dependencies:
sort-package-json "2.15.1"
synckit "0.9.2"
sort-package-json "3.2.1"
synckit "0.11.8"
prettier@3.5.3:
version "3.5.3"
@@ -2829,6 +2910,11 @@ semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.6.0, semve
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
semver@^7.7.1:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
serialize-error@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18"
@@ -2836,6 +2922,13 @@ serialize-error@^7.0.1:
dependencies:
type-fest "^0.13.1"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
@@ -2843,6 +2936,11 @@ shebang-command@^2.0.0:
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
@@ -2853,24 +2951,25 @@ shell-quote@^1.8.1:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
shelljs@^0.8.5:
version "0.8.5"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
shelljs@^0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.9.2.tgz#a8ac724434520cd7ae24d52071e37a18ac2bb183"
integrity sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==
dependencies:
glob "^7.0.0"
execa "^1.0.0"
fast-glob "^3.3.2"
interpret "^1.0.0"
rechoir "^0.6.2"
shx@^0.3.4:
version "0.3.4"
resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.4.tgz#74289230b4b663979167f94e1935901406e40f02"
integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==
shx@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/shx/-/shx-0.4.0.tgz#c6ea6ace7e778da0ab32d2eab9def59d788e9336"
integrity sha512-Z0KixSIlGPpijKgcH6oCMCbltPImvaKy0sGH8AkLRXw1KyzpKtaCTizP2xen+hNDqVF4xxgvA0KXSb9o4Q6hnA==
dependencies:
minimist "^1.2.3"
shelljs "^0.8.5"
minimist "^1.2.8"
shelljs "^0.9.2"
signal-exit@^3.0.2:
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.7"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
@@ -2923,19 +3022,18 @@ sort-object-keys@^1.1.3:
resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
sort-package-json@2.15.1:
version "2.15.1"
resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.15.1.tgz#e5a035fad7da277b1947b9eecc93ea09c1c2526e"
integrity sha512-9x9+o8krTT2saA9liI4BljNjwAbvUnWf11Wq+i/iZt8nl2UGYnf3TH5uBydE7VALmP7AGwlfszuEeL8BDyb0YA==
sort-package-json@3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-3.2.1.tgz#889f3bdf43ceeff5fa4278a7c53ae5b1520d287e"
integrity sha512-rTfRdb20vuoAn7LDlEtCqOkYfl2X+Qze6cLbNOzcDpbmKEhJI30tTN44d5shbKJnXsvz24QQhlCm81Bag7EOKg==
dependencies:
detect-indent "^7.0.1"
detect-newline "^4.0.0"
get-stdin "^9.0.0"
git-hooks-list "^3.0.0"
detect-newline "^4.0.1"
git-hooks-list "^4.0.0"
is-plain-obj "^4.1.0"
semver "^7.6.0"
semver "^7.7.1"
sort-object-keys "^1.1.3"
tinyglobby "^0.2.9"
tinyglobby "^0.2.12"
source-map-support@^0.5.19:
version "0.5.21"
@@ -2990,6 +3088,11 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1:
dependencies:
ansi-regex "^5.0.1"
strip-eof@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==
strip-json-comments@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
@@ -3021,13 +3124,12 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
synckit@0.9.2:
version "0.9.2"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==
synckit@0.11.8:
version "0.11.8"
resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457"
integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==
dependencies:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
"@pkgr/core" "^0.2.4"
tar@^6.0.5, tar@^6.1.11, tar@^6.1.12, tar@^6.2.1:
version "6.2.1"
@@ -3078,12 +3180,12 @@ tiny-typed-emitter@^2.1.0:
resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5"
integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==
tinyglobby@^0.2.9:
version "0.2.10"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.10.tgz#e712cf2dc9b95a1f5c5bbd159720e15833977a0f"
integrity sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==
tinyglobby@^0.2.12:
version "0.2.13"
resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.13.tgz#a0e46515ce6cbcd65331537e57484af5a7b2ff7e"
integrity sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==
dependencies:
fdir "^6.4.2"
fdir "^6.4.4"
picomatch "^4.0.2"
tmp-promise@^3.0.2:
@@ -3117,12 +3219,12 @@ truncate-utf8-bytes@^1.0.0:
dependencies:
utf8-byte-length "^1.0.1"
ts-api-utils@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd"
integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==
ts-api-utils@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91"
integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
tslib@^2.1.0, tslib@^2.6.2:
tslib@^2.1.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01"
integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==
@@ -3149,14 +3251,14 @@ typedarray@^0.0.6:
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
typescript-eslint@^8.31.1:
version "8.31.1"
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.31.1.tgz#b77ab1e48ced2daab9225ff94bab54391a4af69b"
integrity sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA==
typescript-eslint@^8.33.1:
version "8.33.1"
resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.33.1.tgz#d2d59c9b24afe1f903a855b02145802e4ae930ff"
integrity sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==
dependencies:
"@typescript-eslint/eslint-plugin" "8.31.1"
"@typescript-eslint/parser" "8.31.1"
"@typescript-eslint/utils" "8.31.1"
"@typescript-eslint/eslint-plugin" "8.33.1"
"@typescript-eslint/parser" "8.33.1"
"@typescript-eslint/utils" "8.33.1"
typescript@^5.4.3, typescript@^5.8.3:
version "5.8.3"
@@ -3230,6 +3332,13 @@ wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
which@^1.2.9:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
dependencies:
isexe "^2.0.0"
which@^2.0.1, which@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
@@ -3311,3 +3420,8 @@ yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zod@^3.25.51:
version "3.25.51"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.51.tgz#aa2cf648e54f6f060f139cf77b694819f63c9f3a"
integrity sha512-TQSnBldh+XSGL+opiSIq0575wvDPqu09AqWe1F7JhUMKY+M91/aGlK4MhpVNO7MgYfHcVCB1ffwAUTJzllKJqg==

View File

@@ -9,11 +9,11 @@ export default defineConfig({
cleanUrls: true,
ignoreDeadLinks: "localhostLinks",
vite: {
build: {
rollupOptions: {
external: ['client-museum-s3.png'] // Added to handle static asset import
}
}
build: {
rollupOptions: {
external: ["client-museum-s3.png"], // Added to handle static asset import
},
},
},
themeConfig: {
// We use the default theme (with some CSS color overrides). This

View File

@@ -2,6 +2,27 @@
// appropriate place here.
export const sidebar = [
{
text: "Overview",
items: [
{
text: "Introduction",
link: "/overview/",
},
{
text: "Community",
link: "/overview/community",
},
{
text: "Contributing",
link: "/overview/contribute",
},
{
text: "Help",
link: "/overview/help",
},
],
},
{
text: "Photos",
items: [
@@ -292,7 +313,7 @@ export const sidebar = [
},
{
text: "Bucket CORS",
link: '/self-hosting/troubleshooting/bucket-cors'
link: "/self-hosting/troubleshooting/bucket-cors",
},
{
text: "Uploads",
@@ -311,7 +332,7 @@ export const sidebar = [
{
text: "Community Guides",
collapsed: true,
items :[
items: [
{
text: "Ente via Tailscale",
link: "/self-hosting/guides/Tailscale",
@@ -319,8 +340,8 @@ export const sidebar = [
{
text: "Ente with External S3",
link: "/self-hosting/guides/external-s3",
}
]
},
],
},
{
text: "FAQ",
@@ -339,16 +360,12 @@ export const sidebar = [
text: "Backups",
link: "/self-hosting/faq/backup",
},
{
text: "Environment variables",
link: "/self-hosting/faq/environment",
},
],
},
],
},
{
text: "About",
link: "/about/",
},
{
text: "Contribute",
link: "/about/contribute",
},
];

View File

@@ -41,6 +41,16 @@ Usually, this discrepancy occurs because the time in your browser might be
incorrect. In particular, multiple users have reported that Firefox provides
incorrect time when certain privacy settings are enabled.
> [!TIP]
>
> Newer Ente Auth clients (upcoming 4.4.0+) will automatically try to correct
> for incorrect system time, so you should be seeing correct codes even if your
> system time is out of sync. However, this automatic correction will not work
> if you're using Ente Auth in offline mode.
>
> If you've recently changed your system time and the codes are still incorrect,
> try to refresh / restart the app if needed.
### Can I access my codes on web?
You can access your codes on the web at [auth.ente.io](https://auth.ente.io).

View File

@@ -10,8 +10,9 @@ A guide written by Green, an ente.io lover
> [!WARNING]
>
> Authy has dropped all support for its desktop apps. It is no longer possible
> to export data from Authy using methods 1 and 2. You will need either an iOS device
> and computer (method 4) or a rooted Android phone (method 3) to follow this guide.
> to export data from Authy using methods 1 and 2. You will need either an iOS
> device and computer (method 4) or a rooted Android phone (method 3) to follow
> this guide.
---
@@ -204,11 +205,24 @@ This uses the tool [Aegis Authenticator](https://getaegis.app/) from
## Method 4: Authy-iOS-MiTM
**Who should use this?** Technical iOS users of Authy that cannot export their tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due to that method requiring a rooted Android device).
**Who should use this?** Technical iOS users of Authy that cannot export their
tokens with methods 1 or 2 (due to those methods being patched) or method 3 (due
to that method requiring a rooted Android device).
This method works by intercepting the data the Authy app receives while logging in for the first time, which contains your encrypted authenticator tokens. After the encrypted authenticator tokens are dumped, you can decrypt them using your backup password and convert them to an Ente token file.
This method works by intercepting the data the Authy app receives while logging
in for the first time, which contains your encrypted authenticator tokens. After
the encrypted authenticator tokens are dumped, you can decrypt them using your
backup password and convert them to an Ente token file.
For an up-to-date guide of how to retrieve the encrypted authenticator tokens and decrypt them, please see [Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the `decrypted_tokens.json` file from that guide into a format Ente Authenticator can recognize, use [this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087) Python script. Once you have the `ente_auth_import.plain` file from that script, transfer it to your device and follow the instructions below to import it into Ente Authenticator.
For an up-to-date guide of how to retrieve the encrypted authenticator tokens
and decrypt them, please see
[Authy-iOS-MiTM](https://github.com/AlexTech01/Authy-iOS-MiTM). To convert the
`decrypted_tokens.json` file from that guide into a format Ente Authenticator
can recognize, use
[this](https://gist.github.com/gboudreau/94bb0c11a6209c82418d01a59d958c93?permalink_comment_id=5317087#gistcomment-5317087)
Python script. Once you have the `ente_auth_import.plain` file from that script,
transfer it to your device and follow the instructions below to import it into
Ente Authenticator.
## Importing to Ente Authenticator (Method 1, method 2.1, method 4)

View File

@@ -10,4 +10,4 @@ Ende-zu-Ende-verschlüsselte Authenticator-App für jedermann. Wir sind froh, da
du hier bist!
**Please note that this German translation is currently just a placeholder.**
Know German? [Help us fill this in!](/about/contribute).
Know German? [Help us fill this in!](/overview/contribute).

View File

@@ -11,5 +11,5 @@ Use the **sidebar** menu to navigate to information about the product (Photos or
Auth) you'd like to know more about. Or use the **search** at the top to try and
jump directly to page that might contain the information you need.
To know more about Ente, see [about](/about/) or visit our website
To know more about Ente, see [overview](/overview/) or visit our website
[ente.io](https://ente.io).

View File

@@ -0,0 +1,20 @@
---
title: Community
description: >
Information regarding Ente's community channels
---
# Community
## Blog
To stay up to date with new product launches, and behind the scenes details of
how we're building Ente, you can read our [blog](https://ente.io/blog) (or
subscribe to it via [RSS](https://ente.io/blog/rss.xml))
## Community
Or if you'd just like to hang out, join our
[Discord](https://discord.gg/z2YVKkycX3), follow us on
[Twitter](https://twitter.com/enteio) or give us a shout out on
[Mastodon](https://mstdn.social/@ente)

View File

@@ -1,10 +1,18 @@
---
title: Contribute
description: Details about how to contribute to Ente's docs
description: Details about how to contribute to Ente
---
# Contributing
## Suggest a feature
To suggest new features and/or offer your perspective on how we should design
(planned and upcoming features), use our
[GitHub discussions](https://github.com/ente-io/ente/discussions)
## Documentation
To contribute to these docs, you can use the "Edit this page" button at the
bottom of each page. This will allow you to directly edit the markdown file that
is used to generate this documentation and open a quick pull request directly

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

@@ -0,0 +1,13 @@
---
title: Help
description: Get help from Ente via customer support and community
---
# Help
If you encounter any issues with any of the products that's not answered by our
[documentation](/), please reach out to our Customer Support by sending an email
to [support@ente.io](mailto:support@ente.io)
For community support, please post your queries on
[Discord](https://discord.gg/z2YVKkycX3)

View File

@@ -1,5 +1,5 @@
---
title: About Ente
title: Introduction
description: >
An overview of Ente: the company, and the people behind it, and the products
that we make.
@@ -7,17 +7,17 @@ description: >
# About
Ente is a end-to-end encrypted platform for privately, reliably, and securely
storing your data on the cloud. On top of this platform, Ente offers two
products:
Ente (pronounced en-_tay_. Like ca<i>fe</i>) is a end-to-end encrypted platform
for privately, reliably, and securely storing your data on the cloud. On top of
this platform, Ente offers two products:
- **Ente Photos** - An alternative to Google Photos and Apple Photos
- **Ente Auth** - A free 2FA alternative to Authy
Both these apps are available for all desktop (Linux, Mac, Windows) and mobile
(Android, iOS and F-Droid) platforms. They also work directly in your web
browser without you needing to install anything.
(Android and iOS) platforms. They also work directly in your web browser without
you needing to install anything.
More products are in the pipeline.
@@ -48,25 +48,3 @@ the name, and also led to the adoption of "Ducky", Ente's mascot:
For the full origin story of Ducky you can check out
[this blog post](https://ente.io/blog/ducky/).
### How do I pronounce Ente?
en-_tay_. Like ca<i>fe</i>.
## Get in touch
If you have a support query that is not answered by these docs, please reach out
to our Customer Support by sending an email to support@ente.io
To stay up to date with new product launches, and behind the scenes details of
how we're building Ente, you can read our [blog](https://ente.io/blog) (or
subscribe to it via [RSS](https://ente.io/blog/rss.xml))
To suggest new features and/or offer your perspective on how we should design
planned and upcoming features, use our
[GitHub discussions](https://github.com/ente-io/ente/discussions)
Or if you'd just like to hang out, join our
[Discord](https://discord.gg/z2YVKkycX3), follow us on
[Twitter](https://twitter.com/enteio) or give us a shout out on
[Mastodon](https://mstdn.social/@ente)

View File

@@ -1,6 +1,7 @@
---
title: Desktop app FAQ
description: An assortment of frequently asked questions about Ente Photos desktop app
description:
An assortment of frequently asked questions about Ente Photos desktop app
---
# Desktop app FAQ
@@ -15,7 +16,8 @@ to manually update the software.
### Upload errors
**How do I identify which files experienced upload issues within the desktop app?**
**How do I identify which files experienced upload issues within the desktop
app?**
Check the sections within the upload progress bar for "Failed Uploads," "Ignored
Uploads," and "Unsuccessful Uploads."
@@ -33,6 +35,5 @@ be specific to your distro (e.g. `xdg-desktop-menu forceupdate`).
> [!NOTE]
>
> If you're using an AppImage and not seeing the icon, you'll need to [enable
> AppImage desktop
> integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration).
> If you're using an AppImage and not seeing the icon, you'll need to
> [enable AppImage desktop integration](/photos/troubleshooting/desktop-install/#appimage-desktop-integration).

View File

@@ -7,9 +7,10 @@ description: Frequently asked questions about keeping extra backups of your data
## How can I backup my data in a local drive outside Ente?
You can use our CLI tool or our desktop app to set up exports of your data
to your local drive. This way, you can use Ente in your day to day use, with an additional guarantee that a copy of your original photos and videos are
always available on your machine.
You can use our CLI tool or our desktop app to set up exports of your data to
your local drive. This way, you can use Ente in your day to day use, with an
additional guarantee that a copy of your original photos and videos are always
available on your machine.
- You can use [Ente's CLI](https://github.com/ente-io/ente/tree/main/cli#export)
to export your data in a cron job to a location of your choice. The exports
@@ -21,7 +22,7 @@ always available on your machine.
background without you needing to run any other cron jobs. See
[migration/export](/photos/migration/export/) for more details.
## Does the exported data preserve folder structure?
## Does the exported data preserve album structure?
Yes. When you export your data for local backup, it will maintain the exact
album structure how you have set up within Ente.

View File

@@ -1,7 +1,6 @@
---
title: Face recognition
description:
Frequently asked questions about Ente's face recognition
description: Frequently asked questions about Ente's face recognition
---
# Face recognition

View File

@@ -26,10 +26,6 @@ unsupported file format and we will do our best to help you out.
Yes, we currently do not support files larger than 4 GB.
If this constraint is a concern for you, please write to
[support@ente.io](mailto:support@ente.io) with your use case and we will do our
best to help you.
## Does Ente support videos?
Ente supports backing up and downloading of videos in their original format and
@@ -104,29 +100,53 @@ clicking on "Your map" under "Locations" on the search screen.
## How to reset my password if I lost it?
On the login page, enter your email and click on Forgot Password. Then, enter your recovery key and create a new password.
On the login page, enter your email and click on Forgot Password. Then, enter
your recovery key and create a new password.
# iOS Album Backup and Organization in Ente
## Can I search for photos using the descriptions Ive added?
### How does Ente handle photos that are part of multiple iOS albums?
When you select multiple albums for backup, Ente prioritizes uploading each photo to the album with the fewest photos. This means a photo will only be uploaded once, even if it exists in multiple albums on your device. If you create new albums on your device after the initial backup, those photos may not appear in the corresponding Ente album if they were already uploaded to a different album.
Yes, descriptions are searchable, making it easier to find specific photos
later. To do this, open the photo, tap the (i) button, and enter your
description.
## How does the deduplication feature work on the desktop app?
### Why dont all photos from a new iOS album appear in the corresponding Ente album?
If you create a new album on your device after the initial backup, the photos in that album may have already been uploaded to another album in Ente. To fix this, go to the "On Device" album in Ente, select all photos, and manually add them to the corresponding album in Ente.
If the app finds exact duplicates, it will show them in the deduplication. When
you delete a duplicate, the app keeps one copy and creates a symlink for the
other duplicate. This helps save storage space.
### What happens if I reorganize my photos in the iOS Photos app after backing up?
Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums) wont automatically reflect in Ente. Youll need to manually add those photos to the corresponding albums in Ente to maintain consistency.
## What happens if I lose access to my email address? Can I use my recovery key to bypass email verification?
### Can I search for photos using the descriptions Ive added?
Yes, descriptions are searchable, making it easier to find specific photos later.
To do this, open the photo, tap the (i) button, and enter your description.
### How does the deduplication feature work on the desktop app?
If the app finds exact duplicates, it will show them in the deduplication. When you delete a duplicate, the app keeps one copy and creates a symlink for the other duplicate. This helps save storage space.
### What happens if I lose access to my email address? Can I use my recovery key to bypass email verification?
No, the recovery key does not bypass email verification. For security reasons, we do not disable or bypass email verification unless the account owner reaches out to us and successfully verifies their identity by providing details about their account.
No, the recovery key does not bypass email verification. For security reasons,
we do not disable or bypass email verification unless the account owner reaches
out to us and successfully verifies their identity by providing details about
their account.
If you lose access to your email, please contact our support team at
support@ente.io
---
# iOS Album Backup and Organization in Ente
## How does Ente handle photos that are part of multiple iOS albums?
When you select multiple albums for backup, Ente prioritizes uploading each
photo to the album with the fewest photos. This means a photo will only be
uploaded once, even if it exists in multiple albums on your device. If you
create new albums on your device after the initial backup, those photos may not
appear in the corresponding Ente album if they were already uploaded to a
different album.
## Why dont all photos from a new iOS album appear in the corresponding Ente album?
If you create a new album on your device after the initial backup, the photos in
that album may have already been uploaded to another album in Ente. To fix this,
go to the "On Device" album in Ente, select all photos, and manually add them to
the corresponding album in Ente.
## What happens if I reorganize my photos in the iOS Photos app after backing up?
Reorganizing photos in the iOS Photos app (e.g., moving photos to new albums)
wont automatically reflect in Ente. Youll need to manually add those photos to
the corresponding albums in Ente to maintain consistency.

View File

@@ -62,6 +62,7 @@ the upload time as the photo's creation time.
## Modifications
Ente supports modifications to the following metadata:
- File name
- Date & time
- Location

View File

@@ -1,29 +1,49 @@
---
title: Video streaming FAQ
description:
Frequently asked questions about Ente's video streaming feature
description: Frequently asked questions about Ente's video streaming feature
---
# Video streaming
> [!NOTE]
>
> Video streaming is available in beta on mobile apps starting v0.9.98.
> Video streaming is available in beta on mobile apps starting v0.9.98 and on
> desktop starting v1.7.13.
### How to enable video streaming?
#### On mobile
- Open Settings -> General -> Advanced
- Switch on the toggle for `Video streaming`
- Enable the toggle for `Streamable videos`
#### On desktop
- Open Settings -> Preferences
- Enable the toggle for `Streamable videos`
### What happens when I enable video streaming?
#### On mobile
Enabling video streaming will start processing videos captured in the last 30
days, generating streams for each. Both local and remote videos will be
processed, so this may consume bandwidth for downloading of remote files and
uploading of the generated streams.
#### On desktop
When enabled, the desktop app will generate streams both for new uploads, and
also for all existing videos that were previously uploaded.
Stream generation is CPU intensive and can take time so the app will continue
processing them in the background. Clicking on search bar will show "Processing
videos..." when stream generation is happening.
### How can I view video streams?
### On mobile
Settings -> Backup > Backup status will show details regarding the processing
status for videos. Processed videos will have a green play button next to them.
You can open these videos by tapping on them.
@@ -34,6 +54,12 @@ play the stream.
Clicking on the `Info` icon within the original video will show details about
the generated stream.
### On desktop and web
Desktop and web app will automatically play the streaming version of a video if
it has been already generated. The quality selector will show "Auto" when
playing the stream.
### What is a stream?
Stream is an encrypted HLS file with an `.m3u8` playlist that helps play a video
@@ -51,6 +77,7 @@ generated stream.
While this feature is in beta, we will not count the storage consumed by your
streams against your storage quota. This may change in the future. If it does,
we will provide an option to opt-in to one of the following:
1. Original videos only
2. Compressed streams only
3. Both

View File

@@ -43,8 +43,8 @@ need to disable this "Optimize battery usage" mode in the system settings for
Ente if you wish for Ente to automatically back up your photos in the
background.
On Android versions 15 and later, if an app is in private space and the private
space is locked, Android doesnt allow the app to run any background processes.
On Android versions 15 and later, if an app is in private space and the private
space is locked, Android doesnt allow the app to run any background processes.
As a result, background sync will not work.
### Desktop

View File

@@ -52,6 +52,11 @@ Ente also provides a tool for manual de-duplication in _Settings → Backup →
Remove duplicates_. This is useful if you have an existing library with
duplicates across different albums, but wish to keep only one copy.
During this operation, Ente will discard duplicates across all albums, retain a
single copy, and add symlinks to this copy within all existing albums. So your
existing album structure remains unchanged, while the space consumed by the
duplicate data is freed up.
## Adding to Ente album creates symlinks
Note that once a file is in Ente, adding it to another Ente album will create a

View File

@@ -24,19 +24,19 @@ In brief,
## Storage Limits
If you're an admin of a family, you will be able to set storage limits for the
If you're an admin of a family, you will be able to set storage limits for the
members in your family plan.
In brief,
In brief,
- For example, once you set a limit of 10GB for a member, their Storage
quota for uploading photos will be limited to 10GB.
- For example, once you set a limit of 10GB for a member, their Storage quota
for uploading photos will be limited to 10GB.
- Once the invited member accepts the Family invite, you will be able to see
an edit icon in the Members List. Click on it to setup a family limit.
- Once the invited member accepts the Family invite, you will be able to see an
edit icon in the Members List. Click on it to setup a family limit.
- If the admin has set a limit for any user, that limit value will be prefilled
in the input box.
in the input box.
- If you want to remove any storage limit from a members account, you
can click on the "Remove Limit" and they can upload photos without any limit.
- If you want to remove any storage limit from a members account, you can click
on the "Remove Limit" and they can upload photos without any limit.

View File

@@ -14,9 +14,21 @@ directly stream chunks of Google Takeout zips that are stored on network drives.
In particular, the folder watch functionality suffers a lot since the app needs
access to file system events to detect changes to the users files so that they
can be uploaded whenever there are changes.
can be uploaded whenever there are changes. Network drives are less reliable in
providing these file change events correctly.
Since are high chances of the user having a subpar experience, we request
customers to avoid using the desktop app directly with network attached storage
and instead temporarily copy the files to their local storage for uploads, and
avoid watching folders that live on a network drive.
## Exporting to UNC paths
Generally, exports are likely to work better than imports, since the interaction
with the file system is relatively simpler (Note that the app still needs to
scan the folder to find existing files, esp. if the continuous export option is
enabled).
A special case is when exporting to a UNC path. In this case, the file
separators will not work as expected and the export will not start. As a
workaround, you can map your UNC path to a network drive and use that instead.

View File

@@ -3,7 +3,7 @@ title: Creating accounts
description: Creating accounts on your deployment
---
# Creating accounts
# Creating accounts
Once Ente is up and running, the Ente Photos web app will be accessible on
`http://localhost:3000`. Open this URL in your browser and proceed with creating
@@ -20,7 +20,7 @@ This code can be found in the server logs, which should already be shown in your
quickstart terminal. Alternatively, you can open the server logs with the
following command from inside the `my-ente` folder:
```sh
```sh
sudo docker compose logs
```

View File

@@ -0,0 +1,52 @@
---
title: "Environment Variables and Ports"
description:
"Information about all the Environment Variables needed to run Ente"
---
# Environment variables and ports
A self-hosted Ente instance requires specific endpoints in both Museum (the
server) and web apps. This document outlines the essential environment variables
and port mappings of the web apps.
Here's the list of important variables that a self hoster should know about:
### Museum
1. `NEXT_PUBLIC_ENTE_ENDPOINT`
The above environment variable is used to configure Museums endpoint. Where
Museum is running and which port it is listening on. This endpoint should be
configured for all the apps to connect to your self hosted endpoint.
All the apps (regardless of platform) by default connect to api.ente.io - which
is our production instance of Museum.
### Web Apps
> [!IMPORTANT] Web apps don't need to be configured with the below endpoints.
> Web app environment variables are being documented here just so that the users
> know everything in detail. Checkout
> [Configuring your Server](/self-hosting/museum) to configure endpoints for
> particular app.
In Ente, all the web apps are separate NextJS applications. Therefore, they are
all configured via environment variables. The photos app (Ente Photos) has
information about and connects to other web apps like albums, cast, etc.
1. `NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT`
This environment variable is used to configure and declare the endpoint for the
Albums web app.
## Ports
The below format is according to how ports are mapped in Docker.
Typically,`<host>:<container-port>`
1. `8080:8080`: Museum (Ente's server)
2. `3000:3000`: Ente Photos web app
3. `3001:3001`: Ente Accounts web app
4. `3003:3003`: [Ente Auth web app](https://ente.io/auth/)
5. `3004:3004`: [Ente Cast web app](http://ente.io/cast)

View File

@@ -2,39 +2,63 @@
title: Self Hosting with Tailscale (Community)
description: Guides for self-hosting Ente Photos and/or Ente Auth with Tailscale
---
# Guide
This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale (TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot open any port on the internet but want to run their own selfhosted service for themselves, friends and family only.
This guide aims to achieve self-hosting Ente photos or Ente-Auth with tailscale
(TSDPROXY) without exposing any port OR if someone is behind CGNAT and cannot
open any port on the internet but want to run their own selfhosted service for
themselves, friends and family only.
Before getting start keep the following NOTE in mind.
> [!NOTE]
> If someone is behind double or triple CGNAT; must install tailscale system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in your linux terminal and `sudo tailscale up` otherwise dns resolver will fail and uploading will not work. This is not necessary for those who are not behing CGNAT.
> This guide also work on docker rootless and normal.
> [!NOTE] If someone is behind double or triple CGNAT; must install tailscale
> system wide by running `curl -fsSL https://tailscale.com/install.sh | sh` in
> your linux terminal and `sudo tailscale up` otherwise dns resolver will fail
> and uploading will not work. This is not necessary for those who are not
> behing CGNAT. This guide also work on docker rootless and normal.
> [!CAUTION]
Remember that current docker update 28.0.0 has some bug and cannot connect to external network. Make sure to install docker-ce 27.5.0, docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker 28.1.0 will resolve this issue in next week. Refrence links are [Moby Github Repo Issues 49511](https://github.com/moby/moby/issues/49511) and [Moby Github Repo Issues 49519](https://github.com/moby/moby/issues/49519)
> [!CAUTION] Remember that current docker update 28.0.0 has some bug and cannot
> connect to external network. Make sure to install docker-ce 27.5.0,
> docker-ce-rootless-extras 27.5.0 and docker-ce-cli 27.5.0. Hopefully docker
> 28.1.0 will resolve this issue in next week. Refrence links are
> [Moby Github Repo Issues 49511](https://github.com/moby/moby/issues/49511) and
> [Moby Github Repo Issues 49519](https://github.com/moby/moby/issues/49519)
> [!IMPORTANT]
> For Docker rootless, the user must have local permissions for all directories required by the Ente-photos self-hosted server. This can be achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the Linux terminal, you can check the UID with `id -u` or simply `id`. The first user typically has UID 1000.
> To allow listening and pinging on any port without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf` with the following content:
> [!IMPORTANT] For Docker rootless, the user must have local permissions for all
> directories required by the Ente-photos self-hosted server. This can be
> achieved by running `sudo chown -R 1000:1000 /home/ubuntu/docker/ente`. In the
> Linux terminal, you can check the UID with `id -u` or simply `id`. The first
> user typically has UID 1000. To allow listening and pinging on any port
> without root privileges, create a file called `/etc/sysctl.d/99-rootless.conf`
> with the following content:
>
> ```
> net.ipv4.ip_unprivileged_port_start=0
> net.ipv4.ping_group_range = 0 2147483647
> ```
> than run `sudo sysctl --system`.
> Create `~/.config/systemd/user/docker.service.d/override.conf` with the following content:
>
> than run `sudo sysctl --system`. Create
> `~/.config/systemd/user/docker.service.d/override.conf` with the following
> content:
>
> ```
> [Service]
> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_NET=slirp4netns"
> Environment="DOCKERD_ROOTLESS_ROOTLESSKIT_PORT_DRIVER=slirp4netns"
> ```
> and Restart the docker daemon
> `systemctl --user restart docker`
> Instead of `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml, use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock`
>
> and Restart the docker daemon `systemctl --user restart docker` Instead of
> `--volume /var/run/docker.sock:/var/run/docker.sock` in TSDPROXY compose.yaml,
> use `--volume $XDG_RUNTIME_DIR/docker.sock:/var/run/docker.sock`
## GETTING START WITH SETUP
First of all create a directory
`sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy`
and create compose.yaml file by running `sudo nano compose.yaml`. Populate it
with the following:
## GETTING START WITH SETUP ##
First of all create a directory `sudo mkdir -p /home/ubuntu/docker/tsdproxy/config` than `cd docker/tsdproxy` and create compose.yaml file by running `sudo nano compose.yaml`. Populate it with the following:
```
services:
tsdproxy:
@@ -62,9 +86,18 @@ networks:
proxy:
name: proxy
```
Now login into your tailscale account admin counsle > settings > keys > Generate authkey. Give any description and must select resuable, because the key get purged if not selected after rebooting machine. It is advisable to create **Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well. This will create a tag nodes with no key expirory. One is safe to reboot restart docker or machine.
> Copy the generated authkey as it is shown only once.
Make tsdproxy.yaml file in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and pupolate it with the following contant:
Now login into your tailscale account admin counsle > settings > keys > Generate
authkey. Give any description and must select resuable, because the key get
purged if not selected after rebooting machine. It is advisable to create
**Tags** in **ACLs settings** `tag: tsdproxy` `tag: ente` `tag: minio` as well.
This will create a tag nodes with no key expirory. One is safe to reboot restart
docker or machine.
> Copy the generated authkey as it is shown only once. Make tsdproxy.yaml file
> in `cd docker/tsdproxy/config` by running `sudo nano tsdproxy.yaml` and
> pupolate it with the following contant:
```
defaultproxyprovider: default
docker:
@@ -87,12 +120,20 @@ log:
json: false
proxyaccesslog: true
```
In the same directory run `sudo nano authkey` and paste the authkey just copied earlier from tailscale admin counsel.
> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run `docker compose up -d`. Check your tailscale amdin counsel and you will see tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale DNS settings.
> You can visit the TSDPROXY web GUI by https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
## ente Part ##
In the same directory run `sudo nano authkey` and paste the authkey just copied
earlier from tailscale admin counsel.
> Here Tailscale (TSDPROXY) setup is complet in all respect. Just run
> `docker compose up -d`. Check your tailscale amdin counsel and you will see
> tsdproxy node up and running. Make sure that **HTTPS** is enabled in tailscale
> DNS settings. You can visit the TSDPROXY web GUI by
> https://tsdproxy.xyz.ts.net. (xyz is change value for everyone)
## ente Part
First make the following necessary files/directories:
```
sudo mkdir -p /home/ubuntu/docker/ente/custom-logs
sudo mkdir -p /home/ubuntu/docker/ente/data
@@ -100,9 +141,14 @@ sudo mkdir -p /home/ubuntu/docker/ente/minio-data
sudo mkdir -p /home/ubuntu/docker/ente/postgres-data
sudo mkdir -p /home/ubuntu/docker/ente/scripts/compose
```
Than give user permission for each of the above directory. `sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make sure not to skip `/home/ubuntu/docker/tsdproxy/config`
`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than populate it with the following:
Than give user permission for each of the above directory.
`sudo chown -R 1000:1000 /home/ubuntu/docker/ente/custom-logs` etc etc. Make
sure not to skip `/home/ubuntu/docker/tsdproxy/config`
`cd docker/ente/script/compose` and run `sudo nano credentials.yaml` than
populate it with the following:
```
db:
host: postgres
@@ -134,7 +180,9 @@ s3:
bucket: scw-eu-fr-v3
```
In the same directory run `sudo nano minio-provision.sh` and populate it with the following contant:
In the same directory run `sudo nano minio-provision.sh` and populate it with
the following contant:
```
#!/bin/sh
@@ -154,7 +202,9 @@ mc mb -p wasabi-eu-central-2-v3
mc mb -p scw-eu-fr-v3
```
Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it with the following:
Now `cd docker/ente` and run `sudo nano docker-compose.yaml` and populate it
with the following:
```
services:
museum:
@@ -255,32 +305,52 @@ services:
networks:
ente:
name: ente
proxy:
external: true
```
> Thats it. Run `docker compose up -d`. Wait till every container become healthy. Open web browser. Make sure tailscale is installed on the machine. Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it. First time it will take minute or two to get SSL cert. Downnload Desktop or mobile app. Tap 7 time on the screen, which will prompt developer mode. Add https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the six digit and Done.
> Thats it. Run `docker compose up -d`. Wait till every container become
> healthy. Open web browser. Make sure tailscale is installed on the machine.
> Visit https://ente.xyz.ts.net/ping. It will pong. All good if you see it.
> First time it will take minute or two to get SSL cert. Downnload Desktop or
> mobile app. Tap 7 time on the screen, which will prompt developer mode. Add
> https://ente.xyz.ts.net. Add new user. When asked for OTP. Just go to linux
> terminal and run `docker logs ente-museum-1`. Search for userauth. Feed the
> six digit and Done.
> For getting 100TB (limitless) storage. Just Install ente-cli for windows.
> Extract it and add folder. Name it **export**. Add config.yaml file along and
> populate it with the following:
> For getting 100TB (limitless) storage. Just Install ente-cli for windows. Extract it and add folder. Name it **export**. Add config.yaml file along and populate it with the following:
```
endpoint:
api: "https://ente.xyz.ts.net"
accounts: "http://localhost:3001"
log: false
```
Right-Click in the directory where you have extracted ente-cli. Select `open in terminal`. Run
Right-Click in the directory where you have extracted ente-cli. Select
`open in terminal`. Run
```
.\ente.exe account bob # change bob to yours
```
Hit Enter twice.
For export directory, just write export. As already created **export** folder earlier.
**Write email. The one which is already used befor when creating ente account in ente desktop app.**
Type the same Password used before for the account.Run
Hit Enter twice. For export directory, just write export. As already created
**export** folder earlier. **Write email. The one which is already used befor
when creating ente account in ente desktop app.** Type the same Password used
before for the account.Run
```
.\ente.ext account list
```
This will list all account details. Copy Acount ID.
> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml` and add the account ID under Admins. Delete any previous entries.
Restart ente-museum-1 container from linux terminal. Run `docker restart ente-museum-1`. All well, now you will have 100TB storage. Repeat if for any other accounts you want to give unlimited storage access.
> Navigate to museum.yaml file. `cd docker/ente`. Run `sudo nano museum.yaml`
> and add the account ID under Admins. Delete any previous entries. Restart
> ente-museum-1 container from linux terminal. Run
> `docker restart ente-museum-1`. All well, now you will have 100TB storage.
> Repeat if for any other accounts you want to give unlimited storage access.

View File

@@ -3,32 +3,6 @@ title: Server admin
description: Administering your custom self-hosted Ente instance using the CLI
---
# Administering your custom server
You can use
[Ente's CLI](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0) to
administer your self hosted server.
First we need to get your CLI to connect to your custom server. Define a
config.yaml and put it either in the same directory as CLI or path defined in
env variable `ENTE_CLI_CONFIG_PATH`
```yaml
endpoint:
api: "http://localhost:8080"
```
Now you should be able to
[add an account](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_add.md),
and subsequently increase the
[storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md)
using the CLI.
> [!NOTE]
>
> The CLI command to add an account does not create Ente accounts. It only adds
> existing accounts to the list of (existing) accounts that the CLI can use.
## Becoming an admin
By default, the first user (and only the first user) created on the system is
@@ -78,6 +52,37 @@ You can use
[account list](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_list.md)
command to find the user id of any account.
# Administering your custom server
> [!NOTE] For the first user (admin) to perform administrative actions using the
> CLI, their userID must be whitelisted in the `museum.yaml` configuration file
> under `internal.admins`. While the first user is automatically granted admin
> privileges on the server, this additional step is required for CLI operations.
You can use
[Ente's CLI](https://github.com/ente-io/ente/releases?q=tag%3Acli-v0) to
administer your self hosted server.
First we need to get your CLI to connect to your custom server. Define a
config.yaml and put it either in the same directory as CLI or path defined in
env variable `ENTE_CLI_CONFIG_PATH`
```yaml
endpoint:
api: "http://localhost:8080"
```
Now you should be able to
[add an account](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_account_add.md),
and subsequently increase the
[storage and account validity](https://github.com/ente-io/ente/blob/main/cli/docs/generated/ente_admin_update-subscription.md)
using the CLI.
> [!NOTE]
>
> The CLI command to add an account does not create Ente accounts. It only adds
> existing accounts to the list of (existing) accounts that the CLI can use.
## Backups
See this [FAQ](/self-hosting/faq/backup).

View File

@@ -29,7 +29,7 @@ A file upload flows as follows:
The upshot of this is that _both_ the client and museum should be able to reach
your S3 bucket.
## Configuring S3
## Configuring S3
The URL for the S3 bucket is configured in
[scripts/compose/credentials.yaml](https://github.com/ente-io/ente/blob/main/server/scripts/compose/credentials.yaml#L10).
@@ -38,9 +38,8 @@ You can edit this file directly while testing, though it is more robust to
create a `museum.yaml` (in the same folder as the Docker compose file) and to
setup your custom configuration there.
> [!TIP]
> For more details about these configuration objects, see the documentation for
> the `s3` object in
> [!TIP] For more details about these configuration objects, see the
> documentation for the `s3` object in
> [configurations/local.yaml](https://github.com/ente-io/ente/blob/main/server/configurations/local.yaml).
By default, you only need to configure the endpoint for the first bucket.
@@ -56,13 +55,14 @@ components of the setup to communicate with each other seamlessly.
The same principle applies if you're deploying to your custom domain.
## Replication
## Replication
![Replication](/replication.png)
<p align="center">Community contributed diagram of Ente's replication process</p>
> [!IMPORTANT]
>
>
> As of now, replication works only if all the 3 storage type needs are
> fulfilled (1 hot, 1 cold and 1 glacier storage).
>
@@ -72,10 +72,10 @@ If you're wondering why there are 3 buckets on the MinIO UI - that's because our
production instance uses these to perform
[replication](https://ente.io/reliability/).
If you're also wondering about why the bucket names are specifically what they are,
it's because that is exactly what we are using on our production instance.
We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary hot)
and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded.
If you're also wondering about why the bucket names are specifically what they
are, it's because that is exactly what we are using on our production instance.
We use `b2-eu-cen` as hot, `wasabi-eu-central-2-v3` as cold (also the secondary
hot) and `scw-eu-fr-v3` as glacier storage. As of now, all of this is hardcoded.
Hence, the same hardcoded configuration is applied when you self host Ente.
In a self hosted Ente instance replication is turned off by default. When
@@ -84,16 +84,15 @@ other two are ignored. Only the names here are specifically fixed, but in the
configuration body you can put any other keys. It does not have any relation
with `b2`, `wasabi` or even `scaleway`.
Use the `s3.hot_storage.primary` option if you'd like to set one of the other
Use the `s3.hot_storage.primary` option if you'd like to set one of the other
predefined buckets as the primary bucket.
## SSL Configuration
## SSL Configuration
> [!NOTE]
>
> If you need to configure SSL, you'll need to turn off `s3.are_local_buckets`
> (which disables SSL in the default starter compose template).
>
Disabling `s3.are_local_buckets` also switches to the subdomain style URLs for
the buckets. However, not all S3 providers support these. In particular, MinIO
@@ -121,4 +120,4 @@ s3:
endpoint: http://<YOUR-WIFI-IP>:3200
region: eu-central-2
bucket: b2-eu-cen
```
```

Some files were not shown because too many files have changed in this diff Show More