Skip to content

Commit 1dec0b7

Browse files
Add support for GIF, video, and other media types in WebUI (#31)
- Updated `CachedMessage` struct to include `FileName` and `Poll` data. - Modified `AddMessageToCache` to extract and store media info for: - Animations (GIFs) - Videos and Video Notes - Audio and Voice messages - Documents - Polls - Updated WebUI (index.html) to render these new media types using HTML5 tags and custom styling. - Added circular styling for video notes. - Improved message history display to handle truncated text/captions. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: birabittoh <26506860+birabittoh@users.noreply.github.com>
1 parent bc9ab14 commit 1dec0b7

3 files changed

Lines changed: 155 additions & 7 deletions

File tree

index.html

Lines changed: 101 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -618,12 +618,66 @@
618618
overflow: hidden;
619619
}
620620

621-
.cached-message-media img {
622-
max-height: 200px;
621+
.cached-message-media img, .cached-message-media video {
622+
max-height: 300px;
623623
max-width: 100%;
624624
object-fit: contain;
625625
}
626626

627+
.video-note {
628+
border-radius: 50%;
629+
aspect-ratio: 1/1;
630+
object-fit: cover;
631+
max-width: 200px !important;
632+
}
633+
634+
.cached-message-media audio {
635+
width: 100%;
636+
}
637+
638+
.document-info {
639+
display: flex;
640+
align-items: center;
641+
gap: 10px;
642+
padding: 10px;
643+
background: rgba(255, 255, 255, 0.05);
644+
border-radius: 8px;
645+
font-size: 0.85rem;
646+
margin-bottom: 8px;
647+
color: #d1d5db;
648+
}
649+
650+
.cached-message-poll {
651+
background: rgba(255, 255, 255, 0.03);
652+
border: 1px solid rgba(255, 255, 255, 0.1);
653+
border-radius: 8px;
654+
padding: 12px;
655+
margin-bottom: 8px;
656+
}
657+
658+
.poll-question {
659+
font-weight: 600;
660+
margin-bottom: 10px;
661+
color: #a78bfa;
662+
font-size: 0.9rem;
663+
}
664+
665+
.poll-option {
666+
background: rgba(255, 255, 255, 0.05);
667+
border-radius: 6px;
668+
padding: 8px 12px;
669+
margin-bottom: 6px;
670+
font-size: 0.8rem;
671+
display: flex;
672+
justify-content: space-between;
673+
align-items: center;
674+
}
675+
676+
.poll-voters {
677+
color: #9ca3af;
678+
font-size: 0.75rem;
679+
}
680+
627681
/* Toast Notification */
628682
#toast-container {
629683
position: fixed;
@@ -1387,12 +1441,53 @@ <h2>Select a feature to configure</h2>
13871441
<span style="font-size:0.7rem;color:#9ca3af;">#${msg.message_id}</span>
13881442
</div>
13891443
</div>
1390-
${msg.media_url ? `
1391-
<div class="cached-message-media">
1392-
<img src="${msg.media_url}" alt="${msg.media_type}">
1444+
1445+
${(() => {
1446+
if (!msg.media_url) return '';
1447+
if (msg.media_type === 'photo' || msg.media_type === 'sticker') {
1448+
return `<div class="cached-message-media"><img src="${msg.media_url}" alt="${msg.media_type}"></div>`;
1449+
} else if (msg.media_type === 'animation' || msg.media_type === 'video' || msg.media_type === 'video_note') {
1450+
const isVideoNote = msg.media_type === 'video_note';
1451+
return `
1452+
<div class="cached-message-media">
1453+
<video src="${msg.media_url}" autoplay loop muted playsinline controls ${isVideoNote ? 'class="video-note"' : ''}></video>
1454+
</div>`;
1455+
} else if (msg.media_type === 'voice' || msg.media_type === 'audio') {
1456+
return `
1457+
<div class="cached-message-media">
1458+
<audio src="${msg.media_url}" controls></audio>
1459+
</div>`;
1460+
} else if (msg.media_type === 'document') {
1461+
return `
1462+
<div class="document-info">
1463+
<span style="font-size: 1.5rem;">📄</span>
1464+
<div style="overflow: hidden;">
1465+
<div style="font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">${escapeHTML(msg.file_name || 'Document')}</div>
1466+
<a href="${msg.media_url}" target="_blank" style="color: #8b5cf6; font-size: 0.75rem; text-decoration: none;" onclick="event.stopPropagation()">Download</a>
1467+
</div>
1468+
</div>`;
1469+
}
1470+
return '';
1471+
})()}
1472+
1473+
${msg.poll ? `
1474+
<div class="cached-message-poll">
1475+
<div class="poll-question">📊 ${escapeHTML(msg.poll.question)}</div>
1476+
<div class="poll-options">
1477+
${msg.poll.options.map(opt => `
1478+
<div class="poll-option">
1479+
<span>${escapeHTML(opt.text)}</span>
1480+
<span class="poll-voters">${opt.voter_count} voters</span>
1481+
</div>
1482+
`).join('')}
1483+
</div>
1484+
<div style="font-size: 0.75rem; color: #9ca3af; margin-top: 8px; text-align: right;">
1485+
Total: ${msg.poll.total_voter_count} voters • ${msg.poll.is_closed ? 'Closed' : 'Active'}
1486+
</div>
13931487
</div>
13941488
` : ''}
1395-
<div class="cached-message-text">${escapeHTML(truncate(msg.text || msg.caption)) || (msg.media_url ? '' : '<media>')}</div>
1489+
1490+
<div class="cached-message-text">${escapeHTML(truncate(msg.text || msg.caption)) || (msg.media_url || msg.poll ? '' : '<media>')}</div>
13961491
13971492
${msg.history && msg.history.length > 0 ? `
13981493
<div class="message-history" style="font-size: 0.75rem; color: #9ca3af; margin-top: 8px; border-top: 1px solid rgba(255,255,255,0.05); padding-top: 8px;" onclick="event.stopPropagation()">

telegram/autoban.go

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,49 @@ func AddMessageToCache(escarbot *EscarBot, message *tgbotapi.Message) {
298298
fromFirstName = message.SenderChat.Title
299299
}
300300

301-
var mediaURL, mediaType string
301+
var mediaURL, mediaType, fileName string
302+
var poll *CachedPoll
303+
302304
if len(message.Photo) > 0 {
303305
mediaType = "photo"
304306
photo := message.Photo[len(message.Photo)-1]
305307
mediaURL = "/api/media?file_id=" + photo.FileID
306308
} else if message.Sticker != nil {
307309
mediaType = "sticker"
308310
mediaURL = "/api/media?file_id=" + message.Sticker.FileID
311+
} else if message.Animation != nil {
312+
mediaType = "animation"
313+
mediaURL = "/api/media?file_id=" + message.Animation.FileID
314+
} else if message.Video != nil {
315+
mediaType = "video"
316+
mediaURL = "/api/media?file_id=" + message.Video.FileID
317+
} else if message.VideoNote != nil {
318+
mediaType = "video_note"
319+
mediaURL = "/api/media?file_id=" + message.VideoNote.FileID
320+
} else if message.Voice != nil {
321+
mediaType = "voice"
322+
mediaURL = "/api/media?file_id=" + message.Voice.FileID
323+
} else if message.Audio != nil {
324+
mediaType = "audio"
325+
mediaURL = "/api/media?file_id=" + message.Audio.FileID
326+
} else if message.Document != nil {
327+
mediaType = "document"
328+
mediaURL = "/api/media?file_id=" + message.Document.FileID
329+
fileName = message.Document.FileName
330+
} else if message.Poll != nil {
331+
options := make([]CachedPollOption, len(message.Poll.Options))
332+
for i, opt := range message.Poll.Options {
333+
options[i] = CachedPollOption{
334+
Text: opt.Text,
335+
VoterCount: opt.VoterCount,
336+
}
337+
}
338+
poll = &CachedPoll{
339+
Question: message.Poll.Question,
340+
Options: options,
341+
TotalVoterCount: message.Poll.TotalVoterCount,
342+
IsClosed: message.Poll.IsClosed,
343+
}
309344
}
310345

311346
cached := CachedMessage{
@@ -319,6 +354,8 @@ func AddMessageToCache(escarbot *EscarBot, message *tgbotapi.Message) {
319354
Caption: message.Caption,
320355
MediaURL: mediaURL,
321356
MediaType: mediaType,
357+
FileName: fileName,
358+
Poll: poll,
322359
Entities: message.Entities,
323360
ThreadID: message.MessageThreadID,
324361
IsTopicMessage: message.IsTopicMessage,

telegram/telegram.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ type ReactionDetail struct {
6161
Emoji string `json:"emoji"`
6262
}
6363

64+
// CachedPollOption represents an option in a poll
65+
type CachedPollOption struct {
66+
Text string `json:"text"`
67+
VoterCount int `json:"voter_count"`
68+
}
69+
70+
// CachedPoll represents a poll stored in cache
71+
type CachedPoll struct {
72+
Question string `json:"question"`
73+
Options []CachedPollOption `json:"options"`
74+
TotalVoterCount int `json:"total_voter_count"`
75+
IsClosed bool `json:"is_closed"`
76+
}
77+
6478
// ChatInfo represents information about a Telegram chat
6579
type ChatInfo struct {
6680
ID int64 `json:"id,string"`
@@ -80,6 +94,8 @@ type CachedMessage struct {
8094
Caption string `json:"caption,omitempty"`
8195
MediaURL string `json:"media_url,omitempty"`
8296
MediaType string `json:"media_type,omitempty"`
97+
FileName string `json:"file_name,omitempty"`
98+
Poll *CachedPoll `json:"poll,omitempty"`
8399
Entities []tgbotapi.MessageEntity `json:"entities,omitempty"`
84100
ThreadID int `json:"thread_id,omitempty"`
85101
IsTopicMessage bool `json:"is_topic_message"`

0 commit comments

Comments
 (0)