Skip to content

Twitch chat interactivity! #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

dansanderson
Copy link

This PR introduces a major new feature set for Cursewords: Twitch chat interactivity! Cursewords can connect to a Twitch channel's chat room and react to messages posted by viewers. Features include:

  • Guessing
    • When someone posts a message to the chat containing a solution to an unsolved clue, the board will highlight the squares with an animation. This signals to the solver that someone has made a correct guess without revealing it, and rewards viewers for guessing.
    • Any word or phrase in a chat message counts as a guess. Commonly used CursewordsLive syntax is supported.
  • Clues
    • Anyone can request one of the clues from the board with the !clue command, like so: !clue 22d
    • The requested clue is posted to the room.

This introduces a new configuration system for storing Twitch credentials and settings. It can use a configuration file in the TOML format, located in either the current working directory or in $HOME/.config/. Settings can be set or overridden on the command line as well. This system is flexible enough to use for future features.

See README.md for usage instructions.


Technical notes

This version uses twitchapps.com/tmi/ "OAuth tokens" for authentication. OIDC implicit code flow might be more user friendly (I think that's the one where you can open a browser and just sign in with the bot account?) but this works well enough if you're willing to copy-paste the token into config. I include instructions in the README.

The Twitch client runs in its own thread to avoid impeding the solving UI. It accesses Grid without explicit thread safety support, so I don't know if that'll be an issue. I considered a queue.Queue but so far this seems to work as is.

websockets uses asyncio coroutines. The coroutine event loop runs in the Twitch child thread. On exit, the main thread joins the Twitch thread so it can clean up. The Twitch thread also keeps track of who made correct guesses to print in an on-screen thank you message when quitting.

I could have used TwitchIO, an asyncio-based library with much of the chat bot functionality in twitch.py. I decided to try it with raw websockets because I thought I'd be able to figure out "whisper" support that TwitchIO v1 doesn't yet have. I concluded that whisper support requires "verified" bot status and decided to punt for now.

I wanted whisper support so that clue requests could be private and not spam the chat. With clues going to the public chat, I added a cooldown mechanism so a given user can only ask for a clue every so many seconds (configurable). I'm sure CursewordsLive attendees will be well behaved and this is probably overkill.

Outgoing messages use a delayed queue of one message per second to avoid tripping Twitch's rate limit for (unverified?) bots.

I left in some logging support that was useful for troubleshooting Twitch behaviors without cluttering the display. As submitted, it's disabled by default via config, and only logs IRC "NOTICE" messages. It could be used for other things.

I tried to keep intrusions on the main branch minimal:

  • New features are disabled by default. Current users should experience no difference.
  • websockets and pytest are the only new dependencies, and pytest is just for development.
  • Twitch client and config system are in separate source files.
  • cursewords.py still contains Grid and the main loop. It's probably time to spilt things out into more files and helper functions, but I didn't want to introduce refactoring alongside new features.
  • I did reformat a bit for PEP8 compliance, via autopep8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant