Executando verificação de segurança...
7

Notificação de publicações do TabNews no discord (como fiz essa integração) [discord.py]

Recentemente começei a fazer publicações frequentes no TabNews. Foi ai que tomei uma decisão muito importante.

Tenho uma comunidade de programadores chamada Code Company. E para divulgar ela fazia posts no instagram. Mas depois que conheci o TabNews, percebi o quanto o instagram é inferior no sentido de conteúdo.

A maioria das pessoas (inclusive eu), não estão necessariamente tão interessadas assim em entregar um "conteúdo de qualidade", ele só precisa ser superficial e interessante o suficiente para ganhar uma curtida. Dificilmente você vai ver gente focada em entregar algo profundo mesmo.

Mas vocês sabem que aqui não é assim. Você pode se aprofundar nos assuntos, gerar discussões (com pessoas realmente interessadas em agregar e não só em mandar um parabéns por exemplo, mas fazer críticas construtivas que realmente podem melhorar a publicação).

Isso acabou mudando meu pensamento. E estou disposto a criar um conteúdo denso que realmente agregue na vida dos desenvolvedores.

Mas chega de enrolação... Bora para o conteúdo!

Feature no discord

Bom... Montei uma feature nova no discord da comundade para divulgar os posts. E criei esse post, caso alguem tenha interesse em fazer algo parecido no seu servidor, ou acompanhar nossas postagens.

Vou começar mostrando o resultado final para vocês entederem do que estou falando:

TabNews Channel

O bot divulga o post e marca o cargo @Notificação TabNews que pode ser adicionado aqui:

 Cargos TabNews

OBS... Também vou ensinar a fazer essa mensagem

Bora para o código!

Primeiro instale as bibliotecas:

pip install discord
pip install requests
pip install beautifulsoup4
pip install python-dotenv

Importação:

import discord
from discord.ext import commands as c
import requests
import os
from bs4 import BeautifulSoup
from dotenv import load_dotenv

Setando o Client do discord

load_dotenv()
bot = c.Bot(command_prefix=".", intents=discord.Intents.all())
reader = TabReader(bot=bot)

Para instanciar a classe TabReader, você deve passar o Client do discord (a variavel bot), e a string do seu perfil. Não passei porque por padrão ele escolhe o codecompanybrasil. Também pode passar o parametro link no caso de ter um link específico


Classe TabReader responsável por pegar o post

class TabReader:
    def __init__(self, profile: str="codecompanybrasil", bot: c.Bot=None, link=None):
        load_dotenv()
        self.profile = f"https://www.tabnews.com.br/{profile}"
        self.link = link
        self.bot = bot
        asyncio.run(TabReader.requesting())
    
    @classmethod
    async def requesting(cls):
        self.req = requests.get(self.profile)
        self.soup = BeautifulSoup(self.req.text, 'html.parser')
    
    async def lastPost(self):
        await TabReader.requesting()
        elements = []
        for element in self.soup.find_all("article"):
            if element.find("a", {"class": "Link-sc-hrxz1n-0 bPBLTS"}):
                elements.append(element.find("a"))
        
        return f"https://www.tabnews.com.br{elements[0]['href']}"

    async def sendPost(self):
        if self.link:
            self.last = self.link
        else:
            self.last = await self.lastPost()
        guild = self.bot.get_guild(int(os.environ["CODE_COMPANY_ID"]))
        channel = guild.get_channel(int(os.environ["TABNEWS_CHANNEL"]))
        role = guild.get_role(int(os.environ["TABNEWS_ROLE"]))
        m = await channel.send(f"{role.mention}\n{self.last}")
        await m.publish()

Para o bot enviar de fato a mensagem eu criei um slash command no discord. E envio assim que termino de postar. De forma que, se eu mando:

/tabnews - Ele pega o ultimo post que eu fiz

A não ser que o link seja especificado, desse jeito:
/tabnews link=(LINK)

Criando Slash Command

@bot.tree.command(name="tabnews", description="Atualiza o chat Tab News")
@discord.app_commands.describe(link="Especifica o link do post")
async def tabnews(interaction: discord.Interaction, link: str=""):
    await interaction.response.defer(ephemeral=True)
    tab = TabReader(bot=bot, link=link)
    await tab.sendPost()
    await interaction.followup.send("Post feito", ephemeral=True)
    

Fazer uma mensagem como aquela que as pessoas podem reagir e pegar o cargo. Exigem 2 passos

Primeiro você precisa enviar a mensagem, por isso recomendo que crie outro arquivo para não te confundir. Vou deixar o embed do mesmo jeito que enviei lá. Mas você pode fazer como bem entender.

enviarMensagem.py

import discord
from discord.ext import commands as c
import os
from dotenv import load_dotenv

load_dotenv()
bot = c.Bot(command_prefix=".", intents=discord.Intents.all())

@bot.event
async def on_ready():
    guild = bot.get_guild(int(os.environ["CODE_COMPANY_ID"]))
    cargo_channel = guild.get_channel(int(os.environ["CARGOS_CHANNEL"]))
    
    embed = discord.Embed(
        title="Quer o cargo de Tab News?",
        description=f'''
Com o cargo de Tab News você será sempre notificado quando tiver posts novos no chat de {tabnews.mention}

Você tambem pode receber as mensagens no seu servidor se quando quiser! É só seguir o canal.
''',
        color=discord.Color.dark_gray()
    )
    embed.set_image(url="https://i.pinimg.com/564x/f9/1a/20/f91a2081360598d2ce68d4a43dfd88a2.jpg")
    
    b1 = discord.ui.Button(
        label="Sim",
        style=discord.ButtonStyle.success
    )
    
    b2 = discord.ui.Button(
        label="Não",
        style=discord.ButtonStyle.danger
    )
    view = discord.ui.View()
    view.add_item(b1)
    view.add_item(b2)
    
    await cargo_channel.send(embed=embed, view=view)

bot.run(str(os.environ["TOKEN"])) #TOKEN do bot

Agora que enviamos a mensagem... Vamos voltar para o nosso arquivo principal e adicionar essas funções para que o botão funcione quando o bot estiver funcionando.

Mas para isso... Você vai precisar do ID da mensagem que acabou de enviar. Ative o modo de desenvolvedor no discord e copie clickando com o botão direito na mensagem e em Copiar ID.

Ativando o botão e dando o cargo

@bot.event
async def on_ready():
    async def givingRole(member, guild, idRole, dontRemove=False):
        role = guild.get_role(int(idRole))
        
        if not dontRemove:
            for r in member.roles:
                if r.id == role.id:
                    await member.remove_roles(role)
                    return False

        await member.add_roles(role)
        return True
    
    async def controleGivingCargo(interaction: discord.Interaction, word, dontRemove=False):
        guild = interaction.client.get_guild(int(os.environ["CODE_COMPANY_ID"]))
        if dontRemove:
            #Não remover
            if await givingRole(interaction.user, guild, int(os.environ["TABNEWS_ROLE"]), dontRemove=True):
                await interaction.response.send_message(f"Cargo {word} adicionado", ephemeral=True)
            else:
                await interaction.response.send_message(f"Cargo {word} retirado", ephemeral=True)
        else:
            #Remover
            if await givingRole(interaction.user, guild, int(os.environ["TABNEWS_ROLE"])):
                await interaction.response.send_message(f"Cargo {word} adicionado", ephemeral=True)
            else:
                await interaction.response.send_message(f"Cargo {word} retirado", ephemeral=True)
                
    async def simCallbackTabNews(interaction: discord.Interaction):
        await controleGivingCargo(interaction, "Tab news")
    
    async def naoCallbackTabNews(interaction: discord.Interaction):
        role = interaction.guild.get_role(int(os.environ["TABNEWS_ROLE"]))
        for cargo in interaction.user.roles:
            if cargo.id == role.id:
                return await controleGivingCargo(interaction, "Tab news")
        
        return await interaction.response.send_message("Sem cargo para retirar", ephemeral=True)
    
    guild = bot.get_guild(int(os.environ["CODE_COMPANY_ID"]))
    channel = guild.get_channel(int(os.environ["CARGOS_CHANNEL"]))
    message = await channel.fetch_message(int(os.environ["TABNEWS_MESSAGE"]))
    view = discord.ui.View.from_message(message)
    view.timeout = None
    
    for child in view.children:
        print(child)
        if str(child.label).lower() == "sim":
            child.callback = simCallbackTabNews
        elif str(child.label).lower() == "não":
            child.callback = naoCallbackTabNews
    
    await message.edit(view=view)

Agora basta ativar o bot

bot.run(str(os.environ["TOKEN"])) #TOKEN do bot

Lembrando que...

Eu fiz desse jeito com um monte de funções porque o Code Bot tem várias mensagens assim. Então com uma estrutura melhor fica mais fácil para adicionar novas mensagens ou editar as que estão ali.

Tanto que no bot ele está em um arquivo separado. Mas se você quiser deixar o código mais simples ou mais bagunçado mesmo, fica a seu critério.


Espero que tenha gostado ❤️

Para quem quiser participar da comunidade Code Company ou seguir o canal tabnews para acompanhar os nossos posts por aqui:

🎁 Link Code Company

Tentei trazer um conteúdo bem completo para realmente ajudar a galera que tem um servidor no discord. Mas me diz...

O post foi útil para você?

Teve algo que eu esqueci de falar? Comenta ai!

Qual sua opinião da comparação que eu fiz do TabNews e instagram no começo do post? Comenta ai tambem!

Carregando publicação patrocinada...
1

eu também já tive essa ideia, mais eu fiquei com preguiça e prefiri esperar o Felipe adicionar essa feature ¯⁠\⁠_⁠(⁠ツ⁠)⁠_⁠/⁠¯, mais ainda sim, parabéns pelo trabalho

1

Parabéns pelo desenvolvimento!

Eu vi lá no discord do codecompany, não entrei porque eu já vejo por aqui, mas é uma excelente iniciativa!

Sem falar que explicou por aqui como fez, já recebeu meu like 😄