@@ -27,10 +27,73 @@ public struct DFFile: Codable, Hashable, Equatable {
27
27
public let raw : String
28
28
public let date : String
29
29
public let albums : [ Int ]
30
+ public let exif : [ String : AnyCodable ] ?
31
+ public let meta : [ String : AnyCodable ] ?
30
32
31
33
// Skip nested JSON structures
32
34
enum CodingKeys : String , CodingKey {
33
- case id, user, size, mime, name, info, expr, view, maxv, password, `private`, avatar, userName, userUsername, url, thumb, raw, date, albums
35
+ case id, user, size, mime, name, info, expr, view, maxv, password, `private`, avatar, userName, userUsername, url, thumb, raw, date, albums, exif, meta
36
+ }
37
+
38
+ public init ( from decoder: Decoder ) throws {
39
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
40
+ id = try container. decode ( Int . self, forKey: . id)
41
+ user = try container. decode ( Int . self, forKey: . user)
42
+ size = try container. decode ( Int . self, forKey: . size)
43
+ mime = try container. decode ( String . self, forKey: . mime)
44
+ name = try container. decode ( String . self, forKey: . name)
45
+ userName = try container. decode ( String . self, forKey: . userName)
46
+ userUsername = try container. decode ( String . self, forKey: . userUsername)
47
+ info = try container. decode ( String . self, forKey: . info)
48
+ expr = try container. decode ( String . self, forKey: . expr)
49
+ view = try container. decode ( Int . self, forKey: . view)
50
+ maxv = try container. decode ( Int . self, forKey: . maxv)
51
+ password = try container. decode ( String . self, forKey: . password)
52
+ `private` = try container. decode ( Bool . self, forKey: . private)
53
+ avatar = try container. decode ( Bool . self, forKey: . avatar)
54
+ url = try container. decode ( String . self, forKey: . url)
55
+ thumb = try container. decode ( String . self, forKey: . thumb)
56
+ raw = try container. decode ( String . self, forKey: . raw)
57
+ date = try container. decode ( String . self, forKey: . date)
58
+ albums = try container. decode ( [ Int ] . self, forKey: . albums)
59
+
60
+ // Decode exif and meta as dynamic JSON objects
61
+ if let exifContainer = try ? container. decode ( [ String : AnyCodable ] . self, forKey: . exif) {
62
+ exif = exifContainer
63
+ } else {
64
+ exif = nil
65
+ }
66
+
67
+ if let metaContainer = try ? container. decode ( [ String : AnyCodable ] . self, forKey: . meta) {
68
+ meta = metaContainer
69
+ } else {
70
+ meta = nil
71
+ }
72
+ }
73
+
74
+ public func encode( to encoder: Encoder ) throws {
75
+ var container = encoder. container ( keyedBy: CodingKeys . self)
76
+ try container. encode ( id, forKey: . id)
77
+ try container. encode ( user, forKey: . user)
78
+ try container. encode ( size, forKey: . size)
79
+ try container. encode ( mime, forKey: . mime)
80
+ try container. encode ( name, forKey: . name)
81
+ try container. encode ( userName, forKey: . userName)
82
+ try container. encode ( userUsername, forKey: . userUsername)
83
+ try container. encode ( info, forKey: . info)
84
+ try container. encode ( expr, forKey: . expr)
85
+ try container. encode ( view, forKey: . view)
86
+ try container. encode ( maxv, forKey: . maxv)
87
+ try container. encode ( password, forKey: . password)
88
+ try container. encode ( `private`, forKey: . private)
89
+ try container. encode ( avatar, forKey: . avatar)
90
+ try container. encode ( url, forKey: . url)
91
+ try container. encode ( thumb, forKey: . thumb)
92
+ try container. encode ( raw, forKey: . raw)
93
+ try container. encode ( date, forKey: . date)
94
+ try container. encode ( albums, forKey: . albums)
95
+ try container. encode ( exif, forKey: . exif)
96
+ try container. encode ( meta, forKey: . meta)
34
97
}
35
98
36
99
// Helper property to get a Date object when needed
@@ -78,6 +141,72 @@ public struct DFFile: Codable, Hashable, Equatable {
78
141
}
79
142
}
80
143
144
+ // Helper type to handle dynamic JSON values
145
+ public struct AnyCodable : Codable {
146
+ private let storage : Any
147
+
148
+ public init ( _ value: Any ) {
149
+ self . storage = value
150
+ }
151
+
152
+ public init ( from decoder: Decoder ) throws {
153
+ let container = try decoder. singleValueContainer ( )
154
+
155
+ if container. decodeNil ( ) {
156
+ self . storage = NSNull ( )
157
+ } else if let bool = try ? container. decode ( Bool . self) {
158
+ self . storage = bool
159
+ } else if let int = try ? container. decode ( Int . self) {
160
+ self . storage = int
161
+ } else if let double = try ? container. decode ( Double . self) {
162
+ self . storage = double
163
+ } else if let string = try ? container. decode ( String . self) {
164
+ self . storage = string
165
+ } else if let array = try ? container. decode ( [ AnyCodable ] . self) {
166
+ self . storage = array. map { $0. value }
167
+ } else if let dictionary = try ? container. decode ( [ String : AnyCodable ] . self) {
168
+ self . storage = dictionary. mapValues { $0. value }
169
+ } else {
170
+ throw DecodingError . dataCorruptedError ( in: container, debugDescription: " AnyCodable value cannot be decoded " )
171
+ }
172
+ }
173
+
174
+ public func encode( to encoder: Encoder ) throws {
175
+ var container = encoder. singleValueContainer ( )
176
+
177
+ switch storage {
178
+ case is NSNull :
179
+ try container. encodeNil ( )
180
+ case let bool as Bool :
181
+ try container. encode ( bool)
182
+ case let int as Int :
183
+ try container. encode ( int)
184
+ case let double as Double :
185
+ try container. encode ( double)
186
+ case let string as String :
187
+ try container. encode ( string)
188
+ case let array as [ Any ] :
189
+ try container. encode ( array. map { AnyCodable ( $0) } )
190
+ case let dict as [ String : Any ] :
191
+ try container. encode ( dict. mapValues { AnyCodable ( $0) } )
192
+ default :
193
+ let context = EncodingError . Context ( codingPath: container. codingPath, debugDescription: " AnyCodable value cannot be encoded " )
194
+ throw EncodingError . invalidValue ( storage, context)
195
+ }
196
+ }
197
+
198
+ public var value : Any {
199
+ switch storage {
200
+ case let array as [ AnyCodable ] :
201
+ return array. map { $0. value }
202
+ case let dict as [ String : AnyCodable ] :
203
+ return dict. mapValues { $0. value }
204
+ default :
205
+ return storage
206
+ }
207
+ }
208
+ }
209
+
81
210
public struct DFFilesResponse : Codable {
82
211
public let files : [ DFFile ]
83
212
public let next : Int ?
@@ -110,6 +239,26 @@ extension DFAPI {
110
239
return nil
111
240
}
112
241
242
+ public func getFileDetails( fileID: Int , selectedServer: DjangoFilesSession ? = nil ) async -> DFFile ? {
243
+ do {
244
+ let responseBody = try await makeAPIRequest (
245
+ body: Data ( ) ,
246
+ path: getAPIPath ( . file) + " \( fileID) " ,
247
+ parameters: [ : ] ,
248
+ method: . get,
249
+ selectedServer: selectedServer
250
+ )
251
+ let specialDecoder = JSONDecoder ( )
252
+ specialDecoder. keyDecodingStrategy = . convertFromSnakeCase
253
+ return try specialDecoder. decode ( DFFile . self, from: responseBody)
254
+ } catch let DecodingError . keyNotFound( key, context) {
255
+ print ( " Missing key: \( key. stringValue) in context: \( context. debugDescription) " )
256
+ } catch {
257
+ print ( " Request failed \( error) " )
258
+ }
259
+ return nil
260
+ }
261
+
113
262
public func deleteFiles( fileIDs: [ Int ] , selectedServer: DjangoFilesSession ? = nil ) async {
114
263
do {
115
264
let fileIDsData = try JSONSerialization . data ( withJSONObject: [ " ids " : fileIDs] )
0 commit comments