├── 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 | 
4 | 
5 | 
6 | 
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 |
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 |
--------------------------------------------------------------------------------