Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

REFACTOR: Improve Movie and TV Show decoding. Update documentation #109

Merged
merged 2 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/CastMember.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public struct CastMember: Identifiable, Codable, Equatable, Hashable {
///
/// Cast member's profile image.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let profilePath: URL?

///
Expand Down
4 changes: 4 additions & 0 deletions Sources/TMDb/Models/Company.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public struct Company: Identifiable, Codable, Equatable, Hashable {
///
/// Company's logo path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let logoPath: URL

///
Expand Down Expand Up @@ -100,6 +102,8 @@ extension Company {
///
/// Company's logo path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let logoPath: URL

///
Expand Down
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/CrewMember.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ public struct CrewMember: Identifiable, Codable, Equatable, Hashable {
///
/// Crew member's profile image.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let profilePath: URL?

///
Expand Down
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/ImageMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public struct ImageMetadata: Identifiable, Codable, Equatable, Hashable {
///
/// Path of the image.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let filePath: URL

///
Expand Down
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/ImagesConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import Foundation
/// To build an image URL, you will need 3 pieces of data. The `base_url`, `size` and `file_path`. Simply combine them
/// all and you will have a fully qualified URL.
///
/// See <doc:/GeneratingImageURLs> for more details.
///
public struct ImagesConfiguration: Codable, Equatable, Hashable {

///
Expand Down
107 changes: 70 additions & 37 deletions Sources/TMDb/Models/Movie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,20 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
///
/// Movie release date.
///
public var releaseDate: Date? {
guard let releaseDateString else {
return nil
}

return DateFormatter.theMovieDatabase.date(from: releaseDateString)
}
public let releaseDate: Date?

///
/// Movie poster path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let posterPath: URL?

///
/// Movie poster backdrop path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let backdropPath: URL?

///
Expand All @@ -79,13 +77,7 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
///
/// Movie's web site URL.
///
public var homepageURL: URL? {
guard let homepage else {
return nil
}

return URL(string: homepage)
}
public let homepageURL: URL?

///
/// IMDd identifier.
Expand Down Expand Up @@ -130,15 +122,12 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
///
/// Has video.
///
public let video: Bool?
public let hasVideo: Bool?

///
/// Is the movie only suitable for adults.
///
public let adult: Bool?

private let releaseDateString: String?
private let homepage: String?
public let isAdultOnly: Bool?

///
/// Creates a movie object.
Expand Down Expand Up @@ -166,8 +155,8 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
/// - popularity: Current popularity.
/// - voteAverage: Average vote score.
/// - voteCount: Number of votes.
/// - video: Has video.
/// - adult: Is the movie only suitable for adults.
/// - hasVideo: Has video.
/// - isAdultOnly: Is the movie only suitable for adults.
///
public init(
id: Int,
Expand All @@ -192,8 +181,8 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
popularity: Double? = nil,
voteAverage: Double? = nil,
voteCount: Int? = nil,
video: Bool? = nil,
adult: Bool? = nil
hasVideo: Bool? = nil,
isAdultOnly: Bool? = nil
) {
self.id = id
self.title = title
Expand All @@ -203,18 +192,12 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
self.overview = overview
self.runtime = runtime
self.genres = genres
self.releaseDateString = {
guard let releaseDate else {
return nil
}

return DateFormatter.theMovieDatabase.string(from: releaseDate)
}()
self.releaseDate = releaseDate
self.posterPath = posterPath
self.backdropPath = backdropPath
self.budget = budget
self.revenue = revenue
self.homepage = homepageURL?.absoluteString
self.homepageURL = homepageURL
self.imdbID = imdbID
self.status = status
self.productionCompanies = productionCompanies
Expand All @@ -223,8 +206,8 @@ public struct Movie: Identifiable, Codable, Equatable, Hashable {
self.popularity = popularity
self.voteAverage = voteAverage
self.voteCount = voteCount
self.video = video
self.adult = adult
self.hasVideo = hasVideo
self.isAdultOnly = isAdultOnly
}

}
Expand All @@ -240,22 +223,72 @@ extension Movie {
case overview
case runtime
case genres
case releaseDateString = "releaseDate"
case releaseDate
case posterPath
case backdropPath
case budget
case revenue
case homepageURL = "homepage"
case imdbID = "imdbId"
case status
case homepage
case productionCompanies
case productionCountries
case spokenLanguages
case popularity
case voteAverage
case voteCount
case video
case adult
case hasVideo = "video"
case isAdultOnly = "adult"
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let container2 = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decode(Int.self, forKey: .id)
self.title = try container.decode(String.self, forKey: .title)
self.tagline = try container.decodeIfPresent(String.self, forKey: .tagline)
self.originalTitle = try container.decodeIfPresent(String.self, forKey: .originalTitle)
self.originalLanguage = try container.decodeIfPresent(String.self, forKey: .originalLanguage)
self.overview = try container.decodeIfPresent(String.self, forKey: .overview)
self.runtime = try container.decodeIfPresent(Int.self, forKey: .runtime)
self.genres = try container.decodeIfPresent([Genre].self, forKey: .genres)

// Need to deal with empty strings - date decoding will fail with an empty string
let releaseDateString = try container.decodeIfPresent(String.self, forKey: .releaseDate)
self.releaseDate = try {
guard let releaseDateString, !releaseDateString.isEmpty else {
return nil
}

return try container2.decodeIfPresent(Date.self, forKey: .releaseDate)
}()

self.posterPath = try container.decodeIfPresent(URL.self, forKey: .posterPath)
self.backdropPath = try container.decodeIfPresent(URL.self, forKey: .backdropPath)
self.budget = try container.decodeIfPresent(Double.self, forKey: .budget)
self.revenue = try container.decodeIfPresent(Double.self, forKey: .revenue)

// Need to deal with empty strings - URL decoding will fail with an empty string
let homepageURLString = try container.decodeIfPresent(String.self, forKey: .homepageURL)
self.homepageURL = try {
guard let homepageURLString, !homepageURLString.isEmpty else {
return nil
}

return try container2.decodeIfPresent(URL.self, forKey: .homepageURL)
}()

self.imdbID = try container.decodeIfPresent(String.self, forKey: .imdbID)
self.status = try container.decodeIfPresent(Status.self, forKey: .status)
self.productionCompanies = try container.decodeIfPresent([ProductionCompany].self, forKey: .productionCompanies)
self.productionCountries = try container.decodeIfPresent([ProductionCountry].self, forKey: .productionCountries)
self.spokenLanguages = try container.decodeIfPresent([SpokenLanguage].self, forKey: .spokenLanguages)
self.popularity = try container.decodeIfPresent(Double.self, forKey: .popularity)
self.voteAverage = try container.decodeIfPresent(Double.self, forKey: .voteAverage)
self.voteCount = try container.decodeIfPresent(Int.self, forKey: .voteCount)
self.hasVideo = try container.decodeIfPresent(Bool.self, forKey: .hasVideo)
self.isAdultOnly = try container.decodeIfPresent(Bool.self, forKey: .isAdultOnly)
}

}
5 changes: 0 additions & 5 deletions Sources/TMDb/Models/MovieSort.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@ import Foundation
///
public enum MovieSort: CustomStringConvertible {

///
/// Default sort specifier.
///
public static var `default`: Self = .popularity()

///
/// By popularity.
///
Expand Down
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/Network.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public struct Network: Identifiable, Codable, Equatable, Hashable {
///
/// Network logo path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let logoPath: URL?

///
Expand Down
48 changes: 35 additions & 13 deletions Sources/TMDb/Models/Person.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public struct Person: Identifiable, Codable, Equatable, Hashable {
///
/// Person's gender.
///
public let gender: Gender?
public let gender: Gender

///
/// Person's place of birth.
Expand All @@ -53,6 +53,8 @@ public struct Person: Identifiable, Codable, Equatable, Hashable {
///
/// Person's profile path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let profilePath: URL?

///
Expand All @@ -68,15 +70,7 @@ public struct Person: Identifiable, Codable, Equatable, Hashable {
///
/// Person's web site.
///
public var homepageURL: URL? {
guard let homepage else {
return nil
}

return URL(string: homepage)
}

private let homepage: String?
public let homepageURL: URL?

///
/// Creates a person object.
Expand Down Expand Up @@ -104,7 +98,7 @@ public struct Person: Identifiable, Codable, Equatable, Hashable {
biography: String? = nil,
birthday: Date? = nil,
deathday: Date? = nil,
gender: Gender? = nil,
gender: Gender,
placeOfBirth: String? = nil,
profilePath: URL? = nil,
popularity: Double? = nil,
Expand All @@ -123,7 +117,7 @@ public struct Person: Identifiable, Codable, Equatable, Hashable {
self.profilePath = profilePath
self.popularity = popularity
self.imdbID = imdbID
self.homepage = homepageURL?.absoluteString
self.homepageURL = homepageURL
}

}
Expand All @@ -143,7 +137,35 @@ extension Person {
case profilePath
case popularity
case imdbID = "imdbId"
case homepage
case homepageURL = "homepage"
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let container2 = try decoder.container(keyedBy: CodingKeys.self)

self.id = try container.decode(Int.self, forKey: .id)
self.name = try container.decode(String.self, forKey: .name)
self.alsoKnownAs = try container.decodeIfPresent([String].self, forKey: .alsoKnownAs)
self.knownForDepartment = try container.decodeIfPresent(String.self, forKey: .knownForDepartment)
self.biography = try container.decodeIfPresent(String.self, forKey: .biography)
self.birthday = try container.decodeIfPresent(Date.self, forKey: .birthday)
self.deathday = try container.decodeIfPresent(Date.self, forKey: .deathday)
self.gender = (try? container.decodeIfPresent(Gender.self, forKey: .gender)) ?? .unknown
self.placeOfBirth = try container.decodeIfPresent(String.self, forKey: .placeOfBirth)
self.profilePath = try container.decodeIfPresent(URL.self, forKey: .profilePath)
self.popularity = try container.decodeIfPresent(Double.self, forKey: .popularity)
self.imdbID = try container.decodeIfPresent(String.self, forKey: .imdbID)

// Need to deal with empty strings - URL decoding will fail with an empty string
let homepageURLString = try container.decodeIfPresent(String.self, forKey: .homepageURL)
self.homepageURL = try {
guard let homepageURLString, !homepageURLString.isEmpty else {
return nil
}

return try container2.decodeIfPresent(URL.self, forKey: .homepageURL)
}()
}

}
2 changes: 2 additions & 0 deletions Sources/TMDb/Models/ProductionCompany.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public struct ProductionCompany: Identifiable, Codable, Equatable, Hashable {
///
/// Company's logo path.
///
/// To generate a full URL see <doc:/TMDb/GeneratingImageURLs>.
///
public let logoPath: URL?

///
Expand Down
Loading