| 92 | const excludedRanges: Array<{ offset: number; length: number }> = []; |
| 93 | for (const entity of message.entities) { |
| 94 | if ( |
| 95 | [ |
| 96 | "MessageEntityHashtag", |
| 97 | "MessageEntityTextUrl", |
| 98 | "MessageEntityUrl", |
| 99 | ].includes(entity.className) |
| 100 | ) { |
| 101 | excludedRanges.push({ offset: entity.offset, length: entity.length }); |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | if (excludedRanges.length === 0) return fullText; |
| 106 | excludedRanges.sort((a, b) => a.offset - b.offset); |
| 107 | |
| 108 | let result = ""; |
| 109 | let lastEnd = 0; |
| 110 | for (const range of excludedRanges) { |
| 111 | if (range.offset > lastEnd) |
| 112 | result += fullText.substring(lastEnd, range.offset); |
| 113 | lastEnd = range.offset + range.length; |
| 114 | } |
| 115 | if (lastEnd < fullText.length) result += fullText.substring(lastEnd); |
| 116 | |
| 117 | return result.trim(); |
| 118 | } |
| 119 | |
| 120 | private isVideoMessage(message: Api.Message): boolean { |
| 121 | if (message.video) return true; |
| 122 | if (message.document) { |
| 123 | if (message.document.mimeType?.startsWith("video/")) return true; |
| 124 | const fileName = message.document.attributes?.find( |
| 125 | (attr: any) => attr.className === "DocumentAttributeFilename", |
| 126 | )?.fileName; |
| 127 | if (fileName) { |
| 128 | return [ |
| 129 | ".mp4", |
| 130 | ".avi", |
| 131 | ".mov", |
| 132 | ".mkv", |
| 133 | ".webm", |