Compare commits

...

2 Commits

Author SHA1 Message Date
Thor 902e2da2b2 New word list format 3 years ago
Thor 3c71d99c7c New algorithm 3 years ago
  1. 184
      portbot.py
  2. 767
      porthyph.txt

@ -4,19 +4,22 @@ import time
import toml
import random
import re
from datetime import datetime, timedelta, timezone
import sched
import math
import string
from datetime import datetime, timedelta, timezone
from mastodon import Mastodon, MastodonNotFoundError
from fedbot.bot import Bot, BotClient
POST_INTERVAL = timedelta(seconds = 15)
TEST = False
TEST = "test" in sys.argv[1:]
PORT_PCT = 67
def next_dt():
dt = datetime.now(timezone.utc)
dt -= timedelta(hours = -1,
minutes = dt.minute,
dt -= timedelta(hours = 0,
minutes = (dt.minute % 15) - 15,
seconds = dt.second,
microseconds = dt.microsecond)
return dt
@ -28,107 +31,126 @@ loaded_config = {
**toml.load(config_path)}
SUFFIXES = [
['ly'],
['ing'],
['[bdklmptw]?est$'],
['[^ious]s$'],
['ted'],
['[ei]$', 'ty']]
'ly$',
'ing$',
'[bdklmptw]?est$',
'[^ious]s$',
'ted$',
'[ei]ty$']
def is_suffixed(word):
for suffix in SUFFIXES:
if len(suffix) > len(word):
continue
return any(re.fullmatch(suf, word) for suf in SUFFIXES)
syllables = list(zip(suffix, word[-len(suffix):]))
if all(re.fullmatch(suf, syl) for suf, syl in syllables):
#print(word, "matched", suffix)
return True
def overlap_words(left_word, right_word):
if left_word == right_word:
return None
return False
offset = 2
attempts = []
while offset + 2 <= len(left_word):
if right_word.lower().startswith(left_word.lower()[offset : offset + 2]):
attempts.append(left_word[:offset] + right_word)
#break
offset += 1
offset = len(right_word) - 2
while offset >= 0:
if left_word.lower().endswith(right_word.lower()[offset : offset + 2]):
attempts.append(left_word + right_word[offset + 2:])
#break
offset -= 1
attempts = sorted(attempts, key = lambda w: len(w), reverse = True)
if len(attempts) == 0:
return None
return pick_one_word(attempts)
def word_weight(index, length, power = 2):
a = pow((index + 1) / length, 2)
return int(100000 * a)
def pick_one_word(words, power = 2, max_len = 12):
words = list(filter(lambda w: len(w) <= max_len, words))
if len(words) == 0:
return None
weights = [word_weight(i, len(words), power = power) for i in range(0, len(words))]
return random.choices(words, weights = weights)[0]
class WordMaker:
def __init__(self):
print("Loading dictionaries")
illegal = set(ch for ch in (string.ascii_uppercase + string.punctuation + string.digits + string.whitespace))
with open ("mhyph.txt", "r", encoding = "mac-roman") as f:
lines = [line.strip() for line in f.readlines()]
lines = filter(lambda w: len(w) > 0 and not re.search(r'[- A-Z]', w), lines)
words = [line.split("") for line in lines]
words = sorted(words, key = lambda w: len(w), reverse = True)
self.words = words
lines = [l.strip() for l in f.readlines()]
lines = filter(lambda w: len(w) > 0 and not any(ch in illegal for ch in w), lines)
words = [l.replace("", "") for l in lines]
self.all_words = words
words = list(set(sorted(words, key = lambda w: len(w), reverse = True)))
self.first_words = list(filter(lambda w: not is_suffixed(w), words))
self.plain_words = ["".join(w).lower() for w in words]
self.next_words = words
with open("porthyph.txt", "r") as f:
lines = [line.strip() for line in f.readlines()]
lines = filter(lambda l: len(l) > 0, lines)
words = [line.split("=") for line in lines]
words = sorted(words, key = lambda w: len(w), reverse = True)
self.alt_words = words
self.plain_words.extend(["".join(w).lower() for w 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]
if random.randint(0, 100) < 50:
second_dict = self.alt_words
words = list(filter(lambda l: len(l) > 0, lines))
self.all_words = list(set(sorted([w.lower() for w in [*self.all_words, *words]], key = lambda w: len(w), reverse = True)))
self.port_words = list(set(sorted(words, key = lambda w: len(w), reverse = True)))
def extend_word2(self, prev_word):
port_dict = random.randint(0, 100) < PORT_PCT
if port_dict:
next_dict = self.port_words
else:
second_dict = self.words
next_dict = self.next_words
if random.randint(0, 100) < 50:
second_iter = filter(lambda w: w[0].lower().startswith(first_end.lower()) or first_end.lower().startswith(w[0].lower()), second_dict)
else:
second_iter = filter(lambda w: w[0].lower().startswith(first_end.lower()), second_dict)
second_words = list(second_iter)
new_words = [overlap_words(prev_word, w) for w in next_dict if overlap_words(prev_word, w)]
while len(new_words) > 0:
new_word = pick_one_word(new_words, power = 2 if port_dict else 4)
if not new_word:
return None
new_words.remove(new_word)
if new_word.lower() not in self.all_words:
return new_word
while len(second_words) > 0:
second_word_orig = self.get_one_word(second_words)
second_words.remove(second_word_orig)
second_word = [s.lower() for s in second_word_orig]
word = [*first_word[:-1], *second_word]
if not "".join(word).lower() 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
port_dict = random.randint(0, 100) < PORT_PCT
if port_dict:
words = self.port_words
else:
words = self.first_words
while True:
while True:
word = self.get_one_word(words)
word = pick_one_word(words, power = 2 if port_dict else 4)
times = target_times
while times > 0:
next_word = self.get_second_word(word)
if next_word is None:
ext_word = self.extend_word2(word)
if ext_word is None:
break
word = next_word
word = ext_word
times -= 1
if times == 0:
break
word_str = "".join(word)
if len(word_str) < 15:
if len(word) < 15:
break
print(word_str)
word = word.lower()
print(word)
return word_str
return word
def get_portmanteaus(self, count = 10):
return [self.get_portmanteau() for x in range(0, count)]
@ -141,7 +163,6 @@ class PortBotClient(BotClient):
"retry_rate": 60,
"poll_interval": 15,
**config}
super().__init__(bot, config)
@ -159,28 +180,29 @@ class PortBotClient(BotClient):
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
#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
def post():
for client_name, client in bot.clients.items():
words = wm.get_portmanteaus(1)
words = wm.get_portmanteaus(3)
print()
if random.randint(0, 100) <= 100:
visibility = "public"
else:
visibility = "unlisted"
dt = next_dt()
if not TEST:
client.api.status_post("\n".join(words), visibility = visibility)
dt = next_dt()
print("Scheduling at", dt)
print("Scheduling at", dt)
if TEST:
scheduler.enter(1, 1, post)
else:
@ -196,9 +218,9 @@ bot.start()
print("Running")
dt = next_dt()
print("Scheduling at", dt)
if TEST:
scheduler.enter(1, 1, post)
else:
print("Scheduling at", dt)
scheduler.enterabs(dt.timestamp(), 1, post)
scheduler.run()

@ -1,439 +1,394 @@
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
Bat=man
Ba=t=man
Bat=m=an
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
4chan
4channer
acquihire
ActivityPub
amazon
angst
animal
anime
animu
Anon
antifa
Apple
Asperger
aspie
awkward
baka
Baldur
banana
Barbie
based
basic
Batman
birb
bisexual
bitch
Bitcoin
blåhaj
blaseball
blaze
bloatware
blockchain
blogger
boner
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
brain=l=et
boomer
boot
bootstrap
booty
booze
Bowser
brain
brainlet
browser
bruh
bull=shit
butt=load
butt=crack
butt=cr=ack
bullshit
bum
bummer
buttcrack
buttload
Buzzfeed
cancer
cat
cat=girl
cell=phone
cell=pho=ne
catgirl
cellphone
chad
ch=ad
ch=at=room
chatroom
cheem
ch=eem
ch=eems
Chew=bac=ca
chi=bi
ch=i=bi
cheems
Chewbacca
chibi
chick
chill
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
chonker
choomer
clickbait
cocaine
cock
cockblock
computer
conservative
cookie
cool
coomer
crap
creeper
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
crush
crypto
cuck
cucked
cunt
cursed
cyber
cybersex
cyberspace
dad
daddy
dank
darkweb
Debian
Democrat
derp
derpina
desu
dildo
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
doh
Doku
Dolan
dong
dope
dork
douchebag
download
downvote
Dropbox
duh
dumb
dumbphone
dump
eBay
ecchi
email
emoji
emoticon
enby
enderman
endermen
epic
eurofag
evil
Facebook
facepalm
faceplant
fag
faggottry
fanboi
fanboy
fanfic
fanfiction
fangirl
fappable
fapworthy
fart
f=art
fa=rt
fed=i
fe=di
fed=i=verse
fe=di=verse
free=mi=um
fedi
fediverse
fedora
Fedora
fire
fi=red
fi=r=ed
Fire=fox
Fi=re=fox
fuck=ton
fu=ck=ton
fired
Firefox
flame
flamewar
freemium
fuck
fucker
fuckton
futa
fu=ta
futur=ama
futur=a=ma
fu=tur=a=ma
futurama
game
gamer
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
gaydar
gaymer
genderfluid
gigachad
Giphy
goatse
GoFundMe
Google
goomba
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
griefer
groove
guru
hacker
hacktivism
hacktivist
halfass
hangover
hangry
Harambe
harem
hashtag
headdesk
healthcare
hellthread
hentai
herp
hipster
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
hoodie
horny
hung
husbando
hyperlink
hypertext
illegal
incel
Internet
Intertubes
Interwebs
iPhone
Ironman
jam
JavaScript
jerk
jiggle
kalm
Kickstarter
Kirby
Knuckles
Kraftwerk
lame
lamer
laptop
legend
lesbian
liberal
Link
Li=nk
L=ink
Linked=In
Li=nked=In
live=st=ream
live=stream
live=stream=ing
LinkedIn
livestream
login
Loki
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
love
Luigi
lulz
lurk
lurker
mafia
malware
mama
manga
manscape
Mario
Mastodon
masturbate
Megaman
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
metal
Microsoft
millennial
Minecraft
mista
modem
moe
mo=e
m=oe
ne=ko
mother
Murican
mutual
Nazi
neko
nerd
ne=w=fag
non=bin=ary
no=n=bi=nary
newfag
nightcore
Nintendo
nonbinary
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
nord
normalfag
normie
Nutella
Nyancat
Odin
oldfag
oniisan
OnlyFans
oppai
otaku
ozone
panik
pedo
Pedobear
Pepe
photo
photobomb
Pikachu
pirate
Pixelfed
PlayStation
Pleroma
plugin
Pokémon
porn
po=t=at
po=tat
po=t=et
po=tet
psy=op
p=sy=op
pus=sy
pu=s=sy
PornHub
pornography
post
potat
potet
pregnant
protecc
pspsps
psyop
pussy
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
rageface
Reddit
redditor
RedHat
reboot
ree
reee
reeee
repost
Republican
retweet
rickroll
Robocop
sage
sapphic
selfie
senpai
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
shit
shitcoin
shitfaced
shitpost
shitton
shroom
sick
sista
Slenderman
Slendermen
smartphone
smol
smug
smut
Snapchat
Snowden
software
Sonic
soyboy
spam
sp=am
sperg
Spi=der=man
Sp=i=der=man
Spi=der=m=an
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
Spiderman
Spongebob
Spotify
squad
Squidward
startup
steampunk
stonk
stonks
subtweet
swole
swo=le
ten=tac=le
te=n=tac=le
Tes=la
Te=s=la
Tind=er
Tin=der
tentacle
Tesla
thicc
thic=c
totes
to=tes
to=t=es
Thor
thread
tiger
Tiktok
Tinder
tlap
Tor
T=or
totes
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
transsex
transsexual
trap
trending
trollface
trolltard
tsundere
Twitch
Uber
Ubuntu
unfappable
Unix
Valhalla
vegan
viral
virgin
virus
volcel
waifu
Waluigi
wang
wangst
wank
wa=nk
wan=ker
wa=n=ker
wa=nk=er
wanker
wannabe
wasted
webcomic
webshop
website
weeaboo
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
weed
WhatsApp
Wikipedia
Windows
WordPress
Xbox
yandere
Yoda
Yoshi
YouTube
YouTuber
Zelda
zoomer

Loading…
Cancel
Save