chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
|
|
@ -4,6 +4,9 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
|
||||
"telesrv/internal/seed/appearance"
|
||||
"telesrv/internal/seed/catalog"
|
||||
)
|
||||
|
||||
// NotifySettings returns default per-peer notification settings for empty first-phase accounts.
|
||||
|
|
@ -23,17 +26,6 @@ func NotifySettings() *tg.PeerNotifySettings {
|
|||
return settings
|
||||
}
|
||||
|
||||
// ReactionsNotifySettings returns conservative defaults for reaction notifications.
|
||||
func ReactionsNotifySettings() *tg.ReactionsNotifySettings {
|
||||
return &tg.ReactionsNotifySettings{
|
||||
MessagesNotifyFrom: &tg.ReactionNotificationsFromContacts{},
|
||||
StoriesNotifyFrom: &tg.ReactionNotificationsFromContacts{},
|
||||
PollVotesNotifyFrom: &tg.ReactionNotificationsFromContacts{},
|
||||
Sound: &tg.NotificationSoundDefault{},
|
||||
ShowPreviews: true,
|
||||
}
|
||||
}
|
||||
|
||||
func PrivacyRules(key tg.InputPrivacyKeyClass) *tg.AccountPrivacyRules {
|
||||
var rule tg.PrivacyRuleClass = &tg.PrivacyValueAllowAll{}
|
||||
switch key.(type) {
|
||||
|
|
@ -61,16 +53,176 @@ func Passkeys() *tg.AccountPasskeys {
|
|||
return &tg.AccountPasskeys{Passkeys: []tg.Passkey{}}
|
||||
}
|
||||
|
||||
func ContentSettings() *tg.AccountContentSettings {
|
||||
return &tg.AccountContentSettings{}
|
||||
}
|
||||
|
||||
func GlobalPrivacySettings() *tg.GlobalPrivacySettings {
|
||||
return &tg.GlobalPrivacySettings{}
|
||||
}
|
||||
|
||||
func AccountThemes() tg.AccountThemesClass {
|
||||
return &tg.AccountThemesNotModified{}
|
||||
const chatThemesHash int64 = 2026062501
|
||||
const uniqueGiftChatThemesHash int64 = 2026061201
|
||||
const wallPapersHash int64 = 2026062502
|
||||
const peerColorsHash = 2026061202
|
||||
const peerProfileColorsHash = 2026062801
|
||||
|
||||
// IsChatThemeEmoticon reports whether token is a known official chat theme emoticon.
|
||||
func IsChatThemeEmoticon(token string) bool {
|
||||
for _, ct := range appearance.Default().ChatThemes {
|
||||
if ct.Emoticon == token {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ChatThemes(hash int64) tg.AccountThemesClass {
|
||||
if hash == chatThemesHash {
|
||||
return &tg.AccountThemesNotModified{}
|
||||
}
|
||||
return &tg.AccountThemes{
|
||||
Hash: chatThemesHash,
|
||||
Themes: chatThemeList(),
|
||||
}
|
||||
}
|
||||
|
||||
// chatThemeList 用官方外观 catalog(appearancefetch 导出)的聊天主题。
|
||||
func chatThemeList() []tg.Theme {
|
||||
return catalogChatThemes(appearance.Default().ChatThemes)
|
||||
}
|
||||
|
||||
// catalogChatThemes 把官方聊天主题转成 tg.Theme。官方每个主题只带 classic+tinted 两组
|
||||
// settings,而 DrKLO 选择器丢弃 base-theme 设置 <4 的主题
|
||||
// (MediaDataController.generateEmojiPreviewThemes),故扩展到 telesrv 宣告的 5 个 base:
|
||||
// 浅色 base(classic/day/arctic)复用官方浅色设置,深色 base(tinted/night)复用官方深色设置。
|
||||
func catalogChatThemes(cts []appearance.ChatTheme) []tg.Theme {
|
||||
out := make([]tg.Theme, 0, len(cts))
|
||||
for i, ct := range cts {
|
||||
var light, dark *appearance.ThemeSettings
|
||||
for j := range ct.Settings {
|
||||
s := &ct.Settings[j]
|
||||
if s.BaseTheme == "tinted" || s.BaseTheme == "night" {
|
||||
if dark == nil {
|
||||
dark = s
|
||||
}
|
||||
} else if light == nil {
|
||||
light = s
|
||||
}
|
||||
}
|
||||
if light == nil {
|
||||
light = dark
|
||||
}
|
||||
if dark == nil {
|
||||
dark = light
|
||||
}
|
||||
if light == nil {
|
||||
continue
|
||||
}
|
||||
theme := tg.Theme{ID: ct.ID, AccessHash: ct.AccessHash, Slug: ct.Slug, Title: ct.Title}
|
||||
theme.SetForChat(true)
|
||||
if ct.Emoticon != "" {
|
||||
theme.SetEmoticon(ct.Emoticon)
|
||||
}
|
||||
theme.SetInstallsCount(1)
|
||||
settings := make([]tg.ThemeSettings, 0, len(chatThemeBaseThemes))
|
||||
for _, b := range chatThemeBaseThemes {
|
||||
src := light
|
||||
if b.dark {
|
||||
src = dark
|
||||
}
|
||||
settings = append(settings, catalogThemeSettings(*src, b.make()))
|
||||
}
|
||||
theme.SetSettings(settings)
|
||||
if i == 0 || ct.Default {
|
||||
theme.SetDefault(true)
|
||||
}
|
||||
out = append(out, theme)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func catalogThemeSettings(s appearance.ThemeSettings, base tg.BaseThemeClass) tg.ThemeSettings {
|
||||
ts := tg.ThemeSettings{BaseTheme: base, AccentColor: s.AccentColor}
|
||||
if s.OutboxAccentColor != 0 {
|
||||
ts.SetOutboxAccentColor(s.OutboxAccentColor)
|
||||
}
|
||||
if len(s.MessageColors) > 0 {
|
||||
ts.SetMessageColors(append([]int(nil), s.MessageColors...))
|
||||
}
|
||||
if s.Wallpaper.ID != 0 || s.Wallpaper.Document.ID != 0 {
|
||||
ts.SetWallpaper(seedWallPaper(s.Wallpaper))
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
// DefaultThemes serves the built-in chat theme catalog for account.getThemes.
|
||||
//
|
||||
// DrKLO's "Color theme" preview strip on the Chat Settings page
|
||||
// (DefaultThemesPreviewCell) is populated exclusively from account.getThemes
|
||||
// results flagged is_default=true — it does not consult account.getChatThemes.
|
||||
// A fresh client has no cached emoji themes and therefore sends getThemes with
|
||||
// hash 0; returning themesNotModified to that request leaves defaultEmojiThemes
|
||||
// empty, so the strip stays stuck on its FlickerLoadingView shimmer forever.
|
||||
// We return the same catalog as ChatThemes with every entry marked default so
|
||||
// the strip resolves into real preview cards.
|
||||
func DefaultThemes(hash int64) tg.AccountThemesClass {
|
||||
if hash == chatThemesHash {
|
||||
return &tg.AccountThemesNotModified{}
|
||||
}
|
||||
return &tg.AccountThemes{
|
||||
Hash: chatThemesHash,
|
||||
Themes: DefaultThemeList(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultThemeList 返回内置默认主题切片(全标 is_default=true)。account.getThemes
|
||||
// 把它与用户自定义主题合并(rpc 层),故单独暴露列表。
|
||||
func DefaultThemeList() []tg.Theme {
|
||||
themes := chatThemeList()
|
||||
for i := range themes {
|
||||
themes[i].SetDefault(true)
|
||||
}
|
||||
return themes
|
||||
}
|
||||
|
||||
func UniqueGiftChatThemes(hash int64) tg.AccountChatThemesClass {
|
||||
if hash == uniqueGiftChatThemesHash {
|
||||
return &tg.AccountChatThemesNotModified{}
|
||||
}
|
||||
return &tg.AccountChatThemes{
|
||||
Hash: uniqueGiftChatThemesHash,
|
||||
Themes: []tg.ChatThemeClass{},
|
||||
Chats: []tg.ChatClass{},
|
||||
Users: []tg.UserClass{},
|
||||
}
|
||||
}
|
||||
|
||||
// WallPapers returns the read-only default wallpaper catalog. User wallpaper
|
||||
// upload/save/install remains outside the current TDesktop compatibility scope.
|
||||
func WallPapers(hash int64) tg.AccountWallPapersClass {
|
||||
if hash == wallPapersHash {
|
||||
return &tg.AccountWallPapersNotModified{}
|
||||
}
|
||||
wallpapers := seedWallPapers()
|
||||
return &tg.AccountWallPapers{
|
||||
Hash: wallPapersHash,
|
||||
Wallpapers: wallpapers,
|
||||
}
|
||||
}
|
||||
|
||||
// chatThemeBaseThemes enumerates the base themes every emoji chat theme ships
|
||||
// settings for. The client matches a chat theme's settings to whichever base
|
||||
// theme the user currently runs, and DrKLO's theme picker only surfaces a chat
|
||||
// theme whose settings cover at least four base themes
|
||||
// (MediaDataController.generateEmojiPreviewThemes drops anything whose
|
||||
// items.size() < 4, one item per ThemeSettings). dark selects the bubble/accent
|
||||
// palette used for that base theme.
|
||||
var chatThemeBaseThemes = []struct {
|
||||
make func() tg.BaseThemeClass
|
||||
dark bool
|
||||
}{
|
||||
{func() tg.BaseThemeClass { return &tg.BaseThemeClassic{} }, false},
|
||||
{func() tg.BaseThemeClass { return &tg.BaseThemeDay{} }, false},
|
||||
{func() tg.BaseThemeClass { return &tg.BaseThemeArctic{} }, false},
|
||||
{func() tg.BaseThemeClass { return &tg.BaseThemeTinted{} }, true},
|
||||
{func() tg.BaseThemeClass { return &tg.BaseThemeNight{} }, true},
|
||||
}
|
||||
|
||||
func AutoDownloadSettings() *tg.AccountAutoDownloadSettings {
|
||||
|
|
@ -101,10 +253,6 @@ func DefaultGroupPhotoEmojis() tg.EmojiListClass {
|
|||
return &tg.EmojiList{Hash: 0, DocumentID: []int64{}}
|
||||
}
|
||||
|
||||
func ConnectedBots() *tg.AccountConnectedBots {
|
||||
return &tg.AccountConnectedBots{ConnectedBots: []tg.ConnectedBot{}, Users: []tg.UserClass{}}
|
||||
}
|
||||
|
||||
const availableReactionsHash = 20260602
|
||||
const emptyStickerSetHash = 20260602
|
||||
|
||||
|
|
@ -161,10 +309,7 @@ func availableReaction(reaction defaultReaction, index int) tg.AvailableReaction
|
|||
}
|
||||
}
|
||||
|
||||
func Stickers() tg.MessagesStickersClass {
|
||||
return &tg.MessagesStickersNotModified{}
|
||||
}
|
||||
|
||||
// Stickers 返回空的全量 messages.stickers。禁止回 stickersNotModified:DrKLO 对
|
||||
func StickerSet(req *tg.MessagesGetStickerSetRequest) tg.MessagesStickerSetClass {
|
||||
if req != nil && req.Hash == emptyStickerSetHash {
|
||||
return &tg.MessagesStickerSetNotModified{}
|
||||
|
|
@ -206,8 +351,23 @@ func StickerSet(req *tg.MessagesGetStickerSetRequest) tg.MessagesStickerSetClass
|
|||
}
|
||||
}
|
||||
|
||||
func EmojiGroups() tg.MessagesEmojiGroupsClass {
|
||||
return &tg.MessagesEmojiGroupsNotModified{}
|
||||
// EmojiGroups 返回 emoji 分类目录(客户端 emoji 面板顶部的主题快捷标签)。优先用 catalog
|
||||
// 固化的官方分组,未 seed 时回 NotModified(客户端保留本地/无分组)。icon_emoji_id 指向
|
||||
// custom-emoji 文档,本地缺该文档时分类图标回退占位,不影响分组与按词搜索。
|
||||
func EmojiGroups(hash int) tg.MessagesEmojiGroupsClass {
|
||||
groups, h := catalog.EmojiGroups()
|
||||
if len(groups) == 0 || hash == h {
|
||||
return &tg.MessagesEmojiGroupsNotModified{}
|
||||
}
|
||||
out := make([]tg.EmojiGroupClass, 0, len(groups))
|
||||
for _, g := range groups {
|
||||
out = append(out, &tg.EmojiGroup{Title: g.Title, IconEmojiID: g.IconEmojiID, Emoticons: g.Emoticons})
|
||||
}
|
||||
return &tg.MessagesEmojiGroups{Hash: h, Groups: out}
|
||||
}
|
||||
|
||||
func EmojiStatusGroups() tg.MessagesEmojiGroupsClass {
|
||||
return &tg.MessagesEmojiGroups{Hash: 0, Groups: []tg.EmojiGroupClass{}}
|
||||
}
|
||||
|
||||
func EmojiProfilePhotoGroups() tg.MessagesEmojiGroupsClass {
|
||||
|
|
@ -215,11 +375,20 @@ func EmojiProfilePhotoGroups() tg.MessagesEmojiGroupsClass {
|
|||
}
|
||||
|
||||
func AttachMenuBots() tg.AttachMenuBotsClass {
|
||||
return &tg.AttachMenuBotsNotModified{}
|
||||
return &tg.AttachMenuBots{
|
||||
Hash: 0,
|
||||
Bots: []tg.AttachMenuBot{},
|
||||
Users: []tg.UserClass{},
|
||||
}
|
||||
}
|
||||
|
||||
func QuickReplies() tg.MessagesQuickRepliesClass {
|
||||
return &tg.MessagesQuickRepliesNotModified{}
|
||||
return &tg.MessagesQuickReplies{
|
||||
QuickReplies: []tg.QuickReply{},
|
||||
Messages: []tg.MessageClass{},
|
||||
Chats: []tg.ChatClass{},
|
||||
Users: []tg.UserClass{},
|
||||
}
|
||||
}
|
||||
|
||||
func TopPeers() tg.ContactsTopPeersClass {
|
||||
|
|
@ -234,8 +403,93 @@ func BlockedContacts() tg.ContactsBlockedClass {
|
|||
}
|
||||
}
|
||||
|
||||
func PeerColors() tg.HelpPeerColorsClass {
|
||||
return &tg.HelpPeerColorsNotModified{}
|
||||
type defaultPeerColor struct {
|
||||
id int
|
||||
light []int
|
||||
dark []int
|
||||
bg []int
|
||||
story []int
|
||||
hidden bool
|
||||
}
|
||||
|
||||
var defaultPeerColors = []defaultPeerColor{
|
||||
{id: 0, light: []int{0xcc4d4d}, dark: []int{0xff7a7a}, bg: []int{0xffd6d6, 0xfff0f0}, story: []int{0xff7a7a, 0xf24b4b}},
|
||||
{id: 1, light: []int{0xd97829}, dark: []int{0xffa15c}, bg: []int{0xffdfbd, 0xfff2e2}, story: []int{0xffa15c, 0xf07a2b}},
|
||||
{id: 2, light: []int{0x8756d9}, dark: []int{0xb38cff}, bg: []int{0xe3d8ff, 0xf4eeff}, story: []int{0xb38cff, 0x8756d9}},
|
||||
{id: 3, light: []int{0x3ca66b}, dark: []int{0x74d99b}, bg: []int{0xd5f5df, 0xedfff2}, story: []int{0x74d99b, 0x35a86a}},
|
||||
{id: 4, light: []int{0x2d9fc6}, dark: []int{0x6fd8f5}, bg: []int{0xd4f4ff, 0xf0fbff}, story: []int{0x6fd8f5, 0x2d9fc6}},
|
||||
{id: 5, light: []int{0x4a86d9}, dark: []int{0x78aef5}, bg: []int{0xd8e8ff, 0xf2f7ff}, story: []int{0x78aef5, 0x4a86d9}},
|
||||
{id: 6, light: []int{0xd85b93}, dark: []int{0xff8abb}, bg: []int{0xffd7e8, 0xfff5fb}, story: []int{0xff8abb, 0xd85b93}},
|
||||
{id: 7, light: []int{0x5f6a7a, 0x8c96a6}, dark: []int{0x9aa4b4, 0xc0c8d4}, bg: []int{0xe3e7ee, 0xf7f9fc}, story: []int{0x9aa4b4, 0x6f7b8d}},
|
||||
}
|
||||
|
||||
// IsPeerColorID reports whether id is in the TDesktop-compatible peer color palette.
|
||||
func IsPeerColorID(id int) bool {
|
||||
if found, seeded := seedPeerColorID(id, false); seeded {
|
||||
return found
|
||||
}
|
||||
for _, color := range defaultPeerColors {
|
||||
if color.id == id {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsPeerProfileColorID reports whether id is in the profile background palette.
|
||||
func IsPeerProfileColorID(id int) bool {
|
||||
if found, seeded := seedPeerColorID(id, true); seeded {
|
||||
return found
|
||||
}
|
||||
return IsPeerColorID(id)
|
||||
}
|
||||
|
||||
func PeerColors(hash int) tg.HelpPeerColorsClass {
|
||||
if hash == peerColorsHash {
|
||||
return &tg.HelpPeerColorsNotModified{}
|
||||
}
|
||||
colors := seedPeerColorOptions(false)
|
||||
if len(colors) == 0 {
|
||||
colors = make([]tg.HelpPeerColorOption, 0, len(defaultPeerColors))
|
||||
for _, color := range defaultPeerColors {
|
||||
option := tg.HelpPeerColorOption{ColorID: color.id}
|
||||
option.SetColors(&tg.HelpPeerColorSet{Colors: append([]int(nil), color.light...)})
|
||||
option.SetDarkColors(&tg.HelpPeerColorSet{Colors: append([]int(nil), color.dark...)})
|
||||
if color.hidden {
|
||||
option.SetHidden(true)
|
||||
}
|
||||
colors = append(colors, option)
|
||||
}
|
||||
}
|
||||
return &tg.HelpPeerColors{Hash: peerColorsHash, Colors: colors}
|
||||
}
|
||||
|
||||
func PeerProfileColors(hash int) tg.HelpPeerColorsClass {
|
||||
if hash == peerProfileColorsHash {
|
||||
return &tg.HelpPeerColorsNotModified{}
|
||||
}
|
||||
colors := seedPeerColorOptions(true)
|
||||
if len(colors) == 0 {
|
||||
colors = make([]tg.HelpPeerColorOption, 0, len(defaultPeerColors))
|
||||
for _, color := range defaultPeerColors {
|
||||
option := tg.HelpPeerColorOption{ColorID: color.id}
|
||||
option.SetColors(&tg.HelpPeerColorProfileSet{
|
||||
PaletteColors: append([]int(nil), color.light...),
|
||||
BgColors: append([]int(nil), color.bg...),
|
||||
StoryColors: append([]int(nil), color.story...),
|
||||
})
|
||||
option.SetDarkColors(&tg.HelpPeerColorProfileSet{
|
||||
PaletteColors: append([]int(nil), color.dark...),
|
||||
BgColors: append([]int(nil), color.bg...),
|
||||
StoryColors: append([]int(nil), color.story...),
|
||||
})
|
||||
if color.hidden {
|
||||
option.SetHidden(true)
|
||||
}
|
||||
colors = append(colors, option)
|
||||
}
|
||||
}
|
||||
return &tg.HelpPeerColors{Hash: peerProfileColorsHash, Colors: colors}
|
||||
}
|
||||
|
||||
func PromoData(now time.Time) tg.HelpPromoDataClass {
|
||||
|
|
@ -246,17 +500,6 @@ func TermsOfServiceUpdate(now time.Time) tg.HelpTermsOfServiceUpdateClass {
|
|||
return &tg.HelpTermsOfServiceUpdateEmpty{Expires: int(now.Add(24 * time.Hour).Unix())}
|
||||
}
|
||||
|
||||
func PremiumPromo() *tg.HelpPremiumPromo {
|
||||
return &tg.HelpPremiumPromo{}
|
||||
}
|
||||
|
||||
func AllStories() tg.StoriesAllStoriesClass {
|
||||
return &tg.StoriesAllStories{
|
||||
State: "",
|
||||
StealthMode: tg.StoriesStealthMode{},
|
||||
}
|
||||
}
|
||||
|
||||
func StoriesArchive() *tg.StoriesStories {
|
||||
return &tg.StoriesStories{}
|
||||
}
|
||||
|
|
@ -273,6 +516,14 @@ func StarGiftActiveAuctions() tg.PaymentsStarGiftActiveAuctionsClass {
|
|||
return &tg.PaymentsStarGiftActiveAuctionsNotModified{}
|
||||
}
|
||||
|
||||
func StarGifts() tg.PaymentsStarGiftsClass {
|
||||
return &tg.PaymentsStarGifts{
|
||||
Gifts: []tg.StarGiftClass{},
|
||||
Chats: []tg.ChatClass{},
|
||||
Users: []tg.UserClass{},
|
||||
}
|
||||
}
|
||||
|
||||
func SavedStarGifts() *tg.PaymentsSavedStarGifts {
|
||||
return &tg.PaymentsSavedStarGifts{
|
||||
Gifts: []tg.SavedStarGift{},
|
||||
|
|
@ -281,6 +532,29 @@ func SavedStarGifts() *tg.PaymentsSavedStarGifts {
|
|||
}
|
||||
}
|
||||
|
||||
func StarGiftCollections() tg.PaymentsStarGiftCollectionsClass {
|
||||
return &tg.PaymentsStarGiftCollections{
|
||||
Collections: []tg.StarGiftCollection{},
|
||||
}
|
||||
}
|
||||
|
||||
func StarsRevenueStats(ton bool) *tg.PaymentsStarsRevenueStats {
|
||||
zeroAmount := tg.StarsAmountClass(&tg.StarsAmount{})
|
||||
if ton {
|
||||
zeroAmount = &tg.StarsTonAmount{}
|
||||
}
|
||||
return &tg.PaymentsStarsRevenueStats{
|
||||
RevenueGraph: &tg.StatsGraphError{Error: "Not enough data to display."},
|
||||
Status: tg.StarsRevenueStatus{
|
||||
CurrentBalance: zeroAmount,
|
||||
AvailableBalance: zeroAmount,
|
||||
OverallRevenue: zeroAmount,
|
||||
WithdrawalEnabled: false,
|
||||
},
|
||||
UsdRate: 0.013,
|
||||
}
|
||||
}
|
||||
|
||||
func AiComposeTones() tg.AicomposeTonesClass {
|
||||
return &tg.AicomposeTonesNotModified{}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue