Fix a crash when syncing watch entries whose video ID exceeds the CloudKit record name limit

Extracted media-source video IDs are full file paths, so closing a
long-named WebDAV video built a watch record name longer than 255
characters and CKRecord.ID threw a fatal CKException.

Scoped record names now fall back to a SHA-256 digest of the ID when
the verbatim form would exceed the limit. The sync engine's local
lookups for materializing pending saves and applying remote deletions
recognise the digest form and match it against all entities of that
type instead of the indexed ID lookup. Short IDs keep their existing
names, so records already in iCloud are unaffected.
This commit is contained in:
Arkadiusz Fal
2026-09-20 23:59:05 +02:00
parent 5651f8d431
commit 53fda7574c
5 changed files with 141 additions and 12 deletions

View File

@@ -130,6 +130,12 @@ extension DataManager {
return (try? modelContext.fetch(descriptor)) ?? []
}
/// Gets every bookmark, for lookups that cannot go through the
/// video-ID index (CloudKit record names that carry a digest of the ID).
func allBookmarks() -> [Bookmark] {
(try? modelContext.fetch(FetchDescriptor<Bookmark>())) ?? []
}
/// Deletes a single bookmark without queueing a CloudKit deletion.
/// Used by CloudKitSyncEngine when applying remote deletions.
func deleteBookmark(_ bookmark: Bookmark) {

View File

@@ -167,6 +167,12 @@ extension DataManager {
return (try? modelContext.fetch(descriptor)) ?? []
}
/// Gets every watch entry, for lookups that cannot go through the
/// video-ID index (CloudKit record names that carry a digest of the ID).
func allWatchEntries() -> [WatchEntry] {
(try? modelContext.fetch(FetchDescriptor<WatchEntry>())) ?? []
}
/// Deletes a single watch entry without queueing a CloudKit deletion.
/// Used by CloudKitSyncEngine when applying remote deletions.
func deleteWatchEntry(_ entry: WatchEntry) {