v2ray-finder 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. v2ray_finder-0.2.1/CHANGELOG.md +177 -0
  2. v2ray_finder-0.2.1/LICENSE +22 -0
  3. v2ray_finder-0.2.1/MANIFEST.in +8 -0
  4. v2ray_finder-0.2.1/PKG-INFO +405 -0
  5. v2ray_finder-0.2.1/README.md +350 -0
  6. v2ray_finder-0.2.1/pyproject.toml +104 -0
  7. v2ray_finder-0.2.1/setup.cfg +4 -0
  8. v2ray_finder-0.2.1/src/v2ray_finder/__init__.py +55 -0
  9. v2ray_finder-0.2.1/src/v2ray_finder/async_fetcher.py +500 -0
  10. v2ray_finder-0.2.1/src/v2ray_finder/cache.py +395 -0
  11. v2ray_finder-0.2.1/src/v2ray_finder/cli.py +563 -0
  12. v2ray_finder-0.2.1/src/v2ray_finder/cli_rich.py +618 -0
  13. v2ray_finder-0.2.1/src/v2ray_finder/core.py +959 -0
  14. v2ray_finder-0.2.1/src/v2ray_finder/exceptions.py +188 -0
  15. v2ray_finder-0.2.1/src/v2ray_finder/gui/__init__.py +1 -0
  16. v2ray_finder-0.2.1/src/v2ray_finder/gui/main_window.py +314 -0
  17. v2ray_finder-0.2.1/src/v2ray_finder/health_checker.py +437 -0
  18. v2ray_finder-0.2.1/src/v2ray_finder/result.py +65 -0
  19. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/PKG-INFO +405 -0
  20. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/SOURCES.txt +38 -0
  21. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/dependency_links.txt +1 -0
  22. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/entry_points.txt +4 -0
  23. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/requires.txt +33 -0
  24. v2ray_finder-0.2.1/src/v2ray_finder.egg-info/top_level.txt +1 -0
  25. v2ray_finder-0.2.1/tests/test_async_fetcher.py +484 -0
  26. v2ray_finder-0.2.1/tests/test_cache.py +451 -0
  27. v2ray_finder-0.2.1/tests/test_cli.py +412 -0
  28. v2ray_finder-0.2.1/tests/test_cli_rich.py +388 -0
  29. v2ray_finder-0.2.1/tests/test_core.py +299 -0
  30. v2ray_finder-0.2.1/tests/test_error_handling.py +199 -0
  31. v2ray_finder-0.2.1/tests/test_exceptions.py +145 -0
  32. v2ray_finder-0.2.1/tests/test_get_repo_files.py +171 -0
  33. v2ray_finder-0.2.1/tests/test_health_basic.py +141 -0
  34. v2ray_finder-0.2.1/tests/test_health_checker.py +579 -0
  35. v2ray_finder-0.2.1/tests/test_imports.py +53 -0
  36. v2ray_finder-0.2.1/tests/test_integration.py +113 -0
  37. v2ray_finder-0.2.1/tests/test_result.py +111 -0
  38. v2ray_finder-0.2.1/tests/test_servers_from_sources.py +206 -0
  39. v2ray_finder-0.2.1/tests/test_servers_with_health.py +195 -0
  40. v2ray_finder-0.2.1/tests/test_stop_mechanism.py +609 -0
@@ -0,0 +1,177 @@
1
+ # Changelog
2
+
3
+ All notable changes to v2ray-finder will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
+
7
+ ## [0.2.1] - 2026-02-24
8
+
9
+ ### Fixed
10
+
11
+ - **Graceful stop / Ctrl+C handling** — complete overhaul across all layers:
12
+
13
+ **`core.py` — `get_servers_from_known_sources()`**
14
+ - Added `try/except KeyboardInterrupt` around each URL fetch
15
+ - On interrupt: calls `self.request_stop()`, breaks the loop, returns
16
+ whatever was already collected (partial results are no longer lost)
17
+
18
+ **`core.py` — `get_servers_from_github()`**
19
+ - Same `try/except KeyboardInterrupt` pattern applied to the repo-file
20
+ iteration loop
21
+ - Partial results from files fetched before Ctrl+C are preserved
22
+
23
+ **`core.py` — `get_servers_with_health()`**
24
+ - Added `health_batch_size` parameter (default `50`) to split the
25
+ server list into smaller batches
26
+ - `should_stop()` is checked between every batch — no longer necessary
27
+ to wait for all health checks to finish before the stop takes effect
28
+ - `try/except KeyboardInterrupt` inside the batch loop: already-checked
29
+ servers are returned immediately on interrupt
30
+
31
+ **`cli.py` — interactive menu**
32
+ - Removed `start_keyboard_listener()` / `stop_keyboard_listener()` calls
33
+ from `interactive_menu()` — the background thread competed with the
34
+ menu's own `input()` calls, silently discarding the first keystroke
35
+ after each operation
36
+ - Every menu operation (options 1–5) now has its own
37
+ `try/except KeyboardInterrupt` with partial-results save
38
+ - Replaced bare boolean `_stop_listener` flag with `threading.Event`
39
+ inside `StopController` for thread-safe lifecycle control
40
+ - `StopController` (listener thread) is now used **only** in the
41
+ non-interactive (`--output` / `--stats-only`) path where the main
42
+ thread never calls `input()` during a fetch
43
+
44
+ **`cli_rich.py` — Rich interactive mode**
45
+ - `_signal_handler()` now calls `_active_finder.request_stop()` before
46
+ re-raising `KeyboardInterrupt`; previously it only set a bare boolean
47
+ that the core loops never checked
48
+ - `fetch_servers()` updates the `partial` snapshot after every
49
+ individual step (known sources, then GitHub search) so a Ctrl+C at
50
+ any point yields whatever was collected up to that moment
51
+ - `StopController` (same pattern as plain CLI) used only in
52
+ non-interactive path to avoid competing `input()` threads
53
+
54
+ ### Tests
55
+
56
+ - Added `TestHealthBatchStop` class to `tests/test_stop_mechanism.py`:
57
+ - `test_ki_during_batch_returns_partial` — KI on batch N returns
58
+ results from batches 1…N-1 and sets `should_stop()`
59
+ - `test_ki_does_not_propagate` — `KeyboardInterrupt` must not escape
60
+ `get_servers_with_health()`
61
+ - `test_should_stop_between_batches_stops_processing` — once
62
+ `should_stop()` is `True`, no further `check_servers()` calls are made
63
+ - `test_custom_batch_size_splits_work` — `health_batch_size=2` with 6
64
+ servers results in exactly 3 `check_servers()` calls
65
+
66
+ ---
67
+
68
+ ## [0.2.0] - 2026-02-20
69
+
70
+ ### Added
71
+
72
+ - **Async HTTP Fetching** (`async_fetcher` module)
73
+ - 10-50x faster concurrent downloads via `asyncio`
74
+ - Multiple backends: aiohttp (preferred), httpx, or sync fallback
75
+ - Connection pooling and per-request timeout control
76
+ - Automatic retry with exponential backoff (configurable `max_retries`)
77
+ - `fetch_urls_concurrently()` convenience function
78
+
79
+ - **Smart Caching Layer** (`cache` module)
80
+ - Memory cache (fast, temporary) and disk cache (persistent via `diskcache`)
81
+ - Configurable TTL per entry
82
+ - Cache statistics: hit rate, hits, misses
83
+ - `@cache.cached('key', ttl=3600)` decorator support
84
+ - Automatic expiration and cleanup
85
+
86
+ - **Enhanced Error Handling** (`exceptions` + `result` modules)
87
+ - `Result[T, E]` type for explicit error handling (`.is_ok()`, `.unwrap()`, `.error`)
88
+ - Custom exception hierarchy: `V2RayFinderError`, `RateLimitError`, `AuthenticationError`, `NetworkError`, `TimeoutError`, `ParseError`, `RepositoryNotFoundError`
89
+ - `raise_errors=True` constructor flag for exception-based error handling
90
+ - `search_repos_or_empty()` and `get_repo_files_or_empty()` compatibility wrappers
91
+
92
+ - **Health Checking** (`health_checker` module)
93
+ - TCP connectivity verification with precise latency measurement
94
+ - Config format validation for vmess, vless, trojan, ss, ssr
95
+ - Concurrent batch health checks via asyncio semaphore
96
+ - Quality scoring (0–100) based on latency thresholds
97
+ - `filter_healthy_servers()` — filter by status and quality score
98
+ - `sort_by_quality()` — sort servers best-first
99
+
100
+ - **Secure Token Handling**
101
+ - Automatic `GITHUB_TOKEN` environment variable reading on init
102
+ - Token format validation and sanitization (length, character set, known prefixes)
103
+ - `V2RayServerFinder.from_env()` factory classmethod
104
+ - Security warnings logged when token passed directly as parameter
105
+
106
+ - **Rate Limit Tracking**
107
+ - `get_rate_limit_info()` — returns last known limit, remaining, and reset time
108
+ - Automatic warning logged when remaining requests drop below 10
109
+
110
+ - **Test Suite** (78% coverage)
111
+ - Unit tests for all core modules
112
+ - Async tests using `pytest-asyncio`
113
+ - Health checker tests with full TCP mocking
114
+ - CI matrix: Python 3.8–3.12 on Linux, macOS, and Windows
115
+
116
+ ### Changed
117
+
118
+ - `V2RayServerFinder.__init__` now accepts `raise_errors: bool = False`
119
+ - `search_repos()` now returns `Result[List[Dict], V2RayFinderError]` instead of raw list
120
+ - Rate limit checking moved after HTTP status checks to avoid mock-related issues
121
+
122
+ ### Technical Notes
123
+
124
+ - No breaking changes for basic usage (`get_all_servers()`, `save_to_file()`)
125
+ - GUI module excluded from coverage (requires display server)
126
+ - All async code is Python 3.8-compatible (no `asyncio.run()` in public API)
127
+
128
+ ---
129
+
130
+ ## [0.1.0] - 2026-01-15
131
+
132
+ ### First Release
133
+
134
+ #### Added
135
+
136
+ **Core Functionality:**
137
+ - GitHub repository search for public V2Ray configs
138
+ - Curated direct subscription sources (3 reliable sources)
139
+ - Protocol support: vmess, vless, trojan, shadowsocks (ss), ssr
140
+ - Automatic deduplication of server configs
141
+
142
+ **Interfaces:**
143
+ - Python API (`V2RayServerFinder`)
144
+ - CLI (simple interactive TUI via `v2ray-finder`)
145
+ - Rich CLI with colored panels and progress bars (`v2ray-finder-rich`)
146
+ - GUI (PySide6/Qt via `v2ray-finder-gui`)
147
+
148
+ **Export:**
149
+ - Save server list to `.txt` files
150
+ - Protocol statistics display
151
+
152
+ ---
153
+
154
+ ## Project Statistics
155
+
156
+ | Metric | Value |
157
+ |--------|-------|
158
+ | Source Lines | ~2,500+ |
159
+ | Test Files | 8 |
160
+ | Test Coverage | ~82% |
161
+ | Supported Protocols | 5 (vmess, vless, trojan, ss, ssr) |
162
+ | Interfaces | 3 (Python API, CLI, GUI) |
163
+ | Python Versions | 3.8 – 3.12 |
164
+ | Platforms | Linux, macOS, Windows |
165
+ | Languages | 3 (\u0641\u0627\u0631\u0633\u06cc, English, Deutsch) |
166
+
167
+ ---
168
+
169
+ ## Contributors
170
+
171
+ - Ali Sadeghi Aghili ([@alisadeghiaghili](https://github.com/alisadeghiaghili)) — Creator & Maintainer
172
+
173
+ ---
174
+
175
+ ## License
176
+
177
+ MIT License — see [LICENSE](LICENSE) for details.
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ali Sadeghi Aghili
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
13
+ be included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ include README.md
2
+ include LICENSE
3
+ include CHANGELOG.md
4
+ include requirements.txt
5
+ recursive-include src/v2ray_finder/gui *.ui *.qrc
6
+ recursive-include tests *.py
7
+ global-exclude __pycache__
8
+ global-exclude *.py[co]
@@ -0,0 +1,405 @@
1
+ Metadata-Version: 2.4
2
+ Name: v2ray-finder
3
+ Version: 0.2.1
4
+ Summary: Search and collect V2Ray servers from GitHub repositories
5
+ Author-email: Ali Sadeghi Aghili <alisadeghiaghili@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/alisadeghiaghili/v2ray-finder
8
+ Project-URL: Repository, https://github.com/alisadeghiaghili/v2ray-finder
9
+ Project-URL: Issues, https://github.com/alisadeghiaghili/v2ray-finder/issues
10
+ Project-URL: Source Code, https://github.com/alisadeghiaghili/v2ray-finder
11
+ Keywords: v2ray,proxy,vpn,github,vmess,vless,trojan,shadowsocks,subscription
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Topic :: Internet
23
+ Classifier: Topic :: Utilities
24
+ Requires-Python: >=3.8
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: requests>=2.31.0
28
+ Provides-Extra: gui
29
+ Requires-Dist: PySide6>=6.4.0; extra == "gui"
30
+ Provides-Extra: cli-rich
31
+ Requires-Dist: rich>=13.7.0; extra == "cli-rich"
32
+ Provides-Extra: async
33
+ Requires-Dist: aiohttp>=3.8.0; extra == "async"
34
+ Requires-Dist: httpx>=0.24.0; extra == "async"
35
+ Provides-Extra: cache
36
+ Requires-Dist: diskcache>=5.6.0; extra == "cache"
37
+ Provides-Extra: all
38
+ Requires-Dist: PySide6>=6.4.0; extra == "all"
39
+ Requires-Dist: rich>=13.7.0; extra == "all"
40
+ Requires-Dist: aiohttp>=3.8.0; extra == "all"
41
+ Requires-Dist: httpx>=0.24.0; extra == "all"
42
+ Requires-Dist: diskcache>=5.6.0; extra == "all"
43
+ Provides-Extra: dev
44
+ Requires-Dist: pytest>=7.0; extra == "dev"
45
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
46
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
47
+ Requires-Dist: black>=23.0; extra == "dev"
48
+ Requires-Dist: flake8>=6.0; extra == "dev"
49
+ Requires-Dist: mypy>=1.0; extra == "dev"
50
+ Requires-Dist: isort>=5.12; extra == "dev"
51
+ Requires-Dist: aiohttp>=3.8.0; extra == "dev"
52
+ Requires-Dist: httpx>=0.24.0; extra == "dev"
53
+ Requires-Dist: diskcache>=5.6.0; extra == "dev"
54
+ Dynamic: license-file
55
+
56
+ # v2ray-finder
57
+
58
+ [![PyPI version](https://badge.fury.io/py/v2ray-finder.svg)](https://badge.fury.io/py/v2ray-finder)
59
+ [![Python Versions](https://img.shields.io/pypi/pyversions/v2ray-finder.svg)](https://pypi.org/project/v2ray-finder/)
60
+ [![Tests](https://github.com/alisadeghiaghili/v2ray-finder/workflows/Tests/badge.svg)](https://github.com/alisadeghiaghili/v2ray-finder/actions)
61
+ [![Code Quality](https://github.com/alisadeghiaghili/v2ray-finder/workflows/Code%20Quality/badge.svg)](https://github.com/alisadeghiaghili/v2ray-finder/actions)
62
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
63
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
64
+ [![GitHub Stars](https://img.shields.io/github/stars/alisadeghiaghili/v2ray-finder?style=flat)](https://github.com/alisadeghiaghili/v2ray-finder/stargazers)
65
+
66
+ [English](README.en.md) | [فارسی](README.fa.md) | [Deutsch](README.de.md) | [📋 CHANGELOG](CHANGELOG.md)
67
+
68
+
69
+ ---
70
+
71
+ A **high-performance** tool to **fetch, aggregate, validate and health-check public V2Ray server configs** from GitHub and curated subscription sources.
72
+
73
+ هدف این ابزار این است که بدون دردسر، یک لیست تمیز و dedup شده از لینک‌های `vmess://`، `vless://`، `trojan://`، `ss://`، `ssr://` بهت بده.
74
+
75
+ **با عشق برای آزادی همیشگی ❤️**
76
+ **Built with love for eternal freedom ❤️**
77
+
78
+ ---
79
+
80
+ ## 🚀 What's New in v0.2.0
81
+
82
+ ### 🎉 Major Performance & Reliability Release!
83
+
84
+ ⚡ **Async HTTP Fetching** — 10-50x faster concurrent downloads
85
+ 💾 **Smart Caching** — 80-95% fewer GitHub API calls
86
+ 🛡️ **Enhanced Error Handling** — Result type + custom exception hierarchy
87
+ 🔒 **Secure Token Handling** — Environment variable support + `from_env()`
88
+ 🧪 **78% Test Coverage** — Comprehensive test suite across Python 3.8–3.12
89
+ 📈 **Rate Limit Tracking** — Monitor GitHub API usage
90
+ 🏥 **Health Checking** — TCP connectivity, latency measurement, quality scoring
91
+ ⌨️ **Interactive Token Prompt** — Secure masked input with `--prompt-token`
92
+ ⛔ **Graceful Interruption** — Press Ctrl+C to save partial results
93
+
94
+ > See full details in [📋 CHANGELOG.md](CHANGELOG.md)
95
+
96
+ ---
97
+
98
+ ## 🎯 Features / ویژگی‌ها
99
+
100
+ ### Core Features / ویژگی‌های اصلی
101
+ - 🔍 **GitHub repository search** + **curated sources**
102
+ - 🚀 **Three interfaces**: Python API, CLI (simple & rich), GUI (PySide6)
103
+ - 📦 **Deduplicated** and **clean** output
104
+ - 🌐 **Supports**: vmess, vless, trojan, shadowsocks, ssr
105
+ - 💾 **Export** to text files
106
+ - 📊 **Statistics** by protocol
107
+
108
+ ### Performance & Reliability / کارایی و قابلیت اطمینان
109
+ - ⚡ **Async HTTP fetching**: **10-50x faster** concurrent downloads
110
+ - 💾 **Smart caching**: **80-95% fewer** API calls with memory/disk cache
111
+ - ✅ **Health checking**: TCP connectivity, latency measurement, config validation
112
+ - 🎯 **Quality scoring**: Rank servers by speed and reliability
113
+ - 🔄 **Retry logic**: Automatic retry with exponential backoff
114
+ - ⛔ **Graceful interruption**: Ctrl+C saves partial results before exit
115
+
116
+ ### Developer Experience / تجربه توسعه‌دهنده
117
+ - 🛡️ **Robust error handling**: Detailed exception hierarchy with proper error propagation
118
+ - 📈 **Rate limit tracking**: Monitor GitHub API usage
119
+ - 🔒 **Secure token handling**: Environment variable support with validation
120
+ - ⌨️ **Interactive token prompt**: Masked input for secure token entry
121
+ - 🧪 **78% test coverage**: Comprehensive test suite across Linux, macOS, and Windows
122
+ - ✅ **CI/CD**: Automated testing and deployment
123
+
124
+ ---
125
+
126
+ ## 📋 Requirements / پیش‌نیازها
127
+
128
+ - **Python** ≥ 3.8
129
+ - **Internet connection**
130
+ - **Optional**: aiohttp/httpx (async), diskcache (caching), PySide6 (GUI)
131
+
132
+ ---
133
+
134
+ ## 📦 Installation / نصب
135
+
136
+ ```bash
137
+ # Core + lightweight CLI
138
+ pip install v2ray-finder
139
+
140
+ # With async support (10-50x faster!)
141
+ pip install "v2ray-finder[async]"
142
+
143
+ # With caching (80-95% fewer API calls!)
144
+ pip install "v2ray-finder[cache]"
145
+
146
+ # With GUI support (PySide6)
147
+ pip install "v2ray-finder[gui]"
148
+
149
+ # With Rich CLI
150
+ pip install "v2ray-finder[cli-rich]"
151
+
152
+ # Everything (recommended)
153
+ pip install "v2ray-finder[all]"
154
+ ```
155
+
156
+ ### From source / از سورس
157
+
158
+ ```bash
159
+ git clone https://github.com/alisadeghiaghili/v2ray-finder.git
160
+ cd v2ray-finder
161
+ pip install -e ".[all,dev]"
162
+ ```
163
+
164
+ ---
165
+
166
+ ## 🔒 Token Security / امنیت Token
167
+
168
+ ### Method 1: Environment Variable (Recommended)
169
+
170
+ ```bash
171
+ # پیشنهادی / Recommended
172
+ export GITHUB_TOKEN="ghp_your_token_here"
173
+ v2ray-finder -s
174
+ ```
175
+
176
+ ```python
177
+ from v2ray_finder import V2RayServerFinder
178
+
179
+ finder = V2RayServerFinder() # reads GITHUB_TOKEN automatically
180
+ finder = V2RayServerFinder.from_env() # explicit
181
+ ```
182
+
183
+ ### Method 2: Interactive Prompt (New! ✨)
184
+
185
+ ```bash
186
+ # Secure masked input
187
+ v2ray-finder --prompt-token -s -o servers.txt
188
+ v2ray-finder-rich --prompt-token
189
+
190
+ # In interactive mode (no args), you'll be prompted automatically
191
+ v2ray-finder-rich
192
+ # → "Do you want to provide a GitHub token? (y/n)"
193
+ ```
194
+
195
+ **Rate Limits:** without token: 60 req/h — with token: 5000 req/h
196
+
197
+ Generate a token at **GitHub Settings → Developer settings → Personal access tokens** with **public_repo** scope.
198
+
199
+ > ⚠️ **Security Note:** Never use `-t` flag for tokens (insecure). Use env var or `--prompt-token` instead.
200
+
201
+ ---
202
+
203
+ ## ⛔ Graceful Interruption (New! ✨)
204
+
205
+ **Press Ctrl+C at any time** during fetch operations to:
206
+ - Stop immediately without data loss
207
+ - Save all servers collected so far
208
+ - Display statistics for partial results
209
+ - Exit cleanly with code `130`
210
+
211
+ ```bash
212
+ v2ray-finder -s -o servers.txt
213
+ # ... fetching ...
214
+ # Press Ctrl+C
215
+
216
+ [!] Interrupted by user. Saving partial results...
217
+ [✓] Saved 47 servers to v2ray_servers_partial.txt
218
+
219
+ Total servers: 47
220
+ By protocol:
221
+ vmess: 23
222
+ vless: 15
223
+ trojan: 9
224
+ ```
225
+
226
+ **Rich CLI** version:
227
+
228
+ ```bash
229
+ v2ray-finder-rich -s
230
+ # Press Ctrl+C during fetch
231
+
232
+ ⚠ Interrupted by user
233
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
234
+ ✓ Saved 47 servers to v2ray_servers_partial.txt
235
+ ```
236
+
237
+ > 📖 **See detailed guide:** [docs/INTERRUPTION_GUIDE.md](docs/INTERRUPTION_GUIDE.md)
238
+
239
+ ---
240
+
241
+ ## 📚 Library Usage / استفاده به‌صورت کتابخانه
242
+
243
+ ```python
244
+ from v2ray_finder import V2RayServerFinder
245
+
246
+ finder = V2RayServerFinder()
247
+
248
+ # Fast: curated sources only
249
+ servers = finder.get_all_servers()
250
+ print(f"Total: {len(servers)}")
251
+
252
+ # Extended: curated + GitHub search
253
+ servers = finder.get_all_servers(use_github_search=True)
254
+
255
+ # Save to file
256
+ count, filename = finder.save_to_file(filename="v2ray_servers.txt", limit=200)
257
+ ```
258
+
259
+ ### Error Handling
260
+
261
+ ```python
262
+ from v2ray_finder import V2RayServerFinder, RateLimitError, NetworkError
263
+
264
+ # Method 1: Result type
265
+ result = finder.search_repos(keywords=["v2ray"])
266
+ if result.is_ok():
267
+ repos = result.unwrap()
268
+ else:
269
+ print(result.error)
270
+
271
+ # Method 2: Exception mode
272
+ finder = V2RayServerFinder(raise_errors=True)
273
+ try:
274
+ repos = finder.search_repos_or_empty()
275
+ except RateLimitError as e:
276
+ print(f"Rate limit: {e}")
277
+ ```
278
+
279
+ ### Health Checking
280
+
281
+ ```python
282
+ servers = finder.get_servers_with_health(
283
+ check_health=True,
284
+ health_timeout=5.0,
285
+ min_quality_score=60.0,
286
+ filter_unhealthy=True,
287
+ )
288
+ for s in servers[:10]:
289
+ print(f"{s['protocol']:8s} | Quality: {s['quality_score']:5.1f} | {s['latency_ms']:6.1f}ms")
290
+ ```
291
+
292
+ ---
293
+
294
+ ## ⚡ CLI Usage / استفاده از CLI
295
+
296
+ ### Basic CLI
297
+
298
+ ```bash
299
+ export GITHUB_TOKEN="ghp_your_token_here"
300
+
301
+ v2ray-finder # Interactive TUI
302
+ v2ray-finder -o servers.txt # Quick save
303
+ v2ray-finder -s -l 200 -o servers.txt # GitHub search + limit
304
+ v2ray-finder --stats-only # Stats only
305
+ v2ray-finder --prompt-token -s # Secure token input
306
+ ```
307
+
308
+ **With health checking:**
309
+
310
+ ```bash
311
+ v2ray-finder -c --min-quality 60 -o healthy_servers.txt
312
+ ```
313
+
314
+ ### Rich CLI (Recommended)
315
+
316
+ ```bash
317
+ pip install "v2ray-finder[cli-rich]"
318
+ v2ray-finder-rich # Beautiful Rich TUI
319
+ v2ray-finder-rich --prompt-token # With secure token prompt
320
+ ```
321
+
322
+ **Interactive mode features:**
323
+ - Token prompt on first run (if not in env)
324
+ - Press Ctrl+C during fetch → saves partial results
325
+ - Visual progress bars and spinners
326
+ - Color-coded health status
327
+
328
+ ---
329
+
330
+ ## 🖥️ GUI / رابط گرافیکی
331
+
332
+ ```bash
333
+ pip install "v2ray-finder[gui]"
334
+ v2ray-finder-gui
335
+ ```
336
+
337
+ ---
338
+
339
+ ## 🛠️ Advanced Usage
340
+
341
+ ### Interruption in Scripts
342
+
343
+ ```bash
344
+ #!/bin/bash
345
+
346
+ v2ray-finder -s -o servers.txt
347
+ exit_code=$?
348
+
349
+ if [ $exit_code -eq 0 ]; then
350
+ echo "Success!"
351
+ # Process servers.txt
352
+ elif [ $exit_code -eq 130 ]; then
353
+ echo "Interrupted - using partial results"
354
+ mv v2ray_servers_partial.txt servers.txt
355
+ else
356
+ echo "Error occurred"
357
+ exit 1
358
+ fi
359
+ ```
360
+
361
+ ### CI/CD with Timeout
362
+
363
+ ```bash
364
+ # Timeout after 2 minutes, use partial results
365
+ timeout 120 v2ray-finder -s -o servers.txt || {
366
+ if [ $? -eq 124 ]; then
367
+ mv v2ray_servers_partial.txt servers.txt
368
+ fi
369
+ }
370
+ ```
371
+
372
+ ---
373
+
374
+ ## 🤝 Contributing / مشارکت
375
+
376
+ ```bash
377
+ pytest tests/ -v
378
+ black . && isort . && flake8 src/
379
+ ```
380
+
381
+ ---
382
+
383
+ ## 📝 License
384
+
385
+ MIT License © 2026 Ali Sadeghi Aghili
386
+
387
+ ---
388
+
389
+ ## 🔗 Links
390
+
391
+ - [Repository](https://github.com/alisadeghiaghili/v2ray-finder)
392
+ - [PyPI](https://pypi.org/project/v2ray-finder)
393
+ - [Issues](https://github.com/alisadeghiaghili/v2ray-finder/issues)
394
+ - [CHANGELOG](CHANGELOG.md)
395
+ - [Interruption Guide](docs/INTERRUPTION_GUIDE.md)
396
+
397
+ ---
398
+
399
+ ## 🙏 Acknowledgments / تشکرات
400
+
401
+ - [ebrasha/free-v2ray-public-list](https://github.com/ebrasha/free-v2ray-public-list)
402
+ - [barry-far/V2ray-Config](https://github.com/barry-far/V2ray-Config)
403
+ - [Epodonios/v2ray-configs](https://github.com/Epodonios/v2ray-configs)
404
+
405
+ و تمامی توسعه‌دهندگانی که کانفیگ‌های آزاد منتشر می‌کنند ❤️