Skip to content

Commit

Permalink
REFACTOR: Improve Movie and TV Show decoding. Update documentation (#109
Browse files Browse the repository at this point in the history
)
  • Loading branch information
adamayoung committed Aug 2, 2023
1 parent f34c876 commit 0f1406f
Show file tree
Hide file tree
Showing 40 changed files with 565 additions and 205 deletions.
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

0 comments on commit 0f1406f

Please sign in to comment.