新增: 星座运势+AI资讯+知识卡片+桌面设置窗口+秒显示开关
- 星座运势: 天聚数行API集成,5维进度条+幸运标签+今日概述 - AI资讯: 天聚数行API,图文布局5条展示,文件缓存2小时刷新 - 知识卡片: AI生成,关键字+提示词配置,30分钟刷新 - 桌面设置: 独立WebView2窗口,760x1350,含壁纸/布局/城市/颜色等配置 - 显示控制: 壁纸/时间/天气/星座/知识/AI资讯独立开关,秒显示开关 - 文件缓存: 星座运势+AI资讯缓存到本地,启动即显示上次数据 - initDone防抖: 防止设置窗口初始化触发卡片重载
This commit is contained in:
226
bing.go
226
bing.go
@@ -7,12 +7,13 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const bingAPI = "https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=8&mkt=zh-CN"
|
||||
const bingAPIBase = "https://www.bing.com/HPImageArchive.aspx?format=js&n=8&mkt=zh-CN"
|
||||
|
||||
type bingResponse struct {
|
||||
Images []struct {
|
||||
@@ -67,80 +68,82 @@ func fetchBingHistory() {
|
||||
bingMu.Lock()
|
||||
defer bingMu.Unlock()
|
||||
|
||||
resp, err := httpClient.Get(bingAPI)
|
||||
if err != nil {
|
||||
log.Println("Bing API 请求失败:", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var br bingResponse
|
||||
if json.Unmarshal(data, &br) != nil || len(br.Images) == 0 {
|
||||
log.Println("Bing API 解析失败")
|
||||
return
|
||||
}
|
||||
|
||||
os.MkdirAll(bingDir(), 0755)
|
||||
|
||||
existing := loadBingHistory()
|
||||
existingMap := make(map[string]BingRecord)
|
||||
for _, r := range existing.Records {
|
||||
existingMap[r.Date] = r
|
||||
}
|
||||
|
||||
for _, img := range br.Images {
|
||||
date := img.StartDate
|
||||
if date == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := existingMap[date]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
imgURL := img.URL
|
||||
if !strings.HasPrefix(imgURL, "http") {
|
||||
imgURL = "https://www.bing.com" + imgURL
|
||||
}
|
||||
|
||||
imgResp, err := httpClient.Get(imgURL)
|
||||
// 分页下载: idx=0,8,16... 直到命中已有记录或无新图片
|
||||
for idx := 0; idx < 80; idx += 8 {
|
||||
url := fmt.Sprintf("%s&idx=%d", bingAPIBase, idx)
|
||||
resp, err := httpClient.Get(url)
|
||||
if err != nil {
|
||||
log.Printf("Bing 图片下载失败 (%s): %v", date, err)
|
||||
continue
|
||||
log.Printf("Bing API 请求失败 (idx=%d): %v", idx, err)
|
||||
break
|
||||
}
|
||||
imgData, _ := io.ReadAll(imgResp.Body)
|
||||
imgResp.Body.Close()
|
||||
if len(imgData) == 0 {
|
||||
continue
|
||||
data, _ := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
var br bingResponse
|
||||
if json.Unmarshal(data, &br) != nil || len(br.Images) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
filename := date + ".jpg"
|
||||
localPath := filepath.Join(bingDir(), filename)
|
||||
if err := os.WriteFile(localPath, imgData, 0644); err != nil {
|
||||
log.Printf("Bing 图片保存失败 (%s): %v", date, err)
|
||||
continue
|
||||
}
|
||||
log.Printf("Bing 壁纸已下载: %s (%d bytes)", filename, len(imgData))
|
||||
newCount := 0
|
||||
for _, img := range br.Images {
|
||||
date := img.StartDate
|
||||
if date == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := existingMap[date]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
existingMap[date] = BingRecord{
|
||||
Date: date,
|
||||
URLBase: img.URLBase,
|
||||
Copyright: img.Copyright,
|
||||
Filename: filename,
|
||||
imgURL := img.URL
|
||||
if !strings.HasPrefix(imgURL, "http") {
|
||||
imgURL = "https://www.bing.com" + imgURL
|
||||
}
|
||||
|
||||
imgResp, err := httpClient.Get(imgURL)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
imgData, _ := io.ReadAll(imgResp.Body)
|
||||
imgResp.Body.Close()
|
||||
if len(imgData) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
filename := date + ".jpg"
|
||||
localPath := filepath.Join(bingDir(), filename)
|
||||
os.WriteFile(localPath, imgData, 0644)
|
||||
log.Printf("Bing 壁纸已下载: %s (%d bytes)", filename, len(imgData))
|
||||
|
||||
existingMap[date] = BingRecord{
|
||||
Date: date,
|
||||
URLBase: img.URLBase,
|
||||
Copyright: img.Copyright,
|
||||
Filename: filename,
|
||||
}
|
||||
newCount++
|
||||
}
|
||||
|
||||
if newCount == 0 && idx > 0 {
|
||||
break
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
// 按 API 返回顺序重建 records (newest first)
|
||||
// 用 existingMap 里所有记录按 date 降序排列
|
||||
var records []BingRecord
|
||||
for _, img := range br.Images {
|
||||
if r, ok := existingMap[img.StartDate]; ok {
|
||||
records = append(records, r)
|
||||
}
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return
|
||||
for _, r := range existingMap {
|
||||
records = append(records, r)
|
||||
}
|
||||
sort.Slice(records, func(i, j int) bool {
|
||||
return records[i].Date > records[j].Date
|
||||
})
|
||||
|
||||
history := &BingHistory{
|
||||
Records: records,
|
||||
@@ -151,6 +154,7 @@ func fetchBingHistory() {
|
||||
}
|
||||
saveBingHistory(history)
|
||||
|
||||
log.Printf("Bing 壁纸: 共 %d 张", len(records))
|
||||
reloadWallpaper()
|
||||
}
|
||||
|
||||
@@ -178,12 +182,10 @@ func bingPrev() {
|
||||
if len(h.Records) == 0 {
|
||||
return
|
||||
}
|
||||
if h.CurrentIdx < len(h.Records)-1 {
|
||||
h.CurrentIdx++
|
||||
saveBingHistory(h)
|
||||
log.Printf("Bing 壁纸: 上一个 (idx=%d, date=%s)", h.CurrentIdx, h.Records[h.CurrentIdx].Date)
|
||||
reloadWallpaper()
|
||||
}
|
||||
h.CurrentIdx = (h.CurrentIdx + 1) % len(h.Records)
|
||||
saveBingHistory(h)
|
||||
log.Printf("Bing 壁纸: 上一个 (idx=%d, date=%s)", h.CurrentIdx, h.Records[h.CurrentIdx].Date)
|
||||
bingReloadImage()
|
||||
}
|
||||
|
||||
func bingNext() {
|
||||
@@ -191,12 +193,13 @@ func bingNext() {
|
||||
defer bingMu.Unlock()
|
||||
|
||||
h := loadBingHistory()
|
||||
if h.CurrentIdx > 0 {
|
||||
h.CurrentIdx--
|
||||
saveBingHistory(h)
|
||||
log.Printf("Bing 壁纸: 下一个 (idx=%d, date=%s)", h.CurrentIdx, h.Records[h.CurrentIdx].Date)
|
||||
reloadWallpaper()
|
||||
if len(h.Records) == 0 {
|
||||
return
|
||||
}
|
||||
h.CurrentIdx = (h.CurrentIdx - 1 + len(h.Records)) % len(h.Records)
|
||||
saveBingHistory(h)
|
||||
log.Printf("Bing 壁纸: 下一个 (idx=%d, date=%s)", h.CurrentIdx, h.Records[h.CurrentIdx].Date)
|
||||
bingReloadImage()
|
||||
}
|
||||
|
||||
func bingToggleFavorite() string {
|
||||
@@ -229,6 +232,67 @@ func bingCopyrightInfo() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func bingCurrentState() string {
|
||||
h := loadBingHistory()
|
||||
if h.CurrentIdx < 0 || h.CurrentIdx >= len(h.Records) {
|
||||
return `{"fav":false,"label":"☆","copyright":"","idx":0,"total":0}`
|
||||
}
|
||||
r := h.Records[h.CurrentIdx]
|
||||
label := "☆"
|
||||
if r.Favorited {
|
||||
label = "⭐"
|
||||
}
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"fav": r.Favorited,
|
||||
"label": label,
|
||||
"copyright": r.Copyright,
|
||||
"date": r.Date,
|
||||
"filename": r.Filename,
|
||||
"idx": h.CurrentIdx,
|
||||
"total": len(h.Records),
|
||||
})
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func bingFavoritesJSON() string {
|
||||
h := loadBingHistory()
|
||||
type favItem struct {
|
||||
Date string `json:"date"`
|
||||
Copyright string `json:"copyright"`
|
||||
Filename string `json:"filename"`
|
||||
Idx int `json:"idx"`
|
||||
}
|
||||
var favs []favItem
|
||||
for i, r := range h.Records {
|
||||
if r.Favorited {
|
||||
favs = append(favs, favItem{r.Date, r.Copyright, r.Filename, i})
|
||||
}
|
||||
}
|
||||
if favs == nil {
|
||||
favs = []favItem{}
|
||||
}
|
||||
data, _ := json.Marshal(favs)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func bingSetByIdx(idx int) string {
|
||||
bingMu.Lock()
|
||||
defer bingMu.Unlock()
|
||||
h := loadBingHistory()
|
||||
if idx < 0 || idx >= len(h.Records) {
|
||||
return bingCurrentState()
|
||||
}
|
||||
h.CurrentIdx = idx
|
||||
saveBingHistory(h)
|
||||
bingReloadImage()
|
||||
return bingCurrentState()
|
||||
}
|
||||
|
||||
func bingThumbDataURI(filename string) string {
|
||||
p := filepath.Join(bingDir(), filename)
|
||||
return imageToDataURI(p)
|
||||
}
|
||||
|
||||
func bingWallpaperLoop() {
|
||||
cfg := loadConfig()
|
||||
if cfg.WallpaperType == WPBing {
|
||||
@@ -240,11 +304,31 @@ func bingWallpaperLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(4 * time.Hour)
|
||||
// 定时切换壁纸 (1 小时间隔)
|
||||
ticker := time.NewTicker(1 * time.Hour)
|
||||
for range ticker.C {
|
||||
cfg := loadConfig()
|
||||
if cfg.WallpaperType != WPBing || !cfg.BingAutoRefresh {
|
||||
continue
|
||||
}
|
||||
h := loadBingHistory()
|
||||
if len(h.Records) <= 1 {
|
||||
continue
|
||||
}
|
||||
// 顺序切换到下一张
|
||||
nextIdx := (h.CurrentIdx + 1) % len(h.Records)
|
||||
h.CurrentIdx = nextIdx
|
||||
saveBingHistory(h)
|
||||
bingReloadImage()
|
||||
log.Printf("Bing 自动切换: idx=%d/%d", nextIdx, len(h.Records))
|
||||
}
|
||||
|
||||
// 定时拉取新壁纸 (4 小时间隔)
|
||||
fetchTicker := time.NewTicker(4 * time.Hour)
|
||||
for range fetchTicker.C {
|
||||
cfg := loadConfig()
|
||||
if cfg.WallpaperType == WPBing {
|
||||
fetchBingHistory()
|
||||
go fetchBingHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user