Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Moon Man | 60c1ace489 | |
Moon Man | 106a487dc5 | |
Moon Man | 72eac07711 | |
Moon Man | 64a5d0c040 | |
Moon Man | b5d430ed37 | |
Moon Man | f525310f1c |
|
@ -1,3 +1,7 @@
|
||||||
__pycache__
|
__pycache__
|
||||||
list
|
list
|
||||||
token
|
token
|
||||||
|
./*.png
|
||||||
|
.env
|
||||||
|
feditree/feditree.png
|
||||||
|
bots.db
|
22
README.md
22
README.md
|
@ -1,17 +1,17 @@
|
||||||
# Bots de masto.es
|
# SPC fork of Bots from masto.es
|
||||||
|
|
||||||
Aquí se encuentra el código de los bots que se utilizan en masto.es para ayudar con tareas de administración como guiar a los nuevos usuarios, ofrecer funciones adicionales o simplemente servir de pasatiempo.
|
## Installation
|
||||||
|
|
||||||
## Apreciabot
|
Create a venv and inside of it run:
|
||||||
Envía un mensaje directo (visibilidad "sólo cuentas mencionadas") a @apreciabot@masto.es incluyendo el usuario que quieres apreciar con el formato "usuario@servidor" (excluyendo el primer "@" para evitar mencionarlo). Añade "croqueta" al final para activar el modo croqueta.
|
|
||||||
|
|
||||||
Basado en el Niceness Bot https://botsin.space/@nicenessbot
|
pip install -r requirements.txt
|
||||||
|
|
||||||
## Bienvenibot
|
## Running feditree
|
||||||
Revisa las notificaciones de un usuario con los privilegios suficientes para buscar nuevos registros y envía un mensaje de bienvenida.
|
|
||||||
|
|
||||||
|
Create a '.env' file containing:
|
||||||
|
|
||||||
## Requisitos
|
FEDI_DOMAIN=your-domain.tld
|
||||||
- Python 3
|
|
||||||
- Mastodon.py https://github.com/halcy/Mastodon.py
|
Create a file 'token/faggotree' containing your bearer token value
|
||||||
- Apreciabot: bs4
|
|
||||||
|
then just activate your venv or run python from your venv, with 'feditree.py'
|
||||||
|
|
79
common.py
79
common.py
|
@ -1,3 +1,4 @@
|
||||||
|
import sqlite3
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
from sys import exit
|
from sys import exit
|
||||||
|
|
||||||
|
@ -39,6 +40,84 @@ def list_append(name, value):
|
||||||
file.write(value + '\n')
|
file.write(value + '\n')
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
|
conn = sqlite3.connect("bots.db", isolation_level=None)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
cursor.executescript('''
|
||||||
|
create table if not exists bots (
|
||||||
|
id integer primary key autoincrement,
|
||||||
|
name text not null
|
||||||
|
);
|
||||||
|
|
||||||
|
create table if not exists posted_already (
|
||||||
|
id integer primary key autoincrement,
|
||||||
|
bot_id integer not null,
|
||||||
|
user_id text not null,
|
||||||
|
created timestamp default current_timestamp,
|
||||||
|
unique(bot_id, user_id),
|
||||||
|
foreign key (bot_id) references bots(id)
|
||||||
|
);
|
||||||
|
''')
|
||||||
|
|
||||||
|
def get_or_create_bot(name):
|
||||||
|
cursor.execute("SELECT id FROM bots WHERE name = ?", (name,))
|
||||||
|
result = cursor.fetchone()
|
||||||
|
|
||||||
|
if result:
|
||||||
|
return result[0]
|
||||||
|
|
||||||
|
cursor.execute("INSERT INTO bots (name) VALUES (?)", (name,))
|
||||||
|
return cursor.lastrowid
|
||||||
|
|
||||||
|
|
||||||
|
def has_user_posted(bot_name, user_id):
|
||||||
|
user_id = str(user_id)
|
||||||
|
bot_id = get_or_create_bot(bot_name)
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT EXISTS(
|
||||||
|
SELECT 1
|
||||||
|
FROM posted_already
|
||||||
|
WHERE bot_id = ? AND user_id = ?
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
""", (bot_id, user_id))
|
||||||
|
|
||||||
|
return bool(cursor.fetchone()[0])
|
||||||
|
|
||||||
|
def mark_user_posted(bot_name, user_id):
|
||||||
|
user_id = str(user_id)
|
||||||
|
bot_id = get_or_create_bot(bot_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO posted_already (bot_id, user_id)
|
||||||
|
VALUES (?, ?)
|
||||||
|
""", (bot_id, user_id))
|
||||||
|
return True
|
||||||
|
except sqlite3.IntegrityError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def unmark_user_posted(bot_name, user_id):
|
||||||
|
user_id = str(user_id)
|
||||||
|
bot_id = get_or_create_bot(bot_name)
|
||||||
|
|
||||||
|
cursor.execute("""
|
||||||
|
DELETE FROM posted_already
|
||||||
|
WHERE bot_id = ? AND user_id = ?
|
||||||
|
""", (bot_id, user_id))
|
||||||
|
|
||||||
|
return cursor.rowcount > 0 # Returns True if a row was deleted
|
||||||
|
|
||||||
|
def db_close():
|
||||||
|
try:
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# It is not safe to get notifications from "last_id" because some may have been deleted
|
# It is not safe to get notifications from "last_id" because some may have been deleted
|
||||||
def get_new_notifications(api, bot_name, types=None):
|
def get_new_notifications(api, bot_name, types=None):
|
||||||
last_notifications=list_read(bot_name + '_last_notifications')
|
last_notifications=list_read(bot_name + '_last_notifications')
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cd /var/lib/bots/vcs/int/mastoes-bots
|
||||||
|
/var/lib/bots/venvs/faggotree/bin/python3 feditree.py
|
106
feditree.py
106
feditree.py
|
@ -1,8 +1,19 @@
|
||||||
from PIL import Image
|
|
||||||
from common import get_api, get_new_notifications, list_read, list_append
|
from dotenv import load_dotenv
|
||||||
|
from PIL import Image, ImageFile
|
||||||
|
from common import get_api, get_new_notifications, has_user_posted, mark_user_posted, unmark_user_posted, db_close
|
||||||
import datetime
|
import datetime
|
||||||
import gettext
|
import gettext
|
||||||
import requests
|
import requests
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
bot_name = "faggotree"
|
||||||
|
|
||||||
coordinates = [
|
coordinates = [
|
||||||
(350,200),
|
(350,200),
|
||||||
|
@ -17,6 +28,8 @@ coordinates = [
|
||||||
(575,650),
|
(575,650),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
temp_image_name = (tempfile.NamedTemporaryFile(suffix='.png', delete=False)).name
|
||||||
|
|
||||||
def get_ordered_accounts_ids(account_id):
|
def get_ordered_accounts_ids(account_id):
|
||||||
current_year = datetime.date.today().year
|
current_year = datetime.date.today().year
|
||||||
accounts = {}
|
accounts = {}
|
||||||
|
@ -24,16 +37,19 @@ def get_ordered_accounts_ids(account_id):
|
||||||
max_id=None
|
max_id=None
|
||||||
loops = 0
|
loops = 0
|
||||||
while stop == False:
|
while stop == False:
|
||||||
statuses = api.account_statuses(account_id, exclude_reblogs=True, max_id=max_id, limit=80)
|
statuses = api.account_statuses(account_id, exclude_reblogs=True, max_id=max_id, limit=50)
|
||||||
for status in statuses:
|
for status in statuses:
|
||||||
if(status.created_at.year < current_year):
|
if(status.created_at.year < current_year):
|
||||||
stop = True
|
stop = True
|
||||||
break
|
break
|
||||||
for mention in status.mentions:
|
for mention in status.mentions:
|
||||||
if mention.id not in accounts:
|
if mention.username == bot_name or mention.username == status.account.username:
|
||||||
accounts[mention.id] = 1
|
pass
|
||||||
else:
|
else:
|
||||||
accounts[mention.id] = accounts[mention.id] + 1
|
if mention.id not in accounts:
|
||||||
|
accounts[mention.id] = 1
|
||||||
|
else:
|
||||||
|
accounts[mention.id] = accounts[mention.id] + 1
|
||||||
max_id=status.id
|
max_id=status.id
|
||||||
loops = loops + 1
|
loops = loops + 1
|
||||||
if loops > 10 :
|
if loops > 10 :
|
||||||
|
@ -46,13 +62,25 @@ def get_ordered_accounts_ids(account_id):
|
||||||
def get_accounts(accounts_ids):
|
def get_accounts(accounts_ids):
|
||||||
accounts = []
|
accounts = []
|
||||||
for i in range(len(accounts_ids)):
|
for i in range(len(accounts_ids)):
|
||||||
account = api.account(accounts_ids[i])
|
try:
|
||||||
if "nobot" not in account.note:
|
account = api.account(accounts_ids[i])
|
||||||
accounts.append(account)
|
accounts.append(account)
|
||||||
if len(accounts) == len(coordinates):
|
if len(accounts) == len(coordinates):
|
||||||
break
|
break
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
print("Failed to get account id: " + accounts_ids[i])
|
||||||
return accounts
|
return accounts
|
||||||
|
|
||||||
|
def get_avatar():
|
||||||
|
try:
|
||||||
|
with Image.open(temp_image_name) as avatar:
|
||||||
|
avatar.load()
|
||||||
|
return avatar
|
||||||
|
except:
|
||||||
|
with Image.open('feditree/default.png') as avatar:
|
||||||
|
avatar.load()
|
||||||
|
return avatar
|
||||||
|
|
||||||
def create_image(accounts):
|
def create_image(accounts):
|
||||||
with Image.open("feditree/fediverse-christmas-tree.png") as feditree:
|
with Image.open("feditree/fediverse-christmas-tree.png") as feditree:
|
||||||
|
@ -65,14 +93,14 @@ def create_image(accounts):
|
||||||
account = api.account(accounts[i])
|
account = api.account(accounts[i])
|
||||||
avatar_url = account.avatar_static
|
avatar_url = account.avatar_static
|
||||||
avatar_data = requests.get(avatar_url).content
|
avatar_data = requests.get(avatar_url).content
|
||||||
with open('feditree/avatar.png', 'wb') as handler:
|
with open(temp_image_name, 'wb') as handler:
|
||||||
handler.write(avatar_data)
|
handler.write(avatar_data)
|
||||||
with Image.open('feditree/avatar.png') as avatar:
|
avatar = get_avatar()
|
||||||
avatar.load()
|
|
||||||
avatar = avatar.resize((100,100)).convert("RGB")
|
avatar = avatar.resize((100,100)).convert("RGB")
|
||||||
avatar.paste(bola_radio, (0,0), bola_radio)
|
avatar.paste(bola_radio, (0,0), bola_radio)
|
||||||
feditree.paste(avatar, coordinates[i], bola_mask)
|
feditree.paste(avatar, coordinates[i], bola_mask)
|
||||||
feditree.save("feditree/feditree.png")
|
tmp_file = (tempfile.NamedTemporaryFile(suffix='.png', delete=False)).name
|
||||||
|
feditree.save(tmp_file)
|
||||||
bola_radio.close()
|
bola_radio.close()
|
||||||
bola_mask.close()
|
bola_mask.close()
|
||||||
avatar.close()
|
avatar.close()
|
||||||
|
@ -82,35 +110,53 @@ def create_image(accounts):
|
||||||
description = description + " " + _("The accounts appear in the tree in the same order as the mentions, from top to bottom and from left to right.")
|
description = description + " " + _("The accounts appear in the tree in the same order as the mentions, from top to bottom and from left to right.")
|
||||||
description = description + " " + _("The order symbolizes the number of interactions, from most to least.")
|
description = description + " " + _("The order symbolizes the number of interactions, from most to least.")
|
||||||
description = description + "\n\n" + _("The Fediverse logo was created by @eudaimon@fe.disroot.org and the tree design was obtained from https://freesvgdesigns.com")
|
description = description + "\n\n" + _("The Fediverse logo was created by @eudaimon@fe.disroot.org and the tree design was obtained from https://freesvgdesigns.com")
|
||||||
return api.media_post("feditree/feditree.png", description=description)
|
ret = api.media_post(tmp_file, description=description)
|
||||||
|
try:
|
||||||
|
os.remove(tmp_file)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_filtered_notifications():
|
||||||
|
return [n for n in get_new_notifications(api, bot_name, ["mention"]) if n.status.visibility in ["public", "unlisted"]]
|
||||||
|
|
||||||
|
|
||||||
bot_name = "feditree"
|
|
||||||
localedir = './locales'
|
localedir = './locales'
|
||||||
api = get_api('masto.es', bot_name)
|
api = get_api(os.getenv("FEDI_DOMAIN"), bot_name)
|
||||||
notifications = get_new_notifications(api, bot_name, ["mention"])
|
notifications = get_filtered_notifications()
|
||||||
previous_ids = list_read(bot_name + "_previous_ids")
|
i18n = gettext.translation(bot_name, localedir, fallback=True, languages=['en'])
|
||||||
|
i18n.install()
|
||||||
|
|
||||||
for notification in notifications:
|
for notification in notifications:
|
||||||
i18n = gettext.translation(bot_name, localedir, fallback=True, languages=[notification.status.language])
|
|
||||||
i18n.install()
|
|
||||||
try:
|
try:
|
||||||
if str(notification.account.id) in previous_ids:
|
if has_user_posted(bot_name, notification.account.id):
|
||||||
status = "@" + notification.account.acct + " "
|
status = "@" + notification.account.acct + " "
|
||||||
status += _("I have already generated a feditree for you this year. Try again next year!")
|
status += _("I have already generated a faggotree for you this year. Try again next year!")
|
||||||
api.status_post(status, visibility="direct", in_reply_to_id=notification.status.id)
|
api.status_post(status, visibility="direct", in_reply_to_id=notification.status.id)
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
list_append(bot_name + "_previous_ids", previous_ids)
|
mark_user_posted(bot_name, notification.account.id)
|
||||||
accounts_ids = get_ordered_accounts_ids(notification.account.id)
|
accounts_ids = get_ordered_accounts_ids(notification.account.id)
|
||||||
accounts = get_accounts(accounts_ids)
|
accounts = get_accounts(accounts_ids)
|
||||||
image = create_image(accounts)
|
image = create_image(accounts)
|
||||||
status = _("These are the people who have adorned the #FediTree of") + " @" + notification.account.acct + ":"
|
status = _("These are the fags who have adorned the #FaggoTree of") + " @" + notification.account.acct + ":\n\n"
|
||||||
for account in accounts:
|
for account in accounts:
|
||||||
if account.acct == notification.account.acct:
|
if account.username != notification.account.username:
|
||||||
continue
|
status += " - " + account.acct + "\n"
|
||||||
status += " @/" + account.acct
|
|
||||||
api.status_post(status, media_ids=image, visibility="unlisted", in_reply_to_id=notification.status.id)
|
api.status_post(status, media_ids=image, visibility="unlisted", in_reply_to_id=notification.status.id)
|
||||||
previous_ids.append(notification.account.id)
|
except Exception as e:
|
||||||
except:
|
unmark_user_posted(bot_name, notification.account.id)
|
||||||
|
exc_type, exc_obj, exc_tb = sys.exc_info()
|
||||||
|
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
|
||||||
|
print(exc_type, fname, exc_tb.tb_lineno)
|
||||||
|
print(e)
|
||||||
api.status_post(_("An error ocurred. Please try again or contact my creator"), visibility="direct", in_reply_to_id=notification.status.id)
|
api.status_post(_("An error ocurred. Please try again or contact my creator"), visibility="direct", in_reply_to_id=notification.status.id)
|
||||||
|
|
||||||
|
|
||||||
|
if os.path.exists(temp_image_name):
|
||||||
|
try:
|
||||||
|
os.remove(temp_image_name)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
db_close()
|
Binary file not shown.
After Width: | Height: | Size: 7.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 196 KiB |
|
@ -48,9 +48,9 @@ msgstr ""
|
||||||
|
|
||||||
#: feditree.py:98
|
#: feditree.py:98
|
||||||
msgid ""
|
msgid ""
|
||||||
"I have already generated a feditree for you this year. Try again next year!"
|
"I have already generated a faggotree for you this year. Try again next year!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: feditree.py:103
|
#: feditree.py:103
|
||||||
msgid "These are the people who have adorned the #FediTree of"
|
msgid "These are the fags who have adorned the #FaggoTree of"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
python-dotenv
|
||||||
|
Mastodon.py
|
||||||
|
pillow
|
Loading…
Reference in New Issue