├── core ├── database_transfer.sh ├── day_size.py ├── mlxui.sh ├── netscan_torrent_blocker.sh ├── setup_cron.py ├── user_manager.py ├── user_managment.py └── v2ray_bot.py ├── installer.sh ├── menu.sh ├── readme.fa.md └── readme.md /core/database_transfer.sh: -------------------------------------------------------------------------------- 1 | local db_file="/etc/x-ui/x-ui.db" 2 | 3 | read -p "Destination SERVER IP (e.g., 127.0.0.1): " dest_ip 4 | read -p "Destination SERVER USER (e.g., root) [default: root]: " dest_user 5 | read -p "Destination SERVER PORT (e.g., 22) [default: 22]: " dest_port 6 | 7 | dest_user=${dest_user:-root} 8 | dest_port=${dest_port:-22} 9 | 10 | echo "Transferring database..." 11 | scp -P "$dest_port" "$db_file" "$dest_user@$dest_ip:/etc/x-ui" 12 | 13 | if [ $? -eq 0 ]; then 14 | echo -e "${GREEN}Transfer completed successfully.${NC}" 15 | else 16 | echo -e "${RED}Transfer failed.${NC}" 17 | fi -------------------------------------------------------------------------------- /core/day_size.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | import time 3 | import json 4 | 5 | DB_PATH = '/etc/x-ui/x-ui.db' 6 | 7 | def dvhost_connect_to_db(): 8 | return sqlite3.connect(DB_PATH) 9 | 10 | def dvhost_convert_days_to_unix_millis(days): 11 | try: 12 | expiration_time_millis = (int(days) * 86400) * 1000 13 | return int(expiration_time_millis) 14 | except ValueError: 15 | print("Invalid number of days. Please enter a valid integer.") 16 | return None 17 | 18 | def dvhost_update_expiry_time(days): 19 | additional_time_millis = dvhost_convert_days_to_unix_millis(days) 20 | if additional_time_millis is None: 21 | return 22 | 23 | conn = dvhost_connect_to_db() 24 | try: 25 | cursor = conn.cursor() 26 | cursor.execute("SELECT id, expiry_time, total FROM client_traffics") 27 | client_traffics = cursor.fetchall() 28 | for client_id, expiry_time, total in client_traffics: 29 | if expiry_time > 0: 30 | new_expiry_time = expiry_time + additional_time_millis 31 | cursor.execute("UPDATE client_traffics SET expiry_time = ? WHERE id = ?", (new_expiry_time, client_id)) 32 | cursor.execute("SELECT id, settings FROM inbounds") 33 | inbounds = cursor.fetchall() 34 | 35 | for inbound_id, settings_json in inbounds: 36 | settings = json.loads(settings_json) 37 | if 'clients' in settings: 38 | for client in settings['clients']: 39 | if client['enable'] and client['expiryTime'] > 0: 40 | client['expiryTime'] += additional_time_millis 41 | new_settings_json = json.dumps(settings) 42 | cursor.execute("UPDATE inbounds SET settings = ? WHERE id = ?", (new_settings_json, inbound_id)) 43 | 44 | conn.commit() 45 | print("Expiry time and totalGB updated successfully.") 46 | except sqlite3.Error as e: 47 | print(f"An error occurred: {e}") 48 | finally: 49 | conn.close() 50 | 51 | def dvhost_update_traffic(): 52 | additional_gb = input("Enter additional gigabytes to add to totalGB: ") 53 | try: 54 | additional_gb = int(additional_gb) 55 | additional_bytes = additional_gb * 1024 * 1024 * 1024 56 | except ValueError: 57 | print("Invalid number of gigabytes. Please enter a valid integer.") 58 | return 59 | 60 | conn = dvhost_connect_to_db() 61 | try: 62 | cursor = conn.cursor() 63 | 64 | # Update total in client_traffics 65 | cursor.execute("SELECT id, total FROM client_traffics") 66 | client_traffics = cursor.fetchall() 67 | for client_id, total in client_traffics: 68 | if total > 0: 69 | new_total = total + additional_bytes 70 | cursor.execute("UPDATE client_traffics SET total = ? WHERE id = ?", (new_total, client_id)) 71 | 72 | # Update totalGB in inbounds 73 | cursor.execute("SELECT id, settings FROM inbounds") 74 | inbounds = cursor.fetchall() 75 | 76 | for inbound_id, settings_json in inbounds: 77 | settings = json.loads(settings_json) 78 | if 'clients' in settings: 79 | for client in settings['clients']: 80 | if client['enable'] and client['totalGB'] > 0: 81 | client['totalGB'] += additional_bytes 82 | 83 | new_settings_json = json.dumps(settings) 84 | cursor.execute("UPDATE inbounds SET settings = ? WHERE id = ?", (new_settings_json, inbound_id)) 85 | 86 | conn.commit() 87 | print("Traffic updated successfully.") 88 | except sqlite3.Error as e: 89 | print(f"An error occurred: {e}") 90 | finally: 91 | conn.close() 92 | 93 | def dvhost_main(): 94 | try: 95 | while True: 96 | print("\n1- Update Expiration Date\n2- Update Traffic\n0- Exit") 97 | choice = input("Enter your choice: ") 98 | 99 | if choice == '1': 100 | days = input("Enter number of days for expiration: ") 101 | dvhost_update_expiry_time(days) 102 | elif choice == '2': 103 | dvhost_update_traffic() 104 | elif choice == '0': 105 | break 106 | else: 107 | print("Invalid choice. Please enter a valid option.") 108 | except KeyboardInterrupt: 109 | print("\nOperation cancelled by user.") 110 | except Exception as e: 111 | print(f"An unexpected error occurred: {e}") 112 | 113 | if __name__ == "__main__": 114 | print("x-ui Assistant Version 1.9") 115 | dvhost_main() 116 | -------------------------------------------------------------------------------- /core/mlxui.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to check if the user is root 4 | check_root() { 5 | if [ "$EUID" -ne 0 ]; then 6 | echo "Please run this script as root." 7 | exit 1 8 | fi 9 | } 10 | 11 | # Function to check if the OS is Ubuntu 12 | check_ubuntu() { 13 | if [[ -f /etc/os-release ]]; then 14 | . /etc/os-release 15 | if [[ "$ID" != "ubuntu" ]]; then 16 | echo "This script is designed for Ubuntu only." 17 | exit 1 18 | fi 19 | else 20 | echo "Unable to detect the operating system." 21 | exit 1 22 | fi 23 | } 24 | 25 | # Function to install Docker if not installed 26 | install_docker() { 27 | if command -v docker &> /dev/null; then 28 | echo "Docker is already installed." 29 | return 30 | fi 31 | 32 | echo "Docker is not installed. Installing Docker..." 33 | 34 | # Update the package index 35 | apt-get update 36 | 37 | # Install required packages to allow apt to use a repository over HTTPS 38 | apt-get install -y apt-transport-https ca-certificates curl software-properties-common 39 | 40 | # Add Docker's official GPG key 41 | curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg 42 | 43 | # Set up the stable repository 44 | echo \ 45 | "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ 46 | $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null 47 | 48 | # Update the package index again after adding the Docker repository 49 | apt-get update 50 | 51 | # Install Docker CE (Community Edition) 52 | apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 53 | 54 | if [ $? -eq 0 ]; then 55 | echo "Docker has been successfully installed." 56 | else 57 | echo "Failed to install Docker." 58 | exit 1 59 | fi 60 | } 61 | 62 | install_panels() { 63 | read -p "How many panels do you want to install? (1-20): " panel_count 64 | if ! [[ "$panel_count" =~ ^[1-9]$|^1[0-9]$|^20$ ]]; then 65 | echo "Invalid input. Please enter a number between 1 and 20." 66 | return 67 | fi 68 | 69 | base_panel_port=2053 # Base Panel Port 70 | base_sub_port=2096 # Base Sub Port 71 | 72 | declare -A panel_ports # Array to store panel names and their ports 73 | 74 | for ((i = 1; i <= panel_count; i++)); do 75 | panel_dir="3x-ui-$i" 76 | panel_port=$((base_panel_port + (i - 1))) # Increment Panel Port by 1 for each panel 77 | sub_port=$((base_sub_port + (i - 1))) # Increment Sub Port by 1 for each panel 78 | 79 | # Ask the user to input inbound ports 80 | while true; do 81 | read -p "Enter inbound ports for panel $i (comma-separated, e.g., 10000,10001,10002): " inbound_ports 82 | if [[ -z "$inbound_ports" ]]; then 83 | echo "Error: Inbound ports cannot be empty. Please try again." 84 | continue 85 | fi 86 | 87 | # Validate inbound ports 88 | invalid_ports=() 89 | IFS=',' read -r -a ports_array <<< "$inbound_ports" 90 | for port in "${ports_array[@]}"; do 91 | if ! [[ "$port" =~ ^[0-9]+$ ]] || [[ "$port" -lt 1 || "$port" -gt 65535 ]]; then 92 | invalid_ports+=("$port") 93 | fi 94 | done 95 | 96 | if [ ${#invalid_ports[@]} -eq 0 ]; then 97 | break 98 | else 99 | echo "Error: The following ports are invalid: ${invalid_ports[*]}. Ports must be between 1 and 65535." 100 | fi 101 | done 102 | 103 | mkdir -p "$panel_dir" 104 | cd "$panel_dir" || exit 105 | 106 | echo "Cloning repository for panel $i..." 107 | git clone https://github.com/MHSanaEi/3x-ui.git . 108 | 109 | echo "Starting panel $i with the following ports:" 110 | echo "Panel Port: $panel_port" 111 | echo "Sub Port: $sub_port" 112 | echo "Inbound Ports: $inbound_ports" 113 | 114 | # Check if a container with the same name already exists 115 | if docker ps -a --format "{{.Names}}" | grep -q "^3x-ui-$i$"; then 116 | echo "A container with the name '3x-ui-$i' already exists. Removing it..." 117 | docker stop "3x-ui-$i" > /dev/null 2>&1 118 | docker rm "3x-ui-$i" > /dev/null 2>&1 119 | fi 120 | 121 | # Prepare Docker command 122 | docker_cmd="docker run -itd \ 123 | -e XRAY_VMESS_AEAD_FORCED=false \ 124 | -p $panel_port:2053 \ 125 | -p $sub_port:2096" 126 | 127 | # Add inbound ports to Docker command 128 | for port in "${ports_array[@]}"; do 129 | docker_cmd+=" -p $port:$port" 130 | done 131 | 132 | docker_cmd+=" \ 133 | -v $(pwd)/db/:/etc/x-ui/ \ 134 | -v $(pwd)/cert/:/root/cert/ \ 135 | --restart=always \ 136 | --name 3x-ui-$i \ 137 | ghcr.io/mhsanaei/3x-ui:latest" 138 | 139 | # Run Docker command 140 | eval "$docker_cmd" 141 | 142 | if [ $? -eq 0 ]; then 143 | echo "Panel $i has been successfully installed with the following ports:" 144 | echo "Panel Port: $panel_port" 145 | echo "Sub Port: $sub_port" 146 | echo "Inbound Ports: $inbound_ports" 147 | panel_ports["3x-ui-$i"]="Panel Port: $panel_port, Sub Port: $sub_port, Inbound Ports: $inbound_ports" 148 | else 149 | echo "Failed to install panel $i." 150 | # Clean up if the panel failed to install 151 | cd .. 152 | rm -rf "$panel_dir" 153 | fi 154 | 155 | cd .. 156 | done 157 | 158 | # Display the list of installed panels and their ports 159 | echo "====================" 160 | echo "Installed Panels:" 161 | echo "====================" 162 | for panel in "${!panel_ports[@]}"; do 163 | echo "Panel: $panel, Ports: ${panel_ports[$panel]}" 164 | done 165 | } 166 | 167 | # Function to update panels 168 | update_panels() { 169 | # Get the list of installed panels 170 | panels=($(docker ps --format "{{.Names}}" | grep "3x-ui-" || true)) 171 | 172 | if [ ${#panels[@]} -eq 0 ]; then 173 | echo "No panels are installed." 174 | return 175 | fi 176 | 177 | echo "====================" 178 | echo "Installed Panels:" 179 | echo "====================" 180 | 181 | # Display panels with their main port 182 | for panel_name in "${panels[@]}"; do 183 | # Get the main port using 'docker port' 184 | panel_port=$(docker port "$panel_name" 2053 | awk -F':' '{print $2}') 185 | if [ -z "$panel_port" ]; then 186 | panel_port="Unknown" 187 | fi 188 | echo "Panel: $panel_name, Ports: $panel_port" 189 | done 190 | 191 | while true; do 192 | echo "" 193 | echo "What do you want to do?" 194 | echo "1. Update a specific panel" 195 | echo "2. Update all panels" 196 | echo "3. Back to main menu" 197 | read -p "Please select an option: " choice 198 | 199 | case $choice in 200 | 1) 201 | read -p "Enter the name of the panel to update (e.g., 3x-ui-1): " panel_name 202 | if docker ps --format "{{.Names}}" | grep -q "^$panel_name$"; then 203 | echo "Updating panel $panel_name..." 204 | 205 | # Determine the directory of the panel 206 | panel_dir=$(find "$(pwd)" -type d -name "$panel_name" 2>/dev/null) 207 | 208 | if [ -z "$panel_dir" ]; then 209 | echo "Directory for panel $panel_name not found." 210 | continue 211 | fi 212 | 213 | # Perform the update 214 | cd "$panel_dir" || { echo "Failed to access panel directory."; continue; } 215 | docker compose down 216 | docker compose pull 3x-ui 217 | docker compose up -d 218 | 219 | if [ $? -eq 0 ]; then 220 | echo "Panel $panel_name has been updated successfully." 221 | else 222 | echo "Failed to update panel $panel_name." 223 | fi 224 | 225 | cd .. 226 | else 227 | echo "Panel $panel_name does not exist." 228 | fi 229 | ;; 230 | 2) 231 | echo "Updating all panels..." 232 | for panel_name in "${panels[@]}"; do 233 | echo "Updating panel $panel_name..." 234 | 235 | # Determine the directory of the panel 236 | panel_dir=$(find "$(pwd)" -type d -name "$panel_name" 2>/dev/null) 237 | 238 | if [ -z "$panel_dir" ]; then 239 | echo "Directory for panel $panel_name not found. Skipping..." 240 | continue 241 | fi 242 | 243 | # Perform the update 244 | cd "$panel_dir" || { echo "Failed to access panel directory. Skipping..."; continue; } 245 | docker compose down 246 | docker compose pull 3x-ui 247 | docker compose up -d 248 | 249 | if [ $? -eq 0 ]; then 250 | echo "Panel $panel_name has been updated successfully." 251 | else 252 | echo "Failed to update panel $panel_name." 253 | fi 254 | 255 | cd .. 256 | done 257 | ;; 258 | 3) 259 | return 260 | ;; 261 | *) 262 | echo "Invalid option. Please try again." 263 | ;; 264 | esac 265 | done 266 | } 267 | 268 | 269 | 270 | # Function to remove panels 271 | remove_panels() { 272 | # Get the list of running panels 273 | panels=($(docker ps --format "{{.Names}}" | grep "3x-ui-" || true)) 274 | 275 | if [ ${#panels[@]} -eq 0 ]; then 276 | echo "No panels are installed." 277 | return 278 | fi 279 | 280 | echo "====================" 281 | echo "Installed Panels:" 282 | echo "====================" 283 | 284 | # Display panels with only the main port (Panel Port) 285 | for panel_name in "${panels[@]}"; do 286 | # Get the first mapped port using 'docker port' 287 | panel_port=$(docker port "$panel_name" 2053 | awk -F':' '{print $2}') 288 | 289 | if [ -z "$panel_port" ]; then 290 | panel_port="Unknown" 291 | fi 292 | 293 | echo "Panel: $panel_name, Ports: $panel_port" 294 | done 295 | 296 | while true; do 297 | echo "" 298 | echo "What do you want to do?" 299 | echo "1. Remove a specific panel" 300 | echo "2. Remove all panels" 301 | echo "3. Back to main menu" 302 | read -p "Please select an option: " choice 303 | 304 | case $choice in 305 | 1) 306 | read -p "Enter the name of the panel to remove (e.g., 3x-ui-1): " panel_name 307 | if docker ps --format "{{.Names}}" | grep -q "^$panel_name$"; then 308 | echo "Removing panel $panel_name..." 309 | docker stop "$panel_name" > /dev/null 2>&1 310 | docker rm "$panel_name" > /dev/null 2>&1 311 | rm -rf "/$(pwd)/$panel_name" 312 | echo "Panel $panel_name has been removed successfully." 313 | else 314 | echo "Panel $panel_name does not exist." 315 | fi 316 | ;; 317 | 2) 318 | echo "Removing all panels..." 319 | for panel_name in "${panels[@]}"; do 320 | echo "Removing panel $panel_name..." 321 | docker stop "$panel_name" > /dev/null 2>&1 322 | docker rm "$panel_name" > /dev/null 2>&1 323 | rm -rf "/$(pwd)/$panel_name" 324 | done 325 | echo "All panels have been removed successfully." 326 | return 327 | ;; 328 | 3) 329 | return 330 | ;; 331 | *) 332 | echo "Invalid option. Please try again." 333 | ;; 334 | esac 335 | done 336 | } 337 | 338 | 339 | # Main menu 340 | main_menu() { 341 | while true; do 342 | clear 343 | echo "====================" 344 | echo "Panel Management Menu" 345 | echo "====================" 346 | echo "1. Install Panels" 347 | echo "2. Update Panels" 348 | echo "3. Remove Panels" 349 | echo "4. Exit" 350 | echo "" 351 | read -p "Please select an option: " choice 352 | 353 | case $choice in 354 | 1) 355 | install_panels 356 | ;; 357 | 2) 358 | update_panels 359 | ;; 360 | 3) 361 | remove_panels 362 | ;; 363 | 4) 364 | echo "Exiting..." 365 | exit 0 366 | ;; 367 | *) 368 | echo "Invalid option. Please try again." 369 | ;; 370 | esac 371 | 372 | read -p "Press Enter to continue..." 373 | done 374 | } 375 | 376 | # Run the checks and start the main menu 377 | check_root 378 | check_ubuntu 379 | install_docker 380 | main_menu -------------------------------------------------------------------------------- /core/netscan_torrent_blocker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Function to block torrent access 4 | dvhost_block_torrent() { 5 | echo "Blocking torrent access..." 6 | iptables -A OUTPUT -p tcp --dport 6881:6889 -j REJECT 7 | iptables -A OUTPUT -p udp --dport 6881:6889 -j REJECT 8 | iptables -A OUTPUT -p tcp --dport 6969 -j REJECT 9 | iptables -A OUTPUT -p udp --dport 6969 -j REJECT 10 | iptables -A OUTPUT -p udp --dport 4444 -j REJECT 11 | iptables -A OUTPUT -p udp --dport 8999 -j REJECT 12 | iptables -A OUTPUT -p udp -m string --string "announce" --algo bm -j REJECT 13 | iptables -A OUTPUT -p udp --dport 443 -j REJECT 14 | echo "Torrent access has been blocked completely." 15 | } 16 | 17 | # Function to unblock torrent access 18 | dvhost_unblock_torrent() { 19 | echo "Unblocking torrent access..." 20 | iptables -D OUTPUT -p tcp --dport 6881:6889 -j REJECT 21 | iptables -D OUTPUT -p udp --dport 6881:6889 -j REJECT 22 | iptables -D OUTPUT -p tcp --dport 6969 -j REJECT 23 | iptables -D OUTPUT -p udp --dport 6969 -j REJECT 24 | iptables -D OUTPUT -p udp --dport 4444 -j REJECT 25 | iptables -D OUTPUT -p udp --dport 8999 -j REJECT 26 | iptables -D OUTPUT -p udp -m string --string "announce" --algo bm -j REJECT 27 | iptables -D OUTPUT -p udp --dport 443 -j REJECT 28 | echo "Torrent access has been unblocked." 29 | } 30 | 31 | # Function to check the status of torrent blocking 32 | dvhost_torrent_status() { 33 | echo "Checking Torrent blocking status..." 34 | status=$(iptables -L OUTPUT -n | grep -E "6881:6889|6969|4444|8999|announce|443" | wc -l) 35 | if [[ "$status" -gt 0 ]]; then 36 | echo "Torrent access is BLOCKED." 37 | else 38 | echo "Torrent access is OPEN." 39 | fi 40 | } 41 | 42 | # Function to enable NetScan protection 43 | dvhost_enable_netscan_protection() { 44 | echo "Enabling NetScan protection..." 45 | iptables -N PORTSCAN 46 | iptables -A PORTSCAN -p tcp --tcp-flags SYN,ACK,FIN,RST RST -m limit --limit 1/s --limit-burst 4 -j RETURN 47 | iptables -A PORTSCAN -j DROP 48 | iptables -A INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j PORTSCAN 49 | iptables -A INPUT -p icmp --icmp-type echo-request -j DROP 50 | echo "NetScan protection is now ENABLED." 51 | } 52 | 53 | # Function to disable NetScan protection 54 | dvhost_disable_netscan_protection() { 55 | echo "Disabling NetScan protection..." 56 | iptables -D INPUT -p tcp --tcp-flags SYN,ACK,FIN,RST RST -j PORTSCAN 57 | iptables -F PORTSCAN 58 | iptables -X PORTSCAN 59 | iptables -D INPUT -p icmp --icmp-type echo-request -j DROP 60 | echo "NetScan protection is now DISABLED." 61 | } 62 | 63 | # Function to check the status of NetScan protection 64 | dvhost_netscan_status() { 65 | echo "Checking NetScan protection status..." 66 | status=$(iptables -L INPUT -n | grep -E "PORTSCAN|icmp" | wc -l) 67 | if [[ "$status" -gt 0 ]]; then 68 | echo "NetScan protection is ACTIVE." 69 | else 70 | echo "NetScan protection is INACTIVE." 71 | fi 72 | } 73 | 74 | # Main menu 75 | while true; do 76 | echo "" 77 | echo "-------- Torrent Management --------" 78 | echo "1) Block Torrent Access" 79 | echo "2) Unblock Torrent Access" 80 | echo "3) Check Torrent Blocking Status" 81 | echo "" 82 | echo "-------- NetScan Management --------" 83 | echo "4) Enable NetScan Protection" 84 | echo "5) Disable NetScan Protection" 85 | echo "6) Check NetScan Protection Status" 86 | echo "" 87 | echo "-------- General Management --------" 88 | echo "7) Exit" 89 | echo "" 90 | 91 | read -p "Choose an option [1-7]: " choice 92 | 93 | case $choice in 94 | 1) 95 | dvhost_block_torrent 96 | ;; 97 | 2) 98 | dvhost_unblock_torrent 99 | ;; 100 | 3) 101 | dvhost_torrent_status 102 | ;; 103 | 4) 104 | dvhost_enable_netscan_protection 105 | ;; 106 | 5) 107 | dvhost_disable_netscan_protection 108 | ;; 109 | 6) 110 | dvhost_netscan_status 111 | ;; 112 | 7) 113 | echo "Exiting..." 114 | exit 0 115 | ;; 116 | *) 117 | echo "Invalid option. Please try again." 118 | ;; 119 | esac 120 | done 121 | -------------------------------------------------------------------------------- /core/setup_cron.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | 4 | def check_and_install_cron(): 5 | # Check if crontab is installed 6 | cron_check = subprocess.run(['which', 'crontab'], capture_output=True, text=True) 7 | 8 | if cron_check.returncode != 0: 9 | print("Crontab is not installed. Installing cron...") 10 | # Install crontab 11 | os.system('sudo apt-get update') 12 | os.system('sudo apt-get install cron') 13 | print("Crontab has been installed.") 14 | # Start cron service 15 | os.system('sudo systemctl enable cron') 16 | os.system('sudo systemctl start cron') 17 | else: 18 | print("Crontab is already installed.") 19 | 20 | def get_user_input(): 21 | while True: 22 | try: 23 | interval = int(input("Please enter the interval in hours (e.g., 8 for every 8 hours): ")) 24 | if interval > 0 and 24 % interval == 0: 25 | return interval 26 | else: 27 | print("Invalid input. Interval must be a positive divisor of 24 (e.g., 1, 2, 3, 4, 6, 8, 12, 24).") 28 | except ValueError: 29 | print("Invalid input. Please enter an integer.") 30 | 31 | def setup_cron_job(interval): 32 | # Define the cron job 33 | cron_job = f"0 */{interval} * * * /usr/bin/env bash -c 'x-ui restart'\n" 34 | 35 | # Write the cron job to the user's crontab 36 | with open("mycron", "w") as cron_file: 37 | cron_file.write(cron_job) 38 | 39 | # Install the new cron file 40 | os.system('crontab mycron') 41 | os.remove("mycron") 42 | print(f"Cron job has been set to run 'x-ui restart' every {interval} hours.") 43 | 44 | def list_cron_jobs(): 45 | result = subprocess.run(['crontab', '-l'], capture_output=True, text=True) 46 | if result.returncode != 0: 47 | print("No crontab for this user or crontab is not installed.") 48 | return [] 49 | 50 | cron_jobs = result.stdout.strip().split('\n') 51 | if not cron_jobs or cron_jobs == ['']: 52 | print("No cron jobs found.") 53 | return [] 54 | 55 | print("Current cron jobs:") 56 | for i, job in enumerate(cron_jobs): 57 | print(f"{i+1}: {job}") 58 | 59 | return cron_jobs 60 | 61 | def delete_cron_job(cron_jobs): 62 | if not cron_jobs: 63 | return 64 | 65 | while True: 66 | try: 67 | job_number = int(input("Enter the number of the cron job to delete (0 to cancel): ")) 68 | if job_number == 0: 69 | print("Operation cancelled.") 70 | return 71 | elif 1 <= job_number <= len(cron_jobs): 72 | break 73 | else: 74 | print(f"Invalid input. Please enter a number between 0 and {len(cron_jobs)}.") 75 | except ValueError: 76 | print("Invalid input. Please enter a valid number.") 77 | 78 | del cron_jobs[job_number-1] 79 | 80 | with open("mycron", "w") as cron_file: 81 | for job in cron_jobs: 82 | cron_file.write(job + '\n') 83 | 84 | os.system('crontab mycron') 85 | os.remove("mycron") 86 | print("Cron job has been deleted.") 87 | 88 | def main(): 89 | check_and_install_cron() 90 | while True: 91 | print("\nMenu:") 92 | print("1- Set Cronjob Restart X-UI") 93 | print("2- Delete Cronjob") 94 | print("3- Exit") 95 | 96 | choice = input("Enter your choice: ") 97 | 98 | if choice == '1': 99 | user_interval = get_user_input() 100 | setup_cron_job(user_interval) 101 | elif choice == '2': 102 | cron_jobs = list_cron_jobs() 103 | delete_cron_job(cron_jobs) 104 | elif choice == '3': 105 | print("Exiting...") 106 | os.system('bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/xui-assistant/master/main.sh)') 107 | break 108 | else: 109 | print("Invalid choice. Please enter 1, 2, or 3.") 110 | 111 | if __name__ == "__main__": 112 | main() 113 | -------------------------------------------------------------------------------- /core/user_manager.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sqlite3 3 | import subprocess 4 | import bcrypt 5 | 6 | db_path = '/etc/x-ui/x-ui.db' 7 | 8 | def clear_screen(): 9 | os.system('cls' if os.name == 'nt' else 'clear') 10 | 11 | def get_db_connection(): 12 | if not os.path.exists(db_path): 13 | print("Database file does not exist.") 14 | input("Press Enter to continue...") 15 | return None 16 | conn = sqlite3.connect(db_path) 17 | return conn 18 | 19 | def hash_password(password): 20 | salt = bcrypt.gensalt() 21 | hashed = bcrypt.hashpw(password.encode('utf-8'), salt) 22 | return hashed.decode('utf-8') 23 | 24 | def column_exists(cursor, table, column): 25 | cursor.execute(f"PRAGMA table_info({table})") 26 | columns = [row[1] for row in cursor.fetchall()] 27 | return column in columns 28 | 29 | def dvhost_add_user(): 30 | conn = get_db_connection() 31 | if conn is None: 32 | return 33 | cursor = conn.cursor() 34 | 35 | username = input("Enter username: ") 36 | password = input("Enter password: ") 37 | 38 | cursor.execute("SELECT COUNT(*) FROM users WHERE username=?", (username,)) 39 | if cursor.fetchone()[0] > 0: 40 | print("\033[91mUsername already exists.\033[0m") 41 | else: 42 | use_plain = False 43 | if column_exists(cursor, "users", "login_secret"): 44 | cursor.execute("SELECT login_secret FROM users WHERE username=?", (username,)) 45 | row = cursor.fetchone() 46 | if row and row[0]: 47 | use_plain = True 48 | hashed_password = password if use_plain else hash_password(password) 49 | 50 | cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, hashed_password)) 51 | conn.commit() 52 | print("\033[92mUser added successfully.\033[0m") 53 | 54 | conn.close() 55 | input("Press Enter to continue...") 56 | 57 | def dvhost_delete_user(): 58 | conn = get_db_connection() 59 | if conn is None: 60 | return 61 | cursor = conn.cursor() 62 | 63 | user_id = input("Enter User ID: ") 64 | 65 | cursor.execute("SELECT COUNT(*) FROM users WHERE id=?", (user_id,)) 66 | if cursor.fetchone()[0] == 0: 67 | print("User does not exist.") 68 | else: 69 | confirm = input("Are you sure you want to delete this user? (yes/no): ").lower() 70 | if confirm == 'yes': 71 | cursor.execute("DELETE FROM users WHERE id = ?", (user_id,)) 72 | conn.commit() 73 | print("\033[92mUser deleted successfully.\033[0m") 74 | else: 75 | print("Operation cancelled.") 76 | 77 | conn.close() 78 | input("Press Enter to continue...") 79 | 80 | def dvhost_change_password(): 81 | conn = get_db_connection() 82 | if conn is None: 83 | return 84 | cursor = conn.cursor() 85 | 86 | username = input("Enter username: ") 87 | 88 | cursor.execute("SELECT COUNT(*) FROM users WHERE username=?", (username,)) 89 | if cursor.fetchone()[0] == 0: 90 | print("Username does not exist.") 91 | conn.close() 92 | input("Press Enter to continue...") 93 | return 94 | 95 | new_password = input("Enter new password: ") 96 | confirm_password = input("Re-enter new password: ") 97 | 98 | if new_password != confirm_password: 99 | print("Passwords do not match.") 100 | conn.close() 101 | input("Press Enter to continue...") 102 | return 103 | 104 | use_plain = False 105 | if column_exists(cursor, "users", "login_secret"): 106 | cursor.execute("SELECT login_secret FROM users WHERE username=?", (username,)) 107 | row = cursor.fetchone() 108 | if row and row[0]: 109 | use_plain = True 110 | 111 | hashed_password = new_password if use_plain else hash_password(new_password) 112 | 113 | cursor.execute("UPDATE users SET password=? WHERE username=?", (hashed_password, username)) 114 | conn.commit() 115 | print("\033[92mPassword updated successfully.\033[0m") 116 | 117 | conn.close() 118 | input("Press Enter to continue...") 119 | 120 | def dvhost_list_users(): 121 | conn = get_db_connection() 122 | if conn is None: 123 | return 124 | cursor = conn.cursor() 125 | 126 | cursor.execute("SELECT id, username, password FROM users ORDER BY id") 127 | users = cursor.fetchall() 128 | 129 | conn.close() 130 | print("+===========================================================+") 131 | print("|====================== X-UI Users =====================|") 132 | print("+===========================================================+") 133 | header = "| {:^5} | {:^20} | {:^40} |".format('ID', 'Username', 'Password') 134 | separator = "+{:-^7}+{:-^22}+{:-^42}+".format('', '', '') 135 | print(separator) 136 | print(header) 137 | print(separator) 138 | for user in users: 139 | print("| {:^5} | {:^20} | {:^40} |".format(user[0], user[1], user[2])) 140 | print(separator) 141 | 142 | def main(): 143 | try: 144 | while True: 145 | clear_screen() 146 | dvhost_list_users() 147 | 148 | print("\n1. Add User") 149 | print("2. Delete User") 150 | print("3. Change Password") 151 | print("4. Exit") 152 | 153 | choice = input("\nEnter your choice: ") 154 | 155 | if choice == '1': 156 | dvhost_add_user() 157 | elif choice == '2': 158 | dvhost_delete_user() 159 | elif choice == '3': 160 | dvhost_change_password() 161 | elif choice == '4': 162 | subprocess.run(['bash', '-c', 'curl -Ls https://raw.githubusercontent.com/dev-ir/xui-assistant/master/install.sh | bash'], check=True) 163 | break 164 | else: 165 | print("Invalid choice, please try again.") 166 | input("Press Enter to continue...") 167 | except KeyboardInterrupt: 168 | print("\n\nProgram interrupted by user. Exiting...") 169 | 170 | if __name__ == "__main__": 171 | main() 172 | -------------------------------------------------------------------------------- /core/user_managment.py: -------------------------------------------------------------------------------- 1 | import sqlite3 2 | from datetime import datetime 3 | 4 | 5 | import os 6 | 7 | # کدهای رنگ برای نمایش رنگ‌ها 8 | GREEN = "\033[32m" 9 | RED = "\033[31m" 10 | YELLOW = "\033[33m" 11 | RESET = "\033[0m" 12 | 13 | def display_menu(): 14 | # اطلاعات سرور 15 | os.system("clear") 16 | print("+----------------------------------------------------------------------------------------------------+") 17 | print("| _ _ __ __ _ |") 18 | print("| | | | | | \/ | | | |") 19 | print("| | | | | ___ ___ _ __ | \ / | __ _ _ __ __ _ __ _ ___ _ __ ___ ___ _ __ | |_ |") 20 | print("| | | | |/ __| / _ \| __| | |\/| | / _ || _ \ / _ | / _ | / _ \| _ _ \ / _ \| _ \ | __| |") 21 | print("| | |__| |\__ \| __/| | | | | || (_| || | | || (_| || (_| || __/| | | | | || __/| | | || |_ |") 22 | print("| \____/ |___/ \___||_| |_| |_| \__,_||_| |_| \__,_| \__, | \___||_| |_| |_| \___||_| |_| \__| |") 23 | print("| __/ | |") 24 | print("| |___/ |") 25 | print("+----------------------------------------------------------------------------------------------------+") 26 | print(f"| Telegram Channel : {GREEN}@DVHOST_CLOUD{RESET} | YouTube : {RED}youtube.com/@dvhost_cloud{RESET}") 27 | print("+----------------------------------------------------------------------------------------------------+") 28 | print(f"|{YELLOW} Please choose an option:{RESET}") 29 | print("+----------------------------------------------------------------------------------------------------+") 30 | print("| 1- Users with upcoming expiry dates |") 31 | print("| 2- Users with low remaining volume |") 32 | print("| 3- Admin Manager |") 33 | print("| 0- Back |") 34 | print("+----------------------------------------------------------------------------------------------------+") 35 | 36 | 37 | class DvhostCloudDB: 38 | # کدهای رنگ برای نمایش پیام‌ها 39 | RED = "\033[91m" 40 | RESET = "\033[0m" 41 | 42 | def __init__(self, db_path="/etc/x-ui/x-ui.db"): 43 | self.db_path = db_path 44 | self.connection = None 45 | # بررسی وجود فایل دیتابیس 46 | if not os.path.exists(self.db_path): 47 | print(f"{self.RED}Database file not found. Please visit our Telegram channel for support:") 48 | print("https://t.me/dvhost_cloud" + self.RESET) 49 | exit() # خروج از برنامه در صورت عدم وجود فایل دیتابیس 50 | self.dvhost_cloud_connect() 51 | 52 | def dvhost_cloud_connect(self): 53 | """Connects to the SQLite database and displays a connection message.""" 54 | try: 55 | self.connection = sqlite3.connect(self.db_path) 56 | print("Connected to the database successfully.") 57 | except sqlite3.Error as e: 58 | print(f"Failed to connect to the database: {e}") 59 | self.connection = None 60 | 61 | def dvhost_cloud_query(self, query, params=()): 62 | """Executes a query on the database and returns the results if connected.""" 63 | if self.connection is None: 64 | print("No database connection available.") 65 | return None 66 | try: 67 | cursor = self.connection.cursor() 68 | cursor.execute(query, params) 69 | results = cursor.fetchall() 70 | return results 71 | except sqlite3.Error as e: 72 | print(f"An error occurred while executing the query: {e}") 73 | return None 74 | 75 | def dvhost_cloud_calculate_size(self, size_in_bytes): 76 | """Converts size from bytes to the nearest unit and returns it with the unit.""" 77 | units = ["B", "KB", "MB", "GB", "TB"] 78 | size = size_in_bytes 79 | unit_index = 0 80 | 81 | while size >= 1024 and unit_index < len(units) - 1: 82 | size /= 1024 83 | unit_index += 1 84 | 85 | return f"{size:.2f} {units[unit_index]}" 86 | 87 | def dvhost_cloud_time_left(self, expiry_time): 88 | """Calculates the days and hours left until the expiry time.""" 89 | current_timestamp = int(datetime.now().timestamp() * 1000) 90 | time_left_ms = expiry_time - current_timestamp 91 | days_left = time_left_ms // (1000 * 60 * 60 * 24) 92 | hours_left = (time_left_ms % (1000 * 60 * 60 * 24)) // (1000 * 60 * 60) 93 | return days_left, hours_left 94 | 95 | def dvhost_cloud_expire_time(self): 96 | """Displays users with remaining volume under 5 GB in a table format.""" 97 | self.clear_screen() 98 | print("{:<5} {:<25} {:<20}".format("No.", "Email", "Remaining Volume")) 99 | print("=" * 50) 100 | query = """ 101 | SELECT email, total, down, up, (total - (down + up)) AS remaining_volume 102 | FROM client_traffics 103 | """ 104 | results = self.dvhost_cloud_query(query) 105 | 106 | if results: 107 | index = 1 108 | for email, total, down, up, remaining_volume in results: 109 | if 0 < remaining_volume < 5 * 1024 ** 3: 110 | remaining_converted = self.dvhost_cloud_calculate_size(remaining_volume) 111 | print("{:<5} {:<25} {:<20}".format(index, email, remaining_converted)) 112 | index += 1 113 | if index == 1: 114 | print("No users with remaining volume under 5 GB.") 115 | else: 116 | print("No data found.") 117 | 118 | def dvhost_cloud_expire_vol(self): 119 | """Displays users with expiry dates within the next 2 days in a table format.""" 120 | self.clear_screen() 121 | print("{:<5} {:<25} {:<30}".format("No.", "Email", "Time Left")) 122 | print("=" * 60) 123 | results = self.dvhost_cloud_query( 124 | """ 125 | SELECT expiry_time, email 126 | FROM client_traffics 127 | WHERE expiry_time > strftime('%s', 'now') * 1000 128 | AND expiry_time <= (strftime('%s', 'now', '+2 day')) * 1000 129 | ORDER BY rowid ASC 130 | """ 131 | ) 132 | 133 | if results: 134 | for index, (expiry_time, email) in enumerate(results, start=1): 135 | days_left, hours_left = self.dvhost_cloud_time_left(expiry_time) 136 | print("{:<5} {:<25} {:<30}".format(index, email, f"{days_left} days and {hours_left} hours")) 137 | if index == 1: 138 | print("No users with upcoming expiry dates within 2 days.") 139 | else: 140 | print("No data found.") 141 | 142 | def clear_screen(self): 143 | """Clears the console screen.""" 144 | os.system('cls' if os.name == 'nt' else 'clear') 145 | 146 | def dvhost_cloud_close(self): 147 | """Closes the database connection.""" 148 | if self.connection: 149 | self.connection.close() 150 | print("Database connection closed.") 151 | 152 | if __name__ == "__main__": 153 | db = DvhostCloudDB() 154 | try: 155 | while True: 156 | display_menu() 157 | choice = input("Please enter your choice (1, 2, 3, 4...): ") 158 | 159 | if choice == '1': 160 | os.system('cls' if os.name == 'nt' else 'clear') 161 | print("Displaying users with upcoming expiry dates...") 162 | db.dvhost_cloud_expire_vol() 163 | elif choice == '2': 164 | os.system('cls' if os.name == 'nt' else 'clear') 165 | print("Displaying users with low remaining volume...") 166 | db.dvhost_cloud_expire_time() 167 | elif choice == '3': 168 | os.system('cls' if os.name == 'nt' else 'clear') 169 | print("Adding a new admin...") 170 | os.system("cd ~/xui-assistant && python3 core/user_manager.py") 171 | elif choice == '0': 172 | os.system('cls' if os.name == 'nt' else 'clear') 173 | print("Returning to the previous menu...") 174 | os.system("xui-assis") 175 | break 176 | else: 177 | print("Invalid choice. Please try again.") 178 | 179 | input("\nPress Enter to return to the menu...") 180 | except KeyboardInterrupt: 181 | print("\nProgram interrupted. Exiting cleanly...") 182 | db.dvhost_cloud_close() 183 | 184 | -------------------------------------------------------------------------------- /core/v2ray_bot.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import os 3 | import shutil 4 | import time 5 | 6 | def DVHOST_CLOUD_display_menu(): 7 | os.system('clear') # Clear the screen after installation 8 | print("1- Install and Configure") 9 | print("2- Uninstall") 10 | print("0- Exit") 11 | 12 | def DVHOST_CLOUD_install_panels(): 13 | panels = [] 14 | while True: 15 | print("\nPlease enter your panel information:") 16 | url = input("Enter panel URL (e.g., http://1.1.1.1:2020): ") 17 | username = input("Enter username: ") 18 | password = input("Enter password: ") 19 | 20 | panels.append(f" - url: {url}\n username: {username}\n password: {password}\n\n") 21 | 22 | more_panels = input("Do you have another panel? (yes/no): ").strip().lower() 23 | if more_panels != 'yes': 24 | break 25 | 26 | return panels 27 | 28 | def DVHOST_CLOUD_get_telegram_token(): 29 | token = input("Enter your Telegram bot token: ") 30 | return token 31 | 32 | def DVHOST_CLOUD_save_config(config): 33 | config_dir = '/root/v2ray-tel-bot/config/' 34 | 35 | # Create the directory if it doesn't exist 36 | if not os.path.exists(config_dir): 37 | os.makedirs(config_dir) 38 | 39 | config_file_path = os.path.join(config_dir, 'config.yml') 40 | output = f"telegram_token: \"{config['telegram_token']}\"\nchannel_id: \"{config['channel_id']}\"\npanels:\n" + ''.join(config['panels']) 41 | 42 | with open(config_file_path, 'w') as file: 43 | file.write(output) 44 | 45 | def DVHOST_CLOUD_run_process(command): 46 | process = subprocess.Popen(command, shell=True) 47 | process.wait() 48 | 49 | def DVHOST_CLOUD_show_progress_bar(duration): 50 | print("Installing...") 51 | for _ in range(duration): 52 | time.sleep(0.1) 53 | print(".", end="", flush=True) 54 | print("\nInstallation complete.") 55 | 56 | def DVHOST_CLOUD_check_and_install(): 57 | if not os.path.exists('/root/v2ray-tel-bot'): 58 | print("v2ray-tel-bot not found. Installing now...\n") 59 | # Run the installation script 60 | DVHOST_CLOUD_run_process("bash -c 'bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/v2ray-tel-bot/main/install.sh)'") 61 | DVHOST_CLOUD_show_progress_bar(50) 62 | os.system('clear') # Clear the screen after installation 63 | if not os.path.exists('/root/v2ray-tel-bot'): 64 | print("Installation failed. Exiting...") 65 | exit(1) 66 | 67 | # Install python3-pip after v2ray-tel-bot installation 68 | print("Installing python3-pip...\n") 69 | DVHOST_CLOUD_run_process("sudo apt-get update && sudo apt-get install -y python3-pip") 70 | os.system('clear') # Clear the screen after installation 71 | print("python3-pip installation complete.\n") 72 | 73 | def DVHOST_CLOUD_uninstall(): 74 | dir_path = '/root/v2ray-tel-bot/' 75 | if os.path.exists(dir_path): 76 | shutil.rmtree(dir_path) 77 | print(f"\nDirectory {dir_path} has been removed.\n") 78 | else: 79 | print(f"\nDirectory {dir_path} does not exist.\n") 80 | 81 | def DVHOST_CLOUD_reboot_system(): 82 | for i in range(5, 0, -1): 83 | print(f"\033[91m{i}\033[0m") # 91 is the ANSI code for red text 84 | time.sleep(1) 85 | print("Rebooting now...") 86 | DVHOST_CLOUD_run_process("reboot") 87 | 88 | def main(): 89 | # First, check if the necessary directory exists and install if needed 90 | DVHOST_CLOUD_check_and_install() 91 | 92 | # Now display the menu 93 | config = { 94 | "telegram_token": "", 95 | "channel_id": "", # If you want to force the user to join the channel, provide channel's numeric ID (-1243423432). Otherwise, put Empty 96 | "panels": [] 97 | } 98 | 99 | while True: 100 | DVHOST_CLOUD_display_menu() 101 | choice = input("Choose an option: ") 102 | 103 | if choice == '1': 104 | # Get the Telegram bot token first 105 | config['telegram_token'] = DVHOST_CLOUD_get_telegram_token() 106 | 107 | # Then get the panel information 108 | config['panels'] = DVHOST_CLOUD_install_panels() 109 | print("\nConfiguration created:\n") 110 | output = f"telegram_token: \"{config['telegram_token']}\"\nchannel_id: \"{config['channel_id']}\"\npanels:\n" + ''.join(config['panels']) 111 | print(output) 112 | 113 | confirmation = input("\nAre you sure you want to start the bot with this configuration? (yes/no): ").strip().lower() 114 | if confirmation == 'yes': 115 | print("\nSaving configuration to /root/v2ray-tel-bot/config/config.yml...\n") 116 | DVHOST_CLOUD_save_config(config) 117 | 118 | print("\nRunning the bot...\n") 119 | DVHOST_CLOUD_run_process("python3 /root/v2ray-tel-bot/login.py") 120 | 121 | # Countdown and reboot 122 | DVHOST_CLOUD_reboot_system() 123 | break 124 | else: 125 | print("\nRestarting configuration process...\n") 126 | 127 | elif choice == '2': 128 | DVHOST_CLOUD_uninstall() 129 | 130 | elif choice == '0': 131 | print("Exiting...") 132 | break 133 | 134 | else: 135 | print("Invalid option. Please try again.") 136 | 137 | if __name__ == "__main__": 138 | main() 139 | -------------------------------------------------------------------------------- /installer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Color Definitions 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | NC='\033[0m' # No Color 7 | 8 | # Configuration 9 | VERSION='2.3.1' 10 | INSTALL_DIR='/root/xui-assistant' 11 | BIN_PATH='/usr/local/bin/xui-assis' 12 | REPO_URL='https://github.com/dev-ir/xui-assistant.git' 13 | 14 | # Clean previous installation 15 | rm -rf "${INSTALL_DIR}" 16 | 17 | # Install dependencies 18 | if ! command -v git &> /dev/null; then 19 | echo -e "${GREEN}Installing git...${NC}" 20 | apt-get update && apt-get install -y git 21 | fi 22 | 23 | # Clone repository 24 | echo -e "${GREEN}Cloning repository...${NC}" 25 | git clone "${REPO_URL}" "${INSTALL_DIR}" 26 | 27 | # Set permissions 28 | chmod +x "${INSTALL_DIR}" 29 | chmod +x "${INSTALL_DIR}/menu.sh" 30 | 31 | # Install binary 32 | mv "${INSTALL_DIR}/menu.sh" "${BIN_PATH}" 33 | 34 | # Display success message 35 | clear 36 | echo "+------------------------------------------------------------------------+" 37 | echo -e "| Telegram Channel : ${RED}@DVHOST_CLOUD${NC} | YouTube : ${RED}youtube.com/@dvhost_cloud${NC} |" 38 | echo "+------------------------------------------------------------------------+" 39 | echo -e "| Now permanently access the menu by typing: ${GREEN}xui-assis${NC} | Version : ${GREEN}${VERSION}${NC} |" 40 | echo "+------------------------------------------------------------------------+" 41 | -------------------------------------------------------------------------------- /menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Color Definitions 4 | RED='\033[0;31m' 5 | GREEN='\033[0;32m' 6 | YELLOW='\033[0;33m' 7 | NC='\033[0m' # No Color 8 | VERSION='2.3.1' 9 | 10 | # Path Definitions 11 | XUI_ASSISTANT_DIR="/root/xui-assistant" 12 | XUI_DB_PATH="/etc/x-ui/x-ui.db" 13 | 14 | # Check root privilege 15 | [[ $EUID -ne 0 ]] && echo -e "${RED}Fatal error: Please run this script with root privilege${NC}\n" && exit 1 16 | 17 | xui_assis_display_menu() { 18 | clear 19 | local xui_status=$(xui_assis_check_installation) 20 | 21 | cat << "EOF" 22 | +-----------------------------------------------------------------------------+ 23 | | _ ____ ______ ___ __________ __________________ _ ________ 24 | | | |/ / / / / _/ / | / ___/ ___// _/ ___/_ __/ | / | / /_ __/ 25 | | | / / / // / _____ / /| | \__ \\__ \ / / \__ \ / / / /| | / |/ / / / 26 | | / / /_/ // / _____ / ___ |___/ /__/ // / ___/ // / / ___ |/ /| / / / 27 | | /_/|_\____/___/ /_/ |_/____/____/___//____//_/ /_/ |_/_/ |_/ /_/ 28 | +-----------------------------------------------------------------------------+ 29 | EOF 30 | echo -e "| Telegram Channel : ${YELLOW}@DVHOST_CLOUD${NC} | YouTube : ${RED}@dvhost_cloud${NC} | Version : ${GREEN}${VERSION}${NC} " 31 | echo '+-----------------------------------------------------------------------------+' 32 | echo -e "|${YELLOW} Please choose an option:${NC}" 33 | echo '+-----------------------------------------------------------------------------+' 34 | echo -e "$1" 35 | echo '+-----------------------------------------------------------------------------+' 36 | } 37 | 38 | xui_assis_check_installation() { 39 | [[ -f "$XUI_DB_PATH" ]] && echo "${GREEN}Installed${NC}" || echo "${RED}Not installed${NC}" 40 | } 41 | 42 | # Core Functions 43 | xui_assis_transfer_database() { 44 | bash "${XUI_ASSISTANT_DIR}/core/database_transfer.sh" 45 | } 46 | 47 | xui_assis_gift_users() { 48 | python3 "${XUI_ASSISTANT_DIR}/core/day_size.py" 49 | } 50 | 51 | xui_assis_manage_admins() { 52 | python3 "${XUI_ASSISTANT_DIR}/core/user_managment.py" 53 | } 54 | 55 | xui_assis_set_xray_restart() { 56 | python3 "${XUI_ASSISTANT_DIR}/core/setup_cron.py" 57 | } 58 | 59 | xui_assis_fix_whatsapp_time() { 60 | timedatectl set-timezone UTC 61 | echo -e "${GREEN}Timezone set to UTC for WhatsApp compatibility.${NC}" 62 | } 63 | 64 | xui_assis_install_wordpress() { 65 | bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/WordPress-Installer/master/main.sh) 66 | } 67 | 68 | xui_assis_block_speedtest() { 69 | bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/speedtest-ban/master/main.sh) 70 | } 71 | 72 | xui_assis_user_management_bot() { 73 | python3 "${XUI_ASSISTANT_DIR}/core/v2ray_bot.py" 74 | } 75 | 76 | xui_assis_install_panels() { 77 | bash "${XUI_ASSISTANT_DIR}/core/mlxui.sh" 78 | } 79 | 80 | xui_assis_add_subscription_templates() { 81 | bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/xui-subscription-template/refs/heads/master/main.sh ) 82 | } 83 | 84 | xui_assis_uninstall() { 85 | echo -e "${GREEN}Uninstalling XUI-ASSISTANT...${NC}" 86 | rm -rf "$XUI_ASSISTANT_DIR" 87 | rm -f /usr/local/bin/xui-assis 88 | echo -e "${RED}XUI-ASSISTANT has been completely removed.${NC}" 89 | } 90 | 91 | xui_assis_exit() { 92 | echo -e "${GREEN}Exiting the program...${NC}" 93 | exit 0 94 | } 95 | 96 | xui_assis_main_menu() { 97 | local menu_options 98 | read -r -d '' menu_options << EOM 99 | | 1 - Transfer Database to Another Server 100 | | 2 - Gift Flow/Time to All Users 101 | +-----------------------------------------------------------------------------+ 102 | | 3 - Admin Management 103 | | 4 - User Management Bot (Traffic/Date) 104 | +-----------------------------------------------------------------------------+ 105 | | 5 - Schedule Xray Service Restart 106 | | 6 - Fix WhatsApp Date/Time Issue 107 | | 7 - Block Speedtest Websites 108 | +-----------------------------------------------------------------------------+ 109 | | 8 - Install WordPress Alongside X-UI 110 | | 9 - Install More X-UI Panels 111 | | 10 - Add Subscription Templates 112 | +-----------------------------------------------------------------------------+ 113 | | 11 - Uninstall This Script 114 | | 0 - Exit Program 115 | EOM 116 | 117 | xui_assis_display_menu "$menu_options" 118 | echo -ne "${YELLOW}| Enter option number: ${NC}" 119 | read -r choice 120 | case $choice in 121 | 1) xui_assis_transfer_database ;; 122 | 2) xui_assis_gift_users ;; 123 | 3) xui_assis_manage_admins ;; 124 | 4) xui_assis_user_management_bot;; 125 | 5) xui_assis_set_xray_restart ;; 126 | 6) xui_assis_fix_whatsapp_time ;; 127 | 7) xui_assis_block_speedtest ;; 128 | 8) xui_assis_install_wordpress;; 129 | 9) xui_assis_install_panels ;; 130 | 10) xui_assis_add_subscription_templates ;; 131 | 11) xui_assis_uninstall ;; 132 | 0) xui_assis_exit ;; 133 | *) echo -e "${RED}Invalid option. Please try again.${NC}" ;; 134 | esac 135 | } 136 | 137 | # Start the program 138 | xui_assis_main_menu -------------------------------------------------------------------------------- /readme.fa.md: -------------------------------------------------------------------------------- 1 | # ⚡️ به XUI Assistant خوش آمدید ⚡️ 2 | 3 | > **توضیح:** XUI Assistant یک پنل مدیریتی جامع برای مشترکین XUI است. 4 | > **امروز XUI Assistant را امتحان کنید و تفاوت را احساس کنید!** 5 | 6 | ## 📥 نصب و بروزرسانی 7 | 8 | ```bash 9 | bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/xui-assistant/master/installer.sh) 10 | ``` 11 | 12 | ## 🚀 ویژگی‌ها 13 | 14 | ### 🔹 مدیریت کاربران و مدیران 15 | - **مدیریت ادمین‌ها** برای کنترل بهتر 16 | - **ربات مدیریت کاربران** بر اساس ترافیک و تاریخ 17 | - **افزایش حجم و زمان استفاده هدیه** برای تمامی کاربران 18 | 19 | ### 🔹 مدیریت سیستم و امنیت 20 | - **انتقال پایگاه داده به سرور دیگر** برای مهاجرت آسان 21 | - **زمان‌بندی ری‌استارت سرویس Xray** برای نگهداری سیستم 22 | - **رفع مشکل تاریخ/زمان واتساپ** برای همگام‌سازی بهتر 23 | - **مسدودسازی سایت‌های تست سرعت** برای جلوگیری از سوءاستفاده 24 | 25 | ### 🔹 امکانات پیشرفته و افزونه‌ها 26 | - **نصب وردپرس در کنار X-UI** برای امکانات بیشتر 27 | - **نصب پنل‌های اضافی X-UI** برای افزایش قابلیت‌ها 28 | - **افزودن قالب‌های اشتراک** برای مدیریت آسان‌تر 29 | 30 | ### 🔹 مدیریت اسکریپت و برنامه 31 | - **حذف نصب این اسکریپت** در صورت نیاز 32 | - **خروج از برنامه** به صورت ایمن 33 | 34 | ## 🖥️ سیستم‌عامل‌های پشتیبانی‌شده 35 | - **اوبونتو 20+** (پیشنهاد شده برای بهترین سازگاری) 36 | 37 | ## 🌍 زبان‌های پشتیبانی‌شده 38 | - فارسی 39 | - [🌍 English (انگلیسی)](README.md) 40 | 41 | ## 🖼️ پیش‌نمایش 42 |

43 | XUI Assistant Preview 44 |

45 | 46 | ## 🙏 حمایت با رمزارز 47 | **ما نیازی به حمایت مالی نداریم، تنها یک ستاره (⭐) کافی است. سپاسگزاریم!** 48 | 49 | - **USDT (TRC20):** `TVUqVMoCEe5DVUoxmPg8MwmgcHvZLqLjr4` 50 | 51 | ## 📢 به کانال تلگرام ما بپیوندید 52 | 📌 [کانال تلگرام](https://t.me/+EpErnDsDPhw3ZThk) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ⚡️ Welcome to XUI Assistant ⚡️ 2 | 3 | > **Disclaimer:** XUI Assistant is a comprehensive management panel for XUI subscribers. 4 | > **Try XUI Assistant today and experience the difference!** 5 | 6 | ## 📥 Install & Upgrade 7 | 8 | ```bash 9 | bash <(curl -Ls https://raw.githubusercontent.com/dev-ir/xui-assistant/master/installer.sh) 10 | ``` 11 | 12 | ## 🚀 Features 13 | 14 | ### 🔹 User & Admin Management 15 | - **Admin management** for better control 16 | - **User management bot** for traffic and date-based controls 17 | - **Gift flow/time allocation** to all users 18 | 19 | ### 🔹 System & Security Management 20 | - **Transfer database to another server** for seamless migration 21 | - **Schedule Xray service restart** for maintenance 22 | - **Fix WhatsApp date/time issues** for better synchronization 23 | - **Block speed test websites** to prevent misuse 24 | 25 | ### 🔹 Advanced Features & Add-ons 26 | - **Install WordPress alongside X-UI** for extended functionalities 27 | - **Install more X-UI panels** to expand capabilities 28 | - **Add subscription templates** for easier management 29 | 30 | ### 🔹 Script & Program Management 31 | - **Uninstall this script** if needed 32 | - **Exit the program** safely 33 | 34 | ## 🖥️ Supported Operating Systems 35 | - **Ubuntu 20+** (Recommended for best compatibility) 36 | 37 | ## 🌍 Supported Languages 38 | - English 39 | - [🇮🇷 فارسی (Persian)](readme.fa.md) 40 | 41 | ## 🖼️ Preview 42 |

43 | XUI Assistant Preview 44 |

45 | 46 | ## 🙏 Support with Crypto 47 | **We don't need financial support, a simple Star (⭐) is enough. Thank you!** 48 | 49 | - **USDT (TRC20):** `TVUqVMoCEe5DVUoxmPg8MwmgcHvZLqLjr4` 50 | 51 | ## 📢 Join Our Telegram Channel 52 | 📌 [Telegram Channel](https://t.me/+EpErnDsDPhw3ZThk) 53 | 54 | --------------------------------------------------------------------------------