FlamingNinja925
FlamingNinja925

Reputation: 49

How do I send a GIF to a Discord channel using a Python Discord Bot

When the user inputs the command '!gif ' (where is the gif they want), I want the bot to return a gif of that name.

The code that I am trying is based on the API from Tenor, but I don't mind using any other site to get gifs as well. The current code I have doesn't work, and I'm slightly clueless on how I can go about doing this.

Note: I'm doing this as a personal project. I don't mind if you give me the answer, but if you can, please explain why you are doing what you did.

Here's my code so far:

import discord
import requests
import json

from constants import (TenorToken, DiscordToken)

client = discord.Client()
embedColour = 0xff0000

#Retrieves GIF from site
def getGIF(searchTerm):
    response = requests.get("https://g.tenor.com/v1/search?q=%s&key=%s&limit=1" %(searchTerm, TenorToken))
    gif = json.loads(response.content)
    print(gif)

@client.event
async def on_ready():
    print(f"{client.user}"[:-5] + " is now Online!")

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

    if (message.content.lower().startswith(f"{CommandKey}gif")):
        getGIF(message.content.lower()[5:]) #Collects word after !gif

client.run(DiscordToken)

Thank you for any help!

Upvotes: 0

Views: 3818

Answers (1)

furas
furas

Reputation: 143097

I checked your code and Tensor doesn't send GIF data but only urls to images.

This code gives me url for gif in first result`

def get_gif(searchTerm):  # PEP8: lower_case_names for functions

    response = requests.get("https://g.tenor.com/v1/search?q={}&key={}&limit=1".format(searchTerm, TenorToken))

    data = response.json()  # `requests` doesn't need `json.loads()`
         
    return data['results'][0]['media'][0]['gif']['url']

I get it by manually digging in JSON and creating this code

# see urls for all GIFs

for result in data['results']:
    print('- result -')
    #print(result)
    
    for media in result['media']:
        print('- media -')
        #print(media)
        #print(media['gif'])
        print('url:', media['gif']['url'])

And when I get url then I can use Embed to send url and discord will download it and display - I don't have to download it.

if (message.content.lower().startswith(f"{CommandKey}gif")):

    gif_url = get_gif(message.content.lower()[5:]) #Collects word after !gif
    
    embed = discord.Embed()
    embed.set_image(url=gif_url)

    await message.channel.send(embed=embed)

Full working code

import discord
import requests

from constants import (TenorToken, DiscordToken)

#import os
#DiscordToken = os.getenv('DISCORD_TOKEN')
#TenorToken = os.getenv('TENOR_TOKEN')

client = discord.Client()

embedColour = 0xff0000
CommandKey = '!'

# --- functions ---

#Retrieves GIF from site
def get_gif(searchTerm):  # PEP8: lower_case_names for functions
    response = requests.get("https://g.tenor.com/v1/search?q={}&key={}&limit=1".format(searchTerm, TenorToken))
    data = response.json()
    
    ''' 
    # see urls for all GIFs
    
    for result in data['results']:
        print('- result -')
        #print(result)
        
        for media in result['media']:
            print('- media -')
            print(media)
            print(media['gif'])
            print('url:', media['gif']['url'])
    '''
         
    return data['results'][0]['media'][0]['gif']['url']
    

@client.event
async def on_ready():
    print(f"{client.user}"[:-5] + " is now Online!")

@client.event
async def on_message(message):
    if message.author == client.user:  # `if/else` doesn't need `()`
        return

    if message.content.lower().startswith(f"{CommandKey}gif"):
        gif_url = get_gif(message.content.lower()[5:]) #Collects word after !gif
        
        embed = discord.Embed()
        embed.set_image(url=gif_url)
        await message.channel.send(embed=embed)

# --- main ---

client.run(DiscordToken)

EDIT:

The same with downloading gif to local computer memory (using io.BytesIO) and sending as normal file.

import io

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

    if (message.content.lower().startswith(f"{CommandKey}gif")):
        gif_url = get_gif(message.content.lower()[5:]) #Collects word after !gif
        # download image from url
        response = requests.get(gif_url) 
        
        # put it in file-like object in memory
        file_like_object = io.BytesIO(response.content)

        #file_name = 'image.gif'
        file_name = gif_url.split('/')[-1]
        
        # send it as normal file
        # it needs filename with extension `.gif` to display it as GIF image
        await message.channel.send(file=discord.File(file_like_object, filename=file_name))

It need longer time to display because it have to get it to local computer and then send it to internet.

It could be used to edit image (ie. add text, change color, draw figures) using pillow, wand, gizeh, detect faces/peoples/object with opencv, genererate videos with moviepy, etc.


BTW:

In answer to question How to make a canvas profile card in discord python bot? I use pillow to add elements to image. But it is static image, not animated GIF which would need more work (with every frame separatelly)

Upvotes: 4

Related Questions