Skip to content

Commit 08094ce

Browse files
chickdanadamayoung
andauthored
FEATURE: TVShow Content Ratings (#188)
* Add models and reqeust * Add coding key * Finalize * Add id and initializer to Content Rating * Update models * Add mocks and tests * Add json * Add service test * Format * Remove swiftlint disable comment * Request tests * formatting * More mocks and tests --------- Co-authored-by: Adam Young <me@adam-young.co.uk>
1 parent 868a1ad commit 08094ce

15 files changed

+693
-1
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//
2+
// ContentRating.swift
3+
// TMDb
4+
//
5+
// Copyright © 2024 Adam Young.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an AS IS BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
import Foundation
21+
22+
///
23+
/// A model representing the content rating.
24+
///
25+
public struct ContentRating: Codable, Equatable, Hashable, Sendable {
26+
27+
///
28+
/// ?
29+
///
30+
public let descriptors: [String]
31+
32+
///
33+
/// The ISO 3166-1 country code.
34+
///
35+
public let countryCode: String
36+
37+
///
38+
/// The content rating of the tv show
39+
///
40+
public let rating: String
41+
42+
/// Creates a content rating object.
43+
///
44+
/// - Parameters:
45+
/// - descriptors: Array of....
46+
/// - countryCode: ISO 3166-1 country code.
47+
/// - rating: The content rating of the tv show
48+
///
49+
public init(descriptors: [String], countryCode: String, rating: String) {
50+
self.descriptors = descriptors
51+
self.countryCode = countryCode
52+
self.rating = rating
53+
}
54+
}
55+
56+
extension ContentRating {
57+
private enum CodingKeys: String, CodingKey {
58+
case rating
59+
case descriptors
60+
case countryCode = "iso31661"
61+
}
62+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// ContentRatingResult.swift
3+
// TMDb
4+
//
5+
// Copyright © 2024 Adam Young.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an AS IS BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
import Foundation
21+
22+
struct ContentRatingResult: Codable, Equatable, Hashable, Sendable {
23+
let results: [ContentRating]
24+
let id: Int
25+
}

Sources/TMDb/Domain/Models/CrewMember.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import Foundation
2121

2222
///
23-
/// A model representing a crew member..
23+
/// A model representing a crew member.
2424
///
2525
public struct CrewMember: Identifiable, Codable, Equatable, Hashable, Sendable {
2626

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// ContentRatingRequest.swift
3+
// TMDb
4+
//
5+
// Copyright © 2024 Adam Young.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an AS IS BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
import Foundation
21+
22+
final class ContentRatingRequest: DecodableAPIRequest<ContentRatingResult> {
23+
24+
init(id: TVSeries.ID) {
25+
let path = "/tv/\(id)/content_ratings"
26+
27+
super.init(path: path)
28+
}
29+
30+
}

Sources/TMDb/Domain/Services/TVSeries/TMDbTVSeriesService.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,24 @@ final class TMDbTVSeriesService: TVSeriesService {
182182
return result.results[country]
183183
}
184184

185+
func contentRatings(
186+
forTVSeries tvSeriesID: TVSeries.ID,
187+
country: String = "US"
188+
) async throws -> ContentRating? {
189+
let request = ContentRatingRequest(id: tvSeriesID)
190+
191+
let result: ContentRatingResult
192+
do {
193+
result = try await apiClient.perform(request)
194+
} catch let error {
195+
throw TMDbError(error: error)
196+
}
197+
198+
return result.results.first { rating in
199+
rating.countryCode == country
200+
}
201+
}
202+
185203
func externalLinks(forTVSeries tvSeriesID: TVSeries.ID) async throws -> TVSeriesExternalLinksCollection {
186204
let request = TVSeriesExternalLinksRequest(id: tvSeriesID)
187205

Sources/TMDb/Domain/Services/TVSeries/TVSeriesService.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,17 @@ public protocol TVSeriesService: Sendable {
217217
///
218218
func externalLinks(forTVSeries tvSeriesID: TVSeries.ID) async throws -> TVSeriesExternalLinksCollection
219219

220+
///
221+
/// Returns the content rating of a TV series.
222+
///
223+
/// [TMDb API - TVSeries: Content ratings](https://developer.themoviedb.org/reference/tv-series-content-ratings)
224+
///
225+
/// - Parameters:
226+
/// - tvSeriesID: The identifier of the TV series.
227+
///
228+
/// - Returns: A content rating for the specificed TV series.
229+
///
230+
func contentRatings(forTVSeries tvSeriesID: TVSeries.ID, country: String) async throws -> ContentRating?
220231
}
221232

222233
public extension TVSeriesService {
@@ -285,4 +296,10 @@ public extension TVSeriesService {
285296
try await watchProviders(forTVSeries: tvSeriesID, country: country)
286297
}
287298

299+
func contentRatings(
300+
forTVSeries tvSeriesID: TVSeries.ID,
301+
country: String = "US"
302+
) async throws -> ContentRating? {
303+
try await contentRatings(forTVSeries: tvSeriesID, country: country)
304+
}
288305
}

Tests/TMDbIntegrationTests/TVSeriesServiceTests.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,16 @@ final class TVSeriesServiceTests: XCTestCase {
125125
XCTAssertNotNil(linksCollection.twitter)
126126
}
127127

128+
func testContentRatings() async throws {
129+
let tvSeriesID = 8592
130+
131+
let contentRatings = try await tvSeriesService.contentRatings(forTVSeries: tvSeriesID, country: "US")
132+
133+
XCTAssertNotNil(contentRatings)
134+
135+
if let contentRating = contentRatings {
136+
XCTAssertEqual(contentRating.rating, "TV-14")
137+
XCTAssertEqual(contentRating.countryCode, "US")
138+
}
139+
}
128140
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//
2+
// ContentRatingTests.swift
3+
// TMDb
4+
//
5+
// Copyright © 2024 Adam Young.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an AS IS BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
@testable import TMDb
21+
import XCTest
22+
23+
final class ContentRatingTests: XCTestCase {
24+
25+
func testDecodeReturnsContentRating() throws {
26+
let result = try JSONDecoder.theMovieDatabase.decode(ContentRating.self, fromResource: "content-rating")
27+
28+
XCTAssertEqual(result.descriptors, contentRating.descriptors)
29+
XCTAssertEqual(result.countryCode, contentRating.countryCode)
30+
XCTAssertEqual(result.rating, contentRating.rating)
31+
}
32+
33+
private let contentRating = ContentRating(
34+
descriptors: [],
35+
countryCode: "US",
36+
rating: "TV-14"
37+
)
38+
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//
2+
// ContentRatingsTests.swift
3+
// TMDb
4+
//
5+
// Copyright © 2024 Adam Young.
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an AS IS BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
20+
@testable import TMDb
21+
import XCTest
22+
23+
final class ContentRatingsTests: XCTestCase {
24+
25+
func testDecodeReturnsContentRatingResult() throws {
26+
let result = try JSONDecoder.theMovieDatabase.decode(ContentRatingResult.self, fromResource: "content-ratings")
27+
28+
XCTAssertEqual(result, contentRatings)
29+
}
30+
31+
private let contentRatings = ContentRatingResult(
32+
results: [
33+
ContentRating(
34+
descriptors: [],
35+
countryCode: "US",
36+
rating: "TV-14"
37+
),
38+
ContentRating(
39+
descriptors: [],
40+
countryCode: "AU",
41+
rating: "M"
42+
),
43+
ContentRating(
44+
descriptors: [],
45+
countryCode: "RU",
46+
rating: "12+"
47+
),
48+
ContentRating(
49+
descriptors: [],
50+
countryCode: "GB",
51+
rating: "15"
52+
),
53+
ContentRating(
54+
descriptors: [],
55+
countryCode: "BR",
56+
rating: "12"
57+
),
58+
ContentRating(
59+
descriptors: [],
60+
countryCode: "HU",
61+
rating: "12"
62+
),
63+
ContentRating(
64+
descriptors: [],
65+
countryCode: "PH",
66+
rating: "G"
67+
),
68+
ContentRating(
69+
descriptors: [],
70+
countryCode: "MX",
71+
rating: "A"
72+
),
73+
ContentRating(
74+
descriptors: [],
75+
countryCode: "PT",
76+
rating: "NR"
77+
),
78+
ContentRating(
79+
descriptors: [],
80+
countryCode: "ES",
81+
rating: "16"
82+
),
83+
ContentRating(
84+
descriptors: [],
85+
countryCode: "FR",
86+
rating: "16"
87+
),
88+
ContentRating(
89+
descriptors: [],
90+
countryCode: "CA",
91+
rating: "PG"
92+
),
93+
ContentRating(
94+
descriptors: [],
95+
countryCode: "NL",
96+
rating: "6"
97+
),
98+
ContentRating(
99+
descriptors: [],
100+
countryCode: "DE",
101+
rating: "12"
102+
),
103+
ContentRating(
104+
descriptors: [],
105+
countryCode: "DE",
106+
rating: "16"
107+
),
108+
ContentRating(
109+
descriptors: [],
110+
countryCode: "AU",
111+
rating: "PG"
112+
),
113+
ContentRating(
114+
descriptors: [],
115+
countryCode: "KR",
116+
rating: "15"
117+
),
118+
ContentRating(
119+
descriptors: [],
120+
countryCode: "AT",
121+
rating: "12"
122+
),
123+
ContentRating(
124+
descriptors: [],
125+
countryCode: "CH",
126+
rating: "12"
127+
),
128+
ContentRating(
129+
descriptors: [],
130+
countryCode: "PL",
131+
rating: "16"
132+
),
133+
ContentRating(
134+
descriptors: [],
135+
countryCode: "HU",
136+
rating: "16"
137+
),
138+
ContentRating(
139+
descriptors: [],
140+
countryCode: "CZ",
141+
rating: "15+"
142+
),
143+
ContentRating(
144+
descriptors: [],
145+
countryCode: "RO",
146+
rating: "15"
147+
)
148+
],
149+
id: 8592
150+
)
151+
}

0 commit comments

Comments
 (0)