├── LICENSE ├── .gitignore ├── README.md └── app.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 NotAnyoneMe 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[codz] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py.cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # UV 98 | # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | #uv.lock 102 | 103 | # poetry 104 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 105 | # This is especially recommended for binary packages to ensure reproducibility, and is more 106 | # commonly ignored for libraries. 107 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 108 | #poetry.lock 109 | #poetry.toml 110 | 111 | # pdm 112 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 113 | # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. 114 | # https://pdm-project.org/en/latest/usage/project/#working-with-version-control 115 | #pdm.lock 116 | #pdm.toml 117 | .pdm-python 118 | .pdm-build/ 119 | 120 | # pixi 121 | # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. 122 | #pixi.lock 123 | # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one 124 | # in the .venv directory. It is recommended not to include this directory in version control. 125 | .pixi 126 | 127 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 128 | __pypackages__/ 129 | 130 | # Celery stuff 131 | celerybeat-schedule 132 | celerybeat.pid 133 | 134 | # SageMath parsed files 135 | *.sage.py 136 | 137 | # Environments 138 | .env 139 | .envrc 140 | .venv 141 | env/ 142 | venv/ 143 | ENV/ 144 | env.bak/ 145 | venv.bak/ 146 | 147 | # Spyder project settings 148 | .spyderproject 149 | .spyproject 150 | 151 | # Rope project settings 152 | .ropeproject 153 | 154 | # mkdocs documentation 155 | /site 156 | 157 | # mypy 158 | .mypy_cache/ 159 | .dmypy.json 160 | dmypy.json 161 | 162 | # Pyre type checker 163 | .pyre/ 164 | 165 | # pytype static type analyzer 166 | .pytype/ 167 | 168 | # Cython debug symbols 169 | cython_debug/ 170 | 171 | # PyCharm 172 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 173 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 174 | # and can be added to the global gitignore or merged into this file. For a more nuclear 175 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 176 | #.idea/ 177 | 178 | # Abstra 179 | # Abstra is an AI-powered process automation framework. 180 | # Ignore directories containing user credentials, local state, and settings. 181 | # Learn more at https://abstra.io/docs 182 | .abstra/ 183 | 184 | # Visual Studio Code 185 | # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore 186 | # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore 187 | # and can be added to the global gitignore or merged into this file. However, if you prefer, 188 | # you could uncomment the following to ignore the entire vscode folder 189 | # .vscode/ 190 | 191 | # Ruff stuff: 192 | .ruff_cache/ 193 | 194 | # PyPI configuration file 195 | .pypirc 196 | 197 | # Cursor 198 | # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to 199 | # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data 200 | # refer to https://docs.cursor.com/context/ignore-files 201 | .cursorignore 202 | .cursorindexingignore 203 | 204 | # Marimo 205 | marimo/_static/ 206 | marimo/_lsp/ 207 | __marimo__/ 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proxy Checker Pro 2 | 3 | ![Version](https://img.shields.io/badge/version-3.0-brightgreen) 4 | ![Python](https://img.shields.io/badge/python-3.6+-blue) 5 | ![License](https://img.shields.io/badge/license-MIT-orange) 6 | ![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey) 7 | 8 | A professional, feature-rich proxy checker application with a modern dark-themed GUI. Test HTTP, HTTPS, SOCKS4, and SOCKS5 proxies with real-time speed testing, country detection, and advanced verification methods. 9 | 10 | Proxy Checker Pro Interface 11 | 12 | ## Features 13 | 14 | ### Core Functionality 15 | - **Multiple Proxy Types**: HTTP, HTTPS, SOCKS4, SOCKS5 16 | - **Flexible Input Formats**: 17 | - `IP:PORT` 18 | - `IP:PORT:USER:PASS` 19 | - `USER:PASS:IP:PORT` 20 | - `IP PORT` 21 | - `HOST:PORT` 22 | - **Authentication Support**: Full support for proxies with username/password 23 | - **Real-time Testing**: HTTP request verification with custom test URLs 24 | - **Speed Testing**: Measure proxy download speed in KB/s 25 | - **Country Detection**: Automatic IP geolocation via API 26 | - **Duplicate Removal**: Automatically filter duplicate proxies 27 | 28 | ### Advanced Features 29 | - **Verification Methods**: 30 | - HTTP Request (full functionality test) 31 | - Socket Connection (basic connectivity test) 32 | - **Sorting Options**: Sort by IP, Port, Country, Speed, or Status 33 | - **Export Options**: Save results as CSV or TXT 34 | - **Customizable Settings**: 35 | - Adjustable timeout values 36 | - Custom test URLs 37 | - Configurable verification methods 38 | - Speed check toggle 39 | - **Modern Dark Theme**: Professional, eye-friendly interface with color-coded status 40 | 41 | ## Requirements 42 | 43 | ### Python Version 44 | - Python 3.6 or higher 45 | 46 | ### Required Libraries 47 | All required libraries are part of Python's standard library: 48 | - `tkinter` - GUI framework (included with Python) 49 | - `threading` - Concurrent proxy checking 50 | - `socket` - Network connections 51 | - `csv` - Export to CSV format 52 | - `datetime` - Timestamp handling 53 | - `re` - Regular expressions for parsing 54 | - `urllib` - HTTP requests and proxy handling 55 | - `json` - API response parsing 56 | 57 | ### System Requirements 58 | - **Operating System**: Windows, Linux, or macOS 59 | - **Memory**: 512 MB minimum 60 | - **Display**: 1200x700 minimum resolution recommended 61 | - **Internet Connection**: Required for country detection and proxy testing 62 | 63 | ## Installation 64 | 65 | ### Step 1: Clone the Repository 66 | ```bash 67 | git clone https://github.com/NotAnyoneMe/ProxyChecker.git 68 | cd ProxyChecker 69 | ``` 70 | 71 | ### Step 2: Verify Python Installation 72 | ```bash 73 | python --version 74 | # or 75 | python3 --version 76 | ``` 77 | 78 | Ensure you have Python 3.6 or higher installed. 79 | 80 | ### Step 3: Run the Application 81 | ```bash 82 | python app.py 83 | # or 84 | python3 app.py 85 | ``` 86 | 87 | **Note**: No additional dependencies need to be installed. All required libraries are included with Python's standard library. 88 | 89 | ## Usage Guide 90 | 91 | ### Basic Workflow 92 | 93 | **1. Load Proxies** 94 | - Click "Load Proxies" button in the Checker tab 95 | - Select your proxy list file (.txt format) 96 | - Choose the appropriate input format from the dropdown menu 97 | - Enable "Remove Duplicates" if needed 98 | 99 | **2. Configure Settings** 100 | - Select proxy type: HTTP, HTTPS, SOCKS4, or SOCKS5 101 | - Set timeout value in seconds (default: 10) 102 | - Enable/disable "Check Speed" option 103 | - Choose output format for exports 104 | - Select sorting preference 105 | 106 | **3. Start Checking** 107 | - Click "Start Check" to begin verification 108 | - Monitor real-time progress in the status bar 109 | - View results in the table with color-coded status: 110 | - Green = Working proxy 111 | - Red = Failed proxy 112 | - Use "Stop Check" to halt the process if needed 113 | 114 | **4. Export Results** 115 | - Click "Save as CSV" for detailed reports with all columns 116 | - Click "Save as TXT" for a simple list of working proxies only 117 | 118 | ### Input File Format 119 | 120 | Create a text file with your proxies, one per line. The application supports multiple formats: 121 | 122 | ```text 123 | 192.168.1.1:8080 124 | 10.0.0.1:3128:username:password 125 | username:password:proxy.example.com:8080 126 | 203.0.113.5 8080 127 | ``` 128 | 129 | ### Settings Configuration 130 | 131 | Navigate to the **Settings** tab to customize: 132 | 133 | - **Test URL**: Website used to verify proxy connectivity (default: https://www.google.com) 134 | - **Speed Test URL**: File URL for download speed measurement (default: 100KB test file) 135 | - **Default Timeout**: Maximum wait time per proxy in seconds 136 | - **Concurrent Checks**: Thread count for parallel checking (display only in current version) 137 | - **Verification Method**: 138 | - HTTP Request: Full functionality test with actual web request 139 | - Socket Connection: Basic port connectivity test 140 | 141 | ## Use Cases 142 | 143 | - **Web Scraping**: Find and validate reliable proxies for data collection projects 144 | - **Privacy Testing**: Test proxy anonymity levels and connection speeds 145 | - **Proxy Management**: Maintain and validate large proxy lists efficiently 146 | - **Network Administration**: Verify proxy server functionality and performance 147 | - **Security Research**: Test proxy configurations and security settings 148 | - **Bot Development**: Source working proxies for automation tasks 149 | 150 | ## Advanced Configuration 151 | 152 | ### Custom Test URLs 153 | 154 | You can specify custom URLs in the Settings tab to test proxies against specific websites or services: 155 | - Social media platforms (Twitter, Facebook, Instagram) 156 | - E-commerce sites (Amazon, eBay) 157 | - API endpoints 158 | - Geo-restricted content services 159 | - Corporate intranets 160 | 161 | ### Speed Test Customization 162 | 163 | Modify the speed test URL to use different file sizes based on your needs: 164 | - **Small files (100KB)**: Quick speed checks, suitable for large proxy lists 165 | - **Medium files (1-5MB)**: Balanced testing for moderate accuracy 166 | - **Large files (10MB+)**: Accurate speed measurement, takes longer per proxy 167 | 168 | ### Output Format Options 169 | 170 | Choose from multiple output formats: 171 | - **IP:PORT** - Standard format 172 | - **IP PORT** - Space-separated 173 | - **IP,PORT** - Comma-separated (CSV compatible) 174 | 175 | ## Output Details 176 | 177 | ### CSV Export Format 178 | 179 | The CSV export includes comprehensive information: 180 | 181 | | Column | Description | 182 | |--------|-------------| 183 | | IP | IP address of the proxy (with auth username if applicable) | 184 | | Port | Port number | 185 | | Type | Proxy type (HTTP/HTTPS/SOCKS4/SOCKS5) | 186 | | Country | Detected country via geolocation | 187 | | Speed (KB/s) | Download speed measurement | 188 | | Response Time | Time to establish connection | 189 | | Status | Working or Failed with error details | 190 | 191 | ### TXT Export Format 192 | 193 | Simple text file containing only working proxies in the selected output format: 194 | ```text 195 | 192.168.1.1:8080 196 | 10.0.0.1:3128 197 | 203.0.113.5:8080 198 | ``` 199 | 200 | ## Troubleshooting 201 | 202 | ### Common Issues and Solutions 203 | 204 | **Issue**: Proxies showing as "Failed" even though they are known to work 205 | - **Solution 1**: Increase timeout value in settings (try 15-30 seconds) 206 | - **Solution 2**: Switch verification method from HTTP Request to Socket Connection 207 | - **Solution 3**: Check if the test URL is accessible from your location 208 | - **Solution 4**: Some proxies may require specific authentication formats 209 | 210 | **Issue**: Country shows as "Unknown" for all proxies 211 | - **Solution 1**: Verify your internet connection is active 212 | - **Solution 2**: Check if ip-api.com is accessible from your network 213 | - **Solution 3**: Some private IP addresses won't have geolocation data 214 | - **Solution 4**: API rate limiting may occur with very large proxy lists 215 | 216 | **Issue**: Speed test shows "N/A" for all proxies 217 | - **Solution 1**: Ensure the speed test URL is accessible and returns data 218 | - **Solution 2**: Increase timeout value as slow proxies may timeout 219 | - **Solution 3**: Disable speed checking if not needed to speed up verification 220 | - **Solution 4**: Some proxies block file downloads 221 | 222 | **Issue**: Application window not displaying correctly 223 | - **Solution 1**: Verify minimum screen resolution (1200x700) 224 | - **Solution 2**: Check display scaling settings in your OS 225 | - **Solution 3**: Try maximizing the window 226 | 227 | **Issue**: Application not starting or crashes on launch 228 | - **Solution 1**: Verify Python 3.6+ is installed: `python --version` 229 | - **Solution 2**: Check tkinter availability: `python -m tkinter` 230 | - **Solution 3**: On Linux, install tkinter: `sudo apt-get install python3-tk` 231 | - **Solution 4**: Check console for error messages 232 | 233 | **Issue**: Checking process is very slow 234 | - **Solution 1**: Reduce timeout value for faster checking 235 | - **Solution 2**: Disable speed checking if not needed 236 | - **Solution 3**: Use Socket Connection method instead of HTTP Request 237 | - **Solution 4**: Check proxy list for invalid entries 238 | 239 | ## Contributing 240 | 241 | Contributions are welcome and appreciated! Here's how you can help improve Proxy Checker Pro: 242 | 243 | ### How to Contribute 244 | 245 | 1. **Fork the repository** on GitHub 246 | 2. **Clone your fork** locally: `git clone https://github.com/YOUR-USERNAME/ProxyChecker.git` 247 | 3. **Create a feature branch**: `git checkout -b feature/AmazingFeature` 248 | 4. **Make your changes** and test thoroughly 249 | 5. **Commit your changes**: `git commit -m 'Add some AmazingFeature'` 250 | 6. **Push to your branch**: `git push origin feature/AmazingFeature` 251 | 7. **Open a Pull Request** with a clear description of changes 252 | 253 | ### Areas for Contribution 254 | 255 | - **Additional proxy types**: SOCKS4A support, HTTP/2 proxies 256 | - **Enhanced speed testing**: More accurate algorithms, multiple test files 257 | - **Improved country detection**: Alternative APIs, local database support 258 | - **GUI improvements**: Themes, translations, accessibility features 259 | - **Performance optimizations**: Multi-threading implementation, memory efficiency 260 | - **Export formats**: JSON, XML, database export options 261 | - **Proxy chain support**: Test multiple proxy hops 262 | - **Scheduling**: Automated periodic checking 263 | - **Statistics**: Charts and graphs for results analysis 264 | - **Bug fixes**: Report and fix issues 265 | - **Documentation**: Improve guides and examples 266 | 267 | ### Code Style Guidelines 268 | 269 | - Follow PEP 8 style guidelines 270 | - Add comments for complex logic 271 | - Update documentation for new features 272 | - Test changes before submitting 273 | - Keep commits focused and atomic 274 | 275 | ## License 276 | 277 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for full details. 278 | 279 | ### MIT License Summary 280 | 281 | You are free to: 282 | - Use the software for any purpose 283 | - Modify the source code 284 | - Distribute copies 285 | - Use the software commercially 286 | 287 | The software is provided "as is", without warranty of any kind. 288 | 289 | ## Developer 290 | 291 | **Developed by MLBOR** 292 | 293 | - **Telegram**: [@MLBOR](https://t.me/MLBOR) 294 | - **GitHub**: [github.com/NotAnyOneMe](https://github.com/NotAnyOneMe) 295 | 296 | For questions, suggestions, or support, feel free to reach out via Telegram or GitHub. 297 | 298 | ## Support Development 299 | 300 | If you find this tool useful and would like to support its continued development, cryptocurrency donations are greatly appreciated: 301 | 302 | ### Cryptocurrency Addresses 303 | 304 | **TON (The Open Network)** 305 | ``` 306 | UQD-XUfoicqCzV-RCI6RkEzTO0iNi92ahMUSQ8l27s42LcVf 307 | ``` 308 | 309 | **LTC (Litecoin)** 310 | ``` 311 | ltc1qtl2tjdacrwk3r2qutl408quqwzeejv29jrvnnl 312 | ``` 313 | 314 | **BTC (Bitcoin)** 315 | ``` 316 | bc1q6y0qx6xhla2w9utlqusyzpskn0mdvfgzwchg50 317 | ``` 318 | 319 | **ETH (Ethereum)** 320 | ``` 321 | 0xe3C42C6AF102fFDf6856DC2df3Ec7D009F4Eb31B 322 | ``` 323 | 324 | Your support helps maintain and improve this project. Thank you! 325 | 326 | ## Star This Repository 327 | 328 | If you find Proxy Checker Pro useful, please consider giving it a star on GitHub. It helps others discover the tool and motivates continued development. 329 | 330 | ## Contact & Support 331 | 332 | - **Bug Reports**: Submit via [GitHub Issues](https://github.com/NotAnyoneMe/ProxyChecker/issues) 333 | - **Feature Requests**: Open an issue with the "enhancement" label 334 | - **Direct Support**: Contact via Telegram [@MLBOR](https://t.me/MLBOR) 335 | - **Discussions**: Join conversations in [GitHub Discussions](https://github.com/NotAnyoneMe/ProxyChecker/discussions) 336 | 337 | ## Changelog 338 | 339 | ### Version 3.0 - Ultimate Edition (Current) 340 | - Multiple proxy type support (HTTP, HTTPS, SOCKS4, SOCKS5) 341 | - Authentication support with flexible input formats 342 | - Real-time speed testing with configurable URLs 343 | - Automatic country detection via geolocation API 344 | - Modern dark theme with professional styling 345 | - Multiple input and output format options 346 | - Color-coded status indicators (green/red) 347 | - Real-time progress tracking 348 | - Dual verification methods (HTTP/Socket) 349 | - Export to CSV and TXT formats 350 | - Sorting by multiple criteria 351 | - Duplicate removal functionality 352 | 353 | ### Future Roadmap 354 | - Multi-threading for faster checking 355 | - Proxy chain testing 356 | - Export to additional formats (JSON, XML) 357 | - Statistics and analytics dashboard 358 | - Scheduled checking 359 | - Proxy rotation testing 360 | - Advanced filtering options 361 | 362 | --- 363 | 364 |
365 | 366 | **Made with care by MLBOR** 367 | 368 | **Give this project a star if you find it useful!** 369 | 370 | [Report Bug](https://github.com/NotAnyoneMe/ProxyChecker/issues) · [Request Feature](https://github.com/NotAnyoneMe/ProxyChecker/issues) · [Contribute](https://github.com/NotAnyoneMe/ProxyChecker/pulls) 371 | 372 |
373 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from tkinter import ttk, filedialog, messagebox 3 | import threading 4 | import socket 5 | import csv 6 | from datetime import datetime 7 | import re 8 | import urllib.request 9 | import urllib.error 10 | import base64 11 | 12 | class ProxyCheckerApp: 13 | def __init__(self, root): 14 | self.root = root 15 | self.root.title("Proxy Checker Pro") 16 | self.root.geometry("1200x700") 17 | 18 | self.proxies = [] 19 | self.checked_proxies = [] 20 | self.is_checking = False 21 | 22 | self.setup_dark_theme() 23 | 24 | self.notebook = ttk.Notebook(root) 25 | self.notebook.pack(fill='both', expand=True, padx=10, pady=10) 26 | 27 | self.checker_tab = ttk.Frame(self.notebook) 28 | self.settings_tab = ttk.Frame(self.notebook) 29 | self.about_tab = ttk.Frame(self.notebook) 30 | 31 | self.notebook.add(self.checker_tab, text='Checker') 32 | self.notebook.add(self.settings_tab, text='Settings') 33 | self.notebook.add(self.about_tab, text='About') 34 | 35 | self.setup_checker_tab() 36 | self.setup_settings_tab() 37 | self.setup_about_tab() 38 | 39 | def setup_dark_theme(self): 40 | style = ttk.Style() 41 | style.theme_use('default') 42 | 43 | bg_color = '#1a1a1a' 44 | fg_color = '#ffffff' 45 | select_bg = '#2d2d2d' 46 | button_bg = '#2d2d2d' 47 | 48 | self.root.configure(bg=bg_color) 49 | 50 | style.configure('TFrame', background=bg_color) 51 | style.configure('TLabel', background=bg_color, foreground=fg_color) 52 | style.configure('TButton', background=button_bg, foreground=fg_color, borderwidth=1) 53 | style.map('TButton', background=[('active', '#3d3d3d')]) 54 | style.configure('TCheckbutton', background=bg_color, foreground=fg_color) 55 | style.configure('TEntry', fieldbackground='#2d2d2d', foreground=fg_color) 56 | style.configure('TCombobox', fieldbackground='#2d2d2d', foreground=fg_color) 57 | style.configure('TNotebook', background=bg_color, borderwidth=0) 58 | style.configure('TNotebook.Tab', background=button_bg, foreground=fg_color, padding=[20, 10]) 59 | style.map('TNotebook.Tab', background=[('selected', '#3d3d3d')]) 60 | style.configure('Treeview', background='#2d2d2d', foreground=fg_color, fieldbackground='#2d2d2d', borderwidth=0) 61 | style.map('Treeview', background=[('selected', '#404040')]) 62 | style.configure('Treeview.Heading', background='#3d3d3d', foreground=fg_color, borderwidth=1) 63 | style.map('Treeview.Heading', background=[('active', '#4d4d4d')]) 64 | style.configure('TLabelframe', background=bg_color, foreground=fg_color) 65 | style.configure('TLabelframe.Label', background=bg_color, foreground=fg_color) 66 | 67 | def setup_checker_tab(self): 68 | top_frame = ttk.Frame(self.checker_tab) 69 | top_frame.pack(fill='x', padx=10, pady=10) 70 | 71 | self.load_btn = ttk.Button(top_frame, text="Load Proxies", command=self.load_proxies) 72 | self.load_btn.pack(side='left', padx=5) 73 | 74 | self.remove_dup_var = tk.BooleanVar(value=True) 75 | ttk.Checkbutton(top_frame, text="Remove Duplicates", 76 | variable=self.remove_dup_var).pack(side='left', padx=5) 77 | 78 | ttk.Label(top_frame, text="Proxy Type:").pack(side='left', padx=5) 79 | self.proxy_type_var = tk.StringVar(value="HTTP") 80 | type_combo = ttk.Combobox(top_frame, textvariable=self.proxy_type_var, 81 | values=["HTTP", "HTTPS", "SOCKS4", "SOCKS5"], 82 | width=10, state='readonly') 83 | type_combo.pack(side='left', padx=5) 84 | 85 | ttk.Label(top_frame, text="Input Format:").pack(side='left', padx=5) 86 | self.input_format_var = tk.StringVar(value="IP:PORT") 87 | format_combo = ttk.Combobox(top_frame, textvariable=self.input_format_var, 88 | values=["IP:PORT", "IP:PORT:USER:PASS", "USER:PASS:IP:PORT", 89 | "IP PORT", "HOST:PORT"], 90 | width=18, state='readonly') 91 | format_combo.pack(side='left', padx=5) 92 | 93 | second_row = ttk.Frame(self.checker_tab) 94 | second_row.pack(fill='x', padx=10, pady=5) 95 | 96 | ttk.Label(second_row, text="Output Format:").pack(side='left', padx=5) 97 | self.output_format_var = tk.StringVar(value="IP:PORT") 98 | output_combo = ttk.Combobox(second_row, textvariable=self.output_format_var, 99 | values=["IP:PORT", "IP PORT", "IP,PORT"], 100 | width=10, state='readonly') 101 | output_combo.pack(side='left', padx=5) 102 | 103 | ttk.Label(second_row, text="Sort:").pack(side='left', padx=5) 104 | self.sort_var = tk.StringVar(value="None") 105 | sort_combo = ttk.Combobox(second_row, textvariable=self.sort_var, 106 | values=["None", "IP", "Port", "Country", "Speed", "Status"], 107 | width=10, state='readonly') 108 | sort_combo.pack(side='left', padx=5) 109 | 110 | self.speed_check_var = tk.BooleanVar(value=True) 111 | ttk.Checkbutton(second_row, text="Check Speed", 112 | variable=self.speed_check_var).pack(side='left', padx=5) 113 | 114 | mid_frame = ttk.Frame(self.checker_tab) 115 | mid_frame.pack(fill='x', padx=10, pady=5) 116 | 117 | ttk.Label(mid_frame, text="Timeout (s):").pack(side='left', padx=5) 118 | self.timeout_var = tk.StringVar(value="10") 119 | ttk.Entry(mid_frame, textvariable=self.timeout_var, width=10).pack(side='left', padx=5) 120 | 121 | self.check_btn = ttk.Button(mid_frame, text="Start Check", command=self.start_check) 122 | self.check_btn.pack(side='left', padx=5) 123 | 124 | self.stop_btn = ttk.Button(mid_frame, text="Stop Check", command=self.stop_check, state='disabled') 125 | self.stop_btn.pack(side='left', padx=5) 126 | 127 | self.progress_var = tk.StringVar(value="Ready") 128 | ttk.Label(mid_frame, textvariable=self.progress_var).pack(side='left', padx=5) 129 | 130 | save_frame = ttk.Frame(self.checker_tab) 131 | save_frame.pack(fill='x', padx=10, pady=5) 132 | 133 | self.save_csv_btn = ttk.Button(save_frame, text="Save as CSV", 134 | command=lambda: self.save_results('csv'), state='disabled') 135 | self.save_csv_btn.pack(side='left', padx=5) 136 | 137 | self.save_txt_btn = ttk.Button(save_frame, text="Save as TXT", 138 | command=lambda: self.save_results('txt'), state='disabled') 139 | self.save_txt_btn.pack(side='left', padx=5) 140 | 141 | table_frame = ttk.Frame(self.checker_tab) 142 | table_frame.pack(fill='both', expand=True, padx=10, pady=10) 143 | 144 | v_scroll = ttk.Scrollbar(table_frame, orient='vertical') 145 | h_scroll = ttk.Scrollbar(table_frame, orient='horizontal') 146 | 147 | self.tree = ttk.Treeview(table_frame, columns=('IP', 'Port', 'Type', 'Country', 'Speed', 'Response', 'Status'), 148 | show='headings', yscrollcommand=v_scroll.set, 149 | xscrollcommand=h_scroll.set) 150 | 151 | v_scroll.config(command=self.tree.yview) 152 | h_scroll.config(command=self.tree.xview) 153 | 154 | self.tree.heading('IP', text='IP Address') 155 | self.tree.heading('Port', text='Port') 156 | self.tree.heading('Type', text='Type') 157 | self.tree.heading('Country', text='Country') 158 | self.tree.heading('Speed', text='Speed (KB/s)') 159 | self.tree.heading('Response', text='Response Time') 160 | self.tree.heading('Status', text='Status') 161 | 162 | self.tree.column('IP', width=140) 163 | self.tree.column('Port', width=70) 164 | self.tree.column('Type', width=80) 165 | self.tree.column('Country', width=100) 166 | self.tree.column('Speed', width=100) 167 | self.tree.column('Response', width=110) 168 | self.tree.column('Status', width=90) 169 | 170 | self.tree.grid(row=0, column=0, sticky='nsew') 171 | v_scroll.grid(row=0, column=1, sticky='ns') 172 | h_scroll.grid(row=1, column=0, sticky='ew') 173 | 174 | table_frame.grid_rowconfigure(0, weight=1) 175 | table_frame.grid_columnconfigure(0, weight=1) 176 | 177 | def setup_settings_tab(self): 178 | settings_frame = ttk.LabelFrame(self.settings_tab, text="Connection Settings", padding=20) 179 | settings_frame.pack(fill='both', expand=True, padx=20, pady=20) 180 | 181 | ttk.Label(settings_frame, text="Test URL:").grid(row=0, column=0, sticky='w', pady=5) 182 | self.test_url = tk.StringVar(value="https://www.google.com") 183 | ttk.Entry(settings_frame, textvariable=self.test_url, width=40).grid(row=0, column=1, pady=5, sticky='w') 184 | 185 | ttk.Label(settings_frame, text="Speed Test URL:").grid(row=1, column=0, sticky='w', pady=5) 186 | self.speed_test_url = tk.StringVar(value="http://speedtest.ftp.otenet.gr/files/test100k.db") 187 | ttk.Entry(settings_frame, textvariable=self.speed_test_url, width=40).grid(row=1, column=1, pady=5, sticky='w') 188 | 189 | ttk.Label(settings_frame, text="Default Timeout (seconds):").grid(row=2, column=0, sticky='w', pady=5) 190 | self.default_timeout = tk.StringVar(value="10") 191 | ttk.Entry(settings_frame, textvariable=self.default_timeout, width=20).grid(row=2, column=1, pady=5, sticky='w') 192 | 193 | ttk.Label(settings_frame, text="Concurrent Checks:").grid(row=3, column=0, sticky='w', pady=5) 194 | self.threads_var = tk.StringVar(value="10") 195 | ttk.Entry(settings_frame, textvariable=self.threads_var, width=20).grid(row=3, column=1, pady=5, sticky='w') 196 | 197 | ttk.Label(settings_frame, text="Verification Method:").grid(row=4, column=0, sticky='w', pady=5) 198 | self.verify_method = tk.StringVar(value="HTTP Request") 199 | method_combo = ttk.Combobox(settings_frame, textvariable=self.verify_method, 200 | values=["HTTP Request", "Socket Connection"], 201 | width=20, state='readonly') 202 | method_combo.grid(row=4, column=1, pady=5, sticky='w') 203 | 204 | def setup_about_tab(self): 205 | canvas = tk.Canvas(self.about_tab, bg='#1a1a1a', highlightthickness=0) 206 | scrollbar = ttk.Scrollbar(self.about_tab, orient="vertical", command=canvas.yview) 207 | scrollable_frame = ttk.Frame(canvas) 208 | 209 | scrollable_frame.bind( 210 | "", 211 | lambda e: canvas.configure(scrollregion=canvas.bbox("all")) 212 | ) 213 | 214 | canvas_window = canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") 215 | 216 | def on_canvas_configure(event): 217 | canvas.itemconfig(canvas_window, width=event.width) 218 | 219 | canvas.bind('', on_canvas_configure) 220 | canvas.configure(yscrollcommand=scrollbar.set) 221 | 222 | canvas.pack(side="left", fill="both", expand=True) 223 | scrollbar.pack(side="right", fill="y") 224 | 225 | about_frame = ttk.Frame(scrollable_frame) 226 | about_frame.pack(fill='both', expand=True, padx=40, pady=20) 227 | 228 | title = tk.Label(about_frame, text="Proxy Checker Pro", font=('Arial', 24, 'bold'), 229 | bg='#1a1a1a', fg='#00ff00') 230 | title.pack(pady=10) 231 | 232 | version = tk.Label(about_frame, text="Version 3.0 - Ultimate Edition", 233 | bg='#1a1a1a', fg='#ffffff', font=('Arial', 12)) 234 | version.pack(pady=5) 235 | 236 | description = tk.Label(about_frame, 237 | text="Professional Proxy Checker with Advanced Features\n\n" 238 | "Features:\n" 239 | "• Multiple proxy types (HTTP, HTTPS, SOCKS4, SOCKS5)\n" 240 | "• Multiple input formats support\n" 241 | "• Authentication support (user:pass)\n" 242 | "• Real HTTP request testing with custom URL\n" 243 | "• Speed testing for each proxy\n" 244 | "• Country detection\n" 245 | "• Remove duplicates automatically\n" 246 | "• Real-time checking with accurate results\n" 247 | "• Export to CSV, TXT\n", 248 | justify='center', bg='#1a1a1a', fg='#cccccc', font=('Arial', 10)) 249 | description.pack(pady=15) 250 | 251 | credits_frame = tk.LabelFrame(about_frame, text="👨‍💻 Developer Credits", bg='#1a1a1a', fg='#00ff00', 252 | font=('Arial', 15, 'bold'), borderwidth=3, relief='groove') 253 | credits_frame.pack(pady=20, padx=20, fill='x') 254 | 255 | credits_text = tk.Label(credits_frame, 256 | text="Developed by\n\n" 257 | "📱 Telegram: @MLBOR\n\n" 258 | "💻 GitHub: github.com/NotAnyOneMe", 259 | justify='center', bg='#1a1a1a', fg='#00ccff', 260 | font=('Consolas', 14, 'bold')) 261 | credits_text.pack(pady=25) 262 | 263 | donate_frame = tk.LabelFrame(about_frame, text="💰 💎 SUPPORT DEVELOPMENT - CRYPTO DONATIONS 💎 💰", 264 | bg='#1a1a1a', fg='#ffff00', 265 | font=('Arial', 16, 'bold'), borderwidth=5, relief='raised') 266 | donate_frame.pack(pady=20, padx=20, fill='x') 267 | 268 | donate_text = tk.Text(donate_frame, height=18, bg='#0a0a0a', fg='#00ff00', 269 | font=('Consolas', 13, 'bold'), wrap='word', borderwidth=4, 270 | relief='sunken', padx=25, pady=25, spacing3=10) 271 | donate_text.pack(pady=25, padx=25, fill='x') 272 | 273 | donate_content = """═══════════════════════════════════════════════════════════════ 274 | 275 | 🪙 TON (The Open Network): 276 | UQD-XUfoicqCzV-RCI6RkEzTO0iNi92ahMUSQ8l27s42LcVf 277 | 278 | ═══════════════════════════════════════════════════════════════ 279 | 280 | 💎 LTC (Litecoin): 281 | ltc1qtl2tjdacrwk3r2qutl408quqwzeejv29jrvnnl 282 | 283 | ═══════════════════════════════════════════════════════════════ 284 | 285 | ₿ BTC (Bitcoin): 286 | bc1q6y0qx6xhla2w9utlqusyzpskn0mdvfgzwchg50 287 | 288 | ═══════════════════════════════════════════════════════════════ 289 | 290 | 💠 ETH (Ethereum): 291 | 0xe3C42C6AF102fFDf6856DC2df3Ec7D009F4Eb31B 292 | 293 | ═══════════════════════════════════════════════════════════════ 294 | 295 | Your donation helps keep this project alive! 🚀 296 | Every contribution is deeply appreciated! ❤️""" 297 | 298 | donate_text.insert('1.0', donate_content) 299 | donate_text.config(state='disabled') 300 | 301 | thank_you = tk.Label(about_frame, text="⭐ Thank you for your generous support! ⭐", 302 | bg='#1a1a1a', fg='#ff00ff', font=('Arial', 14, 'bold italic')) 303 | thank_you.pack(pady=20) 304 | 305 | footer = tk.Label(about_frame, text="Made with ❤️ by @MLBOR", 306 | bg='#1a1a1a', fg='#888888', font=('Arial', 10, 'italic')) 307 | footer.pack(pady=10) 308 | 309 | canvas.bind_all("", lambda event: canvas.yview_scroll(int(-1*(event.delta/120)), "units")) 310 | 311 | def parse_proxy_line(self, line): 312 | line = line.strip() 313 | if not line: 314 | return None 315 | 316 | format_type = self.input_format_var.get() 317 | 318 | if format_type == "IP:PORT": 319 | match = re.search(r'(\d+\.\d+\.\d+\.\d+):(\d+)', line) 320 | if match: 321 | return {'ip': match.group(1), 'port': match.group(2), 'user': None, 'pass': None} 322 | 323 | elif format_type == "IP:PORT:USER:PASS": 324 | parts = line.split(':') 325 | if len(parts) >= 4: 326 | return {'ip': parts[0], 'port': parts[1], 'user': parts[2], 'pass': parts[3]} 327 | elif len(parts) == 2: 328 | return {'ip': parts[0], 'port': parts[1], 'user': None, 'pass': None} 329 | 330 | elif format_type == "USER:PASS:IP:PORT": 331 | parts = line.split(':') 332 | if len(parts) >= 4: 333 | return {'ip': parts[2], 'port': parts[3], 'user': parts[0], 'pass': parts[1]} 334 | elif len(parts) == 2: 335 | return {'ip': parts[0], 'port': parts[1], 'user': None, 'pass': None} 336 | 337 | elif format_type == "IP PORT": 338 | match = re.search(r'(\d+\.\d+\.\d+\.\d+)\s+(\d+)', line) 339 | if match: 340 | return {'ip': match.group(1), 'port': match.group(2), 'user': None, 'pass': None} 341 | 342 | elif format_type == "HOST:PORT": 343 | parts = line.split(':') 344 | if len(parts) >= 2: 345 | return {'ip': parts[0], 'port': parts[1], 'user': None, 'pass': None} 346 | 347 | return None 348 | 349 | def load_proxies(self): 350 | filename = filedialog.askopenfilename( 351 | title="Select Proxy File", 352 | filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")] 353 | ) 354 | 355 | if not filename: 356 | return 357 | 358 | try: 359 | with open(filename, 'r') as f: 360 | lines = f.readlines() 361 | 362 | self.proxies = [] 363 | for line in lines: 364 | proxy_data = self.parse_proxy_line(line) 365 | if proxy_data: 366 | self.proxies.append(proxy_data) 367 | 368 | if self.remove_dup_var.get(): 369 | seen = set() 370 | unique_proxies = [] 371 | for p in self.proxies: 372 | key = (p['ip'], p['port']) 373 | if key not in seen: 374 | seen.add(key) 375 | unique_proxies.append(p) 376 | self.proxies = unique_proxies 377 | 378 | for item in self.tree.get_children(): 379 | self.tree.delete(item) 380 | 381 | proxy_type = self.proxy_type_var.get() 382 | for proxy in self.proxies: 383 | auth_info = f" ({proxy['user']})" if proxy['user'] else "" 384 | self.tree.insert('', 'end', values=( 385 | proxy['ip'] + auth_info, 386 | proxy['port'], 387 | proxy_type, 388 | 'Unknown', 389 | '-', 390 | '-', 391 | 'Not Checked' 392 | )) 393 | 394 | messagebox.showinfo("Success", f"Loaded {len(self.proxies)} proxies") 395 | 396 | except Exception as e: 397 | messagebox.showerror("Error", f"Failed to load proxies: {str(e)}") 398 | 399 | def get_country(self, ip): 400 | try: 401 | req = urllib.request.Request(f'http://ip-api.com/json/{ip}?fields=country', 402 | headers={'User-Agent': 'Mozilla/5.0'}) 403 | with urllib.request.urlopen(req, timeout=3) as response: 404 | import json 405 | data = json.loads(response.read().decode()) 406 | return data.get('country', 'Unknown') 407 | except: 408 | return 'Unknown' 409 | 410 | def check_proxy_speed(self, proxy_ip, proxy_port, proxy_user, proxy_pass, timeout): 411 | try: 412 | proxy_url = f'http://{proxy_ip}:{proxy_port}' 413 | if proxy_user and proxy_pass: 414 | proxy_url = f'http://{proxy_user}:{proxy_pass}@{proxy_ip}:{proxy_port}' 415 | 416 | proxy_support = urllib.request.ProxyHandler({ 417 | 'http': proxy_url, 418 | 'https': proxy_url 419 | }) 420 | 421 | opener = urllib.request.build_opener(proxy_support) 422 | opener.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')] 423 | 424 | speed_url = self.speed_test_url.get() 425 | 426 | start_time = datetime.now() 427 | response = opener.open(speed_url, timeout=float(timeout)) 428 | data = response.read() 429 | end_time = datetime.now() 430 | 431 | time_taken = (end_time - start_time).total_seconds() 432 | if time_taken > 0: 433 | data_size = len(data) / 1024 434 | speed = data_size / time_taken 435 | return f"{speed:.2f}" 436 | return "N/A" 437 | except: 438 | return "N/A" 439 | 440 | def check_proxy_http(self, proxy_data, timeout): 441 | try: 442 | proxy_ip = proxy_data['ip'] 443 | proxy_port = proxy_data['port'] 444 | proxy_user = proxy_data.get('user') 445 | proxy_pass = proxy_data.get('pass') 446 | 447 | proxy_url = f'http://{proxy_ip}:{proxy_port}' 448 | if proxy_user and proxy_pass: 449 | proxy_url = f'http://{proxy_user}:{proxy_pass}@{proxy_ip}:{proxy_port}' 450 | 451 | proxy_support = urllib.request.ProxyHandler({ 452 | 'http': proxy_url, 453 | 'https': proxy_url 454 | }) 455 | 456 | opener = urllib.request.build_opener(proxy_support) 457 | opener.addheaders = [('User-Agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')] 458 | 459 | test_url = self.test_url.get() 460 | 461 | start_time = datetime.now() 462 | response = opener.open(test_url, timeout=float(timeout)) 463 | end_time = datetime.now() 464 | 465 | response_time = (end_time - start_time).total_seconds() 466 | 467 | if response.getcode() in [200, 301, 302]: 468 | return ('Working', f"{response_time:.2f}s") 469 | else: 470 | return ('Failed', '-') 471 | except urllib.error.HTTPError as e: 472 | if e.code in [200, 301, 302]: 473 | return ('Working', '-') 474 | return ('Failed', f'HTTP {e.code}') 475 | except urllib.error.URLError as e: 476 | return ('Failed', 'Connection Error') 477 | except socket.timeout: 478 | return ('Failed', 'Timeout') 479 | except Exception as e: 480 | return ('Failed', str(e)[:20]) 481 | 482 | def check_proxy_socket(self, proxy_data, timeout): 483 | try: 484 | proxy_ip = proxy_data['ip'] 485 | proxy_port = proxy_data['port'] 486 | 487 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 488 | sock.settimeout(float(timeout)) 489 | 490 | start_time = datetime.now() 491 | result = sock.connect_ex((proxy_ip, int(proxy_port))) 492 | end_time = datetime.now() 493 | 494 | sock.close() 495 | 496 | response_time = (end_time - start_time).total_seconds() 497 | 498 | if result == 0: 499 | return ('Working', f"{response_time:.2f}s") 500 | else: 501 | return ('Failed', f'Error {result}') 502 | except socket.timeout: 503 | return ('Failed', 'Timeout') 504 | except socket.error as e: 505 | return ('Failed', 'Connection Error') 506 | except Exception as e: 507 | return ('Failed', str(e)[:20]) 508 | 509 | def check_worker(self, proxies, timeout): 510 | for idx, proxy_data in proxies: 511 | if not self.is_checking: 512 | break 513 | 514 | ip = proxy_data['ip'] 515 | port = proxy_data['port'] 516 | user = proxy_data.get('user') 517 | 518 | country = self.get_country(ip) 519 | 520 | status, time = ('Failed', '-') 521 | 522 | try: 523 | if self.verify_method.get() == "HTTP Request": 524 | status, time = self.check_proxy_http(proxy_data, timeout) 525 | else: 526 | status, time = self.check_proxy_socket(proxy_data, timeout) 527 | except Exception as e: 528 | status, time = ('Failed', str(e)[:20]) 529 | 530 | speed = "N/A" 531 | if status == 'Working' and self.speed_check_var.get(): 532 | try: 533 | speed = self.check_proxy_speed(ip, port, user, proxy_data.get('pass'), timeout) 534 | except: 535 | speed = "N/A" 536 | 537 | proxy_type = self.proxy_type_var.get() 538 | auth_info = f" ({user})" if user else "" 539 | 540 | self.root.after(0, self.update_tree_item, idx, ip + auth_info, port, proxy_type, country, speed, time, status) 541 | self.checked_proxies.append((ip, port, proxy_type, country, speed, time, status)) 542 | 543 | def update_tree_item(self, idx, ip, port, ptype, country, speed, time, status): 544 | items = self.tree.get_children() 545 | if idx < len(items): 546 | item = items[idx] 547 | self.tree.item(item, values=(ip, port, ptype, country, speed, time, status)) 548 | 549 | if status == 'Working': 550 | self.tree.item(item, tags=('working',)) 551 | else: 552 | self.tree.item(item, tags=('failed',)) 553 | 554 | self.tree.tag_configure('working', foreground='#00ff00') 555 | self.tree.tag_configure('failed', foreground='#ff0000') 556 | 557 | self.progress_var.set(f"Checked: {len(self.checked_proxies)}/{len(self.proxies)}") 558 | 559 | def start_check(self): 560 | if not self.proxies: 561 | messagebox.showwarning("Warning", "Please load proxies first") 562 | return 563 | 564 | self.is_checking = True 565 | self.checked_proxies = [] 566 | self.check_btn.config(state='disabled') 567 | self.stop_btn.config(state='normal') 568 | self.load_btn.config(state='disabled') 569 | self.save_csv_btn.config(state='disabled') 570 | self.save_txt_btn.config(state='disabled') 571 | 572 | timeout = self.timeout_var.get() 573 | 574 | thread = threading.Thread(target=self.check_all_proxies, args=(timeout,)) 575 | thread.daemon = True 576 | thread.start() 577 | 578 | def stop_check(self): 579 | self.is_checking = False 580 | self.stop_btn.config(state='disabled') 581 | self.progress_var.set("Stopped by user") 582 | self.finish_check() 583 | 584 | def check_all_proxies(self, timeout): 585 | indexed_proxies = [(i, proxy) for i, proxy in enumerate(self.proxies)] 586 | self.check_worker(indexed_proxies, timeout) 587 | 588 | self.root.after(0, self.finish_check) 589 | 590 | def finish_check(self): 591 | self.is_checking = False 592 | self.check_btn.config(state='normal') 593 | self.stop_btn.config(state='disabled') 594 | self.load_btn.config(state='normal') 595 | self.save_csv_btn.config(state='normal') 596 | self.save_txt_btn.config(state='normal') 597 | if self.progress_var.get() != "Stopped by user": 598 | self.progress_var.set(f"Completed: {len(self.checked_proxies)} proxies checked") 599 | 600 | self.apply_sort() 601 | 602 | def apply_sort(self): 603 | sort_by = self.sort_var.get() 604 | if sort_by == "None": 605 | return 606 | 607 | items = [(self.tree.set(item, 'IP'), 608 | self.tree.set(item, 'Port'), 609 | self.tree.set(item, 'Type'), 610 | self.tree.set(item, 'Country'), 611 | self.tree.set(item, 'Speed'), 612 | self.tree.set(item, 'Response'), 613 | self.tree.set(item, 'Status')) for item in self.tree.get_children()] 614 | 615 | if sort_by == "IP": 616 | items.sort(key=lambda x: [int(i) for i in x[0].split('.')[0].split()[0].split('.')]) 617 | elif sort_by == "Port": 618 | items.sort(key=lambda x: int(x[1]) if x[1].isdigit() else 0) 619 | elif sort_by == "Country": 620 | items.sort(key=lambda x: x[3]) 621 | elif sort_by == "Speed": 622 | items.sort(key=lambda x: float(x[4]) if x[4] not in ['N/A', '-'] else 0, reverse=True) 623 | elif sort_by == "Status": 624 | items.sort(key=lambda x: x[6]) 625 | 626 | for item in self.tree.get_children(): 627 | self.tree.delete(item) 628 | 629 | for item in items: 630 | self.tree.insert('', 'end', values=item) 631 | 632 | def save_results(self, format_type): 633 | if not self.checked_proxies: 634 | messagebox.showwarning("Warning", "No results to save") 635 | return 636 | 637 | if format_type == 'csv': 638 | filename = filedialog.asksaveasfilename(defaultextension=".csv", 639 | filetypes=[("CSV Files", "*.csv")]) 640 | if filename: 641 | with open(filename, 'w', newline='') as f: 642 | writer = csv.writer(f) 643 | writer.writerow(['IP', 'Port', 'Type', 'Country', 'Speed (KB/s)', 'Response Time', 'Status']) 644 | writer.writerows(self.checked_proxies) 645 | messagebox.showinfo("Success", "Saved as CSV") 646 | 647 | elif format_type == 'txt': 648 | filename = filedialog.asksaveasfilename(defaultextension=".txt", 649 | filetypes=[("Text Files", "*.txt")]) 650 | if filename: 651 | with open(filename, 'w') as f: 652 | separator = self.output_format_var.get().replace('IP', '').replace('PORT', '').strip() 653 | if not separator: 654 | separator = ':' 655 | 656 | for ip, port, ptype, country, speed, timeout, status in self.checked_proxies: 657 | if status == 'Working': 658 | f.write(f"{ip}{separator}{port}\n") 659 | messagebox.showinfo("Success", "Saved as TXT (working proxies only)") 660 | 661 | if __name__ == "__main__": 662 | root = tk.Tk() 663 | app = ProxyCheckerApp(root) 664 | root.mainloop() 665 | --------------------------------------------------------------------------------