Я написав Telegram-клієнт повністю за допомогою AI. І за нього не соромно
Telegram давно став чимось більшим за месенджер. Але читати в ньому канали досі біль, бо інтерфейс під це просто не заточений.
Коли впереміш ідуть особисті чати, робочі флудилки й новини, найти цікаву інформацію важко. Зайшов у канал, поскролив, вийшов, відкрив наступний. Не читання, а нескінченне проклікування.
Мені хотілося єдиної хронологічної стрічки, де пости йдуть підряд, як у старому доброму Twitter. Готового опенсорсного рідера під Android без трекерів я не знайшов. Тож зробив свій. Знайомтеся, Hortay.

З API Telegram я працюю років десять, причому руками: і з Bot API, і з MTProto, і з
TDLib. Можливо, ви натрапляли на моїх ботів fStikBot і QuotLyBot, зараз це близько 800 тисяч MAU і понад 80 тисяч груп. Платформу знаю зсередини, тим більше мені хотілось створити власний клієнт.
Але найцікавіше тут не самі фічі. Hortay цілком написаний за допомогою AI, руками я не торкався коду. І головним було зробити так, щоб це не перетворилося на типовий слоп. До цього повернуся нижче, а спершу коротко про те, що застосунок уміє.
Дерево коментарів замість лінійної каші
У великих каналах секція коментарів швидко перетворюється на хаос. Пара сотень повідомлень, і вже не розбереш, хто кому відповів.
У Hortay коментарі розгортаються гілками. Видно структуру дискусії, видно хто кому відповів, можна читати конкретну гілку й не продиратися крізь решту тексту.


Гостьовий режим: читати без логіна
За публічними каналами можна стежити взагалі без авторизації в Telegram. Копіюєте посилання на паблік, додаєте в застосунок, і він з’являється у вашій стрічці. Жодної прив’язки до номера телефону чи основного акаунта.


Код на 100% згенерований AI
Повертаюся до головного. Руками я не написав жодного рядка коду, увесь застосунок написаний разом зі штучним інтелектом.
Але AI-слоп з’являється саме там, де модель починає вигадувати власні рішення. Тому головне правило, яке я їй дав, звучало просто: не вигадуй. Тримайся того, що рекомендує автор движка й офіційна документація. Пиши якомога менше свого коду, спирайся на TDLib і стандартні бібліотеки Android. Власне щось писати тільки там, де без цього ніяк.
Так і вийшло: майже вся складна логіка це перевірений код TDLib і платформи, а не моя імпровізація. У проєкті близько 56 тисяч рядків Kotlin у 245 файлах, але майже все це Compose-інтерфейс і клей навколо TDLib, а не власні алгоритми. Стек свіжий: чистий Compose, навігація на новому Navigation 3, ручний DI замість Hilt чи Dagger. AI писав код, але рішення, чому саме так, спираються на першоджерела.
Як це виглядало на практиці: я не казав «зроби фічу». Я давав моделі конкретне обмеження, посилання на документацію чи відповідь мейнтейнера й очікувану поведінку, читав diff, ганяв збірку на реальному телефоні й змушував переписувати, якщо рішення не спиралося на першоджерело.
Я не вгадував, як працює Telegram. Я читав мейнтейнера
Протокол Telegram капризний. Якщо робити «як здається логічно», легко словити блок акаунта. Простий приклад: на холодному старті хочеться просто попросити в сервера історію кожного каналу. Зробиш так на 200 каналів і отримаєш FLOOD_WAIT, тимчасове блокування на хвилини, причому глобальне на весь акаунт.
Звідки я знаю, де ці граблі? Я не давав моделі їх вгадувати. TDLib, движок офіційного Telegram, розробляє Олексій Левін (levlam), і він роками відповідає в баг-трекері: де які ліміти, чому щось працює саме так, що можна, а що ні. Замість здогадок ми з моделлю підіймали його відповіді з трекера й клали їх в основу рішень. У кодовій базі Hortay його ім’я згадується 25 разів, з посиланнями приблизно на 30 конкретних обговорень у трекері TDLib.
Ліміт GetChatHistory: 30 запитів за 30 секунд. За перевищення сервер банить акаунт на хвилини. Левін написав це прямо, тому холодний старт у Hortay подієвий: він не питає історію по колу, а ловить оновлення, які сервер і так шле. Бюджет запитів зрізаний приблизно в 30 разів.
Лічильники й реакції оновлюються тільки для відкритого чату. Це теж з відповіді Левіна. Тому застосунок відкриває рівно той чат, чий пост зараз перед очима, а не той, що формально перший у списку.
«Користувач зазвичай тримає відкритим один чат». Це його формулювання, і під ним лежить уся логіка об’єднаної стрічки з багатьох каналів.
Можна було написати клієнт «на дотик», і він би навіть запускався. Рівно до першого FLOOD_WAIT у живих умовах. Замість цього кожне важливе рішення спирається на слова автора движка, а не на здогадку. Як на мене, це і є різниця між «згенерував з AI» і «розібрався з AI».
Прозорі стікери, які Android не вміє показувати
Я казав, що намагався писати мінімум свого коду. Але є рівно одне місце, де без власного нативного коду не обійтися, бо платформа фізично не вміє того, що треба.
Telegram шле анімовані стікери й кастомні емодзі як WebM з прозорим фоном, кодек VP9, теж від Google. І ось фокус: Android не вміє декодувати прозорість у VP9. Взагалі. Кольори декодує нормально, а альфа-канал просто викидає. На виході непрозорий квадрат замість стікера. Це не баг конкретного телефону, а обмеження системного декодера Android: у ньому немає формату під відео з прозорістю.
Найсмішніше тут от що. WebM — формат Google. Прозорість у ньому є з самого початку. Chrome її рендерить, Firefox рендерить. А Android, теж дітище Google, нативно — ні. Apple свою WebM-альфу теж не підтримує, але це хоч послідовно: у них є HEVC with alpha як заміна. В Android заміни нема. Ішус androidx/media #1388 відкрили в травні 2024, повісили на гуглівського інженера — і він досі висить.
Обхідні шляхи, які винаходять люди, це або костилі через OpenGL-шейдери, або хитрощі з кольоровим ключем. Усе криве. Я пішов іншим шляхом: зібрав мінімальний ffmpeg з libvpx (декодером VP9 від Google), увімкнув рівно один декодер під VP9 і нічого зайвого. Telegram тримає прозорість окремим потоком усередині WebM, і дістати її вміє тільки libvpx. Цей шматок важить близько 10 МБ і займається виключно прозорими стікерами. Решта відео й далі йде через залізо, щоб не садити батарею.
Тобто щоб анімований стікер з прозорим фоном просто показався, довелося зібрати з сорсів шматок ffmpeg. Бо Google роками не закриває діру у власному форматі на власній платформі.
І той самий декодер нещодавно підкинув баг. У версії 0.10.4 він крашив застосунок на частині arm64-телефонів: бібліотека припускала, що в процесора є найновіший набір інструкцій, а на трохи старших чіпах це SIGILL і виліт. Полагодив через визначення можливостей процесора в рантаймі. Такий баг видно тільки на живому залізі, не в емуляторі, і це рівно те, чого AI за тебе не зробить.
Він справді легкий
Я боявся, що через TDLib і власний ffmpeg застосунок роздується. Але ні.
Не люблю слово «оптимізований», тому просто покажу цифри.

Реліз важить 36 МБ, і майже вся ця вага це два нативних рушії, а не код. 22 МБ це сам движок Telegram: TDLib, який я збираю з офіційних сорсів через Docker під конкретний коміт, той самий рушій, що й в офіційному клієнті. Ще майже 10 МБ це мій декодер прозорих стікерів. Власне код Hortay, попри 56 тисяч рядків, стискається в кілька мегабайтів. Через Google Play на пристрій прилітає близько 22 МБ, бо туди йде збірка тільки під arm64. x86_64 свідомо не кладу: це зайві 24 МБ заради нуля реальних користувачів.
Тепер про вилизаність. Це не одна вау-фіча, а сотня дрібниць, яких не помічаєш, поки вони працюють.
Стрічка не скаче. Головна біда Compose це зайві перемальовки: міняється одна дрібниця, а перемальовується весь список. Я прибив це по всьому коду через незмінні структури даних, у 42 файлах. На практиці скролиш сотні постів з відео й анімованими емодзі, а воно не лагає.
Заглушок майже не видно. Скелетон завантаження з’являється, тільки якщо екран не встиг прогрузитися за 120 мілісекунд. Блимання сірим прямокутником на чверть секунди дратує більше, ніж коротка пауза.
Поважає «прибрати анімацію». Якщо ви ввімкнули це в системі, Hortay бачить і вимикається: спойлери відкриваються без розсипання, медіа не проявляється плавно, анімовані емодзі застигають. Це не косметика, а доступність, про яку багато застосунків забуває.
Що зараз
Проєкт повністю відкритий і некомерційний. Жодних сторонніх трекерів, аналітики чи Firebase, і свого бекенду теж немає, тож телеметрії й зливу даних з пристрою просто нема куди дітися. У мережу застосунок ходить лише до Telegram, плюс анонімні t.me/s прев’ю в гостьовому режимі та читання публічного списку рекомендованих каналів з мого ж відкритого репозиторія.
Зараз у Google Play уже понад 200 завантажень і добрі відгуки, а на GitHub проєкт зібрав понад 40 зірок.
- Google Play: Hortay
- GitHub: github.com/LyoSU/hortay-android
Якщо у вас Android, буду радий, якщо спробуєте. Будь-яку критику архітектури чи реалізації в Issues сприймаю максимально позитивно.

2 коментарі
Додати коментар Підписатись на коментаріВідписатись від коментарівКолись давно, ще до АІ-революції, теж намагався зробити подібну стрічку: github.com/therxmv/Dirol-Reader
Але руками то виходило повільно, а Телеграм оновлювався швидше. Та й користуватися одним Телеграмом для пп, а іншим для новин виявилося не дуже то і зручно :(
Цікаво ще було б прочитати які АІ агенти і методи використовувалися та статистику витрат.
Так, у мене до ШІ теж раніше було багато ідей і бажань щось робити, але власного часу і сил не вистачало
А з приводу запитання, то лише Клод Код і підписка за 100$, ну і скіли різні. Наприклад context7 для пошуку документацію, суперпавер щоб ші трохи потужніше працювала ну і певно ше якісь не значні