PyXUI
An async python library that allows you to modify your xui panel (alireza0 x-ui) (Sanaeii 3x-ui)
v2.0 is async only. Every panel method is now a coroutine and must be awaited. The HTTP layer moved from
requeststoaiohttp, and a singleClientSessionis reused for the whole lifetime of the client.
How To Install
pip install -U git+https://github.com/staliox/pyxui.git
How To Use
- Import pyxui in your .py file
import asyncio
from pyxui import XUI
# Basic:
xui = XUI(
full_address="https://staliox.com:2087",
panel="alireza", # Your panel name, "alireza" or "sanaei"
)
# Advanced:
xui = XUI(
full_address="http://staliox.site:2087",
panel="alireza", # Your panel name, "alireza" or "sanaei"
https=False, # Make note if you don't use https set False else set True
session_string=..., # If you have session cookie to use panel without login
timeout=10.0, # Per request timeout in seconds
max_connections=20, # Size of the connection pool
cache_ttl=0.0, # Seconds the inbounds list may be reused from memory, 0 disables it
auto_relogin=True, # Login again automatically when the session expires
raise_on_error=False, # Raise PanelError when the panel answers {"success": false}
session=..., # Bring your own aiohttp.ClientSession, pyxui will never close it
)
Building the XUI object does not touch the network or the event loop, the
aiohttp.ClientSession is created on the first request.
- Always close the client when you are done, or use it as a context manager
async def main():
async with XUI(full_address="https://staliox.com:2087", panel="sanaei") as xui:
await xui.login(USERNAME, PASSWORD)
inbounds = await xui.get_inbounds()
asyncio.run(main())
# without the context manager
xui = XUI(full_address="https://staliox.com:2087", panel="sanaei")
try:
...
finally:
await xui.close()
If you forget to close it, aiohttp will warn about an unclosed session on exit.
- Login in your panel
from pyxui.errors import BadLogin
try:
await xui.login(USERNAME, PASSWORD)
except BadLogin:
...
Once you have logged in, the credentials are kept in memory and the session is
refreshed automatically the first time the panel says it expired
(disable it with auto_relogin=False). await xui.logout() drops both.
- Run several calls at once
inbound, stats = await asyncio.gather(
xui.get_inbound(1),
xui.get_client_stats(1, email="Me"),
)
- Get inbounds list
get_inbounds = await xui.get_inbounds()
# Result
{
"success": true,
"msg": "",
"obj": [
{
"id": 1,
"up": 552345026,
"down": 18164200325,
"total": 0,
"remark": "Staliox",
"enable": true,
"expiryTime": 0,
"clientStats": [
{
"id": 1,
"inboundId": 1,
"enable": true,
"email": "Me",
"up": 191308877,
"down": 4945030148,
"expiryTime": 0,
"total": 0
}
],
"listen": "",
"port": 443,
"protocol": "vless",
"settings": "{\n \"clients\": [\n {\n \"email\": \"Me\",\n \"enable\": true,\n \"expiryTime\": 0,\n \"flow\": \"\",\n \"id\": \"c6419651-68d7-gfhg-d611-32v5df41g105\",\n \"limitIp\": 0,\n \"subId\": \"\",\n \"tgId\": \"@staliox\",\n \"totalGB\": 0\n }\n ],\n \"decryption\": \"none\",\n \"fallbacks\": []\n}",
"tag": "inbound-443",
"sniffing": "{\n \"enabled\": true,\n \"destOverride\": [\n \"http\",\n \"tls\"\n ]\n}"
}
]
}
- Add client to the existing inbound
get = await xui.add_client(
inbound_id=1,
email="example@gmal.com",
uuid="5d3d1bac-49cd-4b66-8be9-a728efa205fa",
enable = True,
flow = "",
limit_ip = 0,
total_gb = 5368709120,
expire_time = 1684948641772, # You must pass 13 digit timestamp
telegram_id = "",
subscription_id = ""
)
- Update the existing client
Only the fields you pass are changed, the rest of the client is read from the panel and kept as is, so a partial update is safe.
get = await xui.update_client(
inbound_id=1,
email="example@gmal.com",
uuid="5d3d1bac-49cd-4b66-8be9-a728efa205fa",
enable = True,
flow = "",
limit_ip = 0,
total_gb = 5368709120,
expire_time = 1684948641772,
telegram_id = "",
subscription_id = ""
)
# only bump the quota, everything else stays untouched
get = await xui.update_client(inbound_id=1, email="example@gmal.com", total_gb=10737418240)
- Get client's information:
get_client = await xui.get_client(
inbound_id=1,
email="Me",
uuid="5d3d1bac-49cd-4b66-8be9-a728efa205fa" # Make note you don't have to pass both of them (emaill, uuid), just one is enough
)
# Result
{
'email': 'Me',
'enable': True,
'expiryTime': 0,
'flow': 'xtls-rprx-vision',
'id': '5d3d1bac-49cd-4b66-8be9-a728efa205fa',
'limitIp': 0,
'subId': '',
'tgId': '',
'totalGB': 0
}
- Get client's statistics:
get_client = await xui.get_client_stats(
inbound_id=1,
email="Me",
)
# Result
{
'id': 1,
'inboundId': 1,
'enable': True,
'email': 'Me',
'up': 111494230,
'down': 620533614,
'expiryTime': 0,
'total': 0
}
- Delete client from the existing inbound:
get_client = await xui.delete_client(
inbound_id=1,
email="Me",
uuid="5d3d1bac-49cd-4b66-8be9-a728efa205fa" # Make note you don't have to pass both of them (email, uuid), just one is enough
)
- Reset the traffic of a client:
await xui.reset_client_traffic(
inbound_id=1,
email="Me"
)
Create vmess and vless config string
- Import config_generator
from pyxui.config_gen import config_generator
- VMESS:
config = {
"v": "2",
"ps": "Staliox-Me",
"add": "staliox.com",
"port": "443",
"id": "a85def57-0a86-43d1-b15c-0494519067c6",
"aid": "0",
"scy": "auto",
"net": "tcp",
"type": "ws",
"host": "staliox.site",
"path": "/",
"tls": "tls",
"sni": "staliox.site",
"alpn": "h2,http/1.1",
"fp": "chrome"
}
generate_config = config_generator("vmess", config)
# Result
vmess://eyJ2IjoiMiIsInBzIjoiU3RhbGlveC1NZSIsImFkZCI6InN0YWxpb3guY29tIiwicG9ydCI6IjQ0MyIsImlkIjoiYTg1ZGVmNTctMGE4Ni00M2QxLWIxNWMtMDQ5NDUxOTA2N2M2IiwiYWlkIjoiMCIsInNjeSI6ImF1dG8iLCJuZXQiOiJ0Y3AiLCJ0eXBlIjoid3MiLCJob3N0Ijoic3RhbGlveC5zaXRlIiwicGF0aCI6Ii8iLCJ0bHMiOiJ0bHMiLCJzbmkiOiJzdGFsaW94LnNpdGUiLCJhbHBuIjoiaDIsaHR0cC8xLjEiLCJmcCI6ImNocm9tZSJ9
- VLESS:
config = {
"ps": "Staliox-Me",
"add": "staliox.com",
"port": "443",
"id": "a85def57-0a86-43d1-b15c-0494519067c6"
}
data = {
"security": "tls",
"type": "ws",
"host": "staliox.site",
"path": "/",
"sni": "staliox.site",
"alpn": "h2,http/1.1",
"fp": "chrome"
}
generate_config = config_generator("vless", config, data)
# Result
vless://a85def57-0a86-43d1-b15c-0494519067c6@staliox.com:443?security=tls&type=ws&host=staliox.site&path=%2F&tls=tls&sni=staliox.site&alpn=h2%2Chttp%2F1.1&fp=chrome#Staliox-Me
Release files for pyxui 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyxui-2.0.0.tar.gz | 14.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyxui-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.2 kB
Release files / pyxui-2.0.0.tar.gz
| Download URL | pyxui-2.0.0.tar.gz |
|---|---|
| Size | 14.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
85b676e7c22649c23ba5b907f04a5ccb27146d93b5e1ba6ef6fefb03a3cbe2b2
|
|
BLAKE2b-256 checksum How to use checksums |
e56de1608932023eee4ced8b9305152b004424ff4aff3a96a7044b51268c2fff
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|
Release files / pyxui-2.0.0-py3-none-any.whl
| Download URL | pyxui-2.0.0-py3-none-any.whl |
|---|---|
| Size | 14.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8bf7b3caa650bb6169f7cec3c157edea6a532d7a07a63b9cf9a3e564215da73
|
|
BLAKE2b-256 checksum How to use checksums |
8d961285ee8e0796caeff6a41e636dd84eb2722c903f25eabf54b1646a2f188a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.10.11
|