- tools/scripts/llm-key-hunter: GitHub leak hunting pipeline (hunt_*, pivot miner, two-layer verify/content caches, per-provider verification) - usable_keys: verified key vault across 12 providers (deepseek, minimax, volcanoark, longcat, codingplan, zhipu free-tier, mimo, siliconflow, etc.) - .grok/skills/llm-key-hunter: operator skill for the hunt/verify/vault flow - NewAPI channel import scripts and CDP capture helpers - Result verdict buckets (excluding multi-GB blob caches and dedup dumps)
86 lines
2.8 KiB
Python
86 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Test & prune channels just added by add_hunted_channels.py.
|
|
|
|
- Deletes obvious placeholder/fake channels (e.g. Kimi_aaaaaa).
|
|
- Tests every channel whose name starts with FreeModel_/DeepSeek_/Kimi_.
|
|
- Disables (status=2) any that fail testing so they don't break routing.
|
|
- Prints a summary of live channels.
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
from newapi_client import (
|
|
get_channel, delete_channel, update_channel, test_channel,
|
|
)
|
|
|
|
PREFIXES = ("FreeModel_", "DeepSeek_", "Kimi_")
|
|
FAKE_NAMES = {"Kimi_aaaaaa", "Kimi_QRSTUV"}
|
|
|
|
|
|
def fetch_all(max_id=525):
|
|
channels = []
|
|
with ThreadPoolExecutor(max_workers=20) as pool:
|
|
futs = {pool.submit(get_channel, cid): cid for cid in range(113, max_id + 1)}
|
|
for fut in as_completed(futs):
|
|
ch = fut.result()
|
|
if ch and ch.get("id"):
|
|
channels.append(ch)
|
|
channels.sort(key=lambda c: c["id"])
|
|
return channels
|
|
|
|
|
|
def main():
|
|
chs = fetch_all()
|
|
print(f"Loaded {len(chs)} channels with ID >= 113")
|
|
|
|
# Prune fakes
|
|
for ch in chs:
|
|
if ch["name"] in FAKE_NAMES:
|
|
ok, msg = delete_channel(ch["id"])
|
|
print(f"[DELETE fake] ID={ch['id']} {ch['name']} -> {ok} {msg}")
|
|
chs = [c for c in chs if c["name"] not in FAKE_NAMES]
|
|
|
|
# Filter to newly-added hunted channels
|
|
targets = [c for c in chs if c["name"].startswith(PREFIXES)]
|
|
print(f"\nTesting {len(targets)} hunted channels...\n")
|
|
|
|
passed, failed = [], []
|
|
|
|
def run(ch):
|
|
ok, msg, t = test_channel(ch["id"], timeout=60)
|
|
return ch, ok, msg, t
|
|
|
|
with ThreadPoolExecutor(max_workers=15) as pool:
|
|
futs = {pool.submit(run, c): c for c in targets}
|
|
for fut in as_completed(futs):
|
|
ch, ok, msg, t = fut.result()
|
|
if ok:
|
|
passed.append((ch, msg, t))
|
|
print(f" ✅ ID={ch['id']:3d} {ch['name']:40s} {msg[:80]}")
|
|
else:
|
|
# disable so it doesn't pollute routing
|
|
update_channel(ch["id"], status=2)
|
|
failed.append((ch, msg))
|
|
print(f" ❌ ID={ch['id']:3d} {ch['name']:40s} DISABLED — {msg[:80]}")
|
|
|
|
print("\n=== Summary ===")
|
|
print(f" Live: {len(passed)}")
|
|
print(f" Disabled: {len(failed)}")
|
|
|
|
# Show live by provider
|
|
by_prov = {}
|
|
for ch, msg, t in passed:
|
|
prov = ch["name"].split("_", 1)[0]
|
|
by_prov.setdefault(prov, []).append(ch)
|
|
for prov, items in sorted(by_prov.items()):
|
|
print(f"\n {prov} ({len(items)} live):")
|
|
for ch in items[:20]:
|
|
print(f" ID={ch['id']:3d} {ch['name']}")
|
|
if len(items) > 20:
|
|
print(f" ... and {len(items)-20} more")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|