├── LICENSE ├── README-fa.md ├── README.md ├── backup.py ├── host.py ├── main.py ├── pingtester.py ├── requirements.txt └── update.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Cuf 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-fa.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | 7 |

8 | 9 |

خوش اومدید به اسکریپت وی سی جی

10 | 11 |

12 | 13 | English 14 | 15 | / 16 | 17 | فارسی 18 | 19 | 20 |

21 | 22 |

23 | Easy To Generat With V2Ray Config Generator Easy Install With Few Clicks 24 |

25 | 26 |

This Python script downloads free V2Ray configs , which are updated everyday and include
( Vmess & Vless & Trojan & ShadowSocks & ShadowSocksR )

27 |

اینترنت برای همه ؛ یا هیچ‌کس!

28 |
29 | 30 | 31 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/RealCuf/VCG-Script?color=white&style=for-the-badge) 32 | ![GitHub](https://img.shields.io/github/license/RealCuf/VCG-Script?color=white&style=for-the-badge) 33 | 34 |
35 | 36 |
37 |
38 | screenshot 39 |
40 |
41 | 42 |
43 | 44 | # معرفی 45 | 46 | **اسکریپت وی سی جی پروژه ایی هست که از چندین URL سابسکرایبشن مختلف ، کانفیگ هایی را دریافت میکند و برای شما تعدادی کانفیگ تصادفی که نوع آن را از قبل مشخص کرده اید نمایش میدهد و شما میتونید آن‌ کانفیگ را در یک فایل ذخیره یا QR کد برای آن‌ ها بسازید.** 47 | 48 | **اگر فکر می کنید این پروژه برای شما مفید است ، ممنون میشم یک ستاره بدهید** :star2: 49 | 50 | **برای من قهوه بخر :** 51 | 52 | - Tron USDT (TRC20) : `TDZccmYTC8AwK5vxwgbc9qPQ4VZHMkFgY4` 53 | 54 | ### کانال تلگرام : [VCG Script](https://t.me/VCGScript) 55 | 56 |
57 | 58 | # امکانات 59 | 60 | - پشتیبانی از vless - vmess - trojan - ss - ssr 61 | - پشتیبانی از for - xtls - tls - reality - Grpc - ws - tcp 62 | - اعمال محدودیت در تعداد ساخت کانفیگ 63 | - امکان ذخیره کانفیگ ها و ساخت QR Code 64 | - تغییر لینک سابسکرایبشن به لینک دلخواه شما 65 | - تست پینگ از کانفیگ ها 66 | - متن باز و قابل ویرایش 67 | - چک کردن ریالیتی در ساب ها 68 | - پشتیبان گیری از x-ui 69 | - اپلود فایل ها در هاست 70 | 71 |
72 | 73 | # کلون و نصب اسکریپت 74 | 75 | نصب داشتن Python , Git 76 | 77 | ``` 78 | git clone https://github.com/RealCuf/VCG-Script.git 79 | cd VCG-Script 80 | pip install -r requirements.txt 81 | python main.py 82 | ``` 83 | > در C:\Users\System.name میتونید به سورس کد دسترسی داشته باشید 84 | 85 |
86 | 87 | # آشنایی با محیط 88 | 89 | جدول زیر رو مطالعه کنید! 90 | میتونید برای ساخت کانفیگ ها از دستور مورد نظر و در قسمت OPTIONS از توضیحات جدول / اسکریپت استفاده کنید 91 | 92 | |Number of configs|Vmess configs only|Vless configs only|Trojan configs only|Save configs to a file|Save QR codes|Reality Checker|Pingtester|x-ui Backup|Upload File 93 | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| 94 | |-n| -v| -l| -t| -s| -q| -e| -p| -b| -o| 95 | 96 | مثال : 97 | 98 | ```` 99 | python main.py -n 10 -t -s -q 100 | ```` 101 | > معنی دستور : 10 عدد کانفیگ تروجان به همراه ذخیره کانفیگ ها + ساخت QR Code 102 | 103 |
104 | 105 | ## تمام دستورات 106 | 107 |
108 | برای جزئیات دستورات کلیک کنید 109 | 110 |
111 | 112 | استفاده : `python main.py [Options]` 113 | 114 | | Command | Alternative command | Action | 115 | | :----: | ---------------------------------- | -------------------------------- | 116 | | `-n` | `--number` | Number of Configs - Default : 5 | 117 | | `-v` | `--vmess` | Vmess Configs only | 118 | | `-l` | `--vless` | Vless Configs only | 119 | | `-t` | `--trojan` | Trojan Configs only | 120 | | `-h` | `--shadowsocks` | ShadowSocks Configs only | 121 | | `-a` | `--shadowsocksr` | ShadowSocksR Configs only | 122 | | `-r` | `--reality` | Reality Checker | 123 | | `-s` | `--save` | Save Configs | 124 | | `-q` | `--qr` | Save QR codes | 125 | | `-b` | `--backup` | x-ui Backup | 126 | | `-p` | `--ping` | Pingtester | 127 | | `-o` | `--host` | Upload File to Host | 128 | | `-u` | `--update` | Update Script | 129 | 130 |
131 | 132 |
133 | 134 | ## چک کردن ریالیتی 135 | 136 |
137 | برای جزئیات ریالیتی کلیک کنید 138 | 139 |
140 | 141 | - میتوانید با افزودن یک دستور -r یا - -Reality ، کانفیگ هایی را که ریالیتی دارند ، استخراج کنید. 142 | ``` 143 | python main.py -n 10 -l -r -s -q 144 | ``` 145 | > معنی دستور : 10 عدد کانفیگ وی لس به همراه ذخیره کانفیگ ها + ساخت QR Code + ریالیتی 146 | 147 |
148 | 149 |
150 | 151 |
152 | 153 | ## تست پینگ 154 | 155 |
156 | برای جزئیات پینگ کلیک کنید 157 | 158 |
159 | 160 | - برای پینگ یک فایل txt که شامل تعدادی کانفیگ است ، از دستور زیر استفاده کنید 161 | ``` 162 | python main.py -p 163 | ``` 164 | - سپس روی File Select کلیک کنید و در پوشه Conf ، فایل txt مورد نظر خود را انتخاب کنید 165 | 166 |
167 | 168 | VCG 169 | 170 |
171 | 172 |
173 | 174 | ## آپدیت اسکریپت 175 | 176 |
177 | برای جزئیات آپدیت کلیک کنید 178 | 179 |
180 | 181 | ``` 182 | python main.py -u 183 | ``` 184 | > قبل از بروزرسانی از پوشه های Database و QR Backup و QR بک آپ بگیرید 185 | 186 |
187 | 188 |
189 | 190 | ## بک اپ X-ui 191 | 192 |
193 | برای جزئیات X-ui کلیک کنید 194 | 195 |
196 | 197 | - برای تهیه نسخه پشتیبان از پنل از دستور زیر استفاده کنید 198 | ``` 199 | python main.py -b 200 | ``` 201 | - در بخش داده ها ، اطلاعات سرور خود را بنویسید 202 | > آیپی , پورت , یوزرنیم , پسورد , مسیر فایل 203 | 204 |
205 | 206 |
207 | 208 |
209 | 210 | ## ویرایش کد 211 | 212 |
213 | برای جزئیات ویرایش کلیک کنید 214 | 215 |
216 | 217 | - در بخش های DECODED_URLS , ENCODED_URLS میتونید لینک سابسکرایبشن دلخواه خودتون رو قرار بدید! 218 | 219 | ```python 220 | # URLs for configs not encoded in a base64 string 221 | DECODED_URLS = [ 222 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt", 223 | "https://raw.githubusercontent.com/awesome-vpn/awesome-vpn/master/all", 224 | "https://raw.githubusercontent.com/freefq/free/master/v2", 225 | "https://raw.fastgit.org/ripaojiedian/freenode/main/sub", 226 | ] 227 | 228 | # URLs for configs encoded in a base64 string 229 | ENCODED_URLS = [ 230 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vmess.txt", 231 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vless.txt", 232 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/trojan.txt", 233 | ] 234 | ``` 235 | 236 |
237 | 238 |
239 | 240 | # کتابخانه های استفاده شده در پروژه 241 | 242 | - Base64 - Datetime - OS - Random - Subprocess - Sys 243 | - Qrcode - Requests - Rich - Argparse - Time - Git 244 | - Tkinter - Ping3 - Threading - Pyperclip - Pysftp 245 | - PySimpleGUI - Ftplib - Webbrowser - Shutil 246 | 247 |
248 | 249 | # ارتباط با من 250 | ### حتماً به کانال بپیوندید و از من حمایت کنید 251 | 252 | 😶‍🌫️ Twitter : [CybrDriver](https://twitter.com/CybrDriver) - 253 | Channel : [Telegram](https://t.me/VCGScript) 254 | 255 | ![myImage](https://media.giphy.com/media/XRB1uf2F9bGOA/giphy.gif) 256 | 257 |
258 | 259 | # Stargazers over time 260 | 261 | [![Stargazers over time](https://starchart.cc/RealCuf/VCG-Script.svg)](https://starchart.cc/RealCuf/VCG-Script) 262 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | 7 |

8 | 9 |

Welcome to VCG Script

10 | 11 |

12 | 13 | English 14 | 15 | / 16 | 17 | فارسی 18 | 19 | 20 |

21 | 22 |

23 | Easy To Generat With V2Ray Config Generator Easy Install With Few Clicks 24 |

25 | 26 |

This Python script downloads free V2Ray configs , which are updated everyday and include
( Vmess & Vless & Trojan & ShadowSocks & ShadowSocksR )

27 |

اینترنت برای همه ؛ یا هیچ‌کس!

28 |
29 | 30 | 31 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/RealCuf/VCG-Script?color=white&style=for-the-badge) 32 | ![GitHub](https://img.shields.io/github/license/RealCuf/VCG-Script?color=white&style=for-the-badge) 33 | 34 |
35 | 36 |
37 |
38 | screenshot 39 |
40 |
41 | 42 |
43 | 44 | # Introduction 45 | 46 | **The VCG script is a project that receives the config from several different share URLs and displays some random config whose profile you specified earlier, and you can save that configuration in a file or create a QR code for them.** 47 | 48 | **If you think this project is helpful to you, you may wish to give a** :star2: 49 | 50 | **Buy Me a Coffee :** 51 | 52 | - Tron USDT (TRC20) : `TDZccmYTC8AwK5vxwgbc9qPQ4VZHMkFgY4` 53 | 54 | ### Telegram Channel : [VCG Script](https://t.me/VCGScript) 55 | 56 |
57 | 58 | # Features 59 | 60 | - Support vless - vmess - trojan - ss - ssr 61 | - Support for - xtls - tls - reality - Grpc - ws - tcp 62 | - Apply limits in the number of config 63 | - Save Configs & QR Code 64 | - Change the subs link 65 | - Pingtester 66 | - Open Source 67 | - Reality Checker 68 | - x-ui Backup 69 | - Upload File to Host 70 | 71 |
72 | 73 | # Clone and Install Script 74 | 75 | Installing Python , Git 76 | 77 | ``` 78 | git clone https://github.com/RealCuf/VCG-Script.git 79 | cd VCG-Script 80 | pip install -r requirements.txt 81 | python main.py 82 | ``` 83 | > In C:\Users\System.name you can access the Source Code 84 | 85 |
86 | 87 | # Familiarity with the environment 88 | 89 | Read the table below! 90 | You can use the desired command to create configs and in the OPTIONS section of the table / script description 91 | 92 | |Number of configs|Vmess configs only|Vless configs only|Trojan configs only|Save configs to a file|Save QR codes|Reality Checker|Pingtester|x-ui Backup|Upload File 93 | |:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| 94 | |-n| -v| -l| -t| -s| -q| -e| -p| -b| -o| 95 | 96 | Example : 97 | 98 | ```` 99 | python main.py -n 10 -t -s -q 100 | ```` 101 | > Command Meaning : 10 Trojan Configs with Config Save + QR Code Creation 102 | 103 |
104 | 105 | ## All Command 106 | 107 |
108 | Click for Command details 109 | 110 |
111 | 112 | Usage : `python main.py [Options]` 113 | 114 | | Command | Alternative command | Action | 115 | | :----: | ---------------------------------- | -------------------------------- | 116 | | `-n` | `--number` | Number of Configs - Default : 5 | 117 | | `-v` | `--vmess` | Vmess Configs only | 118 | | `-l` | `--vless` | Vless Configs only | 119 | | `-t` | `--trojan` | Trojan Configs only | 120 | | `-h` | `--shadowsocks` | ShadowSocks Configs only | 121 | | `-a` | `--shadowsocksr` | ShadowSocksR Configs only | 122 | | `-r` | `--reality` | Reality Checker | 123 | | `-s` | `--save` | Save Configs | 124 | | `-q` | `--qr` | Save QR codes | 125 | | `-b` | `--backup` | x-ui Backup | 126 | | `-p` | `--ping` | Pingtester | 127 | | `-o` | `--host` | Upload File to Host | 128 | | `-u` | `--update` | Update Script | 129 | 130 |
131 | 132 |
133 | 134 | ## Reality Checker 135 | 136 |
137 | Click for Reality details 138 | 139 |
140 | 141 | - You can extract the config that has a Reality by adding a -r or --reality command. 142 | ``` 143 | python main.py -n 10 -l -r -s -q 144 | ``` 145 | > Command Meaning : 10 vless Configs with Config Save + QR Code Creation + Reality 146 | 147 |
148 | 149 |
150 | 151 |
152 | 153 | ## Ping Tester 154 | 155 |
156 | Click for Pingtester details 157 | 158 |
159 | 160 | - To ping a txt file that contains a number of config, use the following command 161 | ``` 162 | python main.py -p 163 | ``` 164 | - Then tap Select File and in the conf folder, select the txt file you want 165 | 166 |
167 | 168 | VCG 169 | 170 |
171 | 172 |
173 | 174 | ## Update Script 175 | 176 |
177 | Click for Update details 178 | 179 |
180 | 181 | ``` 182 | python main.py -u 183 | ``` 184 | > Backup conf and qr and database folders before updating 185 | 186 |
187 | 188 |
189 | 190 | ## X-ui Backup 191 | 192 |
193 | Click for XuiBackup details 194 | 195 |
196 | 197 | - Use the following command to back up the panel 198 | ``` 199 | python main.py -b 200 | ``` 201 | - In the data section, write your server information 202 | > ip , port , user , password , remote_path 203 | 204 |
205 | 206 |
207 | 208 |
209 | 210 | ## Edit Source 211 | 212 |
213 | Click for Edit details 214 | 215 |
216 | 217 | - In the DECODED_URLS sections, ENCODED_URLS you can choose your favorite Subscribtion link! 218 | 219 | ```python 220 | # URLs for configs not encoded in a base64 string 221 | DECODED_URLS = [ 222 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt", 223 | "https://raw.githubusercontent.com/awesome-vpn/awesome-vpn/master/all", 224 | "https://raw.githubusercontent.com/freefq/free/master/v2", 225 | "https://raw.fastgit.org/ripaojiedian/freenode/main/sub", 226 | ] 227 | 228 | # URLs for configs encoded in a base64 string 229 | ENCODED_URLS = [ 230 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vmess.txt", 231 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vless.txt", 232 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/trojan.txt", 233 | ] 234 | ``` 235 | 236 |
237 | 238 |
239 | 240 | # Libraries used in the project 241 | 242 | - Base64 - Datetime - OS - Random - Subprocess - Sys 243 | - Qrcode - Requests - Rich - Argparse - Time - Git 244 | - Tkinter - Ping3 - Threading - Pyperclip - Pysftp 245 | - PySimpleGUI - Ftplib - Webbrowser - Shutil 246 | 247 |
248 | 249 | # Contact Developer 250 | ### Be sure to join the channel and support us 251 | 252 | 😶‍🌫️ Twitter : [CybrDriver](https://twitter.com/CybrDriver) - 253 | Channel : [Telegram](https://t.me/VCGScript) 254 | 255 | ![myImage](https://media.giphy.com/media/XRB1uf2F9bGOA/giphy.gif) 256 | 257 |
258 | 259 | # Stargazers over time 260 | ![GitHub View](https://views.whatilearened.today/views/github/RealCuf/VCG-Script.svg) 261 | [![Stargazers over time](https://starchart.cc/RealCuf/VCG-Script.svg)](https://starchart.cc/RealCuf/VCG-Script) 262 | -------------------------------------------------------------------------------- /backup.py: -------------------------------------------------------------------------------- 1 | # GitHub : https://github.com/RealCuf 2 | 3 | import argparse 4 | import datetime 5 | import pysftp 6 | import os 7 | import sys 8 | from rich import print as rprint 9 | 10 | def parse_arguments(): 11 | """Parse command line arguments.""" 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument("-b", "--backup", action="store_true") 14 | return parser.parse_args() 15 | 16 | 17 | def main(): 18 | args = parse_arguments() 19 | 20 | if args.backup: 21 | # Prompt user for SFTP server information 22 | data = [] 23 | while True: 24 | host = input("\n[ ] Enter S.Host (or 'q' to quit) :\n>>>> ") 25 | if host.lower() == 'q': 26 | break 27 | port = int(input("[ ] Enter S.Port:\n>>>> ")) 28 | user = input("[ ] Enter S.Username:\n>>>> ") 29 | password = input("[ ] Enter S.Password:\n>>>> ") 30 | remote_path = input("[ ] Enter remote file path (Default : /etc/x-ui/x-ui.db):\n>>>> ") 31 | if not remote_path: 32 | remote_path = '/etc/x-ui/x-ui.db' 33 | 34 | data.append({ 35 | "host": host, 36 | "port": port, 37 | "user": user, 38 | "pass": password, 39 | "remote": remote_path 40 | }) 41 | 42 | # solar date 43 | date_str = datetime.datetime.now().strftime('%Y/%m/%d') 44 | 45 | # Work !! 46 | for i in data: 47 | # Information required to connect to the SFTP server 48 | hostname = i["host"] 49 | port = i["port"] 50 | username = i['user'] 51 | password = i['pass'] 52 | remote_path = i['remote'] 53 | 54 | # Disable hostkey checking 55 | cnopts = pysftp.CnOpts() 56 | cnopts.hostkeys = None 57 | 58 | try: 59 | # Connect to the SFTP server 60 | with pysftp.Connection(host=hostname, username=username, password=password, port=port, 61 | cnopts=cnopts) as sftp: 62 | # Change directory to the root 63 | sftp.cwd('/') 64 | 65 | # Create the 'database' directory if it doesn't exist 66 | if not os.path.exists('database'): 67 | os.makedirs('database') 68 | 69 | # Generate a unique local file name based on timestamp 70 | timestamp = datetime.datetime.now().strftime('%Y%m%d%H%M%S') 71 | local_filename = f'x-ui_{timestamp}.db' 72 | 73 | # Download the remote file 74 | sftp.get(remote_path, localpath=f'database/{local_filename}') 75 | 76 | rprint("[yellow]------------------------------------------------------------[/yellow]\n") 77 | rprint("[green]Downloaded successfully.[/green]") 78 | rprint(f"[green]Local file path[/green] : [magenta]database/{local_filename}[/magenta]") 79 | rprint("\n[cyan]You can find them in the 'database' directory.[/cyan] [magenta](type : start database)[/magenta]") 80 | rprint("\n[yellow]------------------------------------------------------------[/yellow]") 81 | 82 | os.system("start database") 83 | 84 | 85 | except pysftp.AuthenticationException: 86 | rprint("\n[red]Incorrect login credentials.[/red]") 87 | except pysftp.CredentialException: 88 | rprint("\n[red]Missing or invalid login credentials.[/red]") 89 | except pysftp.SSHException as e: 90 | rprint("\n[red]An SSH error occurred :[/red]", str(e)) 91 | except pysftp.ConnectionException as e: 92 | rprint("\n[red]Could not connect to the server :[/red]", str(e)) 93 | except Exception as e: 94 | rprint("\n[red]An error occurred :[/red]\n", str(e)) 95 | 96 | 97 | 98 | if __name__ == '__main__': 99 | main() 100 | 101 | 102 | # GitHub : https://github.com/RealCuf -------------------------------------------------------------------------------- /host.py: -------------------------------------------------------------------------------- 1 | import PySimpleGUI as sg 2 | import ftplib 3 | import webbrowser 4 | import argparse 5 | 6 | 7 | def parse_arguments(): 8 | """Parse command line arguments.""" 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("-o", "--host", action="store_true") 11 | return parser.parse_args() 12 | 13 | def upload_file_to_ftp(file_path, ftp_host, ftp_user, ftp_password, upload_path): 14 | try: 15 | ftp = ftplib.FTP(ftp_host) 16 | ftp.login(user=ftp_user, passwd=ftp_password) 17 | 18 | file = open(file_path, 'rb') 19 | 20 | ftp.storbinary('STOR {}/{}'.format(upload_path, file_path.split('/')[-1]), file) 21 | 22 | ftp.quit() 23 | file.close() 24 | 25 | return 'http://{}/{}'.format(ftp_host, file_path.split('/')[-1]) 26 | except Exception as e: 27 | print('Error uploading file to FTP:', str(e)) 28 | return None 29 | 30 | def open_default_browser(url): 31 | webbrowser.open(url) 32 | 33 | sg.theme('TealMono') 34 | font = ('Calibri', 11) 35 | 36 | 37 | layout = [ 38 | [sg.Column([ 39 | [sg.Text('IP/Domin Host:', font=font)], 40 | [sg.Text('Username:', font=font)], 41 | [sg.Text('Password:', font=font)], 42 | [sg.Text('Upload Path:', font=font)] 43 | ]), 44 | sg.Column([ 45 | [sg.FileBrowse(key='-FILE-', font=font)], 46 | [sg.Input(key='-HOST-', size=(40, 1), font=font)], 47 | [sg.Input(key='-USER-', size=(20, 1), font=font)], 48 | [sg.Input(key='-PASS-', size=(20, 1), password_char='*', font=font)], 49 | [sg.Input(key='-PATH-', size=(40, 1), default_text='/home/(example)/public_html', font=font)], 50 | [sg.Button('Upload', key='-UPLOAD-', font=font), sg.Text('', key='-URL-', size=(20, 1), font=font)] 51 | ])] 52 | ] 53 | 54 | 55 | window = sg.Window('Upload File to Host', layout) 56 | 57 | while True: 58 | event, values = window.read() 59 | if event == sg.WINDOW_CLOSED: 60 | break 61 | elif event == '-UPLOAD-': 62 | file_path = values['-FILE-'] 63 | ftp_host = values['-HOST-'] 64 | ftp_user = values['-USER-'] 65 | ftp_password = values['-PASS-'] 66 | upload_path = values['-PATH-'] 67 | 68 | result = upload_file_to_ftp(file_path, ftp_host, ftp_user, ftp_password, upload_path) 69 | if result: 70 | window['-URL-'].update('File link: {}'.format(result)) 71 | open_default_browser(result) 72 | else: 73 | window['-URL-'].update('Error uploading file.') 74 | 75 | window.close() 76 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # GitHub : https://github.com/RealCuf 2 | 3 | import base64 4 | import datetime 5 | import os 6 | import random 7 | import subprocess 8 | import sys 9 | import qrcode 10 | import requests 11 | from rich import print as rprint 12 | from rich.progress import track 13 | import argparse 14 | import time 15 | 16 | # URLs for configs not encoded in a base64 string 17 | 18 | DECODED_URLS = [ 19 | "https://raw.githubusercontent.com/mostafasadeghifar/v2ray-config/main/config_file.txt", 20 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/Eternity.txt", 21 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/EternityAir.txt", 22 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt", 23 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/splitted/vmess.txt", 24 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/splitted/trojan.txt", 25 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/splitted/ssr.txt", 26 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/splitted/ss.txt", 27 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vmess.txt", 28 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/trojan.txt", 29 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/ss.txt", 30 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/ssr.txt", 31 | "https://raw.githubusercontent.com/vpei/Free-Node-Merge/main/o/node.txt", 32 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub1.txt", 33 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub2.txt", 34 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub3.txt", 35 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub3.txt", 36 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub5.txt", 37 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub6.txt", 38 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub7.txt", 39 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Sub8.txt", 40 | ] 41 | 42 | # URLs for configs encoded in a base64 string 43 | 44 | ENCODED_URLS = [ 45 | "https://raw.githubusercontent.com/wwwzywasia/free/main/sub", 46 | "https://raw.fastgit.org/wwwzywasia/free/main/sub", 47 | "https://gitlab.com/mfuu/v2ray/-/raw/master/v2ray", 48 | "https://raw.githubusercontent.com/mfuu/v2ray/master/v2ray", 49 | "https://raw.githubusercontent.com/Bardiafa/Free-V2ray-Config/main/Splitted-By-Protocol/vless.txt", 50 | "https://raw.githubusercontent.com/tbbatbb/Proxy/master/dist/v2ray.config.txt", 51 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/Eternity", 52 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/EternityAir", 53 | "https://raw.githubusercontent.com/ts-sf/fly/main/v2", 54 | "https://raw.fastgit.org/ts-sf/fly/main/v2", 55 | "https://raw.fgit.ml/ts-sf/fly/main/v2", 56 | "https://raw.githubusercontent.com/mahdibland/ShadowsocksAggregator/master/sub/sub_merge.txt", 57 | "https://raw.githubusercontent.com/tbbatbb/Proxy/master/dist/v2ray.config.txt", 58 | "https://raw.githubusercontent.com/awesome-vpn/awesome-vpn/master/all", 59 | "https://raw.githubusercontent.com/Pawdroid/Free-servers/main/sub", 60 | "https://raw.githubusercontent.com/AzadNetCH/Clash/main/V2Ray.txt", 61 | "https://raw.githubusercontent.com/aiboboxx/v2rayfree/main/v2", 62 | "https://raw.githubusercontent.com/freefq/free/master/v2", 63 | "https://raw.fastgit.org/ripaojiedian/freenode/main/sub", 64 | ] 65 | 66 | logo = r""" 67 | ____ _____________ ________ 68 | \ \ / /\_ ___ \ / _____/ 69 | \ Y / / \ \// \ ___ 70 | \ / \ \___\ \_\ \ 71 | \___/ \______ /\______ / 72 | \/ \/ 73 | """ 74 | 75 | COLORS = ["red", "green", "yellow", "blue", "magenta", "cyan", "white"] 76 | NOW = datetime.datetime.now() 77 | config_folder = "./conf" 78 | QR_DIR = "./qr" 79 | 80 | 81 | def check_reality(links): 82 | reality_links = [] 83 | 84 | for link in links: 85 | response = requests.head(link) 86 | if response.status_code == 200: 87 | headers = response.headers 88 | if all(param in headers for param in ['Dest', 'ShortIds', 'security', 'tls', 'xtls']): 89 | reality_links.append(link) 90 | print(f"The link {link} is reachable and valid.") 91 | else: 92 | print(f"The link {link} is reachable but not reality.") 93 | else: 94 | print(f"The link {link} is not reachable or invalid.") 95 | 96 | if reality_links: 97 | print("Reality links found:") 98 | for link in reality_links: 99 | print(link) 100 | 101 | def main(): 102 | parser = argparse.ArgumentParser() 103 | parser.add_argument("-e", "--reality", action="store_true", help="Check reality of URLs") 104 | args = parser.parse_args() 105 | 106 | if args.reality: 107 | all_urls = DECODED_URLS + ENCODED_URLS 108 | check_reality(all_urls) 109 | 110 | def get_config(url): 111 | """Get config from URL.""" 112 | 113 | try: 114 | response = requests.get(url) 115 | if response.status_code == 200: 116 | return response.text 117 | except requests.exceptions.RequestException as e: 118 | print(f"Error: {e}") 119 | return None 120 | 121 | def decode_base64(string): 122 | """Decode base64 encoded string.""" 123 | 124 | try: 125 | decoded_string = base64.b64decode(string).decode() 126 | return decoded_string 127 | except Exception as e: 128 | print(f"Error: {e}") 129 | return None 130 | 131 | 132 | def get_cleaned_configs(vmess=False, vless=False, trojan=False, shadowsocks=False, shadowsocksr=False): 133 | """Get cleaned configs.""" 134 | 135 | configs = [] 136 | all_urls = DECODED_URLS + ENCODED_URLS 137 | 138 | for url in all_urls: 139 | if url in DECODED_URLS: 140 | config = get_config(url) 141 | if config: 142 | configs.extend(config.splitlines()) 143 | break 144 | elif url in ENCODED_URLS: 145 | decoded_config = decode_base64(get_config(url)) 146 | if decoded_config: 147 | configs.extend(decoded_config.splitlines()) 148 | break 149 | 150 | if not configs: 151 | return [] 152 | 153 | if vmess: 154 | configs = [config for config in configs if "vmess" in config] 155 | elif vless: 156 | configs = [config for config in configs if "vless" in config] 157 | elif trojan: 158 | configs = [config for config in configs if "trojan" in config] 159 | elif shadowsocks: 160 | configs = [config for config in configs if "ss" in config] 161 | elif shadowsocksr: 162 | configs = [config for config in configs if "ssr" in config] 163 | 164 | return configs 165 | 166 | 167 | def save_configs(configs): 168 | """Save configs to file.""" 169 | 170 | if not os.path.exists(config_folder): 171 | os.makedirs(config_folder) 172 | 173 | file_name = os.path.join(config_folder, f"configs_{NOW.strftime('%Y-%m-%d_%H-%M-%S')}.txt") 174 | with open(file_name, "w", encoding="utf-8") as f: 175 | f.write("\n".join(configs)) 176 | rprint(f"[bold green]Config file saved to {file_name}[/bold green]") 177 | 178 | 179 | def get_random_color(word): 180 | """Returns a random color wrapped around the given word.""" 181 | 182 | random_color = random.choice(COLORS) 183 | return f"[{random_color}]{word}[/{random_color}]" 184 | 185 | 186 | def get_random_config(configs, random_configs=5): 187 | """Returns a list of random configs from the given list of whole configs.""" 188 | 189 | random_configs = random.sample(configs, random_configs) 190 | return random_configs 191 | 192 | 193 | def save_qr_code(data): 194 | """Save QR codes to qr_codes directory.""" 195 | 196 | for index, qr_data in enumerate(data, start=1): 197 | qr = qrcode.QRCode( 198 | version=1, 199 | error_correction=qrcode.constants.ERROR_CORRECT_L, 200 | box_size=10, 201 | border=4, 202 | ) 203 | qr.add_data(qr_data) 204 | qr.make(fit=True) 205 | 206 | if not os.path.exists(QR_DIR): 207 | os.makedirs(QR_DIR) 208 | 209 | img = qr.make_image(fill_color="white", back_color="black") 210 | file_name = f"{QR_DIR}/{str(index).zfill(0000)}_qr_code_{NOW.strftime('%Y-%m-%d_%H-%M-%S')}.png" 211 | img.save(file_name) 212 | 213 | rprint( 214 | f"[bold yellow]{len(data)} QR code(s) saved to qr_codes directory.[/bold yellow]" 215 | ) 216 | 217 | 218 | if "-p" in sys.argv or "--ping" in sys.argv: 219 | subprocess.call(["python", "pingtester.py"]) 220 | os.system("python main.py") 221 | sys.exit() 222 | 223 | 224 | import sys 225 | 226 | if '-u' in sys.argv or '--update' in sys.argv: 227 | with open('update.py', 'r') as file: 228 | code = compile(file.read(), 'update.py', 'exec') 229 | exec(code) 230 | time.sleep(2) 231 | os.system("python main.py") 232 | sys.exit() 233 | 234 | if '-b' in sys.argv or '--backup' in sys.argv: 235 | with open('backup.py', 'r') as file: 236 | code = compile(file.read(), 'backup.py', 'exec') 237 | exec(code) 238 | time.sleep(2) 239 | os.system("python main.py") 240 | sys.exit() 241 | 242 | if '-o' in sys.argv or '--host' in sys.argv: 243 | with open('host.py', 'r') as file: 244 | code = compile(file.read(), 'host.py', 'exec') 245 | exec(code) 246 | os.system("python main.py") 247 | sys.exit() 248 | 249 | def run_code(): 250 | 251 | if len(sys.argv) == 1: 252 | rprint("[magenta]------------------------------------------------------------▶[/magenta]") 253 | rprint(logo) 254 | rprint("\n[cyan]V E R S I O N : [cyan][[/cyan][yellow]v 1.6.4[yellow][cyan]][/cyan] [bold green]GitHub : [cyan]https://github.com/RealCuf[/cyan][/bold green]\n") 255 | rprint("[cyan]U S A G E : [cyan][white]python main.py[/white] [cyan][[/cyan][bold yellow]O P T I O N S[/bold yellow][cyan]][/cyan]\n") 256 | rprint("[bold yellow]O P T I O N S : [/bold yellow]\n") 257 | rprint("• [bold yellow]-n[/bold yellow][bold blue] --number[/bold blue] 〔 [bold green]Number of Configs - Default : 5 [/bold green]") 258 | rprint("• [bold yellow]-v[/bold yellow][bold blue] --vmess [/bold blue] 〔 [bold green]Vmess Configs only[/bold green]") 259 | rprint("• [bold yellow]-l[/bold yellow][bold blue] --vless [/bold blue] 〔 [bold green]Vless Configs only[/bold green]") 260 | rprint("• [bold yellow]-t[/bold yellow][bold blue] --trojan[/bold blue] 〔 [bold green]Trojan Configs only[/bold green]") 261 | rprint("• [bold yellow]-h[/bold yellow][bold blue] --shadowsocks[/bold blue] 〔 [bold green]ShadowSocks Configs only[/bold green]") 262 | rprint("• [bold yellow]-a[/bold yellow][bold blue] --shadowsocksr[/bold blue] 〔 [bold green]ShadowSocksR Configs only[/bold green]") 263 | rprint("• [bold yellow]-r[/bold yellow][bold blue] --reality [/bold blue] 〔 [bold green]Reality Checker[/bold green]") 264 | rprint("• [bold yellow]-s[/bold yellow][bold blue] --save [/bold blue] 〔 [bold green]Save Configs[/bold green]") 265 | rprint("• [bold yellow]-q[/bold yellow][bold blue] --qr [/bold blue] 〔 [bold green]Save QR codes[/bold green]") 266 | rprint("• [bold yellow]-b[/bold yellow][bold blue] --backup [/bold blue] 〔 [bold green]x-ui Backup[/bold green]") 267 | rprint("• [bold yellow]-p[/bold yellow][bold blue] --ping [/bold blue] 〔 [bold green]Pingtester[/bold green]") 268 | rprint("• [bold yellow]-o[/bold yellow][bold blue] --host [/bold blue] 〔 [bold green]Upload File to Host[/bold green]") 269 | rprint("• [bold yellow]-u[/bold yellow][bold blue] --update[/bold blue] 〔 [bold green]Update Script[/bold green]\n") 270 | rprint("[magenta]------------------------------------------------------------▶[/magenta]") 271 | sys.exit(1) 272 | 273 | if "-v" in sys.argv or "--vmess" in sys.argv: 274 | configs = get_cleaned_configs(vmess=True) 275 | elif "-l" in sys.argv or "--vless" in sys.argv: 276 | configs = get_cleaned_configs(vless=True) 277 | elif "-t" in sys.argv or "--trojan" in sys.argv: 278 | configs = get_cleaned_configs(trojan=True) 279 | elif "-h" in sys.argv or "--shadowsocks" in sys.argv: 280 | configs = get_cleaned_configs(shadowsocks=True) 281 | elif "-a" in sys.argv or "--shadowsocksr" in sys.argv: 282 | configs = get_cleaned_configs(shadowsocksr=True) 283 | else: 284 | configs = get_cleaned_configs() 285 | 286 | configs_length = len(configs) 287 | rprint(f"\n[bold yellow]{configs_length} configs downloaded.[/bold yellow]") 288 | 289 | if configs_length == 0: 290 | rprint("[bold red]No configs found.[/bold red]\n") 291 | sys.exit(1) 292 | 293 | if "-n" in sys.argv or "--number" in sys.argv: 294 | try: 295 | config_number = int(sys.argv[sys.argv.index("-n") + 1]) 296 | except ValueError: 297 | try: 298 | config_number = int(sys.argv[sys.argv.index("--number") + 1]) 299 | except ValueError: 300 | config_number = 5 301 | if config_number > configs_length: 302 | config_number = configs_length 303 | 304 | random_configs = get_random_config(configs, config_number) 305 | 306 | if "--silent" not in sys.argv: 307 | for config in random_configs: 308 | rprint(get_random_color(config)) 309 | rprint("") 310 | 311 | if "-s" in sys.argv or "--save" in sys.argv: 312 | save_configs(random_configs) 313 | 314 | if "-q" in sys.argv or "--qr" in sys.argv: 315 | save_qr_code(random_configs) 316 | 317 | rprint(f"[bold yellow]{config_number} random configs generated.[/bold yellow]\n") 318 | 319 | os.system("start conf") 320 | os.system("start qr") 321 | 322 | time.sleep(3) 323 | os.system("python main.py") 324 | 325 | 326 | if __name__ == "__main__": 327 | run_code() 328 | 329 | # GitHub : https://github.com/RealCuf 330 | -------------------------------------------------------------------------------- /pingtester.py: -------------------------------------------------------------------------------- 1 | # GitHub : https://github.com/RealCuf 2 | 3 | import tkinter as tk 4 | from tkinter import ttk 5 | from tkinter import filedialog 6 | from ping3 import ping 7 | import json 8 | import base64 9 | import threading 10 | import pyperclip 11 | 12 | 13 | proxies = [] 14 | current_file = "" 15 | 16 | 17 | def extract_proxy_info(filepath): 18 | with open(filepath, 'r') as file: 19 | lines = file.readlines() 20 | proxies.clear() 21 | for line in lines: 22 | line = line.strip() 23 | if line.startswith('vmess://'): 24 | config_type = 'Vmess' 25 | proxy_info = line[8:] 26 | try: 27 | proxy_info = base64.urlsafe_b64decode(proxy_info + '=' * (-len(proxy_info) % 4)).decode('utf-8') 28 | except Exception as e: 29 | print(f'Error decoding Vmess proxy info: {str(e)}') 30 | continue 31 | elif line.startswith('vless://'): 32 | config_type = 'Vless' 33 | proxy_info = line[8:] 34 | elif line.startswith('trojan://'): 35 | config_type = 'Trojan' 36 | proxy_info = line[9:] 37 | elif line.startswith('ss://'): 38 | config_type = 'SS' 39 | proxy_info = line[9:] 40 | elif line.startswith('ssr://'): 41 | config_type = 'SSR' 42 | proxy_info = line[9:] 43 | else: 44 | continue 45 | 46 | proxy_info_parts = proxy_info.split('@') 47 | if len(proxy_info_parts) == 2: 48 | address_port = proxy_info_parts[1].split('#')[0] 49 | address_parts = address_port.split(':') 50 | if len(address_parts) == 2: 51 | address = address_parts[0] 52 | port = address_parts[1] 53 | proxies.append((config_type, address, port, line)) 54 | elif config_type == 'Vmess': 55 | proxy_info_dict = json.loads(proxy_info) 56 | proxies.append((config_type, proxy_info_dict.get('add'), proxy_info_dict.get('port'), line)) 57 | 58 | 59 | def select_file(): 60 | filepath = filedialog.askopenfilename(filetypes=[('Text Files', '*.txt')]) 61 | if filepath: 62 | ping_proxy(filepath) 63 | 64 | 65 | def ping_proxy(filepath=None): 66 | if filepath: 67 | extract_proxy_info(filepath) 68 | global current_file 69 | current_file = filepath 70 | 71 | root = tk.Tk() 72 | root.title('Ping Results v2.3.1') 73 | 74 | style = ttk.Style() 75 | style.theme_use('clam') 76 | 77 | refresh_button = ttk.Button(root, text='Refresh', command=lambda: refresh_results(root)) 78 | refresh_button.pack(pady=10) 79 | 80 | result_frame = ttk.Frame(root) 81 | result_frame.pack(fill=tk.BOTH, expand=True) 82 | 83 | for index, proxy in enumerate(proxies): 84 | config_type, address, port, proxy_info = proxy 85 | 86 | result_label = ttk.Label(result_frame, text=f'{config_type} Config (Domain or IP: {address}): ') 87 | result_label.grid(row=index, column=0, sticky='w', padx=10, pady=5) 88 | 89 | response_label = ttk.Label(result_frame, text="Pinging...") 90 | response_label.grid(row=index, column=1, padx=10, pady=5) 91 | 92 | copy_button = ttk.Button(result_frame, text="Copy", command=lambda txt=proxy_info: copy_to_clipboard(txt)) 93 | copy_button.grid(row=index, column=2, padx=10, pady=5) 94 | 95 | threading.Thread(target=ping_proxy_async, args=(address, response_label)).start() 96 | 97 | root.update_idletasks() 98 | root.mainloop() 99 | 100 | 101 | for proxy in proxies: 102 | config_type, address, port, proxy_info = proxy 103 | result = f'{config_type} Config (Domain or IP: {address}): ' 104 | 105 | label = ttk.Label(result_frame, text=result) 106 | label.pack() 107 | 108 | response_label = ttk.Label(result_frame, text="Pinging...") 109 | response_label.pack() 110 | 111 | copy_button = ttk.Button(result_frame, text="Copy", command=lambda txt=proxy_info: copy_to_clipboard(txt)) 112 | copy_button.pack() 113 | 114 | threading.Thread(target=ping_proxy_async, args=(address, response_label)).start() 115 | 116 | root.geometry('500x430') 117 | root.mainloop() 118 | 119 | 120 | def ping_proxy_async(address, response_label): 121 | try: 122 | response_time = ping(address, timeout=1) 123 | if response_time is not None: 124 | response_time_str = '{:.0f} ms'.format(response_time * 1000) 125 | if response_time >= 100: 126 | response_time_str = '\033[91m{}\033[0m'.format(response_time_str, foreground='red') 127 | else: 128 | response_label.config(text=response_time_str, foreground='green') 129 | else: 130 | response_label.config(text="failed", foreground='red') 131 | except Exception as e: 132 | response_label.config(text="Error: {}".format(str(e)), foreground='red') 133 | 134 | 135 | def refresh_results(root): 136 | root.destroy() 137 | ping_proxy(current_file) 138 | 139 | def copy_to_clipboard(txt): 140 | pyperclip.copy(txt) 141 | 142 | def create_gui(): 143 | root = tk.Tk() 144 | root.title('VCG Pinger v2.3.1') 145 | 146 | style = ttk.Style() 147 | style.theme_use('clam') 148 | 149 | screen_width = root.winfo_screenwidth() 150 | screen_height = root.winfo_screenheight() 151 | 152 | window_width = 300 153 | window_height = 55 154 | x = (screen_width - window_width) // 2 155 | y = (screen_height - window_height) // 2 156 | 157 | root.geometry(f'{window_width}x{window_height}+{x}+{y}') 158 | root.resizable(False, False) 159 | 160 | select_button = ttk.Button(root, text='Select File', command=select_file) 161 | select_button.pack(pady=10) 162 | 163 | root.mainloop() 164 | 165 | 166 | if __name__ == "__main__": 167 | create_gui() 168 | 169 | # GitHub : https://github.com/RealCuf 170 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyQRCode 2 | qrcode 3 | requests 4 | rich 5 | pysftp 6 | PySimpleGUI 7 | ping3 8 | pyperclip 9 | argparse 10 | importlib 11 | 12 | # pip install -r requirements.txt 13 | -------------------------------------------------------------------------------- /update.py: -------------------------------------------------------------------------------- 1 | # GitHub : https://github.com/RealCuf 2 | 3 | import os 4 | import argparse 5 | from git import Repo 6 | import shutil 7 | from rich import print as rprint 8 | 9 | COLORS = ["red", "green", "yellow", "blue", "magenta", "cyan", "white"] 10 | 11 | def update_project(repo_url, project_dir): 12 | # Remove the previous project directory 13 | if os.path.exists(project_dir): 14 | rprint("\n[bold yellow][ ][/bold yellow] [bold white]Removing the previous project...[/bold white]") 15 | shutil.rmtree(project_dir, onerror=onerror) 16 | 17 | # Clone the new repository 18 | rprint("\n[bold yellow][ ][/bold yellow] [bold white]Cloning the new repository...[/bold white]") 19 | Repo.clone_from(repo_url, project_dir) 20 | 21 | rprint("\n[bold green][ ][/bold green] [bold white]Project successfully updated.[/bold white]\n") 22 | 23 | def onerror(func, path, exc_info): 24 | """ 25 | Error handler for `shutil.rmtree`. 26 | If the error is due to a permission issue (Access is denied), 27 | it will attempt to change the file permissions and retry the operation. 28 | """ 29 | import stat 30 | import errno 31 | 32 | # Get the exception details 33 | exception_class, exception, traceback = exc_info 34 | 35 | # Check if the error is due to a permission issue (Access is denied) 36 | if exception.errno == errno.EACCES: 37 | # Change the file permissions to allow removal 38 | os.chmod(path, stat.S_IWRITE) 39 | 40 | # Retry the operation 41 | func(path) 42 | else: 43 | # Re-raise the exception for other errors 44 | raise exception 45 | 46 | def main(): 47 | parser = argparse.ArgumentParser(description='Update project') 48 | parser.add_argument('-u', '--update', action='store_true', help='Update the project') 49 | 50 | args = parser.parse_args() 51 | 52 | if args.update: 53 | # New repository information 54 | repo_url = "https://github.com/RealCuf/VCG-Script.git" # New repo URL 55 | 56 | # Get the current user's home directory 57 | home_dir = os.path.expanduser("~") 58 | 59 | # Set the project directory 60 | project_dir = os.path.join(home_dir, "VCG-Script") 61 | 62 | # Update the project 63 | update_project(repo_url, project_dir) 64 | 65 | os.system("python main.py") 66 | 67 | if __name__ == '__main__': 68 | main() 69 | 70 | # GitHub : https://github.com/RealCuf --------------------------------------------------------------------------------