commit
bdc0afb800
7 changed files with 187865 additions and 0 deletions
@ -0,0 +1,3 @@ |
||||
[submodule "fedbot"] |
||||
path = fedbot |
||||
url = git@git.thj.no:thor/fedbot.git |
@ -0,0 +1,19 @@ |
||||
Copyright (c) 2021 Thor <thj@thj.no> |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,34 @@ |
||||
# Log name |
||||
#name = "portmanteau" |
||||
|
||||
[defaults] |
||||
# Name of the application as listed in the account settings on the server |
||||
#app_name = "PortmanteauBot" |
||||
|
||||
# Minimum seconds between requests to the server |
||||
#rate_limit = 3 |
||||
|
||||
# Seconds between retrying failed requests to the server |
||||
#retry_rate = 60 |
||||
|
||||
# Seconds between polling the server for updates |
||||
#poll_interval = 15 |
||||
|
||||
[clients] |
||||
# The client name (in quotes below) is displayed in log messages, and is |
||||
# used as the default hostname of the server to connect to, and as the |
||||
# default base name of the various files and folders that are used by |
||||
# each client. |
||||
[clients."mastodon.social"] |
||||
|
||||
# The URL of the server that the client connects to |
||||
#base_url = "https://mastodon.social" |
||||
|
||||
# Where to store the authorisation key for the client |
||||
#client_file = "clients/mastodon.social/client.secret" |
||||
|
||||
# Where to store the authorisation key for the user account |
||||
#user_file = "clients/mastodon.social/user.secret" |
||||
|
||||
# Where to store the persisted state of the client |
||||
#state_file = "clients/mastodon.social/state.json" |
@ -0,0 +1 @@ |
||||
Subproject commit ac336e9492fe8605bcef61775568c0dcbbc78236 |
@ -0,0 +1,201 @@ |
||||
import os |
||||
import sys |
||||
import time |
||||
import toml |
||||
import random |
||||
import re |
||||
from datetime import datetime, timedelta, timezone |
||||
import sched |
||||
|
||||
from mastodon import Mastodon, MastodonNotFoundError |
||||
from fedbot.bot import Bot, BotClient |
||||
|
||||
POST_INTERVAL = timedelta(seconds = 15) |
||||
|
||||
def next_dt(): |
||||
dt = datetime.now(timezone.utc) |
||||
dt -= timedelta(hours = -1, |
||||
minutes = dt.minute, |
||||
seconds = dt.second, |
||||
microseconds = dt.microsecond) |
||||
return dt |
||||
|
||||
|
||||
config_path = os.path.join(os.path.dirname(sys.argv[0]), "config.toml") |
||||
loaded_config = { |
||||
"name": "portmanteaubot", |
||||
**toml.load(config_path)} |
||||
|
||||
SUFFIXES = [ |
||||
['ly'], |
||||
['ing'], |
||||
['[bdklmptw]?est$'], |
||||
['[^ious]s$'], |
||||
['ted'], |
||||
['[ei]$', 'ty']] |
||||
|
||||
def is_suffixed(word): |
||||
for suffix in SUFFIXES: |
||||
if len(suffix) > len(word): |
||||
continue |
||||
|
||||
syllables = list(zip(suffix, word[-len(suffix):])) |
||||
|
||||
if all(re.fullmatch(suf, syl) for suf, syl in syllables): |
||||
#print(word, "matched", suffix) |
||||
return True |
||||
|
||||
return False |
||||
|
||||
class WordMaker: |
||||
def __init__(self): |
||||
print("Loading dictionaries") |
||||
with open ("mhyph.txt", "r", encoding = "mac-roman") as f: |
||||
lines = [line.strip() for line in f.readlines()] |
||||
lines = filter(lambda word: len(word) > 0 and not re.search(r'[- A-Z]', word), lines) |
||||
words = [line.split("•") for line in lines] |
||||
words = sorted(words, key = lambda w: len(w), reverse = True) |
||||
self.words = words |
||||
self.first_words = list(filter(lambda word: not is_suffixed(word), words)) |
||||
self.plain_words = ["".join(word) for word in words] |
||||
|
||||
with open("porthyph.txt", "r") as f: |
||||
lines = [line.strip() for line in f.readlines()] |
||||
words = [line.split("=") for line in lines] |
||||
words = sorted(words, key = lambda w: len(w), reverse = True) |
||||
self.alt_words = words |
||||
self.plain_words.append(["".join(word) for word in words]) |
||||
|
||||
def get_one_word(self, words): |
||||
weights = [int(100.0 * (x + 1.0) / len(words)) for x in range(0, len(words))] |
||||
return random.choices(words, weights = weights)[0] |
||||
|
||||
def get_second_word(self, first_word): |
||||
first_word = list(first_word) |
||||
first_end = first_word[-1].lower() |
||||
|
||||
if random.randint(0, 100) < 50: |
||||
second_dict = self.alt_words |
||||
else: |
||||
second_dict = self.words |
||||
|
||||
if random.randint(0, 100) < 50: |
||||
second_iter = filter(lambda w: w[0].lower().startswith(first_end) or first_end.startswith(w[0].lower()), second_dict) |
||||
else: |
||||
second_iter = filter(lambda w: w[0].lower().startswith(first_end), second_dict) |
||||
second_words = list(second_iter) |
||||
|
||||
#if len(second_words) < 8: |
||||
# return None |
||||
|
||||
while len(second_words) > 0: |
||||
second_word_orig = self.get_one_word(second_words) |
||||
second_word = [s.lower() for s in second_word_orig] |
||||
second_words.remove(second_word_orig) |
||||
word = [*first_word[:-1], *second_word] |
||||
if not "".join(word) in self.plain_words: |
||||
return word |
||||
|
||||
return None |
||||
|
||||
def get_portmanteau(self): |
||||
target_times = 1 |
||||
if random.randint(0, 100) > 50: |
||||
words = self.alt_words |
||||
else: |
||||
words = self.first_words |
||||
|
||||
while True: |
||||
while True: |
||||
word = self.get_one_word(words) |
||||
|
||||
end = word[-1] |
||||
|
||||
times = target_times |
||||
while times > 0: |
||||
next_word = self.get_second_word(word) |
||||
if next_word is None: |
||||
break |
||||
else: |
||||
word = next_word |
||||
times -= 1 |
||||
|
||||
if times > 0: |
||||
continue |
||||
else: |
||||
break |
||||
|
||||
word_str = "".join(word) |
||||
|
||||
if len(word_str) < 15: |
||||
break |
||||
|
||||
print(word_str) |
||||
|
||||
return word_str |
||||
|
||||
def get_portmanteaus(self, count = 10): |
||||
return [self.get_portmanteau() for x in range(0, count)] |
||||
|
||||
class PortBotClient(BotClient): |
||||
def __init__(self, bot, config): |
||||
config = { |
||||
"app_name": "PortmanteuBot", |
||||
"rate_limit": 3, |
||||
"retry_rate": 60, |
||||
"poll_interval": 15, |
||||
**config} |
||||
|
||||
|
||||
super().__init__(bot, config) |
||||
|
||||
self.my_id = None |
||||
|
||||
def on_start(self): |
||||
self.log("Starting") |
||||
self.my_id = self.api.me()["id"] |
||||
pass |
||||
|
||||
def on_poll(self): |
||||
pass |
||||
|
||||
def on_status(self, status): |
||||
if status["account"]["id"] != self.my_id: |
||||
return |
||||
|
||||
if status["created_at"] < datetime.now(timezone.utc) - timedelta(hours = 24) and status["reblogs_count"] == 0 and status["favourites_count"] == 0: |
||||
try: |
||||
print("Deleting", status["created_at"], status["content"]) |
||||
self.api.status_delete(status["id"]) |
||||
time.sleep(2) |
||||
except MastodonNotFoundError: |
||||
pass |
||||
pass |
||||
|
||||
def post(): |
||||
for client_name, client in bot.clients.items(): |
||||
words = wm.get_portmanteaus(1) |
||||
if random.randint(0, 100) <= 100: |
||||
visibility = "public" |
||||
else: |
||||
visibility = "unlisted" |
||||
|
||||
client.api.status_post("\n".join(words), visibility = visibility) |
||||
|
||||
dt = next_dt() |
||||
print("Scheduling at", dt) |
||||
scheduler.enterabs(dt.timestamp(), 1, post) |
||||
|
||||
wm = WordMaker() |
||||
scheduler = sched.scheduler(timefunc = time.time, delayfunc = time.sleep) |
||||
|
||||
bot = Bot(PortBotClient, loaded_config) |
||||
del loaded_config |
||||
bot.start() |
||||
|
||||
print("Running") |
||||
|
||||
dt = next_dt() |
||||
print("Scheduling at", dt) |
||||
scheduler.enterabs(dt.timestamp(), 1, post) |
||||
scheduler.run() |
@ -0,0 +1,432 @@ |
||||
4=chan |
||||
4=chan=ner |
||||
ac=qui=hire |
||||
ac=qui=hi=re |
||||
am=az=on |
||||
am=a=zon |
||||
a=maz=on |
||||
a=ma=zon |
||||
an=i=me |
||||
a=ni=me |
||||
an=i=mu |
||||
a=ni=mu |
||||
A=non |
||||
An=on |
||||
App=le |
||||
Ap=ple |
||||
Ap=p=le |
||||
As=perg=er |
||||
As=per=ger |
||||
ba=ka |
||||
ba=sed |
||||
b=as=ed |
||||
Bar=bie |
||||
bi=sex=u=al |
||||
Bit=coin |
||||
block=chain |
||||
bloat=ware |
||||
blog=ger |
||||
boom=er |
||||
bo=om=er |
||||
bo=o=mer |
||||
bo=ner |
||||
bo=n=er |
||||
boob |
||||
boo=b |
||||
b=oob |
||||
boo=ty |
||||
brow=ser |
||||
Bow=ser |
||||
Bo=w=ser |
||||
Bo=ws=er |
||||
Buzz=feed |
||||
Bu=zz=feed |
||||
brain=let |
||||
bra=in=let |
||||
bruh |
||||
bull=shit |
||||
butt=load |
||||
butt=crack |
||||
butt=cr=ack |
||||
cat |
||||
cat=girl |
||||
cell=phone |
||||
cell=pho=ne |
||||
chad |
||||
ch=ad |
||||
ch=at=room |
||||
cheem |
||||
ch=eem |
||||
ch=eems |
||||
Chew=bac=ca |
||||
chi=bi |
||||
ch=i=bi |
||||
chonk |
||||
ch=on=k |
||||
chonk=er |
||||
ch=onk=er |
||||
click=ba=it |
||||
com=put=er |
||||
coo=mer |
||||
coom=er |
||||
cuck |
||||
cuck=ed |
||||
creep=er |
||||
cree=per |
||||
cringe |
||||
cri=n=ge |
||||
cryp=to |
||||
cy=ber |
||||
cy=ber=sex |
||||
cy=ber=s=ex |
||||
cy=ber=space |
||||
cy=ber=s=pace |
||||
cy=ber=spa=ce |
||||
De=b=i=an |
||||
Deb=i=an |
||||
dil=do |
||||
dild=o |
||||
doge |
||||
do=ge |
||||
Do=ku |
||||
Do=lan |
||||
Do=l=an |
||||
douche=bag |
||||
dou=che=bag |
||||
do=wn=load |
||||
dumb=phone |
||||
du=mb=phone |
||||
Drop=box |
||||
ec=chi |
||||
Er=lang |
||||
Erl=ang |
||||
e=Bay |
||||
e=mail |
||||
e=mo=ti=con |
||||
e=mo=ji |
||||
en=by |
||||
end=er=man |
||||
en=d=er=man |
||||
end=er=m=en |
||||
en=d=er=m=an |
||||
end=er=men |
||||
end=er=m=en |
||||
en=d=er=men |
||||
en=d=er=m=en |
||||
Fa=ce=book |
||||
face=plant |
||||
face=pl=ant |
||||
fa=ce=pl=ant |
||||
face=palm |
||||
fa=ce=palm |
||||
fag=got=try |
||||
fa=g=got=try |
||||
fan=boy |
||||
fa=n=boy |
||||
fan=boi |
||||
fa=n=boi |
||||
fan=fic |
||||
fa=n=fic |
||||
fan=fiction |
||||
fan=fic=tion |
||||
fa=n=fic=tion |
||||
fan=girl |
||||
fa=n=girl |
||||
fap=p=able |
||||
fap=p=ab=le |
||||
fa=pp=ab=le |
||||
fap=worthy |
||||
fap=wor=thy |
||||
fa=p=wor=thy |
||||
fart |
||||
f=art |
||||
fa=rt |
||||
fed=i |
||||
fe=di |
||||
fed=i=verse |
||||
fe=di=verse |
||||
free=mi=um |
||||
fire |
||||
fi=red |
||||
fi=r=ed |
||||
Fire=fox |
||||
Fi=re=fox |
||||
fuck=ton |
||||
fu=ck=ton |
||||
futa |
||||
fu=ta |
||||
futur=ama |
||||
futur=a=ma |
||||
fu=tur=a=ma |
||||
gay |
||||
gay=dar |
||||
gay=d=ar |
||||
gen=der=flu=id |
||||
gig=a=chad |
||||
giga=ch=ad |
||||
gi=ga=ch=ad |
||||
Giph=y |
||||
Gi=phy |
||||
Goo=gle |
||||
Goo=g=le |
||||
Goog=le |
||||
goo=m=ba |
||||
goom=ba |
||||
goat=se |
||||
go=at=se |
||||
Go=Fund=Me |
||||
goth |
||||
go=th |
||||
grief=er |
||||
grie=fer |
||||
gu=ru |
||||
hack=tiv=ist |
||||
hack=tiv=ism |
||||
ha=lf=ass |
||||
hang=ry |
||||
ha=n=gry |
||||
Ha=ram=be |
||||
ha=rem |
||||
hash=tag |
||||
ha=sh=tag |
||||
head=desk |
||||
hell=thread |
||||
hell=th=read |
||||
hen=tai |
||||
hip=ster |
||||
hips=ter |
||||
hodl |
||||
hod=l |
||||
hor=ny |
||||
horn=y |
||||
ho=r=ny |
||||
hus=ban=do |
||||
hus=band=o |
||||
hy=per=link |
||||
in=cel |
||||
In=ter=net |
||||
i=Pho=ne |
||||
I=sa=bel=le |
||||
Ja=va=Script |
||||
Jobs |
||||
J=obs |
||||
J=PEG |
||||
JP=EG |
||||
Kar=da=shi=an |
||||
Kick=start=er |
||||
Kick=star=ter |
||||
Kir=by |
||||
Knuck=les |
||||
Knuckl=es |
||||
les=bi=an |
||||
Link |
||||
Li=nk |
||||
L=ink |
||||
Linked=In |
||||
Li=nked=In |
||||
live=st=ream |
||||
live=stream |
||||
live=stream=ing |
||||
lol |
||||
lord |
||||
lo=rd |
||||
l=ord |
||||
lore |
||||
lo=re |
||||
lul=z |
||||
Lui=gi |
||||
Lu=i=gi |
||||
Nin=ten=do |
||||
ma=fi=a |
||||
mal=ware |
||||
ma=l=ware |
||||
ma=ma |
||||
man=ga |
||||
ma=n=ga |
||||
man=scape |
||||
ma=n=scape |
||||
ma=n=sc=ape |
||||
man=sc=ape |
||||
Mar=i=o |
||||
Ma=ri=o |
||||
Ma=rio |
||||
meme |
||||
me=me |
||||
Me=ga=man |
||||
Mic=ro=soft |
||||
mil=len=ni=al |
||||
mi=len=n=ial |
||||
Mine=craft |
||||
Mine=cr=aft |
||||
mo=dem |
||||
mod=em |
||||
mo=ther |
||||
mo=th=er |
||||
Mu=ri=can |
||||
mu=tu=al |
||||
moe |
||||
mo=e |
||||
m=oe |
||||
ne=ko |
||||
nerd |
||||
ne=w=fag |
||||
non=bin=ary |
||||
no=n=bi=nary |
||||
noob |
||||
no=ob |
||||
norm=al=fag |
||||
no=rm=al=fag |
||||
no=rmie |
||||
nor=mie |
||||
norm=ie |
||||
Nut=el=la |
||||
Nyan=cat |
||||
Ny=an=cat |
||||
old=fag |
||||
o=ta=ku |
||||
on=ii=san |
||||
op=pai |
||||
opp=ai |
||||
pe=do |
||||
Pe=do=bear |
||||
pe=pe |
||||
pho=to=bomb |
||||
Play=Sta=tion |
||||
Ple=ro=ma |
||||
Pi=ka=chu |
||||
plug=in |
||||
Po=ké=mon |
||||
po=rn |
||||
porn |
||||
po=t=at |
||||
po=tat |
||||
po=t=et |
||||
po=tet |
||||
psy=op |
||||
p=sy=op |
||||
pus=sy |
||||
pu=s=sy |
||||
pwned |
||||
pwn=ed |
||||
rage=face |
||||
ra=ge=face |
||||
re=tweet |
||||
Red=Hat |
||||
Re=d=Hat |
||||
rick=roll |
||||
ri=ck=roll |
||||
sa=p=phic |
||||
sap=phic |
||||
sap=p=hic |
||||
sap=ph=ic |
||||
sel=fie |
||||
se=l=fie |
||||
sen=pai |
||||
se=n=pai |
||||
sex |
||||
s=ex |
||||
soy=boy |
||||
Slen=der=man |
||||
Slen=der=m=an |
||||
Slen=der=men |
||||
Slen=der=m=en |
||||
smart=pho=ne |
||||
Snap=chat |
||||
Snap=ch=at |
||||
shit=coin |
||||
shi=t=coin |
||||
shi=t=ton |
||||
shit=post |
||||
Snow=den |
||||
soft=ware |
||||
so=ft=ware |
||||
Son=ic |
||||
So=n=ic |
||||
spam |
||||
sp=am |
||||
sperg |
||||
Sponge=bob |
||||
Spot=i=fy |
||||
Spo=ti=fy |
||||
start=up |
||||
steam=punk |
||||
steam=pun=k |
||||
ston=k |
||||
st=on=k |
||||
ston=ks |
||||
st=on=ks |
||||
sub=tweet |
||||
su=b=tweet |
||||
Squid=ward |
||||
swole |
||||
swo=le |
||||
ten=tac=le |
||||
te=n=tac=le |
||||
Tes=la |
||||
Te=s=la |
||||
Tind=er |
||||
Tin=der |
||||
thicc |
||||
thic=c |
||||
totes |
||||
to=tes |
||||
to=t=es |
||||
Tor |
||||
T=or |
||||
trans |
||||
trans=sex |
||||
trans=sex=u=al |
||||
trend=ing |
||||
troll=face |
||||
troll=tard |
||||
tsun=de=re |
||||
tsu=n=de=re |
||||
Tw=itch |
||||
Twi=tch |
||||
U=ber |
||||
Ub=er |
||||
U=bun=tu |
||||
U=nix |
||||
Un=ix |
||||
un=fapp=able |
||||
vi=ral |
||||
vi=r=al |
||||
vi=rus |
||||
vi=r=us |
||||
vol=cel |
||||
vo=l=c=el |
||||
wai=fu |
||||
wa=i=fu |
||||
wa=if=u |
||||
Wa=lu=i=gi |
||||
wank |
||||
wa=nk |
||||
wan=ker |
||||
wa=n=ker |
||||
wa=nk=er |
||||
weeb |
||||
wee=a=boo |
||||
web=com=ic |
||||
web=co=mic |
||||
web=site |
||||
Wik=i=pe=di=a |
||||
Wi=ki=pe=di=a |
||||
Wind=ows |
||||
Win=dows |
||||
Whats=App |
||||
Whats=Ap=p |
||||
Whats=Ap=p |
||||
What=s=Ap=p |
||||
Word=Press |
||||
yan=de=re |
||||
ya=n=de=re |
||||
You=Tube |
||||
You=Tu=be |
||||
X=box |
||||
Yo=da |
||||
Yo=shi |
||||
Zel=da |
||||
Ze=l=da |
||||
zoom=er |
||||
zoo=mer |
||||
zoo=m=er |
Loading…
Reference in new issue