diff --git a/autosync/autosync/__init__.py b/autosync/autosync/__init__.py index d7e74d1f..3fcca024 100644 --- a/autosync/autosync/__init__.py +++ b/autosync/autosync/__init__.py @@ -1,13 +1,22 @@ -import json +import logging import os +import dataclasses_json import pika from pika import spec from pika.adapters.blocking_connection import BlockingChannel import pika.credentials +from datetime import date, datetime +from autosync.models.message import Message from autosync.services.aggregate import Aggregate from autosync.services.simkl import Simkl +dataclasses_json.cfg.global_config.encoders[date] = date.isoformat +dataclasses_json.cfg.global_config.decoders[date] = date.fromisoformat +dataclasses_json.cfg.global_config.encoders[datetime] = datetime.isoformat +dataclasses_json.cfg.global_config.decoders[datetime] = datetime.fromisoformat + +logging.basicConfig(level=logging.INFO) service = Aggregate([Simkl()]) @@ -17,8 +26,12 @@ def on_message( properties: spec.BasicProperties, body: bytes, ): - status = json.loads(body) - service.update(status.user, status.resource, status) + try: + status = Message.from_json(body) + service.update(status.user, status.resource, status) + except Exception as e: + logging.exception("Error processing message.", exc_info=e) + logging.exception("Body: %s", body) def main(): @@ -41,4 +54,5 @@ def main(): channel.basic_consume( queue=queue_name, on_message_callback=on_message, auto_ack=True ) + logging.info("Listening for autosync.") channel.start_consuming() diff --git a/autosync/autosync/models/episode.py b/autosync/autosync/models/episode.py index 047344a6..8cbf8c71 100644 --- a/autosync/autosync/models/episode.py +++ b/autosync/autosync/models/episode.py @@ -1,9 +1,10 @@ from typing import Literal from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from .metadataid import MetadataID - +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class Episode: external_id: dict[str, MetadataID] diff --git a/autosync/autosync/models/message.py b/autosync/autosync/models/message.py index 31d10779..94b3312e 100644 --- a/autosync/autosync/models/message.py +++ b/autosync/autosync/models/message.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from autosync.models.episode import Episode from autosync.models.movie import Movie @@ -7,12 +8,14 @@ from autosync.models.user import User from autosync.models.watch_status import WatchStatus +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class WatchStatusMessage(WatchStatus): user: User resource: Movie | Show | Episode +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class Message: action: str diff --git a/autosync/autosync/models/metadataid.py b/autosync/autosync/models/metadataid.py index 87bfc915..a9ec2267 100644 --- a/autosync/autosync/models/metadataid.py +++ b/autosync/autosync/models/metadataid.py @@ -1,7 +1,9 @@ from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from typing import Optional +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class MetadataID: data_id: str diff --git a/autosync/autosync/models/movie.py b/autosync/autosync/models/movie.py index 6d886868..03b2273d 100644 --- a/autosync/autosync/models/movie.py +++ b/autosync/autosync/models/movie.py @@ -1,10 +1,12 @@ from typing import Literal, Optional from datetime import date from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from .metadataid import MetadataID +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class Movie: name: str diff --git a/autosync/autosync/models/show.py b/autosync/autosync/models/show.py index 364dd5b3..5400af70 100644 --- a/autosync/autosync/models/show.py +++ b/autosync/autosync/models/show.py @@ -1,10 +1,12 @@ from typing import Literal, Optional from datetime import date from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from .metadataid import MetadataID +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class Show: name: str diff --git a/autosync/autosync/models/user.py b/autosync/autosync/models/user.py index 653af8eb..30f18b7a 100644 --- a/autosync/autosync/models/user.py +++ b/autosync/autosync/models/user.py @@ -1,8 +1,10 @@ from datetime import datetime, time from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from typing import Optional +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class JwtToken: token_type: str @@ -12,6 +14,7 @@ class JwtToken: expire_at: datetime +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class ExternalToken: id: str @@ -20,6 +23,7 @@ class ExternalToken: token: JwtToken +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class User: id: str diff --git a/autosync/autosync/models/watch_status.py b/autosync/autosync/models/watch_status.py index 5f42ab9d..6bd8bc7b 100644 --- a/autosync/autosync/models/watch_status.py +++ b/autosync/autosync/models/watch_status.py @@ -1,21 +1,23 @@ from datetime import date from dataclasses import dataclass +from dataclasses_json import dataclass_json, LetterCase from typing import Optional from enum import Enum class Status(str, Enum): - COMPLETED = "completed" - WATCHING = "watching" - DROPED = "droped" - PLANNED = "planned" - DELETED = "deleted" + COMPLETED = "Completed" + WATCHING = "Watching" + DROPED = "Droped" + PLANNED = "Planned" + DELETED = "Deleted" +@dataclass_json(letter_case=LetterCase.CAMEL) @dataclass class WatchStatus: added_date: date - played_date: date + played_date: Optional[date] status: Status watched_time: Optional[int] watched_percent: Optional[int] diff --git a/autosync/autosync/services/aggregate.py b/autosync/autosync/services/aggregate.py index e8771507..6044ed46 100644 --- a/autosync/autosync/services/aggregate.py +++ b/autosync/autosync/services/aggregate.py @@ -18,4 +18,9 @@ class Aggregate(Service): def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus): for service in self._services: - service.update(user, resource, status) + try: + service.update(user, resource, status) + except Exception as e: + logging.exception( + "Unhandled error on autosync %s:", service.name, exc_info=e + ) diff --git a/autosync/autosync/services/simkl.py b/autosync/autosync/services/simkl.py index 8912e202..7cb7ad9f 100644 --- a/autosync/autosync/services/simkl.py +++ b/autosync/autosync/services/simkl.py @@ -1,5 +1,4 @@ import os -from typing_extensions import assert_type import requests import logging diff --git a/autosync/requirements.txt b/autosync/requirements.txt index 9f75faf9..0976c85c 100644 --- a/autosync/requirements.txt +++ b/autosync/requirements.txt @@ -1,2 +1,3 @@ pika -requets +requests +dataclasses-json diff --git a/shell.nix b/shell.nix index 5c7729e3..7c1b81ee 100644 --- a/shell.nix +++ b/shell.nix @@ -7,6 +7,7 @@ watchfiles pika requests + dataclasses-json ]); dotnet = with pkgs.dotnetCorePackages; combinePackages [