@@ -106,7 +106,7 @@ class PutioRealm {
106106 private static func migrate( _ migration: Migration , _ oldSchemaVersion: UInt64 ) {
107107 if oldSchemaVersion < 1 {
108108 migration. enumerateObjects ( ofType: Download . className ( ) ) { _, newDownload in
109- newDownload![ " fileType " ] = 1
109+ newDownload![ " fileTypeRaw " ] = Download . FileType . audio . rawValue
110110 }
111111 }
112112
@@ -134,7 +134,7 @@ class PutioRealm {
134134 newAppUserSettings![ " showOptimisticUsage " ] = false
135135 }
136136
137- migration. enumerateObjects ( ofType: User . className ( ) ) { newAppUser , _ in
137+ migration. enumerateObjects ( ofType: User . className ( ) ) { _ , newAppUser in
138138 migration. enumerateObjects ( ofType: UserDisk . className ( ) ) { _, newAppUserDisk in
139139 newAppUserDisk![ " used " ] = 0
140140 newAppUser![ " disk " ] = newAppUserDisk
@@ -161,10 +161,39 @@ class PutioRealm {
161161 }
162162 }
163163
164- // Schema 12: Download columns renamed from state/fileType to
165- // stateRaw/fileTypeRaw. No migration needed — old format v9
166- // databases are deleted before this runs, and fresh databases
167- // get the new column names automatically.
164+ if oldSchemaVersion < 12 {
165+ migrateDownloadRawColumns ( migration)
166+ }
167+ }
168+
169+ private static func migrateDownloadRawColumns( _ migration: Migration ) {
170+ let hasLegacyState = migration. oldSchema [ Download . className ( ) ] ? [ " state " ] != nil
171+ let hasLegacyFileType = migration. oldSchema [ Download . className ( ) ] ? [ " fileType " ] != nil
172+
173+ migration. enumerateObjects ( ofType: Download . className ( ) ) { oldDownload, newDownload in
174+ let rawValues = legacyDownloadRawValues (
175+ state: hasLegacyState ? oldDownload ? [ " state " ] : nil ,
176+ fileType: hasLegacyFileType ? oldDownload ? [ " fileType " ] : nil
177+ )
178+
179+ if let stateRaw = rawValues. stateRaw {
180+ newDownload![ " stateRaw " ] = stateRaw
181+ }
182+
183+ if let fileTypeRaw = rawValues. fileTypeRaw {
184+ newDownload![ " fileTypeRaw " ] = fileTypeRaw
185+ }
186+ }
187+ }
188+
189+ static func legacyDownloadRawValues( state: Any ? , fileType: Any ? ) -> ( stateRaw: Int ? , fileTypeRaw: Int ? ) {
190+ return ( legacyIntValue ( state) , legacyIntValue ( fileType) )
191+ }
192+
193+ private static func legacyIntValue( _ value: Any ? ) -> Int ? {
194+ if let value = value as? Int { return value }
195+ if let value = value as? NSNumber { return value. intValue }
196+ return nil
168197 }
169198
170199 private static func updateUserSettings( _ migration: Migration , updates: @escaping ( MigrationObject ? ) -> Void ) {
@@ -212,16 +241,15 @@ class PutioRealm {
212241 // Fallback: scan Documents directory for audio files whose UserDefaults entries were lost
213242 if let contents = try ? FileManager . default. contentsOfDirectory ( atPath: documentsURL. path) {
214243 for filename in contents where filename. hasPrefix ( " putio_adm_ " ) {
215- // Extract file ID from "putio_adm_{id}.ext" or "putio_adm_{id}"
216- let stripped = filename
217- . replacingOccurrences ( of: " putio_adm_ " , with: " " )
218- . components ( separatedBy: " . " ) . first ?? " "
219- guard let fileId = Int ( stripped) , fileId > 0 , !recoveredFileIds. contains ( fileId) else { continue }
244+ guard let fileId = recoveredAudioFileId ( from: filename) ,
245+ fileId > 0 ,
246+ !recoveredFileIds. contains ( fileId) else { continue }
220247
221248 let fileURL = documentsURL. appendingPathComponent ( filename)
222249 guard FileManager . default. fileExists ( atPath: fileURL. path) else { continue }
223250
224251 addRecoveredDownload ( buildRecoveredDownload ( fileId: fileId, isVideo: false ) , to: realm)
252+ defaults. set ( filename, forKey: String ( fileId) )
225253 recovered += 1
226254 recoveredFileIds. insert ( fileId)
227255 }
@@ -243,6 +271,16 @@ class PutioRealm {
243271 FileManager . default. urls ( for: . documentDirectory, in: . userDomainMask) . first!
244272 }
245273
274+ static func recoveredAudioFileId( from filename: String ) -> Int ? {
275+ let prefix = " putio_adm_ "
276+ guard filename. hasPrefix ( prefix) else { return nil }
277+
278+ let filenameWithoutExtension = ( filename as NSString ) . deletingPathExtension
279+ let idAndSlug = String ( filenameWithoutExtension. dropFirst ( prefix. count) )
280+ let id = idAndSlug. split ( separator: " _ " , maxSplits: 1 ) . first. map ( String . init) ?? idAndSlug
281+ return Int ( id)
282+ }
283+
246284 private static func buildRecoveredDownload( fileId: Int , defaults: UserDefaults , documentsURL: URL ) -> Download ? {
247285 if hasValidVideoBookmark ( fileId: fileId, defaults: defaults) {
248286 return buildRecoveredDownload ( fileId: fileId, isVideo: true )
0 commit comments