set up a proper git repository
This commit is contained in:
commit
e256ad251c
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -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)
|
|
@ -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')
|
|
@ -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('-------')
|
Binary file not shown.
Loading…
Reference in New Issue