sonolink 0.0.0__tar.gz

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.
Files changed (84) hide show
  1. sonolink-0.0.0/LICENSE +21 -0
  2. sonolink-0.0.0/PKG-INFO +107 -0
  3. sonolink-0.0.0/README.md +69 -0
  4. sonolink-0.0.0/pyproject.toml +87 -0
  5. sonolink-0.0.0/setup.cfg +4 -0
  6. sonolink-0.0.0/sonolink/__init__.py +50 -0
  7. sonolink-0.0.0/sonolink/_registry.py +36 -0
  8. sonolink-0.0.0/sonolink/_version.py +48 -0
  9. sonolink-0.0.0/sonolink/errors.py +31 -0
  10. sonolink-0.0.0/sonolink/gateway/__init__.py +38 -0
  11. sonolink-0.0.0/sonolink/gateway/cache.py +120 -0
  12. sonolink-0.0.0/sonolink/gateway/client/__init__.py +411 -0
  13. sonolink-0.0.0/sonolink/gateway/client/_base.py +23 -0
  14. sonolink-0.0.0/sonolink/gateway/client/_factory.py +48 -0
  15. sonolink-0.0.0/sonolink/gateway/client/adapters/__init__.py +11 -0
  16. sonolink-0.0.0/sonolink/gateway/client/adapters/_disnake.py +55 -0
  17. sonolink-0.0.0/sonolink/gateway/client/adapters/_dpy.py +55 -0
  18. sonolink-0.0.0/sonolink/gateway/client/adapters/_pycord.py +55 -0
  19. sonolink-0.0.0/sonolink/gateway/enums.py +150 -0
  20. sonolink-0.0.0/sonolink/gateway/errors.py +72 -0
  21. sonolink-0.0.0/sonolink/gateway/event_models.py +234 -0
  22. sonolink-0.0.0/sonolink/gateway/node.py +790 -0
  23. sonolink-0.0.0/sonolink/gateway/player/__init__.py +191 -0
  24. sonolink-0.0.0/sonolink/gateway/player/_base.py +746 -0
  25. sonolink-0.0.0/sonolink/gateway/player/_factory.py +130 -0
  26. sonolink-0.0.0/sonolink/gateway/player/adapters/__init__.py +11 -0
  27. sonolink-0.0.0/sonolink/gateway/player/adapters/_disnake.py +228 -0
  28. sonolink-0.0.0/sonolink/gateway/player/adapters/_dpy.py +227 -0
  29. sonolink-0.0.0/sonolink/gateway/player/adapters/_pycord.py +207 -0
  30. sonolink-0.0.0/sonolink/gateway/player/handlers/__init__.py +16 -0
  31. sonolink-0.0.0/sonolink/gateway/player/handlers/_autoplay.py +127 -0
  32. sonolink-0.0.0/sonolink/gateway/player/handlers/_base.py +44 -0
  33. sonolink-0.0.0/sonolink/gateway/player/handlers/_events.py +231 -0
  34. sonolink-0.0.0/sonolink/gateway/player/handlers/_incativity.py +121 -0
  35. sonolink-0.0.0/sonolink/gateway/player/handlers/_lifecycle.py +170 -0
  36. sonolink-0.0.0/sonolink/gateway/player/handlers/_playback.py +224 -0
  37. sonolink-0.0.0/sonolink/gateway/queue/__init__.py +17 -0
  38. sonolink-0.0.0/sonolink/gateway/queue/base.py +240 -0
  39. sonolink-0.0.0/sonolink/gateway/queue/history.py +61 -0
  40. sonolink-0.0.0/sonolink/gateway/queue/queue.py +461 -0
  41. sonolink-0.0.0/sonolink/gateway/schemas/__init__.py +12 -0
  42. sonolink-0.0.0/sonolink/gateway/schemas/events.py +86 -0
  43. sonolink-0.0.0/sonolink/gateway/schemas/receive.py +149 -0
  44. sonolink-0.0.0/sonolink/models/__init__.py +17 -0
  45. sonolink-0.0.0/sonolink/models/base.py +207 -0
  46. sonolink-0.0.0/sonolink/models/filters.py +800 -0
  47. sonolink-0.0.0/sonolink/models/info.py +180 -0
  48. sonolink-0.0.0/sonolink/models/player_info.py +119 -0
  49. sonolink-0.0.0/sonolink/models/playlist.py +117 -0
  50. sonolink-0.0.0/sonolink/models/responses.py +110 -0
  51. sonolink-0.0.0/sonolink/models/settings.py +165 -0
  52. sonolink-0.0.0/sonolink/models/track.py +218 -0
  53. sonolink-0.0.0/sonolink/network/__init__.py +93 -0
  54. sonolink-0.0.0/sonolink/network/_aiohttp.py +140 -0
  55. sonolink-0.0.0/sonolink/network/_curl_cffi.py +157 -0
  56. sonolink-0.0.0/sonolink/network/base.py +107 -0
  57. sonolink-0.0.0/sonolink/network/errors.py +65 -0
  58. sonolink-0.0.0/sonolink/network/message.py +67 -0
  59. sonolink-0.0.0/sonolink/rest/__init__.py +22 -0
  60. sonolink-0.0.0/sonolink/rest/enums.py +115 -0
  61. sonolink-0.0.0/sonolink/rest/errors.py +104 -0
  62. sonolink-0.0.0/sonolink/rest/http/__init__.py +118 -0
  63. sonolink-0.0.0/sonolink/rest/http/base.py +17 -0
  64. sonolink-0.0.0/sonolink/rest/http/info.py +31 -0
  65. sonolink-0.0.0/sonolink/rest/http/planner.py +40 -0
  66. sonolink-0.0.0/sonolink/rest/http/player.py +52 -0
  67. sonolink-0.0.0/sonolink/rest/http/session.py +26 -0
  68. sonolink-0.0.0/sonolink/rest/http/track.py +38 -0
  69. sonolink-0.0.0/sonolink/rest/schemas/__init__.py +64 -0
  70. sonolink-0.0.0/sonolink/rest/schemas/filters.py +279 -0
  71. sonolink-0.0.0/sonolink/rest/schemas/info.py +210 -0
  72. sonolink-0.0.0/sonolink/rest/schemas/planner.py +138 -0
  73. sonolink-0.0.0/sonolink/rest/schemas/player.py +166 -0
  74. sonolink-0.0.0/sonolink/rest/schemas/playlist.py +43 -0
  75. sonolink-0.0.0/sonolink/rest/schemas/session.py +51 -0
  76. sonolink-0.0.0/sonolink/rest/schemas/track.py +130 -0
  77. sonolink-0.0.0/sonolink/utils/__init__.py +12 -0
  78. sonolink-0.0.0/sonolink/utils/properties.py +99 -0
  79. sonolink-0.0.0/sonolink/utils/snowflake.py +16 -0
  80. sonolink-0.0.0/sonolink.egg-info/PKG-INFO +107 -0
  81. sonolink-0.0.0/sonolink.egg-info/SOURCES.txt +82 -0
  82. sonolink-0.0.0/sonolink.egg-info/dependency_links.txt +1 -0
  83. sonolink-0.0.0/sonolink.egg-info/requires.txt +13 -0
  84. sonolink-0.0.0/sonolink.egg-info/top_level.txt +1 -0
sonolink-0.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present SonoLink Development Team.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,107 @@
1
+ Metadata-Version: 2.4
2
+ Name: sonolink
3
+ Version: 0.0.0
4
+ Summary: A high-performance Lavalink v4 wrapper for Python, inspired by WaveLink.
5
+ Author: vmphase, Soheab, DA-344 (aka Developer Anonymous)
6
+ Maintainer: vmphase, DA-344 (aka Developer Anonymous), Soheab
7
+ License: MIT
8
+ Project-URL: Repository, https://github.com/sonolink/sonolink
9
+ Keywords: lavalink,wavelink,fork,sonolink,discord.py,discord,music,audio,bot,library,python,asyncio,pycord,py-cord,disnake
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Framework :: AsyncIO
12
+ Classifier: Natural Language :: English
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: Implementation :: CPython
18
+ Classifier: Topic :: Internet
19
+ Classifier: Topic :: Software Development :: Libraries
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Utilities
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.12
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: aiohttp<4,>=3.11.0
27
+ Requires-Dist: msgspec<1,>=0.20.0
28
+ Requires-Dist: typing_extensions>=4.0.0
29
+ Requires-Dist: packaging<27.0,>=26.0
30
+ Provides-Extra: speed
31
+ Requires-Dist: curl-cffi<1,>=0.14.0; extra == "speed"
32
+ Provides-Extra: docs
33
+ Requires-Dist: sphinx>=9.1.0; extra == "docs"
34
+ Requires-Dist: furo; extra == "docs"
35
+ Requires-Dist: sphinx-copybutton; extra == "docs"
36
+ Requires-Dist: sphinx-autobuild>=2024.10.3; extra == "docs"
37
+ Dynamic: license-file
38
+
39
+ <div align="center">
40
+
41
+ ![SonoLink](https://raw.githubusercontent.com/sonolink/sonolink/main/docs/_static/images/banner.png)
42
+
43
+ **SonoLink** is a high-performance Lavalink v4 wrapper for Python, inspired by [WaveLink](https://github.com/PythonistaGuild/Wavelink).
44
+
45
+ [Documentation](https://sonolink.readthedocs.io/en/latest) · [Discord](https://discord.gg/tPHVWBPedt) · [Migration from WaveLink](https://sonolink.readthedocs.io/en/latest/guides/migrating-from-wavelink.html)
46
+
47
+
48
+
49
+ [![PyPI](https://img.shields.io/pypi/v/sonolink)](https://pypi.org/project/sonolink)
50
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org)
51
+ [![License](https://img.shields.io/github/license/sonolink/sonolink)](LICENSE)
52
+ [![Lavalink](https://img.shields.io/badge/lavalink-4.x-orange)](https://lavalink.dev)
53
+ [![Discord](https://img.shields.io/discord/1471146455002775624?label=discord)](https://discord.gg/tPHVWBPedt)
54
+
55
+ </div>
56
+
57
+ ---
58
+
59
+ ## Features
60
+
61
+ - Full Lavalink v4+ REST API support
62
+ - Built on [msgspec](https://github.com/jcrist/msgspec) for rapid serialization and strict type validation
63
+ - Optional [curl_cffi](https://github.com/lexiforest/curl_cffi) for faster networking
64
+ - Drop-in familiarity for Wavelink users — [migration guide included](https://sonolink.readthedocs.io/en/latest/guides/migrating-from-wavelink.html)
65
+ - Async-first and [Basedpyright](https://docs.basedpyright.com/latest/) strict-compliant
66
+ - Built-in support for [discord.py](https://github.com/Rapptz/discord.py), [pycord](https://github.com/Pycord-Development/pycord), and [disnake](https://github.com/DisnakeDev/disnake)
67
+
68
+ ## Installation
69
+
70
+ > [!NOTE]
71
+ > A [virtual environment](https://docs.python.org/3/library/venv.html) is recommended, especially on Linux where the system Python may restrict package installations.
72
+ >
73
+ ### Requirements:
74
+ - Python 3.12 or higher
75
+ - A running Lavalink 4.x server ([guide on setup](https://sonolink.readthedocs.io/en/latest/guides/lavalink-setup.html))
76
+ - Any of the supported libraries:
77
+ - [discord.py](https://pypi.org/project/discord.py)[voice] 2.7+
78
+ - [py-cord](https://pypi.org/project/py-cord)[voice] 2.8+
79
+ - [disnake](https://pypi.org/project/disnake)[voice] 2.12+
80
+
81
+ To install the stable version from PyPI:
82
+ ```sh
83
+ # Linux/macOS
84
+ python3 -m pip install -U sonolink
85
+
86
+ # Windows
87
+ py -3 -m pip install -U sonolink
88
+ ```
89
+
90
+ To install with optional speed improvements:
91
+ ```sh
92
+ # Linux/macOS
93
+ python3 -m pip install -U "sonolink[speed]"
94
+
95
+ # Windows
96
+ py -3 -m pip install -U "sonolink[speed]"
97
+ ```
98
+
99
+ <br>
100
+
101
+ <p align="center">
102
+ <img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/footers/gray0_ctp_on_line.svg?sanitize=true" />
103
+ </p>
104
+
105
+ <p align="center">
106
+ <i><code>&copy 2026 <a href="https://github.com/sonolink">SonoLink Development Team</a></code></i>
107
+ </p>
@@ -0,0 +1,69 @@
1
+ <div align="center">
2
+
3
+ ![SonoLink](https://raw.githubusercontent.com/sonolink/sonolink/main/docs/_static/images/banner.png)
4
+
5
+ **SonoLink** is a high-performance Lavalink v4 wrapper for Python, inspired by [WaveLink](https://github.com/PythonistaGuild/Wavelink).
6
+
7
+ [Documentation](https://sonolink.readthedocs.io/en/latest) · [Discord](https://discord.gg/tPHVWBPedt) · [Migration from WaveLink](https://sonolink.readthedocs.io/en/latest/guides/migrating-from-wavelink.html)
8
+
9
+
10
+
11
+ [![PyPI](https://img.shields.io/pypi/v/sonolink)](https://pypi.org/project/sonolink)
12
+ [![Python](https://img.shields.io/badge/python-3.12%2B-blue)](https://www.python.org)
13
+ [![License](https://img.shields.io/github/license/sonolink/sonolink)](LICENSE)
14
+ [![Lavalink](https://img.shields.io/badge/lavalink-4.x-orange)](https://lavalink.dev)
15
+ [![Discord](https://img.shields.io/discord/1471146455002775624?label=discord)](https://discord.gg/tPHVWBPedt)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - Full Lavalink v4+ REST API support
24
+ - Built on [msgspec](https://github.com/jcrist/msgspec) for rapid serialization and strict type validation
25
+ - Optional [curl_cffi](https://github.com/lexiforest/curl_cffi) for faster networking
26
+ - Drop-in familiarity for Wavelink users — [migration guide included](https://sonolink.readthedocs.io/en/latest/guides/migrating-from-wavelink.html)
27
+ - Async-first and [Basedpyright](https://docs.basedpyright.com/latest/) strict-compliant
28
+ - Built-in support for [discord.py](https://github.com/Rapptz/discord.py), [pycord](https://github.com/Pycord-Development/pycord), and [disnake](https://github.com/DisnakeDev/disnake)
29
+
30
+ ## Installation
31
+
32
+ > [!NOTE]
33
+ > A [virtual environment](https://docs.python.org/3/library/venv.html) is recommended, especially on Linux where the system Python may restrict package installations.
34
+ >
35
+ ### Requirements:
36
+ - Python 3.12 or higher
37
+ - A running Lavalink 4.x server ([guide on setup](https://sonolink.readthedocs.io/en/latest/guides/lavalink-setup.html))
38
+ - Any of the supported libraries:
39
+ - [discord.py](https://pypi.org/project/discord.py)[voice] 2.7+
40
+ - [py-cord](https://pypi.org/project/py-cord)[voice] 2.8+
41
+ - [disnake](https://pypi.org/project/disnake)[voice] 2.12+
42
+
43
+ To install the stable version from PyPI:
44
+ ```sh
45
+ # Linux/macOS
46
+ python3 -m pip install -U sonolink
47
+
48
+ # Windows
49
+ py -3 -m pip install -U sonolink
50
+ ```
51
+
52
+ To install with optional speed improvements:
53
+ ```sh
54
+ # Linux/macOS
55
+ python3 -m pip install -U "sonolink[speed]"
56
+
57
+ # Windows
58
+ py -3 -m pip install -U "sonolink[speed]"
59
+ ```
60
+
61
+ <br>
62
+
63
+ <p align="center">
64
+ <img src="https://raw.githubusercontent.com/catppuccin/catppuccin/main/assets/footers/gray0_ctp_on_line.svg?sanitize=true" />
65
+ </p>
66
+
67
+ <p align="center">
68
+ <i><code>&copy 2026 <a href="https://github.com/sonolink">SonoLink Development Team</a></code></i>
69
+ </p>
@@ -0,0 +1,87 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ dynamic = ["version"]
7
+ name = "sonolink"
8
+ dependencies = [
9
+ "aiohttp>=3.11.0,<4",
10
+ "msgspec>=0.20.0,<1",
11
+ "typing_extensions>=4.0.0",
12
+ "packaging>=26.0,<27.0",
13
+ ]
14
+ requires-python = ">=3.12"
15
+ authors = [
16
+ { name = "vmphase" },
17
+ { name = "Soheab" },
18
+ { name = "DA-344 (aka Developer Anonymous)" },
19
+ ]
20
+ maintainers = [
21
+ { name = "vmphase" },
22
+ { name = "DA-344 (aka Developer Anonymous)" },
23
+ { name = "Soheab" },
24
+ ]
25
+ description = "A high-performance Lavalink v4 wrapper for Python, inspired by WaveLink."
26
+ readme = "README.md"
27
+ license = { text = "MIT" }
28
+ keywords = [
29
+ "lavalink",
30
+ "wavelink",
31
+ "fork",
32
+ "sonolink",
33
+ "discord.py",
34
+ "discord",
35
+ "music",
36
+ "audio",
37
+ "bot",
38
+ "library",
39
+ "python",
40
+ "asyncio",
41
+ "pycord",
42
+ "py-cord",
43
+ "disnake",
44
+ ]
45
+ classifiers = [
46
+ "Development Status :: 5 - Production/Stable",
47
+ "Framework :: AsyncIO",
48
+ "Natural Language :: English",
49
+ "Operating System :: OS Independent",
50
+ "Programming Language :: Python :: 3.12",
51
+ "Programming Language :: Python :: 3.13",
52
+ "Programming Language :: Python :: 3.14",
53
+ "Programming Language :: Python :: Implementation :: CPython",
54
+ "Topic :: Internet",
55
+ "Topic :: Software Development :: Libraries",
56
+ "Topic :: Software Development :: Libraries :: Python Modules",
57
+ "Topic :: Utilities",
58
+ "Typing :: Typed",
59
+ ]
60
+
61
+ [project.optional-dependencies]
62
+ speed = ["curl-cffi>=0.14.0,<1"]
63
+ docs = [
64
+ "sphinx>=9.1.0",
65
+ "furo",
66
+ "sphinx-copybutton",
67
+ "sphinx-autobuild>=2024.10.3",
68
+ ]
69
+
70
+ [project.urls]
71
+ Repository = "https://github.com/sonolink/sonolink"
72
+
73
+ [tool.basedpyright]
74
+ pythonVersion = "3.12"
75
+ typeCheckingMode = "strict"
76
+ reportPrivateUsage = false
77
+ reportUnnecessaryComparison = false
78
+ exclude = ["docs/"]
79
+
80
+ [tool.ruff]
81
+ exclude = ["docs/"]
82
+
83
+ [tool.ruff.lint]
84
+ ignore = ["F405", "F403"]
85
+
86
+ [tool.setuptools.dynamic]
87
+ version = { attr = "sonolink._version.__version__" }
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,50 @@
1
+ """
2
+ sonolink
3
+ ~~~~~~
4
+
5
+ A high-performance Lavalink v4 wrapper for Python, inspired by WaveLink.
6
+
7
+ :copyright: (c) 2026-present SonoLink Development Team
8
+ :license: MIT
9
+ """
10
+
11
+ from . import gateway, models, rest, utils
12
+ from ._version import __version__, version_info
13
+ from .gateway import *
14
+ from .rest import *
15
+ from .utils import *
16
+
17
+ __all__ = (
18
+ "__version__",
19
+ "version_info",
20
+ "Client",
21
+ "Node",
22
+ "Player",
23
+ "gateway",
24
+ "models",
25
+ "rest",
26
+ "utils",
27
+ "PlayerConnectionState",
28
+ "NodeStatus",
29
+ "TrackEndReason",
30
+ "TrackExceptionSeverity",
31
+ "QueueMode",
32
+ "AutoPlayMode",
33
+ "InactivityMode",
34
+ "SearchProvider",
35
+ "NodeError",
36
+ "InvalidNodePassword",
37
+ "NodeURINotFound",
38
+ "QueueEmpty",
39
+ "HistoryEmpty",
40
+ "Queue",
41
+ "History",
42
+ "ExceptionSeverity",
43
+ "TrackLoadResult",
44
+ "TrackSourceType",
45
+ "RoutePlannerType",
46
+ "IPBlockType",
47
+ "ErrorResponseType",
48
+ "HTTPException",
49
+ "cached_property",
50
+ )
@@ -0,0 +1,36 @@
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2026-present SonoLink Development Team.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ from typing import TYPE_CHECKING, Any
28
+ from weakref import WeakKeyDictionary
29
+
30
+ if TYPE_CHECKING:
31
+ from .gateway.client import Client
32
+
33
+
34
+ __all__ = ("clients",)
35
+
36
+ clients: WeakKeyDictionary[Any, Client[Any]] = WeakKeyDictionary()
@@ -0,0 +1,48 @@
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2026-present SonoLink Development Team.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ from __future__ import annotations
26
+ from typing import Literal, NamedTuple
27
+
28
+ __all__ = ("version_info", "__version__")
29
+
30
+
31
+ class VersionInfo(NamedTuple):
32
+ major: int
33
+ minor: int
34
+ patch: int
35
+ release_level: Literal["alpha", "beta", "candidate", "final"]
36
+
37
+ def __str__(self) -> str:
38
+ return self.as_str()
39
+
40
+ def as_str(self) -> str:
41
+ base = f"{self.major}.{self.minor}.{self.patch}"
42
+ suffixes = {"alpha": "a0", "beta": "b0", "candidate": "rc0"}
43
+ suffix = suffixes.get(self.release_level, "")
44
+ return base + suffix
45
+
46
+
47
+ version_info = VersionInfo(major=0, minor=0, patch=0, release_level="final")
48
+ __version__ = version_info.as_str()
@@ -0,0 +1,31 @@
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2026-present SonoLink Development Team.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ __all__ = ("SonoLinkException",)
28
+
29
+
30
+ class SonoLinkException(Exception):
31
+ """Base exception class for all errors on this library."""
@@ -0,0 +1,38 @@
1
+ """
2
+ sonolink.gateway
3
+ ~~~~~~~~~~~~~~
4
+
5
+ Module that handles gateway-related objects.
6
+
7
+ :copyright: (c) 2026-present SonoLink Development Team
8
+ :license: MIT
9
+ """
10
+
11
+ from .client import *
12
+ from .enums import *
13
+ from .errors import *
14
+ from .event_models import *
15
+ from .node import *
16
+ from .player import *
17
+ from .queue import *
18
+
19
+ __all__ = (
20
+ "AutoPlayMode",
21
+ "Client",
22
+ "History",
23
+ "HistoryEmpty",
24
+ "InactivityMode",
25
+ "InvalidNodePassword",
26
+ "Node",
27
+ "NodeError",
28
+ "NodeStatus",
29
+ "NodeURINotFound",
30
+ "Player",
31
+ "PlayerConnectionState",
32
+ "Queue",
33
+ "QueueEmpty",
34
+ "QueueMode",
35
+ "SearchProvider",
36
+ "TrackEndReason",
37
+ "TrackExceptionSeverity",
38
+ )
@@ -0,0 +1,120 @@
1
+ """
2
+ MIT License
3
+
4
+ Copyright (c) 2026-present SonoLink Development Team.
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import collections
28
+ from typing import Any, Final
29
+
30
+ import msgspec
31
+
32
+ from sonolink.models.settings import CacheSettings
33
+
34
+ UNSET: Final = msgspec.UNSET
35
+
36
+
37
+ class CacheNode[K, V]:
38
+ __slots__ = ("key", "value", "freq", "prev", "next")
39
+
40
+ def __init__(self, key: K, value: V, freq: int = 1) -> None:
41
+ self.key: K = key
42
+ self.value: V = value
43
+ self.freq: int = freq
44
+
45
+ self.prev: CacheNode[K, V] = self
46
+ self.next: CacheNode[K, V] = self
47
+
48
+
49
+ class LFUCache[K, V]:
50
+ """
51
+ LFU cache utilizing Circular Doubly Linked Lists.
52
+ """
53
+
54
+ __slots__ = ("_settings", "_cache", "_freq_map", "_min_freq")
55
+
56
+ def __init__(self, settings: CacheSettings | None = None) -> None:
57
+ self._settings = settings or CacheSettings.default()
58
+
59
+ self._cache: dict[K, CacheNode[K, V]] = {}
60
+ self._freq_map: dict[int, CacheNode[Any, Any]] = collections.defaultdict(
61
+ lambda: CacheNode(None, None, 0)
62
+ )
63
+ self._min_freq: int = 0
64
+
65
+ def __repr__(self) -> str:
66
+ return f"<LFUCache entries={len(self._cache)} max_items={self._settings.max_items}>"
67
+
68
+ def __len__(self) -> int:
69
+ return len(self._cache)
70
+
71
+ def _unlink(self, node: CacheNode[K, V]) -> None:
72
+ """Remove a node from its current circular list."""
73
+ node.prev.next = node.next
74
+ node.next.prev = node.prev
75
+
76
+ def _link(self, sentinel: CacheNode[Any, Any], node: CacheNode[K, V]) -> None:
77
+ """Add a node to the end of a circular list (just before the sentinel)."""
78
+ node.next = sentinel
79
+ node.prev = sentinel.prev
80
+ sentinel.prev.next = node
81
+ sentinel.prev = node
82
+
83
+ def get(self, key: K, default: Any = UNSET) -> V | Any:
84
+ if not self._settings.enabled or (node := self._cache.get(key)) is None:
85
+ return default
86
+
87
+ self._unlink(node)
88
+
89
+ # If the min_freq list is empty (sentinel points to itself)
90
+ if (
91
+ node.freq == self._min_freq
92
+ and self._freq_map[node.freq].next is self._freq_map[node.freq]
93
+ ):
94
+ self._min_freq += 1
95
+
96
+ node.freq += 1
97
+ self._link(self._freq_map[node.freq], node)
98
+ return node.value
99
+
100
+ def put(self, key: K, value: V) -> None:
101
+ if not self._settings.enabled or self._settings.max_items <= 0:
102
+ return
103
+
104
+ if key in self._cache:
105
+ node = self._cache[key]
106
+ node.value = value
107
+ self.get(key)
108
+ return
109
+
110
+ if len(self._cache) >= self._settings.max_items:
111
+ # Evict the oldest node from the lowest freq. list
112
+ sentinel = self._freq_map[self._min_freq]
113
+ evicted = sentinel.next
114
+ self._unlink(evicted)
115
+ del self._cache[evicted.key]
116
+
117
+ new_node = CacheNode(key, value)
118
+ self._cache[key] = new_node
119
+ self._link(self._freq_map[1], new_node)
120
+ self._min_freq = 1