set up a proper git repository

This commit is contained in:
Wardyn 2022-11-23 01:07:54 -08:00
commit e256ad251c
6 changed files with 376 additions and 0 deletions

11
LICENSE Normal file
View File

@ -0,0 +1,11 @@
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.

33
README.md Normal file
View File

@ -0,0 +1,33 @@
# wardyns-feditools
Collection of simple tools to add functionality to the fediverse
## Installation
All these tools are designed to run in the same directory in order to prevent generating multiple access tokens. Installation is simple, download master branch as zip, extract into a folder of your choice, then, in that directory, run:
pip install -r requirements.txt
**Note:** These programs were written and tested in python 3.8
## Usage
All the programs are created with a built in help command, simply run [script] -h
## fedisearch.py
fedisearch is a tool that allows you to search through a users profile for a specific keyword or phrase.
Limitations:
- Very slow. Takes longer the the older a post is
- Does not currently support regular expressions
## autodeny.py
A simple script to automatically deny follow requests that do not pass certain tests. Those tests are:
1. The user has more than 1 post (configurable)
2. The user has a pfp other than the default one their instance assigns.
3. The user has text within their bio
It will not deny a follow request if you are following the user
You can also specify instances to block all follow requests from

167
autodeny.py Normal file
View File

@ -0,0 +1,167 @@
#!/usr/bin/python3.8
from mastodon import Mastodon
import sys
import os
import re
import sys
import argparse
import time
parser = argparse.ArgumentParser(description='Remove follow requests that match the following filters:\n1: Has less than n (defaults to 1) posts\n2: Has no profile picture\n3: Has no bio\n\nAdding extra filters is somewhat easy if you are familiar with python as well as the mastodon.py wrapper.', formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument('-t', '--threshold',
action='store',
type=int,
help='The amount of filters the request has to pass to not be automatically declined, defaults to 1 (setting this to a number higher than the amount of availible filters will deny every request in the list)',
default=1,
dest='threshold'
)
parser.add_argument('-i', '--instances',
action='store',
type=str,
help='block follow requests from these instances (comma seperated list)',
default=None,
dest='instances'
)
parser.add_argument('-p', '--posts',
action='store',
type=int,
help='The minimum number of posts a user must have to pass the posts filter (does not include boosts), defaults to 1',
default=1,
dest='minposts'
)
parser.add_argument('-y', '--yes',
action='store_const',
const=True,
help='Skips asking for confirmation before denying requests, use this if you want to automate this script.',
default=False,
dest='auto'
)
parser.add_argument('-s', '--simulate',
action='store_const',
const=True,
help='Simulates the process without modifying anything',
default=False,
dest='simulate'
)
parser.add_argument('-a', '--accept',
action='store_const',
const=True,
help='Automatically accept requests that arent rejected',
default=False,
dest='accept'
)
parser.add_argument('-l', '--loop',
action='store',
type=int,
help='Loop command every x hours',
default=None,
dest='loop'
)
args = parser.parse_args()
threshold = args.threshold
minposts = args.minposts
auto = args.auto
simulate = args.simulate
accept= args.accept
loop = args.loop
instances = args.instances
if instances is not None:
instances = instances.split(", ")
if type(loop) == int:
loop = loop * 60 * 60
# Ensure Fediverse credentials
parent = os.path.dirname(os.path.realpath(__file__))
if os.path.exists(os.path.join(parent, '.creds')) == False:
os.mkdir(os.path.join(parent, '.creds'))
if os.path.exists(os.path.join(parent, '.creds', 'client.secret')) == False:
instance = input('Please enter your instance: ')
if not instance[:4] == 'http':
instance = 'https://' + instance
Mastodon.create_app('Wardyns fedi tools', api_base_url = instance, to_file = os.path.join(parent, '.creds', 'client.secret'))
mastodon = Mastodon(
client_id = os.path.join(parent, '.creds', 'client.secret'),
)
if os.path.exists(os.path.join(parent, '.creds', 'user.secret')) == False:
username = input('Enter your username: ')
password = input('Enter your password: ')
mastodon.log_in(username=username, password=password, scopes=['read', 'write'], to_file=os.path.join(parent, '.creds', 'user.secret'))
mastodon = Mastodon(
access_token = os.path.join(parent, '.creds', 'user.secret')
)
def filterposts(min, request):
posts = request['statuses_count']
if posts >= min:
return(True)
else:
return(False)
def filterbio(request):
if request['note'] == '<p></p>':
return(False)
else:
return(True)
def filterpfp(request):
if request['avatar'] == mastodon.api_base_url + '/avatars/original/missing.png' or request['avatar'] == mastodon.api_base_url + '/images/avi.png':
return(False)
else:
return(True)
while True:
denied=[]
accepted=[]
while True:
try:
requests = mastodon.follow_requests()
break
except:
continue
if len(requests) > 0:
for request in requests:
#print(request['fqn'])
#print(request['id'])
postcheck = filterposts(minposts, request)
pfpcheck = filterpfp(request)
biocheck = filterbio(request)
#print('Has more than one post?: ' + str(postcheck))
#print('Has a pfp?: ' + str(pfpcheck))
#print('Has a bio?: ' + str(biocheck))
following = mastodon.account_relationships(request)[0]['following']
blockedinstance = False
if instances is not None:
blockedinstance = request['fqn'].split('@')[-1] in instances
if postcheck + biocheck + pfpcheck < threshold and following == False or blockedinstance == True:
denied.append(request)
elif accept == True:
accepted.append(request)
print('DENIED: ')
for request in denied:
print(request['fqn'])
confirm = None
if auto == False:
while True:
confirm = input('Deny these requests? (y/n): ')
if confirm == 'n':
pass
elif not confirm == 'y':
print('Not recognized, try again')
continue
break
if auto == True or confirm == 'y':
for request in denied:
if simulate:
print('This is where ' + request['fqn'] + ' would be rejected')
else:
mastodon.follow_request_reject(request['id'])
for request in accepted:
if simulate:
print('This is where ' + request['fqn'] + ' would be accepted')
else:
mastodon.follow_request_authorize(request['id'])
if loop == None:
break
else:
time.sleep(loop)

110
fedisearch.py Normal file
View File

@ -0,0 +1,110 @@
# Import modules
from mastodon import Mastodon
import os
import html2text
from argparse import ArgumentParser
import os
# Initialize arguments
parser = ArgumentParser(description='Search a fedi users posts for a specific word or phrase')
parser.add_argument('-c', '--case',
action='store_const',
const=True,
help='Match string as case sensitive',
default=False,
dest='case'
)
parser.add_argument('-d', '--dms',
action='store_const',
const=True,
help='Include DMs',
default=False,
dest='dms'
)
parser.add_argument('account',
type=str,
help='Account to search through',
)
parser.add_argument('pattern',
type=str,
help='Pattern to search for',
)
args = parser.parse_args()
case = args.case
dms = args.dms
account = args.account
pattern = args.pattern
# Ensure Fediverse credentials
parent = os.path.dirname(os.path.realpath(__file__))
if os.path.exists(os.path.join(parent, '.creds')) == False:
os.mkdir(os.path.join(parent, '.creds'))
if os.path.exists(os.path.join(parent, '.creds', 'client.secret')) == False:
instance = input('Please enter your instance: ')
if not instance[:4] == 'http':
instance = 'https://' + instance
Mastodon.create_app('Wardyns fedi tools', api_base_url = instance, to_file = os.path.join(parent, '.creds', 'client.secret'))
mastodon = Mastodon(
client_id = os.path.join(parent, '.creds', 'client.secret'),
)
if os.path.exists(os.path.join(parent, '.creds', 'user.secret')) == False:
username = input('Enter your username: ')
password = input('Enter your password: ')
mastodon.log_in(username=username, password=password, scopes=['read', 'write'], to_file=os.path.join(parent, '.creds', 'user.secret'))
mastodon = Mastodon(
access_token = os.path.join(parent, '.creds', 'user.secret')
)
# Main block
if case == False:
pattern = pattern.lower()
oldest_status_id = None
htmlconvert = html2text.HTML2Text()
htmlconvert.ignore_links = True
htmlconvert.body_width = 0
if account[0] == '@':
account = account[1:]
if len(account.split('@')) == 1:
account = account + '@' + mastodon.api_base_url.split('/')[2]
accountlist = mastodon.account_search(account)
for curaccount in accountlist:
print(curaccount['fqn'])
if curaccount['fqn'].lower() == account.lower():
account = curaccount
break
if type(account) is str:
print('Could not find an account with the search term: ' + account)
exit()
accid = account['id']
print('Searching for posts including "' + pattern + '" from user ' + account['fqn'])
print('\n---\n')
while True:
while True:
try:
statuses = mastodon.account_statuses(accid, max_id=oldest_status_id, limit=1000)
break
except IndexError:
break
except:
pass
if len(statuses) == 0:
break
oldest_status_id = statuses[-1]['id']
for status in statuses:
if status['reblog'] == None:
if status['visibility'] == 'direct' and dms == False:
continue
content = str(htmlconvert.handle(status['content']))
if case == False:
content = content.lower()
if pattern in content:
print(content)
print('\nlink: ' + status['url'])
print('\n---\n')
print('Finished searching')

55
highestpost.py Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/python3.8
from mastodon import Mastodon
import os
import sys
import html2text
if os.path.exists('./.creds/') == False:
os.mkdir('./.creds')
if os.path.exists('./.creds/client.secret') == False:
instance = input('Please enter your instance: ')
if not instance[:4] == 'http':
instance = 'https://' + instance
Mastodon.create_app('Wardyns fedi tools', api_base_url = instance, to_file = './.creds/client.secret')
mastodon = Mastodon(
client_id = './.creds/client.secret',
)
if os.path.exists('./.creds/user.secret') == False:
username = input('Enter your username: ')
password = input('Enter your password: ')
mastodon.log_in(username=username, password=password, scopes=['read', 'write'], to_file='./.creds/user.secret')
mastodon = Mastodon(
access_token = './.creds/user.secret'
)
if len(sys.argv) < 2:
print('Expected 1 argument (account)')
quit()
else:
highestpost = None
oldest_status_id = None
htmlconvert = html2text.HTML2Text()
htmlconvert.ignore_links = True
htmlconvert.body_width = 0
account = sys.argv[1]
accid = mastodon.account_search(account)[0]['id']
while True:
statuses = mastodon.account_statuses(accid, max_id=oldest_status_id, limit=1000)
try:
oldest_status_id = statuses[-1]['id']
except IndexError:
print('Reached end of posts')
quit()
for status in statuses:
statusscore = status['reblogs_count'] + status['favourites_count']
if status['reblogged'] == False:
if highestpost == None or statusscore > highestpost['score']:
highestpost = {'score' : status['reblogs_count'] + status['favourites_count'], 'post' : status}
content = str(htmlconvert.handle(status['content']))
print(content)
print('Favorites: ' + str(status['favourites_count']) + ' Boosts: ' + str(status['reblogs_count']))
print('link: ' + status['url'])
print('-------')

BIN
requirements.txt Normal file

Binary file not shown.