242 lines
5.6 KiB
Go
242 lines
5.6 KiB
Go
package main
|
||
|
||
import (
|
||
_ "embed"
|
||
"encoding/base64"
|
||
"encoding/json"
|
||
"fmt"
|
||
"log"
|
||
"os"
|
||
"path/filepath"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
//go:embed web/overlay.html
|
||
var overlayHTML string
|
||
|
||
//go:embed web/themes/aurora.html
|
||
var themeAurora string
|
||
|
||
//go:embed web/themes/starfield.html
|
||
var themeStarfield string
|
||
|
||
//go:embed web/themes/gradient.html
|
||
var themeGradient string
|
||
|
||
//go:embed web/themes/particles.html
|
||
var themeParticles string
|
||
|
||
//go:embed web/themes/fractal.html
|
||
var themeFractal string
|
||
|
||
//go:embed web/themes/text.html
|
||
var themeText string
|
||
|
||
var themeMap = map[ThemeName]string{
|
||
ThemeAurora: themeAurora,
|
||
ThemeStar: themeStarfield,
|
||
ThemeGradient: themeGradient,
|
||
ThemeParticle: themeParticles,
|
||
ThemeFractal: themeFractal,
|
||
ThemeText: themeText,
|
||
}
|
||
|
||
func buildWallpaperHTML(cfg *Config) string {
|
||
var bg string
|
||
|
||
if cfg.WallpaperType == WPTheme {
|
||
if t, ok := themeMap[cfg.Theme]; ok {
|
||
bg = t
|
||
} else {
|
||
bg = themeAurora
|
||
}
|
||
} else {
|
||
bg = buildBgHTML(cfg)
|
||
}
|
||
|
||
if bg == "" {
|
||
bg = themeAurora
|
||
}
|
||
bgWrapped := fmt.Sprintf(`<div id="bg-layer">%s</div>`, bg)
|
||
if cfg.HideWallpaper {
|
||
bgWrapped = `<div id="bg-layer" style="display:none"></div>`
|
||
}
|
||
html := strings.Replace(overlayHTML, "{{BACKGROUND}}", bgWrapped, 1)
|
||
html = strings.Replace(html, "{{LAYOUT}}", string(cfg.Layout), 1)
|
||
|
||
var bodyClasses []string
|
||
if cfg.HideTime {
|
||
bodyClasses = append(bodyClasses, "hide-time")
|
||
}
|
||
if cfg.HideWeather {
|
||
bodyClasses = append(bodyClasses, "hide-weather")
|
||
}
|
||
if cfg.HideZodiac {
|
||
bodyClasses = append(bodyClasses, "hide-zodiac")
|
||
}
|
||
showSec := "false"
|
||
if cfg.ShowSeconds {
|
||
showSec = "true"
|
||
}
|
||
html = strings.Replace(html, "{{SHOW_SECONDS}}", showSec, 1)
|
||
if cfg.HideAINews {
|
||
bodyClasses = append(bodyClasses, "hide-ainews")
|
||
}
|
||
if cfg.HideKnowledge {
|
||
bodyClasses = append(bodyClasses, "hide-knowledge")
|
||
}
|
||
if cfg.HidePhoto {
|
||
bodyClasses = append(bodyClasses, "hide-photo")
|
||
}
|
||
if cfg.PhotoFrameMode && cfg.PhotoDir != "" {
|
||
bodyClasses = append(bodyClasses, "photo-frame-mode")
|
||
}
|
||
if len(bodyClasses) > 0 {
|
||
cls := strings.Join(bodyClasses, " ")
|
||
html = strings.Replace(html, "{{BODY_CLASSES}}", cls, 1)
|
||
} else {
|
||
html = strings.Replace(html, " {{BODY_CLASSES}}", "", 1)
|
||
}
|
||
|
||
// 注入自定义文字
|
||
if cfg.WallpaperType == WPTheme && cfg.Theme == ThemeText && cfg.WallpaperText != "" {
|
||
escaped, _ := json.Marshal(cfg.WallpaperText)
|
||
html = strings.Replace(html, "</script>", `window.wallpaperText = `+string(escaped)+`;</script>`, 1)
|
||
}
|
||
|
||
return html
|
||
}
|
||
|
||
func imageToDataURI(path string) string {
|
||
data, err := os.ReadFile(path)
|
||
if err != nil {
|
||
log.Println("读取图片失败:", err)
|
||
return ""
|
||
}
|
||
ext := strings.ToLower(filepath.Ext(path))
|
||
mime := "image/jpeg"
|
||
switch ext {
|
||
case ".png":
|
||
mime = "image/png"
|
||
case ".gif":
|
||
mime = "image/gif"
|
||
case ".webp":
|
||
mime = "image/webp"
|
||
case ".bmp":
|
||
mime = "image/bmp"
|
||
}
|
||
return fmt.Sprintf("data:%s;base64,%s", mime, base64.StdEncoding.EncodeToString(data))
|
||
}
|
||
|
||
func reloadWallpaper() {
|
||
if wv == nil || wvHwnd == 0 {
|
||
return
|
||
}
|
||
cfg := loadConfig()
|
||
|
||
// 非主题壁纸切换:仅替换 #bg-layer,不销毁卡片状态
|
||
if cfg.WallpaperType != WPTheme {
|
||
updateBackground(cfg)
|
||
return
|
||
}
|
||
|
||
// 主题切换需要 SetHtml(canvas+script),之后恢复卡片数据
|
||
html := buildWallpaperHTML(cfg)
|
||
select {
|
||
case htmlQueue <- html:
|
||
default:
|
||
}
|
||
procPostMessageW.Call(wvHwnd, wmSetHtml, 0, 0)
|
||
go reloadAllCards()
|
||
}
|
||
|
||
func buildBgHTML(cfg *Config) string {
|
||
switch cfg.WallpaperType {
|
||
case WPImage:
|
||
if cfg.ImagePath != "" {
|
||
src := imageToDataURI(cfg.ImagePath)
|
||
if src != "" {
|
||
return buildCoverImgHTML(src)
|
||
}
|
||
}
|
||
case WPBing:
|
||
if p := getCurrentBingPath(); p != "" {
|
||
if _, err := os.Stat(p); err == nil {
|
||
src := imageToDataURI(p)
|
||
if src != "" {
|
||
return buildCoverImgHTML(src)
|
||
}
|
||
}
|
||
}
|
||
case WPColor:
|
||
if cfg.ColorGradient && cfg.Color2 != "" {
|
||
return fmt.Sprintf(`<div style="position:fixed;top:0;left:0;width:100%%;height:100%%;z-index:1;background:linear-gradient(135deg,%s,%s);"></div>`, cfg.Color1, cfg.Color2)
|
||
}
|
||
return fmt.Sprintf(`<div style="position:fixed;top:0;left:0;width:100%%;height:100%%;z-index:1;background:%s;"></div>`, cfg.Color1)
|
||
}
|
||
return ""
|
||
}
|
||
|
||
const coverImgTpl = `<img src="%s" style="position:fixed;top:0;left:0;width:100%%;height:100%%;object-fit:cover;z-index:1;">`
|
||
|
||
func buildCoverImgHTML(src string) string {
|
||
return fmt.Sprintf(coverImgTpl, src)
|
||
}
|
||
|
||
func updateBackground(cfg *Config) {
|
||
bg := buildBgHTML(cfg)
|
||
if bg == "" {
|
||
return
|
||
}
|
||
display := ""
|
||
if cfg.HideWallpaper {
|
||
display = ` style="display:none"`
|
||
}
|
||
html := fmt.Sprintf(`<div id="bg-layer"%s>%s</div>`, display, bg)
|
||
evalJS(fmt.Sprintf(`var el=document.getElementById('bg-layer'); if(el){el.outerHTML=%q;}`, html))
|
||
}
|
||
|
||
func reloadAllCards() {
|
||
time.Sleep(800 * time.Millisecond)
|
||
|
||
evalJS(fmt.Sprintf(`window.userZodiac = %q;`, loadConfig().Zodiac))
|
||
|
||
if cached := loadHoroscopeCache(); cached != nil {
|
||
pushHoroscopeInfo(cached)
|
||
}
|
||
if cached := loadAINewsCache(); cached != nil {
|
||
pushAINews(cached)
|
||
}
|
||
cfg := loadConfig()
|
||
if cfg.KnowledgeKeyword != "" && !cfg.HideKnowledge {
|
||
if cached := getRandomKnowledgeCard(cfg.KnowledgeKeyword); cached != "" {
|
||
pushKnowledgeJSON(cached, cfg.KnowledgeKeyword)
|
||
}
|
||
}
|
||
if city := getCurrentCity(); city.ID != "" {
|
||
go fetchAndPushWeather(city)
|
||
}
|
||
if cfg.PhotoDir != "" && !cfg.HidePhoto {
|
||
go func() {
|
||
time.Sleep(500 * time.Millisecond)
|
||
pushCurrentPhoto(cfg.PhotoInterval)
|
||
}()
|
||
}
|
||
}
|
||
|
||
func bingReloadImage() {
|
||
if wv == nil || wvHwnd == 0 {
|
||
return
|
||
}
|
||
p := getCurrentBingPath()
|
||
if p == "" {
|
||
return
|
||
}
|
||
src := imageToDataURI(p)
|
||
if src == "" {
|
||
return
|
||
}
|
||
evalJS(fmt.Sprintf(`var bg=document.querySelector('#bg-layer img'); if(bg) bg.src=%q;`, src))
|
||
}
|