Articolo originale: Python Discord Bot Tutorial – Code a Discord Bot And Host it for Free

Questo tutorial mostra come costruire il tuo bot Discord completamente nel cloud.

Non hai bisogno di installare nulla sul tuo computer, e non hai bisogno di pagare nulla per hostare il tuo bot.

Useremo vari strumenti, quali Discord API, librerie di Python, e una piattaforma di cloud computing chiamata Repl.it.

C'è anche una versione video di questo tutorial. Il video è qua sotto, e la versione scritta dopo il video.

Come creare un Account Discord Bot

Per lavorare con la libreria di Python e la API di Discord dobbiamo prima creare un account Bot in Discord.

Ecco gli step per creare un account Discord Bot.

1. Assicurati di avere fatto il lod in sul sito web di Discord.

2. Naviga alla pagina delle applicazioni.

3. Usa il pulsante “New Application”.

image-117

4. Dai un nome all'applicazione e usa il pulsante “Create”.

image-118

5. Vai alla scheda “Bot” e premi “Add Bot”. Dovrai confermarlo premento il pulsante "Yes, do it!"

image-119

Usa le impostazioni di default per Public Bot (segnato) e Require OAuth2 Code Grant (non segnato).

Il tuo bot è stato creato. Lo step successivo è copiare il token.

image-122

Questo token è la password del tuo bot, quindi non condividerla con nessuno. Permetterebbe ad altri di accedere al tuo bot e fare cose cattive.

Puoi rigenerare il token se viene condiviso accidentalmente.

Come invitare il tuo bot a unirsi a un server

Ora devi inserire il tuo bot in un server. Per farlo devi creare un URL di invito per esso.

Vai alla scheda "OAuth2". Poi seleziona "bot" nella sezione "scopes".

image-123

Ora scegli i permessi che vuoi che il tuo bot abbia. Il tuo bot userà principalmente messaggi di testo quindi non ha bisogno di molte autorizzazioni. Potresti aver bisogno di più autorizzazioni a seconda di cosa vuoi che il tuo bot faccia. Fai attenzione con l'autorizzazione "Administrator".

image-124

Dopo aver seleziono le autorizzazioni approrpiate, usa il pulsante "copy" sopra le autorizzazioni, così da copiare un URL che può essere usato per aggiungere il bot a un server.

Incolla l'URL nel tuo broswe, seleziona un server a cui invitare il bot e premi il pulsante "Authorize".

Per aggiungere il bot, il tuo account ha bisogno dell'autorizzazione  "Manage Server".

Ora che hai creato l'utente bot, iniziamo a scrivere il codice in Python per il bot.

Come programmare un Bot per discord basico con la libreria discord.py

Useremo la libreria discord.py per scrivere il codice del bot, è un wrapper per la API di Discord che rende più semplice creare un bot Discord in Python.

Come creare un Repl e installare discord.py

Puoi sviluppare il bot sul tuo computer con qualsiasi editor di codice, però in questo tutorial useremo Replit perché rende più semplice per tutti seguire il tutorial. Replit è un IDE online che puoi usare nel tuo browser.

Inizia andando su Repl.it e crea un nuovo Repl, scegli Python come linguaggio da usare.

Per usare la libreria discord.py scrivi semplicemente import discord in cima al file main.py, e replit installerà automaticamente la dipendenza quando usi il pulsante "Run".

Se preferisci programmare il locale. puoi usare questo comando su macOS per installare discord.py:

python3 -m pip install -U discord.py

Potresti dover usare pip3 invece di pip.

Se stai usando Windows allora dovresti usare questa riga di comando:

py -3 -m pip install -U discord.py

Come impostare gli eventi Discord per il tuo bot

discord.py è incentrato sul concetto di eventi. Un evento è qualcosa a cui ascolti e poi rispondi. Per esempio quando un messaggio viene mandato, riceverai un evento legato a cui puoi rispondere.

Facciamo un bot che risponde a uno specifico messaggio. Questo semplice codice per il bot, assieme alla spiegazione, è preso dalla documentazione ufficiale di discord.py. Aggiungeremo altre funzionalità al bot più tardi.

Aggiungi questo codice a main.py. (puoi chiamare il file come vuoi, basta che non si chiami discord.py). Spiegherò cosa fa questo codice in un momento.

import discord
import os

client = discord.Client()

@client.event
async def on_ready():
    print('We have logged in as {0.user}'.format(client))

@client.event
async def on_message(message):
    if message.author == client.user:
        return

    if message.content.startswith('$hello'):
        await message.channel.send('Hello!')

client.run(os.getenv('TOKEN'))

Quando hai creato il tuo utente bot su Discord, hai ottenuto un token. Ora salveremo questo token nella tab Secrets.

image-2

In questo modo il Token rimarrà segreto. Al di fuori di repl.it useresti un file .env per dichiarare le variabili di ambiente.

Quindi, se stai sviluppando su Repl.it, includi solo informazioni private come token o chiavi tab Secrets.

Per salvare il tuo Token, scrivi TOKEN nel campo "key", e incolla il token che hai preso dalle impostazioni del bot nel campo "value", poi premi "Add new secret".

Ora vediamo cosa fa ogni riga di codice nel tuo bot Discord.

  1. La prima riga importa la libreria discord.py.
  2. La seconda riga importa la libreria os, che è usata per ottenere la variabile TOKEN dal file .env (o dalla tab Secrets nel caso di replit).
  3. Poi, creiamo una istanza di Client. Questa è la connessione con Discord.
  4. Il decoratore @client.event() è usato per registrare un evento. Questa è una libreria asincrona, quindi le cose sono eseguite tramite i callback. Un callback è una funzione che è chiamata quando qualcos altro accade. In questo caso la funzione on_ready() è chiamata quando il bot è pronto a iniziare a essere usato. Poi, quando il bot riceve un messaggio, viene chiamato l'evento on_message().
  5. L'evento on_message() è attivato ogni volta che un messaggio viene ricevuto, ma non vogliamo che accada nulla se il messaggio è da noi stessi (dal bot). Quindi se l'autore del messaggio Message.author è uguale a Client.user il codice semplicemente ritorna.
  6. Poi controlliamo se il contenuto del messaggio Message.content inizia con '$hello'. In tal caso il bot risponde con 'Hello!' nello stesso canale.
  7. Ora che il bot è impostato, l'ultima riga esegue il bot con il token per il login, prendendo il token dai nostri Secrets.

Abbiamo il codice del bot, ora dobbiamo eseguirlo.

Come eseguire il Bot

Clicka il pulsante Run in cima alla pagina per eseguire il tuo bot su replit.

Se stai scrivendo il tuo bot in locale, puoi usare questi comandi nel terminale per eseguire il bot:

Su Windows:

py -3 main.py

Su altri sistemi:

python3 main.py

Ora vai sul tuo server Discord e scrivi "$hello". Il tuo bot dovrebbe rispondere con "Hello!".

image-141

Come migliorare il bot

Ora che abbiamo un bot basilare funzionante, lo miglioreremo. Si chiama "Encourage Bot" per una ragione.

Questo bot risponderà con un messaggio di incoraggiamento ogni volta che qualcuno usa una parola triste o deprimente.

Chiunque sarà in grado di aggiungere messaggi da far usare al bot e i messaggi creati dagli utenti saranno immagazzinati nel database di replit.

Il bot avrà anche la funzionalità di mandare una citazione ispirante da una API quando qualcuno scrive "$inspire" nella chat.

Iniziamo aggiungendo la funzione "$inspire".

Come aggiungere citazioni ispiranti al bot

Otterremo le citazioni da una API chiamata zenquotes.io. Dobbiamo importare un altro paio di moduli Python, get_quote() function, e aggiornare il nostro bot affinché la usi.

Ecco il codice aggiornato, dopo il codice spiegherò le nuove parti.

import discord
import os
import requests
import json

client = discord.Client()

def get_quote():
  response = requests.get("https://zenquotes.io/api/random")
  json_data = json.loads(response.text)
  quote = json_data[0]['q'] + " -" + json_data[0]['a']
  return(quote)

@client.event
async def on_ready():
  print('We have logged in as {0.user}'.format(client))

@client.event
async def on_message(message):
  if message.author == client.user:
    return

  if message.content.startswith('$inspire'):
    quote = get_quote()
    await message.channel.send(quote)

client.run(os.getenv('TOKEN'))

Adesso dobbiamo importare il modulo requests che permette di fare richieste HTTP  per ottenere dati dalla API, l'API restituisce JSON, e il modulo json ci rende più facile lavorare con i dati ricevuti.

La funzione get_quote() è piuttosto semplice: come prima cosa usa il modulo requests per richiedere dati dall'URL dell'API. L'API restituisce una citazione casuale (questa funzione può facilmente essere riscritta per usare una API diversa se questa smette di funzionare).

Poi, dentro la funzione usiamo json.loads() per convertire la risposta dell'API in JSON. Con svariate prove sono riuscito a ottenere la citazione dal JSON nel formato stringa che volevo. La citazione è restituita dalla funzione come una stringa.

L'ultima parte che è stata aggiunta è verso la fine. Prima guardava per un messaggio che inizia con "$hello", ora guarda per "$inspire", e invece di restituire "Hello!" ottiene la citazione con quote = get_quote() e restituisce la citazione.

A questo punto puoi eseguire il codice e provarlo.

Come aggiungere messaggi di incoraggiamento al bot

Ora implementeremo la funzione in cui il bot risponde con un messaggio incoraggiante quando un utente usa una parola triste in un messaggio.

Come aggiungere le parole tristi al bot

Prima dobbiamo creare una lista di Python che contiene le parole tristi a cui il bot dovrà rispondere.

Aggiungi la seguente riga dopo che è stata creata la variabile client:

sad_words = ["sad", "depressed", "unhappy", "angry", "miserable"]

Aggiungi liberamente altre parole alla lista.

Come aggiungere messaggi incoraggianti al bot

Ora aggiungeremo una lista di messaggi incoraggianti che il bot può usare per rispondere.

Aggiungi questa lista dopo la lista sad_words che hai creato:

starter_encouragements = [
  "Cheer up!",
  "Hang in there.",
  "You are a great person / bot!"
]

Come prima, aggiungi liberamente altre frasi di tua scelta alla lista. Sto usando solo tre elementi per adesso perché poi aggiungeremo l'abilità di avere gli utenti aggiungere nuove frasi che il bot possa usare.

Come rispondere ai messaggi

Ora dobbiamo aggiornare il nostro bot per usare le due liste che abbiamo creato. Come prima cosa importa il modulo random così il bot sceglierà i messaggi incoraggianti casualmente. Aggiungi questa riga agli import in cima al file: import random.

Ora aggiorneremo la funzione on_message() per controllare tutti i messaggi e vedere se contengono una delle parole nella lista sad_words, e se una è trovata il bot risponderà con un incoraggiamento casuale.

Ecco il codice aggiornato:

async def on_message(message):
  if message.author == client.user:
    return

  msg = message.content

  if msg.startswith('$inspire'):
    quote = get_quote()
    await message.channel.send(quote)
    
  if any(word in msg for word in sad_words):
    await message.channel.send(random.choice(starter_encouragements))

Questo è un buon momento per testare il bot. Ora ne sai abbastanza per creare il tuo bot, ma prima imparerai come implementare funzionalità più avanzare e immagazzinare dati usando il database di replit.

Come attivare i messaggi aggiunti dagli utenti

Il bot è completamente funzionale, ma ora vogliamo rendere possibile aggiornare il bot direttamente da Discord: un utente dovrebbe essere in grado di aggiungere nuovi messaggi incoraggianti alla lista di messaggi che il bot usa.

Useremo il database integrato in replit per immagazzinare i messaggi creati dagli utenti, è un database chiave-valore integrato in ogni repl.

In cima al codice, sotto gli altri import, aggiungi from replit import db, questo ci permetterà di usare il database di replit.

Gli utenti avranno la possibilità di aggiungere messaggi incoraggianti personalizzati alla lista disponibile al bot direttamente da Discord. Ma prima di creare nuovi comandi per il bot, creiamo due funzioni che aggiungono e rimuovono i messaggi personalizzati dal database.

Aggiungi questo codice dopo la funzione get_quote():

def update_encouragements(encouraging_message):
  if "encouragements" in db.keys():
    encouragements = db["encouragements"]
    encouragements.append(encouraging_message)
    db["encouragements"] = encouragements
  else:
    db["encouragements"] = [encouraging_message]

def delete_encouragment(index):
  encouragements = db["encouragements"]
  if len(encouragements) > index:
    del encouragements[index]
  db["encouragements"] = encouragements

La funzione update_encouragements() accetta un messaggio incoraggiante come argomento.

Prima controlla se "encouragements" è una chiave nel database, se sì ottiene la lista dei messaggi già presenti nel database, aggiunge il nuovo messaggio alla lista, e salva la lista aggiornata nel database sotto la chiave "encouragements".

Se il database non contiene la chiave "encouragements", allora crea una nuova chiave con questo nome, e il nuovo messaggio di incoraggiamento è aggiunto come primo elemento della lista.

La funzione delete_encouragement() accetta un indice come argomento.

Ottiene la lista degli incoraggiamenti dal database salvati sotto la chiave "encouragements". Se il numero degli elementi nella lista è maggiore del valore di inev allora l'elemento a quell'indice viene eliminato.

Infine la lista aggiornata è salvata di nuovo nel database sotto la chiave "encouragements".

Ecco il codice aggiornato per la funzione on_message(). Dopo il codice spiego questa nuova sezione.

async def on_message(message):
  if message.author == client.user:
    return

  msg = message.content
 
  if msg.startswith("$inspire"):
    quote = get_quote()
    await message.channel.send(quote)

  options = starter_encouragements
  if "encouragements" in db.keys():
    options = options + db["encouragements"]

  if any(word in msg for word in sad_words):
    await message.channel.send(random.choice(options))

  if msg.startswith("$new"):
    encouraging_message = msg.split("$new ",1)[1]
    update_encouragements(encouraging_message)
    await message.channel.send("New encouraging message added.")

  if msg.startswith("$del"):
    encouragements = []
    if "encouragements" in db.keys():
      index = int(msg.split("$del",1)[1])
      delete_encouragment(index)
      encouragements = db["encouragements"]
    await message.channel.send(encouragements)

La prima riga nuova nel codice qua sopra è options = starter_encouragements. Stiamo facendo una copia di starter_encouragements perché aggiungeremo i messaggi creati dagli utenti alla lista prima di scegliere il messaggio casuale che il bot userà.

Controlliamo se "encouragements" è già una chiave nel database (cioè se gli utenti hanno creato almeno un messaggio personalizzato). Se è così, aggiungiamo i messaggi creati dagli utenti ai messaggi iniziali di incoraggiamento.

Poi, invece di inviare un messaggio casuale da starter_encouragements, il messaggio è estratto casualmente da options.

La prossima sezione nuova è usata per aggiungere un messaggio creato dagli utenti al database. Se un messaggio di Discord inizia con "$new", il testo dopo "$new" sarà usato come messaggio incoraggiante.

Il codice msg.split("$new ",1)[1] divide il messaggio dal comando "$new" e salva il emssaggio in una variabile. In questa riga di codice nota lo spazio in  "$new ". Vogliamo tutto dopo lo spazio.

Poi chiamiamo la funzione aiutante update_encouragements con il nuovo messaggio e poi il bot manda un messaggio confermando che il nuovo messaggio è stato aggiunto.

La terza sezione (alla fine del codice esaminato qua dopra) controlla se un messaggio inizia con  "$del". Questo è il comando per eliminare un messaggio dalla lista "encouragements" nel database.

Come prima cosa una variabile chiamata encouragements è inizializzata come array vuoto. La ragione per questo è che la sezione del codice manderà un messaggio con un array vuoto se il database non include la chiave "encouragement".

Se la chiave  "encouragement" è nel database, l'indice sarà separato dal messaggio che inizia con "$del". Allora, la funzione delete_encouragement() è chiamata con argomento l'indice così ottenuto. La lista aggiornata è caricata nella variabile encouragements e il bot manda un messaggio a Discord con l'attuale lista.

Funzionalità finali del bot

Il bot dovrebbe funzionare ed è un buon momento per testarlo. Aggiungeremo adesso alcune funzionalità finali.

Aggiungeremo l'abilità di ottenere una lista di messaggi creati dagli utenti direttamente da Discord, e aggiungeremo l'abilità di attivare e disattivare la funzionalità della risposta alle parole tristi.

Ti darò il codice completo del programma, poi discuterò gli aggiornamenti sotto il codice.

import discord
import os
import requests
import json
import random
from replit import db

client = discord.Client()

sad_words = ["sad", "depressed", "unhappy", "angry", "miserable"]

starter_encouragements = [
  "Cheer up!",
  "Hang in there.",
  "You are a great person / bot!"
]

if "responding" not in db.keys():
  db["responding"] = True

def get_quote():
  response = requests.get("https://zenquotes.io/api/random")
  json_data = json.loads(response.text)
  quote = json_data[0]["q"] + " -" + json_data[0]["a"]
  return(quote)

def update_encouragements(encouraging_message):
  if "encouragements" in db.keys():
    encouragements = db["encouragements"]
    encouragements.append(encouraging_message)
    db["encouragements"] = encouragements
  else:
    db["encouragements"] = [encouraging_message]

def delete_encouragment(index):
  encouragements = db["encouragements"]
  if len(encouragements) > index:
    del encouragements[index]
  db["encouragements"] = encouragements

@client.event
async def on_ready():
  print("We have logged in as {0.user}".format(client))

@client.event
async def on_message(message):
  if message.author == client.user:
    return

  msg = message.content

  if msg.startswith("$inspire"):
    quote = get_quote()
    await message.channel.send(quote)

  if db["responding"]:
    options = starter_encouragements
    if "encouragements" in db.keys():
      options = options + db["encouragements"]

    if any(word in msg for word in sad_words):
      await message.channel.send(random.choice(options))

  if msg.startswith("$new"):
    encouraging_message = msg.split("$new ",1)[1]
    update_encouragements(encouraging_message)
    await message.channel.send("New encouraging message added.")

  if msg.startswith("$del"):
    encouragements = []
    if "encouragements" in db.keys():
      index = int(msg.split("$del",1)[1])
      delete_encouragment(index)
      encouragements = db["encouragements"]
    await message.channel.send(encouragements)

  if msg.startswith("$list"):
    encouragements = []
    if "encouragements" in db.keys():
      encouragements = db["encouragements"]
    await message.channel.send(encouragements)
    
  if msg.startswith("$responding"):
    value = msg.split("$responding ",1)[1]

    if value.lower() == "true":
      db["responding"] = True
      await message.channel.send("Responding is on.")
    else:
      db["responding"] = False
      await message.channel.send("Responding is off.")

client.run(os.getenv("TOKEN"))

La prima sezione aggiunta al codice è sotto la lista starter_encouragements:

if "responding" not in db.keys():
  db["responding"] = True

Creiamo una nuova chiave nel database chiamata "responding" e la impostiamo su "True". Useremo questo per determinare se il bot debba rispondere alle parole tristi o no. Visto che il database è salvato anche dopo che il programma smette di eseguire, creiamo la nuova chiave solo se non esiste.

La parte successiva del codice è che la sezione del codice che risponde alle parole tristi è ora all'interno di una istruzione if: if db["responding"]:. Il bot risponderà alle parole tristi solo se db["responding"] = True. L'abilità di cambiare questo valore viene nella sezione successiva.

Poi, dopo il codice che fa sì che il bot risponda a "$del", c'è del nuovo codice che fa rispondere a un comando "$list".

Questa sezione inizia creando una lista vuota chiamata encouragements. Quindi, se ci sono già incoraggiamenti nel database, questi rimpiazziano la lista vuota appena creata.

Infine, il bot manda la lista di incoraggiamenti in un messaggio su Discord.

L'ultima nuova sezione viene come successiva. Questo codice fa si che il bot risponda al comando "$responding". Questo comando prende un argomento di "true" o "false". Ecco un esempio di utilizzo: "$responding true".

Il codice prima estrae l'argomento dal messaggio con value = msg.split("$responding ",1)[1] (come prima, nota il messaggio in "$responding "). Poi c'è una istruzione if/else che imposta la chiave "responding" nel database e manda un messaggio di notifica a Discord. Se l'argomento è diverso da "true", il codice assume "false".

Il codice per il bot è completo! Puoi adesso esegurie il tuo bot e provarlo. Ma c'è un altro importante step da discutere.

Come fare sì che il tuo bot esegua continuamente

Se esegui il tuo bot in replit e poi chiudi la scheda, il bot smetterà di eseguire.

Ma ci sono due modi in cui puoi tenere il tuo bot in continua esecuzione, anche dopo aver chiuso il browser.

Il primo modo e il più semplice è abbonarsi a replit, il loro abbonamento più economico si chiama Hacker Plan e include 5 repl sempre attive.

Puoi ottenere tre mesi gratis con questo codice (limitato alle prime 1000 persone):  https://repl.it/claim?code=tryalwayson2103

Una colta che hai fatto l'abbonamento, apri il tuo repl e clicca sul nome in cima, poi seleziona l'opzione "Always On".

image-35-1

C'è un altro metodo per tenere il tuo codice in esecuzione anche sul piano gratuito di replit. Replit continuerà a eseguire un server web anche dopo che la tab è stata chiusa, ma eseguirà solo per un'ora senza alcun uso.

Ecco cosa dice la documentazione di replit:

Una volta eseguito, il server continuerà a eseguire nel backgroun anche dopo che chiudi la scheda del browser. Il server starà sveglio e attivo fino a un'ora dopo la sua ultima richiesta, dopo di che entrerà in uno stato dormiente. Repl addormentate si svegliano una volta ricevuta una nuova richiesta; non c'è alcuna necessità di eseguire di nuovo il repl. Ma se fai cambiamenti al tuo server allora dovrai farla ripartire per vedere cambiamenti riflessi nella versione live.

Per mantenere il bot sempre attivo useremo un altro servizio gratuito, https://uptimerobot.com/.

Uptime Robot può essere impostato per fare un ping al server del bot ogni 5 minuti. Con ping costanti, il bot non entrerà mai nella fase dormiente e continuerà a eseguire.

Quindi dobbiamo fare altre due cose per avere un bot sempre in esecuzione:

  1. creare un server web in replit e
  2. impostare Uptime Robot per mandare ping continui al server.

Come creare un server web in replit

Creare un server web è più semplice di quanto tu possa pensare.

Per farlo crea un nuovo file nel tuo progetto chiamato keep_alive.py.

Quindi aggiungi questo codice:

from flask import Flask
from threading import Thread

app = Flask('')

@app.route('/')
def home():
    return "Hello. I am alive!"

def run():
  app.run(host='0.0.0.0',port=8080)

def keep_alive():
    t = Thread(target=run)
    t.start()

In questo codice usiamo Flask per iniziare un server web, il server restituisce "Hello. I am alive." a chiunque lo visiti. Il server eseguirà su un thread separato rispetto al nostro bot. Non discuteremo tutto qui visto che il resto non è rilevante per il nostro bot.

Ora abbiamo solo bisogno che il nostro bot esegua questo server web.

Aggiungi la seguente riga verso la cima di main.py per importare il server.

from keep_alive import keep_alive

Per iniziare il server web quando main.py viene eseguito, aggiungi la seguente riga come penultima riga del fila, proprio prima che il bot venga eseguito.

keep_alive()

Quando esegui il bot on replit dopo aver aggiunto questo codice una nuova finestra per il server web si aprirà, e c'è un URL mostrato per il server web, copia questo url, lo useremo nella prossima sezione.

image-20-1

Come impostare Uptime Robot

Ora dobbiamo impostare Uptime Robot affinché mandi un ping al nostro web server ogni cinque mintui. Questo farà si che il bot esegua continuamente.

Crea un account gratuito su https://uptimerobot.com/.

Una volta che hai fatto accesso con il tuo account, clicca su "Add New Monitor".

image-21-1

Per il nuovo monitor, seleziona "HTTP(s)" come Monitor Type e chiamalo come preferisci, poi incolla l'url del web server e clicca su "Create Monitor".

image-22-1

E con questo abbiamo finito! Ora il tuo bot eseguirà continuamente su replit e gli utenti potranno sempre interagirci!

Conclusione

Ora sai come creare un bot Discord con Python e eseguirlo continuosamente nel cloud.

Ci sono un sacco di altre cose che la libreria discord.py può fare. Se vuoi dare ancora più funzionalità al tuo bot il tuo prossimo passo è consultare la documentazione ufficiale di discord.py.