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

Compare commits

..

No commits in common. "1c67016fa6aba3cbfe8640a84cc0b642a0ee32a7" and "00369be990d74008c9a1deca14b1aaef349c0f04" have entirely different histories.

13 changed files with 76 additions and 201 deletions

View file

@ -27,7 +27,8 @@ If this doesn't work, try using ``pip`` instead. If it still doesn't work, you m
```
CREATE DATABASE `fedibooks`;
CREATE USER 'myuser' IDENTIFIED BY 'mypassword';
GRANT ALL PRIVILEGES ON `fedibooks`.* TO 'myuser';
GRANT USAGE ON *.* TO 'myuser'@localhost IDENTIFIED BY 'mypassword';
GRANT ALL privileges ON `fedibooks`.* TO 'myuser'@localhost;
FLUSH PRIVILEGES;
exit
```

View file

@ -34,14 +34,20 @@ def extract_post(post):
text = text.rstrip("\n") # remove trailing newline(s)
return text
def generate_output(handle):
def make_post(args):
id = None
acct = None
if len(args) > 1:
id = args[1]
acct = args[3]
handle = args[0]
db = MySQLdb.connect(
host = cfg['db_host'],
user=cfg['db_user'],
passwd=cfg['db_pass'],
db=cfg['db_name']
)
# print("Generating post for {}".format(handle))
print("Generating post for {}".format(handle))
dc = db.cursor(MySQLdb.cursors.DictCursor)
c = db.cursor()
dc.execute("""
@ -63,6 +69,12 @@ def generate_output(handle):
""", (handle,))
bot = dc.fetchone()
client = Mastodon(
client_id = bot['client_id'],
client_secret = bot['client_secret'],
access_token = bot['secret'],
api_base_url = "https://{}".format(handle.split("@")[2])
)
# by default, only select posts that don't have CWs.
# if learn_from_cw, then also select posts with CWs
@ -80,7 +92,7 @@ def generate_output(handle):
# 4. join the list into a string separated by newlines
posts = "\n".join(list(sum(c.fetchall(), ())))
if len(posts) == 0:
print("{} - No posts to learn from.".format(handle))
print("No posts to learn from.")
return
if bot['fake_mentions'] == 'never':
@ -116,37 +128,7 @@ def generate_output(handle):
# also format handles without instances, e.g. @user instead of @user@instan.ce
post = re.sub(r"(?<!\S)@(\w+)", r"@{}\1".format(zws), post)
return bot, post
def make_post(args):
id = None
acct = None
if len(args) > 1:
id = args[1]
acct = args[3]
handle = args[0]
# print("Generating post for {}".format(handle))
bot, post = generate_output(handle)
client = Mastodon(
client_id = bot['client_id'],
client_secret = bot['client_secret'],
access_token = bot['secret'],
api_base_url = "https://{}".format(handle.split("@")[2])
)
db = MySQLdb.connect(
host = cfg['db_host'],
user=cfg['db_user'],
passwd=cfg['db_pass'],
db=cfg['db_name']
)
c = db.cursor()
# print(post)
print(post)
visibility = bot['post_privacy'] if len(args) == 1 else args[2]
visibilities = ['public', 'unlisted', 'private']
if visibilities.index(visibility) < visibilities.index(bot['post_privacy']):
@ -156,7 +138,6 @@ def make_post(args):
post = "{} {}".format(acct, post)
# ensure post isn't longer than bot['length']
# TODO: ehhhhhhhhh
post = post[:bot['length']]
# send toot!!
try:
@ -165,11 +146,8 @@ def make_post(args):
# 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,))
except:
print("Failed to create post for {}".format(handle))
if id == None:
# this wasn't a reply, it was a regular post, so update the last post date
c.execute("UPDATE bots SET last_post = CURRENT_TIMESTAMP() WHERE handle = %s", (handle,))
db.commit()
c.close()

View file

@ -81,7 +81,6 @@ def bot_accounts_add(mysql, cfg):
username = client.account_verify_credentials()['username']
if username != session['username']:
error = "Please authenticate as {}.".format(session['username'])
print("Auth error - {} is not {}".format(session['username'], username))
return render_template("bot/accounts_add.html", error = error)
except:
session['step'] = 1

View file

@ -19,7 +19,7 @@ def scrape_posts(account):
)
handle = account[0]
outbox = account[1]
# print("Scraping {}".format(handle))
print("Scraping {}".format(handle))
c = db.cursor()
last_post = 0
c.execute("SELECT COUNT(*) FROM `posts` WHERE `fedi_id` = %s", (handle,))
@ -80,15 +80,9 @@ def scrape_posts(account):
if not done:
if pleroma:
if 'next' in j:
r = requests.get(j['next'], timeout = 10)
else:
done = True
else:
if 'prev' in j:
r = requests.get(j['prev'], timeout = 10)
else:
done = True
if r.status_code == 429:
# we are now being ratelimited, move on to the next user
@ -100,7 +94,7 @@ def scrape_posts(account):
db.commit()
db.commit()
# print("Finished scraping {}".format(handle))
print("Finished scraping {}".format(handle))
print("Establishing DB connection")
db = MySQLdb.connect(

View file

@ -2,14 +2,12 @@
import MySQLdb
from mastodon import Mastodon
from multiprocessing import Pool
import requests
import json
import functions
cfg = json.load(open('config.json'))
def update_icon(bot):
try:
db = MySQLdb.connect(
host = cfg['db_host'],
user=cfg['db_user'],
@ -18,39 +16,19 @@ def update_icon(bot):
use_unicode=True,
charset="utf8mb4"
)
except:
print("Failed to connect to database.")
return
url = "https://{}".format(bot['handle'].split("@")[2])
try:
r = requests.head(url, timeout=10, allow_redirects = True)
if r.status_code != 200:
raise
except:
print("{} is down.".format(url))
return
print("Updating cached icon for {}".format(bot['handle']))
client = Mastodon(
client_id = bot['client_id'],
client_secret = bot['client_secret'],
access_token = bot['secret'],
api_base_url = url
api_base_url = "https://{}".format(bot['handle'].split("@")[2])
)
c = db.cursor()
try:
avatar = client.account_verify_credentials()['avatar']
except:
c.execute("UPDATE bots SET icon_update_time = CURRENT_TIMESTAMP() WHERE handle = %s", (bot['handle'],))
db.commit()
c.close()
return
c = db.cursor()
c.execute("UPDATE bots SET icon = %s, icon_update_time = CURRENT_TIMESTAMP() WHERE handle = %s", (avatar, bot['handle']))
db.commit()
c.close()
print("Establishing DB connection")
db = MySQLdb.connect(
@ -70,7 +48,6 @@ db.commit()
print("Generating posts")
cursor.execute("SELECT handle FROM bots WHERE enabled = TRUE AND TIMESTAMPDIFF(MINUTE, last_post, CURRENT_TIMESTAMP()) >= post_frequency")
# cursor.execute("SELECT handle FROM bots WHERE enabled = TRUE")
bots = cursor.fetchall()
with Pool(cfg['service_threads']) as p:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -1,44 +0,0 @@
var chatlog = [];
function sendMessage() {
let id = window.location.href.split("/").slice(-1)[0]
message = document.getElementById("chatbox-input-box").value
document.getElementById("chatbox-input-box").value = ''
document.getElementById("chatbox-input-box").disabled = true;
chatlog.push(["user", message])
renderChatlog();
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4) {
if (this.status == 200) {
message = this.responseText.replace("\n", "<br>");
} else {
message = "Encountered an error while trying to get a response.";
}
chatlog.push(["bot", message]);
renderChatlog();
document.getElementById("chatbox-input-box").disabled = false;
}
};
xhttp.open("GET", `/bot/chat/${id}/message`, true);
xhttp.send();
return false;
}
function renderChatlog() {
let chatbox = document.getElementById("chatbox");
let out = "";
if (chatlog.length > 50) {
chatlog.shift(); //only keep the 50 most recent messages to avoid slowdown
}
chatlog.forEach(function(item, i) {
if (item[0] == "user") {
out += `<div class="message-container user"><div class="message user">${item[1]}</div></div>`;
} else {
out += `<div class="message-container bot"><div class="bot-icon"></div><div class="message bot">${item[1]}</div></div>`;
}
})
chatbox.innerHTML = out;
chatbox.scrollTop = chatbox.scrollHeight;
}

View file

@ -217,29 +217,21 @@ form .row {
height: 90vh;
background-color: #3d4353;
padding: 10px;
overflow-y: scroll;
}
#chatbox-input, #chatbox-input input{
width: 100%;
}
#chatbox, #chatbox-input {
max-width: 600px;
margin: 0 auto;
}
#chatbox-input {
display: block;
}
.message {
display: inline-block;
padding: 5px;
min-height: 30px;
max-width: 60%;
margin-bottom: 5px;
}
.message-container.user {
text-align: right;
}
.message-container .bot-icon {
background: center / contain url("https://lynnesbian.space/img/bune.png") no-repeat;
height: 30px;
width: 30px;
display: inline-block;

View file

@ -4,17 +4,6 @@
<meta charset="UTF-8">
<title>FediBooks</title>
{% include 'imports.html' %}
<style>
.bot-icon {
background: center / contain url("{{icon}}") no-repeat;
}
</style>
<script>
window.onload = function() {
document.getElementById("chatbox-input-box").focus();
document.getElementById("chatbox-input").onsubmit = sendMessage;
}
</script>
</head>
<body>
@ -22,7 +11,7 @@
<h1 class="thin centred">Chat</h1>
<p class="centred">Talking to {{ bot }}</p>
<p class="centred" style="margin: 20px 0;">
<a class="button btn-primary" href="/" role="button"><i class="fas fa-home"></i> Home</a>
<a class="button btn-primary" href="/bot/accounts/add" role="button"><i class="fas fa-home"></i> Home</a>
</p>
</div>
@ -34,11 +23,17 @@
<div class="container">
<div id="chatbox">
<div class="message-container user">
<div class="message user">Henlo</div>
</div>
<div class="message-container bot">
<div class="bot-icon"></div>
<div class="message bot">Henlo human uwu<br>How are you</div>
</div>
</div>
<form id="chatbox-input">
<input id="chatbox-input-box" autocomplete="off" required name="message" placeholder="Press enter to send">
<input name="message" placeholder="Press enter to send">
</form>
</div>

View file

@ -26,12 +26,12 @@
{% elif session['step'] == 3 %}
<p>You now need to give your bot access to the {{ session['instance'] }} account you have created for it. If you have not yet created an account on {{ session['instance'] }} for your bot to use, please do so now.</p>
<p>In another tab, sign in to the {{ session['instance'] }} account you want your bot to use. Once that's done, click next to begin the authorisation process.</p>
<p>Sign in to the {{ session['instance'] }} account you want your bot to use, then click next to begin the authorisation process.</p>
{% elif session['step'] == 4 %}
<h2 class="thin centred">Congratulations!</h2>
<p>FediBooks has successfully authenticated with your instance, and your bot is ready to be configured. Click finish to return to the bot management screen.</p>
<p><strong>Important:</strong> To get your bot working, you need to add at least one account for it to learn from. You can do so by clicking the <i class="fas fa-users"></i> button. To configure settings such as posting frequency and content warnings, click the <i class="fas fa-cog"></i> button.</p>
<p>To get your bot working, you need to add at least one account for it to learn from. You can do so by clicking the <i class="fas fa-users"></i> button. To configure settings such as posting frequency and content warnings, click the <i class="fas fa-cog"></i> button.</p>
{% else %}
<h2 class="thin centred">Error</h2>

View file

@ -2,7 +2,6 @@
<div class='subtle small'>
<p>FediBooks is beta software. It might behave unexpectedly. You can learn more about FediBooks <a href="/about">here</a>. <br>
Website design and FediBooks software by <a href='https://fedi.lynnesbian.space/@LynnearSoftware'>Lynne</a>. This site uses <a href="https://fontawesome.com">Font Awesome</a>. <br>
Some of FediBooks' functionality requires JavaScript to be enabled, although the core functions such as bot configuration do not. <br>
FediBooks uses a cookie to keep you logged in. Deleting this cookie will log you out, and your bots will still work. You can also sign out <a href="/do/signout">here</a>. <br>
Source code is available <a href="https://github.com/Lynnesbian/Fedibooks">here</a> under the AGPLv3 license.</p>
</div>

View file

@ -2,4 +2,3 @@
<link rel="stylesheet" href="https://kit-free.fontawesome.com/releases/latest/css/free.min.css">
<link rel='stylesheet' type='text/css' href="{{ url_for('static', filename='style.css') }}" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,700&display=swap">
<script src="{{ url_for('static', filename='script.js') }}"></script>

View file

@ -159,20 +159,8 @@ def bot_toggle(id):
@app.route("/bot/chat/<id>")
def bot_chat(id):
# return render_template("coming_soon.html")
if bot_check(id):
c = mysql.connection.cursor()
c.execute("SELECT icon FROM `bots` WHERE handle = %s", (id,))
icon = c.fetchone()[0]
if icon is None:
icon = "/img/bot_generic.png"
return render_template("/bot/chat.html", bot = id, icon = icon)
@app.route("/bot/chat/<id>/message")
def bot_chat_message(id):
if bot_check(id):
_, message = functions.generate_output(id)
return message
return render_template("coming_soon.html")
# return render_template("/bot/chat.html", bot = id)
@app.route("/bot/blacklist/<id>")
def bot_blacklist(id):
@ -270,12 +258,9 @@ def push(id):
'privkey': int(bot[0].rstrip("\0")),
'auth': bot[1]
}
try:
push_object = client.push_subscription_decrypt_push(request.data, params, request.headers['Encryption'], request.headers['Crypto-Key'])
notification = client.notifications(id = push_object['notification_id'])
me = client.account_verify_credentials()['id']
except:
return "Push failed - do we still have access to {}?".format(id)
# first, check how many times the bot has posted in this thread.
# if it's over 15, don't reply.