1
0
Fork 0
mirror of https://github.com/Lynnesbian/FediBooks/ synced 2024-11-25 16:48:58 +00:00

Compare commits

..

8 commits

5 changed files with 32 additions and 11 deletions

View file

@ -1,7 +1,7 @@
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
import MySQLdb import MySQLdb
import markovify import markovify
from mastodon import Mastodon from mastodon import Mastodon, MastodonUnauthorizedError
import html, re, json import html, re, json
cfg = json.load(open('config.json')) cfg = json.load(open('config.json'))
@ -138,7 +138,12 @@ def make_post(args):
# ensure post isn't longer than bot['length'] # ensure post isn't longer than bot['length']
post = post[:bot['length']] post = post[:bot['length']]
# send toot!! # send toot!!
client.status_post(post, id, visibility = visibility, spoiler_text = bot['content_warning']) try:
client.status_post(post, id, visibility = visibility, spoiler_text = bot['content_warning'])
except MastodonUnauthorizedError:
# user has revoked the token given to the bot
# this needs to be dealt with properly later on, but for now, we'll just disable the bot
c.execute("UPDATE bots SET enabled = FALSE WHERE handle = %s", (handle,))
if id == None: if id == None:
# this wasn't a reply, it was a regular post, so update the last post date # this wasn't a reply, it was a regular post, so update the last post date

View file

@ -1,3 +1,5 @@
#!/usr/bin/env python3
import MySQLdb import MySQLdb
import requests import requests
from multiprocessing import Pool from multiprocessing import Pool
@ -14,7 +16,7 @@ def scrape_posts(account):
last_post = 0 last_post = 0
c.execute("SELECT COUNT(*) FROM `posts` WHERE `fedi_id` = %s", (handle,)) c.execute("SELECT COUNT(*) FROM `posts` WHERE `fedi_id` = %s", (handle,))
count = c.fetchone() count = c.fetchone()
if count is not None and count[0] > 0: if count is not None and int(count[0]) > 0:
# we've downloaded this user's posts before # we've downloaded this user's posts before
# find out the most recently downloaded post of theirs # find out the most recently downloaded post of theirs
c.execute("SELECT `post_id` FROM `posts` WHERE `fedi_id` = %s ORDER BY `id` DESC LIMIT 1", (handle,)) c.execute("SELECT `post_id` FROM `posts` WHERE `fedi_id` = %s ORDER BY `id` DESC LIMIT 1", (handle,))
@ -41,7 +43,8 @@ def scrape_posts(account):
# first, check to see if we already have this in the database # first, check to see if we already have this in the database
post_id = re.search(r"([^\/]+)/?$", oi['object']['id']).group(1) # extract 123 from https://example.com/posts/123/ post_id = re.search(r"([^\/]+)/?$", oi['object']['id']).group(1) # extract 123 from https://example.com/posts/123/
c.execute("SELECT COUNT(*) FROM `posts` WHERE `fedi_id` = %s AND `post_id` = %s", (handle, post_id)) c.execute("SELECT COUNT(*) FROM `posts` WHERE `fedi_id` = %s AND `post_id` = %s", (handle, post_id))
if c.fetchone()[0] > 0: count = c.fetchone()
if count is not None and int(count[0]) > 0:
# this post is already in the DB. # this post is already in the DB.
# we'll set done to true because we've caught up to where we were last time. # we'll set done to true because we've caught up to where we were last time.
done = True done = True
@ -80,7 +83,7 @@ def scrape_posts(account):
j = r.json() j = r.json()
db.commit() db.commit()
c.close()
print("Finished scraping {}".format(handle)) print("Finished scraping {}".format(handle))
print("Establishing DB connection") print("Establishing DB connection")

View file

@ -31,9 +31,9 @@ CREATE TABLE IF NOT EXISTS `bots` (
`fake_mentions_full` BOOLEAN DEFAULT 0, `fake_mentions_full` BOOLEAN DEFAULT 0,
`post_privacy` ENUM('public', 'unlisted', 'private') DEFAULT 'unlisted', `post_privacy` ENUM('public', 'unlisted', 'private') DEFAULT 'unlisted',
`learn_from_cw` BOOLEAN DEFAULT 0, `learn_from_cw` BOOLEAN DEFAULT 0,
`last_post` DATETIME DEFAULT 0, `last_post` DATETIME DEFAULT CURRENT_TIMESTAMP(),
`icon` VARCHAR(512), `icon` VARCHAR(512),
`icon_update_time` DATETIME DEFAULT 0, `icon_update_time` DATETIME DEFAULT '1000-01-01 00:00:00',
FOREIGN KEY (`user_id`) REFERENCES users(id) ON DELETE CASCADE, FOREIGN KEY (`user_id`) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (`credentials_id`) REFERENCES credentials(id) ON DELETE CASCADE FOREIGN KEY (`credentials_id`) REFERENCES credentials(id) ON DELETE CASCADE
) ENGINE=INNODB; ) ENGINE=INNODB;

View file

@ -23,7 +23,7 @@
<div class="panel-text"> <div class="panel-text">
{% set handle_list = bot['handle'].split('@') %} {% set handle_list = bot['handle'].split('@') %}
<div class="panel-name">@{{ handle_list[1] }}<span class="subtle tiny">@{{ handle_list[2] }}</span></div> <div class="panel-name">@{{ handle_list[1] }}<span class="subtle tiny">@{{ handle_list[2] }}</span></div>
<div class="panel-status">{{ "Online" if bot['enabled'] else "Offline"}}, learning from {{ bot_users[bot['handle']] }} accounts</div> <div class="panel-status">{{ "Online" if bot['enabled'] else "Offline"}}, learning from {{ bot_users[bot['handle']] }} accounts.{% if bot['handle'] in next_posts %} Next post in {{ next_posts[bot['handle']][0] }} minutes.{% endif %}</div>
</div> </div>
<div class="panel-actions"> <div class="panel-actions">
<a class="button btn-secondary" href="/bot/toggle/{{ bot['handle'] }}" title="Turn on/off"><i class="fas fa-power-off"></i></a><a class="button btn-secondary" href="/bot/edit/{{ bot['handle'] }}" title="Configure"><i class="fas fa-cog"></i></a><a class="button btn-secondary" href="/bot/accounts/{{ bot['handle'] }}" title="Accounts learned from"><i class="fas fa-users"></i></a><a class="button btn-secondary" href="/bot/blacklist/{{ bot['handle'] }}" title="Banned words"><i class="fas fa-strikethrough"></i></a><a class="button btn-secondary" href="/bot/chat/{{ bot['handle'] }}" title="Chat"><i class="fas fa-comment"></i></a><a class="button btn-dangerous" href="/bot/delete/{{ bot['handle'] }}" title="Delete"><i class="fas fa-trash"></i></a> <a class="button btn-secondary" href="/bot/toggle/{{ bot['handle'] }}" title="Turn on/off"><i class="fas fa-power-off"></i></a><a class="button btn-secondary" href="/bot/edit/{{ bot['handle'] }}" title="Configure"><i class="fas fa-cog"></i></a><a class="button btn-secondary" href="/bot/accounts/{{ bot['handle'] }}" title="Accounts learned from"><i class="fas fa-users"></i></a><a class="button btn-secondary" href="/bot/blacklist/{{ bot['handle'] }}" title="Banned words"><i class="fas fa-strikethrough"></i></a><a class="button btn-secondary" href="/bot/chat/{{ bot['handle'] }}" title="Chat"><i class="fas fa-comment"></i></a><a class="button btn-dangerous" href="/bot/delete/{{ bot['handle'] }}" title="Delete"><i class="fas fa-trash"></i></a>

View file

@ -42,18 +42,23 @@ def home():
c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s AND enabled = TRUE", (session['user_id'],)) c.execute("SELECT COUNT(*) FROM `bots` WHERE user_id = %s AND enabled = TRUE", (session['user_id'],))
active_count = c.fetchone()[0] active_count = c.fetchone()[0]
dc = mysql.connection.cursor(MySQLdb.cursors.DictCursor) dc = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
dc.execute("SELECT `handle`, `enabled` FROM `bots` WHERE user_id = %s", (session['user_id'],)) dc.execute("SELECT `handle`, `enabled`, `last_post`, `post_frequency` FROM `bots` WHERE user_id = %s", (session['user_id'],))
bots = dc.fetchall() bots = dc.fetchall()
dc.close() dc.close()
bot_users = {} bot_users = {}
next_posts = {}
for bot in bots: for bot in bots:
# multiple SELECTS is slow, maybe SELECT all at once and filter with python? # multiple SELECTS is slow, maybe SELECT all at once and filter with python?
c.execute("SELECT COUNT(*) FROM `bot_learned_accounts` WHERE bot_id = %s", (bot['handle'],)) c.execute("SELECT COUNT(*) FROM `bot_learned_accounts` WHERE bot_id = %s", (bot['handle'],))
bot_users[bot['handle']] = c.fetchone()[0] bot_users[bot['handle']] = c.fetchone()[0]
c.execute("SELECT post_frequency - TIMESTAMPDIFF(MINUTE, last_post, CURRENT_TIMESTAMP()) FROM bots WHERE TIMESTAMPDIFF(MINUTE, last_post, CURRENT_TIMESTAMP()) <= post_frequency AND enabled = TRUE AND handle = %s", (bot['handle'],))
next_post = c.fetchone()
if next_post is not None:
next_posts[bot['handle']] = next_post
c.close() c.close()
return render_template("home.html", bot_count = bot_count, active_count = active_count, bots = bots, bot_users = bot_users) return render_template("home.html", bot_count = bot_count, active_count = active_count, bots = bots, bot_users = bot_users, next_posts = next_posts)
else: else:
return render_template("front_page.html") return render_template("front_page.html")
@ -375,7 +380,15 @@ def bot_create():
session['instance'] = re.match(r"^(?:https?:\/\/)?(.*)", request.form['instance']).group(1) session['instance'] = re.match(r"^(?:https?:\/\/)?(.*)", request.form['instance']).group(1)
# check for mastodon/pleroma # check for mastodon/pleroma
r = requests.get("https://{}/api/v1/instance".format(session['instance']), timeout=10) try:
r = requests.get("https://{}/api/v1/instance".format(session['instance']), timeout=10)
except requests.ConnectionError:
session['error'] = "Couldn't connect to https://{}.".format(session['instance'])
return render_template("bot_create.html", error = session.pop('error', None))
except:
session['error'] = "An unknown error occurred while trying to load https://{}".format(session['instance'])
return render_template("bot_create.html", error = session.pop('error', None))
if r.status_code == 200: if r.status_code == 200:
j = r.json() j = r.json()
if "Pleroma" in j['version']: if "Pleroma" in j['version']: