Skip to content

Commit 89bc29f

Browse files
authored
Add plans for missing features (#258)
1 parent 2b2d207 commit 89bc29f

10 files changed

+4341
-0
lines changed
Lines changed: 372 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,372 @@
1+
# Plan 1: Movie Service Additions
2+
3+
**Priority:** HIGHEST
4+
**Impact:** High - Movies are core functionality with high user engagement
5+
**Effort:** Medium
6+
**Dependencies:** None
7+
8+
## Overview
9+
10+
Add missing Movie Service endpoints to enable user interactions (ratings, account states) and improve content discovery (alternative titles, translations, changes tracking).
11+
12+
## Missing Endpoints
13+
14+
### Critical - User Interaction (9 endpoints)
15+
16+
1. **GET /3/movie/{movie_id}/account_states** - Get user's rating/favorite/watchlist state
17+
- Returns: `{ id, favorite, rated: { value }, watchlist }`
18+
- Requires: Session ID
19+
- Method: `accountStates(forMovie:session:)`
20+
21+
2. **POST /3/movie/{movie_id}/rating** - Rate a movie
22+
- Body: `{ value: 0.5-10.0 }` (increments of 0.5)
23+
- Requires: Session ID or Guest Session ID
24+
- Method: `addRating(value:movie:session:)`
25+
26+
3. **DELETE /3/movie/{movie_id}/rating** - Delete movie rating
27+
- Requires: Session ID or Guest Session ID
28+
- Method: `deleteRating(forMovie:session:)`
29+
30+
### Important - Content Discovery (5 endpoints)
31+
32+
4. **GET /3/movie/{movie_id}/alternative_titles** - Get alternative titles by country
33+
- Returns: `{ id, titles: [{ iso_3166_1, title, type }] }`
34+
- Optional: country filter
35+
- Method: `alternativeTitles(forMovie:country:)`
36+
37+
5. **GET /3/movie/{movie_id}/translations** - Get movie translations
38+
- Returns: `{ id, translations: [{ iso_3166_1, iso_639_1, name, english_name, data }] }`
39+
- Method: `translations(forMovie:)`
40+
41+
6. **GET /3/movie/{movie_id}/lists** - Get lists containing this movie
42+
- Returns: Pageable list of `MediaList`
43+
- Method: `lists(forMovie:page:)`
44+
45+
### Lower Priority - Metadata (3 endpoints)
46+
47+
7. **GET /3/movie/{movie_id}/changes** - Get movie changes by date range
48+
- Parameters: start_date, end_date, page
49+
- Returns: Change entries with keys and values
50+
- Method: `changes(forMovie:startDate:endDate:page:)`
51+
52+
8. **GET /3/movie/latest** - Get latest movie added to TMDb
53+
- Returns: Full `Movie` object
54+
- Method: `latest()`
55+
56+
9. **GET /3/movie/changes** - Get list of movie IDs that changed
57+
- Parameters: start_date, end_date, page
58+
- Returns: `{ results: [{ id, adult }], ... }`
59+
- Method: `changes(startDate:endDate:page:)`
60+
61+
## New Models Required
62+
63+
### 1. AccountStates
64+
```swift
65+
public struct AccountStates: Codable, Equatable, Hashable, Sendable {
66+
public let id: Int
67+
public let favorite: Bool
68+
public let rated: RatedValue?
69+
public let watchlist: Bool
70+
71+
public struct RatedValue: Codable, Equatable, Hashable, Sendable {
72+
public let value: Double
73+
}
74+
}
75+
```
76+
77+
**Location:** `Sources/TMDb/Domain/Models/AccountStates.swift`
78+
79+
### 2. AlternativeTitle
80+
```swift
81+
public struct AlternativeTitle: Codable, Equatable, Hashable, Sendable {
82+
public let iso3166_1: String
83+
public let title: String
84+
public let type: String?
85+
}
86+
87+
public struct AlternativeTitleCollection: Codable, Equatable, Hashable, Sendable {
88+
public let id: Int
89+
public let titles: [AlternativeTitle]
90+
}
91+
```
92+
93+
**Location:** `Sources/TMDb/Domain/Models/AlternativeTitle.swift`
94+
95+
### 3. Translation & TranslationData
96+
```swift
97+
public struct Translation<DataType: Codable & Equatable & Hashable & Sendable>:
98+
Codable, Equatable, Hashable, Sendable {
99+
public let iso3166_1: String
100+
public let iso639_1: String
101+
public let name: String
102+
public let englishName: String
103+
public let data: DataType
104+
}
105+
106+
public struct MovieTranslationData: Codable, Equatable, Hashable, Sendable {
107+
public let title: String
108+
public let overview: String
109+
public let homepage: String?
110+
public let tagline: String?
111+
}
112+
113+
public struct TranslationCollection<DataType: Codable & Equatable & Hashable & Sendable>:
114+
Codable, Equatable, Hashable, Sendable {
115+
public let id: Int
116+
public let translations: [Translation<DataType>]
117+
}
118+
```
119+
120+
**Location:** `Sources/TMDb/Domain/Models/Translation.swift`
121+
122+
### 4. Change Models
123+
```swift
124+
public struct Change: Codable, Equatable, Hashable, Sendable {
125+
public let key: String
126+
public let items: [ChangeItem]
127+
}
128+
129+
public struct ChangeItem: Codable, Equatable, Hashable, Sendable {
130+
public let id: String
131+
public let action: String
132+
public let time: Date
133+
public let iso639_1: String?
134+
public let iso3166_1: String?
135+
public let value: AnyCodable?
136+
public let originalValue: AnyCodable?
137+
}
138+
139+
public struct ChangeCollection: Codable, Equatable, Hashable, Sendable {
140+
public let changes: [Change]
141+
}
142+
143+
public struct ChangedID: Codable, Equatable, Hashable, Sendable {
144+
public let id: Int
145+
public let adult: Bool?
146+
}
147+
148+
public struct ChangedIDCollection: Codable, Equatable, Hashable, Sendable {
149+
public let results: [ChangedID]
150+
public let page: Int
151+
public let totalPages: Int
152+
public let totalResults: Int
153+
}
154+
```
155+
156+
**Location:** `Sources/TMDb/Domain/Models/Change.swift`
157+
158+
**Note:** Requires `AnyCodable` wrapper for dynamic JSON values
159+
160+
### 5. RatingRequest
161+
```swift
162+
struct RatingRequest: Codable {
163+
let value: Double
164+
}
165+
```
166+
167+
**Location:** Internal to service implementation
168+
169+
## Service Protocol Updates
170+
171+
Update `Sources/TMDb/Domain/Services/Movies/MovieService.swift`:
172+
173+
```swift
174+
public protocol MovieService: Sendable {
175+
// ... existing methods ...
176+
177+
/// Returns the user's rating, favorite, and watchlist state for a movie
178+
func accountStates(forMovie movieID: Movie.ID, session: Session) async throws -> AccountStates
179+
180+
/// Adds a rating for a movie
181+
func addRating(_ rating: Double, toMovie movieID: Movie.ID, session: Session) async throws
182+
183+
/// Deletes the user's rating for a movie
184+
func deleteRating(forMovie movieID: Movie.ID, session: Session) async throws
185+
186+
/// Returns alternative titles for a movie
187+
func alternativeTitles(
188+
forMovie movieID: Movie.ID,
189+
country: String?,
190+
language: String?
191+
) async throws -> AlternativeTitleCollection
192+
193+
/// Returns translations for a movie
194+
func translations(forMovie movieID: Movie.ID) async throws -> TranslationCollection<MovieTranslationData>
195+
196+
/// Returns lists that contain the movie
197+
func lists(
198+
forMovie movieID: Movie.ID,
199+
page: Int?,
200+
language: String?
201+
) async throws -> MediaPageableList
202+
203+
/// Returns change history for a movie
204+
func changes(
205+
forMovie movieID: Movie.ID,
206+
startDate: Date?,
207+
endDate: Date?,
208+
page: Int?
209+
) async throws -> ChangeCollection
210+
211+
/// Returns the latest movie added to TMDb
212+
func latest() async throws -> Movie
213+
214+
/// Returns a list of movie IDs that have changed
215+
func changes(
216+
startDate: Date?,
217+
endDate: Date?,
218+
page: Int?
219+
) async throws -> ChangedIDCollection
220+
}
221+
```
222+
223+
## Implementation Steps
224+
225+
### Phase 1: Account States & Ratings (Critical)
226+
1. Create `AccountStates` model with tests
227+
2. Implement `accountStates(forMovie:session:)` method
228+
3. Implement `addRating(_:toMovie:session:)` method with validation (0.5-10.0, increments of 0.5)
229+
4. Implement `deleteRating(forMovie:session:)` method
230+
5. Add unit tests with JSON fixtures
231+
6. Add integration tests
232+
233+
### Phase 2: Alternative Titles & Translations
234+
1. Create `AlternativeTitle` and `Translation` models
235+
2. Implement `alternativeTitles(forMovie:country:language:)` method
236+
3. Implement `translations(forMovie:)` method
237+
4. Implement `lists(forMovie:page:language:)` method
238+
5. Add unit tests with JSON fixtures
239+
6. Add integration tests
240+
241+
### Phase 3: Changes Tracking
242+
1. Create `Change`, `ChangeItem`, and `ChangedID` models
243+
2. Create `AnyCodable` helper for dynamic values
244+
3. Implement `changes(forMovie:startDate:endDate:page:)` method
245+
4. Implement `changes(startDate:endDate:page:)` method
246+
5. Implement `latest()` method
247+
6. Add unit tests with JSON fixtures
248+
7. Add integration tests
249+
250+
## Testing Requirements
251+
252+
### Unit Tests (`Tests/TMDbTests/Services/Movies/`)
253+
254+
Create test files:
255+
- `TMDbMovieServiceAccountStatesTests.swift` - Account states tests
256+
- `TMDbMovieServiceRatingTests.swift` - Rating add/delete tests
257+
- `TMDbMovieServiceAlternativeTitlesTests.swift` - Alternative titles tests
258+
- `TMDbMovieServiceTranslationsTests.swift` - Translations tests
259+
- `TMDbMovieServiceListsTests.swift` - Lists containing movie tests
260+
- `TMDbMovieServiceChangesTests.swift` - Changes tracking tests
261+
262+
JSON Fixtures (`Tests/TMDbTests/Resources/json/`):
263+
- `movie-account-states.json`
264+
- `movie-alternative-titles.json`
265+
- `movie-translations.json`
266+
- `movie-lists.json`
267+
- `movie-changes.json`
268+
- `movie-changes-list.json`
269+
- `movie-latest.json`
270+
271+
### Integration Tests (`Tests/TMDbIntegrationTests/`)
272+
273+
Add to `MovieIntegrationTests.swift`:
274+
- Test account states retrieval
275+
- Test rating add/delete (cleanup required)
276+
- Test alternative titles
277+
- Test translations
278+
- Test lists containing movie
279+
- Test changes (if available)
280+
- Test latest movie
281+
282+
## Documentation Updates
283+
284+
### DocC Extensions
285+
286+
Update `Sources/TMDb/TMDb.docc/Extensions/MovieService.md`:
287+
288+
Add new topic groups:
289+
```markdown
290+
### User Interactions
291+
292+
- ``MovieService/accountStates(forMovie:session:)``
293+
- ``MovieService/addRating(_:toMovie:session:)``
294+
- ``MovieService/deleteRating(forMovie:session:)``
295+
296+
### Content Discovery
297+
298+
- ``MovieService/alternativeTitles(forMovie:country:language:)``
299+
- ``MovieService/translations(forMovie:)``
300+
- ``MovieService/lists(forMovie:page:language:)``
301+
302+
### Change Tracking
303+
304+
- ``MovieService/changes(forMovie:startDate:endDate:page:)``
305+
- ``MovieService/changes(startDate:endDate:page:)``
306+
- ``MovieService/latest()``
307+
```
308+
309+
### New Model Documentation
310+
311+
Add to `Sources/TMDb/TMDb.docc/TMDb.md`:
312+
313+
Under "### Models":
314+
```markdown
315+
- ``AccountStates``
316+
- ``AlternativeTitle``
317+
- ``AlternativeTitleCollection``
318+
- ``Translation``
319+
- ``TranslationCollection``
320+
- ``MovieTranslationData``
321+
- ``Change``
322+
- ``ChangeItem``
323+
- ``ChangeCollection``
324+
- ``ChangedID``
325+
- ``ChangedIDCollection``
326+
```
327+
328+
## API Endpoints Reference
329+
330+
```
331+
GET /3/movie/{movie_id}/account_states?session_id={session_id}
332+
POST /3/movie/{movie_id}/rating?session_id={session_id}
333+
Body: { "value": 8.5 }
334+
DELETE /3/movie/{movie_id}/rating?session_id={session_id}
335+
GET /3/movie/{movie_id}/alternative_titles?country={country}
336+
GET /3/movie/{movie_id}/translations
337+
GET /3/movie/{movie_id}/lists?page={page}
338+
GET /3/movie/{movie_id}/changes?start_date={date}&end_date={date}&page={page}
339+
GET /3/movie/latest
340+
GET /3/movie/changes?start_date={date}&end_date={date}&page={page}
341+
```
342+
343+
## Verification Checklist
344+
345+
Before considering complete:
346+
- [ ] All models created with full test coverage
347+
- [ ] All 9 methods implemented in TMDbMovieService
348+
- [ ] Unit tests passing with JSON fixtures
349+
- [ ] Integration tests passing against live API
350+
- [ ] DocC documentation updated and building without warnings
351+
- [ ] Code formatted (`make format`)
352+
- [ ] Linting passing (`make lint`)
353+
- [ ] All tests passing (`make test && make integration-test`)
354+
355+
## Impact Assessment
356+
357+
**User-Facing Benefits:**
358+
- ✅ Users can rate movies and manage ratings
359+
- ✅ Users can check their interaction state with movies
360+
- ✅ Improved internationalization with alternative titles and translations
361+
- ✅ Apps can track changes for caching/sync
362+
363+
**API Coverage Improvement:**
364+
- Before: 15/24 endpoints (63%)
365+
- After: 24/24 endpoints (100%)
366+
367+
## Notes
368+
369+
- Rating validation: 0.5 to 10.0 in increments of 0.5
370+
- Session ID supports both user sessions and guest sessions
371+
- Changes tracking requires date range (max 14 days)
372+
- Alternative titles can be filtered by country (ISO 3166-1)

0 commit comments

Comments
 (0)