Ryzenth 2.0.5__py3-none-any.whl → 2.0.7__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.
- Ryzenth/__init__.py +2 -1
- Ryzenth/__version__.py +1 -1
- Ryzenth/_base_client.py +66 -0
- Ryzenth/_benchmark.py +34 -0
- Ryzenth/_client.py +123 -50
- Ryzenth/_shared.py +47 -2
- Ryzenth/enums/__init__.py +3 -0
- Ryzenth/enums/types.py +8 -0
- Ryzenth/tests/test_ryzenthapiclient.py +17 -0
- Ryzenth/tests/test_send_downloader.py +0 -10
- Ryzenth/tl/__init__.py +3 -0
- Ryzenth/tl/logger_service.py +66 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.7.dist-info}/METADATA +13 -2
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.7.dist-info}/RECORD +17 -10
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.7.dist-info}/WHEEL +0 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.7.dist-info}/licenses/LICENSE +0 -0
- {ryzenth-2.0.5.dist-info → ryzenth-2.0.7.dist-info}/top_level.txt +0 -0
Ryzenth/__init__.py
CHANGED
@@ -19,7 +19,8 @@
|
|
19
19
|
|
20
20
|
from . import *
|
21
21
|
from .__version__ import __version__
|
22
|
-
from .
|
22
|
+
from ._base_client import ApiKeyFrom, FromConvertDot, UrHellFrom
|
23
|
+
from ._client import RyzenthApiClient
|
23
24
|
|
24
25
|
__all__ = [
|
25
26
|
"ApiKeyFrom",
|
Ryzenth/__version__.py
CHANGED
Ryzenth/_base_client.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright 2019-2025 (c) Randy W @xtdevs, @xtsea
|
4
|
+
#
|
5
|
+
# from : https://github.com/TeamKillerX
|
6
|
+
# Channel : @RendyProjects
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
import base64
|
21
|
+
from os import environ
|
22
|
+
|
23
|
+
from box import Box
|
24
|
+
|
25
|
+
from ._asynchisded import RyzenthXAsync
|
26
|
+
from ._shared import UNKNOWN_TEST
|
27
|
+
from ._synchisded import RyzenthXSync
|
28
|
+
from .helper import Decorators
|
29
|
+
|
30
|
+
|
31
|
+
class ApiKeyFrom:
|
32
|
+
def __init__(self, api_key: str = None, is_ok=False):
|
33
|
+
if api_key == Ellipsis:
|
34
|
+
is_ok = True
|
35
|
+
api_key = None
|
36
|
+
|
37
|
+
if not api_key:
|
38
|
+
api_key = environ.get("RYZENTH_API_KEY")
|
39
|
+
|
40
|
+
if not api_key:
|
41
|
+
error404_bytes = UNKNOWN_TEST.encode("ascii")
|
42
|
+
string_bytes = base64.b64decode(error404_bytes)
|
43
|
+
api_key = string_bytes.decode("ascii") if is_ok else None
|
44
|
+
|
45
|
+
|
46
|
+
self.api_key = api_key
|
47
|
+
self.aio = RyzenthXAsync(api_key)
|
48
|
+
self._sync = RyzenthXSync(api_key)
|
49
|
+
|
50
|
+
def something(self):
|
51
|
+
pass
|
52
|
+
|
53
|
+
class UrHellFrom:
|
54
|
+
def __init__(self, name: str, only_author=False):
|
55
|
+
self.decorators = Decorators(ApiKeyFrom)
|
56
|
+
self.ai = self.decorators.send_ai(name=name, only_author=only_author)
|
57
|
+
|
58
|
+
def something(self):
|
59
|
+
pass
|
60
|
+
|
61
|
+
class FromConvertDot:
|
62
|
+
def __init__(self, obj):
|
63
|
+
self.obj = obj
|
64
|
+
|
65
|
+
def to_dot(self):
|
66
|
+
return Box(self.obj if self.obj is not None else {})
|
Ryzenth/_benchmark.py
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
import logging
|
2
|
+
import time
|
3
|
+
from functools import wraps
|
4
|
+
|
5
|
+
logger = logging.getLogger(__name__)
|
6
|
+
|
7
|
+
class Benchmark:
|
8
|
+
@classmethod
|
9
|
+
def performance(cls, level=logging.INFO):
|
10
|
+
def decorator(func):
|
11
|
+
@wraps(func)
|
12
|
+
async def wrapper(*args, **kwargs):
|
13
|
+
start_time = time.perf_counter()
|
14
|
+
result = await func(*args, **kwargs)
|
15
|
+
end_time = time.perf_counter()
|
16
|
+
msg = f"[BENCH] {func.__name__} executed in {end_time - start_time:.2f}s"
|
17
|
+
logger.log(level, msg)
|
18
|
+
return result
|
19
|
+
return wrapper
|
20
|
+
return decorator
|
21
|
+
|
22
|
+
@classmethod
|
23
|
+
def sync(cls, level=logging.INFO):
|
24
|
+
def decorator(func):
|
25
|
+
@wraps(func)
|
26
|
+
def wrapper(*args, **kwargs):
|
27
|
+
start_time = time.perf_counter()
|
28
|
+
result = func(*args, **kwargs)
|
29
|
+
end_time = time.perf_counter()
|
30
|
+
msg = f"[BENCH] {func.__name__} executed in {end_time - start_time:.2f}s"
|
31
|
+
logger.log(level, msg)
|
32
|
+
return result
|
33
|
+
return wrapper
|
34
|
+
return decorator
|
Ryzenth/_client.py
CHANGED
@@ -19,58 +19,25 @@
|
|
19
19
|
|
20
20
|
import asyncio
|
21
21
|
import json
|
22
|
-
import
|
22
|
+
import logging
|
23
23
|
import random
|
24
24
|
import time
|
25
25
|
import typing as t
|
26
|
-
from os import
|
26
|
+
from os import getenv
|
27
27
|
|
28
28
|
import aiohttp
|
29
29
|
import httpx
|
30
|
-
|
30
|
+
import requests
|
31
31
|
|
32
32
|
from .__version__ import get_user_agent
|
33
|
-
from .
|
33
|
+
from ._benchmark import Benchmark
|
34
34
|
from ._errors import ForbiddenError, InternalError, ToolNotFoundError, WhatFuckError
|
35
35
|
from ._shared import TOOL_DOMAIN_MAP
|
36
|
-
from .
|
37
|
-
from .helper import AutoRetry
|
36
|
+
from .enums import ResponseType
|
37
|
+
from .helper import AutoRetry
|
38
|
+
from .tl import LoggerService
|
38
39
|
|
39
40
|
|
40
|
-
class ApiKeyFrom:
|
41
|
-
def __init__(self, api_key: str = None, is_ok=False):
|
42
|
-
if api_key is Ellipsis:
|
43
|
-
is_ok = True
|
44
|
-
api_key = None
|
45
|
-
|
46
|
-
if not api_key:
|
47
|
-
api_key = environ.get("RYZENTH_API_KEY")
|
48
|
-
|
49
|
-
if not api_key:
|
50
|
-
api_key = "akeno_UKQEQMt991kh2Ehh7JqJYKapx8CCyeC" if is_ok else None
|
51
|
-
|
52
|
-
self.api_key = api_key
|
53
|
-
self.aio = RyzenthXAsync(api_key)
|
54
|
-
self._sync = RyzenthXSync(api_key)
|
55
|
-
|
56
|
-
def something(self):
|
57
|
-
pass
|
58
|
-
|
59
|
-
class UrHellFrom:
|
60
|
-
def __init__(self, name: str, only_author=False):
|
61
|
-
self.decorators = Decorators(ApiKeyFrom)
|
62
|
-
self.ai = self.decorators.send_ai(name=name, only_author=only_author)
|
63
|
-
|
64
|
-
def something(self):
|
65
|
-
pass
|
66
|
-
|
67
|
-
class FromConvertDot:
|
68
|
-
def __init__(self, obj):
|
69
|
-
self.obj = obj
|
70
|
-
|
71
|
-
def to_dot(self):
|
72
|
-
return Box(self.obj if self.obj is not None else {})
|
73
|
-
|
74
41
|
class RyzenthApiClient:
|
75
42
|
def __init__(
|
76
43
|
self,
|
@@ -79,7 +46,9 @@ class RyzenthApiClient:
|
|
79
46
|
api_key: dict[str, list[dict]],
|
80
47
|
rate_limit: int = 5,
|
81
48
|
use_default_headers: bool = False,
|
82
|
-
use_httpx: bool = False
|
49
|
+
use_httpx: bool = False,
|
50
|
+
settings: dict = None,
|
51
|
+
logger: t.Optional[LoggerService] = None
|
83
52
|
) -> None:
|
84
53
|
if not isinstance(api_key, dict) or not api_key:
|
85
54
|
raise WhatFuckError("API Key must be a non-empty dict of tool_name → list of headers")
|
@@ -92,17 +61,36 @@ class RyzenthApiClient:
|
|
92
61
|
self._request_counter = 0
|
93
62
|
self._last_reset = time.monotonic()
|
94
63
|
self._use_httpx = use_httpx
|
64
|
+
self._settings = settings or {}
|
65
|
+
self._logger = logger
|
66
|
+
self._init_logging()
|
95
67
|
|
96
68
|
self._tools: dict[str, str] = {
|
97
69
|
name: TOOL_DOMAIN_MAP.get(name)
|
98
70
|
for name in tools_name
|
99
71
|
}
|
72
|
+
self._sync_session = requests.Session()
|
100
73
|
self._session = (
|
101
74
|
httpx.AsyncClient()
|
102
75
|
if use_httpx else
|
103
76
|
aiohttp.ClientSession()
|
104
77
|
)
|
105
78
|
|
79
|
+
def _init_logging(self):
|
80
|
+
log_level = "WARNING"
|
81
|
+
disable_httpx_log = False
|
82
|
+
|
83
|
+
for entry in self._settings.get("logging", []):
|
84
|
+
if "level" in entry:
|
85
|
+
log_level = entry["level"].upper()
|
86
|
+
if "httpx_log" in entry:
|
87
|
+
disable_httpx_log = not entry["httpx_log"]
|
88
|
+
|
89
|
+
logging.basicConfig(level=getattr(logging, log_level, logging.WARNING))
|
90
|
+
if disable_httpx_log:
|
91
|
+
logging.getLogger("httpx").setLevel(logging.CRITICAL)
|
92
|
+
logging.getLogger("httpcore").setLevel(logging.CRITICAL)
|
93
|
+
|
106
94
|
def get_base_url(self, tool: str) -> str:
|
107
95
|
check_ok = self._tools.get(tool, None)
|
108
96
|
if check_ok is None:
|
@@ -169,14 +157,43 @@ class RyzenthApiClient:
|
|
169
157
|
elif resp.status == 500:
|
170
158
|
raise InternalError("Error requests status code 500")
|
171
159
|
|
160
|
+
def request(self, method, url, **kwargs):
|
161
|
+
return self._sync_session.request(method=method, url=url, **kwargs)
|
162
|
+
|
163
|
+
@Benchmark.sync(level=logging.DEBUG)
|
164
|
+
def sync_get(
|
165
|
+
self,
|
166
|
+
tool: str,
|
167
|
+
path: str,
|
168
|
+
params: t.Optional[dict] = None,
|
169
|
+
use_type: ResponseType = ResponseType.JSON
|
170
|
+
) -> t.Union[dict, bytes, str]:
|
171
|
+
base_url = self.get_base_url(tool)
|
172
|
+
url = f"{base_url}{path}"
|
173
|
+
headers = self._get_headers_for_tool(tool)
|
174
|
+
resp = self.request("get", url, params=params, headers=headers)
|
175
|
+
if resp.status_code == 403:
|
176
|
+
raise ForbiddenError("Access Forbidden: You may be blocked or banned.")
|
177
|
+
elif resp.status_code == 401:
|
178
|
+
raise ForbiddenError("Access Forbidden: Required API key or invalid params.")
|
179
|
+
elif resp.status_code == 500:
|
180
|
+
raise InternalError("Error requests status code 500")
|
181
|
+
resp.raise_for_status()
|
182
|
+
if use_type == ResponseType.IMAGE:
|
183
|
+
return resp.content
|
184
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
185
|
+
return resp.text
|
186
|
+
return resp.json()
|
187
|
+
|
188
|
+
@Benchmark.performance(level=logging.DEBUG)
|
172
189
|
@AutoRetry(max_retries=3, delay=1.5)
|
173
190
|
async def get(
|
174
191
|
self,
|
175
192
|
tool: str,
|
176
193
|
path: str,
|
177
194
|
params: t.Optional[dict] = None,
|
178
|
-
|
179
|
-
) -> t.Union[dict, bytes]:
|
195
|
+
use_type: ResponseType = ResponseType.JSON
|
196
|
+
) -> t.Union[dict, bytes, str]:
|
180
197
|
await self._throttle()
|
181
198
|
base_url = self.get_base_url(tool)
|
182
199
|
url = f"{base_url}{path}"
|
@@ -186,13 +203,53 @@ class RyzenthApiClient:
|
|
186
203
|
resp = await self._session.get(url, params=params, headers=headers)
|
187
204
|
await self._status_resp_error(resp, status_httpx=True)
|
188
205
|
resp.raise_for_status()
|
189
|
-
|
206
|
+
if use_type == ResponseType.IMAGE:
|
207
|
+
data = resp.content
|
208
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
209
|
+
data = resp.text
|
210
|
+
else:
|
211
|
+
data = resp.json()
|
190
212
|
else:
|
191
213
|
async with self._session.get(url, params=params, headers=headers) as resp:
|
192
214
|
await self._status_resp_error(resp, status_httpx=False)
|
193
215
|
resp.raise_for_status()
|
194
|
-
|
216
|
+
if use_type == ResponseType.IMAGE:
|
217
|
+
data = await resp.read()
|
218
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
219
|
+
data = await resp.text()
|
220
|
+
else:
|
221
|
+
data = await resp.json()
|
222
|
+
if self._logger:
|
223
|
+
await self._logger.log(f"[GET {tool}] ✅ Success: {url}")
|
224
|
+
return data
|
195
225
|
|
226
|
+
@Benchmark.sync(level=logging.DEBUG)
|
227
|
+
def sync_post(
|
228
|
+
self,
|
229
|
+
tool: str,
|
230
|
+
path: str,
|
231
|
+
data: t.Optional[dict] = None,
|
232
|
+
json: t.Optional[dict] = None,
|
233
|
+
use_type: ResponseType = ResponseType.JSON
|
234
|
+
) -> t.Union[dict, bytes, str]:
|
235
|
+
base_url = self.get_base_url(tool)
|
236
|
+
url = f"{base_url}{path}"
|
237
|
+
headers = self._get_headers_for_tool(tool)
|
238
|
+
resp = self.request("post", url, data=data, json=json, headers=headers)
|
239
|
+
if resp.status_code == 403:
|
240
|
+
raise ForbiddenError("Access Forbidden: You may be blocked or banned.")
|
241
|
+
elif resp.status_code == 401:
|
242
|
+
raise ForbiddenError("Access Forbidden: Required API key or invalid params.")
|
243
|
+
elif resp.status_code == 500:
|
244
|
+
raise InternalError("Error requests status code 500")
|
245
|
+
resp.raise_for_status()
|
246
|
+
if use_type == ResponseType.IMAGE:
|
247
|
+
return resp.content
|
248
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
249
|
+
return resp.text
|
250
|
+
return resp.json()
|
251
|
+
|
252
|
+
@Benchmark.performance(level=logging.DEBUG)
|
196
253
|
@AutoRetry(max_retries=3, delay=1.5)
|
197
254
|
async def post(
|
198
255
|
self,
|
@@ -200,8 +257,8 @@ class RyzenthApiClient:
|
|
200
257
|
path: str,
|
201
258
|
data: t.Optional[dict] = None,
|
202
259
|
json: t.Optional[dict] = None,
|
203
|
-
|
204
|
-
) -> t.Union[dict, bytes]:
|
260
|
+
use_type: ResponseType = ResponseType.JSON
|
261
|
+
) -> t.Union[dict, bytes, str]:
|
205
262
|
await self._throttle()
|
206
263
|
base_url = self.get_base_url(tool)
|
207
264
|
url = f"{base_url}{path}"
|
@@ -211,12 +268,28 @@ class RyzenthApiClient:
|
|
211
268
|
resp = await self._session.post(url, data=data, json=json, headers=headers)
|
212
269
|
await self._status_resp_error(resp, status_httpx=True)
|
213
270
|
resp.raise_for_status()
|
214
|
-
|
271
|
+
if use_type == ResponseType.IMAGE:
|
272
|
+
data = resp.content
|
273
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
274
|
+
data = resp.text
|
275
|
+
else:
|
276
|
+
data = resp.json()
|
215
277
|
else:
|
216
278
|
async with self._session.post(url, data=data, json=json, headers=headers) as resp:
|
217
279
|
await self._status_resp_error(resp, status_httpx=False)
|
218
280
|
resp.raise_for_status()
|
219
|
-
|
281
|
+
if use_type == ResponseType.IMAGE:
|
282
|
+
data = await resp.read()
|
283
|
+
elif use_type in [ResponseType.TEXT, ResponseType.HTML]:
|
284
|
+
data = await resp.text()
|
285
|
+
else:
|
286
|
+
data = await resp.json()
|
287
|
+
if self._logger:
|
288
|
+
await self._logger.log(f"[POST {tool}] ✅ Success: {url}")
|
289
|
+
return data
|
290
|
+
|
291
|
+
def sync_close(self):
|
292
|
+
return self._sync_session.close()
|
220
293
|
|
221
294
|
async def close(self):
|
222
|
-
await self._session.close()
|
295
|
+
return await self._session.aclose() if self._use_httpx else await self._session.close()
|
Ryzenth/_shared.py
CHANGED
@@ -1,13 +1,58 @@
|
|
1
|
+
# Expired 2026 💀
|
2
|
+
UNKNOWN_TEST = "YWtlbm9fVUtRRVFNdDk5MWtoMkVoaDdKcUpZS2FweDhDQ3llQw=="
|
3
|
+
|
1
4
|
TOOL_DOMAIN_MAP = {
|
2
5
|
"itzpire": "https://itzpire.com",
|
3
6
|
"ryzenth": "https://randydev-ryu-js.hf.space",
|
4
7
|
"onrender": "https://x-api-js.onrender.com",
|
8
|
+
"deepseek": "https://api.deepseek.com",
|
5
9
|
"openai": "https://api.openai.com/v1",
|
6
|
-
"
|
10
|
+
"alibaba": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
11
|
+
"gemini": "https://generativelanguage.googleapis.com/v1beta",
|
12
|
+
"gemini-openai": "https://generativelanguage.googleapis.com/v1beta/openai"
|
7
13
|
}
|
8
14
|
|
9
|
-
|
15
|
+
###-------------AI-----------------###
|
16
|
+
# ALIBABA
|
17
|
+
"""
|
18
|
+
headers = {
|
19
|
+
'Authorization': 'Bearer {api_key}',
|
20
|
+
'Content-Type': 'application/json'
|
21
|
+
}
|
22
|
+
alibaba_response = await clients.post(
|
23
|
+
tool="alibaba",
|
24
|
+
path="/chat/completions",
|
25
|
+
json={
|
26
|
+
"model": "qwen-plus",
|
27
|
+
"messages": [
|
28
|
+
{"role": "user", "content": "hello world!"}
|
29
|
+
],
|
30
|
+
"temperature": 0.7
|
31
|
+
}
|
32
|
+
)
|
33
|
+
"""
|
10
34
|
|
35
|
+
# DEEPSEEK
|
36
|
+
"""
|
37
|
+
headers = {
|
38
|
+
'Authorization': 'Bearer {api_key}',
|
39
|
+
'Content-Type': 'application/json'
|
40
|
+
}
|
41
|
+
deepseek_response = await clients.post(
|
42
|
+
tool="deepseek",
|
43
|
+
path="/chat/completions",
|
44
|
+
json={
|
45
|
+
"model": "deepseek-chat",
|
46
|
+
"messages": [
|
47
|
+
{"role": "user", "content": "hello world!"}
|
48
|
+
],
|
49
|
+
"temperature": 0.7
|
50
|
+
}
|
51
|
+
)
|
52
|
+
"""
|
53
|
+
###-------------END AI-----------------###
|
54
|
+
|
55
|
+
# this API is different
|
11
56
|
BASE_DICT_RENDER = {
|
12
57
|
"transcript": "transcript-dl", #url #render
|
13
58
|
"pinterest": "pinterest-dl", #url #render
|
Ryzenth/enums/types.py
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
from Ryzenth import RyzenthApiClient
|
2
|
+
from Ryzenth.enums import ResponseType
|
3
|
+
|
4
|
+
clients = RyzenthApiClient(
|
5
|
+
tools_name=["itzpire"],
|
6
|
+
api_key={"itzpire": [{}]},
|
7
|
+
rate_limit=100,
|
8
|
+
use_httpx=True # Fixed Aiohttp RuntimeError: no running event loop
|
9
|
+
)
|
10
|
+
|
11
|
+
def test_itzpire():
|
12
|
+
result = clients.sync_get(
|
13
|
+
tool="itzpire",
|
14
|
+
path="/games/siapakah-aku",
|
15
|
+
use_type=ResponseType.JSON
|
16
|
+
)
|
17
|
+
assert result is not None
|
@@ -24,16 +24,6 @@ def test_yt_username():
|
|
24
24
|
)
|
25
25
|
assert result is not None
|
26
26
|
|
27
|
-
def test_hentai_anime():
|
28
|
-
ryz = RyzenthXSync("test", base_url="https://x-api-js.onrender.com/api")
|
29
|
-
result = ryz.send_downloader(
|
30
|
-
switch_name="hentai-anime",
|
31
|
-
params=None,
|
32
|
-
params_only=False,
|
33
|
-
on_render=True
|
34
|
-
)
|
35
|
-
assert result is not None
|
36
|
-
|
37
27
|
def test_xnxxdl():
|
38
28
|
ryz = RyzenthXSync("test", base_url="https://x-api-js.onrender.com/api")
|
39
29
|
result = ryz.send_downloader(
|
Ryzenth/tl/__init__.py
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
# Copyright 2019-2025 (c) Randy W @xtdevs, @xtsea
|
4
|
+
#
|
5
|
+
# from : https://github.com/TeamKillerX
|
6
|
+
# Channel : @RendyProjects
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU Affero General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU Affero General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU Affero General Public License
|
18
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
import logging
|
21
|
+
from datetime import datetime as dt
|
22
|
+
|
23
|
+
import httpx
|
24
|
+
|
25
|
+
from .._errors import ForbiddenError, InternalError
|
26
|
+
|
27
|
+
|
28
|
+
class LoggerService:
|
29
|
+
def __init__(self, config: dict):
|
30
|
+
self.config = config
|
31
|
+
|
32
|
+
async def log(self, message: str):
|
33
|
+
timestamp = dt.now().strftime("%Y-%m-%d %H:%M:%S")
|
34
|
+
full_message = f"[{timestamp}] {message}"
|
35
|
+
|
36
|
+
if self.config.get("telegram", {}).get("enabled"):
|
37
|
+
try:
|
38
|
+
await self._send_telegram(full_message)
|
39
|
+
except Exception as e:
|
40
|
+
logging.info(f"[Logger] Telegram log failed: {e}")
|
41
|
+
|
42
|
+
if self.config.get("database", {}).get("enabled"):
|
43
|
+
try:
|
44
|
+
await self.config["database"]["save_func"](full_message)
|
45
|
+
except Exception as e:
|
46
|
+
logging.info(f"[Logger] DB log failed: {e}")
|
47
|
+
|
48
|
+
async def _send_telegram(self, text: str):
|
49
|
+
token = self.config["telegram"]["token"]
|
50
|
+
chat_id = self.config["telegram"]["chat_id"]
|
51
|
+
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
52
|
+
|
53
|
+
try:
|
54
|
+
async with httpx.AsyncClient() as client:
|
55
|
+
resp = await client.post(url, data={"chat_id": chat_id, "text": text})
|
56
|
+
if resp.status_code == 200:
|
57
|
+
logging.info("[Logger] Telegram log success")
|
58
|
+
elif resp.status_code == 403:
|
59
|
+
raise ForbiddenError("Access Forbidden: You may be blocked or banned.")
|
60
|
+
elif resp.status_code == 401:
|
61
|
+
raise ForbiddenError("Access Forbidden: Required bot token or invalid params.")
|
62
|
+
elif resp.status_code == 500:
|
63
|
+
raise InternalError("Error requests status code 500")
|
64
|
+
except Exception as e:
|
65
|
+
logging.info(f"[Logger] httpx failed: {e}")
|
66
|
+
raise e
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: Ryzenth
|
3
|
-
Version: 2.0.
|
3
|
+
Version: 2.0.7
|
4
4
|
Summary: Ryzenth Python Wrapper For Perfomance
|
5
5
|
Author: TeamKillerX
|
6
6
|
License: MIT
|
@@ -63,7 +63,17 @@ Dynamic: summary
|
|
63
63
|
<a href="https://github.com/TeamKillerX/Ryzenth/workflows/"><img src="https://github.com/TeamKillerX/Ryzenth/actions/workflows/sync-tests.yml/badge.svg" alt="API Tests"/></a>
|
64
64
|
</div>
|
65
65
|
|
66
|
-
|
66
|
+
---
|
67
|
+
|
68
|
+

|
69
|
+
|
70
|
+
---
|
71
|
+
|
72
|
+
**Ryzenth** is a flexible Multi-API SDK with built-in support for API key management and database integration.
|
73
|
+
|
74
|
+
It supports both **synchronous and asynchronous** workflows out of the box, making it ideal for modern use cases such as AI APIs, Telegram bots, REST services, and automation tools.
|
75
|
+
|
76
|
+
With native integration for `httpx`, `aiohttp`, advanced logging (including optional Telegram alerts), and support for database storage like MongoDB, Ryzenth is designed for developers who need a lightweight, scalable, and customizable API client.
|
67
77
|
|
68
78
|
> Note: Ryzenth API V1 (**javascript**) is still alive and supported, but Ryzenth is the next generation.
|
69
79
|
|
@@ -73,6 +83,7 @@ Dynamic: summary
|
|
73
83
|
- Built-in API Key management
|
74
84
|
- Support for modern AI endpoints (image generation, search, text, and more)
|
75
85
|
- Designed for speed with `httpx`
|
86
|
+
- Etc
|
76
87
|
|
77
88
|
## Installation
|
78
89
|
|
@@ -1,10 +1,14 @@
|
|
1
|
-
Ryzenth/__init__.py,sha256=
|
2
|
-
Ryzenth/__version__.py,sha256=
|
1
|
+
Ryzenth/__init__.py,sha256=tUSSKb2xEQGDZFg1g-9PsSuWAPvuUBG9cAXyIHyBmMg,1066
|
2
|
+
Ryzenth/__version__.py,sha256=veVwJEAurqkYKy2C6Ejt7eKkpeq2yOG9QGXSjUBNHcs,223
|
3
3
|
Ryzenth/_asynchisded.py,sha256=5ZjrXZzMSZw3T6kQ3eg-owgH1Y2dmGWJy9AOQqcoFUQ,5051
|
4
|
-
Ryzenth/
|
4
|
+
Ryzenth/_base_client.py,sha256=9oVkoYduSILsk38T2_jvT0frsl2B7ISD2YsR4BJ3Rfk,2032
|
5
|
+
Ryzenth/_benchmark.py,sha256=ldXzfxOXzZhMC_yaNLxaBbPrC5BuWzDzlypftK4Eq_U,1143
|
6
|
+
Ryzenth/_client.py,sha256=8hH40oHL0zu2HuiaBwXMSN5rN1XEALe9q_gIx897i9I,11290
|
5
7
|
Ryzenth/_errors.py,sha256=bOqi0_DElcmRrBqyDim6K248Ys-JQRSOvd32sJGW3aw,1812
|
6
|
-
Ryzenth/_shared.py,sha256=
|
8
|
+
Ryzenth/_shared.py,sha256=Hr72hnxpoG5sFFb0YK47_7cD5TGjgyXIyzykZeldk0Q,3061
|
7
9
|
Ryzenth/_synchisded.py,sha256=Ns0F4iA4kWUg2j5u0Tyqj2E1mXIMs29IoQZCYW5G1Gw,4922
|
10
|
+
Ryzenth/enums/__init__.py,sha256=5V6-BcLESFrWFhSDQ7IwmSccAITjb82HgpYi7NQeIeU,60
|
11
|
+
Ryzenth/enums/types.py,sha256=FE7d5qdAGRCRqs5HAyiJZPPMcn5MAm7WHuGz5GTQuTo,129
|
8
12
|
Ryzenth/helper/__init__.py,sha256=ZditYtDnZOtTJ_odPgWH0Nrj-qQJ868zjy41_DzK_ns,1473
|
9
13
|
Ryzenth/helper/_decorators.py,sha256=8uKdcseA7Cbq5sy2twgujZhbwqjaLwX13BT70diNRFs,2782
|
10
14
|
Ryzenth/helper/_federation.py,sha256=pfqqGjg179f-olvW1Z7aX1nQf0GQJdSK4NDMaMDxmbA,14552
|
@@ -18,11 +22,14 @@ Ryzenth/pyoraddons/__init__.py,sha256=Xt4w4YHoFKwMZe8QslhLKp6mHBjBowvYjzkN95ikpj
|
|
18
22
|
Ryzenth/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
23
|
Ryzenth/tests/test_deepseek.py,sha256=_KbYr-haKBt5Xc-YULBL9Ic5OM02SX17hvQWWjYpNAk,255
|
20
24
|
Ryzenth/tests/test_moderator.py,sha256=wc9A_0gx3LobMD7CDS-h2eTNPNYxeJk_rqtd2QTt428,291
|
25
|
+
Ryzenth/tests/test_ryzenthapiclient.py,sha256=U0WuYg2bc4p3jQK0P77eez4cKxkfiZjUKLKO0oe0rCc,440
|
21
26
|
Ryzenth/tests/test_send.py,sha256=yPQV3XRsPKBo4eSsz5kc2R6BEuru0zmMexYshX0Ac3s,573
|
22
|
-
Ryzenth/tests/test_send_downloader.py,sha256=
|
27
|
+
Ryzenth/tests/test_send_downloader.py,sha256=LvS7QSO4XyjG1UXH8pHvXCCMpvAs9_QVMfh7J9w_xdM,1038
|
28
|
+
Ryzenth/tl/__init__.py,sha256=SDoC1aFqHf682PasjkCIWzBdqvOJQ-Wn7ybDOxhHmMo,71
|
29
|
+
Ryzenth/tl/logger_service.py,sha256=23Mdi9obe-aF9SWBwgbRlk3hgQJdK9JYfg1iOsaUAW0,2651
|
23
30
|
Ryzenth/types/__init__.py,sha256=2q3Oy7wCtgHa1cVY1JVN6cJht7uEAva3yFijSiJxYdI,1392
|
24
|
-
ryzenth-2.0.
|
25
|
-
ryzenth-2.0.
|
26
|
-
ryzenth-2.0.
|
27
|
-
ryzenth-2.0.
|
28
|
-
ryzenth-2.0.
|
31
|
+
ryzenth-2.0.7.dist-info/licenses/LICENSE,sha256=C73aiGSgoCAVNzvAHs-TROaf5vV8yCj9nqpGrmfNHHo,1068
|
32
|
+
ryzenth-2.0.7.dist-info/METADATA,sha256=2H9iYtByjZbowDYzReZnjMT8gWDfJHLeykKulu1r7oc,5250
|
33
|
+
ryzenth-2.0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
34
|
+
ryzenth-2.0.7.dist-info/top_level.txt,sha256=0vIhjOjoQuCxLeZO0of8VCx2jsri-bLHV28nh8wWDnc,8
|
35
|
+
ryzenth-2.0.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|