Files
u-desktop/wallpaper.go

242 lines
5.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
// 主题切换需要 SetHtmlcanvas+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))
}