0

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!

  • 1
    you print(gif) but you do nothing to send this GIF - you should see documentation how to send/embed files. I'm not sure but It may need to save file on disk before sending. Eventually it may need to use `io.BytesIO` to create fake file in memory. – furas Apr 26 '21 at 22:09
  • Oh, I was hoping I wouldn't need to save the GIF on my computer first, but I guess I might have to in the end. – FlamingNinja925 Apr 26 '21 at 22:10
  • 1
    first you should search information how to send image - ie. `send(file=filename)` - and later you can try to use `io.BytesIO()` (file-like object) instead of `filename`. Some functions (in different modules) can work with file-like object instead of `filename` – furas Apr 26 '21 at 22:12
  • 1
    using Gooogle I found some example which send image from file on disk and it use handler to opened file and this means you can use `io.BytesIO()` instead of handler. – furas Apr 26 '21 at 22:14
  • Oh all right, thanks @furas – FlamingNinja925 Apr 26 '21 at 22:22
  • I checked your code and `tenor` doesn't send GIF file but only URL to file and this may need something different. You would have to download it - or you could use `Embed` with `url` – furas Apr 26 '21 at 22:27

1 Answers1

4

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)

furas
  • 134,197
  • 12
  • 106
  • 148