[scrobbles] Fix dataclass parsing and add puzzles to urls
This commit is contained in:
@ -1,5 +1,3 @@
|
||||
from functools import cached_property
|
||||
import inspect
|
||||
import json
|
||||
from dataclasses import asdict, dataclass
|
||||
from typing import Optional
|
||||
@ -33,214 +31,25 @@ class JSONDataclass(JSONWizard):
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScrobbleLogData(JSONDataclass):
|
||||
description: Optional[str] = None
|
||||
class BaseLogData(JSONDataclass):
|
||||
details: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class LongPlayLogData(JSONDataclass):
|
||||
serial_scrobble_id: Optional[int]
|
||||
long_play_complete: bool = False
|
||||
|
||||
|
||||
class WithOthersLogData(JSONDataclass):
|
||||
with_user_ids: Optional[list[int]] = None
|
||||
with_names_str: Optional[list[str]] = None
|
||||
|
||||
@property
|
||||
def with_names(self) -> list[str]:
|
||||
with_names = []
|
||||
if self.with_user_ids:
|
||||
with_names += [u.full_name for u in self.with_users if u]
|
||||
if self.with_names_str:
|
||||
with_names += [u for u in self.with_names_str]
|
||||
return with_names
|
||||
|
||||
@property
|
||||
def with_users(self) -> list[User]:
|
||||
with_users = []
|
||||
if self.with_user_ids:
|
||||
with_users = [
|
||||
User.objects.filter(id=i).first() for i in self.with_user_ids
|
||||
]
|
||||
return with_users
|
||||
|
||||
|
||||
@dataclass
|
||||
class BoardGameScoreLogData(JSONDataclass):
|
||||
person_id: Optional[int] = None
|
||||
bgg_username: str = ""
|
||||
color: Optional[str] = None
|
||||
character: Optional[str] = None
|
||||
team: Optional[str] = None
|
||||
score: Optional[int] = None
|
||||
win: Optional[bool] = None
|
||||
new: Optional[bool] = None
|
||||
rank: Optional[int] = None
|
||||
seat_order: Optional[int] = None
|
||||
role: Optional[str] = None
|
||||
rank: Optional[int] = None
|
||||
seat_order: Optional[int] = None
|
||||
role: Optional[str] = None
|
||||
lichess_username: Optional[str] = None
|
||||
# Legacy
|
||||
user_id: Optional[int] = None
|
||||
name_str: Optional[str] = None
|
||||
|
||||
|
||||
@property
|
||||
def person(self) -> Optional[Person]:
|
||||
return Person.objects.filter(id=self.person_id).first()
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
name = ""
|
||||
if self.person:
|
||||
name = self.person.name
|
||||
return name
|
||||
|
||||
def __str__(self) -> str:
|
||||
out = self.name
|
||||
if self.score:
|
||||
out += f" {self.score}"
|
||||
if self.color:
|
||||
out += f" ({self.color})"
|
||||
if self.win:
|
||||
out += f" [W]"
|
||||
return out
|
||||
|
||||
|
||||
@dataclass
|
||||
class BoardGameLogData(LongPlayLogData):
|
||||
complete: Optional[bool] = None
|
||||
serial_scrobble_id: Optional[int] = None
|
||||
long_play_complete: Optional[bool] = None
|
||||
players: Optional[list[BoardGameScoreLogData]] = None
|
||||
location_id: Optional[int] = None
|
||||
difficulty: Optional[int] = None
|
||||
solo: Optional[bool] = None
|
||||
two_handed: Optional[bool] = None
|
||||
expansion_ids: Optional[int] = None
|
||||
moves: Optional[list] = None
|
||||
rated: Optional[str] = None
|
||||
speed: Optional[str] = None
|
||||
variant: Optional[str] = None
|
||||
lichess_id: Optional[int] = None
|
||||
board: Optional[str] = None
|
||||
rounds: Optional[int] = None
|
||||
details: Optional[str] = None
|
||||
# Legacy
|
||||
learning: Optional[bool] = None
|
||||
location: Optional[str] = None
|
||||
geo_location_id: Optional[int] = None
|
||||
scenario: Optional[str] = None
|
||||
@cached_property
|
||||
def geo_location(self) -> Optional[GeoLocation]:
|
||||
if self.geo_location_id:
|
||||
return GeoLocation.objects.filter(id=self.geo_location_id).first()
|
||||
|
||||
@cached_property
|
||||
def player_log(self) -> str:
|
||||
if self.players:
|
||||
return ", ".join([BoardGameScoreLogData(**player).__str__() for player in self.players])
|
||||
return ""
|
||||
|
||||
@dataclass
|
||||
class BookPageLogData(JSONDataclass):
|
||||
page_number: Optional[int] = None
|
||||
end_ts: Optional[int] = None
|
||||
start_ts: Optional[int] = None
|
||||
duration: Optional[int] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BookLogData(LongPlayLogData):
|
||||
long_play_complete: Optional[bool] = None
|
||||
koreader_hash: Optional[str] = None
|
||||
page_data: Optional[dict[int, BookPageLogData]] = None
|
||||
pages_read: Optional[int] = None
|
||||
page_start: Optional[int] = None
|
||||
page_end: Optional[int] = None
|
||||
serial_scrobble_id: Optional[int] = None
|
||||
details: Optional[str] = None
|
||||
class WithPeopleLogData(JSONDataclass):
|
||||
with_people_ids: Optional[list[int]] = None
|
||||
|
||||
@property
|
||||
def with_people(self) -> list["Person"]:
|
||||
from people.models import Person
|
||||
|
||||
@dataclass
|
||||
class LifeEventLogData(WithOthersLogData):
|
||||
with_user_ids: Optional[list[int]] = None
|
||||
with_names_str: Optional[list[str]] = None
|
||||
location: Optional[str] = None
|
||||
geo_location_id: Optional[int] = None
|
||||
details: Optional[str] = None
|
||||
|
||||
def geo_location(self):
|
||||
return GeoLocation.objects.filter(id=self.geo_location_id).first()
|
||||
|
||||
|
||||
@dataclass
|
||||
class MoodLogData(JSONDataclass):
|
||||
reasons: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class VideoLogData(JSONDataclass):
|
||||
title: str
|
||||
video_type: str
|
||||
run_time_seconds: int
|
||||
kind: str
|
||||
year: Optional[int]
|
||||
episode_number: Optional[int] = None
|
||||
source_url: Optional[str] = None
|
||||
imdbID: Optional[str] = None
|
||||
season_number: Optional[int] = None
|
||||
cover_url: Optional[str] = None
|
||||
next_imdb_id: Optional[int] = None
|
||||
tv_series_id: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class VideoGameLogData(LongPlayLogData):
|
||||
serial_scrobble_id: Optional[int] = None
|
||||
long_play_complete: Optional[bool] = False
|
||||
console: Optional[str] = None
|
||||
emulated: Optional[bool] = False
|
||||
emulator: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BrickSetLogData(LongPlayLogData, WithOthersLogData):
|
||||
serial_scrobble_id: Optional[int]
|
||||
long_play_complete: bool = False
|
||||
with_user_ids: Optional[list[int]] = None
|
||||
with_names_str: Optional[list[str]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class TrailLogData(WithOthersLogData):
|
||||
with_user_ids: Optional[list[int]] = None
|
||||
with_names_str: Optional[list[str]] = None
|
||||
details: Optional[str] = None
|
||||
effort: Optional[str] = None
|
||||
difficulty: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BeerLogData(WithOthersLogData):
|
||||
with_user_ids: Optional[list[int]] = None
|
||||
with_names_str: Optional[list[str]] = None
|
||||
details: Optional[str] = None
|
||||
rating: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class FoodLogData(JSONDataclass):
|
||||
meal: Optional[str] = None
|
||||
details: Optional[str] = None
|
||||
rating: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class PuzzleLogData(JSONDataclass):
|
||||
with_others: Optional[str] = None
|
||||
rating: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
if not self.with_people_ids:
|
||||
return []
|
||||
return [Person.objects.filter(id=pid) for pid in self.with_people_ids]
|
||||
|
||||
Reference in New Issue
Block a user