iCloud files download on demand, then go back to the cloud - #33
Merged
Conversation
…ources are pulled in on a cancellable thread with a size-scaled deadline, then evicted back to cloud-only once their audio is extracted (only ones this run downloaded — 82 lecture videos cost one file of disk, not 12.8 GB), detection moves from st_blocks to the UF_DATALESS flag because an APFS-compressed local file also reports zero blocks, and failures finally render through the ScriptoError key/params the catalogs were always written for.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reported from a run over a folder of lecture recordings in iCloud Drive: every file failed with
extract: ... looks like an iCloud placeholder that is not downloaded locally. In Finder, right-click it and choose "Download Now".What was actually happening
check_readable()refused any file whosest_blockswas 0 and told the user to go download it by hand. But macOS materializes a dataless file on read — the kernel asks the file provider for the bytes the moment anything opens it. Nothing was stopping these files except our own pre-flight check.Verified on a real iCloud file: a one-byte read took 2.43s and the
datalessflag was gone afterwards.Download, use, put back
access.materialize()triggers the download with a single read. That read blocks for the whole transfer (minutes for a 138 MB recording), so it runs on a thread while the caller polls the file growing, stays responsive to the stop button, and gives up on a size-scaled deadline (120s floor + 12s/MB) instead of hanging forever with no network.access.evict()returns the file to cloud-only afterwards — Finder's "Remove Download".brctl evictandfileproviderctlno longer have that subcommand on current macOS, so the only supported route isNSFileManager.evictUbiquitousItemAtURL:, reached through the Objective-C runtime with ctypes rather than by taking a PyObjC dependency for one selector. It returns False rather than raising: failing to tidy up is never worth failing a job.finally, so a failed or errored job doesn't leave a download behind.On the reported folder: 82 videos, 81 of them in the cloud, 12.8 GB total. Peak disk cost is now one file (~150 MB) instead of 12.8 GB.
Full round trip against a real iCloud file:
dataless=True → download (1.46s) → readable → evict → dataless=True.A false positive worth fixing
Those files stat as
flags=compressed,dataless— two flags. A fully-downloaded but APFS-compressed file also reportsst_blocks == 0, so the old heuristic would have rejected it as "not downloaded" too. Detection now reads theUF_DATALESSflag, which is the authoritative signal; the blocks heuristic survives only as a fallback for platforms with nost_flags.Localized failures
The screenshot showed English error text in a Chinese UI.
ScriptoErrorhas carried an i18n key and params since it was written —errors.pysays so explicitly (R7) — but_fail()flattened it tostr(exc)and dropped both, so every catalog entry undererrors.*was unreachable from the run page. The key and params now travel onStatusEventto the row, which renders them throught(); errors with no key (a raw ffmpeg or engine message) still show through in English. A key whose params don't match falls back to the English text rather than displaying a half-substituted template.errors.icloud_placeholderis deleted — nothing raises it any more.Also
downloadingjob status, shown as "downloading from iCloud" / "从 iCloud 下载中" with a progress bar. Progress is best-effort: it is read from the block count, and a provider that only publishes blocks at the end will sit at 0 until the file lands.Tests
199 passed / 5 skipped, 12 new: dataless detection, the compressed-file false positive, download-by-reading, skipping a local file, timeout, stop, failed download, evict not raising on ordinary files; pipeline download-then-evict, local files never evicted, the toggle being respected, eviction after a failed job; and error localization including both fallback paths.
Note
The rows in the report looked duplicated but are not — they are different files with identical names across
Week N/<session>/folders, and the row shows only the basename (full path is in the tooltip). Not addressed here; say the word if the row should carry its folder.