-
-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
44 changed files
with
1,016 additions
and
188 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
FROM python:3.12 | ||
WORKDIR /app | ||
|
||
COPY ./requirements.txt . | ||
RUN pip3 install -r ./requirements.txt | ||
|
||
COPY . . | ||
ENTRYPOINT ["python3", "-m", "autosync"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import logging | ||
import os | ||
|
||
import dataclasses_json | ||
from datetime import datetime | ||
from marshmallow import fields | ||
|
||
dataclasses_json.cfg.global_config.encoders[datetime] = datetime.isoformat | ||
dataclasses_json.cfg.global_config.decoders[datetime] = datetime.fromisoformat | ||
dataclasses_json.cfg.global_config.mm_fields[datetime] = fields.DateTime(format="iso") | ||
dataclasses_json.cfg.global_config.encoders[datetime | None] = datetime.isoformat | ||
dataclasses_json.cfg.global_config.decoders[datetime | None] = datetime.fromisoformat | ||
dataclasses_json.cfg.global_config.mm_fields[datetime | None] = fields.DateTime( | ||
format="iso" | ||
) | ||
|
||
import pika | ||
from pika import spec | ||
from pika.adapters.blocking_connection import BlockingChannel | ||
import pika.credentials | ||
from autosync.models.message import Message | ||
from autosync.services.aggregate import Aggregate | ||
|
||
from autosync.services.simkl import Simkl | ||
|
||
|
||
logging.basicConfig(level=logging.INFO) | ||
service = Aggregate([Simkl()]) | ||
|
||
|
||
def on_message( | ||
ch: BlockingChannel, | ||
method: spec.Basic.Deliver, | ||
properties: spec.BasicProperties, | ||
body: bytes, | ||
): | ||
try: | ||
message = Message.from_json(body) # type: Message | ||
service.update(message.value.user, message.value.resource, message.value) | ||
except Exception as e: | ||
logging.exception("Error processing message.", exc_info=e) | ||
logging.exception("Body: %s", body) | ||
|
||
|
||
def main(): | ||
connection = pika.BlockingConnection( | ||
pika.ConnectionParameters( | ||
host=os.environ.get("RABBITMQ_HOST", "rabbitmq"), | ||
credentials=pika.credentials.PlainCredentials( | ||
os.environ.get("RABBITMQ_DEFAULT_USER", "guest"), | ||
os.environ.get("RABBITMQ_DEFAULT_PASS", "guest"), | ||
), | ||
) | ||
) | ||
channel = connection.channel() | ||
|
||
channel.exchange_declare(exchange="events.watched", exchange_type="topic") | ||
result = channel.queue_declare("", exclusive=True) | ||
queue_name = result.method.queue | ||
channel.queue_bind(exchange="events.watched", queue=queue_name, routing_key="#") | ||
|
||
channel.basic_consume( | ||
queue=queue_name, on_message_callback=on_message, auto_ack=True | ||
) | ||
logging.info("Listening for autosync.") | ||
channel.start_consuming() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env python | ||
import autosync | ||
|
||
autosync.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from typing import Literal | ||
from dataclasses import dataclass | ||
from dataclasses_json import dataclass_json, LetterCase | ||
|
||
from autosync.models.show import Show | ||
|
||
from .metadataid import MetadataID | ||
|
||
|
||
@dataclass_json(letter_case=LetterCase.CAMEL) | ||
@dataclass | ||
class Episode: | ||
external_id: dict[str, MetadataID] | ||
show: Show | ||
season_number: int | ||
episode_number: int | ||
absolute_number: int | ||
kind: Literal["episode"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from dataclasses import dataclass | ||
from dataclasses_json import dataclass_json, LetterCase | ||
|
||
from autosync.models.episode import Episode | ||
from autosync.models.movie import Movie | ||
from autosync.models.show import Show | ||
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 | ||
type: str | ||
value: WatchStatusMessage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
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 | ||
link: Optional[str] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from typing import Literal, Optional | ||
from datetime import datetime | ||
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 | ||
air_date: Optional[datetime] | ||
external_id: dict[str, MetadataID] | ||
kind: Literal["movie"] | ||
|
||
@property | ||
def year(self): | ||
return self.air_date.year if self.air_date is not None else None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
from typing import Literal, Optional | ||
from datetime import datetime | ||
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 | ||
start_air: Optional[datetime] | ||
external_id: dict[str, MetadataID] | ||
kind: Literal["show"] | ||
|
||
@property | ||
def year(self): | ||
return self.start_air.year if self.start_air is not None else None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
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 | ||
access_token: str | ||
refresh_token: Optional[str] | ||
expire_in: time | ||
expire_at: datetime | ||
|
||
|
||
@dataclass_json(letter_case=LetterCase.CAMEL) | ||
@dataclass | ||
class ExternalToken: | ||
id: str | ||
username: str | ||
profileUrl: Optional[str] | ||
token: JwtToken | ||
|
||
|
||
@dataclass_json(letter_case=LetterCase.CAMEL) | ||
@dataclass | ||
class User: | ||
id: str | ||
username: str | ||
email: str | ||
permissions: list[str] | ||
settings: dict[str, str] | ||
external_id: dict[str, ExternalToken] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from datetime import datetime | ||
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" | ||
|
||
|
||
@dataclass_json(letter_case=LetterCase.CAMEL) | ||
@dataclass | ||
class WatchStatus: | ||
added_date: datetime | ||
played_date: Optional[datetime] | ||
status: Status | ||
watched_time: Optional[int] | ||
watched_percent: Optional[int] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import logging | ||
from autosync.services.service import Service | ||
from ..models.user import User | ||
from ..models.show import Show | ||
from ..models.movie import Movie | ||
from ..models.episode import Episode | ||
from ..models.watch_status import WatchStatus | ||
|
||
|
||
class Aggregate(Service): | ||
def __init__(self, services: list[Service]): | ||
self._services = [x for x in services if x.enabled] | ||
logging.info("Autosync enabled with %s", [x.name for x in self._services]) | ||
|
||
@property | ||
def name(self) -> str: | ||
return "aggragate" | ||
|
||
def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus): | ||
for service in self._services: | ||
try: | ||
service.update(user, resource, status) | ||
except Exception as e: | ||
logging.exception( | ||
"Unhandled error on autosync %s:", service.name, exc_info=e | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from abc import abstractmethod, abstractproperty | ||
|
||
from ..models.user import User | ||
from ..models.show import Show | ||
from ..models.movie import Movie | ||
from ..models.episode import Episode | ||
from ..models.watch_status import WatchStatus | ||
|
||
|
||
class Service: | ||
@abstractproperty | ||
def name(self) -> str: | ||
raise NotImplementedError | ||
|
||
@abstractproperty | ||
def enabled(self) -> bool: | ||
return True | ||
|
||
@abstractmethod | ||
def update(self, user: User, resource: Movie | Show | Episode, status: WatchStatus): | ||
raise NotImplementedError |
Oops, something went wrong.