mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
fix(core,fuse,gui,cli): read only the photos a refresh has not read
A timeline refresh resolved every photo's node to learn its name, media type, favourite tag, content hash and photo relation — 63 round-trips for a 12,445-photo library, minutes of work, repeated every time the timeline went stale sixty seconds later. None of that metadata changes on its own, and when it does change the event feed names the node it changed. `photos.resolved_at` (schema v31) records that a photo's node was read. The refresh resolves the photos without that mark: the ones it has never read, and the ones a remote event marked stale. An existing timeline is backfilled as resolved, so upgrading does not re-read the library once. Remote changes now name what they changed instead of asking for everything. `classify_photo_events` turns a `NodeUpdated` into `photos_mark_unresolved(uid)`, so a favourite toggled on a phone costs one node read rather than the whole library; a local toggle is claimed as our own echo, because the feed replays it and a `NodeUpdated` carries nothing that says what changed. A continuity loss and `refresh photos --full` drop every mark, which is the way back to a whole-library read. Along the way: `photos_replace` never kept a photo's name, so a photo the SDK could not decrypt was renamed to nothing on every refresh — and the tab split and the RAW+JPEG grouping are both derived from the name. It is kept now, and a row that *was* resolved is authoritative instead, so a photo unlinked from its main elsewhere finally loses its `main_uid`. `TIMELINE_ENRICH_CHUNK` is 150, matching the SDK's own `MAX_BATCH_COUNT`: a chunk of 200 was split there into a full request and a 50-uid tail.
This commit is contained in:
1 parent
376f3edb28
commit
6cc8f72bab
12 files changed
+634
-69
No files matched your search
@@ -310,6 +310,11 @@ enum Command {
|
||||
/// What to refresh: a folder path (inside the mountpoint or relative to
|
||||
/// it), `trash`, or `photos`. The mount root if omitted.
|
||||
target: Option<String>,
|
||||
/// With `photos`: read every photo's metadata again instead of only what
|
||||
/// changed. Minutes on a large library; for a gallery that disagrees with
|
||||
/// the account.
|
||||
#[arg(long)]
|
||||
full: bool,
|
||||
},
|
||||
|
||||
/// Manage the account's registered devices.
|
||||
@@ -683,7 +688,7 @@ fn main() -> Result<()> {
|
||||
Command::Restore { uids } => cmd_restore(uids),
|
||||
Command::DeleteForever { uids } => cmd_delete_forever(uids),
|
||||
Command::EmptyTrash => cmd_empty_trash(),
|
||||
Command::Refresh { target } => cmd_refresh(target),
|
||||
Command::Refresh { target, full } => cmd_refresh(target, full),
|
||||
Command::Devices { action } => cmd_devices(action),
|
||||
Command::Sync { action } => cmd_sync(action),
|
||||
Command::Share {
|
||||
@@ -2269,15 +2274,15 @@ fn cmd_empty_trash() -> Result<()> {
|
||||
/// Drop a cached listing. `trash` and `photos` name those two listings; anything
|
||||
/// else is read as a folder path, so a folder actually called "trash" is still
|
||||
/// reachable as `./trash`.
|
||||
fn cmd_refresh(target: Option<String>) -> Result<()> {
|
||||
fn cmd_refresh(target: Option<String>, full: bool) -> Result<()> {
|
||||
let scope = match target.as_deref() {
|
||||
Some("trash") => RefreshScope::Trash,
|
||||
Some("photos") => RefreshScope::Photos,
|
||||
Some("photos") => RefreshScope::Photos { full },
|
||||
path => RefreshScope::Dir {
|
||||
path: path.unwrap_or("").to_string(),
|
||||
},
|
||||
};
|
||||
let photos = scope == RefreshScope::Photos;
|
||||
let photos = matches!(scope, RefreshScope::Photos { .. });
|
||||
match control_request(CtlRequest::Refresh { scope })? {
|
||||
CtlResponse::Ok { message } => println!("{message}"),
|
||||
CtlResponse::Error { message, kind } => bail!("{}", cli_error(kind, &message)),
|
||||
|
||||
Reference in new issue
Block a user