Add twitter task
This commit is contained in:
parent
ee87c6cb40
commit
c767174439
1 changed files with 84 additions and 0 deletions
84
jarvis_tasks/tasks/twitter.py
Normal file
84
jarvis_tasks/tasks/twitter.py
Normal file
|
@ -0,0 +1,84 @@
|
|||
"""JARVIS Twitter sync."""
|
||||
import asyncio
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import tweepy
|
||||
from jarvis_core.db import q
|
||||
from jarvis_core.db.models import TwitterAccount, TwitterFollow
|
||||
|
||||
from jarvis_tasks.config import TaskConfig
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from dis_snek import Snake
|
||||
|
||||
config = TaskConfig.from_yaml()
|
||||
|
||||
|
||||
async def twitter(self, bot: "Snake") -> None:
|
||||
"""
|
||||
Sync tweets in the background.
|
||||
|
||||
Args:
|
||||
bot: Snake instance
|
||||
"""
|
||||
auth = tweepy.AppAuthHandler(config.twitter["consumer_key"], config.twitter["consumer_secret"])
|
||||
api = tweepy.API(auth)
|
||||
while True:
|
||||
# Only check once a minute
|
||||
asyncio.sleep(60)
|
||||
|
||||
accounts = TwitterAccount.find()
|
||||
accounts_to_delete = []
|
||||
|
||||
# Go through all actively followed accounts
|
||||
async for account in accounts:
|
||||
# Check if account needs updated (handle changes)
|
||||
if account.last_sync + timedelta(hours=1) <= datetime.utcnow():
|
||||
user = api.get_user(id=account.twitter_id)
|
||||
account.update(q(handle=user.screen_name, last_sync=datetime.utcnow()))
|
||||
|
||||
# Get new tweets
|
||||
if tweets := api.user_timeline(id=account.twitter_id, since_id=account.last_tweet):
|
||||
tweets = sorted(tweets, key=lambda x: x.id)
|
||||
follows = TwitterFollow.find(q(twitter_id=account.twitter_id))
|
||||
follows_to_delete = []
|
||||
num_follows = 0
|
||||
|
||||
# Go through follows and send tweet if necessary
|
||||
async for follow in follows:
|
||||
num_follows += 1
|
||||
guild = await bot.fetch_guild(follow.guild_id)
|
||||
if not guild:
|
||||
follows_to_delete.append(follow)
|
||||
continue
|
||||
channel = await guild.fetch_channel(follow.channel_id)
|
||||
if not channel:
|
||||
follows_to_delete.append(follow)
|
||||
continue
|
||||
for tweet in tweets:
|
||||
retweet = "retweeted_status" in tweet.__dict__
|
||||
if retweet and not follow.retweets:
|
||||
continue
|
||||
|
||||
timestamp = int(tweet.created_at.timestamp())
|
||||
url = f"https://twitter.com/{account.handle}/status/{tweet.id}"
|
||||
mod = "re" if retweet else ""
|
||||
await channel.send(
|
||||
f"`@{account.handle}` {mod}tweeted this at <t:{timestamp}:f>: {url}"
|
||||
)
|
||||
|
||||
# Delete invalid follows
|
||||
for follow in follows_to_delete:
|
||||
await follow.delete()
|
||||
|
||||
if num_follows == 0:
|
||||
accounts_to_delete.append(account)
|
||||
else:
|
||||
newest = tweets[0]
|
||||
account.update(q(last_tweet=newest.id))
|
||||
await account.commit()
|
||||
|
||||
# Delete invalid accounts (no follows)
|
||||
for account in accounts_to_delete:
|
||||
await account.delete()
|
Loading…
Add table
Reference in a new issue