Stop a playlist import that outlived its login

Videos are read with one account's credential and written one at a time
into a local playlist, which is not account-scoped: it belongs to
whoever uses the device and syncs to iCloud. The sheet can be dismissed
and somebody else signed in on the same server while the import is still
running — nothing cancels it — and the rest of one person's private
playlist would land in the other's library.

The credential is checked before every write rather than only at the
start. What was already written stays: it was imported under the login
that asked for it.
This commit is contained in:
Arkadiusz Fal
2026-08-29 23:56:18 +02:00
parent 5295dd5e86
commit 00bab2ae63
2 changed files with 26 additions and 0 deletions

View File

@@ -5006,6 +5006,17 @@
}
}
},
"import.playlists.loginChanged" : {
"comment" : "Error message when the account was signed out or replaced during an import",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "The login changed while importing, so the rest was not added."
}
}
}
},
"import.playlists.notLoggedIn" : {
"comment" : "Error message when not logged in to Invidious",
"localizations" : {

View File

@@ -370,6 +370,18 @@ struct ImportPlaylistsView: View {
importProgress = (current: index + 1, total: total)
}
// These videos are private to the login they were read with,
// and the destination is not: local playlists are shared by
// whoever uses the device and sync to iCloud. The sheet can be
// dismissed and somebody else signed in on the same server
// while this runs, so the credential is checked before every
// write rather than only at the start. What has already been
// written stays — it was imported under the login that asked
// for it.
guard appEnvironment.credential(forInstance: instance) == credential else {
throw ImportError.loginChanged
}
// Skip if already in playlist
if localPlaylist.contains(videoID: video.id.videoID) {
skippedCount += 1
@@ -425,6 +437,7 @@ struct ImportPlaylistsView: View {
enum ImportError: LocalizedError {
case notLoggedIn
case notSupported
case loginChanged
var errorDescription: String? {
switch self {
@@ -432,6 +445,8 @@ struct ImportPlaylistsView: View {
return String(localized: "import.playlists.notLoggedIn")
case .notSupported:
return String(localized: "import.playlists.notSupported")
case .loginChanged:
return String(localized: "import.playlists.loginChanged")
}
}
}