Skip to content
Open
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
48 changes: 48 additions & 0 deletions trakt/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,54 @@ def get_collection(list_type=None, extended=None):
results.append(TVShow(**d.pop('show')))

yield results

@get
def get_history(list_type=None, id=None, start_at=None, end_at=None):
"""Returns movies and episodes that a user has watched, sorted by most recent.

:param list_type: Optional Filter by a specific type.
Possible values: movies or episodes.
:param id: Optional Trakt ID for a specific item.
:param start_at : Optional, A `datetime.datetime` object or `str`, Filter by watched date starting at.
:param end_at : Optional, A `datetime.datetime` object or `str`, Filter by watched date ending at.
"""
valid_type = ('movies', 'episodes')

if list_type and list_type not in valid_type:
raise ValueError('list_type must be one of {}'.format(valid_type))

uri = 'sync/history'
if list_type:
uri += '/{}'.format(list_type)

if id:
uri += '/{}'.format(id)

if not isinstance(start_at, str):
start_at = timestamp(start_at)
if start_at:
uri += '?start_at={start_at}'.format(start_at=start_at)

if not isinstance(end_at, str):
end_at = timestamp(end_at)
if end_at:
uri += '?end_at={end_at}'.format(end_at=end_at)

Comment on lines +554 to +563
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix None handling and join query params correctly for start_at/end_at

timestamp(None) will raise, and using ? twice yields an invalid URL when both params are present.

Apply this diff:

-    if not isinstance(start_at, str):
-        start_at = timestamp(start_at)
-    if start_at:
-        uri += '?start_at={start_at}'.format(start_at=start_at)
-               
-    if not isinstance(end_at, str):
-        end_at = timestamp(end_at)
-    if end_at:
-        uri += '?end_at={end_at}'.format(end_at=end_at)
+    # Normalize timestamps only when provided; then build query string once.
+    if start_at is not None and not isinstance(start_at, str):
+        start_at = timestamp(start_at)
+    if end_at is not None and not isinstance(end_at, str):
+        end_at = timestamp(end_at)
+
+    params = []
+    if start_at:
+        params.append(f"start_at={start_at}")
+    if end_at:
+        params.append(f"end_at={end_at}")
+    if params:
+        uri += "?" + "&".join(params)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not isinstance(start_at, str):
start_at = timestamp(start_at)
if start_at:
uri += '?start_at={start_at}'.format(start_at=start_at)
if not isinstance(end_at, str):
end_at = timestamp(end_at)
if end_at:
uri += '?end_at={end_at}'.format(end_at=end_at)
# Normalize timestamps only when provided; then build query string once.
if start_at is not None and not isinstance(start_at, str):
start_at = timestamp(start_at)
if end_at is not None and not isinstance(end_at, str):
end_at = timestamp(end_at)
params = []
if start_at:
params.append(f"start_at={start_at}")
if end_at:
params.append(f"end_at={end_at}")
if params:
uri += "?" + "&".join(params)
🤖 Prompt for AI Agents
In trakt/sync.py around lines 554 to 563, the code calls
timestamp(start_at)/timestamp(end_at) without guarding against None and appends
query params using '?' twice; change logic to only call timestamp when value is
not None, collect params into a list (e.g. add "start_at=..." and "end_at=..."
entries only when present), then append them to uri once using '?' + '&'. Ensure
you convert non-string datetime-like inputs via timestamp before adding to the
params list so timestamp(None) is never invoked.


data = yield uri
results = []
for d in data:
if 'movie' in d:
from trakt.movies import Movie

results.append(Movie(**d.pop('movie')))
elif 'show' in d:
from trakt.tv import TVShow

results.append(TVShow(**d.pop('show')))

yield results
Comment on lines +567 to +577
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Return TVEpisode for episode history entries (currently returns TVShow)

History responses include an episode object with a companion show. Checking show first maps episodes to TVShow incorrectly.

Apply this diff:

     results = []
     for d in data:
         if 'movie' in d:
             from trakt.movies import Movie
             results.append(Movie(**d.pop('movie')))
-        elif 'show' in d:
-            from trakt.tv import TVShow
-
-            results.append(TVShow(**d.pop('show')))
+        elif 'episode' in d:
+            from trakt.tv import TVEpisode
+            show = d.pop('show', {})  # expected for episodes
+            episode = d.pop('episode')
+            results.append(TVEpisode(
+                show.get('title', None),
+                show_id=(show.get('ids') or {}).get('trakt'),
+                **episode
+            ))
+        elif 'show' in d:
+            from trakt.tv import TVShow
+            results.append(TVShow(**d.pop('show')))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for d in data:
if 'movie' in d:
from trakt.movies import Movie
results.append(Movie(**d.pop('movie')))
elif 'show' in d:
from trakt.tv import TVShow
results.append(TVShow(**d.pop('show')))
yield results
results = []
for d in data:
if 'movie' in d:
from trakt.movies import Movie
results.append(Movie(**d.pop('movie')))
elif 'episode' in d:
from trakt.tv import TVEpisode
# Extract the parent show info (always present for episodes)
show = d.pop('show', {})
episode = d.pop('episode')
results.append(TVEpisode(
show.get('title', None),
show_id=(show.get('ids') or {}).get('trakt'),
**episode
))
elif 'show' in d:
from trakt.tv import TVShow
results.append(TVShow(**d.pop('show')))
yield results
🤖 Prompt for AI Agents
In trakt/sync.py around lines 567 to 577, the loop checks for 'show' before
'episode' causing episode history entries to be mapped to TVShow instead of
TVEpisode; update the conditional order to check for 'episode' (and construct a
TVEpisode from d.pop('episode') using from trakt.episodes import TVEpisode)
before checking for 'show', keep the existing handling for 'movie' unchanged,
and ensure results.append uses the appropriate popped object for each branch.




@post
Expand Down