diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2a22ca --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +config.json + +db/accounts/*.json + +actions/*.curl +scripts/* diff --git a/actions/delete.curl.example b/actions/delete.curl.example new file mode 100644 index 0000000..421b0db --- /dev/null +++ b/actions/delete.curl.example @@ -0,0 +1,5 @@ +1. Ve a un toot de prueba tuyo, desde el panel de administración +2. Abre el "panel de desarrollador" del navegador. Ve a la sección "Red" (Network) +3. Realiza un borrado del toot de prueba. +4. Copia como "curl" la petición POST del borrado. +5. Pega el texto en este archivo y reemplaza el ID de account por {accid} y el ID del status por {status} diff --git a/config.json.example b/config.json.example new file mode 100644 index 0000000..d5350c1 --- /dev/null +++ b/config.json.example @@ -0,0 +1,8 @@ +{ + "db": { + "host": "127.0.0.1", + "port": 5432, + "username": "postgres", + "password": null + } +} diff --git a/db/accounts/ID.json.example b/db/accounts/ID.json.example new file mode 100644 index 0000000..64e489d --- /dev/null +++ b/db/accounts/ID.json.example @@ -0,0 +1,16 @@ +[ + { + "days_old": 30, + "visibility": "public", + "exclude": ["#Activismo", "#NoBIGTech", "#Octavillas", "#Pancartas"] + }, + { + "days_old": 7, + "visibility": "unlisted", + "exclude": ["#NoBIGTech", "tutoriales"] + }, + { + "days_old": 7, + "visibility": "followers" + } +] diff --git a/purge.py b/purge.py new file mode 100644 index 0000000..e09bef1 --- /dev/null +++ b/purge.py @@ -0,0 +1,99 @@ +#!/bin/bash +import psycopg2 +import json +import os +import re + + +def psql_connect(): + cfg = json.loads(readf('config.json')) + return psycopg2.connect(\ + host=cfg['db']['host'],\ + port=cfg['db']['port'],\ + user=cfg['db']['username'],\ + password=cfg['db']['password']\ + ) + +def get_statuses(accid, visibility, days_old): + visibility_set = { + 'followers': 2, + 'unlisted': 1, + 'public': 0 + } + con = psql_connect() + cur = con.cursor() + cur.execute("SELECT id, created_at, text FROM statuses WHERE account_id = {accid} AND visibility = {visibility} AND DATE_PART('day', NOW() - created_at) >= {days_old} AND text != ''".replace('{accid}', str(accid)).replace('{visibility}', str(visibility_set[visibility])).replace('{days_old}', str(days_old))) + ret = cur.fetchall() + con.close() + return ret + +def get_statuses_pinned(accid): + con = psql_connect() + cur = con.cursor() + cur.execute('SELECT status_id FROM status_pins WHERE account_id = {}'.format(accid)) + ret = cur.fetchall() + con.close() + return [str(a[0]) for a in ret] + + +def main(): + accounts = {} + for fil in os.listdir('db/accounts'): + if not fil.endswith('.json'): + continue + id_ = fil.replace('.json', '') + accounts[id_] = json.loads(readf('db/accounts/{}'.format(fil))) + + action_delete = readf('actions/delete.curl') + for id_ in accounts: + account = accounts[id_] + pinned = get_statuses_pinned(id_) + allstatuses = [] + for item in accounts[id_]: + exclude = [] + if 'exclude' in item: + exclude = [a.lower() for a in item['exclude']] + exclude = [normalize(a) for a in exclude] + statuses = get_statuses(id_, item['visibility'], item['days_old']) + for id_status, created_at, text in statuses: + if str(id_status) in pinned: + continue + words = text.strip().replace('\n', ' ').lower() + words = re.sub(r'[^a-z0-9\#\@\.\-]', ' ', normalize(words)) + words = re.sub(r'\s+', ' ', words).split() + words = [a.strip('.') for a in words] + text = ' '+(' '.join(words))+' ' + text = re.sub(r'\s+', ' ', text) + excludeit = False + for excl in exclude: + if ' '+excl+' ' in text: + excludeit = True + break + if excludeit: + continue + allstatuses.append(id_status) + + allstatuses = sorted(set(allstatuses)) + cmd = action_delete.replace('{accid}', id_) + for status in allstatuses: + cmd2 = cmd.replace('{status}', str(status)) + print('I| Removing status '+str(status)+' ', end='') + os.system(cmd2+' >/dev/null 2>&1') + print('done') + +def normalize(t): + t = t.replace('á', 'a') + t = t.replace('é', 'e') + t = t.replace('í', 'i') + t = t.replace('ó', 'o') + t = t.replace('ú', 'u') + return t + +def readf(f): + r = open(f,'r') + c = r.read().strip() + r.close() + return c + +if __name__ == '__main__': + main()