mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-30 03:36:37 +08:00
feat: site management + cross-site torrent search
Port the complete site management system from the original MediaStation:
Model:
- model/model.go: Added Site table with fields for name, base_url,
site_type (nexusphp/gazelle/unit3d/mteam/custom_rss), auth_type
(cookie/api_key/authorization), cookie, api_key, auth_header,
user_agent, rss_url, timeout, priority, use_proxy, enabled,
login_status, downloader. Registered in AllModels().
Backend services:
- service/site.go: SiteService with CRUD (Create/List/FindByID/Update/
Delete), TestConnection (validates credentials via HTTP, updates
login_status in DB), and Search (cross-site fan-out that queries
every enabled site adapter and returns merged results sorted by
seeders descending).
- service/site_adapter.go: SiteAdapter interface + NewSiteAdapter
factory + 5 implementations:
* nexusPhpAdapter — regex HTML scraping of torrents.php
* gazelleAdapter — JSON API /ajax.php?action=browse
* unit3dAdapter — REST API /api/torrents/filter
* mteamAdapter — M-Team v3 POST /api/torrent/search with x-api-key
* rssAdapter — XML RSS/Atom feed parsing with keyword filter
Handler + routes:
- handler/sites.go: listSites, getSite, createSite, updateSite,
deleteSite, testSite, siteSearch handlers.
- handler/handler.go: 7 new routes under authed group:
GET/POST /sites, GET/PUT/DELETE /sites/:id,
POST /sites/:id/test, GET /sites/search.
Frontend:
- api/sites.ts: typed interfaces (Site, SiteSearchResult,
CreateSiteInput) and sitesAPI helper.
- pages/SitesPage.tsx: full CRUD UI with add-site form (site_type +
auth_type selectors, cookie/api_key/rss inputs), connection test
button with live status indicator, delete action.
- pages/SiteSearchPage.tsx: cross-site search with keyword input,
merged result table (site/title/size/seeders/leechers/free),
one-click download-to-qBittorrent button.
- App.tsx: lazy-loaded routes /sites and /site-search.
- Layout.tsx: sidebar links 站点管理 + 站点搜索 under 自动化 group.
Verified: go build + go vet + go test pass; tsc -b + vite build passes
(32 lazy chunks, main bundle 255 KB / 85 KB gzipped).
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { api } from './client'
|
||||
|
||||
export interface Site {
|
||||
id: string
|
||||
name: string
|
||||
base_url: string
|
||||
site_type: string
|
||||
auth_type: string
|
||||
cookie?: string
|
||||
api_key?: string
|
||||
auth_header?: string
|
||||
user_agent?: string
|
||||
rss_url?: string
|
||||
timeout: number
|
||||
priority: number
|
||||
use_proxy: boolean
|
||||
enabled: boolean
|
||||
login_status: string
|
||||
downloader?: string
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface SiteSearchResult {
|
||||
site_name: string
|
||||
site_id: string
|
||||
title: string
|
||||
torrent_url: string
|
||||
download_url: string
|
||||
size: number
|
||||
seeders: number
|
||||
leechers: number
|
||||
free: boolean
|
||||
}
|
||||
|
||||
export interface CreateSiteInput {
|
||||
name: string
|
||||
base_url: string
|
||||
site_type?: string
|
||||
auth_type?: string
|
||||
cookie?: string
|
||||
api_key?: string
|
||||
auth_header?: string
|
||||
user_agent?: string
|
||||
rss_url?: string
|
||||
timeout?: number
|
||||
priority?: number
|
||||
use_proxy?: boolean
|
||||
enabled?: boolean
|
||||
downloader?: string
|
||||
}
|
||||
|
||||
export const sitesAPI = {
|
||||
list: () => api.get<{ items: Site[] }>('/sites').then((r) => r.data.items),
|
||||
|
||||
get: (id: string) => api.get<Site>(`/sites/${id}`).then((r) => r.data),
|
||||
|
||||
create: (input: CreateSiteInput) =>
|
||||
api.post<Site>('/sites', input).then((r) => r.data),
|
||||
|
||||
update: (id: string, patch: Partial<CreateSiteInput>) =>
|
||||
api.put<Site>(`/sites/${id}`, patch).then((r) => r.data),
|
||||
|
||||
remove: (id: string) => api.delete(`/sites/${id}`).then((r) => r.data),
|
||||
|
||||
test: (id: string) =>
|
||||
api
|
||||
.post<{ success: boolean; message: string }>(`/sites/${id}/test`)
|
||||
.then((r) => r.data),
|
||||
|
||||
search: (keyword: string) =>
|
||||
api
|
||||
.get<{ items: SiteSearchResult[]; total: number }>('/sites/search', {
|
||||
params: { keyword },
|
||||
})
|
||||
.then((r) => r.data),
|
||||
}
|
||||
Reference in New Issue
Block a user