137 lines
4.8 KiB
Swift
137 lines
4.8 KiB
Swift
import Foundation
|
|
|
|
public struct RadioStation: Codable, Hashable, Identifiable, Sendable {
|
|
public var uuid: String
|
|
public var name: String
|
|
public var url: String
|
|
public var resolvedURL: String
|
|
public var homepage: String
|
|
public var favicon: String
|
|
public var country: String
|
|
public var tags: String
|
|
public var codec: String
|
|
public var bitrate: Int
|
|
public var votes: Int
|
|
public var isOnline: Bool
|
|
public var isFavorite: Bool
|
|
public var isManual: Bool
|
|
|
|
public var id: String {
|
|
if !uuid.isEmpty { return uuid }
|
|
if !resolvedURL.isEmpty { return resolvedURL }
|
|
if !url.isEmpty { return url }
|
|
return name
|
|
}
|
|
|
|
public var playbackURLString: String {
|
|
resolvedURL.isEmpty ? url : resolvedURL
|
|
}
|
|
|
|
public var searchableText: String {
|
|
[name, tags, country, codec].joined(separator: " ").lowercased()
|
|
}
|
|
|
|
public init(
|
|
uuid: String = "",
|
|
name: String,
|
|
url: String = "",
|
|
resolvedURL: String = "",
|
|
homepage: String = "",
|
|
favicon: String = "",
|
|
country: String = "",
|
|
tags: String = "",
|
|
codec: String = "",
|
|
bitrate: Int = 0,
|
|
votes: Int = 0,
|
|
isOnline: Bool = true,
|
|
isFavorite: Bool = false,
|
|
isManual: Bool = false
|
|
) {
|
|
self.uuid = uuid
|
|
self.name = name
|
|
self.url = url
|
|
self.resolvedURL = resolvedURL
|
|
self.homepage = homepage
|
|
self.favicon = favicon
|
|
self.country = country
|
|
self.tags = tags
|
|
self.codec = codec
|
|
self.bitrate = bitrate
|
|
self.votes = votes
|
|
self.isOnline = isOnline
|
|
self.isFavorite = isFavorite
|
|
self.isManual = isManual
|
|
}
|
|
|
|
enum CodingKeys: String, CodingKey {
|
|
case uuid = "stationuuid"
|
|
case legacyUUID = "uuid"
|
|
case name
|
|
case url
|
|
case resolvedURL = "url_resolved"
|
|
case legacyResolvedURL = "urlResolved"
|
|
case homepage
|
|
case favicon
|
|
case country
|
|
case tags
|
|
case codec
|
|
case bitrate
|
|
case votes
|
|
case lastCheckOK = "lastcheckok"
|
|
case isFavorite
|
|
case isManual
|
|
}
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
uuid = try container.decodeIfPresent(String.self, forKey: .uuid)
|
|
?? container.decodeIfPresent(String.self, forKey: .legacyUUID)
|
|
?? ""
|
|
name = try container.decodeIfPresent(String.self, forKey: .name) ?? ""
|
|
url = try container.decodeIfPresent(String.self, forKey: .url) ?? ""
|
|
resolvedURL = try container.decodeIfPresent(String.self, forKey: .resolvedURL)
|
|
?? container.decodeIfPresent(String.self, forKey: .legacyResolvedURL)
|
|
?? ""
|
|
homepage = try container.decodeIfPresent(String.self, forKey: .homepage) ?? ""
|
|
favicon = try container.decodeIfPresent(String.self, forKey: .favicon) ?? ""
|
|
country = try container.decodeIfPresent(String.self, forKey: .country) ?? ""
|
|
tags = try container.decodeIfPresent(String.self, forKey: .tags) ?? ""
|
|
codec = try container.decodeIfPresent(String.self, forKey: .codec) ?? ""
|
|
bitrate = try container.decodeFlexibleInt(forKey: .bitrate) ?? 0
|
|
votes = try container.decodeFlexibleInt(forKey: .votes) ?? 0
|
|
let lastCheckOK = try container.decodeFlexibleInt(forKey: .lastCheckOK)
|
|
isOnline = lastCheckOK.map { $0 > 0 } ?? true
|
|
isFavorite = try container.decodeIfPresent(Bool.self, forKey: .isFavorite) ?? false
|
|
isManual = try container.decodeIfPresent(Bool.self, forKey: .isManual) ?? false
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encode(uuid, forKey: .legacyUUID)
|
|
try container.encode(name, forKey: .name)
|
|
try container.encode(url, forKey: .url)
|
|
try container.encode(resolvedURL, forKey: .legacyResolvedURL)
|
|
try container.encode(homepage, forKey: .homepage)
|
|
try container.encode(favicon, forKey: .favicon)
|
|
try container.encode(country, forKey: .country)
|
|
try container.encode(tags, forKey: .tags)
|
|
try container.encode(codec, forKey: .codec)
|
|
try container.encode(bitrate, forKey: .bitrate)
|
|
try container.encode(votes, forKey: .votes)
|
|
try container.encode(isFavorite, forKey: .isFavorite)
|
|
try container.encode(isManual, forKey: .isManual)
|
|
}
|
|
}
|
|
|
|
extension KeyedDecodingContainer {
|
|
func decodeFlexibleInt(forKey key: Key) throws -> Int? {
|
|
if let intValue = try? decodeIfPresent(Int.self, forKey: key) {
|
|
return intValue
|
|
}
|
|
if let stringValue = try? decodeIfPresent(String.self, forKey: key) {
|
|
return Int(stringValue)
|
|
}
|
|
return nil
|
|
}
|
|
}
|