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
Metadata
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 | Provenance | Actions |
|---|---|---|---|---|
| pyxui-2.0.0.tar.gz | 14.6 kB | Without provenance | Details for pyxui-2.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| pyxui-2.0.0-py3-none-any.whl | Python 3 | none | any | Details for pyxui-2.0.0-py3-none-any.whl |
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
|
Security for pyxui 2.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.