aioaudiobookshelf 0.1.1__py3-none-any.whl → 0.1.3__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.

@@ -3,15 +3,16 @@
3
3
  from aiohttp.client_exceptions import ClientResponseError, InvalidUrlClientError
4
4
 
5
5
  from aioaudiobookshelf.client import AdminClient, SessionConfiguration, SocketClient, UserClient
6
- from aioaudiobookshelf.exceptions import LoginError
7
- from aioaudiobookshelf.schema.calls_login import LoginParameters, LoginResponse
6
+ from aioaudiobookshelf.exceptions import LoginError, TokenIsMissingError
7
+ from aioaudiobookshelf.schema.calls_login import AuthorizeResponse, LoginParameters, LoginResponse
8
8
 
9
- __version__ = "0.1.1"
9
+ __version__ = "0.1.3"
10
10
 
11
11
 
12
12
  async def _get_login_response(
13
13
  *, session_config: SessionConfiguration, username: str, password: str
14
14
  ) -> LoginResponse:
15
+ """Login via username and password."""
15
16
  login_request = LoginParameters(username=username, password=password).to_dict()
16
17
 
17
18
  try:
@@ -26,6 +27,42 @@ async def _get_login_response(
26
27
  return LoginResponse.from_json(await resp.read())
27
28
 
28
29
 
30
+ async def _get_authorize_response(*, session_config: SessionConfiguration) -> AuthorizeResponse:
31
+ """Login via token."""
32
+ try:
33
+ resp = await session_config.session.post(
34
+ f"{session_config.url}/api/authorize",
35
+ ssl=session_config.verify_ssl,
36
+ raise_for_status=True,
37
+ headers=session_config.headers,
38
+ )
39
+ except (ClientResponseError, InvalidUrlClientError, TokenIsMissingError) as exc:
40
+ raise LoginError from exc
41
+ return AuthorizeResponse.from_json(await resp.read())
42
+
43
+
44
+ async def get_user_client_by_token(*, session_config: SessionConfiguration) -> UserClient:
45
+ """Get user client by token. Token must be set in session_config."""
46
+ authorize_response = await _get_authorize_response(session_config=session_config)
47
+ return UserClient(session_config=session_config, login_response=authorize_response)
48
+
49
+
50
+ async def get_user_and_socket_client_by_token(
51
+ *, session_config: SessionConfiguration
52
+ ) -> tuple[UserClient, SocketClient]:
53
+ """Get user and socket client by token. Token must be set in session_config."""
54
+ authorize_response = await _get_authorize_response(session_config=session_config)
55
+ user_client = UserClient(session_config=session_config, login_response=authorize_response)
56
+ socket_client = SocketClient(session_config=session_config)
57
+ return user_client, socket_client
58
+
59
+
60
+ async def get_admin_client_by_token(*, session_config: SessionConfiguration) -> AdminClient:
61
+ """Get admin client by token. Token must be set in session_config."""
62
+ authorize_response = await _get_authorize_response(session_config=session_config)
63
+ return AdminClient(session_config=session_config, login_response=authorize_response)
64
+
65
+
29
66
  async def get_user_client(
30
67
  *,
31
68
  session_config: SessionConfiguration,
@@ -9,7 +9,7 @@ import socketio
9
9
  import socketio.exceptions
10
10
  from aiohttp import ClientSession
11
11
 
12
- from aioaudiobookshelf.exceptions import BadUserError
12
+ from aioaudiobookshelf.exceptions import BadUserError, TokenIsMissingError
13
13
  from aioaudiobookshelf.schema.events_socket import (
14
14
  LibraryItemRemoved,
15
15
  PodcastEpisodeDownload,
@@ -37,7 +37,7 @@ class SessionConfiguration:
37
37
  session: ClientSession
38
38
  url: str
39
39
  verify_ssl: bool = True
40
- token: str = ""
40
+ token: str | None = None
41
41
  pagination_items_per_page: int = 10
42
42
  logger: logging.Logger | None = None
43
43
 
@@ -45,7 +45,7 @@ class SessionConfiguration:
45
45
  def headers(self) -> dict[str, str]:
46
46
  """Session headers."""
47
47
  if self.token is None:
48
- raise RuntimeError("Token not set.")
48
+ raise TokenIsMissingError("Token not set.")
49
49
  return {"Authorization": f"Bearer {self.token}"}
50
50
 
51
51
  def __post_init__(self) -> None:
@@ -97,7 +97,7 @@ class BaseClient:
97
97
  """DELETE request to abs api."""
98
98
  try:
99
99
  await self.session_config.session.delete(
100
- endpoint,
100
+ f"{self.session_config.url}/{endpoint}",
101
101
  ssl=self.session_config.verify_ssl,
102
102
  headers=self.session_config.headers,
103
103
  raise_for_status=True,
@@ -11,3 +11,7 @@ class LoginError(Exception):
11
11
 
12
12
  class ApiError(Exception):
13
13
  """Exception raised if call to api failed."""
14
+
15
+
16
+ class TokenIsMissingError(Exception):
17
+ """Exception raised if token is missing."""
@@ -26,3 +26,7 @@ class LoginResponse(DataClassJSONMixin):
26
26
  user_default_library_id: Annotated[str, Alias("userDefaultLibraryId")]
27
27
  server_settings: Annotated[ServerSettings, Alias("serverSettings")]
28
28
  source: Annotated[str, Alias("Source")]
29
+
30
+
31
+ # api/authorize, if token is used for authorization
32
+ AuthorizeResponse = LoginResponse
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.2
2
+ Name: aioaudiobookshelf
3
+ Version: 0.1.3
4
+ Summary: Async library for Audiobookshelf
5
+ Author-email: Fabian Munkes <105975993+fmunkes@users.noreply.github.com>
6
+ License: Apache-2.0
7
+ Platform: any
8
+ Classifier: Environment :: Console
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Classifier: Programming Language :: Python :: 3.13
11
+ Requires-Python: >=3.12
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: aiohttp
15
+ Requires-Dist: mashumaro
16
+ Requires-Dist: python-socketio>=5.12
17
+ Provides-Extra: test
18
+ Requires-Dist: codespell==2.3.0; extra == "test"
19
+ Requires-Dist: isort==5.13.2; extra == "test"
20
+ Requires-Dist: mypy==1.13.0; extra == "test"
21
+ Requires-Dist: pre-commit==4.0.1; extra == "test"
22
+ Requires-Dist: pre-commit-hooks==5.0.0; extra == "test"
23
+ Requires-Dist: pytest==8.3.4; extra == "test"
24
+ Requires-Dist: pytest-aiohttp==1.0.5; extra == "test"
25
+ Requires-Dist: pytest-cov==5.0.0; extra == "test"
26
+ Requires-Dist: syrupy==4.8.1; extra == "test"
27
+ Requires-Dist: tomli==2.2.1; extra == "test"
28
+ Requires-Dist: ruff==0.9.2; extra == "test"
29
+ Requires-Dist: bumpver; extra == "test"
30
+
31
+ # aioaudiobookshelf
32
+ Async python library to interact with
33
+ [Audiobookshelf](https://github.com/advplyr/audiobookshelf) (ABS).
34
+
35
+ This lib's primary goal is to be used within the Audiobookshelf music provider
36
+ in Music Assistant, but it can be used independently. Calls to endpoints not
37
+ needed for the provider will be added over time.
38
+
39
+ Not all endpoints are yet implemented.
40
+
41
+ ## Releases
42
+ Releases can be found on [pypi](https://pypi.org/project/aioaudiobookshelf/),
43
+ and are tagged.
44
+
45
+ ## Basic usage
46
+ ABS has a rest api, documented
47
+ [here](https://api.audiobookshelf.org) and additionally uses socket.io, see
48
+ [here](https://api.audiobookshelf.org/#socket) for some event driven
49
+ functionality.
50
+ Accessibility to the endpoints is determined by the [user
51
+ types](https://api.audiobookshelf.org/#user), which may be `root, admin, user, guest`.
52
+ This lib is not tested with a `guest` user.
53
+
54
+ As of `0.1.2` this lib has two different clients, the `UserClient` and the
55
+ `SocketClient`. Admin endpoints are not yet implemented. The user client
56
+ handles calls to the Rest API, the socket client allows to subscribe to certain
57
+ events.
58
+
59
+ To authenticate the socket client, you always need the user's token, username
60
+ and password are not enough. The user client can be authenticated by username
61
+ and password, which yields the token.
62
+
63
+ Usage example:
64
+ ```python
65
+ import asyncio
66
+ import logging
67
+ import os
68
+
69
+ import aiohttp
70
+
71
+ from aioaudiobookshelf import SessionConfiguration, get_user_client
72
+ from aioaudiobookshelf.schema.library import LibraryItemMinifiedBook, LibraryItemMinifiedPodcast
73
+
74
+ ABS_HOST = os.environ.get("ABS_HOST")
75
+ ABS_USER = os.environ.get("ABS_USER")
76
+ ABS_PASSWORD = os.environ.get("ABS_PASSWORD")
77
+
78
+
79
+ async def abs_basics():
80
+ assert ABS_HOST is not None
81
+ assert ABS_USER is not None
82
+ assert ABS_PASSWORD is not None
83
+
84
+ logger = logging.getLogger()
85
+ logger.setLevel(logging.INFO)
86
+
87
+ async with aiohttp.ClientSession() as session:
88
+ client = await get_user_client(
89
+ session_config=SessionConfiguration(
90
+ session=session, url=ABS_HOST, logger=logger, pagination_items_per_page=30
91
+ ),
92
+ username=ABS_USER,
93
+ password=ABS_PASSWORD,
94
+ )
95
+
96
+ # get libraries
97
+ libraries = await client.get_all_libraries()
98
+
99
+ # get library items
100
+ for library in libraries:
101
+ async for response in client.get_library_items(library_id=library.id_):
102
+ if not response.results:
103
+ break
104
+ for lib_item_minified in response.results:
105
+ if isinstance(lib_item_minified, LibraryItemMinifiedPodcast):
106
+ ...
107
+ if isinstance(lib_item_minified, LibraryItemMinifiedBook):
108
+ ...
109
+
110
+ # get a single podcast
111
+ podcast_id = "dda96167-eaad-4012-83e1-149c6700d3e8"
112
+ podcast_expanded = client.get_library_item_podcast(podcast_id=podcast_id, expanded=True)
113
+
114
+
115
+ asyncio.run(abs_basics())
116
+ ```
117
+
118
+ Have a look into `aioaudiobookshelf/client/*.py` to see which endpoints are
119
+ currently implemented. And the [provider
120
+ implementation](https://github.com/music-assistant/server/blob/dev/music_assistant/providers/audiobookshelf/__init__.py) shows, how the lib can potentially be used.
@@ -1,8 +1,8 @@
1
- aioaudiobookshelf/__init__.py,sha256=IAfzHf7g91fL00jEwYQU9Qww11y6ZuSfZgw_aRz3WMY,2328
2
- aioaudiobookshelf/exceptions.py,sha256=_RtQE75rMnMkEfHxHN0D1N1pcEOLiGI1-Ajjdix1flk,289
1
+ aioaudiobookshelf/__init__.py,sha256=0EEeNclXbVxB0ihoNGvWevaWt-SpLj3okzHDIVCR0mU,4138
2
+ aioaudiobookshelf/exceptions.py,sha256=JQNdqBaR5AhuCUBg5DH5-orkfJrx_CJpe53ignWD6vE,377
3
3
  aioaudiobookshelf/helpers.py,sha256=ImZntca2l39P285TVVrFah82MjrP4wXLnVd7LMoD5Ck,1581
4
- aioaudiobookshelf/client/__init__.py,sha256=wQ7AB-Ly3G6hGNtU0Fg9bnYPtyZiznNe1Ubwdwm1H88,6894
5
- aioaudiobookshelf/client/_base.py,sha256=edEkmSrzSFcq38DQMYHLkWeOp6yCYSdDA3WGO9lyyxg,3784
4
+ aioaudiobookshelf/client/__init__.py,sha256=YnrNm2ZmQeVqGQ8EfAKIPRI4p2cLFqCzv4uKgL6HJPM,6931
5
+ aioaudiobookshelf/client/_base.py,sha256=1S0ACN-fiXKy0uVVLb422LGFB4bOvVFnSvyEDM47-v0,3815
6
6
  aioaudiobookshelf/client/authors.py,sha256=8bXN0NsPvH1rvF166xUu7rVC-0P0Sp4N7oxZrO666nc,1129
7
7
  aioaudiobookshelf/client/collections_.py,sha256=Z3r7dxHhzMm_cGCMRJkVzN5-Eesftib3d0bs4iXmmzY,879
8
8
  aioaudiobookshelf/client/items.py,sha256=4yWy7Shd6sbKj4MSGYJXklXs-yZH2q95qGIm4L-PS5o,3624
@@ -20,7 +20,7 @@ aioaudiobookshelf/schema/calls_authors.py,sha256=eIvdyEcrmXuOxFJuCX39cGU9HSZprl4
20
20
  aioaudiobookshelf/schema/calls_collections.py,sha256=nXurha41Y1atAuOWG9aXJbYo66qgcFUaW02QPEVdo4w,319
21
21
  aioaudiobookshelf/schema/calls_items.py,sha256=KF8s6WNbsVUIxAuN9TZBBGsysnxfw-FQWM9XRTljOpo,1547
22
22
  aioaudiobookshelf/schema/calls_library.py,sha256=IX4vf55fUW5wLADo1QnCIg3tEhtQ2UuyKsZWpx5CmtU,2543
23
- aioaudiobookshelf/schema/calls_login.py,sha256=36HeRkoIyTLQbsSMxVq1PiE0iLnR48VsOfKsc_VDI6E,703
23
+ aioaudiobookshelf/schema/calls_login.py,sha256=squLCKxXHRxzlm4-1BOCDQ5-Zics1717JuZ89STkN5g,791
24
24
  aioaudiobookshelf/schema/calls_me.py,sha256=jdpvExRytoqX8FHkzq4N9RtKn50cmTc_B693e9lLCHQ,693
25
25
  aioaudiobookshelf/schema/calls_playlists.py,sha256=Ll1scstd1NNc6PXgkhmWUfqSzIR07LKzqBCEvrVHACE,305
26
26
  aioaudiobookshelf/schema/calls_series.py,sha256=aUdlTR01UE2APN0pGS1h7x0ydsREqZf53mKaHq2zeh4,597
@@ -38,8 +38,8 @@ aioaudiobookshelf/schema/series_books.py,sha256=rs8a4JmSHqJR6WPA2XKXmC6XDq8D9wmz
38
38
  aioaudiobookshelf/schema/server.py,sha256=yWBRxtwtX1USs43yGFuDIM3jfWbmduW3GRahisOUCqw,2726
39
39
  aioaudiobookshelf/schema/session.py,sha256=jqCHNUthuzE6jhgG3UwFgagl1HA_rfDwn6Te38jaqC8,2684
40
40
  aioaudiobookshelf/schema/user.py,sha256=Zcnl6gqfc97dmHrNOHVsX_OOqwcJq-eFMhc9zVMLIs4,2057
41
- aioaudiobookshelf-0.1.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
42
- aioaudiobookshelf-0.1.1.dist-info/METADATA,sha256=qY_lHwOyIzg-fG_HSU4eHKYirUlrP4M5D47U-P68BOA,1184
43
- aioaudiobookshelf-0.1.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
44
- aioaudiobookshelf-0.1.1.dist-info/top_level.txt,sha256=2_I2_xz98xmVIT84pcF3tlq3NdZNKskfs7BqUmYZylk,18
45
- aioaudiobookshelf-0.1.1.dist-info/RECORD,,
41
+ aioaudiobookshelf-0.1.3.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
42
+ aioaudiobookshelf-0.1.3.dist-info/METADATA,sha256=ljk8u6oZQb4vvS8meJbMlxxC_HrT0rfs9GCzzJzntOE,4377
43
+ aioaudiobookshelf-0.1.3.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
44
+ aioaudiobookshelf-0.1.3.dist-info/top_level.txt,sha256=2_I2_xz98xmVIT84pcF3tlq3NdZNKskfs7BqUmYZylk,18
45
+ aioaudiobookshelf-0.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (75.8.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,32 +0,0 @@
1
- Metadata-Version: 2.2
2
- Name: aioaudiobookshelf
3
- Version: 0.1.1
4
- Summary: Async library for Audiobookshelf
5
- Author-email: Fabian Munkes <105975993+fmunkes@users.noreply.github.com>
6
- License: Apache-2.0
7
- Platform: any
8
- Classifier: Environment :: Console
9
- Classifier: Programming Language :: Python :: 3.12
10
- Classifier: Programming Language :: Python :: 3.13
11
- Requires-Python: >=3.12
12
- Description-Content-Type: text/markdown
13
- License-File: LICENSE
14
- Requires-Dist: aiohttp
15
- Requires-Dist: mashumaro
16
- Requires-Dist: python-socketio>=5.12
17
- Provides-Extra: test
18
- Requires-Dist: codespell==2.3.0; extra == "test"
19
- Requires-Dist: isort==5.13.2; extra == "test"
20
- Requires-Dist: mypy==1.13.0; extra == "test"
21
- Requires-Dist: pre-commit==4.0.1; extra == "test"
22
- Requires-Dist: pre-commit-hooks==5.0.0; extra == "test"
23
- Requires-Dist: pytest==8.3.4; extra == "test"
24
- Requires-Dist: pytest-aiohttp==1.0.5; extra == "test"
25
- Requires-Dist: pytest-cov==5.0.0; extra == "test"
26
- Requires-Dist: syrupy==4.8.1; extra == "test"
27
- Requires-Dist: tomli==2.2.1; extra == "test"
28
- Requires-Dist: ruff==0.9.2; extra == "test"
29
- Requires-Dist: bumpver; extra == "test"
30
-
31
- # aioaudiobookshelf
32
- Async python library to interact with Audiobookshelf