From 1958dcb7b27f3543ce8dd87ee952281558a0dffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:29:02 +0200 Subject: [PATCH 01/69] TVShow: Extract progress property body to _progress() method --- trakt/tv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..c7eb5b67 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -295,6 +295,9 @@ def comments(self): self._comments.append(Comment(user=user, **com)) yield self._comments + def _progress(self, progress_type): + yield f'{self.ext}/progress/{progress_type}' + @property @get def progress(self): @@ -305,7 +308,7 @@ def progress(self): The next_episode will be the next episode the user should collect, if there are no upcoming episodes it will be set to null. """ - yield (self.ext + '/progress/collection') + return self._progress('collection') @property def crew(self): From b74a0b647e55c80ab263c9e4d6dd9027bf8de330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:11:21 +0200 Subject: [PATCH 02/69] TVShow: Add specials parameter to _progress() method --- trakt/tv.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/trakt/tv.py b/trakt/tv.py index c7eb5b67..cc5664d0 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -295,8 +295,12 @@ def comments(self): self._comments.append(Comment(user=user, **com)) yield self._comments - def _progress(self, progress_type): - yield f'{self.ext}/progress/{progress_type}' + def _progress(self, progress_type, specials=False): + uri = f'{self.ext}/progress/{progress_type}' + if specials: + uri += '?specials=true' + data = yield uri + yield data @property @get From c308ce1de197d639b1dae1ecb92575eadf733970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:13:22 +0200 Subject: [PATCH 03/69] TVShow: Add collection_progress() method --- trakt/tv.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/trakt/tv.py b/trakt/tv.py index cc5664d0..6e076ff4 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -314,6 +314,21 @@ def progress(self): """ return self._progress('collection') + @get + def collection_progress(self, specials=False): + """ + collection progress for a show including details on all aired + seasons and episodes. + + The next_episode will be the next episode the user should collect, + if there are no upcoming episodes it will be set to null. + + specials: include specials as season 0 Example: false. + + https://trakt.docs.apiary.io/#reference/shows/collection-progress/get-show-collection-progress + """ + return self._progress('collection', specials) + @property def crew(self): """All of the crew members that worked on this :class:`TVShow`""" From 649a8661442f1e80af2c57d7c304e00ae8a4214e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:15:28 +0200 Subject: [PATCH 04/69] TVShow: Add watched_progress() method --- trakt/tv.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/trakt/tv.py b/trakt/tv.py index 6e076ff4..dec9f765 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -329,6 +329,18 @@ def collection_progress(self, specials=False): """ return self._progress('collection', specials) + @get + def watched_progress(self, specials=False): + """ + watched progress for a show including details on all aired seasons + and episodes. + + specials: include specials as season 0 Example: false. + + https://trakt.docs.apiary.io/#reference/shows/watched-progress/get-show-collection-progress + """ + return self._progress('watched', specials) + @property def crew(self): """All of the crew members that worked on this :class:`TVShow`""" From f234cd87b3b5782ba25f0334608f45526789049a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:27:15 +0200 Subject: [PATCH 05/69] TVShow: Add collection_progress() testing --- tests/test_shows.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/test_shows.py b/tests/test_shows.py index 8f54819a..9d6784b1 100644 --- a/tests/test_shows.py +++ b/tests/test_shows.py @@ -129,6 +129,13 @@ def test_show_comment(): assert got.comment('Test Comment Data').get('comment') +def test_collection_progress(): + show = TVShow('Game of Thrones') + assert show.progress is None + assert show.collection_progress() is None + assert show.watched_progress() is None + + def test_rate_show(): got = TVShow('Game of Thrones') assert got.rate(10)['added'] == {'episodes': 2, 'movies': 1, 'seasons': 1, 'shows': 1} From 02d29f02b9a3516f1af58289675ef13ddc65520b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:59:59 +0200 Subject: [PATCH 06/69] Add deprecated~=1.2.13 dependency --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fa971311..b3cf4647 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -requests>=2.25 +deprecated~=1.2.13 requests-oauthlib>=1.3 +requests>=2.25 From 3c3e2977946467f24293245de220ee9746011d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 15:20:19 +0200 Subject: [PATCH 07/69] Add User.get_liked_lists method --- trakt/users.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..cd842a0b 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -480,6 +480,27 @@ def get_stats(self): data = yield 'users/{user}/stats'.format(user=slugify(self.username)) yield data + @get + def get_liked_lists(self, list_type=None, limit=None): + """Get items a user likes. + + This will return an array of standard media objects. + You can optionally limit the type of results to return. + + list_type possible values are "comments", "lists". + + https://trakt.docs.apiary.io/#reference/users/likes/get-likes + """ + uri = 'users/likes' + if list_type is not None: + uri += f'/{list_type}' + + if limit is not None: + uri += f'?limit={limit}' + + data = yield uri + yield data + def follow(self): """Follow this :class:`User`""" follow(self.username) From f60922bacf275407f69afd3c73f2918f95ae4f38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 15:42:07 +0200 Subject: [PATCH 08/69] Add test_liked_lists test --- tests/test_users.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_users.py b/tests/test_users.py index 3b5cab23..7539aa54 100644 --- a/tests/test_users.py +++ b/tests/test_users.py @@ -128,3 +128,16 @@ def test_watched(): def test_stats(): sean = User('sean') assert isinstance(sean.get_stats(), dict) + + +def test_liked_lists(): + sean = User('sean') + + lists = sean.get_liked_lists() + assert lists is None + + lists = sean.get_liked_lists('lists') + assert isinstance(lists, list) + + lists = sean.get_liked_lists('comments') + assert isinstance(lists, list) From ee435c5b328dc43e2383edde9f373371ce646eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 14:55:06 +0200 Subject: [PATCH 09/69] TVShow: Add count_specials, hidden parameters to _progress --- trakt/tv.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/trakt/tv.py b/trakt/tv.py index dec9f765..1b81de59 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -2,6 +2,8 @@ """Interfaces to all of the TV objects offered by the Trakt.tv API""" from collections import namedtuple from datetime import datetime, timedelta +from urllib.parse import urlencode + from trakt.core import Airs, Alias, Comment, Genre, delete, get from trakt.errors import NotFoundException from trakt.sync import (Scrobbler, rate, comment, add_to_collection, @@ -295,11 +297,22 @@ def comments(self): self._comments.append(Comment(user=user, **com)) yield self._comments - def _progress(self, progress_type, specials=False): + def _progress(self, progress_type, + specials=False, count_specials=False, hidden=False): uri = f'{self.ext}/progress/{progress_type}' + params = {} if specials: - uri += '?specials=true' + params['specials'] = 'true' + if count_specials: + params['count_specials'] = 'true' + if hidden: + params['hidden'] = 'true' + + if params: + uri += '?' + urlencode(params) + data = yield uri + yield data @property From af1b70dc36875814403af019f2f812c72aeb371a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 14:59:35 +0200 Subject: [PATCH 10/69] TVShow: Add count_specials, hidden to watched_progress() and collection_progress() --- trakt/tv.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/trakt/tv.py b/trakt/tv.py index 1b81de59..b82f35ca 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -328,7 +328,7 @@ def progress(self): return self._progress('collection') @get - def collection_progress(self, specials=False): + def collection_progress(self, **kwargs): """ collection progress for a show including details on all aired seasons and episodes. @@ -336,23 +336,27 @@ def collection_progress(self, specials=False): The next_episode will be the next episode the user should collect, if there are no upcoming episodes it will be set to null. - specials: include specials as season 0 Example: false. + specials: include specials as season 0. Default: false. + count_specials: count specials in the overall stats. Default: false. + hidden: include any hidden seasons. Default: false. https://trakt.docs.apiary.io/#reference/shows/collection-progress/get-show-collection-progress """ - return self._progress('collection', specials) + return self._progress('collection', **kwargs) @get - def watched_progress(self, specials=False): + def watched_progress(self, **kwargs): """ watched progress for a show including details on all aired seasons and episodes. - specials: include specials as season 0 Example: false. + specials: include specials as season 0. Default: false. + count_specials: count specials in the overall stats. Default: false. + hidden: include any hidden seasons. Default: false. https://trakt.docs.apiary.io/#reference/shows/watched-progress/get-show-collection-progress """ - return self._progress('watched', specials) + return self._progress('watched', **kwargs) @property def crew(self): From 921bfd34da5061e2a334dcdab03d28a92ce13330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 15:36:40 +0200 Subject: [PATCH 11/69] tests: Print urls for what mock data is missing --- tests/conftest.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index 16129eeb..46997050 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -40,7 +40,11 @@ def _handle_request(self, method, url, data=None): # use a deepcopy of the mocked data to ensure clean responses on every # request. this prevents rewrites to JSON responses from persisting method_responses = deepcopy(self.mock_data).get(uri, {}) - return method_responses.get(method.upper()) + result = method_responses.get(method.upper()) + if result is None: + print(f"Missing mock for {method.upper()} {trakt.core.BASE_URL}{uri}") + + return result """Override utility functions from trakt.core to use an underlying MockCore From f59e5606ac797aa3997403f8113748335955e3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 19:40:39 +0200 Subject: [PATCH 12/69] Fix progress typo --- trakt/users.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..a17e2955 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -380,7 +380,7 @@ def show_collection(self): @property @get def watched_movies(self): - """Watched profess for all :class:`Movie`'s in this :class:`User`'s + """Watched progress for all :class:`Movie`'s in this :class:`User`'s collection. """ if self._watched_movies is None: @@ -398,7 +398,7 @@ def watched_movies(self): @property @get def watched_shows(self): - """Watched profess for all :class:`TVShow`'s in this :class:`User`'s + """Watched progress for all :class:`TVShow`'s in this :class:`User`'s collection. """ if self._watched_shows is None: From cc0be4afb3a87c3a484a92e1197ebd3074fb8c06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 15:44:21 +0200 Subject: [PATCH 13/69] Tests: Add mock data for progress/collection --- tests/mock_data/shows.json | 83 ++++++++++++++++++++++++++++++++++++++ tests/test_shows.py | 6 +-- 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/tests/mock_data/shows.json b/tests/mock_data/shows.json index e98784c1..8d728987 100644 --- a/tests/mock_data/shows.json +++ b/tests/mock_data/shows.json @@ -149,6 +149,89 @@ {"username":"sean","private":false,"name":"Sean Rudford","vip":true,"vip_ep":false} ] }, + "shows/game-of-thrones/progress/collection": { + "GET": { + "aired": 2, + "completed": 2, + "last_collected_at": "2020-08-25T20:10:33.000Z", + "seasons": [ + { + "number": 1, + "title": null, + "aired": 2, + "completed": 2, + "episodes": [ + { + "number": 1, + "completed": true, + "collected_at": "2011-12-18T12:21:20.000Z" + }, + { + "number": 2, + "completed": true, + "collected_at": "2011-12-18T14:18:22.000Z" + } + ] + } + ], + "hidden_seasons": [], + "next_episode": null, + "last_episode": { + "season": 1, + "number": 1, + "title": "Winter Is Coming", + "ids": { + "trakt": 73640, + "tvdb": 3254641, + "imdb": "tt1480055", + "tmdb": 63056, + "tvrage": 1065008299 + } + } + } + }, + "shows/game-of-thrones/progress/watched": { + "GET": { + "aired": 2, + "completed": 0, + "last_watched_at": null, + "reset_at": null, + "seasons": [ + { + "number": 1, + "title": null, + "aired": 2, + "completed": 0, + "episodes": [ + { + "number": 1, + "completed": false, + "last_watched_at": null + }, + { + "number": 2, + "completed": false, + "last_watched_at": null + } + ] + } + ], + "hidden_seasons": [], + "next_episode": { + "season": 1, + "number": 1, + "title": "Winter Is Coming", + "ids": { + "trakt": 73640, + "tvdb": 3254641, + "imdb": "tt1480055", + "tmdb": 63056, + "tvrage": 1065008299 + } + }, + "last_episode": null + } + }, "shows/the-walking-dead?extended=full": { "GET": {"title":"The Walking Dead","year":2010,"ids":{"trakt":1393,"slug":"the-walking-dead","tvdb":153021,"imdb":"tt1520211","tmdb":1402,"tvrage":25056},"overview":"The world we knew is gone. An epidemic of apocalyptic proportions has swept the globe causing the dead to rise and feed on the living. In a matter of months society has crumbled. In a world ruled by the dead, we are forced to finally start living. Based on a comic book series of the same name by Robert Kirkman, this AMC project focuses on the world after a zombie apocalypse. The series follows a police officer, Rick Grimes, who wakes up from a coma to find the world ravaged with zombies. Looking for his family, he and a group of survivors attempt to battle against the zombies in order to stay alive.\n","first_aired":"2010-10-31T07:00:00.000Z","airs":{"day":"Sunday","time":"21:00","timezone":"America/New_York"},"runtime":60,"certification":"TV-MA","network":"AMC","country":"us","trailer":"http://youtube.com/watch?v=R1v0uFms68U","homepage":"http://www.amctv.com/shows/the-walking-dead/","status":"returning series","rating":8.62829,"votes":34161,"updated_at":"2016-04-24T10:50:26.000Z","language":"en","available_translations":["en","de","sv","it","pt","tr","ru","zh","fr","es","nl","pl","bg","el","hu","ja","he","da","cs","ko","cn","bs","hr","fa","lt","lv","ro","sr","vi","et","uk","fi","th","id","ms"],"genres":["drama","action","horror","suspense"],"aired_episodes":83} } diff --git a/tests/test_shows.py b/tests/test_shows.py index 9d6784b1..2ec24078 100644 --- a/tests/test_shows.py +++ b/tests/test_shows.py @@ -131,9 +131,9 @@ def test_show_comment(): def test_collection_progress(): show = TVShow('Game of Thrones') - assert show.progress is None - assert show.collection_progress() is None - assert show.watched_progress() is None + assert isinstance(show.progress, dict) + assert isinstance(show.collection_progress(), dict) + assert isinstance(show.watched_progress(), dict) def test_rate_show(): From 908ee2dbc5de1f0a2e4a5fb4bec55bc5a62dc895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Thu, 13 Jan 2022 10:59:39 +0200 Subject: [PATCH 14/69] Add GitHub Actions workflow to publish to pypi --- .github/workflows/pypi.yml | 42 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 .github/workflows/pypi.yml diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml new file mode 100644 index 00000000..1302c245 --- /dev/null +++ b/.github/workflows/pypi.yml @@ -0,0 +1,42 @@ +# This workflow will upload a Python Package using Twine when a release is created +# For more information see: +# https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries + +name: PyPI + +on: + workflow_dispatch: ~ + release: + types: [published] + push: + tags: + - '*.*.*' + +env: + DEFAULT_PYTHON: 3.10 + +jobs: + pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python + uses: actions/setup-python@v2 + with: + python-version: ${{ env.DEFAULT_PYTHON }} + + - name: Install dependencies and build + run: | + python -m pip install --upgrade build + python -m build + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} + +# vim:ts=2:sw=2:et From a133af122b87cbea364d728243a43b02c4aa3863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Fri, 14 Jan 2022 20:04:17 +0200 Subject: [PATCH 15/69] Drop api_key (deprecated in 2.x) --- docs/getstarted.rst | 2 -- trakt/core.py | 5 +---- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/getstarted.rst b/docs/getstarted.rst index 85808f74..923dee7d 100644 --- a/docs/getstarted.rst +++ b/docs/getstarted.rst @@ -86,8 +86,6 @@ Should you choose to store your credentials in another way and not to set the `store` flag, you will need to ensure that your application applies the following settings before attempting to interact with Trakt -* `trakt.core.api_key` - * Note: api_key is deprecated in favor of OAUTH_TOKEN and will go away with the next major release * `trakt.core.OAUTH_TOKEN` * `trakt.core.CLIENT_ID` * `trakt.core.CLIENT_SECRET` diff --git a/trakt/core.py b/trakt/core.py index dd3f8931..665d4565 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -43,7 +43,7 @@ CONFIG_PATH = os.path.join(os.path.expanduser('~'), '.pytrakt.json') #: Your personal Trakt.tv OAUTH Bearer Token -OAUTH_TOKEN = api_key = None +OAUTH_TOKEN = None # OAuth token validity checked OAUTH_TOKEN_VALID = None @@ -476,9 +476,6 @@ def _bootstrap(self): if (not OAUTH_TOKEN_VALID and OAUTH_EXPIRES_AT is not None and OAUTH_REFRESH is not None): _validate_token(self) - # For backwards compatibility with trakt<=2.3.0 - if api_key is not None and OAUTH_TOKEN is None: - OAUTH_TOKEN = api_key @staticmethod def _get_first(f, *args, **kwargs): From 2fa05ddf65fcb1899ab2d0ca87bd055c49cfa27d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 11:31:10 +0200 Subject: [PATCH 16/69] Add BadResponseException exception with code -1 --- trakt/errors.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/trakt/errors.py b/trakt/errors.py index 8a54cd48..6c6a1acc 100644 --- a/trakt/errors.py +++ b/trakt/errors.py @@ -6,7 +6,13 @@ __author__ = 'Jon Nappi' __all__ = [ + # Base Exception 'TraktException', + + # Errors for use by PyTrakt + 'BadResponseException', + + # Exceptions by HTTP status code 'BadRequestException', 'OAuthException', 'ForbiddenException', @@ -32,6 +38,12 @@ def __str__(self): return self.message +class BadResponseException(TraktException): + """TraktException type to be raised when json could not be decoded""" + http_code = -1 + message = "Bad Response - Response could not be parsed" + + class BadRequestException(TraktException): """TraktException type to be raised when a 400 return code is received""" http_code = 400 From 5a3fdf1c4d53dbc196054914e2a69166ecd003cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 11 Jan 2022 22:59:59 +0200 Subject: [PATCH 17/69] Add deprecated~=1.2.13 dependency --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fa971311..b3cf4647 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ -requests>=2.25 +deprecated~=1.2.13 requests-oauthlib>=1.3 +requests>=2.25 From ae7d500729f96a72971cd2e8fc6cf2c5e8506deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 14:35:42 +0200 Subject: [PATCH 18/69] Update documentation for get_watchlist --- trakt/sync.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..ed264d3d 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -302,13 +302,18 @@ def search_by_id(query, id_type='imdb', media_type=None, slugify_query=False): @get def get_watchlist(list_type=None, sort=None): """ - Get a watchlist. - + Returns all items in a user's watchlist filtered by type. optionally with a filter for a specific item type. + + The watchlist should not be used as a list + of what the user is actively watching. + :param list_type: Optional Filter by a specific type. Possible values: movies, shows, seasons or episodes. :param sort: Optional sort. Only if the type is also sent. Possible values: rank, added, released or title. + + https://trakt.docs.apiary.io/#reference/sync/get-watchlist/get-watchlist """ valid_type = ('movies', 'shows', 'seasons', 'episodes') valid_sort = ('rank', 'added', 'released', 'title') From 69936fbd4bb4ef3b86e71ff735c6e9fa81a23d6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 14:42:12 +0200 Subject: [PATCH 19/69] Deprecate get_watched to indicate wrong api call being used --- trakt/sync.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trakt/sync.py b/trakt/sync.py index ed264d3d..0ee8b594 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -2,6 +2,8 @@ """This module contains Trakt.tv sync endpoint support functions""" from datetime import datetime, timezone +from deprecated import deprecated + from trakt.core import get, post, delete from trakt.utils import slugify, extract_ids, timestamp @@ -349,6 +351,8 @@ def get_watchlist(list_type=None, sort=None): yield results +@deprecated("This method returns watchlist, not watched list. " + "This will be fixed in PyTrakt 4.x to return watched list") @get def get_watched(list_type=None, extended=None): """Return all movies or shows a user has watched sorted by most plays. From 6d36b688b02e6687fff9da7e00fec95963eb54e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 11:41:08 +0200 Subject: [PATCH 20/69] Catch json decode errors for unhandled status codes --- trakt/core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/trakt/core.py b/trakt/core.py index dd3f8931..8132ba59 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -5,6 +5,7 @@ import json import logging import os +from json import JSONDecodeError from urllib.parse import urljoin import requests @@ -529,7 +530,12 @@ def _handle_request(self, method, url, data=None): raise self.error_map[response.status_code](response) elif response.status_code == 204: # HTTP no content return None - json_data = json.loads(response.content.decode('UTF-8', 'ignore')) + + try: + json_data = json.loads(response.content.decode('UTF-8', 'ignore')) + except JSONDecodeError: + raise errors.BadResponseException(response) + return json_data def get(self, f): From 9d46799cfffb7a2fc857ea3ccff4136e36f2c72f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 22:15:19 +0200 Subject: [PATCH 21/69] Test details of TVSeason containing TVEpisode --- tests/test_seasons.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_seasons.py b/tests/test_seasons.py index f061402c..c69ef2a2 100644 --- a/tests/test_seasons.py +++ b/tests/test_seasons.py @@ -8,6 +8,10 @@ def test_get_seasons(): got = TVShow('Game of Thrones') assert all([isinstance(s, TVSeason) for s in got.seasons]) + season = got.seasons[1] + assert season.season == 1 + assert len(season.episodes) == 10 + assert all([isinstance(episode, TVEpisode) for episode in season.episodes]) def test_get_seasons_with_year(): From bb777194a1b3d6931dc6bd1f17d8504b626437d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 12 Jan 2022 21:29:10 +0200 Subject: [PATCH 22/69] TVShow: Use /seasons endpoint to fill seasons and episodes This will make one api request to create list of TVSeason with TVEpisode objects. --- trakt/tv.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..7fabd866 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -377,15 +377,23 @@ def related(self): @get def seasons(self): """A list of :class:`TVSeason` objects representing all of this show's - seasons + seasons which each contain :class:`TVEpisode` elements """ if self._seasons is None: - data = yield self.ext + '/seasons?extended=full' + data = yield self.ext + '/seasons?extended=episodes' self._seasons = [] for season in data: extract_ids(season) - self._seasons.append(TVSeason(self.title, - season['number'], **season)) + + # Prepare episodes + episodes = [] + for ep in season.pop('episodes', []): + episode = TVEpisode(show=self.title, **ep) + episodes.append(episode) + season['episodes'] = episodes + + season = TVSeason(self.title, season['number'], **season) + self._seasons.append(season) yield self._seasons @property From 123d7c3b4ee533289c14c93d618461d5d97ca7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 22:14:40 +0200 Subject: [PATCH 23/69] Avoid poisoning "number" into TVSeason --- trakt/tv.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trakt/tv.py b/trakt/tv.py index 7fabd866..c7fe6090 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -392,7 +392,8 @@ def seasons(self): episodes.append(episode) season['episodes'] = episodes - season = TVSeason(self.title, season['number'], **season) + number = season.pop('number') + season = TVSeason(self.title, number, **season) self._seasons.append(season) yield self._seasons From d11e29bea3d1c76899a1e990c4e50b1dbbe327a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 22:36:32 +0200 Subject: [PATCH 24/69] Add shows/the-flash-2014/seasons?extended=episodes mock data --- tests/mock_data/seasons.json | 178 +++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/tests/mock_data/seasons.json b/tests/mock_data/seasons.json index 9873856f..c487ce25 100644 --- a/tests/mock_data/seasons.json +++ b/tests/mock_data/seasons.json @@ -17,6 +17,184 @@ {"number":4,"ids":{"trakt":5,"tvdb":522882,"tmdb":3628,"tvrage":null}} ] }, + "shows/the-flash-2014/seasons?extended=episodes": { + "GET": [ + { + "number": 0, + "ids": { "trakt": 126556, "tvdb": 578365, "tmdb": 79954, "tvrage": null }, + "episodes": [ + { + "season": 0, + "number": 1, + "title": "Chronicles Of Cisco (1)", + "ids": { "trakt": 2221945, "tvdb": 7444560, "imdb": "tt5656730", "tmdb": 1220887, "tvrage": null } + }, + { + "season": 0, + "number": 2, + "title": "Chronicles Of Cisco (2)", + "ids": { "trakt": 2221946, "tvdb": 7444566, "imdb": "tt5666962", "tmdb": 1220888, "tvrage": null } + } + ] + }, + { + "number": 1, + "ids": { "trakt": 61430, "tvdb": 578373, "tmdb": 60523, "tvrage": 36939 }, + "episodes": [ + { + "season": 1, + "number": 1, + "title": "Pilot", + "ids": { "trakt": 962074, "tvdb": 4812524, "imdb": "tt3187092", "tmdb": 977122, "tvrage": 1065564472 } + }, + { + "season": 1, + "number": 2, + "title": "Fastest Man Alive", + "ids": { "trakt": 962075, "tvdb": 4929322, "imdb": "tt3819518", "tmdb": 1005650, "tvrage": 1065603573 } + }, + { + "season": 1, + "number": 3, + "title": "Things You Can't Outrun", + "ids": { "trakt": 962076, "tvdb": 4929325, "imdb": "tt3826166", "tmdb": 1005651, "tvrage": 1065603574 } + }, + { + "season": 1, + "number": 4, + "title": "Going Rogue", + "ids": { "trakt": 962077, "tvdb": 4936770, "imdb": "tt3881958", "tmdb": 1005652, "tvrage": 1065609025 } + }, + { + "season": 1, + "number": 5, + "title": "Plastique", + "ids": { "trakt": 999423, "tvdb": 5025023, "imdb": "tt3887830", "tmdb": 1010677, "tvrage": 1065625291 } + }, + { + "season": 1, + "number": 6, + "title": "The Flash is Born", + "ids": { "trakt": 999424, "tvdb": 5028737, "imdb": "tt3920288", "tmdb": 1010678, "tvrage": 1065702880 } + }, + { + "season": 1, + "number": 7, + "title": "Power Outage", + "ids": { "trakt": 999426, "tvdb": 5028738, "imdb": "tt3922506", "tmdb": 1010679, "tvrage": 1065709260 } + }, + { + "season": 1, + "number": 8, + "title": "Flash vs. Arrow (I)", + "ids": { "trakt": 999428, "tvdb": 5028739, "imdb": "tt3899320", "tmdb": 1010680, "tvrage": 1065710605 } + }, + { + "season": 1, + "number": 9, + "title": "The Man in the Yellow Suit", + "ids": { "trakt": 999429, "tvdb": 5042818, "imdb": "tt4017786", "tmdb": 1018354, "tvrage": 1065711822 } + }, + { + "season": 1, + "number": 10, + "title": "Revenge of the Rogues", + "ids": { "trakt": 999431, "tvdb": 5052260, "imdb": "tt4016102", "tmdb": 1018355, "tvrage": 1065644215 } + }, + { + "season": 1, + "number": 11, + "title": "The Sound and the Fury", + "ids": { "trakt": 1701689, "tvdb": 5073549, "imdb": "tt4111294", "tmdb": 1037712, "tvrage": 1065735300 } + }, + { + "season": 1, + "number": 12, + "title": "Crazy for You", + "ids": { "trakt": 1701690, "tvdb": 5073556, "imdb": "tt4105618", "tmdb": 1037713, "tvrage": 1065683600 } + }, + { + "season": 1, + "number": 13, + "title": "The Nuclear Man", + "ids": { "trakt": 1701691, "tvdb": 5088525, "imdb": "tt4138324", "tmdb": 1037714, "tvrage": 1065735301 } + }, + { + "season": 1, + "number": 14, + "title": "Fallout", + "ids": { "trakt": 1718914, "tvdb": 5104336, "imdb": "tt4138326", "tmdb": 1039988, "tvrage": 1065738929 } + }, + { + "season": 1, + "number": 15, + "title": "Out of Time", + "ids": { "trakt": 1718915, "tvdb": 5104337, "imdb": "tt4138338", "tmdb": 1039989, "tvrage": 1065738930 } + }, + { + "season": 1, + "number": 16, + "title": "Rogue Time", + "ids": { "trakt": 1718916, "tvdb": 5104338, "imdb": "tt4138340", "tmdb": 1039990, "tvrage": 1065738931 } + }, + { + "season": 1, + "number": 17, + "title": "Tricksters", + "ids": { "trakt": 1718917, "tvdb": 5104339, "imdb": "tt4138344", "tmdb": 1039991, "tvrage": 1065728023 } + }, + { + "season": 1, + "number": 18, + "title": "All-Star Team Up", + "ids": { "trakt": 1725151, "tvdb": 5110414, "imdb": "tt4138352", "tmdb": 1047470, "tvrage": 1065747417 } + }, + { + "season": 1, + "number": 19, + "title": "Who Is Harrison Wells?", + "ids": { "trakt": 1765383, "tvdb": 5166508, "imdb": "tt4138350", "tmdb": 1051229, "tvrage": null } + }, + { + "season": 1, + "number": 20, + "title": "The Trap", + "ids": { "trakt": 1765384, "tvdb": 5166509, "imdb": "tt4138356", "tmdb": 1051230, "tvrage": null } + }, + { + "season": 1, + "number": 21, + "title": "Grodd Lives", + "ids": { "trakt": 1765385, "tvdb": 5166510, "imdb": "tt4138376", "tmdb": 1051231, "tvrage": null } + }, + { + "season": 1, + "number": 22, + "title": "Rogue Air", + "ids": { "trakt": 1765386, "tvdb": 5163053, "imdb": "tt4138378", "tmdb": 1051232, "tvrage": null } + }, + { + "season": 1, + "number": 23, + "title": "Fast Enough", + "ids": { "trakt": 1798337, "tvdb": 5166511, "imdb": "tt4146568", "tmdb": 1051233, "tvrage": null } + } + ] + }, + { + "number": 2, + "ids": { "trakt": 110984, "tvdb": 626964, "tmdb": 66922, "tvrage": null }, + "episodes": [ + { + "season": 2, + "number": 1, + "title": "The Man Who Saved Central City", + "ids": { "trakt": 1866102, "tvdb": 5260562, "imdb": "tt4346792", "tmdb": 1063859, "tvrage": null } + } + ] + } + ] + }, "shows/game-of-thrones/seasons?extended=images": { "GET": [ {"number":0,"ids":{"trakt":1,"tvdb":137481,"tmdb":3627,"tvrage":null},"images":{"poster":{"full":"https://walter.trakt.us/images/seasons/000/002/145/posters/original/41221f3712.jpg?1409351965","medium":"https://walter.trakt.us/images/seasons/000/002/145/posters/medium/41221f3712.jpg?1409351965","thumb":"https://walter.trakt.us/images/seasons/000/002/145/posters/thumb/41221f3712.jpg?1409351965"},"thumb":{"full":"https://walter.trakt.us/images/seasons/000/002/145/thumbs/original/c41b46dd09.jpg?1409351965"}}}, From fc7a72b5b790795c01cf2bc6cc0be733374cd8ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 Jan 2022 00:05:17 +0200 Subject: [PATCH 25/69] Drop classes extending from object This is not needed for Python3 as the "old style" classes don't exist and inheritance from object is implicit. - https://stackoverflow.com/questions/15374857/should-all-python-classes-extend-object - http://docs.python.org/release/2.5.2/ref/node33.html --- tests/test_sync.py | 2 +- trakt/calendar.py | 2 +- trakt/core.py | 2 +- trakt/movies.py | 2 +- trakt/people.py | 8 ++++---- trakt/sync.py | 4 ++-- trakt/tv.py | 6 +++--- trakt/users.py | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/test_sync.py b/tests/test_sync.py index e13bc3da..de335be5 100644 --- a/tests/test_sync.py +++ b/tests/test_sync.py @@ -10,7 +10,7 @@ -class FakeMedia(object): +class FakeMedia: """Mock media type object to use with mock sync requests""" media_type = 'fake' diff --git a/trakt/calendar.py b/trakt/calendar.py index 5fdae2d0..3f04d0ca 100644 --- a/trakt/calendar.py +++ b/trakt/calendar.py @@ -12,7 +12,7 @@ 'MySeasonCalendar', 'MovieCalendar', 'MyMovieCalendar'] -class Calendar(object): +class Calendar: """Base :class:`Calendar` type serves as a foundation for other Calendar types """ diff --git a/trakt/core.py b/trakt/core.py index dd3f8931..f0bad5ad 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -441,7 +441,7 @@ def load_config(): APPLICATION_ID = config_data.get('APPLICATION_ID', None) -class Core(object): +class Core: """This class contains all of the functionality required for interfacing with the Trakt.tv API """ diff --git a/trakt/movies.py b/trakt/movies.py index fd5f15cf..328e5af6 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -81,7 +81,7 @@ def updated_movies(timestamp=None): 'note', 'release_type']) -class Movie(object): +class Movie: """A Class representing a Movie object""" def __init__(self, title, year=None, slug=None, **kwargs): super(Movie, self).__init__() diff --git a/trakt/people.py b/trakt/people.py index 074dfdb5..6f9a3384 100644 --- a/trakt/people.py +++ b/trakt/people.py @@ -9,7 +9,7 @@ 'TVCredits'] -class Person(object): +class Person: """A Class representing a trakt.tv Person such as an Actor or Director""" def __init__(self, name, slug=None, **kwargs): super(Person, self).__init__() @@ -112,7 +112,7 @@ def __str__(self): __repr__ = __str__ -class ActingCredit(object): +class ActingCredit: """An individual credit for a :class:`Person` who played a character in a Movie or TV Show """ @@ -130,7 +130,7 @@ def __str__(self): __repr__ = __str__ -class CrewCredit(object): +class CrewCredit: """An individual crew credit for a :class:`Person` who had an off-screen job on a Movie or a TV Show """ @@ -148,7 +148,7 @@ def __str__(self): __repr__ = __str__ -class Credits(object): +class Credits: """A base type representing a :class:`Person`'s credits for Movies or TV Shows """ diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..c3d75c42 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -431,7 +431,7 @@ def delete_checkin(): yield "checkin" -class Scrobbler(object): +class Scrobbler: """Scrobbling is a seemless and automated way to track what you're watching in a media center. This class allows the media center to easily send events that correspond to starting, pausing, stopping or finishing @@ -504,7 +504,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.finish() -class SearchResult(object): +class SearchResult: """A SearchResult is an individual result item from the trakt.tv search API. It wraps a single media entity whose type is indicated by the type field. diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..9c14dc4e 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -195,7 +195,7 @@ def anticipated_shows(page=1, limit=10, extended=None): yield [TVShow(**show['show']) for show in data] -class TVShow(object): +class TVShow: """A Class representing a TV Show object.""" def __init__(self, title='', slug=None, **kwargs): @@ -499,7 +499,7 @@ def __str__(self): __repr__ = __str__ -class TVSeason(object): +class TVSeason: """Container for TV Seasons""" def __init__(self, show, season=1, slug=None, **kwargs): @@ -639,7 +639,7 @@ def __len__(self): __repr__ = __str__ -class TVEpisode(object): +class TVEpisode: """Container for TV Episodes""" def __init__(self, show, season, number=-1, **kwargs): diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..9484c752 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -200,7 +200,7 @@ def unlike(self): yield uri.format(username=slugify(self.creator), id=self.trakt) -class User(object): +class User: """A Trakt.tv User""" def __init__(self, username, **kwargs): super(User, self).__init__() From bc77e26d3e862c14667fc363873d82febbc33899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 Jan 2022 00:57:44 +0200 Subject: [PATCH 26/69] Cleanup: __iter__ doesn't take any args --- trakt/users.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..f6e0b358 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -72,9 +72,9 @@ def __init__(self, *args, **kwargs): super(UserList, self).__init__() self._items = list() - def __iter__(self, *args, **kwargs): + def __iter__(self): """Iterate over the items in this user list""" - return self._items.__iter__(*args, **kwargs) + return self._items.__iter__() @classmethod @post From 6d268694c3a90da0d2aaed88e643127b66b78d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 16 Jan 2022 02:15:18 +0200 Subject: [PATCH 27/69] Remove old (python<3.0) super constructor syntax --- tests/conftest.py | 2 +- trakt/calendar.py | 2 +- trakt/movies.py | 2 +- trakt/people.py | 2 +- trakt/sync.py | 2 +- trakt/tv.py | 6 +++--- trakt/users.py | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 16129eeb..ef1770de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -27,7 +27,7 @@ class MockCore(trakt.core.Core): def __init__(self, *args, **kwargs): - super(MockCore, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.mock_data = {} for mock_file in MOCK_DATA_FILES: with open(mock_file, encoding='utf-8') as f: diff --git a/trakt/calendar.py b/trakt/calendar.py index 5fdae2d0..d5a5980e 100644 --- a/trakt/calendar.py +++ b/trakt/calendar.py @@ -26,7 +26,7 @@ def __init__(self, date=None, days=7, extended=None): :param days: Number of days for this :class:`Calendar`. Defaults to 7 days """ - super(Calendar, self).__init__() + super().__init__() self.date = date or now() self.days = days self._calendar = [] diff --git a/trakt/movies.py b/trakt/movies.py index fd5f15cf..cebdea20 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -84,7 +84,7 @@ def updated_movies(timestamp=None): class Movie(object): """A Class representing a Movie object""" def __init__(self, title, year=None, slug=None, **kwargs): - super(Movie, self).__init__() + super().__init__() self.media_type = 'movies' self.title = title self.year = int(year) if year is not None else year diff --git a/trakt/people.py b/trakt/people.py index 074dfdb5..0d6827d4 100644 --- a/trakt/people.py +++ b/trakt/people.py @@ -12,7 +12,7 @@ class Person(object): """A Class representing a trakt.tv Person such as an Actor or Director""" def __init__(self, name, slug=None, **kwargs): - super(Person, self).__init__() + super().__init__() self.name = name self.biography = self.birthplace = self.tmdb_id = self.birthday = None self.job = self.character = self._images = self._movie_credits = None diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..9ea717be 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -448,7 +448,7 @@ def __init__(self, media, progress, app_version, app_date): :param app_version: The media center application version :param app_date: The date that *app_version* was released """ - super(Scrobbler, self).__init__() + super().__init__() self.progress, self.version = progress, app_version self.media, self.date = media, app_date if self.progress > 0: diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..bf18acfa 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -199,7 +199,7 @@ class TVShow(object): """A Class representing a TV Show object.""" def __init__(self, title='', slug=None, **kwargs): - super(TVShow, self).__init__() + super().__init__() self.media_type = 'shows' self.top_watchers = self.top_episodes = self.year = self.tvdb = None self.imdb = self.genres = self.certification = self.network = None @@ -503,7 +503,7 @@ class TVSeason(object): """Container for TV Seasons""" def __init__(self, show, season=1, slug=None, **kwargs): - super(TVSeason, self).__init__() + super().__init__() self.show = show self.season = season self.slug = slug or slugify(show) @@ -643,7 +643,7 @@ class TVEpisode(object): """Container for TV Episodes""" def __init__(self, show, season, number=-1, **kwargs): - super(TVEpisode, self).__init__() + super().__init__() self.media_type = 'episodes' self.show = show self.season = season diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..15237db4 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -69,7 +69,7 @@ class UserList(namedtuple('UserList', ['name', 'description', 'privacy', """A list created by a Trakt.tv :class:`User`""" def __init__(self, *args, **kwargs): - super(UserList, self).__init__() + super().__init__() self._items = list() def __iter__(self, *args, **kwargs): @@ -203,7 +203,7 @@ def unlike(self): class User(object): """A Trakt.tv User""" def __init__(self, username, **kwargs): - super(User, self).__init__() + super().__init__() self.username = username self._calendar = self._last_activity = self._watching = None self._movies = self._movie_collection = self._movies_watched = None From 19b599daf5c320fe4813a986dc74a62287bd9af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 17 Jan 2022 11:29:22 +0200 Subject: [PATCH 28/69] Refactor slugify to handle special cases --- trakt/utils.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/trakt/utils.py b/trakt/utils.py index fbf54dc5..f9785b4e 100644 --- a/trakt/utils.py +++ b/trakt/utils.py @@ -14,10 +14,16 @@ def slugify(value): Adapted from django.utils.text.slugify """ - nfkd_form = unicodedata.normalize('NFKD', value) - decoded = nfkd_form.encode('ascii', 'ignore').decode('utf-8') - value = re.sub(r'[^\w\s-]', ' ', decoded).strip().lower() - return re.sub(r'[-\s]+', '-', value) + value = unicodedata.normalize('NFKD', value) + # special case, "ascii" encode would just remove it + value = value.replace("’", '-') + value = value.encode('ascii', 'ignore').decode('utf-8') + value = value.lower() + value = re.sub(r'[^\w\s-]', ' ', value) + value = re.sub(r'[-\s]+', '-', value) + value = value.strip('-') + + return value def airs_date(airs_at): From 9a391e372c258ae0c5d30e1dec7608c3acb28582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 17 Jan 2022 11:29:33 +0200 Subject: [PATCH 29/69] Add two slugify special cases to test --- tests/test_utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_utils.py b/tests/test_utils.py index 9b6b5555..9c2526a0 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -12,6 +12,8 @@ def test_slugify(): (' LOOK AT MY WHITESPACE ', 'look-at-my-whitespace'), ("Marvel's Agents of S.H.I.E.L.D.", 'marvel-s-agents-of-s-h-i-e-l-d'), ('Naruto Shippūden', 'naruto-shippuden'), + ('Re:ZERO -Starting Life in Another World-', 're-zero-starting-life-in-another-world'), + ('So I’m a Spider, So What?', 'so-i-m-a-spider-so-what'), ] for inp, expected in test_data: From 18906869d0f0c2bf6b824951ef3666faea4da8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Jan 2022 15:01:18 +0200 Subject: [PATCH 30/69] Add Bad Gateway exception --- trakt/errors.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/trakt/errors.py b/trakt/errors.py index 8a54cd48..9dce8807 100644 --- a/trakt/errors.py +++ b/trakt/errors.py @@ -17,6 +17,7 @@ 'LockedUserAccountException', 'RateLimitException', 'TraktInternalException', + 'TraktBadGateway', 'TraktUnavailable', ] @@ -92,6 +93,12 @@ class TraktInternalException(TraktException): message = 'Internal Server Error' +class TraktBadGateway(TraktException): + """TraktException type to be raised when a 502 error is raised""" + http_code = 502 + message = 'Trakt Unavailable - Bad Gateway' + + class TraktUnavailable(TraktException): """TraktException type to be raised when a 503 error is raised""" http_code = 503 From 80de702b23df0015586f5cf1d1ffebdd70c5904a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 30 Jan 2022 19:35:28 +0200 Subject: [PATCH 31/69] Don't log headers to protect privacy --- trakt/core.py | 1 - 1 file changed, 1 deletion(-) diff --git a/trakt/core.py b/trakt/core.py index dd3f8931..2ba2c039 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -516,7 +516,6 @@ def _handle_request(self, method, url, data=None): self.logger.debug('%s: %s', method, url) HEADERS['trakt-api-key'] = CLIENT_ID HEADERS['Authorization'] = 'Bearer {0}'.format(OAUTH_TOKEN) - self.logger.debug('headers: %s', str(HEADERS)) self.logger.debug('method, url :: %s, %s', method, url) if method == 'get': # GETs need to pass data as params, not body response = session.request(method, url, headers=HEADERS, From 350a5302ed4b1b69d179ed749500f8d46a3b316e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 31 Jan 2022 00:13:05 +0200 Subject: [PATCH 32/69] Return responses of Scrobble methods --- trakt/sync.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..12fd75a4 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -456,15 +456,15 @@ def __init__(self, media, progress, app_version, app_date): def start(self): """Start scrobbling this :class:`Scrobbler`'s *media* object""" - self._post('scrobble/start') + return self._post('scrobble/start') def pause(self): """Pause the scrobbling of this :class:`Scrobbler`'s *media* object""" - self._post('scrobble/pause') + return self._post('scrobble/pause') def stop(self): """Stop the scrobbling of this :class:`Scrobbler`'s *media* object""" - self._post('scrobble/stop') + return self._post('scrobble/stop') def finish(self): """Complete the scrobbling this :class:`Scrobbler`'s *media* object""" @@ -477,7 +477,7 @@ def update(self, progress): object """ self.progress = progress - self.start() + return self.start() @post def _post(self, uri): @@ -488,7 +488,8 @@ def _post(self, uri): payload = dict(progress=self.progress, app_version=self.version, date=self.date) payload.update(self.media.to_json_singular()) - yield uri, payload + response = yield uri, payload + yield response def __enter__(self): """Context manager support for `with Scrobbler` syntax. Begins From 629b425115e706c9727a25ab13c82c1ded7c81f1 Mon Sep 17 00:00:00 2001 From: Baptiste Roux Date: Sat, 19 Feb 2022 13:10:00 +0100 Subject: [PATCH 33/69] Return season slug from seasons function --- trakt/tv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..b6531f06 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -385,7 +385,7 @@ def seasons(self): for season in data: extract_ids(season) self._seasons.append(TVSeason(self.title, - season['number'], **season)) + season['number'], self.slug, **season)) yield self._seasons @property From 31d6737571b14ee37938bcccab6cbbe6a876c180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 21:47:18 +0200 Subject: [PATCH 34/69] Add details parameter to BadResponseException constructor --- trakt/errors.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/trakt/errors.py b/trakt/errors.py index 6c6a1acc..30e01694 100644 --- a/trakt/errors.py +++ b/trakt/errors.py @@ -43,6 +43,10 @@ class BadResponseException(TraktException): http_code = -1 message = "Bad Response - Response could not be parsed" + def __init__(self, response=None, details=None): + super().__init__(response) + self.details = details + class BadRequestException(TraktException): """TraktException type to be raised when a 400 return code is received""" From 27d90b1a4c4850889accd5234356a8253e5b59a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sat, 15 Jan 2022 18:09:04 +0200 Subject: [PATCH 35/69] Add details to BadResponseException of json error --- trakt/core.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trakt/core.py b/trakt/core.py index 8132ba59..6dcaa04a 100644 --- a/trakt/core.py +++ b/trakt/core.py @@ -16,6 +16,7 @@ from requests_oauthlib import OAuth2Session from datetime import datetime, timedelta, timezone from trakt import errors +from trakt.errors import BadResponseException __author__ = 'Jon Nappi' __all__ = ['Airs', 'Alias', 'Comment', 'Genre', 'get', 'delete', 'post', 'put', @@ -533,8 +534,8 @@ def _handle_request(self, method, url, data=None): try: json_data = json.loads(response.content.decode('UTF-8', 'ignore')) - except JSONDecodeError: - raise errors.BadResponseException(response) + except JSONDecodeError as e: + raise BadResponseException(response, f"Unable to parse JSON: {e}") return json_data From d6fe4dddc9076444bede34b69b41b879624731f7 Mon Sep 17 00:00:00 2001 From: twolaw Date: Mon, 13 Jun 2022 20:18:07 +0200 Subject: [PATCH 36/69] fix wrong uri in sync.py --- trakt/sync.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..0fd517f9 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -357,7 +357,7 @@ def get_watched(list_type=None, extended=None): if list_type and list_type not in valid_type: raise ValueError('list_type must be one of {}'.format(valid_type)) - uri = 'sync/watchlist' + uri = 'sync/watched' if list_type: uri += '/{}'.format(list_type) @@ -394,7 +394,7 @@ def get_collection(list_type=None, extended=None): if list_type and list_type not in valid_type: raise ValueError('list_type must be one of {}'.format(valid_type)) - uri = 'sync/watchlist' + uri = 'sync/collection' if list_type: uri += '/{}'.format(list_type) From 80fae411e1042d313e79bb7cc3ae639847d54370 Mon Sep 17 00:00:00 2001 From: twolaw Date: Mon, 13 Jun 2022 23:05:51 +0200 Subject: [PATCH 37/69] fix season number in show_collection --- trakt/users.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..ed825ad5 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -372,7 +372,8 @@ def show_collection(self): s = show.pop('show') extract_ids(s) sh = TVShow(**s) - sh._seasons = [TVSeason(show=sh.title, **sea) + sh._seasons = [TVSeason(show=sh.title, + season=sea['number'], **sea) for sea in show.pop('seasons')] self._show_collection.append(sh) yield self._show_collection From 2613efbe0136cc6e61f8d361892ae03273883926 Mon Sep 17 00:00:00 2001 From: twolaw Date: Sat, 18 Jun 2022 10:41:46 +0200 Subject: [PATCH 38/69] type added to Userlist --- trakt/users.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trakt/users.py b/trakt/users.py index 523b83d3..b8fc28e1 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -61,8 +61,9 @@ def unfollow(user_name): class UserList(namedtuple('UserList', ['name', 'description', 'privacy', - 'display_numbers', 'allow_comments', - 'sort_by', 'sort_how', 'created_at', + 'type', 'display_numbers', + 'allow_comments', 'sort_by', + 'sort_how', 'created_at', 'updated_at', 'item_count', 'comment_count', 'likes', 'trakt', 'slug', 'user', 'creator'])): From 27f9375451cc0979a1444f0d8ab91a56796ab42f Mon Sep 17 00:00:00 2001 From: twolaw Date: Sat, 18 Jun 2022 10:46:35 +0200 Subject: [PATCH 39/69] add type value to lists --- tests/mock_data/users.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/mock_data/users.json b/tests/mock_data/users.json index f0222c3b..3e9176e2 100644 --- a/tests/mock_data/users.json +++ b/tests/mock_data/users.json @@ -47,6 +47,7 @@ "name":"Star Wars in NEW machete order", "description":"Some descriptive text", "privacy":"private", + "type":"personal", "display_numbers":true, "allow_comments":false, "updated_at":"2014-10-11T17:00:54.000Z", @@ -188,7 +189,7 @@ {"type":"show","show":{"title":"Breaking Bad","year":2008,"ids":{"trakt":1,"slug":"breaking-bad","tvdb":81189,"imdb":"tt0903747","tmdb":1396,"tvrage":18164}},"comment":{"id":199,"comment":"Skyler, I AM THE DANGER.","spoiler":false,"review":false,"parent_id":0,"created_at":"2015-02-18T06:02:30.000Z","replies":0,"likes":0,"user_rating":10,"user":{"username":"justin","private":false,"name":"Justin N.","vip":true,"vip_ep":false}}}, {"type":"season","season":{"number":1,"ids":{"trakt":3958,"tvdb":274431,"tmdb":60394,"tvrage":38049}},"show":{"title":"Gotham","year":2014,"ids":{"trakt":869,"slug":"gotham","tvdb":274431,"imdb":"tt3749900","tmdb":60708,"tvrage":38049}},"comment":{"id":220,"comment":"Kicking off season 1 for a new Batman show.","spoiler":false,"review":false,"parent_id":0,"created_at":"2015-04-21T06:53:25.000Z","replies":0,"likes":0,"user_rating":8,"user":{"username":"justin","private":false,"name":"Justin N.","vip":true,"vip_ep":false}}}, {"type":"episode","episode":{"season":1,"number":1,"title":"Jim Gordon","ids":{"trakt":63958,"tvdb":4768720,"imdb":"tt3216414","tmdb":975968,"tvrage":1065564827}},"show":{"title":"Gotham","year":2014,"ids":{"trakt":869,"slug":"gotham","tvdb":274431,"imdb":"tt3749900","tmdb":60708,"tvrage":38049}},"comment":{"id":229,"comment":"Is this the OC?","spoiler":false,"review":false,"parent_id":0,"created_at":"2015-04-21T15:42:31.000Z","replies":1,"likes":0,"user_rating":7,"user":{"username":"justin","private":false,"name":"Justin N.","vip":true,"vip_ep":false}}}, - {"type":"list","list":{"name":"Star Wars","description":"The complete Star Wars saga!","privacy":"public","display_numbers":false,"allow_comments":true,"updated_at":"2015-04-22T22:01:39.000Z","item_count":8,"comment_count":0,"likes":0,"ids":{"trakt":51,"slug":"star-wars"}},"comment":{"id":268,"comment":"May the 4th be with you!","spoiler":false,"review":false,"parent_id":0,"created_at":"2014-12-08T17:34:51.000Z","replies":0,"likes":0,"user_rating":null,"user":{"username":"justin","private":false,"name":"Justin N.","vip":true,"vip_ep":false}}} + {"type":"list","list":{"name":"Star Wars","description":"The complete Star Wars saga!","privacy":"public","type":"personal","display_numbers":false,"allow_comments":true,"updated_at":"2015-04-22T22:01:39.000Z","item_count":8,"comment_count":0,"likes":0,"ids":{"trakt":51,"slug":"star-wars"}},"comment":{"id":268,"comment":"May the 4th be with you!","spoiler":false,"review":false,"parent_id":0,"created_at":"2014-12-08T17:34:51.000Z","replies":0,"likes":0,"user_rating":null,"user":{"username":"justin","private":false,"name":"Justin N.","vip":true,"vip_ep":false}}} ] }, "users/sean/lists": { @@ -197,6 +198,7 @@ "name":"Star Wars in machete order", "description":"Some descriptive text", "privacy":"public", + "type":"personal", "display_numbers":true, "allow_comments":true, "sort_by": "rank", @@ -220,6 +222,7 @@ "name":"Vampires FTW", "description":"These suck, but in a good way!", "privacy":"public", + "type":"personal", "display_numbers":false, "allow_comments":true, "sort_by": "rank", @@ -244,6 +247,7 @@ "name":"Star Wars in machete order", "description":"Some descriptive text", "privacy":"public", + "type":"personal", "display_numbers":true, "allow_comments":true, "sort_by": "rank", @@ -261,6 +265,7 @@ "name":"Star Wars in machete order", "description":"Some descriptive text", "privacy":"public", + "type":"personal", "display_numbers":true, "allow_comments":true, "sort_by": "rank", @@ -277,6 +282,7 @@ "name":"Star Wars in NEW machete order", "description":"Some descriptive text", "privacy":"private", + "type":"personal", "display_numbers":true, "allow_comments":false, "sort_by": "rank", From fb98340fbbd34084115e141ef39d09a3d4bd08b9 Mon Sep 17 00:00:00 2001 From: twolaw Date: Sat, 22 Oct 2022 11:43:49 +0200 Subject: [PATCH 40/69] add show_id attribute to TVEpisode found from search --- trakt/sync.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trakt/sync.py b/trakt/sync.py index c4bf7cfe..9f55987b 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -221,6 +221,7 @@ def get_search_results(query, search_type=None, slugify_query=False): from trakt.tv import TVEpisode show = media_item.pop('show') result.media = TVEpisode(show.get('title', None), + show_id=show['ids'].get('trakt'), **media_item.pop('episode')) elif media_item['type'] == 'person': from trakt.people import Person @@ -286,7 +287,9 @@ def search_by_id(query, id_type='imdb', media_type=None, slugify_query=False): from trakt.tv import TVEpisode show = d.pop('show') extract_ids(d['episode']) - results.append(TVEpisode(show.get('title', None), **d['episode'])) + results.append(TVEpisode(show.get('title', None), + show_id=show['ids'].get('trakt'), + **d.pop('episode'))) elif 'movie' in d: from trakt.movies import Movie results.append(Movie(**d.pop('movie'))) From da02d9575bf5e208236ed24a507e2ba75da9204b Mon Sep 17 00:00:00 2001 From: twolaw Date: Sun, 23 Oct 2022 14:51:26 +0200 Subject: [PATCH 41/69] uses show_id instead of slug when available --- trakt/tv.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/trakt/tv.py b/trakt/tv.py index 9c60d9f1..9b3c04ca 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -694,8 +694,11 @@ def comments(self): @property def ext(self): + show_id = getattr(self, "show_id", None) + if not show_id: + show_id = slugify(self.show) return 'shows/{id}/seasons/{season}/episodes/{episode}'.format( - id=slugify(self.show), season=self.season, episode=self.number + id=show_id, season=self.season, episode=self.number ) @property From 72a80d54394431b07ff7acb7446f5d077adb1ccc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 15:57:47 +0300 Subject: [PATCH 42/69] Add name to authors --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 52a42816..14b1689c 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -6,5 +6,5 @@ pass version_info = (3, 4, 0) -__author__ = 'Jon Nappi' +__author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From 5440af3f28d748409e9bbf994dc6b77445ccbffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 15:57:54 +0300 Subject: [PATCH 43/69] Set version to 3.4.1 --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 14b1689c..8d05a23e 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 0) +version_info = (3, 4, 1) __author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From becb165dd8024baae670b0d2c727a94ab8566468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 17:09:50 +0300 Subject: [PATCH 44/69] Set version to 3.4.2 --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 8d05a23e..7f501aaf 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 1) +version_info = (3, 4, 2) __author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From b3a46e9d9b06510ab9f43287c985ffd830858b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 17:33:16 +0300 Subject: [PATCH 45/69] Set version to 3.4.3 --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 7f501aaf..51b3d6e3 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 2) +version_info = (3, 4, 3) __author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From 4a2d6f4431ca683561d8f74c14c24fcdc4c2b0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 17:46:09 +0300 Subject: [PATCH 46/69] Set version to 3.4.4 --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 51b3d6e3..de4567f0 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 3) +version_info = (3, 4, 4) __author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From 62f73db31e4809e5f9f25995a7abcf0a0a097f56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:28:45 +0300 Subject: [PATCH 47/69] Update project homepage, name package as "pytrakt" --- setup.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 847e11a2..3885086d 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ import trakt -__author__ = 'Jon Nappi' +__author__ = 'Elan Ruusamäe, Jon Nappi' with open('README.rst') as f: readme = f.read() @@ -16,13 +16,13 @@ 'Trakt.tv REST API.') setup( - name='trakt', + name='pytrakt', version=trakt.__version__, description=description, long_description='\n'.join([readme, history]), - author='Jonathan Nappi', - author_email='moogar0880@gmail.com', - url='https://github.com/moogar0880/PyTrakt', + author='Elan Ruusamäe', + author_email='glen@pld-linux.org', + url='https://github.com/glensc/python-pytrakt', packages=packages, install_requires=requires, license='Apache 2.0', From 4bd4bb76d10d3673b302ae30ee8e3e0a1d23eaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:38:27 +0300 Subject: [PATCH 48/69] Update some project urls --- README.rst | 14 +++++++------- docs/index.rst | 12 ++++++------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.rst b/README.rst index b387889a..f4f5f66f 100644 --- a/README.rst +++ b/README.rst @@ -34,19 +34,19 @@ To install with `pip `_, just run this in your te Get the code ^^^^^^^^^^^^ -trakt is available on `GitHub `_. +trakt is available on `GitHub `_. You can either clone the public repository:: - $ git clone git://github.com/moogar0880/PyTrakt.git + $ git clone git://github.com/glensc/python-pytrakt.git -Download the `tarball `_:: +Download the `tarball `_:: - $ curl -OL https://github.com/moogar0880/PyTrakt/tarball/master + $ curl -OL https://github.com/glensc/python-pytrakt/tarball/master -Or, download the `zipball `_:: +Or, download the `zipball `_:: - $ curl -OL https://github.com/moogar0880/PyTrakt/zipball/master + $ curl -OL https://github.com/glensc/python-pytrakt/zipball/main Once you have a copy of the source, you can embed it in your Python package, or install it into your site-packages easily:: @@ -58,7 +58,7 @@ Contributing Pull requests are graciously accepted. Any pull request should not break any tests and should pass `flake8` style checks (unless otherwise warranted). Additionally the user opening the Pull Request should ensure that their username and a link to -their GitHub page appears in `CONTRIBUTORS.md `_. +their GitHub page appears in `CONTRIBUTORS.md `_. TODO diff --git a/docs/index.rst b/docs/index.rst index 9e3a7529..fbdcc9f7 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,19 +28,19 @@ To install with `pip `_, just run this in your te Get the code ^^^^^^^^^^^^ -trakt is available on `GitHub `_. +trakt is available on `GitHub `_. You can either clone the public repository:: - $ git clone git://github.com/moogar0880/PyTrakt.git + $ git clone git://github.com/glensc/python-pytrakt.git -Download the `tarball `_:: +Download the `tarball `_:: - $ curl -OL https://github.com/moogar0880/PyTrakt/tarball/master + $ curl -OL https://github.com/glensc/python-pytrakt/tarball/master -Or, download the `zipball `_:: +Or, download the `zipball `_:: - $ curl -OL https://github.com/moogar0880/PyTrakt/zipball/master + $ curl -OL https://github.com/glensc/python-pytrakt/zipball/main Once you have a copy of the source, you can embed it in your Python package, or install it into your site-packages easily:: From 19123aca6dcd21cdf3d52f6357e668a131b953a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:40:18 +0300 Subject: [PATCH 49/69] Fix DEFAULT_PYTHON parsing in yaml --- .github/workflows/pypi.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 1302c245..7e6cc1f4 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -13,7 +13,7 @@ on: - '*.*.*' env: - DEFAULT_PYTHON: 3.10 + DEFAULT_PYTHON: "3.10" jobs: pypi: From 48a0579ef91cc20893fb9b1fc292d15454c7f186 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:53:34 +0300 Subject: [PATCH 50/69] Set version to 3.4.5 --- trakt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index de4567f0..9e28d631 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 4) +version_info = (3, 4, 5) __author__ = 'Jon Nappi, Elan Ruusamäe' __version__ = '.'.join([str(i) for i in version_info]) From b8ebac6587097ae3ad2cb681b1b0989a6d8ccf87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 20:18:59 +0300 Subject: [PATCH 51/69] Update actions to avoid node 12 deprecation warnings --- .github/workflows/pypi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 7e6cc1f4..07188c58 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -21,10 +21,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ env.DEFAULT_PYTHON }} From 380d5a7c73010db8243387708e9780bd56173690 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:56:39 +0300 Subject: [PATCH 52/69] Add version file --- trakt/__version__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 trakt/__version__.py diff --git a/trakt/__version__.py b/trakt/__version__.py new file mode 100644 index 00000000..4f7facb8 --- /dev/null +++ b/trakt/__version__.py @@ -0,0 +1 @@ +__version__ = "Unknown" From 56fcd881cf6de97c64a73ed2a51c3eef08afe097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 19:58:46 +0300 Subject: [PATCH 53/69] Use __version__ from __version__.py --- trakt/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trakt/__init__.py b/trakt/__init__.py index 9e28d631..1004aed6 100644 --- a/trakt/__init__.py +++ b/trakt/__init__.py @@ -5,6 +5,6 @@ except ImportError: pass -version_info = (3, 4, 5) +from .__version__ import __version__ + __author__ = 'Jon Nappi, Elan Ruusamäe' -__version__ = '.'.join([str(i) for i in version_info]) From e8937eee3a8e0e2f9aa98ccb7e946fece0f868a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Sun, 23 Oct 2022 20:00:13 +0300 Subject: [PATCH 54/69] Automate version setup for PyPI publishing in CI Bumping version manually in source repo is super annoying and prone to errors. --- .github/workflows/pypi.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 07188c58..c872383e 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -28,8 +28,30 @@ jobs: with: python-version: ${{ env.DEFAULT_PYTHON }} + - name: Set version variable + id: version + run: | + if [[ "${GITHUB_REF#refs/heads/}" = "${GITHUB_REF}" ]]; then + APP_VERSION=${GITHUB_REF#refs/tags/} + else + git fetch --tags --unshallow + version=$(git describe --tags --abbrev=0) + subver=${{ github.run_number }} + APP_VERSION=$version.post$subver + fi + echo "version=$APP_VERSION" >> $GITHUB_OUTPUT + - name: Install dependencies and build + env: + APP_VERSION: ${{ steps.version.outputs.version }} run: | + # Setup version + set -x + echo "__version__ = '$APP_VERSION'" > trakt/__version__.py + cat trakt/__version__.py + python -c "from trakt import __version__; print(__version__)" + + # Build the package python -m pip install --upgrade build python -m build From 237ed8adddcf87a9c6bc12ea8cf37a4aae4239b2 Mon Sep 17 00:00:00 2001 From: twolaw Date: Sun, 23 Oct 2022 19:48:56 +0200 Subject: [PATCH 55/69] pip install pytrakt --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f4f5f66f..33686f95 100644 --- a/README.rst +++ b/README.rst @@ -30,7 +30,7 @@ Install Via Pip ^^^^^^^^^^^^^^^ To install with `pip `_, just run this in your terminal:: - $ pip install trakt + $ pip install pytrakt Get the code ^^^^^^^^^^^^ From 125c9ae9058121fdc0c67678a368cbb1a201faa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 21:58:19 +0300 Subject: [PATCH 56/69] Add workflow to run tests in CI --- .github/workflows/test.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..a71c6051 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,26 @@ +name: Test + +on: + pull_request: + +env: + DEFAULT_PYTHON: 3.6 + +jobs: + test: + runs-on: ubuntu-20.04 + name: Test + steps: + - name: Check out source repository + uses: actions/checkout@v3 + - name: Set up Python environment + uses: actions/setup-python@v4 + with: + python-version: ${{ env.DEFAULT_PYTHON }} + cache: pip + - name: Install dependencies (pip) + run: python -m pip install -r requirements.txt -r testing-requirements.txt + - name: Test + run: make test + +# vim:ts=2:sw=2:et From 0cd061b1349344b2691ce3ed4cc728b200b8f902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:08:39 +0300 Subject: [PATCH 57/69] Run tests in matrix --- .github/workflows/test.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a71c6051..6e3fde12 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -3,20 +3,26 @@ name: Test on: pull_request: -env: - DEFAULT_PYTHON: 3.6 - jobs: test: runs-on: ubuntu-20.04 - name: Test + name: Python ${{ matrix.python }} + strategy: + matrix: + python: + - "3.6" + - "3.7" + - "3.8" + - "3.9" + - "3.10" + steps: - name: Check out source repository uses: actions/checkout@v3 - name: Set up Python environment uses: actions/setup-python@v4 with: - python-version: ${{ env.DEFAULT_PYTHON }} + python-version: ${{ matrix.python }} cache: pip - name: Install dependencies (pip) run: python -m pip install -r requirements.txt -r testing-requirements.txt From afd45fcfc7d4fb4572f60507e3b58ade2b1980c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:11:25 +0300 Subject: [PATCH 58/69] Update badges for project name --- README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 33686f95..333f90fc 100644 --- a/README.rst +++ b/README.rst @@ -4,12 +4,12 @@ PyTrakt :target: https://circleci.com/gh/moogar0880/PyTrakt/tree/master :alt: CircleCI Status -.. image:: https://img.shields.io/pypi/dm/trakt.svg - :target: https://pypi.python.org/pypi/trakt +.. image:: https://img.shields.io/pypi/dm/pytrakt.svg + :target: https://pypi.org/project/pytrakt/ :alt: Downloads -.. image:: https://img.shields.io/pypi/l/trakt.svg - :target: https://pypi.python.org/pypi/trakt/ +.. image:: https://img.shields.io/pypi/l/pytrakt.svg + :target: https://pypi.org/project/pytrakt/ :alt: License This module is designed to be a Pythonic interface to the `Trakt.tv `_. From 7c7e4d497ddf142f98a58ac869fdc4772930614a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:13:20 +0300 Subject: [PATCH 59/69] Update CI badge url --- README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 333f90fc..d4a781b0 100644 --- a/README.rst +++ b/README.rst @@ -1,8 +1,9 @@ PyTrakt ======= -.. image:: https://circleci.com/gh/moogar0880/PyTrakt/tree/master.svg?style=svg - :target: https://circleci.com/gh/moogar0880/PyTrakt/tree/master - :alt: CircleCI Status + +.. image:: https://github.com/glensc/python-pytrakt/actions/workflows/test.yml/badge.svg + :target: https://github.com/glensc/python-pytrakt/actions + :alt: CI Status .. image:: https://img.shields.io/pypi/dm/pytrakt.svg :target: https://pypi.org/project/pytrakt/ From 4bc933d9bdbb61675545ba2c15befe8a31c9c19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:09:14 +0300 Subject: [PATCH 60/69] Remove circleci setup --- .circleci/config.yml | 161 ------------------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 6bc76779..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,161 +0,0 @@ -############################################################################### -### Reusable template definitions -############################################################################### -.py_3_6_container: &py_3_6_container - docker: - # CircleCI Python images available at: https://hub.docker.com/r/circleci/python/ - - image: circleci/python:3.6 - -.py_3_7_container: &py_3_7_container - docker: - # CircleCI Python images available at: https://hub.docker.com/r/circleci/python/ - - image: circleci/python:3.7 - -.py_3_8_container: &py_3_8_container - docker: - # CircleCI Python images available at: https://hub.docker.com/r/circleci/python/ - - image: circleci/python:3.8 - -.py_3_9_container: &py_3_9_container - docker: - # CircleCI Python images available at: https://hub.docker.com/r/circleci/python/ - - image: circleci/python:3.9 - -.py_3_10_container: &py_3_10_container - docker: - # CircleCI Python images available at: https://hub.docker.com/r/circleci/python/ - - image: circleci/python:3.10 - -.pytest: &pytest - run: - name: Run unit tests - command: make test - -.flake8: &flake8 - run: - name: Run flake8 - command: make style - -.test_steps: &test_steps - steps: - - checkout - - <<: *pytest - - store_artifacts: # upload test summary for display in Artifacts - path: ${TEST_RESULTS} - destination: raw-test-output - - store_test_results: # upload test results for display in Test Summary - path: /tmp/test-results - -.lint_steps: &lint_steps - steps: - - checkout - - <<: *flake8 - - store_artifacts: # upload lint summary for display in Artifacts - path: ${LINT_RESULTS} - destination: raw-lint-output - -.common: &common - # Run multiple jobs in parallel. - parallelism: 2 - - # Declare the working directory for the job. - working_directory: ~/PyTrakt - - # Define the environment variables to be injected into the build itself. - environment: - TEST_RESULTS: /tmp/test-results # path to where test results will be saved - LINT_RESULTS: /tmp/lint-results # path to where lint results will be saved - -version: 2 - -############################################################################### -### Job Definitions -############################################################################### -jobs: - ############################################################################# - ### Python 3.6 Jobs - ############################################################################# - test.3.6: - <<: *py_3_6_container - <<: *common - <<: *test_steps - lint.3.6: - <<: *py_3_6_container - <<: *common - <<: *lint_steps - - ############################################################################# - ### Python 3.7 Jobs - ############################################################################# - test.3.7: - <<: *py_3_7_container - <<: *common - <<: *test_steps - lint.3.7: - <<: *py_3_7_container - <<: *common - <<: *lint_steps - - ############################################################################# - ### Python 3.8 Jobs - ############################################################################# - test.3.8: - <<: *py_3_8_container - <<: *common - <<: *test_steps - lint.3.8: - <<: *py_3_8_container - <<: *common - <<: *lint_steps - - ############################################################################# - ### Python 3.9 Jobs - ############################################################################# - test.3.9: - <<: *py_3_9_container - <<: *common - <<: *test_steps - lint.3.9: - <<: *py_3_9_container - <<: *common - <<: *lint_steps - - ############################################################################# - ### Python 3.10 Jobs - ############################################################################# - test.3.10: - <<: *py_3_10_container - <<: *common - <<: *test_steps - lint.3.10: - <<: *py_3_10_container - <<: *common - <<: *lint_steps - -workflows: - version: 2 - - py-3.6-verify: - jobs: - - test.3.6 - - lint.3.6 - - py-3.7-verify: - jobs: - - test.3.7 - - lint.3.7 - - py-3.8-verify: - jobs: - - test.3.8 - - lint.3.8 - - py-3.9-verify: - jobs: - - test.3.9 - - lint.3.9 - - py-3.10-verify: - jobs: - - test.3.10 - - lint.3.10 From 28322e28340fa77cec02b22af06d19321cf96ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:18:05 +0300 Subject: [PATCH 61/69] Few more master -> main changes --- README.rst | 6 +++--- docs/index.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index d4a781b0..ceac4759 100644 --- a/README.rst +++ b/README.rst @@ -41,9 +41,9 @@ You can either clone the public repository:: $ git clone git://github.com/glensc/python-pytrakt.git -Download the `tarball `_:: +Download the `tarball `_:: - $ curl -OL https://github.com/glensc/python-pytrakt/tarball/master + $ curl -OL https://github.com/glensc/python-pytrakt/tarball/main Or, download the `zipball `_:: @@ -59,7 +59,7 @@ Contributing Pull requests are graciously accepted. Any pull request should not break any tests and should pass `flake8` style checks (unless otherwise warranted). Additionally the user opening the Pull Request should ensure that their username and a link to -their GitHub page appears in `CONTRIBUTORS.md `_. +their GitHub page appears in `CONTRIBUTORS.md `_. TODO diff --git a/docs/index.rst b/docs/index.rst index fbdcc9f7..75cdfe75 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -34,7 +34,7 @@ You can either clone the public repository:: $ git clone git://github.com/glensc/python-pytrakt.git -Download the `tarball `_:: +Download the `tarball `_:: $ curl -OL https://github.com/glensc/python-pytrakt/tarball/master From 7fe463de0f48f9f53bdda515bb7a2276bdb23580 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:35:28 +0300 Subject: [PATCH 62/69] Use @classmethod propertly The idea of @classmethod is to have class in a variable --- trakt/users.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trakt/users.py b/trakt/users.py index ff596337..9ebc56a6 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -97,7 +97,7 @@ def create(cls, name, creator, description=None, privacy='private', args['description'] = description data = yield 'users/{user}/lists'.format(user=slugify(creator)), args extract_ids(data) - yield UserList(creator=creator, user=creator, **data) + yield cls(creator=creator, user=creator, **data) @classmethod @get @@ -109,7 +109,7 @@ def _get(cls, title, creator): data = yield 'users/{user}/lists/{id}'.format(user=slugify(creator), id=slugify(title)) extract_ids(data) - ulist = UserList(creator=creator, **data) + ulist = cls(creator=creator, **data) ulist.get_items() yield ulist From 461830941ae4a76fbbc04c5e15d2a789d919a8cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 22:36:47 +0300 Subject: [PATCH 63/69] Use @staticmethod instead of @classmethod Use @staticmethod when class or instance is not needed in a method --- trakt/movies.py | 4 ++-- trakt/people.py | 4 ++-- trakt/tv.py | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/trakt/movies.py b/trakt/movies.py index fd5f15cf..39232bab 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -106,8 +106,8 @@ def __init__(self, title, year=None, slug=None, **kwargs): else: self._get() - @classmethod - def search(cls, title, year=None): + @staticmethod + def search(title, year=None): """Perform a search for a movie with a title matching *title* :param title: The title to search for diff --git a/trakt/people.py b/trakt/people.py index 074dfdb5..8b1d02bc 100644 --- a/trakt/people.py +++ b/trakt/people.py @@ -24,8 +24,8 @@ def __init__(self, name, slug=None, **kwargs): else: self._get() - @classmethod - def search(cls, name, year=None): + @staticmethod + def search(name, year=None): """Perform a search for an episode with a title matching *title* :param name: The name of the person to search for diff --git a/trakt/tv.py b/trakt/tv.py index e41bf4f5..80bea968 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -227,8 +227,8 @@ def slug(self): return slugify(self.title + ' ' + str(self.year)) - @classmethod - def search(cls, title, year=None): + @staticmethod + def search(title, year=None): """Perform a search for the specified *title*. :param title: The title to search for @@ -770,8 +770,8 @@ def images_ext(self): """Uri to retrieve additional image information""" return self.ext + '?extended=images' - @classmethod - def search(cls, title, year=None): + @staticmethod + def search(title, year=None): """Perform a search for an episode with a title matching *title* :param title: The title to search for From db50999b52244df8e3a615e294baa97a3217cc32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Mon, 24 Oct 2022 23:23:17 +0300 Subject: [PATCH 64/69] Add progress parameter to Scrobbler methods This allows caller to pass progress value in same go --- trakt/sync.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/trakt/sync.py b/trakt/sync.py index 32c7bc78..5610eb75 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -457,16 +457,22 @@ def __init__(self, media, progress, app_version, app_date): if self.progress > 0: self.start() - def start(self): + def start(self, progress=None): """Start scrobbling this :class:`Scrobbler`'s *media* object""" + if progress is not None: + self.progress = progress return self._post('scrobble/start') - def pause(self): + def pause(self, progress=None): """Pause the scrobbling of this :class:`Scrobbler`'s *media* object""" + if progress is not None: + self.progress = progress return self._post('scrobble/pause') - def stop(self): + def stop(self, progress=None): """Stop the scrobbling of this :class:`Scrobbler`'s *media* object""" + if progress is not None: + self.progress = progress return self._post('scrobble/stop') def finish(self): From ff50421c4868345922a508a0d3f1b28d871d9eb4 Mon Sep 17 00:00:00 2001 From: twolaw Date: Tue, 25 Oct 2022 14:03:24 +0200 Subject: [PATCH 65/69] add show_id to TVEpisode --- trakt/calendar.py | 3 ++- trakt/sync.py | 4 +++- trakt/tv.py | 9 ++++++--- trakt/users.py | 6 ++++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/trakt/calendar.py b/trakt/calendar.py index d5a5980e..dd63ec4e 100644 --- a/trakt/calendar.py +++ b/trakt/calendar.py @@ -81,7 +81,8 @@ def _build(self, data): 'show_data': TVShow(**show_data) } self._calendar.append( - TVEpisode(show_data['title'], season, ep_num, **e_data) + TVEpisode(show_data['title'], season, ep_num, + show_id=show_data['trakt'], **e_data) ) self._calendar = sorted(self._calendar, key=lambda x: x.airs_at) diff --git a/trakt/sync.py b/trakt/sync.py index 32c7bc78..bdd90576 100644 --- a/trakt/sync.py +++ b/trakt/sync.py @@ -336,7 +336,9 @@ def get_watchlist(list_type=None, sort=None): from trakt.tv import TVEpisode show = d.pop('show') extract_ids(d['episode']) - results.append(TVEpisode(show.get('title', None), **d['episode'])) + results.append(TVEpisode(show.get('title', None), + show_id=show.get('trakt', None), + **d['episode'])) elif 'movie' in d: from trakt.movies import Movie results.append(Movie(**d.pop('movie'))) diff --git a/trakt/tv.py b/trakt/tv.py index 3b8fc52e..0890d82d 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -439,7 +439,8 @@ def seasons(self): # Prepare episodes episodes = [] for ep in season.pop('episodes', []): - episode = TVEpisode(show=self.title, **ep) + episode = TVEpisode(show=self.title, + show_id=self.trakt, **ep) episodes.append(episode) season['episodes'] = episodes @@ -456,7 +457,8 @@ def last_episode(self): """ if self._last_episode is None: data = yield self.ext + '/last_episode?extended=full' - self._last_episode = data and TVEpisode(show=self.title, **data) + self._last_episode = data and TVEpisode(show=self.title, + show_id=self.trakt, **data) yield self._last_episode @property @@ -467,7 +469,8 @@ def next_episode(self): """ if self._next_episode is None: data = yield self.ext + '/next_episode?extended=full' - self._next_episode = data and TVEpisode(show=self.title, **data) + self._next_episode = data and TVEpisode(show=self.title, + show_id=self.trakt, **data) yield self._next_episode @property diff --git a/trakt/users.py b/trakt/users.py index 175117bb..d1669729 100644 --- a/trakt/users.py +++ b/trakt/users.py @@ -147,7 +147,8 @@ def get_items(self): show_data = item.pop('show') extract_ids(show_data) episode = TVEpisode(show_data['title'], item_data['season'], - item_data['number']) + item_data['number'], + show_id=show_data['trakt']) self._items.append(episode) elif item_type == 'person': self._items.append(Person(item_data['name'], @@ -439,7 +440,8 @@ def watching(self): ep_data = data.pop('episode') extract_ids(ep_data) sh_data = data.pop('show') - ep_data.update(data, show=sh_data.get('title')) + ep_data.update(data, show=sh_data.get('title'), + show_id=sh_data.get('trakt')) yield TVEpisode(**ep_data) @staticmethod From 9660b932a10e897b4594dc94c6c31a6b345cd09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 25 Oct 2022 17:15:20 +0300 Subject: [PATCH 66/69] Run CI tests on default branch --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6e3fde12..e94c4efe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -2,6 +2,9 @@ name: Test on: pull_request: + push: + branches: + - main jobs: test: From 45ec546c21032561c33005e8b6486fac2a244be8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 2 Nov 2022 17:50:55 +0200 Subject: [PATCH 67/69] Update methods to return api responses The responses may contain useful information what was updated: { 'added': { 'movies': 1, 'episodes': 0 }, 'not_found': { 'movies': [], 'shows': [], 'seasons': [], 'episodes': [], 'people': [], 'users': [] } } --- trakt/movies.py | 18 +++++++++--------- trakt/tv.py | 22 +++++++++++----------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/trakt/movies.py b/trakt/movies.py index 5190a7b0..2e5ce58d 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -258,16 +258,16 @@ def watching_now(self): def add_to_library(self): """Add this :class:`Movie` to your library.""" - add_to_collection(self) + return add_to_collection(self) add_to_collection = add_to_library def add_to_watchlist(self): """Add this :class:`Movie` to your watchlist""" - add_to_watchlist(self) + return add_to_watchlist(self) def comment(self, comment_body, spoiler=False, review=False): """Add a comment (shout or review) to this :class:`Move` on trakt.""" - comment(self, comment_body, spoiler, review) + return comment(self, comment_body, spoiler, review) def dismiss(self): """Dismiss this movie from showing up in Movie Recommendations""" @@ -305,28 +305,28 @@ def get_translations(self, country_code='us'): def mark_as_seen(self, watched_at=None): """Add this :class:`Movie`, watched outside of trakt, to your library. """ - add_to_history(self, watched_at) + return add_to_history(self, watched_at) def mark_as_unseen(self): """Remove this :class:`Movie`, watched outside of trakt, from your library. """ - remove_from_history(self) + return remove_from_history(self) def rate(self, rating): """Rate this :class:`Movie` on trakt. Depending on the current users settings, this may also send out social updates to facebook, twitter, tumblr, and path. """ - rate(self, rating) + return rate(self, rating) def remove_from_library(self): """Remove this :class:`Movie` from your library.""" - remove_from_collection(self) + return remove_from_collection(self) remove_from_collection = remove_from_library def remove_from_watchlist(self): - remove_from_watchlist(self) + return remove_from_watchlist(self) def scrobble(self, progress, app_version, app_date): """Notify trakt that the current user has finished watching a movie. @@ -362,7 +362,7 @@ def checkin(self, app_version, app_date, message="", sharing=None, """ if delete: delete_checkin() - checkin_media(self, app_version, app_date, message, sharing, venue_id, + return checkin_media(self, app_version, app_date, message, sharing, venue_id, venue_name) def to_json_singular(self): diff --git a/trakt/tv.py b/trakt/tv.py index 0890d82d..015e08b2 100644 --- a/trakt/tv.py +++ b/trakt/tv.py @@ -673,13 +673,13 @@ def watching_now(self): def add_to_library(self): """Add this :class:`TVSeason` to your library.""" - add_to_collection(self) + return add_to_collection(self) add_to_collection = add_to_library def remove_from_library(self): """Remove this :class:`TVSeason` from your library.""" - remove_from_collection(self) + return remove_from_collection(self) remove_from_collection = remove_from_library @@ -864,40 +864,40 @@ def rate(self, rating): settings, this may also send out social updates to facebook, twitter, tumblr, and path. """ - rate(self, rating) + return rate(self, rating) def add_to_library(self): """Add this :class:`TVEpisode` to your Trakt.tv library""" - add_to_collection(self) + return add_to_collection(self) add_to_collection = add_to_library def add_to_watchlist(self): """Add this :class:`TVEpisode` to your watchlist""" - add_to_watchlist(self) + return add_to_watchlist(self) def mark_as_seen(self, watched_at=None): """Mark this episode as seen""" - add_to_history(self, watched_at) + return add_to_history(self, watched_at) def mark_as_unseen(self): """Remove this :class:`TVEpisode` from your list of watched episodes""" - remove_from_history(self) + return remove_from_history(self) def remove_from_library(self): """Remove this :class:`TVEpisode` from your library""" - remove_from_collection(self) + return remove_from_collection(self) remove_from_collection = remove_from_library def remove_from_watchlist(self): """Remove this :class:`TVEpisode` from your watchlist""" - remove_from_watchlist(self) + return remove_from_watchlist(self) def comment(self, comment_body, spoiler=False, review=False): """Add a comment (shout or review) to this :class:`TVEpisode` on trakt. """ - comment(self, comment_body, spoiler, review) + return comment(self, comment_body, spoiler, review) def scrobble(self, progress, app_version, app_date): """Scrobble this :class:`TVEpisode` via the TraktTV Api @@ -930,7 +930,7 @@ def checkin(self, app_version, app_date, message="", sharing=None, """ if delete: delete_checkin() - checkin_media(self, app_version, app_date, message, sharing, venue_id, + return checkin_media(self, app_version, app_date, message, sharing, venue_id, venue_name) def to_json_singular(self): From f230a8f8eb0452635821dfeebfc06a504267de4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Wed, 2 Nov 2022 21:29:15 +0200 Subject: [PATCH 68/69] Update tests to match signature The tests doesn't seem to be testing anything much other than coverage? --- tests/test_episodes.py | 4 ++-- tests/test_movies.py | 12 +++++++++--- tests/test_seasons.py | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/test_episodes.py b/tests/test_episodes.py index c3b82582..8a41f84f 100644 --- a/tests/test_episodes.py +++ b/tests/test_episodes.py @@ -74,13 +74,13 @@ def test_oneliners(): e1.remove_from_collection, e1.remove_from_watchlist] for fn in functions: r = fn() - assert r is None + assert r is not None def test_episode_comment(): e1 = TVEpisode('Game of Thrones', season=1, number=1) r = e1.comment('Test Comment') - assert r is None + assert r is not None def test_episode_scrobble(): diff --git a/tests/test_movies.py b/tests/test_movies.py index f6156df7..da38e5b0 100644 --- a/tests/test_movies.py +++ b/tests/test_movies.py @@ -148,21 +148,27 @@ def test_movie_search(): assert all(isinstance(m, Movie) for m in results) +def test_dismiss(): + tron = Movie('Tron Legacy 2010') + r = tron.dismiss() + assert r is None + + def test_utilities(): tron = Movie('Tron Legacy 2010') functions = [tron.add_to_library, tron.add_to_collection, - tron.add_to_watchlist, tron.dismiss, tron.mark_as_unseen, + tron.add_to_watchlist, tron.mark_as_unseen, tron.remove_from_library, tron.remove_from_collection, tron.remove_from_watchlist, tron.mark_as_seen] for fn in functions: r = fn() - assert r is None + assert r is not None def test_movie_comment(): tron = Movie('Tron Legacy 2010') r = tron.comment('Some comment data') - assert r is None + assert r is not None def test_rate_movie(): diff --git a/tests/test_seasons.py b/tests/test_seasons.py index c69ef2a2..23a6bb22 100644 --- a/tests/test_seasons.py +++ b/tests/test_seasons.py @@ -53,7 +53,7 @@ def test_oneliners(): s1.remove_from_library, s1.remove_from_collection] for fn in functions: r = fn() - assert r is None + assert r is not None def test_season_to_json(): From fe8d3334406bd31b712a988063239cdbb4ecaa95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elan=20Ruusam=C3=A4e?= Date: Tue, 29 Nov 2022 20:07:28 +0200 Subject: [PATCH 69/69] Initialize Movie.trakt property with None --- trakt/movies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trakt/movies.py b/trakt/movies.py index 4c2958ba..e6be7c73 100644 --- a/trakt/movies.py +++ b/trakt/movies.py @@ -94,7 +94,7 @@ def __init__(self, title, year=None, slug=None, **kwargs): self.slug = slug or slugify(self.title) self.released = self.tmdb_id = self.imdb_id = self.duration = None - self.trakt_id = self.tagline = self.overview = self.runtime = None + self.trakt = self.trakt_id = self.tagline = self.overview = self.runtime = None self.updated_at = self.trailer = self.homepage = self.rating = None self.votes = self.language = self.available_translations = None self.genres = self.certification = None