Spaces:
Running
Running
nacho commited on
Commit ·
594e4c0
1
Parent(s): 091565f
chore: 清理 dead code,更新面板支持 JSON 导入,补全 .env.example,修复 Actions checkout v5
Browse files- .env.example +17 -1
- .github/workflows/sync_to_hf.yml +1 -1
- account_manager.py +1 -2
- main.py +0 -1
- static/index.html +25 -7
.env.example
CHANGED
|
@@ -11,8 +11,24 @@ DS2API_KEYS=sk-test123456
|
|
| 11 |
# 管理员密钥
|
| 12 |
DS2API_ADMIN_KEY=admin
|
| 13 |
|
| 14 |
-
# 服务端口
|
| 15 |
DS2API_PORT=5001
|
|
|
|
| 16 |
|
| 17 |
# 无头浏览器模式
|
| 18 |
DS2API_HEADLESS=true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
# 管理员密钥
|
| 12 |
DS2API_ADMIN_KEY=admin
|
| 13 |
|
| 14 |
+
# 服务端口与监听地址
|
| 15 |
DS2API_PORT=5001
|
| 16 |
+
DS2API_HOST=0.0.0.0
|
| 17 |
|
| 18 |
# 无头浏览器模式
|
| 19 |
DS2API_HEADLESS=true
|
| 20 |
+
|
| 21 |
+
# 真人行为模拟
|
| 22 |
+
DS2API_HUMANIZE=true
|
| 23 |
+
|
| 24 |
+
# 每账号最大并发请求数
|
| 25 |
+
DS2API_MAX_CONCURRENT=3
|
| 26 |
+
|
| 27 |
+
# 最大同时活跃浏览器数(= 最大并发数)
|
| 28 |
+
DS2API_MAX_ACTIVE_BROWSERS=50
|
| 29 |
+
|
| 30 |
+
# 请求超时(毫秒)
|
| 31 |
+
DS2API_TIMEOUT=60000
|
| 32 |
+
|
| 33 |
+
# 全局代理(可选)
|
| 34 |
+
# DS2API_DEFAULT_PROXY=http://127.0.0.1:7890
|
.github/workflows/sync_to_hf.yml
CHANGED
|
@@ -10,7 +10,7 @@ jobs:
|
|
| 10 |
runs-on: ubuntu-latest
|
| 11 |
steps:
|
| 12 |
- name: Checkout repository
|
| 13 |
-
uses: actions/checkout@
|
| 14 |
with:
|
| 15 |
fetch-depth: 0
|
| 16 |
lfs: true
|
|
|
|
| 10 |
runs-on: ubuntu-latest
|
| 11 |
steps:
|
| 12 |
- name: Checkout repository
|
| 13 |
+
uses: actions/checkout@v5
|
| 14 |
with:
|
| 15 |
fetch-depth: 0
|
| 16 |
lfs: true
|
account_manager.py
CHANGED
|
@@ -27,10 +27,9 @@ class Account:
|
|
| 27 |
|
| 28 |
|
| 29 |
class AccountManager:
|
| 30 |
-
def __init__(self,
|
| 31 |
self.accounts: Dict[str, Account] = {}
|
| 32 |
self.queue: deque = deque()
|
| 33 |
-
self.max_inflight = max_inflight
|
| 34 |
self.max_active_browsers = max_active_browsers
|
| 35 |
self._lock = asyncio.Lock()
|
| 36 |
|
|
|
|
| 27 |
|
| 28 |
|
| 29 |
class AccountManager:
|
| 30 |
+
def __init__(self, max_active_browsers: int = 3):
|
| 31 |
self.accounts: Dict[str, Account] = {}
|
| 32 |
self.queue: deque = deque()
|
|
|
|
| 33 |
self.max_active_browsers = max_active_browsers
|
| 34 |
self._lock = asyncio.Lock()
|
| 35 |
|
main.py
CHANGED
|
@@ -70,7 +70,6 @@ app.add_middleware(
|
|
| 70 |
|
| 71 |
config: Config = load_config()
|
| 72 |
manager = AccountManager(
|
| 73 |
-
max_inflight=2,
|
| 74 |
max_active_browsers=int(os.getenv("DS2API_MAX_ACTIVE_BROWSERS", "50")),
|
| 75 |
)
|
| 76 |
|
|
|
|
| 70 |
|
| 71 |
config: Config = load_config()
|
| 72 |
manager = AccountManager(
|
|
|
|
| 73 |
max_active_browsers=int(os.getenv("DS2API_MAX_ACTIVE_BROWSERS", "50")),
|
| 74 |
)
|
| 75 |
|
static/index.html
CHANGED
|
@@ -266,8 +266,8 @@ select{cursor:pointer;appearance:none;background-image:url("data:image/svg+xml,%
|
|
| 266 |
<h2><span class="icon">📥</span> 导入账号</h2>
|
| 267 |
</div>
|
| 268 |
<div class="card-body">
|
| 269 |
-
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px">
|
| 270 |
-
<textarea id="inp" placeholder="user@gmail.com
|
| 271 |
<div class="row" style="margin-top:12px">
|
| 272 |
<button class="btn btn-primary" onclick="doImport()">▸ 导入</button>
|
| 273 |
<span id="msg" style="font-size:11px;color:var(--text-dim)"></span>
|
|
@@ -563,12 +563,30 @@ async function doImport(){
|
|
| 563 |
const v=document.getElementById('inp').value.trim();
|
| 564 |
if(!v)return toast('请输入账号',0);
|
| 565 |
const accts=[];
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
| 569 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 570 |
}
|
| 571 |
-
if(!accts.length)return toast('
|
| 572 |
try{
|
| 573 |
const d=await api('/admin/accounts/import',{
|
| 574 |
method:'POST',json:true,
|
|
|
|
| 266 |
<h2><span class="icon">📥</span> 导入账号</h2>
|
| 267 |
</div>
|
| 268 |
<div class="card-body">
|
| 269 |
+
<div style="font-size:11px;color:var(--text-dim);margin-bottom:8px">支持 JSON 或 邮箱:密码[:备注] 格式,每行一个</div>
|
| 270 |
+
<textarea id="inp" placeholder="[ {"email":"user@gmail.com","password":"xxx"}, {"email":"user2@gmail.com","password":"xxx","name":"备注"} ]" style="min-height:110px"></textarea>
|
| 271 |
<div class="row" style="margin-top:12px">
|
| 272 |
<button class="btn btn-primary" onclick="doImport()">▸ 导入</button>
|
| 273 |
<span id="msg" style="font-size:11px;color:var(--text-dim)"></span>
|
|
|
|
| 563 |
const v=document.getElementById('inp').value.trim();
|
| 564 |
if(!v)return toast('请输入账号',0);
|
| 565 |
const accts=[];
|
| 566 |
+
// 自动检测:JSON 格式 vs 文本格式
|
| 567 |
+
if(/^\s*[\[{]/.test(v)){
|
| 568 |
+
try{
|
| 569 |
+
let parsed=JSON.parse(v);
|
| 570 |
+
if(Array.isArray(parsed)){
|
| 571 |
+
for(const a of parsed){
|
| 572 |
+
if(a.email&&a.password)accts.push({email:a.email.trim(),password:a.password,name:a.name||'',proxy:a.proxy||''});
|
| 573 |
+
}
|
| 574 |
+
}else if(parsed.accounts&&Array.isArray(parsed.accounts)){
|
| 575 |
+
for(const a of parsed.accounts){
|
| 576 |
+
if(a.email&&a.password)accts.push({email:a.email.trim(),password:a.password,name:a.name||'',proxy:a.proxy||''});
|
| 577 |
+
}
|
| 578 |
+
}else if(parsed.email&&parsed.password){
|
| 579 |
+
accts.push({email:parsed.email.trim(),password:parsed.password,name:parsed.name||'',proxy:parsed.proxy||''});
|
| 580 |
+
}
|
| 581 |
+
}catch(e){return toast('JSON 解析失败: '+e.message,0)}
|
| 582 |
+
}else{
|
| 583 |
+
for(const l of v.split('\n')){
|
| 584 |
+
const t=l.trim();if(!t)continue;
|
| 585 |
+
const p=t.split(':',4);
|
| 586 |
+
if(p.length>=2)accts.push({email:p[0].trim(),password:p[1],name:p[2]||'',proxy:p[3]||''});
|
| 587 |
+
}
|
| 588 |
}
|
| 589 |
+
if(!accts.length)return toast('未识别到有效账号',0);
|
| 590 |
try{
|
| 591 |
const d=await api('/admin/accounts/import',{
|
| 592 |
method:'POST',json:true,
|