Skip to content

Commit

Permalink
Count twitch subs
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaserlang committed Feb 26, 2024
1 parent d4726fb commit 3c2142c
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 42 deletions.
26 changes: 0 additions & 26 deletions tbot/discord_bot/tasks/twitch_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,33 +161,7 @@ async def get_subscribers(self):
after = d['pagination']['cursor']
return subs

async def count_subs(self, subs: list):
self_subs = 0
gifted_subs = 0
primes = 0
for sub in subs:
points = 1
if sub['tier'] == '2000':
points = 2
elif sub['tier'] == '3000':
points = 6

if sub['is_gift']:
gifted_subs += points
elif sub['tier'].lower() == 'prime':
primes += points
else:
self_subs += points
await self.bot.db.execute('''
INSERT INTO twitch_sub_stats
(channel_id, self_sub_points, gifted_sub_points, primes, updated_at)
VALUES (%s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
self_sub_points=VALUES(self_sub_points),
gifted_sub_points=VALUES(gifted_sub_points),
primes=VALUES(primes),
updated_at=VALUES(updated_at)
''', (self.info['channel_id'], self_subs, gifted_subs, primes, datetime.now(tz=timezone.utc)))

async def get_cached_badges_months(self):
rows = await self.bot.db.fetchall(
Expand Down
38 changes: 38 additions & 0 deletions tbot/migrations/20240226_02_QLusc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
"""

from yoyo import step

__depends__ = {'20240226_01_mF9Rj'}

steps = [
step('''
CREATE TABLE `twitch_subs` (
`channel_id` VARCHAR(32) NOT NULL,
`user_id` VARCHAR(32) NOT NULL,
`plan_name` VARCHAR(45) NULL,
`tier` VARCHAR(45) NOT NULL,
`gifter_id` VARCHAR(32) NULL,
`is_gift` TINYINT NULL,
`updated_at` DATETIME NULL,
PRIMARY KEY (`channel_id`, `user_id`));
'''),

step('drop table twitch_sub_log'),

step('''
CREATE TABLE `twitch_sub_log` (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`channel_id` VARCHAR(32) NOT NULL,
`message_id` uuid NULL,
`created_at` DATETIME(6) NOT NULL,
`user_id` VARCHAR(32) NULL,
`plan_name` VARCHAR(45) NULL,
`tier` VARCHAR(45) NULL,
`gifter_id` VARCHAR(32) NULL,
`is_gift` BOOLEAN NOT NULL DEFAULT 0,
`total` INT NULL,
UNIQUE INDEX `message_id_UNIQUE` (`message_id` ASC))
'''),
]
6 changes: 6 additions & 0 deletions tbot/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ def twitch_eventsub_check():
from tbot.web.handlers.api.twitch.eventsubs.eventsub import task_check_channels
asyncio.run(task_check_channels())

@cli.command()
def twitch_count_subs():
set_logger('twitch_count_subs.log')
from tbot.twitch_bot.tasks.count_subs import count_subs
asyncio.run(count_subs())

def main():
cli()

Expand Down
45 changes: 29 additions & 16 deletions tbot/twitch_bot/modlog.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,19 @@ def created_by_user_id():

async def log_sub(self, data):
try:
# If the viewer is upgrading from a gifted sub or a prime sub,
# the partner plus points are first awarded the next month.
# This month
is_already_prime_or_gifted = await self.db.fetchone('''
SELECT 1
FROM twitch_sub_log
WHERE
channel_id=%s
AND user_id=%s
AND created_at > NOW() - INTERVAL 1 MONTH
AND (is_gift=1 OR tier='Prime')
''', (data['channel_id'], data['user_id'],))

await self.db.execute('''
INSERT INTO twitch_sub_log (channel_id, created_at, user_id, plan_name, tier, gifter_id, is_gift, total) VALUES
(%s, %s, %s, %s, %s, %s, %s, %s)
Expand All @@ -123,22 +136,22 @@ async def log_sub(self, data):
points = 2
elif data['sub_plan'] == '3000':
points = 6

await self.db.execute('''
INSERT INTO twitch_sub_stats (channel_id, self_sub_points, gifted_sub_points, primes, updated_at) VALUES
(%s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
self_sub_points=self_sub_points+VALUES(self_sub_points),
gifted_sub_points=gifted_sub_points+VALUES(gifted_sub_points),
primes=primes+VALUES(primes),
updated_at=VALUES(updated_at)
''', (
data['channel_id'],
points if not data['is_gift'] else 0,
points if data['is_gift'] else 0,
points if data['sub_plan'] == 'Prime' else 0,
datetime.utcnow(),
))
if not is_already_prime_or_gifted:
await self.db.execute('''
INSERT INTO twitch_sub_stats (channel_id, self_sub_points, gifted_sub_points, primes, updated_at) VALUES
(%s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
self_sub_points=self_sub_points+VALUES(self_sub_points),
gifted_sub_points=gifted_sub_points+VALUES(gifted_sub_points),
primes=primes+VALUES(primes),
updated_at=VALUES(updated_at)
''', (
data['channel_id'],
points if not data['is_gift'] else 0,
points if data['is_gift'] else 0,
points if data['sub_plan'] == 'Prime' else 0,
datetime.utcnow(),
))
except Exception as e:
logger.exception(e)

Expand Down
81 changes: 81 additions & 0 deletions tbot/twitch_bot/tasks/count_subs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from datetime import datetime, timezone
import aiohttp
from tbot import db, logger
from tbot.utils.twitch import twitch_channel_token_request


async def count_subs():
from tbot.twitch_bot.bot_base import bot
bot.db = await db.Db().connect()
bot.ahttp = aiohttp.ClientSession()
try:
channels = await bot.db.fetchall('''
SELECT channel_id, twitch_scope
FROM twitch_channels
WHERE
active="Y" AND
not isnull(twitch_scope);
''')
logger.info('Counting subs')
for c in channels:
if 'channel:read:subscriptions' not in c['twitch_scope']:
continue

logger.info(f'Channel: {c["channel_id"]}')
try:
subs = await get_subs(bot, c['channel_id'])
await _count_subs(bot, c['channel_id'], subs)
except Exception as e:
logger.exception(e)
finally:
await bot.ahttp.close()
bot.db.pool.close()
await bot.db.pool.wait_closed()


async def get_subs(bot, channel_id: str):
url = 'https://api.twitch.tv/helix/subscriptions'
after = ''
subs = []
while True:
d = await twitch_channel_token_request(bot, channel_id, url, params={
'broadcaster_id': channel_id,
'after': after,
})
if d['data']:
subs.extend(d['data'])
else:
break
if not 'pagination' in d or not d['pagination']:
break
after = d['pagination']['cursor']
return subs


async def _count_subs(bot, channel_id: str, subs: list):
self_subs = 0
gifted_subs = 0
primes = 0
for sub in subs:
points = 1
if sub['tier'] == '2000':
points = 2
elif sub['tier'] == '3000':
points = 6

if sub['is_gift']:
gifted_subs += points
elif sub['tier'].lower() == 'prime':
primes += points
else:
self_subs += points
await bot.db.execute('''
INSERT INTO twitch_sub_stats
(channel_id, self_sub_points, gifted_sub_points, primes, updated_at)
VALUES (%s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
self_sub_points=VALUES(self_sub_points),
gifted_sub_points=VALUES(gifted_sub_points),
primes=VALUES(primes),
updated_at=VALUES(updated_at)
''', (channel_id, self_subs, gifted_subs, primes, datetime.now(tz=timezone.utc)))

0 comments on commit 3c2142c

Please sign in to comment.