chzzk-python 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.
- chzzk/__init__.py +175 -0
- chzzk/_version.py +34 -0
- chzzk/api/__init__.py +29 -0
- chzzk/api/base.py +147 -0
- chzzk/api/category.py +65 -0
- chzzk/api/channel.py +218 -0
- chzzk/api/chat.py +239 -0
- chzzk/api/live.py +212 -0
- chzzk/api/restriction.py +147 -0
- chzzk/api/session.py +389 -0
- chzzk/api/user.py +47 -0
- chzzk/auth/__init__.py +34 -0
- chzzk/auth/models.py +115 -0
- chzzk/auth/oauth.py +452 -0
- chzzk/auth/token.py +119 -0
- chzzk/client.py +515 -0
- chzzk/exceptions/__init__.py +37 -0
- chzzk/exceptions/errors.py +130 -0
- chzzk/http/__init__.py +68 -0
- chzzk/http/client.py +310 -0
- chzzk/http/endpoints.py +52 -0
- chzzk/models/__init__.py +86 -0
- chzzk/models/category.py +18 -0
- chzzk/models/channel.py +69 -0
- chzzk/models/chat.py +63 -0
- chzzk/models/common.py +23 -0
- chzzk/models/live.py +78 -0
- chzzk/models/restriction.py +18 -0
- chzzk/models/session.py +161 -0
- chzzk/models/user.py +14 -0
- chzzk/py.typed +0 -0
- chzzk/realtime/__init__.py +8 -0
- chzzk/realtime/client.py +635 -0
- chzzk_python-0.1.0.dist-info/METADATA +314 -0
- chzzk_python-0.1.0.dist-info/RECORD +37 -0
- chzzk_python-0.1.0.dist-info/WHEEL +4 -0
- chzzk_python-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: chzzk-python
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unofficial Python SDK for Chzzk (NAVER Live Streaming Platform) API
|
|
5
|
+
Project-URL: Homepage, https://github.com/hypn4/chzzk-python
|
|
6
|
+
Project-URL: Repository, https://github.com/hypn4/chzzk-python
|
|
7
|
+
Project-URL: Documentation, https://github.com/hypn4/chzzk-python#readme
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/hypn4/chzzk-python/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/hypn4/chzzk-python/blob/main/CHANGELOG.md
|
|
10
|
+
Author: hypn4
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: api,chat,chzzk,korean,live-streaming,naver,sdk,streaming,websocket
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.12
|
|
25
|
+
Requires-Dist: httpx>=0.28.0
|
|
26
|
+
Requires-Dist: pydantic>=2.10.0
|
|
27
|
+
Requires-Dist: python-socketio[asyncio-client]<5.0.0,>=4.6.0
|
|
28
|
+
Requires-Dist: websocket-client>=1.9.0
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# chzzk-python
|
|
32
|
+
|
|
33
|
+
[](https://www.python.org/downloads/)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
|
|
36
|
+
Unofficial Python SDK for Chzzk (NAVER Live Streaming Platform) API
|
|
37
|
+
|
|
38
|
+
[한국어](README_KO.md)
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Using uv (recommended)
|
|
44
|
+
uv add chzzk-python
|
|
45
|
+
|
|
46
|
+
# Using pip
|
|
47
|
+
pip install chzzk-python
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Quick Start
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from chzzk import ChzzkClient, FileTokenStorage
|
|
54
|
+
|
|
55
|
+
# Create client with OAuth support
|
|
56
|
+
client = ChzzkClient(
|
|
57
|
+
client_id="your-client-id",
|
|
58
|
+
client_secret="your-client-secret",
|
|
59
|
+
redirect_uri="http://localhost:8080/callback",
|
|
60
|
+
token_storage=FileTokenStorage("token.json"),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
# Generate authorization URL
|
|
64
|
+
auth_url, state = client.get_authorization_url()
|
|
65
|
+
# User visits auth_url and authorizes the app
|
|
66
|
+
|
|
67
|
+
# Exchange code for token (after OAuth callback)
|
|
68
|
+
token = client.authenticate(code="auth-code", state=state)
|
|
69
|
+
|
|
70
|
+
# Use the API
|
|
71
|
+
user = client.user.get_me()
|
|
72
|
+
print(f"Channel: {user.channel_name}")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## API Categories & Implementation Status
|
|
76
|
+
|
|
77
|
+
| Category | Status | Description |
|
|
78
|
+
|----------|--------|-------------|
|
|
79
|
+
| **Authorization** | ✅ Implemented | OAuth 2.0, Token issue/refresh/revoke |
|
|
80
|
+
| **User** | ✅ Implemented | Get logged-in user info |
|
|
81
|
+
| **Channel** | ✅ Implemented | Channel info, managers, followers, subscribers |
|
|
82
|
+
| **Category** | ✅ Implemented | Category search |
|
|
83
|
+
| **Live** | ✅ Implemented | Live list, stream key, broadcast settings |
|
|
84
|
+
| **Chat** | ✅ Implemented | Send messages, announcements, chat settings |
|
|
85
|
+
| **Session** | ✅ Implemented | Session create/list, event subscription |
|
|
86
|
+
| **Restriction** | ✅ Implemented | Activity restriction list management |
|
|
87
|
+
| **Drops** | ❌ Not Implemented | - |
|
|
88
|
+
| **Webhook Event** | ❌ Not Implemented | - |
|
|
89
|
+
|
|
90
|
+
## Features
|
|
91
|
+
|
|
92
|
+
### Sync/Async Support
|
|
93
|
+
|
|
94
|
+
Both synchronous and asynchronous clients are available:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# Synchronous
|
|
98
|
+
from chzzk import ChzzkClient
|
|
99
|
+
|
|
100
|
+
with ChzzkClient(client_id="...", client_secret="...") as client:
|
|
101
|
+
user = client.user.get_me()
|
|
102
|
+
|
|
103
|
+
# Asynchronous
|
|
104
|
+
from chzzk import AsyncChzzkClient
|
|
105
|
+
|
|
106
|
+
async with AsyncChzzkClient(client_id="...", client_secret="...") as client:
|
|
107
|
+
user = await client.user.get_me()
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Token Storage
|
|
111
|
+
|
|
112
|
+
Multiple token storage options:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from chzzk import InMemoryTokenStorage, FileTokenStorage, CallbackTokenStorage
|
|
116
|
+
|
|
117
|
+
# In-memory (default)
|
|
118
|
+
storage = InMemoryTokenStorage()
|
|
119
|
+
|
|
120
|
+
# File-based persistence
|
|
121
|
+
storage = FileTokenStorage("token.json")
|
|
122
|
+
|
|
123
|
+
# Custom callback
|
|
124
|
+
storage = CallbackTokenStorage(
|
|
125
|
+
get_callback=lambda: load_from_db(),
|
|
126
|
+
save_callback=lambda token: save_to_db(token),
|
|
127
|
+
delete_callback=lambda: delete_from_db(),
|
|
128
|
+
)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Realtime Events
|
|
132
|
+
|
|
133
|
+
Receive chat, donation, and subscription events in realtime:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from chzzk import ChzzkClient, ChatEvent, DonationEvent, SubscriptionEvent
|
|
137
|
+
|
|
138
|
+
client = ChzzkClient(...)
|
|
139
|
+
event_client = client.create_event_client()
|
|
140
|
+
|
|
141
|
+
@event_client.on_chat
|
|
142
|
+
def on_chat(event: ChatEvent):
|
|
143
|
+
print(f"{event.profile.nickname}: {event.content}")
|
|
144
|
+
|
|
145
|
+
@event_client.on_donation
|
|
146
|
+
def on_donation(event: DonationEvent):
|
|
147
|
+
print(f"{event.donator_nickname} donated {event.pay_amount}won")
|
|
148
|
+
|
|
149
|
+
@event_client.on_subscription
|
|
150
|
+
def on_subscription(event: SubscriptionEvent):
|
|
151
|
+
print(f"{event.subscriber_nickname} subscribed!")
|
|
152
|
+
|
|
153
|
+
# Connect and subscribe
|
|
154
|
+
event_client.connect()
|
|
155
|
+
event_client.subscribe_chat()
|
|
156
|
+
event_client.subscribe_donation()
|
|
157
|
+
event_client.subscribe_subscription()
|
|
158
|
+
event_client.run_forever()
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Usage Examples
|
|
162
|
+
|
|
163
|
+
### OAuth Authentication Flow
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
from chzzk import ChzzkClient, FileTokenStorage
|
|
167
|
+
|
|
168
|
+
client = ChzzkClient(
|
|
169
|
+
client_id="your-client-id",
|
|
170
|
+
client_secret="your-client-secret",
|
|
171
|
+
redirect_uri="http://localhost:8080/callback",
|
|
172
|
+
token_storage=FileTokenStorage("token.json"),
|
|
173
|
+
auto_refresh=True, # Automatically refresh expired tokens
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# 1. Generate authorization URL
|
|
177
|
+
auth_url, state = client.get_authorization_url()
|
|
178
|
+
print(f"Visit: {auth_url}")
|
|
179
|
+
|
|
180
|
+
# 2. After user authorizes, exchange code for token
|
|
181
|
+
token = client.authenticate(code="received-code", state=state)
|
|
182
|
+
|
|
183
|
+
# 3. Refresh token manually if needed
|
|
184
|
+
new_token = client.refresh_token()
|
|
185
|
+
|
|
186
|
+
# 4. Revoke token on logout
|
|
187
|
+
client.revoke_token()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Channel & Live Information
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
# Get channel info
|
|
194
|
+
channel = client.channel.get_channel("channel-id")
|
|
195
|
+
print(f"Channel: {channel.channel_name}")
|
|
196
|
+
print(f"Description: {channel.channel_description}")
|
|
197
|
+
|
|
198
|
+
# Get followers
|
|
199
|
+
followers = client.channel.get_followers(size=20)
|
|
200
|
+
for follower in followers.data:
|
|
201
|
+
print(f"Follower: {follower.nickname}")
|
|
202
|
+
|
|
203
|
+
# Get live broadcasts
|
|
204
|
+
lives = client.live.get_lives(size=10)
|
|
205
|
+
for live in lives.data:
|
|
206
|
+
print(f"{live.channel_name}: {live.live_title} ({live.concurrent_user_count} viewers)")
|
|
207
|
+
|
|
208
|
+
# Get/Update live settings
|
|
209
|
+
setting = client.live.get_setting()
|
|
210
|
+
client.live.update_setting(default_live_title="My Stream Title")
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Chat Messages
|
|
214
|
+
|
|
215
|
+
```python
|
|
216
|
+
# Send chat message
|
|
217
|
+
client.chat.send_message(channel_id="channel-id", message="Hello!")
|
|
218
|
+
|
|
219
|
+
# Set chat announcement
|
|
220
|
+
client.chat.set_notice(
|
|
221
|
+
channel_id="channel-id",
|
|
222
|
+
message="Welcome to the stream!",
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
# Get/Update chat settings
|
|
226
|
+
settings = client.chat.get_settings(channel_id="channel-id")
|
|
227
|
+
client.chat.update_settings(
|
|
228
|
+
channel_id="channel-id",
|
|
229
|
+
chat_available_group="FOLLOWER",
|
|
230
|
+
)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Async Example
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
import asyncio
|
|
237
|
+
from chzzk import AsyncChzzkClient, FileTokenStorage
|
|
238
|
+
|
|
239
|
+
async def main():
|
|
240
|
+
async with AsyncChzzkClient(
|
|
241
|
+
client_id="your-client-id",
|
|
242
|
+
client_secret="your-client-secret",
|
|
243
|
+
redirect_uri="http://localhost:8080/callback",
|
|
244
|
+
token_storage=FileTokenStorage("token.json"),
|
|
245
|
+
) as client:
|
|
246
|
+
# Get user info
|
|
247
|
+
user = await client.user.get_me()
|
|
248
|
+
print(f"Channel: {user.channel_name}")
|
|
249
|
+
|
|
250
|
+
# Get live broadcasts
|
|
251
|
+
lives = await client.live.get_lives(size=10)
|
|
252
|
+
for live in lives.data:
|
|
253
|
+
print(f"{live.channel_name}: {live.live_title}")
|
|
254
|
+
|
|
255
|
+
asyncio.run(main())
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Exception Handling
|
|
259
|
+
|
|
260
|
+
```python
|
|
261
|
+
from chzzk import (
|
|
262
|
+
ChzzkError, # Base exception
|
|
263
|
+
ChzzkAPIError, # API error response
|
|
264
|
+
AuthenticationError, # 401 errors
|
|
265
|
+
InvalidTokenError, # Invalid/expired token
|
|
266
|
+
InvalidClientError, # Invalid client credentials
|
|
267
|
+
ForbiddenError, # 403 errors
|
|
268
|
+
NotFoundError, # 404 errors
|
|
269
|
+
RateLimitError, # 429 errors
|
|
270
|
+
ServerError, # 5xx errors
|
|
271
|
+
TokenExpiredError, # Token expired, need re-auth
|
|
272
|
+
InvalidStateError, # OAuth state mismatch
|
|
273
|
+
SessionError, # Session-related errors
|
|
274
|
+
SessionConnectionError, # Socket.IO connection failed
|
|
275
|
+
SessionLimitExceededError, # Max session limit exceeded
|
|
276
|
+
EventSubscriptionError, # Event subscription failed
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
try:
|
|
280
|
+
user = client.user.get_me()
|
|
281
|
+
except InvalidTokenError:
|
|
282
|
+
# Token is invalid or expired
|
|
283
|
+
token = client.refresh_token()
|
|
284
|
+
except RateLimitError:
|
|
285
|
+
# Rate limit exceeded, wait and retry
|
|
286
|
+
time.sleep(60)
|
|
287
|
+
except ChzzkAPIError as e:
|
|
288
|
+
print(f"API Error: [{e.status_code}] {e.error_code}: {e.message}")
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Examples
|
|
292
|
+
|
|
293
|
+
See the [examples](examples/) directory for complete working examples:
|
|
294
|
+
|
|
295
|
+
- `oauth_server.py` - OAuth authentication with Flask
|
|
296
|
+
- `realtime_chat.py` - Realtime chat/donation/subscription events (sync)
|
|
297
|
+
- `realtime_chat_async.py` - Realtime events (async)
|
|
298
|
+
- `session_management.py` - Session management example
|
|
299
|
+
|
|
300
|
+
## API Reference
|
|
301
|
+
|
|
302
|
+
For detailed API documentation, see the [Official Chzzk API Documentation](https://chzzk.gitbook.io/chzzk).
|
|
303
|
+
|
|
304
|
+
## License
|
|
305
|
+
|
|
306
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
307
|
+
|
|
308
|
+
## Contributing
|
|
309
|
+
|
|
310
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
311
|
+
|
|
312
|
+
## Disclaimer
|
|
313
|
+
|
|
314
|
+
This is an unofficial SDK and is not affiliated with NAVER or Chzzk. Use at your own risk.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
chzzk/__init__.py,sha256=1TXefU4G9kkQy40hPBoqeZnJvHE8--Wc_T-dRaIeXdE,3766
|
|
2
|
+
chzzk/_version.py,sha256=5jwwVncvCiTnhOedfkzzxmxsggwmTBORdFL_4wq0ZeY,704
|
|
3
|
+
chzzk/client.py,sha256=zkS5RxU8q8_JjKj682fDZs77E8_jbS22xuZt-Z9mpc4,17953
|
|
4
|
+
chzzk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
chzzk/api/__init__.py,sha256=UfHYFruwdPx966QxBsaDXZXA9F7IULFJQrNHAyZ40eQ,935
|
|
6
|
+
chzzk/api/base.py,sha256=hziWCfL-JgtqImqjy95qgARKHSX27eKYoeB_VsSUCn4,4909
|
|
7
|
+
chzzk/api/category.py,sha256=zgIMttpxYZWgNXBEi2bLcC7UgU6ee2M8uHjJ9nyN7mE,1925
|
|
8
|
+
chzzk/api/channel.py,sha256=ceVzuMiVtJuBqr6hPkRcmM1jqGQ2d1UBCl0_qn11FsI,6600
|
|
9
|
+
chzzk/api/chat.py,sha256=1G-Cq3FHIopkBo27g8XFE_nPvjvxRyYGnDDFFmTlGjQ,8016
|
|
10
|
+
chzzk/api/live.py,sha256=CLc_3NfmklpOtS-lVfnLtlKIQtn61xuY4y6KuSjRvSU,6645
|
|
11
|
+
chzzk/api/restriction.py,sha256=1sPDnR83DQG06ZjEdTcGhWezhW4CgfR7K3dGXP0mF2I,4418
|
|
12
|
+
chzzk/api/session.py,sha256=lk_UGucJf19anp2cX_f-BhrFi0iMAjgdUbhXo55lCUw,13610
|
|
13
|
+
chzzk/api/user.py,sha256=a-Z4I2lzHlHcC6DJ7GpSM1tHJYW34BEcwkWidmITmw0,1385
|
|
14
|
+
chzzk/auth/__init__.py,sha256=Q72PXxMDFWGFMU1rayT_wR4VzOB4Xsf3xJvrWoPtaqk,716
|
|
15
|
+
chzzk/auth/models.py,sha256=jRIsEjKeew1zlaaS3yKsGI2mGAa-FSvTDIb0oaNRVmI,3487
|
|
16
|
+
chzzk/auth/oauth.py,sha256=Nhe7BNmB5zfhI9a7ARm1SVOGOHW-R659a6TkOH7NJ6E,13935
|
|
17
|
+
chzzk/auth/token.py,sha256=N0Zz5QZU50sm62nGihRhFmfR_KLfX2GoWMT97GA7PSY,3651
|
|
18
|
+
chzzk/exceptions/__init__.py,sha256=cYYlVe2R_tV8KXB2bOsRBpzNEjZlzxJ_UDFx8_PQsEQ,793
|
|
19
|
+
chzzk/exceptions/errors.py,sha256=Q2c7jPM7I_eluBngLFHmDGNTvXg3QNVnHTEWj2Ra8ls,4096
|
|
20
|
+
chzzk/http/__init__.py,sha256=545jgKZ1cLa1qPvmaFDCFsBjMAzoDjblP9_QTm53cBs,1746
|
|
21
|
+
chzzk/http/client.py,sha256=nyGE5adrh83C53LwwDOFsvsm9C4XVtg-3Z6zmMMfRhQ,8804
|
|
22
|
+
chzzk/http/endpoints.py,sha256=U32XOYEljI-A2CrPEHBhAPD3FkBJ5vmf8pVyE0bbSe8,2068
|
|
23
|
+
chzzk/models/__init__.py,sha256=JdQ-RmfEzDS57YyWwQykep_0dESA360jloDpkhvVq9c,1824
|
|
24
|
+
chzzk/models/category.py,sha256=d4fWTCMmVKsw5m58XHaTZQcgqlduou6ouT82wD6lKgs,515
|
|
25
|
+
chzzk/models/channel.py,sha256=HB22tDUJlh2WzCM-vNCColSX2vg_TMSjoK8PEgtbdnY,1966
|
|
26
|
+
chzzk/models/chat.py,sha256=S-8WgdSDX_3s6Pf-cgmp9bG3J4jG7_FEB-V5ndl1oDw,2049
|
|
27
|
+
chzzk/models/common.py,sha256=6F8PaXZKTNsusCWTcPEy4JYTXpOmcxea5wcg4Ns0MS0,420
|
|
28
|
+
chzzk/models/live.py,sha256=P4KCYZS5uJu9FeI_SjVS9KDaUPCJSqwc-uLtk_MpUWM,2573
|
|
29
|
+
chzzk/models/restriction.py,sha256=ktScIZ4ja5HQRRAtcGO4gn5mecSks0-xsIaQxjdwWSM,550
|
|
30
|
+
chzzk/models/session.py,sha256=_nBK74uen2jqtm6BKiid4XGRHa7q0-eQDS71OBTVeUk,4240
|
|
31
|
+
chzzk/models/user.py,sha256=VMMsD--1lDFm07HRC7LOpFcBhDhlKWY-tmniRh5Dlqw,347
|
|
32
|
+
chzzk/realtime/__init__.py,sha256=W9zCfP8M3bJ_kIcSiioXJ_Z9Lol1E0kn3oEKRVf1nBY,186
|
|
33
|
+
chzzk/realtime/client.py,sha256=YyKUK3T2EpqaqQ-LqntOvvyNRhoebkzVyL2giL4FQGw,21663
|
|
34
|
+
chzzk_python-0.1.0.dist-info/METADATA,sha256=QU5HF5wBPW6suSX-CfEPJ_SA76aLznTqVbEF2hXB2ww,9210
|
|
35
|
+
chzzk_python-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
36
|
+
chzzk_python-0.1.0.dist-info/licenses/LICENSE,sha256=_v9Nf8gbo1wGWzG43mf3FR1afupceNnAmEH_4q742mE,1062
|
|
37
|
+
chzzk_python-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 hypn4
|
|
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.
|