// ============================================================================ // poem.go — 随机古诗 // // 主窗口首个 Tab(笔记页)footer 内水平滚动显示一首随机古诗; // 数据来自 poetry.palemoky.com 的随机接口,颜色 / 字号 / 刷新间隔可配置。 // ============================================================================ package main import ( "encoding/json" "fmt" "net/http" "strings" "time" ) const ( PoemAPIURL = "https://poetry.palemoky.com/api/poems/random" // 随机古诗接口 DefaultPoemColor = "#c98a3a" // 默认文字颜色(深琥珀,暗底明显可读) DefaultPoemFontSize = 16 // 默认字号(px) DefaultPoemInterval = 60 // 默认随机换诗间隔(秒),0 表示不自动换 DefaultPoemSpeed = 18 // 默认滚动一轮时长(秒) ) // PoemConfig 古诗显示的配置 type PoemConfig struct { Enabled bool `json:"enabled"` // 是否启用古诗显示 Color string `json:"color"` // 文字颜色 FontSize int `json:"fontSize"` // 字号(px) TTS bool `json:"tts"` // 允许 TTS 阅读(显示朗读按钮) Interval int `json:"interval"` // 自动换诗间隔(秒),0 表示不自动换 Speed int `json:"speed"` // 滚动速度(秒/轮),即滚动一个文本周期所需秒数,越小越快 } // PoemData 一首古诗的完整数据(从接口解析) type PoemData struct { Title string `json:"title"` // 题目 Author string `json:"author"` // 作者 Dynasty string `json:"dynasty"` // 朝代 Content []string `json:"content"` // 每句诗(数组,按行显示) Type string `json:"type"` // 体裁,如 五言律诗 } // poemAPIResponse 接口返回的外层结构 type poemAPIResponse struct { Data struct { ID int `json:"id"` Title string `json:"title"` Content []string `json:"content"` Author struct { ID int `json:"id"` Name string `json:"name"` } `json:"author"` Dynasty struct { ID int `json:"id"` Name string `json:"name"` } `json:"dynasty"` Type struct { ID int `json:"id"` Name string `json:"name"` } `json:"type"` } `json:"data"` Lang string `json:"lang"` } // fetchRandomPoem 从接口拉取一首随机古诗;失败时返回错误 func fetchRandomPoem() (PoemData, error) { client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Get(PoemAPIURL) if err != nil { return PoemData{}, fmt.Errorf("请求古诗接口失败: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return PoemData{}, fmt.Errorf("古诗接口返回状态 %d", resp.StatusCode) } var out poemAPIResponse if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { return PoemData{}, fmt.Errorf("解析古诗数据失败: %w", err) } p := PoemData{ Title: strings.TrimSpace(out.Data.Title), Author: strings.TrimSpace(out.Data.Author.Name), Dynasty: strings.TrimSpace(out.Data.Dynasty.Name), Content: out.Data.Content, Type: strings.TrimSpace(out.Data.Type.Name), } if p.Title == "" && len(p.Content) == 0 { return PoemData{}, fmt.Errorf("古诗接口返回空数据") } return p, nil } // GetRandomPoem 返回一首随机古诗(供主窗口前端加载 / 手动刷新调用) func (s *SettingsService) GetRandomPoem() (PoemData, error) { return fetchRandomPoem() } // normalizePoemConfig 校正古诗配置:颜色默认、字号限制、间隔限制 func normalizePoemConfig(cfg PoemConfig) PoemConfig { if strings.TrimSpace(cfg.Color) == "" { cfg.Color = DefaultPoemColor } if cfg.FontSize < 12 || cfg.FontSize > 48 { cfg.FontSize = DefaultPoemFontSize } if cfg.Interval < 0 || cfg.Interval > 3600 { cfg.Interval = DefaultPoemInterval } if cfg.Speed < 5 || cfg.Speed > 120 { cfg.Speed = DefaultPoemSpeed } return cfg }