A Better Quoting System [Live Coding Recap]
Tags: python, beginners, livecoding, twitch
Published: 2019-10-27 22:26:29


## Streamed: 10/27 on Twitch

**Topic(s):** We created a persistent data system for the Twitch Bot
**Language:** [Python](http://bit.ly/nb9kPython), JSON
**Tech & libs used:** [VSCode](http://bit.ly/vscodenb9k), [TwitchIO](https://github.com/TwitchIO/TwitchIO)

> 👇 You can find the code we wrote on stream down below! :D

⭐ **Star** ⇒ [Project Repository](http://bit.ly/DeepThonkRepo)
💜 **Follow** ⇒ on [Twitch](http://bit.ly/nb9kTwitch) and [GitHub](https://github.com/NinjaBunny9000)
🔴 **Watch** ⇒ [Twitch VOD](https://www.twitch.tv/videos/500163411) (replay)

## During the stream we...
✔ unboxed the a hat from DEV!! Ty!!
✔ changed voice on tts to Brian
✔ moved !project command to DeepThonk
✔ get !quoth partially working
✔ handled a case of key-errors
✔ tested out the fixes - it works!
✔ worked on vscode for the next live coding article for a bit
✔ ended the night playing video games w/community

## Making the quote system

We made a command called `!quoth` that takes a user name as an argument and saves the last thing that user said as a quote.

> **BestCoderNA:** I'm not totally useless. I can be used as a bad example!
**F1SavesLives:** !quoth @BestCoderNA
**QUOTE SAVED:** "I'm not totally useless. I can be used as a bad example!" - @BestCoderNA

Here's the entry point to the quoth feature. It's an async command registered in the bot's event loop. You invoke it by sending `!quoth` in chat.

```python
# commands.py
@bot.command(name="quoth")
async def quoth(ctx):
    'the raven, nevermore. nevermore.'
    token = ctx.content.split(' ', 1)  # tokenize™
    author = token[1].lower()  # match case for msg database keys
    if author[0] == '@':  # strip the @ if tagged
        author = author[1:]
    data.quoth(author)
```

Every message sent in chat is added to a dictionary with a key of the user name.

```python
# called in event_message():
def save_last_message(self, author, msg):
    if msg[0] == '!':  # ignore commands
        return
    if msg[0] == '@': # strip tags if tagged
        author = author[1:]
    self.last_message[author] = msg
    log.debug(f"saved: {author} - {self.last_message[author]}")
```

In our `data` object, which is our JSON "database" interface, we use the quoth method to append the python quote to a list of quotes.

```python
# in the `data` object, an instance of DataInterface
def quoth(self, author):
    'take in an author name and add the last thing said from them'

    try:  # check if they've even said anything yet
        incoming_quote = {
            "author" : author,
            "quote" : self.last_message[author]
        }
    except KeyError:
        log.debug(f"{author} hasn't said anything yet...")

    # pull the json data to an object
    with open('quotes.json') as json_file:
        data = json.load(json_file)
        quotes = list()
        for quote in data:
            quotes.append(quote) # add all the quotes from json to a list
        quotes.append(incoming_quote) # add the new quote to the end of the list
        log.debug(f"QUOTE SAVED! {incoming_quote}")

    # rewrite with the new quote
    with open('quotes.json', 'w+') as json_file:
        json.dump(quotes, json_file, indent=4)  # dump it back in to jso
```

And here's the JSON "database" after we tested it out with a few quotes!

```json
[
    {
        "author": "Jigokuniku",
        "quote": "TBH, some best practices are really only ever learned by getting annoyed at the bad practice"
    },
    {
        "author": "NinjaBunny9000",
        "quote": "JUST 👏 BECAUSE 👏 IT'S 👏 EATABLE 👏 DOESN'T 👏 MEAN 👏 IT'S 👏 EDIBLE 👏"
    },
    {
        "author": "J0nnyclueless",
        "quote": "I sometimes get kernel panic attacks"
    },
    {
        "author": "Sockelo",
        "quote": "Forgive them, for they know not what they compile."
    }
]
```