Download main.py from rtian001/flask: direct link, hf CLI and curl.
- Browser
- Download file 18.1 kB
-
https://huggingface.co/spaces/rtian001/flask/resolve/main/main.py
- Command line
-
hf download hf://spaces/rtian001/flask/main.py
-
curl -L -o main.py https://huggingface.co/spaces/rtian001/flask/resolve/main/main.py
18.1 kB
| import os | |
| import re | |
| import json | |
| import time | |
| import base64 | |
| import shutil | |
| import asyncio | |
| import requests | |
| import subprocess | |
| import threading | |
| from threading import Thread | |
| # WEB站点 | |
| WEB_ARGO_DOMAIN=os.environ.get('WEB_DOMAIN','') | |
| WEB_ARGO_AUTH = os.environ.get('WEB_ARGO_AUTH', '') | |
| # Environment variables | |
| FILE_PATH = os.environ.get('FILE_PATH', './.cache') # 运行路径,sub.txt保存路径 | |
| SUB_PATH = os.environ.get('SUB_PATH', 'getmysubs') # 订阅token,默认sub,例如:https://www.google.com/sub | |
| UUID = os.environ.get('UUID', 'b0cc09a7-06f0-42fb-a161-17434162ebdf') # UUID,如使用哪吒v1,在不同的平台部署需要修改,否则会覆盖 | |
| NEZHA_SERVER = os.environ.get('NEZHA_SERVER', '') # 哪吒面板域名或ip, v1格式: nezha.xxx.com:8008, v0格式: nezha.xxx.com | |
| NEZHA_PORT = os.environ.get('NEZHA_PORT', '') # v1哪吒请留空, v0哪吒的agent通信端口,自动匹配tls | |
| NEZHA_KEY = os.environ.get('NEZHA_KEY', '') # v1哪吒的NZ_CLIENT_SECRET或v0哪吒agent密钥 | |
| ARGO_DOMAIN = os.environ.get('ARGO_DOMAIN', '') # Argo固定隧道域名,留空即使用临时隧道 | |
| ARGO_AUTH = os.environ.get('ARGO_AUTH', '') # Argo固定隧道密钥,留空即使用临时隧道 | |
| ARGO_PORT = int(os.environ.get('ARGO_PORT', '8001')) # Argo端口,使用固定隧道token需在cloudflare后台设置端口和这里一致 | |
| CFIP = os.environ.get('CFIP', 'www.visa.com.tw') # 优选ip或优选域名 | |
| CFPORT = int(os.environ.get('CFPORT', '443')) # 优选ip或优选域名对应端口 | |
| NAME = os.environ.get('NAME', 'dbs-rtian1') # 节点名称 | |
| PORT = int(os.environ.get('SERVER_PORT') or os.environ.get('PORT') or 3000) # 订阅端口,如无法订阅,请手动修改为分配的端口 | |
| # Execute shell command and return output | |
| def exec_cmd(command): | |
| try: | |
| process = subprocess.Popen( | |
| command, | |
| shell=True, | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.PIPE, | |
| text=True | |
| ) | |
| stdout, stderr = process.communicate() | |
| return stdout.strip() | |
| except Exception as e: | |
| print(f"Error executing command: {e}") | |
| return null | |
| # Create running folder | |
| def create_directory(): | |
| if not os.path.exists(FILE_PATH): | |
| os.makedirs(FILE_PATH) | |
| # print(f"{FILE_PATH} is created") | |
| # else: | |
| # print(f"{FILE_PATH} already exists") | |
| # Global variables | |
| npm_path = os.path.join(FILE_PATH, 'npm') | |
| php_path = os.path.join(FILE_PATH, 'php') | |
| crawl_path = os.path.join(FILE_PATH, 'crawl') | |
| bot_path = os.path.join(FILE_PATH, 'bot') | |
| sub_path = os.path.join(FILE_PATH, 'sub.txt') | |
| list_path = os.path.join(FILE_PATH, 'list.txt') | |
| boot_log_path = os.path.join(FILE_PATH, 'boot.log') | |
| config_path = os.path.join(FILE_PATH, 'config.json') | |
| # Delete nodes | |
| def delete_nodes(): | |
| try: | |
| if not os.path.exists(sub_path): | |
| return | |
| try: | |
| with open(sub_path, 'r') as file: | |
| file_content = file.read() | |
| except: | |
| return None | |
| decoded = base64.b64decode(file_content).decode('utf-8') | |
| nodes = [line for line in decoded.split('\n') if any(protocol in line for protocol in ['vless://', 'vmess://', 'trojan://', 'hysteria2://', 'tuic://'])] | |
| if not nodes: | |
| return | |
| except Exception as e: | |
| print(f"Error in delete_nodes: {e}") | |
| return None | |
| # Clean up old files | |
| def cleanup_old_files(): | |
| paths_to_delete = ['crawl', 'bot', 'npm', 'php', 'boot.log', 'list.txt'] | |
| for file in paths_to_delete: | |
| file_path = os.path.join(FILE_PATH, file) | |
| try: | |
| if os.path.exists(file_path): | |
| if os.path.isdir(file_path): | |
| shutil.rmtree(file_path) | |
| else: | |
| os.remove(file_path) | |
| except Exception as e: | |
| print(f"Error removing {file_path}: {e}") | |
| # Determine system architecture | |
| def get_system_architecture(): | |
| # architecture = platform.machine().lower() | |
| architecture = exec_cmd("uname -m").lower() | |
| if 'arm' in architecture or 'aarch64' in architecture: | |
| return 'arm' | |
| else: | |
| return 'amd' | |
| # Download file based on architecture | |
| def download_file(file_name, file_url): | |
| file_path = os.path.join(FILE_PATH, file_name) | |
| try: | |
| response = requests.get(file_url, stream=True) | |
| response.raise_for_status() | |
| with open(file_path, 'wb') as f: | |
| for chunk in response.iter_content(chunk_size=8192): | |
| f.write(chunk) | |
| print(f"Download {file_name} successfully") | |
| return True | |
| except Exception as e: | |
| if os.path.exists(file_path): | |
| os.remove(file_path) | |
| print(f"Download {file_name} failed: {e}") | |
| return False | |
| # Get files for architecture | |
| def get_files_for_architecture(architecture): | |
| if architecture == 'arm': | |
| base_files = [ | |
| {"fileName": "crawl", "fileUrl": "https://arm64.ssss.nyc.mn/web"}, | |
| {"fileName": "bot", "fileUrl": "https://arm64.ssss.nyc.mn/2go"} | |
| ] | |
| else: | |
| base_files = [ | |
| {"fileName": "crawl", "fileUrl": "https://amd64.ssss.nyc.mn/web"}, | |
| {"fileName": "bot", "fileUrl": "https://amd64.ssss.nyc.mn/2go"} | |
| ] | |
| if NEZHA_SERVER and NEZHA_KEY: | |
| if NEZHA_PORT: | |
| npm_url = "https://arm64.ssss.nyc.mn/agent" if architecture == 'arm' else "https://amd64.ssss.nyc.mn/agent" | |
| base_files.insert(0, {"fileName": "npm", "fileUrl": npm_url}) | |
| else: | |
| php_url = "https://arm64.ssss.nyc.mn/v1" if architecture == 'arm' else "https://amd64.ssss.nyc.mn/v1" | |
| base_files.insert(0, {"fileName": "php", "fileUrl": php_url}) | |
| return base_files | |
| # Authorize files with execute permission | |
| def authorize_files(file_paths): | |
| for relative_file_path in file_paths: | |
| absolute_file_path = os.path.join(FILE_PATH, relative_file_path) | |
| if os.path.exists(absolute_file_path): | |
| try: | |
| os.chmod(absolute_file_path, 0o775) | |
| print(f"Empowerment success for {absolute_file_path}: 775") | |
| except Exception as e: | |
| print(f"Empowerment failed for {absolute_file_path}: {e}") | |
| # Configure Argo tunnel | |
| def argo_type(): | |
| if not ARGO_AUTH or not ARGO_DOMAIN: | |
| # print("ARGO_DOMAIN or ARGO_AUTH variable is empty, use quick tunnels") | |
| return | |
| if "TunnelSecret" in ARGO_AUTH: | |
| with open(os.path.join(FILE_PATH, 'tunnel.json'), 'w') as f: | |
| f.write(ARGO_AUTH) | |
| tunnel_id = ARGO_AUTH.split('"')[11] | |
| tunnel_yml = f""" | |
| tunnel: {tunnel_id} | |
| credentials-file: {os.path.join(FILE_PATH, 'tunnel.json')} | |
| protocol: http2 | |
| ingress: | |
| - hostname: {ARGO_DOMAIN} | |
| service: http://localhost:{ARGO_PORT} | |
| originRequest: | |
| noTLSVerify: true | |
| - service: http_status:404 | |
| """ | |
| with open(os.path.join(FILE_PATH, 'tunnel.yml'), 'w') as f: | |
| f.write(tunnel_yml) | |
| else: | |
| # print("Use token connect to tunnel,please set the {ARGO_PORT} in cloudflare") | |
| return | |
| # Download and run necessary files | |
| async def download_files_and_run(): | |
| global private_key, public_key | |
| architecture = get_system_architecture() | |
| files_to_download = get_files_for_architecture(architecture) | |
| if not files_to_download: | |
| print("Can't find a file for the current architecture") | |
| return | |
| # Download all files | |
| download_success = True | |
| for file_info in files_to_download: | |
| if not download_file(file_info["fileName"], file_info["fileUrl"]): | |
| download_success = False | |
| if not download_success: | |
| print("Error downloading files") | |
| return | |
| # Authorize files | |
| files_to_authorize = ['npm', 'crawl', 'bot'] if NEZHA_PORT else ['php', 'crawl', 'bot'] | |
| authorize_files(files_to_authorize) | |
| # Check TLS | |
| port = NEZHA_SERVER.split(":")[-1] if ":" in NEZHA_SERVER else "" | |
| if port in ["443", "8443", "2096", "2087", "2083", "2053"]: | |
| nezha_tls = "true" | |
| else: | |
| nezha_tls = "false" | |
| # Configure nezha | |
| if NEZHA_SERVER and NEZHA_KEY: | |
| if not NEZHA_PORT: | |
| # Generate config.yaml for v1 | |
| config_yaml = f""" | |
| client_secret: {NEZHA_KEY} | |
| debug: false | |
| disable_auto_update: true | |
| disable_command_execute: false | |
| disable_force_update: true | |
| disable_nat: false | |
| disable_send_query: false | |
| gpu: false | |
| insecure_tls: false | |
| ip_report_period: 1800 | |
| report_delay: 4 | |
| server: {NEZHA_SERVER} | |
| skip_connection_count: false | |
| skip_procs_count: false | |
| temperature: false | |
| tls: {nezha_tls} | |
| use_gitee_to_upgrade: false | |
| use_ipv6_country_code: false | |
| uuid: {UUID}""" | |
| with open(os.path.join(FILE_PATH, 'config.yaml'), 'w') as f: | |
| f.write(config_yaml) | |
| # Generate configuration file | |
| config ={"log":{"access":"/dev/null","error":"/dev/null","loglevel":"none",},"inbounds":[{"port":ARGO_PORT ,"protocol":"vless","settings":{"clients":[{"id":UUID ,"flow":"xtls-rprx-vision",},],"decryption":"none","fallbacks":[{"dest":3001 },{"path":"/vless-argo","dest":3002 },{"path":"/vmess-argo","dest":3003 },{"path":"/trojan-argo","dest":3004 },],},"streamSettings":{"network":"tcp",},},{"port":3001 ,"listen":"127.0.0.1","protocol":"vless","settings":{"clients":[{"id":UUID },],"decryption":"none"},"streamSettings":{"network":"ws","security":"none"}},{"port":3002 ,"listen":"127.0.0.1","protocol":"vless","settings":{"clients":[{"id":UUID ,"level":0 }],"decryption":"none"},"streamSettings":{"network":"ws","security":"none","wsSettings":{"path":"/vless-argo"}},"sniffing":{"enabled":True ,"destOverride":["http","tls","quic"],"metadataOnly":False }},{"port":3003 ,"listen":"127.0.0.1","protocol":"vmess","settings":{"clients":[{"id":UUID ,"alterId":0 }]},"streamSettings":{"network":"ws","wsSettings":{"path":"/vmess-argo"}},"sniffing":{"enabled":True ,"destOverride":["http","tls","quic"],"metadataOnly":False }},{"port":3004 ,"listen":"127.0.0.1","protocol":"trojan","settings":{"clients":[{"password":UUID },]},"streamSettings":{"network":"ws","security":"none","wsSettings":{"path":"/trojan-argo"}},"sniffing":{"enabled":True ,"destOverride":["http","tls","quic"],"metadataOnly":False }},],"outbounds":[{"protocol":"freedom","tag": "direct" },{"protocol":"blackhole","tag":"block"}]} | |
| with open(os.path.join(FILE_PATH, 'config.json'), 'w', encoding='utf-8') as config_file: | |
| json.dump(config, config_file, ensure_ascii=False, indent=2) | |
| # Run nezha | |
| if NEZHA_SERVER and NEZHA_PORT and NEZHA_KEY: | |
| tls_ports = ['443', '8443', '2096', '2087', '2083', '2053'] | |
| nezha_tls = '--tls' if NEZHA_PORT in tls_ports else '' | |
| command = f"nohup {os.path.join(FILE_PATH, 'npm')} -s {NEZHA_SERVER}:{NEZHA_PORT} -p {NEZHA_KEY} {nezha_tls} >/dev/null 2>&1 &" | |
| try: | |
| exec_cmd(command) | |
| print('npm is running') | |
| time.sleep(1) | |
| except Exception as e: | |
| print(f"npm running error: {e}") | |
| elif NEZHA_SERVER and NEZHA_KEY: | |
| # Run V1 | |
| command = f"nohup {FILE_PATH}/php -c \"{FILE_PATH}/config.yaml\" >/dev/null 2>&1 &" | |
| try: | |
| exec_cmd(command) | |
| print('php is running') | |
| time.sleep(1) | |
| except Exception as e: | |
| print(f"php running error: {e}") | |
| else: | |
| print('NEZHA variable is empty, skipping running') | |
| # Run sbX | |
| command = f"nohup {os.path.join(FILE_PATH, 'crawl')} -c {os.path.join(FILE_PATH, 'config.json')} >/dev/null 2>&1 &" | |
| try: | |
| # 首次启动不开启sbx | |
| # exec_cmd(command) | |
| print('crawl is running') | |
| time.sleep(1) | |
| except Exception as e: | |
| print(f"crawl running error: {e}") | |
| # Run cloudflared | |
| if os.path.exists(os.path.join(FILE_PATH, 'bot')): | |
| if re.match(r'^[A-Z0-9a-z=]{120,250}$', ARGO_AUTH): | |
| args = f"tunnel --edge-ip-version auto --no-autoupdate --protocol http2 run --token {ARGO_AUTH}" | |
| elif "TunnelSecret" in ARGO_AUTH: | |
| args = f"tunnel --edge-ip-version auto --config {os.path.join(FILE_PATH, 'tunnel.yml')} run" | |
| else: | |
| args = f"tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile {os.path.join(FILE_PATH, 'boot.log')} --loglevel info --url http://localhost:{ARGO_PORT}" | |
| if WEB_ARGO_DOMAIN and WEB_ARGO_AUTH: | |
| web_args=f"tunnel --edge-ip-version auto --no-autoupdate --protocol http2 run --token {WEB_ARGO_AUTH}" | |
| exec_cmd(f"nohup {os.path.join(FILE_PATH, 'bot')} {web_args} >/dev/null 2>&1 &") | |
| print('web_bot is running') | |
| time.sleep(3) | |
| try: | |
| exec_cmd(f"nohup {os.path.join(FILE_PATH, 'bot')} {args} >/dev/null 2>&1 &") | |
| print('bot is running') | |
| time.sleep(2) | |
| except Exception as e: | |
| print(f"Error executing command: {e}") | |
| time.sleep(5) | |
| # Extract domains and generate sub.txt | |
| await extract_domains() | |
| # Extract domains from cloudflared logs | |
| async def extract_domains(): | |
| argo_domain = None | |
| if ARGO_AUTH and ARGO_DOMAIN: | |
| argo_domain = ARGO_DOMAIN | |
| print(f'ARGO_DOMAIN: {argo_domain}') | |
| await generate_links(argo_domain) | |
| else: | |
| try: | |
| with open(boot_log_path, 'r') as f: | |
| file_content = f.read() | |
| lines = file_content.split('\n') | |
| argo_domains = [] | |
| for line in lines: | |
| domain_match = re.search(r'https?://([^ ]*trycloudflare\.com)/?', line) | |
| if domain_match: | |
| domain = domain_match.group(1) | |
| argo_domains.append(domain) | |
| if argo_domains: | |
| argo_domain = argo_domains[0] | |
| print(f'ArgoDomain: {argo_domain}') | |
| await generate_links(argo_domain) | |
| else: | |
| print('ArgoDomain not found, re-running bot to obtain ArgoDomain') | |
| # Remove boot.log and restart bot | |
| if os.path.exists(boot_log_path): | |
| os.remove(boot_log_path) | |
| try: | |
| exec_cmd('pkill -f "[b]ot" > /dev/null 2>&1') | |
| except: | |
| pass | |
| time.sleep(1) | |
| args = f'tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile {FILE_PATH}/boot.log --loglevel info --url http://localhost:{ARGO_PORT}' | |
| exec_cmd(f'nohup {os.path.join(FILE_PATH, "bot")} {args} >/dev/null 2>&1 &') | |
| print('bot is running.') | |
| time.sleep(6) # Wait 6 seconds | |
| await extract_domains() # Try again | |
| except Exception as e: | |
| print(f'Error reading boot.log: {e}') | |
| # Generate links and subscription content | |
| async def generate_links(argo_domain): | |
| meta_info = exec_cmd('curl -s https://speed.cloudflare.com/meta') | |
| meta_info = meta_info.split('"') | |
| ISP = f"【{meta_info[25]}】" | |
| time.sleep(2) | |
| VMESS = {"v": "2", "ps": f"{NAME}-{ISP}-1", "add": CFIP, "port": CFPORT, "id": UUID, "aid": "0", "scy": "none", "net": "ws", "type": "none", "host": argo_domain, "path": "/vmess-argo?ed=2560", "tls": "tls", "sni": argo_domain, "alpn": "", "fp": "chrome"} | |
| list_txt = f""" | |
| vmess://{ base64.b64encode(json.dumps(VMESS).encode('utf-8')).decode('utf-8')} | |
| vless://{UUID}@{CFIP}:{CFPORT}?encryption=none&security=tls&sni={argo_domain}&fp=chrome&type=ws&host={argo_domain}&path=%2Fvless-argo%3Fed%3D2560#{NAME}-{ISP}-2 | |
| trojan://{UUID}@{CFIP}:{CFPORT}?security=tls&sni={argo_domain}&fp=chrome&type=ws&host={argo_domain}&path=%2Ftrojan-argo%3Fed%3D2560#{NAME}-{ISP}-3 | |
| """ | |
| with open(os.path.join(FILE_PATH, 'list.txt'), 'w', encoding='utf-8') as list_file: | |
| list_file.write(list_txt) | |
| sub_txt = base64.b64encode(list_txt.encode('utf-8')).decode('utf-8') | |
| with open(os.path.join(FILE_PATH, 'sub.txt'), 'w', encoding='utf-8') as sub_file: | |
| sub_file.write(sub_txt) | |
| print(f"{FILE_PATH}/sub.txt saved successfully") | |
| return sub_txt | |
| # Clean up files after 90 seconds | |
| def clean_files(): | |
| def _cleanup(): | |
| time.sleep(90) # Wait 90 seconds | |
| files_to_delete = [boot_log_path, config_path, list_path, crawl_path, bot_path, php_path, npm_path] | |
| for file in files_to_delete: | |
| try: | |
| if os.path.exists(file): | |
| if os.path.isdir(file): | |
| shutil.rmtree(file) | |
| else: | |
| os.remove(file) | |
| except: | |
| pass | |
| print('App is running') | |
| print('Thank you for using this script, enjoy!') | |
| threading.Thread(target=_cleanup, daemon=True).start() | |
| # Main function to start the server | |
| async def start_sbx(): | |
| if os.path.exists(crawl_path): | |
| command = f"nohup {os.path.join(FILE_PATH, 'crawl')} -c {os.path.join(FILE_PATH, 'config.json')} >/dev/null 2>&1 &" | |
| exec_cmd(command) | |
| else: | |
| # delete_nodes() | |
| # cleanup_old_files() | |
| create_directory() | |
| argo_type() | |
| await download_files_and_run() | |
| # clean_files() | |
| def run_start(): | |
| crawl_loop = asyncio.new_event_loop() | |
| asyncio.set_event_loop(crawl_loop) | |
| crawl_loop.run_until_complete(start_sbx()) | |
| crawl_loop.close() | |
| def run_stop(): | |
| exec_cmd('pkill -f crawl > /dev/null 2>&1') | |
| def get_links(): | |
| running=exec_cmd('ps -ef|grep cache/crawl |grep -v grep') | |
| if running: | |
| status='running' | |
| else: | |
| status='stopped' | |
| if os.path.exists(sub_path): | |
| with open(sub_path, 'r', encoding='utf-8') as sub_file: | |
| sub_txt = sub_file.read() | |
| return json.dumps({"status":status,"data":sub_txt,"running":running}).encode('utf-8') | |
| else: | |
| return json.dumps({"status":status,"data":None,"running":running}).encode('utf-8') | |
| if __name__ == "__main__": | |
| run_start() | |