aioaudiobookshelf 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of aioaudiobookshelf might be problematic. Click here for more details.
- aioaudiobookshelf/__init__.py +72 -0
- aioaudiobookshelf/client/__init__.py +189 -0
- aioaudiobookshelf/client/_base.py +110 -0
- aioaudiobookshelf/client/authors.py +34 -0
- aioaudiobookshelf/client/collections_.py +28 -0
- aioaudiobookshelf/client/items.py +108 -0
- aioaudiobookshelf/client/libraries.py +173 -0
- aioaudiobookshelf/client/me.py +103 -0
- aioaudiobookshelf/client/playlists.py +29 -0
- aioaudiobookshelf/client/podcasts.py +22 -0
- aioaudiobookshelf/client/series.py +27 -0
- aioaudiobookshelf/client/session.py +35 -0
- aioaudiobookshelf/exceptions.py +13 -0
- aioaudiobookshelf/helpers.py +56 -0
- aioaudiobookshelf/schema/__init__.py +14 -0
- aioaudiobookshelf/schema/audio.py +71 -0
- aioaudiobookshelf/schema/author.py +46 -0
- aioaudiobookshelf/schema/book.py +125 -0
- aioaudiobookshelf/schema/calls_authors.py +33 -0
- aioaudiobookshelf/schema/calls_collections.py +14 -0
- aioaudiobookshelf/schema/calls_items.py +53 -0
- aioaudiobookshelf/schema/calls_library.py +103 -0
- aioaudiobookshelf/schema/calls_login.py +28 -0
- aioaudiobookshelf/schema/calls_me.py +28 -0
- aioaudiobookshelf/schema/calls_playlists.py +14 -0
- aioaudiobookshelf/schema/calls_series.py +25 -0
- aioaudiobookshelf/schema/calls_session.py +17 -0
- aioaudiobookshelf/schema/collection.py +36 -0
- aioaudiobookshelf/schema/events_socket.py +46 -0
- aioaudiobookshelf/schema/file.py +22 -0
- aioaudiobookshelf/schema/folder.py +18 -0
- aioaudiobookshelf/schema/library.py +221 -0
- aioaudiobookshelf/schema/media_progress.py +42 -0
- aioaudiobookshelf/schema/playlist.py +74 -0
- aioaudiobookshelf/schema/podcast.py +129 -0
- aioaudiobookshelf/schema/series.py +45 -0
- aioaudiobookshelf/schema/series_books.py +34 -0
- aioaudiobookshelf/schema/server.py +76 -0
- aioaudiobookshelf/schema/session.py +78 -0
- aioaudiobookshelf/schema/user.py +81 -0
- aioaudiobookshelf-0.1.0.dist-info/LICENSE +201 -0
- aioaudiobookshelf-0.1.0.dist-info/METADATA +32 -0
- aioaudiobookshelf-0.1.0.dist-info/RECORD +45 -0
- aioaudiobookshelf-0.1.0.dist-info/WHEEL +5 -0
- aioaudiobookshelf-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Library Schema."""
|
|
2
|
+
# Discriminators don't work together with aliases.
|
|
3
|
+
# https://github.com/Fatal1ty/mashumaro/issues/254
|
|
4
|
+
# ruff: noqa: N815
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import StrEnum
|
|
8
|
+
from typing import Annotated
|
|
9
|
+
|
|
10
|
+
from mashumaro.types import Alias, Discriminator
|
|
11
|
+
|
|
12
|
+
from aioaudiobookshelf.schema.author import AuthorMinified
|
|
13
|
+
from aioaudiobookshelf.schema.series import SeriesFilterData
|
|
14
|
+
|
|
15
|
+
from . import _BaseModel
|
|
16
|
+
from .book import Book, BookExpanded, BookMinified
|
|
17
|
+
from .file import FileMetadata
|
|
18
|
+
from .folder import Folder
|
|
19
|
+
from .podcast import Podcast, PodcastExpanded, PodcastMinified
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LibraryIcons(StrEnum):
|
|
23
|
+
"""LibraryIcons."""
|
|
24
|
+
|
|
25
|
+
DATABASE = "database"
|
|
26
|
+
AUDIOBOOKSHELF = "audiobookshelf"
|
|
27
|
+
BOOKS1 = "books-1"
|
|
28
|
+
BOOKS2 = "books-2"
|
|
29
|
+
BOOK1 = "book-1"
|
|
30
|
+
MICROPHONE1 = "microphone-1"
|
|
31
|
+
MICROPHONE3 = "microphone-3"
|
|
32
|
+
RADIO = "radio"
|
|
33
|
+
PODCAST = "podcast"
|
|
34
|
+
RSS = "rss"
|
|
35
|
+
HEADPHONES = "headphones"
|
|
36
|
+
MUSIC = "music"
|
|
37
|
+
FILEPICTURE = "file-picture"
|
|
38
|
+
ROCKET = "rocket"
|
|
39
|
+
POWER = "power"
|
|
40
|
+
START = "star"
|
|
41
|
+
HEART = "heart"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class LibraryMediaType(StrEnum):
|
|
45
|
+
"""LibraryMediaType."""
|
|
46
|
+
|
|
47
|
+
BOOK = "book"
|
|
48
|
+
PODCAST = "podcast"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(kw_only=True)
|
|
52
|
+
class LibraryFile(_BaseModel):
|
|
53
|
+
"""LibraryFile."""
|
|
54
|
+
|
|
55
|
+
ino: str
|
|
56
|
+
metadata: FileMetadata
|
|
57
|
+
added_at: Annotated[int, Alias("addedAt")] # ms epoch
|
|
58
|
+
updated_at: Annotated[int, Alias("updatedAt")] # ms epoch
|
|
59
|
+
file_type: Annotated[str, Alias("fileType")]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(kw_only=True)
|
|
63
|
+
class LibrarySettings(_BaseModel):
|
|
64
|
+
"""LibrarySettings."""
|
|
65
|
+
|
|
66
|
+
cover_aspect_ratio: Annotated[int, Alias("coverAspectRatio")]
|
|
67
|
+
disable_watcher: Annotated[bool, Alias("disableWatcher")]
|
|
68
|
+
skip_matching_media_with_asin: Annotated[bool, Alias("skipMatchingMediaWithAsin")]
|
|
69
|
+
skip_matching_media_with_isbn: Annotated[bool, Alias("skipMatchingMediaWithIsbn")]
|
|
70
|
+
auto_scan_cron_expression: Annotated[str | None, Alias("autoScanCronExpression")] = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@dataclass(kw_only=True)
|
|
74
|
+
class Library(_BaseModel):
|
|
75
|
+
"""Library."""
|
|
76
|
+
|
|
77
|
+
id_: Annotated[str, Alias("id")]
|
|
78
|
+
name: str
|
|
79
|
+
folders: list[Folder]
|
|
80
|
+
display_order: Annotated[int, Alias("displayOrder")]
|
|
81
|
+
icon: LibraryIcons
|
|
82
|
+
media_type: Annotated[LibraryMediaType, Alias("mediaType")]
|
|
83
|
+
# TODO: add enum
|
|
84
|
+
provider: str
|
|
85
|
+
settings: LibrarySettings
|
|
86
|
+
created_at: Annotated[int, Alias("createdAt")] # ms epoch
|
|
87
|
+
last_update: Annotated[int, Alias("lastUpdate")] # ms epoch
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass(kw_only=True)
|
|
91
|
+
class _LibraryItemBase(_BaseModel):
|
|
92
|
+
id_: Annotated[str, Alias("id")]
|
|
93
|
+
ino: str
|
|
94
|
+
library_id: Annotated[str, Alias("libraryId")]
|
|
95
|
+
folder_id: Annotated[str, Alias("folderId")]
|
|
96
|
+
path: str
|
|
97
|
+
relative_path: Annotated[str, Alias("relPath")]
|
|
98
|
+
is_file: Annotated[bool, Alias("isFile")]
|
|
99
|
+
modified_time_ms: Annotated[int, Alias("mtimeMs")]
|
|
100
|
+
changed_time_ms: Annotated[int, Alias("ctimeMs")]
|
|
101
|
+
created_time_ms: Annotated[int, Alias("birthtimeMs")] # epoch
|
|
102
|
+
added_at: Annotated[int, Alias("addedAt")]
|
|
103
|
+
updated_at: Annotated[int, Alias("updatedAt")] # ms epoch
|
|
104
|
+
is_missing: Annotated[bool, Alias("isMissing")]
|
|
105
|
+
is_invalid: Annotated[bool, Alias("isInvalid")]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass(kw_only=True)
|
|
109
|
+
class LibraryItem(_LibraryItemBase):
|
|
110
|
+
"""LibraryItem."""
|
|
111
|
+
|
|
112
|
+
class Config(_LibraryItemBase.Config):
|
|
113
|
+
"""Config."""
|
|
114
|
+
|
|
115
|
+
discriminator = Discriminator(
|
|
116
|
+
field="mediaType",
|
|
117
|
+
include_subtypes=True,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
last_scan: Annotated[int | None, Alias("lastScan")] = None # ms epoch
|
|
121
|
+
scan_version: Annotated[str | None, Alias("scanVersion")] = None
|
|
122
|
+
library_files: Annotated[list[LibraryFile], Alias("libraryFiles")]
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@dataclass(kw_only=True)
|
|
126
|
+
class LibraryItemBook(LibraryItem):
|
|
127
|
+
"""LibraryItemBook."""
|
|
128
|
+
|
|
129
|
+
media: Book
|
|
130
|
+
mediaType: LibraryMediaType = LibraryMediaType.BOOK
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@dataclass(kw_only=True)
|
|
134
|
+
class LibraryItemPodcast(LibraryItem):
|
|
135
|
+
"""LibraryItemPodcast."""
|
|
136
|
+
|
|
137
|
+
media: Podcast
|
|
138
|
+
mediaType: LibraryMediaType = LibraryMediaType.PODCAST
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass(kw_only=True)
|
|
142
|
+
class LibraryItemMinified(_LibraryItemBase):
|
|
143
|
+
"""LibraryItemMinified."""
|
|
144
|
+
|
|
145
|
+
class Config(_LibraryItemBase.Config):
|
|
146
|
+
"""Config."""
|
|
147
|
+
|
|
148
|
+
discriminator = Discriminator(
|
|
149
|
+
field="mediaType",
|
|
150
|
+
include_subtypes=True,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
num_files: Annotated[int, Alias("numFiles")]
|
|
154
|
+
size: int
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@dataclass(kw_only=True)
|
|
158
|
+
class LibraryItemMinifiedBook(LibraryItemMinified):
|
|
159
|
+
"""LibraryItemMinifiedBook."""
|
|
160
|
+
|
|
161
|
+
media: BookMinified
|
|
162
|
+
mediaType: LibraryMediaType = LibraryMediaType.BOOK
|
|
163
|
+
# media_type: Annotated[LibraryMediaType, Alias("mediaType")] = LibraryMediaType.BOOK
|
|
164
|
+
# media_type: LibraryMediaType = field(
|
|
165
|
+
# metadata=field_options(alias="mediaType"), default=LibraryMediaType.BOOK
|
|
166
|
+
# )
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
@dataclass(kw_only=True)
|
|
170
|
+
class LibraryItemMinifiedPodcast(LibraryItemMinified):
|
|
171
|
+
"""LibraryItemMinifiedPodcast."""
|
|
172
|
+
|
|
173
|
+
media: PodcastMinified
|
|
174
|
+
mediaType: LibraryMediaType = LibraryMediaType.PODCAST
|
|
175
|
+
# media_type: Annotated[LibraryMediaType, Alias("mediaType")] = LibraryMediaType.PODCAST
|
|
176
|
+
# media_type: LibraryMediaType = field(
|
|
177
|
+
# metadata=field_options(alias="mediaType"), default=LibraryMediaType.PODCAST
|
|
178
|
+
# )
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass(kw_only=True)
|
|
182
|
+
class LibraryItemExpanded(LibraryItem):
|
|
183
|
+
"""LibraryItemExpanded."""
|
|
184
|
+
|
|
185
|
+
class Config(LibraryItem.Config):
|
|
186
|
+
"""Config."""
|
|
187
|
+
|
|
188
|
+
discriminator = Discriminator(
|
|
189
|
+
field="mediaType",
|
|
190
|
+
include_subtypes=True,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
size: int
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
@dataclass(kw_only=True)
|
|
197
|
+
class LibraryItemExpandedBook(LibraryItemExpanded):
|
|
198
|
+
"""LibraryItemExpandedBook."""
|
|
199
|
+
|
|
200
|
+
media: BookExpanded
|
|
201
|
+
mediaType: LibraryMediaType = LibraryMediaType.BOOK
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass(kw_only=True)
|
|
205
|
+
class LibraryItemExpandedPodcast(LibraryItemExpanded):
|
|
206
|
+
"""LibraryItemExpandedPodcast."""
|
|
207
|
+
|
|
208
|
+
media: PodcastExpanded
|
|
209
|
+
mediaType: LibraryMediaType = LibraryMediaType.PODCAST
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@dataclass(kw_only=True)
|
|
213
|
+
class LibraryFilterData(_BaseModel):
|
|
214
|
+
"""LibraryFilterData."""
|
|
215
|
+
|
|
216
|
+
authors: list[AuthorMinified]
|
|
217
|
+
genres: list[str]
|
|
218
|
+
tags: list[str]
|
|
219
|
+
series: list[SeriesFilterData]
|
|
220
|
+
narrators: list[str]
|
|
221
|
+
languages: list[str]
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Schema for media progress."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
from mashumaro.types import Alias
|
|
7
|
+
|
|
8
|
+
from . import _BaseModel
|
|
9
|
+
from .book import BookExpanded
|
|
10
|
+
from .podcast import PodcastEpisode, PodcastExpanded
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(kw_only=True)
|
|
14
|
+
class MediaProgress(_BaseModel):
|
|
15
|
+
"""MediaProgress."""
|
|
16
|
+
|
|
17
|
+
id_: Annotated[str, Alias("id")]
|
|
18
|
+
library_item_id: Annotated[str, Alias("libraryItemId")]
|
|
19
|
+
episode_id: Annotated[str | None, Alias("episodeId")] = None
|
|
20
|
+
duration: float # seconds
|
|
21
|
+
progress: float # percent 0->1
|
|
22
|
+
current_time: Annotated[float, Alias("currentTime")] # seconds
|
|
23
|
+
is_finished: Annotated[bool, Alias("isFinished")]
|
|
24
|
+
hide_from_continue_listening: Annotated[bool, Alias("hideFromContinueListening")]
|
|
25
|
+
last_update: Annotated[int, Alias("lastUpdate")] # ms epoch
|
|
26
|
+
started_at: Annotated[int, Alias("startedAt")] # ms epoch
|
|
27
|
+
finished_at: Annotated[int | None, Alias("finishedAt")] = None # ms epoch
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(kw_only=True)
|
|
31
|
+
class MediaProgressWithMediaBook(MediaProgress):
|
|
32
|
+
"""MediaProgressWithMediaBook."""
|
|
33
|
+
|
|
34
|
+
media: BookExpanded
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(kw_only=True)
|
|
38
|
+
class MediaProgressWithMediaPodcast(MediaProgress):
|
|
39
|
+
"""MediaProgressWithMediaPodcast."""
|
|
40
|
+
|
|
41
|
+
media: PodcastExpanded
|
|
42
|
+
episode: PodcastEpisode
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Schema for playlist."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
from mashumaro.types import Alias, Discriminator
|
|
7
|
+
|
|
8
|
+
from aioaudiobookshelf.schema.podcast import PodcastEpisodeExpanded
|
|
9
|
+
|
|
10
|
+
from . import _BaseModel
|
|
11
|
+
from .library import LibraryItemExpandedBook, LibraryItemMinifiedPodcast
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass(kw_only=True)
|
|
15
|
+
class PlaylistItem(_BaseModel):
|
|
16
|
+
"""PlaylistItem."""
|
|
17
|
+
|
|
18
|
+
library_item_id: Annotated[str, Alias("libraryItemId")]
|
|
19
|
+
episode_id: Annotated[str | None, Alias("episodeId")] = None
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass(kw_only=True)
|
|
23
|
+
class PlaylistItemExpanded(_BaseModel):
|
|
24
|
+
"""PlaylistExpanded."""
|
|
25
|
+
|
|
26
|
+
class Config(PlaylistItem.Config):
|
|
27
|
+
"""Config."""
|
|
28
|
+
|
|
29
|
+
# can't use field as episode_id is either existing or not.
|
|
30
|
+
discriminator = Discriminator(
|
|
31
|
+
include_subtypes=True,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(kw_only=True)
|
|
36
|
+
class PlaylistItemExpandedBook(PlaylistItemExpanded):
|
|
37
|
+
"""PlaylistExpanded."""
|
|
38
|
+
|
|
39
|
+
library_item: Annotated[LibraryItemExpandedBook, Alias("libraryItem")]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(kw_only=True)
|
|
43
|
+
class PlaylistItemExpandedPodcast(PlaylistItemExpanded):
|
|
44
|
+
"""PlaylistItemExpandedPodcast."""
|
|
45
|
+
|
|
46
|
+
library_item: Annotated[LibraryItemMinifiedPodcast, Alias("libraryItem")]
|
|
47
|
+
episode_id: Annotated[str, Alias("episodeId")]
|
|
48
|
+
episode: PodcastEpisodeExpanded
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(kw_only=True)
|
|
52
|
+
class _PlaylistBase(_BaseModel):
|
|
53
|
+
id_: Annotated[str, Alias("id")]
|
|
54
|
+
library_id: Annotated[str, Alias("libraryId")]
|
|
55
|
+
user_id: Annotated[str | None, Alias("userId")] = None
|
|
56
|
+
name: str
|
|
57
|
+
description: str | None = None
|
|
58
|
+
cover_path: Annotated[str | None, Alias("coverPath")] = None
|
|
59
|
+
last_update: Annotated[int, Alias("lastUpdate")] # ms epoch
|
|
60
|
+
created_at: Annotated[int, Alias("createdAt")] # ms epoch
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@dataclass(kw_only=True)
|
|
64
|
+
class Playlist(_PlaylistBase):
|
|
65
|
+
"""Playlist."""
|
|
66
|
+
|
|
67
|
+
items: list[PlaylistItem]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(kw_only=True)
|
|
71
|
+
class PlaylistExpanded(_PlaylistBase):
|
|
72
|
+
"""Playlist."""
|
|
73
|
+
|
|
74
|
+
items: list[PlaylistItemExpanded]
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""Schema for podcasts."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
from mashumaro.types import Alias
|
|
7
|
+
|
|
8
|
+
from . import _BaseModel
|
|
9
|
+
from .audio import AudioFile, AudioTrack
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(kw_only=True)
|
|
13
|
+
class PodcastMetadata(_BaseModel):
|
|
14
|
+
"""PodcastMetadata."""
|
|
15
|
+
|
|
16
|
+
title: str | None = None
|
|
17
|
+
author: str | None = None
|
|
18
|
+
description: str | None = None
|
|
19
|
+
release_date: Annotated[str | None, Alias("releaseDate")] = None
|
|
20
|
+
genres: list[str]
|
|
21
|
+
feed_url: Annotated[str | None, Alias("feedUrl")] = None
|
|
22
|
+
image_url: Annotated[str | None, Alias("imageUrl")] = None
|
|
23
|
+
itunes_page_url: Annotated[str | None, Alias("itunesPageUrl")] = None
|
|
24
|
+
itunes_id: Annotated[int | str | None, Alias("itunesId")] = None
|
|
25
|
+
# str: is not documented
|
|
26
|
+
itunes_artist_id: Annotated[int | str | None, Alias("itunesArtistId")] = None
|
|
27
|
+
explicit: bool
|
|
28
|
+
language: str | None = None
|
|
29
|
+
type_: Annotated[str | None, Alias("type")] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(kw_only=True)
|
|
33
|
+
class PodcastMetadataMinified(PodcastMetadata):
|
|
34
|
+
"""PodcastMetadataMinified."""
|
|
35
|
+
|
|
36
|
+
title_ignore_prefix: Annotated[str | None, Alias("titleIgnorePrefix")] = None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
PodcastMetaDataExpanded = PodcastMetadataMinified
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass(kw_only=True)
|
|
43
|
+
class PodcastEpisodeEnclosure(_BaseModel):
|
|
44
|
+
"""PodcastEpisodeEnclosure."""
|
|
45
|
+
|
|
46
|
+
url: str
|
|
47
|
+
type_: Annotated[str, Alias("type")]
|
|
48
|
+
length: str
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass(kw_only=True)
|
|
52
|
+
class _PodcastEpisodeBase(_BaseModel):
|
|
53
|
+
"""PodcastEpisode."""
|
|
54
|
+
|
|
55
|
+
library_item_id: Annotated[str, Alias("libraryItemId")]
|
|
56
|
+
id_: Annotated[str, Alias("id")]
|
|
57
|
+
index: int | None = None
|
|
58
|
+
season: str
|
|
59
|
+
episode: str
|
|
60
|
+
episode_type: Annotated[str, Alias("episodeType")]
|
|
61
|
+
title: str
|
|
62
|
+
subtitle: str
|
|
63
|
+
description: str
|
|
64
|
+
pub_date: Annotated[str, Alias("pubDate")]
|
|
65
|
+
published_at: Annotated[int | None, Alias("publishedAt")] = None # ms posix epoch
|
|
66
|
+
added_at: Annotated[int, Alias("addedAt")] # ms posix epoch
|
|
67
|
+
updated_at: Annotated[int, Alias("updatedAt")] # ms posix epoch
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@dataclass(kw_only=True)
|
|
71
|
+
class PodcastEpisode(_PodcastEpisodeBase):
|
|
72
|
+
"""PodcastEpisode."""
|
|
73
|
+
|
|
74
|
+
audio_file: AudioFile | None = None
|
|
75
|
+
enclosure: PodcastEpisodeEnclosure | None = None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass(kw_only=True)
|
|
79
|
+
class PodcastEpisodeExpanded(_PodcastEpisodeBase):
|
|
80
|
+
"""PodcastEpisodeExpanded."""
|
|
81
|
+
|
|
82
|
+
audio_track: Annotated[AudioTrack, Alias("audioTrack")]
|
|
83
|
+
duration: float
|
|
84
|
+
size: int
|
|
85
|
+
audio_file: AudioFile | None = None
|
|
86
|
+
enclosure: PodcastEpisodeEnclosure | None = None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@dataclass(kw_only=True)
|
|
90
|
+
class _PodcastBase(_BaseModel):
|
|
91
|
+
"""_PodcastBase."""
|
|
92
|
+
|
|
93
|
+
cover_path: Annotated[str | None, Alias("coverPath")] = None
|
|
94
|
+
auto_download_episodes: Annotated[bool, Alias("autoDownloadEpisodes")]
|
|
95
|
+
auto_download_schedule: Annotated[str, Alias("autoDownloadSchedule")]
|
|
96
|
+
# None is not documented
|
|
97
|
+
last_episode_check_ms: Annotated[int | None, Alias("lastEpisodeCheck")] = None
|
|
98
|
+
max_episodes_to_keep: Annotated[int, Alias("maxEpisodesToKeep")] # 0 = all
|
|
99
|
+
max_new_episodes_to_download: Annotated[int, Alias("maxNewEpisodesToDownload")]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@dataclass(kw_only=True)
|
|
103
|
+
class Podcast(_PodcastBase):
|
|
104
|
+
"""ABSPodcast."""
|
|
105
|
+
|
|
106
|
+
library_item_id: Annotated[str, Alias("libraryItemId")]
|
|
107
|
+
metadata: PodcastMetadata
|
|
108
|
+
tags: list[str]
|
|
109
|
+
episodes: list[PodcastEpisode]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@dataclass(kw_only=True)
|
|
113
|
+
class PodcastMinified(_PodcastBase):
|
|
114
|
+
"""ABSPodcastMinified."""
|
|
115
|
+
|
|
116
|
+
metadata: PodcastMetadataMinified
|
|
117
|
+
size: int # bytes
|
|
118
|
+
num_episodes: Annotated[int, Alias("numEpisodes")]
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
@dataclass(kw_only=True)
|
|
122
|
+
class PodcastExpanded(_PodcastBase):
|
|
123
|
+
"""PodcastEpisodeExpanded."""
|
|
124
|
+
|
|
125
|
+
library_item_id: Annotated[str, Alias("libraryItemId")]
|
|
126
|
+
tags: list[str]
|
|
127
|
+
size: int # bytes
|
|
128
|
+
metadata: PodcastMetaDataExpanded
|
|
129
|
+
episodes: list[PodcastEpisodeExpanded]
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Schema for series."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
from mashumaro.types import Alias
|
|
7
|
+
|
|
8
|
+
from . import _BaseModel
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(kw_only=True)
|
|
12
|
+
class _SeriesBase(_BaseModel):
|
|
13
|
+
"""_SeriesBase."""
|
|
14
|
+
|
|
15
|
+
id_: Annotated[str, Alias("id")]
|
|
16
|
+
name: str
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# in get_library call including filterdata we get only id and name of series
|
|
20
|
+
SeriesFilterData = _SeriesBase
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(kw_only=True)
|
|
24
|
+
class Series(_SeriesBase):
|
|
25
|
+
"""Series."""
|
|
26
|
+
|
|
27
|
+
description: str | None = None
|
|
28
|
+
added_at: Annotated[int, Alias("addedAt")] # ms epoch
|
|
29
|
+
updated_at: Annotated[int, Alias("updatedAt")] # ms epoch
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass(kw_only=True)
|
|
33
|
+
class SeriesNumBooks(_SeriesBase):
|
|
34
|
+
"""SeriesNumBooks."""
|
|
35
|
+
|
|
36
|
+
name_ignore_prefix: Annotated[str, Alias("nameIgnorePrefix")]
|
|
37
|
+
library_item_ids: Annotated[list[str], Alias("libraryItemIds")]
|
|
38
|
+
num_books: Annotated[int, Alias("numBooks")]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(kw_only=True)
|
|
42
|
+
class SeriesSequence(_SeriesBase):
|
|
43
|
+
"""Series Sequence."""
|
|
44
|
+
|
|
45
|
+
sequence: str | None = None
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""SeriesBase classes."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Annotated
|
|
5
|
+
|
|
6
|
+
from mashumaro.types import Alias
|
|
7
|
+
|
|
8
|
+
from .library import LibraryItemBook, LibraryItemMinifiedBook
|
|
9
|
+
from .series import _SeriesBase
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(kw_only=True)
|
|
13
|
+
class _SeriesBooksBase(_SeriesBase):
|
|
14
|
+
"""SeriesBooks."""
|
|
15
|
+
|
|
16
|
+
added_at: Annotated[int, Alias("addedAt")] # ms epoch
|
|
17
|
+
name_ignore_prefix: Annotated[str, Alias("nameIgnorePrefix")]
|
|
18
|
+
name_ignore_prefix_sort: Annotated[str, Alias("nameIgnorePrefixSort")]
|
|
19
|
+
type_: Annotated[str, Alias("type")]
|
|
20
|
+
total_duration: Annotated[float, Alias("totalDuration")] # s
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass(kw_only=True)
|
|
24
|
+
class SeriesBooks(_SeriesBooksBase):
|
|
25
|
+
"""SeriesBooks."""
|
|
26
|
+
|
|
27
|
+
books: list[LibraryItemBook]
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass(kw_only=True)
|
|
31
|
+
class SeriesBooksMinified(_SeriesBase):
|
|
32
|
+
"""SeriesBooks."""
|
|
33
|
+
|
|
34
|
+
books: list[LibraryItemMinifiedBook]
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Server Schema."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from enum import Enum, StrEnum
|
|
5
|
+
from typing import Annotated
|
|
6
|
+
|
|
7
|
+
from mashumaro.types import Alias
|
|
8
|
+
|
|
9
|
+
from . import _BaseModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ServerSettingsMetadataFileFormat(StrEnum):
|
|
13
|
+
"""ServerSettingsMetadataFileFormat."""
|
|
14
|
+
|
|
15
|
+
ABS = "abs"
|
|
16
|
+
JSON = "json"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ServerSettingsDateFormat(StrEnum):
|
|
20
|
+
"""ServerSettingsDateFormat."""
|
|
21
|
+
|
|
22
|
+
MM_DD_YYYY = "MM/dd/yyyy"
|
|
23
|
+
DD_MM_YYYY = "dd/MM/yyyy"
|
|
24
|
+
DDpMMpYYYY = "dd.MM.yyyy"
|
|
25
|
+
YYYY_MM_DD = "yyyy-MM-dd"
|
|
26
|
+
MMM_DO_YYYY = "MMM do, yyyy"
|
|
27
|
+
MMMM_DO_YYYY = "MMMM do, yyyy"
|
|
28
|
+
DD_MMM_YYYY = "dd MMM yyyy"
|
|
29
|
+
DD_MMMM_YYYY = "dd MMMM yyyy"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ServerSettingsTimeFormat(StrEnum):
|
|
33
|
+
"""ServerSettingsTimeFormat."""
|
|
34
|
+
|
|
35
|
+
TWENTY_FOUR_HOOUR = "HH:mm"
|
|
36
|
+
TWELVE_HOUR = "h:mma"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ServerLogLevel(Enum):
|
|
40
|
+
"""ServerLogLevel."""
|
|
41
|
+
|
|
42
|
+
DEBUG = 1
|
|
43
|
+
INFO = 2
|
|
44
|
+
WARNING = 3
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(kw_only=True)
|
|
48
|
+
class ServerSettings(_BaseModel):
|
|
49
|
+
"""ServerSettings."""
|
|
50
|
+
|
|
51
|
+
id: Annotated[str, Alias("id")]
|
|
52
|
+
scanner_find_covers: Annotated[bool, Alias("scannerFindCovers")]
|
|
53
|
+
scanner_cover_provider: Annotated[str, Alias("scannerCoverProvider")]
|
|
54
|
+
scanner_parse_subtitle: Annotated[bool, Alias("scannerParseSubtitle")]
|
|
55
|
+
scanner_prefer_matched_metadata: Annotated[bool, Alias("scannerPreferMatchedMetadata")]
|
|
56
|
+
scanner_disable_watcher: Annotated[bool, Alias("scannerDisableWatcher")]
|
|
57
|
+
store_cover_with_item: Annotated[bool, Alias("storeCoverWithItem")]
|
|
58
|
+
store_metadata_with_item: Annotated[bool, Alias("storeMetadataWithItem")]
|
|
59
|
+
metadata_file_format: Annotated[ServerSettingsMetadataFileFormat, Alias("metadataFileFormat")]
|
|
60
|
+
rate_limit_login_requests: Annotated[int, Alias("rateLimitLoginRequests")]
|
|
61
|
+
rate_limit_login_window: Annotated[int, Alias("rateLimitLoginWindow")] # ms
|
|
62
|
+
backup_schedule: Annotated[str, Alias("backupSchedule")]
|
|
63
|
+
backups_to_keep: Annotated[int, Alias("backupsToKeep")]
|
|
64
|
+
max_backup_size: Annotated[int, Alias("maxBackupSize")] # GB
|
|
65
|
+
logger_daily_logs_to_keep: Annotated[int, Alias("loggerDailyLogsToKeep")]
|
|
66
|
+
logger_scanner_logs_to_keep: Annotated[int, Alias("loggerScannerLogsToKeep")]
|
|
67
|
+
home_bookshelf_view: Annotated[int, Alias("homeBookshelfView")]
|
|
68
|
+
bookshelf_view: Annotated[int, Alias("bookshelfView")]
|
|
69
|
+
sorting_ignore_prefix: Annotated[bool, Alias("sortingIgnorePrefix")]
|
|
70
|
+
sorting_prefixes: Annotated[list[str], Alias("sortingPrefixes")]
|
|
71
|
+
chromecast_enabled: Annotated[bool, Alias("chromecastEnabled")]
|
|
72
|
+
date_format: Annotated[ServerSettingsDateFormat, Alias("dateFormat")]
|
|
73
|
+
time_format: Annotated[ServerSettingsTimeFormat, Alias("timeFormat")]
|
|
74
|
+
language: str
|
|
75
|
+
log_level: Annotated[ServerLogLevel, Alias("logLevel")]
|
|
76
|
+
version: str
|