Skip to content

Commit

Permalink
Merge pull request #22 from moogar0880/rate-history-fixes
Browse files Browse the repository at this point in the history
sync.rate() and sync.add_to_history
  • Loading branch information
moogar0880 committed Aug 23, 2015
2 parents 8cc4460 + fd5606b commit ec20434
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 20 deletions.
7 changes: 7 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
Release History
^^^^^^^^^^^^^^^
2.2.0 (2015-08-23)
++++++++++++++++++

* A TVSeason's `episodes` attribute is now dynamically generated from all episodes in that season
* `sync.rate` and `sync.add_to_history` now properly make valid requests (#21)
* Note: `sync.add_to_history`'s `watched_at` argument is now expected to be a datetime object, in order to match `sync.rate`

2.1.0 (2015-07-19)
++++++++++++++++++

Expand Down
2 changes: 1 addition & 1 deletion trakt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
except ImportError:
pass

version_info = (2, 1, 0)
version_info = (2, 2, 0)
__author__ = 'Jon Nappi'
__version__ = '.'.join([str(i) for i in version_info])
1 change: 1 addition & 0 deletions trakt/movies.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Movie(object):
"""A Class representing a Movie object"""
def __init__(self, title, year=None, **kwargs):
super(Movie, self).__init__()
self.media_type = 'movies'
self.title = title
self.year = int(year) if year is not None else year
if self.year is not None:
Expand Down
30 changes: 20 additions & 10 deletions trakt/sync.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
"""This module contains Trakt.tv sync endpoint support functions"""
from datetime import datetime

from .core import get, post
from .utils import slugify, extract_ids
from .utils import slugify, extract_ids, timestamp

__author__ = 'Jon Nappi'
__all__ = ['Scrobbler', 'comment', 'rate', 'add_to_history',
Expand Down Expand Up @@ -32,29 +33,38 @@ def comment(media, comment_body, spoiler=False, review=False):


@post
def rate(media, rating):
def rate(media, rating, rated_at=None):
"""Add a rating from 1 to 10 to a :class:`Movie`, :class:`TVShow`, or
:class:`TVEpisode`
:param media: The media object to post a rating to
:param rating: A rating from 1 to 10 for the media item
:param rated_at: A `datetime.datetime` object indicating the time at which
this rating was created
"""
data = dict(rating=rating)
data.update(media.to_json())
yield 'sync/ratings', data
if rated_at is None:
rated_at = datetime.now()

data = dict(rating=rating, rated_at=timestamp(rated_at))
data.update(media.ids)
yield 'sync/ratings', {media.media_type: [data]}


@post
def add_to_history(media, watched_at):
def add_to_history(media, watched_at=None):
"""Add a :class:`Movie`, :class:`TVShow`, or :class:`TVEpisode` to your
watched history
:param media: The media object to add to your history
:param watched_at: A trakt formatted timestampt that *media* was watched at
:param watched_at: A `datetime.datetime` object indicating the time at
which this media item was viewed
"""
data = dict(watched_at=watched_at)
data.update(media.to_json())
yield 'sync/history', data
if watched_at is None:
watched_at = datetime.now()

data = dict(watched_at=timestamp(watched_at))
data.update(media.ids)
yield 'sync/history', {media.media_type: [data]}


@post
Expand Down
50 changes: 41 additions & 9 deletions trakt/tv.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from datetime import datetime, timedelta

from .core import Airs, Alias, Comment, Genre, Translation, delete, get
from .errors import NotFoundException
from .sync import (Scrobbler, rate, comment, add_to_collection,
add_to_watchlist, add_to_history, remove_from_collection,
remove_from_watchlist, remove_from_history, search)
Expand Down Expand Up @@ -88,6 +89,7 @@ class TVShow(object):

def __init__(self, title='', **kwargs):
super(TVShow, self).__init__()
self.media_type = 'shows'
self.top_watchers = self.top_episodes = self.year = self.tvdb_id = None
self.imdb_id = self.genres = self.certification = self.network = None
self.trakt_id = self.tmdb_id = self._aliases = self._comments = None
Expand Down Expand Up @@ -343,7 +345,7 @@ def __init__(self, show, season=1, slug=None, **kwargs):
self.show = show
self.season = season
self.slug = slug or slugify(show)
self.episodes = []
self._episodes = None
self._comments = []
self._ratings = []
self.ext = 'shows/{id}/seasons/{season}'.format(id=self.slug,
Expand All @@ -363,14 +365,8 @@ def _get(self):

def _build(self, data):
"""Build this :class:`Movie` object with the data in *data*"""
if isinstance(data, list):
for episode in data:
if self.season == episode.pop('season'):
extract_ids(episode)
self.episodes.append(TVEpisode(self.show, self.season,
episode_data=episode))
else:
self.episodes.append(TVEpisode(self.show, self.season, **data))
for key, val in data.items():
setattr(self, key, val)

@property
@get
Expand All @@ -388,6 +384,41 @@ def comments(self):
self._comments.append(Comment(user=user, **com))
yield self._comments

@property
def episodes(self):
"""A list of :class:`TVEpisode` objects representing all of the
Episodes in this :class:`TVSeason`. Because there is no "Get all
episodes for a season" endpoint on the trakt api
"""
if self._episodes is None:
self._episodes = []
index = 1
while True: # Dangerous? Perhaps, but it works
try:
ep = self._episode_getter(index)
self._episodes.append(ep)
except NotFoundException:
break
index += 1
return self._episodes

@get
def _episode_getter(self, episode):
"""Recursive episode getter generator. Will attempt to get the
speicifed episode for this season, and if the requested episode wasn't
found, then we return :const:`None` to indicate to the `episodes`
property that we've already yielded all valid episodes for this season.
:param episode: An int corresponding to the number of the episode
we're trying to retrieve
"""
episode_extension = '/episodes/{}?extended=full'.format(episode)
try:
data = yield (self.ext + episode_extension)
yield TVEpisode(show=self.show, **data)
except NotFoundException:
yield None

@property
@get
def ratings(self):
Expand Down Expand Up @@ -452,6 +483,7 @@ class TVEpisode(object):

def __init__(self, show, season, number=-1, **kwargs):
super(TVEpisode, self).__init__()
self.media_type = 'episodes'
self.show = show
self.season = season
self.number = number
Expand Down
6 changes: 6 additions & 0 deletions trakt/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ def now():
return '{}-{}-{}'.format(year, month, day)


def timestamp(date_object):
"""Generate a trakt formatted timestamp from the given date object"""
fmt = '%Y-%m-%d:T%H:%M:%S.000Z'
return date_object.strftime(fmt)


def extract_ids(id_dict):
"""Extract the inner `ids` dict out of trakt JSON responses and insert them
into the containing `dict`. Then return the input `dict`
Expand Down

0 comments on commit ec20434

Please sign in to comment.