Browse Source

added raffle feature

closes #12
dev
Netali 1 year ago
parent
commit
4c27c411a1
  1. 4
      python/eulinchen/dc_pusher/dc_pusher.py
  2. 6
      python/eulinchen/dc_responder/dc_responder.py
  3. 5
      python/eulinchen/lib/db/exceptions.py
  4. 1
      python/eulinchen/lib/exceptions/__init__.py
  5. 7
      python/eulinchen/lib/exceptions/exceptions.py
  6. 25
      python/eulinchen/lib/twitch/dataclasses.py
  7. 17
      python/eulinchen/lib/twitch/exceptions.py
  8. 26
      python/eulinchen/lib/twitch/twitch.py
  9. 0
      python/eulinchen/twitch_responder/lib/__init__.py
  10. 52
      python/eulinchen/twitch_responder/lib/raffle.py
  11. 8
      python/eulinchen/twitch_responder/lib/redis.py
  12. 102
      python/eulinchen/twitch_responder/twitch_responder.py
  13. 1
      requirements.txt

4
python/eulinchen/dc_pusher/dc_pusher.py

@ -49,7 +49,7 @@ async def event_loop(): @@ -49,7 +49,7 @@ async def event_loop():
+ "**" + data['broadcaster_user_name'] + "** streamt jetzt!")
else:
stream_data = stream_data[0]
user = twitch.get_user(id=stream_data['user_id'])['data'][0]
user = twitch.get_user(id=stream_data['user_id'])
embed = discord.Embed(
title="Link zum Stream",
url="https://twitch.tv/{stream_user}".format(
@ -63,7 +63,7 @@ async def event_loop(): @@ -63,7 +63,7 @@ async def event_loop():
url="https://twitch.tv/{stream_user}".format(
stream_user=stream_data['user_login']
),
icon_url=user['profile_image_url']
icon_url=user.profile_image_url
)
embed.set_thumbnail(
url=stream_data['thumbnail_url'].format(

6
python/eulinchen/dc_responder/dc_responder.py

@ -64,15 +64,15 @@ async def hallo(ctx: Context): @@ -64,15 +64,15 @@ async def hallo(ctx: Context):
@bot.command('amaistream')
async def amaistream(ctx: Context):
user_data = twitch.get_user(id=config.amai_twitch_user_id)['data'][0]
user_data = twitch.get_user(id=config.amai_twitch_user_id)
stream_data = twitch.get_streams(user_id=config.amai_twitch_user_id)['data']
if stream_data:
stream_data = stream_data[0]
message = '**' + user_data['display_name'] + '** streamt gerade **' + \
message = '**' + user_data.display_name + '** streamt gerade **' + \
stream_data['game_name'] + '**!\n**Streamtitel:** ' + stream_data['title'] + \
'\n**Link zum Stream:** https://twitch.tv/' + stream_data['user_login']
else:
message = '**' + user_data['display_name'] + '** streamt grade nicht :('
message = '**' + user_data.display_name + '** streamt grade nicht :('
await ctx.send(message)

5
python/eulinchen/lib/db/exceptions.py

@ -1,4 +1,7 @@ @@ -1,4 +1,7 @@
class MySQLException(Exception):
from eulinchen.lib.exceptions import EulinchenException
class MySQLException(EulinchenException):
pass

1
python/eulinchen/lib/exceptions/__init__.py

@ -0,0 +1 @@ @@ -0,0 +1 @@
from .exceptions import *

7
python/eulinchen/lib/exceptions/exceptions.py

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
# Base exception for all exceptions of Eulinchen
class EulinchenException(Exception):
pass
class InvalidArgumentException(EulinchenException):
pass

25
python/eulinchen/lib/twitch/dataclasses.py

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
from dataclasses import dataclass, InitVar
from dateutil import parser
from datetime import datetime, tzinfo
import pytz
@dataclass
class TwitchUser:
id: int
login: str
display_name: str
type: str
broadcaster_type: str
description: str
profile_image_url: str
offline_image_url: str
view_count: int
created_at: datetime
init_id: InitVar[str]
init_created_at: InitVar[str]
init_tz: InitVar[tzinfo] = pytz.utc
def __post_init__(self, init_id: str, init_created_at: str, init_tz: tzinfo):
self.id = int(init_id)
self.created_at = parser.isoparse(init_created_at).astimezone(init_tz)

17
python/eulinchen/lib/twitch/exceptions.py

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
from eulinchen.lib.exceptions import EulinchenException
class TwitchException(EulinchenException):
pass
class TwitchUserNotFoundException(TwitchException):
pass
class TwitchFollowNotFoundException(TwitchException):
pass
class TwitchInvalidUserId(TwitchException):
pass

26
python/eulinchen/lib/twitch/twitch.py

@ -1,6 +1,10 @@ @@ -1,6 +1,10 @@
import requests
from datetime import datetime, timedelta
from pytz import timezone
from eulinchen.lib.exceptions import InvalidArgumentException
from eulinchen.lib.twitch.exceptions import TwitchFollowNotFoundException, TwitchUserNotFoundException
from eulinchen.lib.twitch.dataclasses import TwitchUser
from dateutil import parser
class Twitch:
@ -40,7 +44,7 @@ class Twitch: @@ -40,7 +44,7 @@ class Twitch:
return self._headers
def subscribe(self, sub_type: str, broadcaster_user_id: str, secret: str) -> dict:
def subscribe(self, sub_type: str, broadcaster_user_id: int, secret: str) -> dict:
data = {
"type": sub_type,
"version": "1",
@ -73,13 +77,22 @@ class Twitch: @@ -73,13 +77,22 @@ class Twitch:
headers=self.request_headers,
)
def get_user(self, **params) -> dict:
def get_user(self, **params) -> TwitchUser:
request = requests.get(
'https://api.twitch.tv/helix/users',
headers=self.request_headers,
params=params
)
return request.json()
if request.status_code == 400:
raise InvalidArgumentException()
result = request.json()
if not result['data']:
raise TwitchUserNotFoundException()
ret_user = result['data'][0]
return TwitchUser(init_id=ret_user['id'],
init_created_at=ret_user['created_at'],
init_tz=self._tz,
**ret_user)
def get_streams(self, **params) -> dict:
request = requests.get(
@ -96,3 +109,10 @@ class Twitch: @@ -96,3 +109,10 @@ class Twitch:
params=params
)
return request.json()
def get_user_follows_since(self, from_id: int, to_id: int) -> timedelta:
follows = self.get_user_follows(from_id=from_id, to_id=to_id)
if follows['total'] < 1:
raise TwitchFollowNotFoundException()
followed_at = parser.isoparse(follows['data'][0]['followed_at'])
return datetime.now(tz=self._tz) - followed_at.astimezone(self._tz)

0
python/eulinchen/twitch_responder/lib/__init__.py

52
python/eulinchen/twitch_responder/lib/raffle.py

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
from eulinchen.twitch_responder.lib.redis import local_redis as redis
import json
import random
def check_raffle_active() -> bool:
if not redis.exists('raffle_entry_active'):
return False
running = bool(int(redis.get('raffle_entry_active')))
if running:
return True
else:
return False
def get_raffle_entries() -> list:
if not redis.exists('raffle_entries'):
return list()
entries = json.loads(str(redis.get('raffle_entries'), encoding='UTF-8'))
return entries
def add_raffle_entry(user_id: int) -> bool:
entries = get_raffle_entries()
if user_id in entries:
return False
else:
entries.append(user_id)
redis.set('raffle_entries', json.dumps(entries))
return True
def get_winner() -> int:
entries = get_raffle_entries()
if not entries:
return -1
random.shuffle(entries)
winner = entries.pop()
redis.set('raffle_entries', json.dumps(entries))
return winner
def reset():
redis.delete('raffle_entries')
def enable():
redis.set('raffle_entry_active', 1)
def disable():
redis.set('raffle_entry_active', 0)

8
python/eulinchen/twitch_responder/lib/redis.py

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
import eulinchen.config as config
import redis
local_redis = redis.Redis(
host=config.redis_host,
port=config.redis_port,
db=config.redis_db
)

102
python/eulinchen/twitch_responder/twitch_responder.py

@ -1,8 +1,12 @@ @@ -1,8 +1,12 @@
import eulinchen.config as config
from twitchio.ext import commands
from twitchio import Message
from twitchio import Message, Context, User
from datetime import timedelta
from eulinchen.lib.chat import PeriodicMessage
from eulinchen.lib.twitch import Twitch
from eulinchen.lib.twitch.exceptions import TwitchFollowNotFoundException, TwitchUserNotFoundException
from eulinchen.lib.exceptions import InvalidArgumentException
from eulinchen.twitch_responder.lib import raffle
bot = commands.Bot(
irc_token=config.twitch_tmi_token,
@ -11,6 +15,12 @@ bot = commands.Bot( @@ -11,6 +15,12 @@ bot = commands.Bot(
prefix='!',
initial_channels=[config.twitch_bot_channel]
)
twitch = Twitch(
config.twitch_client_id,
config.twitch_client_secret,
config.twitch_webhook_callback_url,
config.timezone
)
# TODO: move stuff to db
periodic_messages = [
@ -47,6 +57,7 @@ async def event_message(ctx: Message): @@ -47,6 +57,7 @@ async def event_message(ctx: Message):
await bot.handle_commands(ctx)
# simple commands
@bot.command(name='hallo')
async def hallo(ctx):
await ctx.send('/me Hallo, ich bin Eulinchen!')
@ -62,5 +73,94 @@ async def pdb(ctx): @@ -62,5 +73,94 @@ async def pdb(ctx):
await ctx.send('Link zur Personality Database: https://www.personality-database.com/')
# raffle commands
@bot.command(name='rstart')
async def rstart(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
raffle.enable()
await ctx.send('Der Eintragezeitraum für das Gewinnspiel hat begonnen!')
@bot.command(name='rstatus')
async def rstatus(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
if raffle.check_raffle_active():
await ctx.send('Der Eintragezeitraum für das Gewinnspiel läuft grade!')
else:
await ctx.send('Der Eintragezeitraum für das Gewinnspiel läuft grade nicht!')
@bot.command(name='rstop')
async def rstop(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
raffle.disable()
await ctx.send('Der Eintragezeitraum für das Gewinnspiel ist beendet!')
@bot.command(name='gewinnspiel')
async def rentry(ctx: Context):
author: User = ctx.author
if not raffle.check_raffle_active():
await ctx.send('Es läuft grade kein Eintragezeitraum für ein Gewinnspiel!')
return
try:
follows_since = twitch.get_user_follows_since(author.id, config.amai_twitch_user_id)
# TODO: make follow time configurable
if follows_since < timedelta(hours=1):
await ctx.send('Du folgst noch nicht lange genug!')
return
except TwitchFollowNotFoundException:
await ctx.send('Du bist noch kein Follower!')
return
if raffle.add_raffle_entry(author.id):
await ctx.send('Du bist nun im Lostopf!')
else:
await ctx.send('Du bist bereits im Lostopf!')
@bot.command(name='gewinner')
async def winner(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
winner_id = raffle.get_winner()
if winner_id == -1:
await ctx.send('Es nimmt aktuell niemand am Gewinnspiel teil!')
return
try:
user = twitch.get_user(id=winner_id)
await ctx.send('{winner} hat gewonnen! Herzlichen Glückwunsch! amaicmLove amaicmLove'.format(
winner=user.display_name
))
except TwitchUserNotFoundException:
await ctx.send('Der Account des Gewinners konnte nicht gefunden werden!')
except InvalidArgumentException:
await ctx.send('Der Account des Gewinners konnte nicht gefunden werden!')
@bot.command(name='rreset')
async def winner(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
raffle.reset()
@bot.command(name='rpool')
async def winner(ctx: Context):
author: User = ctx.author
if not author.is_mod:
return
await ctx.send('Aktuell befinden sich {count} Teilnehmer im Lostopf.'.format(
count=len(raffle.get_raffle_entries())
))
def main():
bot.run()

1
requirements.txt

@ -8,3 +8,4 @@ uwsgi @@ -8,3 +8,4 @@ uwsgi
redis
tweepy
twitchio
python-dateutil

Loading…
Cancel
Save