Настоящая инструкция, как делать динамические стикеры в Telegram

Шо, посоны, анимэ? Что это за тренд пошел писать статьи про то, как создать в Тележеньке динамические стикеры — при том, либо максимально поверхностные, либо максимально тугие (вот вам curl, и любуйтесь им сколько вам угодно).

Решил, чего это я, потрачу полчасика, напишу статью, как реально создать динамические стикеры в тележеньке на Node.js, TypeScript, Telegraf.js и с использованием еще горсти сторонних зависимостей. Ну и с исходным кодом, который любой ламер сможет адаптировать под свои нужды. Поехали!

Структуру проекта я особо не буду объяснять — стандартный бойлерплейт TypeScript, коих в интернетах-этих-ваших мульоны. Даже я стартер для себя написал недавно, чтобы упростить запуск MVP. Перейду сразу к соку.

Мы создадим простого бота под документации Telegraf.js. По команде /start он будет создавать стикерпак (желательно сделать это один раз) с одним стикером, а после будет по куллдауну обновлять этот один стикер.

Для генерации картинки стикера, воспользуемся пакетом text-to-picture (он немного приуныл, поэтому я сделал свой форк с блекджеком и нормальными зависимостями, который и буду использовать).

Алсо, я не буду углубляться в работу с @BotFather — по нему и по инструкции использования прокатились в других статьях. На текущий момент у вас должны быть:

  • Токен бота от @BotFather
  • Установленные на компуктере node и yarn

Если вы ну уж полный ламер далекий от кодирования, переходите в конец статьи — там я просто опишу шаги по созданию вашего собственного бота на основе кода стартера. Следующие пара-тройка секций для простых программистов.

Создаем бота

Ну это очень просто. За пазухой у скрипта, естественно, dotenv, в котором лежат TOKEN (токен бота) и ADMIN (ваш user id). Начинаем кодирование, быстренько накатаем скриптик, который отвечает на /start.

import Telegraf from 'telegraf' const bot = new Telegraf(process.env.TOKEN) bot.start(ctx => ctx.reply('WoW Classic — это симулятор очередей')) bot.launch().then(() => console.log("It's alive!"))

Нойс. Теперь можем запустить скриптик при помощи того же yarn develop — команду, которую я любезно включил в `package.json` нашего стартера; отправить боту /start и даже получить ответ.

Генерим картинку

async function getStickerId() { const secondsAfterPHP = Math.floor( new Date().getTime() / 1000 - new Date('1995').getTime() / 1000 ) const result = await textToPicture.convert({ text: `${secondsAfterPHP}`, source: { width: 512, height: 512, background: '0xFF0000FF', }, color: 'white', }) const file = await bot.telegram.uploadStickerFile(ownerId, { source: await result.getBuffer(), }) return file.file_id }

Скриптец выше делает следующие вещи:

  • Считает количество секунд после создания PHP в 1995 году
  • Создает картинку при помощи text-to-picture пакета
  • Загружает буфер картинки от text-to-picture в Телеграм
  • Возвращает результат функции — file_id нашего стикера

Эту функцию мы сможем использовать дальше.

Создаем стикерпак

Тут все изи. Мы берем результат getStickerId функции и пихаем ее в функцию создания стикерпака. Ну а потом грех не ответить на это сообщение созданным стикером, чтобы вы могли себе сохранить стикерпак.

const stickerSetName = 'phpSuckedSeconds' bot.start(async ctx => { try { const botUsername = ctx.me const stickerId = await getStickerId() await ctx.telegram.createNewStickerSet( ownerId, `${stickerSetName}_by_${botUsername}`, 'PHP sucked for this many seconds', { png_sticker: stickerId, emojis: '💩', mask_position: undefined, } ) const stickerSet = await bot.telegram.getStickerSet(`${stickerSetName}_by_${botUsername}`) const sticker = stickerSet.stickers[0] return ctx.replyWithSticker(sticker.file_id) } catch (err) { return ctx.reply(err.message) } })

Опять пройдемся построчно, что тут мы имеем:

  • Во-первых, тут все может плюнуть в нас ошибкой — поэтому мы ловим ошибку в одном месте и отвечаем ей пользователю, если нужно
  • Дальше мы получаем username нашего бота, чтоб создать в итоге название стикерпака, оканчивающееся на _by_mybot — неочевидная обязабма в API
  • Используем вышеописанную функцию и получаем идентификатор стикера
  • Создаем сам стикер пак простой командой
  • Так как эта команда возвращает лишь результат выполнения (получилось или нет), мы еще раз вытягиваем информацию о паке стикеров
  • Берем первый (и единственный) стикер
  • Отвечаем этим стикером нам любимым
Как-то так в итоге получается

Делаем стикерпак 🌈 *динамичным* 🦄

Здесь все просто — каждые 30 секунд мы будем удалять единственный стикер и добавлять туда новый. Вот код функции, собственно говоря.

setInterval(updateSticker, 30 * 1000) async function updateSticker() { console.log('Updating stickers') const botUsername = bot.options.username const stickerSet = await bot.telegram.getStickerSet( `${stickerSetName}_by_${botUsername}` ) const sticker = stickerSet.stickers[0] await bot.telegram.deleteStickerFromSet(sticker.file_id) await bot.telegram.addStickerToSet( ownerId, stickerSetName, { png_sticker: await getStickerId(), emojis: '💩', mask_position: undefined, }, false ) console.log('Updated stickers') }

Никакой магии, мы просто:

  • Заставляем безмозглую машину выполнять одно и то же действие каждые 30 секунд
  • Логируем нам любимым, что обновление инициированно
  • Получаем стикерпак и единственный стикер оттуда
  • Удаляем этот стикер
  • Добавляем новый стикер с новым временем, воспользовавшись функцией создания и загрузки картинки
  • Логируем окончание процесса
  • А, это все

Вот так просто — буквально за полчаса — мы собрали рабочее (хоть и не самое красивое) решение для создания динамических стикеров в Телеграме. И это почти пошаговое руководство, а не просто статья со словами "создавайте стикеров через ботов" или "просто курлите напрямую в тележеньку, каждый раз, когда нужно обновить стикеры — но где брать картинки я не скажу".

Держите этот скрипт запущенным на своем пека, мокинтоше или линухе на сервачке — и будет вам счастье. А теперь к секции, которой все ждут: как же нам генерить динамические стикеры без знаний программирования?

Вот так

1. Качаете файлики из стартера

2. Ставите себе нужные зависимости через yarn install

3. Создаете файл .env

4. Заполняете в нем TOKEN и ADMIN поля, как в .env.sample

3. Открываете src/app.ts

4. Меняете stickerSetName и stickerSetDescription

5. Меняете переменную text (это то, что будет на картинке)

6. Запускаете все через yarn develop

Зетс ол фолкс!

Заключение и наглый пиар себя

Надеюсь, этот материал кому-нибудь да будет полезным. Никакого зла я не держу в сторону авторов предыдущих статей — они замечательные люди (просто недоговаривают). Если вам понравилась моя статья — не стесняйтесь апвоутить, подписываться и оставлять эмодзи хлопков в комментариях.

К слову, на любые вопросы с удовольствием отвечу в тех же самых комментариях. Ну и, как принято на VC.ru, пара слов о моем новом проекте, чтобы вы обязательно зашли и покрутили его.

Todorant — это сервис, который позволяет мне лично держать голову легкой (без веса постоянно накапливающихся задач в моих тудулистах) благодаря идеям из книг Eat That Frog, Willpower и Getting Things Done, что я недавно прочитал.

Я взял оттуда методологии, упростил, убрал лишнее и обернул все в приятный вебсервис. Todorant абсолютно бесплатен — попробуйте его сегодня, если вам надоело, что вы постоянно теряетесь в задачах, которые необходимо сделать здесь и сейчас.

Спасибо!

0
27 комментариев
Написать комментарий...
Mihail

Спасибо за материал, я ламер и мне интересно.
Но разрешите пару замечаний. Коль вы пишите доя ламеров (остальным наверное и не надо) :
1 множество терминов да ещё английских на русском. Это не для ламеров
2 стиль изложения 'пацановский', смотрите как все просто. Это не для ламеров
По факту нужна грамотная инструкция которая научит и поможет.

Ответить
Развернуть ветку
borodutch
Автор

К сожалению, вырос на улице — язык белых людей так и не освоил. В этой статье я постарался как-то более прилично написать, похоже, не вышло. Ну, всяко лучше, чем мой Пацанский разбор кода ТОН

Ответить
Развернуть ветку
Mihail

NASA теперь берет с улицы? 3 языка и это только людских?

Не прибедняйтесь:) Да и улица ваших лет, это спокойствие и благодать.

Действительно хорошая статья, просто для начинающих попроще хотелось бы, чуть поакадимичнее, аккуратней с терминами.

Ответить
Развернуть ветку
Андрей

После слов node, yarn, dotenv, я приуныл и понял, что это совсем не для ламеров.

Ответить
Развернуть ветку
Mihail

Да на английском это ещё норм, погуглить можно. В транскрипте тяжелей

Ответить
Развернуть ветку
borodutch
Автор

Я первый 👏

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Anatoliy Bones

Делаем ставки сколько еще будет инструкций

Ответить
Развернуть ветку
borodutch
Автор

Сначала будет вебсервис-конструтор таких стикеров, а потом аггрегатор таких сервисов и статей по ним.

Ответить
Развернуть ветку
Довжухались

Такое ощущение, что попала в 2007-й или на Хабр. Афтар, непеши есчо. Серьёзно, найдётся кто-то, кто эту прелесть переведёт на вменяемый русский и перепишет без сленга типа «алсо»?

Ответить
Развернуть ветку
borodutch
Автор

Спасибо за комментарий, не буду писать ещё!

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
borodutch
Автор

Спасибо за комментарий, буду писать ещё!

Ответить
Развернуть ветку
Аккаунт удален

Комментарий недоступен

Ответить
Развернуть ветку
Ерофей

Судя по некоторым словам автору за 30. Но статья интересная, спасибо.

Ответить
Развернуть ветку
Ерофей

Зашёл на сайт:

Этот вебсайт использует печеньки. Мы не следим за вами. Но Фейсбук, возможно, следит. Понятненько!

Ясненько )))

Ответить
Развернуть ветку
borodutch
Автор

Старался быть максимально открытым и правдивым в этом попапе. Спасибо, что посмотрели сайтец :) для меня это очень важно

Ответить
Развернуть ветку
Kokoulin Nikolay

В вашей инструкции есть один нюанс. Не смотря на то, что она черезвычайно подробная, она понятна только людям которые активно программируют на JS, а инструкции выложенные ранее были понятны программисту на любом языке. Ну и curl так-то стандарт описания запросов не вижу ничего в этом плохого

Ответить
Развернуть ветку
borodutch
Автор

ИМХО, программисты понимают инструкции на любых языках — на то они и программисты, ведь все языки — это просто друг друга братья и кузены.

Если человек не может прочитать псевдокод или код на каких-нибудь путоне, рубях или (господи-упаси) Яве, то не программист это вовсе.

Но я соглашусь с вашей претензией — статья получилась черезчур JS-хеви.

Ответить
Развернуть ветку
Kokoulin Nikolay

Я не верно выразился, правильнее сказать было бы, непонятна без вникания в код, с друго стороны непрограммисту будет проще

Ответить
Развернуть ветку
Andrey Akt

Спасибо, получилось!

Ответить
Развернуть ветку
Oleg Garvin

Сначала удаляем стикер, потом добавляем новый. А что случится, если кто-нибудь запросит стикер между двумя операциями?

Ответить
Развернуть ветку
borodutch
Автор

Какой-нибудь "sticker not found". Хорошей идеей будет:

1. Всегда в паке держать минимум один постоянный стикер (например, с указанием авторства)
2. Не удалять, а потом добавлять, но наоборот: добавить — и потом удалить.

Но это уже вне рамок статьи :) ну и после удаления стикера он не исчезает из чатов, куда его уже кидали.

Ответить
Развернуть ветку
Kokoulin Nikolay

Если удалить последний стикер, стикерпак не будет открываться с устройства пока в него не положишь новый

Ответить
Развернуть ветку
Вячеслав Жилов

А пак на 240 стикеров (котировки) так тоже сделать можно?

Ответить
Развернуть ветку
borodutch
Автор

Да!

Ответить
Развернуть ветку

Комментарий удален модератором

Развернуть ветку
borodutch
Автор

Странная реклама финансовой пирамиды. Пометил, как спам, на всякий случай.

Ответить
Развернуть ветку
24 комментария
Раскрывать всегда