-
-
Notifications
You must be signed in to change notification settings - Fork 601
Expand file tree
/
Copy pathassets.py
More file actions
140 lines (109 loc) · 5.27 KB
/
Copy pathassets.py
File metadata and controls
140 lines (109 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
from __future__ import annotations
from functools import cached_property
from typing import TYPE_CHECKING
from sqlalchemy import BigInteger, ForeignKey, String
from sqlalchemy.orm import Mapped, mapped_column, relationship, validates
from models.base import (
FILE_EXTENSION_MAX_LENGTH,
FILE_NAME_MAX_LENGTH,
FILE_PATH_MAX_LENGTH,
BaseModel,
compute_file_name_parts,
)
if TYPE_CHECKING:
from models.device_save_sync import DeviceSaveSync
from models.rom import Rom
from models.user import User
class BaseAsset(BaseModel):
__abstract__ = True
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
file_name: Mapped[str] = mapped_column(String(length=FILE_NAME_MAX_LENGTH))
file_name_no_tags: Mapped[str] = mapped_column(String(length=FILE_NAME_MAX_LENGTH))
file_name_no_ext: Mapped[str] = mapped_column(String(length=FILE_NAME_MAX_LENGTH))
file_extension: Mapped[str] = mapped_column(
String(length=FILE_EXTENSION_MAX_LENGTH)
)
file_path: Mapped[str] = mapped_column(String(length=FILE_PATH_MAX_LENGTH))
file_size_bytes: Mapped[int] = mapped_column(BigInteger(), default=0)
missing_from_fs: Mapped[bool] = mapped_column(default=False, nullable=False)
@validates("file_name")
def _sync_file_name_parts(self, _key: str, file_name: str) -> str:
"""Derive the stored `file_name_no_tags` / `file_name_no_ext` /
`file_extension` columns whenever `file_name` is assigned.
Defined on the abstract base so every asset subclass inherits it.
"""
parts = compute_file_name_parts(file_name)
self.file_name_no_tags = parts.no_tags
self.file_name_no_ext = parts.no_ext
self.file_extension = parts.extension
return file_name
@cached_property
def full_path(self) -> str:
return f"{self.file_path}/{self.file_name}"
@cached_property
def download_path(self) -> str:
return f"/api/raw/assets/{self.full_path}?timestamp={self.updated_at}"
class RomAsset(BaseAsset):
__abstract__ = True
rom_id: Mapped[int] = mapped_column(ForeignKey("roms.id", ondelete="CASCADE"))
user_id: Mapped[int] = mapped_column(ForeignKey("users.id", ondelete="CASCADE"))
class Screenshot(RomAsset):
__tablename__ = "screenshots"
__table_args__ = {"extend_existing": True}
# `is_gallery` distinguishes intentionally-uploaded gallery screenshots from
# the auto-captured save/state thumbnails that also live in this table.
# `is_public` mirrors RomNote — lets other users browse a user's public
# screenshots (community). Both default false; save/state thumbnails keep the
# defaults, only the gallery upload endpoint sets `is_gallery=True`.
is_gallery: Mapped[bool] = mapped_column(default=False)
is_public: Mapped[bool] = mapped_column(default=False)
rom: Mapped[Rom] = relationship(lazy="joined", back_populates="screenshots")
user: Mapped[User] = relationship(lazy="joined", back_populates="screenshots")
class Save(RomAsset):
__tablename__ = "saves"
__table_args__ = {"extend_existing": True}
emulator: Mapped[str | None] = mapped_column(String(length=50))
slot: Mapped[str | None] = mapped_column(String(length=255))
content_hash: Mapped[str | None] = mapped_column(String(length=32))
origin_device_id: Mapped[str | None] = mapped_column(
String(length=255),
ForeignKey("devices.id", ondelete="SET NULL"),
default=None,
)
# `is_public` mirrors Screenshot/RomNote — lets other users browse and
# download a user's public saves (community). Defaults false (private).
is_public: Mapped[bool] = mapped_column(default=False)
rom: Mapped[Rom] = relationship(lazy="joined", back_populates="saves")
user: Mapped[User] = relationship(lazy="joined", back_populates="saves")
device_syncs: Mapped[list[DeviceSaveSync]] = relationship(
back_populates="save",
cascade="all, delete-orphan",
lazy="raise",
)
@cached_property
def screenshot(self) -> Screenshot | None:
from handler.database import db_screenshot_handler
return db_screenshot_handler.get_screenshot(
rom_id=self.rom_id,
user_id=self.user_id,
file_name=self.file_name, # Match state filename against screenshot filename stem
file_name_no_ext=self.file_name_no_ext,
)
class State(RomAsset):
__tablename__ = "states"
__table_args__ = {"extend_existing": True}
emulator: Mapped[str | None] = mapped_column(String(length=50))
# `is_public` mirrors Screenshot/RomNote — lets other users browse and
# download a user's public states (community). Defaults false (private).
is_public: Mapped[bool] = mapped_column(default=False)
rom: Mapped[Rom] = relationship(lazy="joined", back_populates="states")
user: Mapped[User] = relationship(lazy="joined", back_populates="states")
@cached_property
def screenshot(self) -> Screenshot | None:
from handler.database import db_screenshot_handler
return db_screenshot_handler.get_screenshot(
rom_id=self.rom_id,
user_id=self.user_id,
file_name=self.file_name, # Match state filename against screenshot filename stem
file_name_no_ext=self.file_name_no_ext,
)