更新 main.go

This commit is contained in:
XOF
2025-12-17 01:35:10 +08:00
parent aa94af0925
commit 1611d40296

116
main.go
View File

@@ -3,6 +3,7 @@ package main
import ( import (
"crypto/md5" "crypto/md5"
"crypto/subtle" "crypto/subtle"
"encoding/json"
"fmt" "fmt"
"html/template" "html/template"
"io" "io"
@@ -21,6 +22,7 @@ const (
downloadDir = "./chrome_versions" downloadDir = "./chrome_versions"
checkInterval = 24 * time.Hour checkInterval = 24 * time.Hour
maxRetries = 3 maxRetries = 3
versionAPI = "https://versionhistory.googleapis.com/v1/chrome/platforms/win64/channels/stable/versions"
) )
var ( var (
@@ -28,7 +30,6 @@ var (
authEnabled bool authEnabled bool
port string port string
keepVersions int keepVersions int
chromeURL string
) )
type Version struct { type Version struct {
@@ -37,12 +38,20 @@ type Version struct {
Time time.Time Time time.Time
} }
type ChromeVersion struct {
Name string `json:"name"`
Version string `json:"version"`
}
type ChromeVersionResponse struct {
Versions []ChromeVersion `json:"versions"`
}
func init() { func init() {
authToken = getEnv("AUTH_TOKEN", "") authToken = getEnv("AUTH_TOKEN", "")
authEnabled = getEnv("AUTH_ENABLED", "false") == "true" || authToken != "" authEnabled = getEnv("AUTH_ENABLED", "false") == "true" || authToken != ""
port = getEnv("PORT", "8080") port = getEnv("PORT", "8080")
keepVersions, _ = strconv.Atoi(getEnv("KEEP_VERSIONS", "3")) keepVersions, _ = strconv.Atoi(getEnv("KEEP_VERSIONS", "3"))
chromeURL = getEnv("CHROME_URL", "https://dl.google.com/tag/s/appguid%3D%7B8A69D345-D564-463C-AFF1-A69D9E530F96%7D%26iid%3D%7B00000000-0000-0000-0000-000000000000%7D%26lang%3Dzh-CN%26browser%3D4%26usagestats%3D0%26appname%3DGoogle%2520Chrome%26needsadmin%3Dprefers%26ap%3Dx64-stable-statsdef_1%26installdataindex%3Dempty/chrome/install/ChromeStandaloneSetup64.exe")
} }
func getEnv(key, defaultValue string) string { func getEnv(key, defaultValue string) string {
@@ -56,7 +65,6 @@ func main() {
os.MkdirAll(downloadDir, 0755) os.MkdirAll(downloadDir, 0755)
log.Printf("Auth enabled: %v, Port: %s, Keep versions: %d", authEnabled, port, keepVersions) log.Printf("Auth enabled: %v, Port: %s, Keep versions: %d", authEnabled, port, keepVersions)
// 启动时立即检查一次
log.Println("Performing initial check...") log.Println("Performing initial check...")
checkAndDownload() checkAndDownload()
@@ -79,34 +87,86 @@ func monitor() {
} }
} }
func checkAndDownload() { func getLatestVersion() (string, error) {
var data []byte resp, err := http.Get(versionAPI)
var err error if err != nil {
return "", err
}
defer resp.Body.Close()
var versionResp ChromeVersionResponse
if err := json.NewDecoder(resp.Body).Decode(&versionResp); err != nil {
return "", err
}
if len(versionResp.Versions) == 0 {
return "", fmt.Errorf("no versions found")
}
return versionResp.Versions[0].Version, nil
}
func checkAndDownload() {
version, err := getLatestVersion()
if err != nil {
log.Printf("Failed to get latest version: %v", err)
return
}
log.Printf("Latest Chrome version: %s", version)
// 尝试多个可能的下载 URL 模式
urls := []string{
fmt.Sprintf("https://dl.google.com/release2/chrome/%%s_%s/%s_chrome_installer.exe", version, version),
fmt.Sprintf("https://dl.google.com/tag/s/appguid%%3D%%7B8A69D345-D564-463C-AFF1-A69D9E530F96%%7D%%26iid%%3D%%7B00000000-0000-0000-0000-000000000000%%7D%%26lang%%3Dzh-CN%%26browser%%3D4%%26usagestats%%3D0%%26appname%%3DGoogle%%2520Chrome%%26needsadmin%%3Dprefers%%26ap%%3Dx64-stable-statsdef_1%%26installdataindex%%3Dempty/chrome/install/ChromeStandaloneSetup64.exe"),
}
var data []byte
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
log.Printf("Redirecting to: %s", req.URL.String())
return nil
},
}
for _, urlPattern := range urls {
for i := 0; i < maxRetries; i++ { for i := 0; i < maxRetries; i++ {
resp, err := http.Get(chromeURL) url := urlPattern
if strings.Contains(url, "%s") {
// 跳过需要 hash 的 URL
continue
}
log.Printf("Trying URL: %s", url)
resp, err := client.Get(url)
if err != nil { if err != nil {
log.Printf("Attempt %d failed: %v", i+1, err) log.Printf("Attempt %d failed: %v", i+1, err)
time.Sleep(time.Duration(i+1) * 10 * time.Second) time.Sleep(time.Duration(i+1) * 10 * time.Second)
continue continue
} }
contentType := resp.Header.Get("Content-Type")
contentLength := resp.Header.Get("Content-Length")
log.Printf("Content-Type: %s, Content-Length: %s", contentType, contentLength)
data, err = io.ReadAll(resp.Body) data, err = io.ReadAll(resp.Body)
resp.Body.Close() resp.Body.Close()
if err == nil { if err == nil && len(data) > 10000000 && !strings.Contains(contentType, "text/html") {
break goto success
}
log.Printf("Attempt %d read failed: %v", i+1, err)
} }
if err != nil { log.Printf("Invalid response (size: %d bytes)", len(data))
log.Println("All retries failed") time.Sleep(time.Duration(i+1) * 10 * time.Second)
}
}
log.Println("All download attempts failed")
return return
}
success:
hash := fmt.Sprintf("%x", md5.Sum(data)) hash := fmt.Sprintf("%x", md5.Sum(data))
filename := fmt.Sprintf("chrome_%s_%s.exe", time.Now().Format("20060102"), hash[:8]) filename := fmt.Sprintf("chrome_%s_%s.exe", version, hash[:8])
filepath := filepath.Join(downloadDir, filename) filepath := filepath.Join(downloadDir, filename)
if _, err := os.Stat(filepath); err == nil { if _, err := os.Stat(filepath); err == nil {
@@ -192,14 +252,30 @@ func serveIndex(w http.ResponseWriter, r *http.Request) {
<h1>Chrome Offline Versions</h1> <h1>Chrome Offline Versions</h1>
<ul> <ul>
{{range .Versions}} {{range .Versions}}
<li><a href="/download/{{.Filename}}{{if $.Token}}?token={{$.Token}}{{end}}">{{.Filename}}</a> ({{.Size}} bytes, {{.Time.Format "2006-01-02 15:04"}})</li> <li><a href="/download/{{.Filename}}{{if $.Token}}?token={{$.Token}}{{end}}">{{.Filename}}</a> ({{printf "%.2f" .SizeMB}} MB, {{.Time.Format "2006-01-02 15:04"}})</li>
{{end}} {{end}}
</ul> </ul>
</body> </body>
</html> </html>
`)) `))
tmpl.Execute(w, struct {
Versions []Version type VersionDisplay struct {
Token string Filename string
}{versions, token}) SizeMB float64
Time time.Time
}
var displayVersions []VersionDisplay
for _, v := range versions {
displayVersions = append(displayVersions, VersionDisplay{
Filename: v.Filename,
SizeMB: float64(v.Size) / 1024 / 1024,
Time: v.Time,
})
}
tmpl.Execute(w, struct {
Versions []VersionDisplay
Token string
}{displayVersions, token})
} }