From 3bdd60703d6f22da06afcc3ec355b361def9c202 Mon Sep 17 00:00:00 2001 From: taynpg Date: Wed, 22 Jan 2025 16:22:28 +0800 Subject: [PATCH] =?UTF-8?q?add=EF=BC=9A=E8=87=AA=E5=B8=A6=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=8E=88=E6=9D=83=E4=BB=A4=E7=89=8C=EF=BC=8C=E5=90=A6?= =?UTF-8?q?=E5=88=99=E5=8F=AF=E8=83=BD=E6=97=A0=E6=B3=95=E8=AE=BF=E9=97=AE?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 104 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/main.go b/main.go index bafab3a..432e290 100644 --- a/main.go +++ b/main.go @@ -9,18 +9,16 @@ import ( "path/filepath" "runtime" "sort" - "strings" ) -// 仓库配置 -var repositories = []string{ - "https://www.sinxmiao.cn/taynpg/transm", - "https://www.sinxmiao.cn/taynpg/blank", - "https://www.sinxmiao.cn/taynpg/xp", - "https://www.sinxmiao.cn/taynpg/cmt", -} +// 站点配置 +var baseSiteURL = "https://www.sinxmiao.cn/" -const downloadDir = "./downloads/" // 下载路径 +// 下载路径 +const downloadDir = "./downloads/" + +// 令牌 +const apiToken = "a6d1d94a9d49e14a9a85dc1767a91d78c00249e6" // Release 结构体用于解析 API 返回的 JSON 数据 type Release struct { @@ -35,16 +33,27 @@ type Asset struct { BrowserDownloadURL string `json:"browser_download_url"` } -func main() { +// Repo 结构体用于解析仓库信息 +type Repo struct { + FullName string `json:"full_name"` +} +func main() { fmt.Printf("GOARCH: %s\n", runtime.GOARCH) fmt.Printf("GOOS: %s\n", runtime.GOOS) + // 获取所有公开仓库 + repositories, err := fetchRepositories(baseSiteURL) + if err != nil { + fmt.Printf("获取仓库信息失败: %v\n", err) + return + } + // 选择仓库 repo := chooseRepository(repositories) - apiURL := convertToAPIURL(repo) - // 获取所有版本信息 + // 获取该仓库的所有版本信息 + apiURL := convertToAPIURL(repo) releases, err := fetchReleases(apiURL) if err != nil { fmt.Printf("获取发行版信息失败: %v\n", err) @@ -72,19 +81,55 @@ func main() { } } +// fetchRepositories 获取站点下的所有仓库 +func fetchRepositories(baseURL string) ([]Repo, error) { + client := createHTTPClient() + + page := 1 + limit := 200 + url := fmt.Sprintf("%sapi/v1/user/repos?page=%d&limit=%d", baseURL, page, limit) + + resp, err := client.Get(url) + if err != nil { + return nil, fmt.Errorf("请求仓库列表失败: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("API 响应状态码: %d", resp.StatusCode) + } + + var repos []Repo + if err := json.NewDecoder(resp.Body).Decode(&repos); err != nil { + return nil, fmt.Errorf("解析仓库列表失败: %v", err) + } + + // 筛选有附件的仓库 + var validRepos []Repo + for _, repo := range repos { + apiURL := convertToAPIURL(repo.FullName) + releases, err := fetchReleases(apiURL) + if err == nil && len(releases) > 0 { + validRepos = append(validRepos, repo) + } + } + + return validRepos, nil +} + // chooseRepository 选择仓库 -func chooseRepository(repositories []string) string { +func chooseRepository(repositories []Repo) string { for { fmt.Println("可用的仓库:") for i, repo := range repositories { - fmt.Printf("[%d] %s\n", i+1, repo[strings.LastIndex(repo, "/")+1:]) + fmt.Printf("[%d] %s\n", i+1, repo.FullName) } fmt.Print("请选择一个仓库 (输入编号): ") var choice int _, err := fmt.Scan(&choice) if err == nil && choice > 0 && choice <= len(repositories) { - return repositories[choice-1] + return repositories[choice-1].FullName } fmt.Println("无效的选择,请重新输入。") } @@ -92,13 +137,13 @@ func chooseRepository(repositories []string) string { // convertToAPIURL 将仓库链接转换为 API 地址 func convertToAPIURL(repo string) string { - // 将仓库链接转换为 Gitea API 地址 - return strings.Replace(repo, "https://www.sinxmiao.cn", "https://www.sinxmiao.cn/api/v1/repos", 1) + "/releases" + return baseSiteURL + "api/v1/repos/" + repo + "/releases" } // fetchReleases 获取所有版本信息 func fetchReleases(apiURL string) ([]Release, error) { - resp, err := http.Get(apiURL) + client := createHTTPClient() + resp, err := client.Get(apiURL) if err != nil { return nil, fmt.Errorf("请求 API 失败: %v", err) } @@ -184,3 +229,26 @@ func downloadFile(url, filePath string) error { return nil } + +// createHTTPClient 创建带有 Authorization 头的 HTTP 客户端 +func createHTTPClient() *http.Client { + client := &http.Client{} + return &http.Client{ + Transport: &transportWithAuth{ + base: client.Transport, + }, + } +} + +type transportWithAuth struct { + base http.RoundTripper +} + +func (t *transportWithAuth) RoundTrip(req *http.Request) (*http.Response, error) { + if t.base == nil { + t.base = http.DefaultTransport + } + + req.Header.Set("Authorization", "token "+apiToken) + return t.base.RoundTrip(req) +}