diff --git a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+GeoURI.swift b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+GeoURI.swift index 8206434..d2603d1 100644 --- a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+GeoURI.swift +++ b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+GeoURI.swift @@ -17,5 +17,50 @@ extension PodcastLocation { self.height = height self.accuracy = accuracy } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + let geoStr = try container.decode(String.self) + + guard + let geoScheme = geoStr.split(separator: ":")[safe: 0], + geoScheme == "geo" else { + throw DecodingError.dataCorrupted( + .init( + codingPath: [PodcastLocation.CodingKeys.geo], + debugDescription: "Invalid prefix for geo attribute: \(geoStr)" + ) + ) + } + guard let geoPath = geoStr.split(separator: ":")[safe: 1] else { + throw DecodingError.dataCorrupted( + .init( + codingPath: [PodcastLocation.CodingKeys.geo], + debugDescription: "Invalid path for geo attribute: \(geoStr)" + ) + ) + } + guard + let geoCoords = geoPath.split(separator: ";")[safe: 0], + let latitude = geoCoords.split(separator: ",")[safe: 0]?.asDouble(), + let longitude = geoCoords.split(separator: ",")[safe: 1]?.asDouble() + else { + throw DecodingError.dataCorrupted( + .init( + codingPath: [PodcastLocation.CodingKeys.geo], + debugDescription: "Invalid coordinates for geo attribute: \(geoStr)" + ) + ) + } + let height = geoCoords.split(separator: ",")[safe: 2]?.asExactInt() + let accuracy = geoPath.split(separator: ";")[safe: 1]? + .split(separator: "=")[safe: 1]? + .asDouble() + + self.latitude = latitude + self.longitude = longitude + self.height = height + self.accuracy = accuracy + } } } diff --git a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+OsmQuery.swift b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+OsmQuery.swift index a353bc6..ddb93d7 100644 --- a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+OsmQuery.swift +++ b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation+OsmQuery.swift @@ -19,5 +19,33 @@ extension PodcastLocation { let id: Int let type: OsmType let revision: Int? + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + + var osmStr = try container.decode(String.self) + + guard let osmType = osmStr.removeFirst().asOsmType() else { + throw DecodingError.dataCorrupted( + .init( + codingPath: [PodcastLocation.CodingKeys.osm], + debugDescription: "Invalid type for osm attribute: \(osmStr)" + ) + ) + } + guard let osmID = osmStr.split(separator: "#")[safe: 0]?.asExactInt() else { + throw DecodingError.dataCorrupted( + .init( + codingPath: [PodcastLocation.CodingKeys.osm], + debugDescription: "Invalid id of type Int for osm attribute: \(osmStr)" + ) + ) + } + let osmRevision = osmStr.split(separator: "#")[safe: 1]?.asInt() + + self.id = osmID + self.type = osmType + self.revision = osmRevision + } } } diff --git a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation.swift b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation.swift index 57d5ae4..e66cf70 100644 --- a/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation.swift +++ b/Sources/SyndiKit/Formats/Media/Podcast/PodcastLocation.swift @@ -23,62 +23,8 @@ public struct PodcastLocation: Codable, Equatable { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) + self.geo = try container.decode(GeoURI.self, forKey: .geo) + self.osm = try container.decode(OsmQuery.self, forKey: .osm) self.name = try container.decode(String.self, forKey: .name) - - - let geoStr = try container.decode(String.self, forKey: .geo) - - guard - let geoScheme = geoStr.split(separator: ":")[safe: 0], - geoScheme == "geo" else { - throw DecodingError.dataCorruptedError( - forKey: .geo, - in: container, - debugDescription: "Invalid prefix for geo attribute: \(geoStr)" - ) - } - guard let geoPath = geoStr.split(separator: ":")[safe: 1] else { - throw DecodingError.dataCorruptedError( - forKey: .geo, - in: container, - debugDescription: "Invalid path for geo attribute: \(geoStr)" - ) - } - guard - let geoCoords = geoPath.split(separator: ";")[safe: 0], - let latitude = geoCoords.split(separator: ",")[safe: 0]?.asDouble(), - let longitude = geoCoords.split(separator: ",")[safe: 1]?.asDouble() - else { - throw DecodingError.dataCorruptedError( - forKey: .geo, - in: container, - debugDescription: "Invalid coordinates for geo attribute: \(geoStr)" - ) - } - let height = geoCoords.split(separator: ",")[safe: 2]?.asExactInt() - let accuracy = geoPath.split(separator: ";")[safe: 1]? - .split(separator: "=")[safe: 1]? - .asDouble() - self.geo = .init(latitude: latitude, longitude: longitude, height: height, accuracy: accuracy) - - - var osmStr = try container.decode(String.self, forKey: .osm) - - guard let osmType = osmStr.removeFirst().asOsmType() else { - throw DecodingError.dataCorruptedError( - forKey: .osm, - in: container, - debugDescription: "Invalid type for osm attribute: \(osmStr)" - ) - } - guard let osmID = osmStr.split(separator: "#")[safe: 0]?.asExactInt() else { - throw DecodingError.dataCorruptedError( - forKey: .osm, - in: container, - debugDescription: "Invalid id of type Int for osm attribute: \(osmStr)" - ) - } - let osmRevision = osmStr.split(separator: "#")[safe: 1]?.asInt() - self.osm = .init(id: osmID, type: osmType, revision: osmRevision) } }