Initial commit

master
Thor 3 years ago
commit bdc0afb800
  1. 3
      .gitmodules
  2. 19
      LICENSE
  3. 34
      config.example.toml
  4. 1
      fedbot
  5. 187175
      mhyph.txt
  6. 201
      portbot.py
  7. 432
      porthyph.txt

3
.gitmodules vendored

@ -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

187175
mhyph.txt

File diff suppressed because it is too large Load Diff

@ -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…
Cancel
Save