Como criei um bot do Tabnews para o Bluesky
Olá pessoal, na semana retrasada, fiquei motivado no desafio de criar um bot do Tabnews para o Bluesky, graças a ideia de nosso colega fausto
e pelo fato da experiência de desenvolvimento no Bluesky ter sido muito elogiada em alguns artigos que vi. Como tinha falado no texto anterior, irei compartilhar com vocês como foi o processo de criação do bot e explicando como funciona o processo de desenvolvimento de um bot no Bluesky.
Para isso, é necessário ter em mãos os itens:
- Uma conta no Bluesky criada - Basta apenas criar a conta. Não existe um tempo mínimo para a conta ficar ativa para ativar a geração de senhas de App.
- Algum local para rodar a Cronjob. Para o meu bot, usei o servidor PHP simples do meu site pessoal na Hostinger
Como eu criei para rodar em um servidor PHP, irei manifestar a maioria das instruções em PHP, mas procurarei também explicar como funciona em JavaScript.
O Bluesky suporta envio de códigos de verificação por e-mail. Eu recomendo ativar isso nas configurações, enquanto que o Bluesky não suporta outros métodos de 2FA.
Criando a senha de App
Para que o seu bot possa fazer as postagens, é necessário você criar um App Password
(Senha de Aplicativo), para que você possa informar no ato do login pela biblioteca de conexão ao Bluesky. É importante reiterar que a senha que você usa para entrar no site ou aplicativo NÃO funcionará para o bot.
Para criar, acesse o site do Bluesky, faça o login no site, e acesse a seção "Settings". Em seguida, no painel central, procure por "App Passwords" e clique nele:
Em seguida, caso não tenha criado um senha de aplicativo, você deve ver apenas o botão "Add App Password". Clique neste botão. No print a seguir, temos um criado, que é usado pelo bot para fazer a alimentação dos posts todos os dias às 12h.
O Bluesky perguntará qual é o nome que você quer dar para identificar a senha de aplicativo. Este nome aparecerá na lista das senhas de aplicativo para você identificar quando você desejar excluir a senha do app. Escreva o nome e clique em "Create App Password".
Após isso, o Bluesky mostrará pela única vez a senha do aplicativo criada. Copie e salve a senha em um lugar seguro. Quando você se certificar que você copiou e salvou a senha, clique em "Done".
Com a senha salva, podemos avançar para a próxima etapa.
Configurando a Biblioteca de conexão ao Bluesky e fazendo a primeira postagem
Com a senha de aplicativo salva em um lugar seguro, é necessário instalar em seu projeto a biblioteca responsável por fazer a ponte entre seu código e o Bluesky. Para NodeJS, é necessário instalar a biblioteca oficial @atproto/api
. Já para o PHP (linguagem a qual programei o Bot) temos o pacote mantido por Clark Rasmussen cjrasmussen/bluesky-api
. Para instalar, use o comando:
composer require cjrasmussen/bluesky-api
Com o pacote instalado, você pode fazer a conexão do seu bot ao Bluesky. Para NodeJS, você pode seguir este script baseado no guia oficial do Bluesky:
import { BskyAgent } from '@atproto/api';
import { CronJob } from 'cron';
import * as process from 'process';
const handle = "tabnewsbot.bsky.social"
const app_password = "ISTO NÃO DEVE SER PASSADO NO CÓDIGO"
// Create a Bluesky Agent
const agent = new BskyAgent({
service: 'https://bsky.social',
})
async function login() {
await agent.login({ identifier: handle, password: password})
console.log("Connected!")
}
main();
Para realizar a autenticação usando o pacote PHP, há algumas diferenças. A conexão seria desta forma:
use cjrasmussen\BlueskyApi\BlueskyApi;
$bluesky = new BlueskyApi();
$handle = "tabnewsbot.bsky.social"
$app_password = "ISTO NÃO DEVE SER PASSADO NO CÓDIGO"
try {
$bluesky->auth($handle, $app_password);
} catch (Exception $e) {
// TODO: Aqui é o tratamento de exceções
}
Para realizar a postagem, é algo simples. Segue abaixo o trecho de código Typescript para realizar esta tarefa:
async function main() {
await login();
// este é o trecho necessário
await agent.post({
text: "🙂"
});
console.log("Just posted!")
}
main();
Já para a biblioteca PHP, a função é mais complexa, mas o entendimento é fácil. Com a variável $bluesky
com a conexão, basta indicar no atributo text
o texto a ser postado e em langs
, o array com as linguagens da postagem. No caso do nosso bot, alteramos o array para ['pt-br', 'en']
, para sinalizar ao Bluesky que o post tem como línguas Português e Inglês.
Se o atributo
langs
não for informado, o Bluesky tentará detectar a linguagem com base no texto fornecido.
A seguir, apresentamos como ficaria o código para fazer a postagem em PHP:
$args = [
'collection' => 'app.bsky.feed.post',
'repo' => $bluesky->getAccountDid(),
'record' => [
'text' => 'Testing #TestingInProduction',
'langs' => ['en'],
'createdAt' => date('c'),
'$type' => 'app.bsky.feed.post',
],
];
$data = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
A partir deste momento, seu script já deve estar postando no Bluesky. Em relação aos requisitos do nosso Bot do Tabnews, estamos quase lá. Na próxima seção mostraremos como funciona a postagem de links.
Adicionando links a postagem
Quando estava fazendo o Bot do Tabnews, primeiro testei apenas com o texto normal. Com as postagens funcionando, decidi colocar no campo texto o link para ver o que acontecia. O texto era postado com o link, porém quando via a postagem no Bluesky, o link aparecia como texto puro, não sendo clicável.
Descobri então, que para postar links usando a API do Bluesky, é necessário declarar explicitamente o link para a API, marcando os bytes de início e final do link. O Bluesky chama este recurso de Rich Text Facets, que é a forma que o Bluesky encontrou para delimitar quando começa e quando termina no texto um link.
Neste sistema, você determina os bytes de início e fim da string onde serão marcados como o link. Este texto a ser demarcado não precisa ser a URL explícita, podendo ser qualquer texto.
No projeto do Bot, como o link será a URL do post, criei uma função, onde dado um texto com a URL e a URL a ser colocada no texto, ele procura o byte inicial da URL a ser encontrada usando a função strpos
e depois, através de um strlen
na string contendo a URL a ser encontrada e somando o valor retornado pelo strlen
pela soma do byte inicial, encontramos as posições inicial e final a serem demarcadas:
function discoverByteStartAndEnd($merged, $find){
// Find the start byte position of $firstPositionUrl
$startBytePos = strpos($merged, $find);
// Find the length of $firstPositionUrl (in bytes)
$byteLength = strlen($find);
// Find the end byte position (start position + length)
$endBytePos = $startBytePos + $byteLength ;
return [$startBytePos, $endBytePos];
}
Com o texto a ser enviado na variável $text
, a URL para ser incorporada como link $url
e as posições inicial e final do texto a ser considerado como link nas variáveis $startBytePos
e $endBytePos
, podemos enviar o texto com o Rich Text Facet da seguinte maneira (note o novo atributo facets
para declarar a posição inicial e final do texto a ser considerado como link e a declaração da URL):
$args = [
'collection' => 'app.bsky.feed.post',
'repo' => $bluesky->getAccountDid(),
'record' => [
'text' => $text,
'langs' => ['pt-br', 'en'],
'createdAt' => date('c'),
'$type' => 'app.bsky.feed.post',
'facets' => [
[
'index' => [
'byteStart' => $startBytePos,
'byteEnd' => $endBytePos,
],
'features' => [
[
'$type' => 'app.bsky.richtext.facet#link',
'uri' => $url,
]
]
]
]
],
];
$data = $bluesky->request('POST', 'com.atproto.repo.createRecord', $args);
E com isso, temos o nosso post com o link incorporado:
Para entender mais detalhes de como funciona este recurso, consulte a documentação oficial do Rich Text Facets do Bluesky. Através deste recurso, você pode marcar também usuários e hashtags.
E depois?
O bot está funcionando initerruptamente há 11 dias seguidos, levando os links mais relevantes do Tabnews aos usuários do Bluesky. Porém, em relação ao bot original que está rodando na Rede X - o bot do Bluesky falta apenas um recurso: Postar os links como se fossem cards, para facilitar o usuário a visualizar e clicar na postagem.
Para isso, preciso usar um outro recurso avançado do Bluesky, que é o app.bsky.embed.external
. Procurarei implementar isso, e irei trazer mais informações de como implementar em um novo artigo que publicarei aqui no Tabnews.
Se você tem conta no Bluesky e quer seguir os posts mais relevantes daqui, basta só seguir. Nosso handle é tabnewsbot.bsky.social
e você pode acessar aqui.
Para encerrar, permita me sugerir uma leitura adicional. Recomendo ler o artigo oficial do Bluesky que se trata a respeito dos rate limits que os bots devem seguir. Neste momento que escrevo este artigo, o Bluesky classifica as operações por pontos e limita as contas em relação ao número de pontos acumulados no período. Ao contrário do seu concorrente Rede X, o Bluesky oferece neste momento um limite generoso, sendo permitido criar 1666 posts por hora e 11666 posts por dia. Mas recomendamos sempre que você use esta ferramenta com moderação.
Espero que este artigo seja de grande valia para você!
Eu tô na idéia de criar um pro meu site. falta é tempo mesmo kkkk mas parabéns pelo projeto. muito bom