users: add profanity filter to censor our gosh darned potty mouthes

remotes/1693176582716663532/tmp_refs/heads/watchparty
justcool393 2022-11-03 17:59:18 -05:00
parent 6b068de522
commit 339d5fe8f1
6 changed files with 90 additions and 57 deletions

View File

@ -79,6 +79,7 @@ class User(Base):
hidevotedon = Column(Boolean, default=False)
highlightcomments = Column(Boolean, default=True)
slurreplacer = Column(Boolean, default=True)
profanityreplacer = Column(Boolean, default=True)
flairchanged = Column(Integer)
newtab = Column(Boolean, default=False)
newtabexternal = Column(Boolean, default=True)

View File

@ -102,6 +102,36 @@ SLURS = {
"daisy destruction": "Cars 2",
}
PROFANITIES = {
'motherfucker': ['motherlover'],
'fuck': ['frick', 'fudge', 'freak', 'f-word', 'f-bomb', 'cuss'],
'asshole': ['butthole', 'ahole'],
'arsehole': ['butthole', 'ahole'],
'(ass)\W': ['butt', 'backside', 'rear end', 'bum', 'tochus'],
'shit': ['poop', 'poop', 'crap', 'puckey'],
'lmao': ['lmbo'],
'damn': ['dang', 'darn'],
'bastard': ['fatherless child'],
'piss': ['pee'],
'bitch': ['b-word', 'mean lady'],
'dick': ['weiner'],
'cock': ['weiner'],
'penis': ['peepee'],
'pussy': ['girl weiner'],
'vagina': ['girl peepee'],
'cunt': ['rude lady'],
'hell': ['heck', 'h-e-double-hockey-sticks'],
'sexual intercourse': ['sexual congress'],
'(sex)\W': ['intercourse'],
'(arse)\W': ['butt', 'backside', 'rear end', 'bum', 'tochus'],
'god': ['gosh'],
'wanker': ['rude masturbator'],
'twat': ['girl weiner'],
'cum': ['c*m'],
'orgasm': ['sexual climax'],
'toilet': ['potty'],
}
if SITE_NAME == 'rDrama':
RDRAMA_SLURS = {
"retarded": "r-slurred",
@ -134,7 +164,8 @@ if SITE_NAME == 'rDrama':
}
SLURS.update(RDRAMA_SLURS)
single_words = "|".join([slur.lower() for slur in SLURS.keys()])
slur_single_words = "|".join([slur.lower() for slur in SLURS.keys()])
profanity_single_words = "|".join([profanity.lower() for profanity in PROFANITIES.keys()])
LONGPOST_REPLIES = ('Wow, you must be a JP fan.', 'This is one of the worst posts I have EVER seen. Delete it.', "No, don't reply like this, please do another wall of unhinged rant please.", '<h1>😴😴😴</h1>', "Ma'am we've been over this before. You need to stop.", "I've known more coherent downies.", "Your pulitzer's in the mail", "That's great and all, but I asked for my burger without cheese.", 'That degree finally paying off', "That's nice sweaty. Why don't you have a seat in the time out corner with Pizzashill until you calm down, then you can have your Capri Sun.", "All them words won't bring your pa back.", "You had a chance to not be completely worthless, but it looks like you threw it away. At least you're consistent.", 'Some people are able to display their intelligence by going on at length on a subject and never actually saying anything. This ability is most common in trades such as politics, public relations, and law. You have impressed me by being able to best them all, while still coming off as an absolute idiot.', "You can type 10,000 characters and you decided that these were the one's that you wanted.", 'Have you owned the libs yet?', "I don't know what you said, because I've seen another human naked.", 'Impressive. Normally people with such severe developmental disabilities struggle to write much more than a sentence or two. He really has exceded our expectations for the writing portion. Sadly the coherency of his writing, along with his abilities in the social skills and reading portions, are far behind his peers with similar disabilities.', "This is a really long way of saying you don't fuck.", "Sorry ma'am, looks like his delusions have gotten worse. We'll have to admit him.", 'If only you could put that energy into your relationships', 'Posts like this is why I do Heroine.', 'still unemployed then?', 'K', 'look im gunna have 2 ask u 2 keep ur giant dumps in the toilet not in my replys 😷😷😷', "Mommy is soooo proud of you, sweaty. Let's put this sperg out up on the fridge with all your other failures.", "Good job bobby, here's a star", "That was a mistake. You're about to find out the hard way why.", f'You sat down and wrote all this shit. You could have done so many other things with your life. What happened to your life that made you decide writing novels of bullshit here was the best option?', "I don't have enough spoons to read this shit", "All those words won't bring daddy back.", 'OUT!', "Damn, you're really mad over this, but thanks for the effort you put into typing that all out! Sadly I won't read it all.", "Jesse what the fuck are you talking about??", "▼you're fucking bananas if you think I'm reading all that, take my downvote and shut up idiot", "Are you feeling okay bud?", '<img loading="lazy" data-bs-toggle="tooltip" alt=":#marseywoah:" src="/e/marseywoah.webp" b title=":#marseywoah:">', 'At no point in your rambling, incoherent post were you even close to anything that could be considered a rational thought. Everyone on this site is now dumber for having read it. May God have mercy on your soul.')

View File

@ -1,4 +1,7 @@
import random
import re
from files.classes.user import User
from typing import List, Literal, Optional, Union
from .const import *
from random import choice, choices
@ -57,8 +60,11 @@ email_regex = re.compile(EMAIL_REGEX_PATTERN, flags=re.A)
utm_regex = re.compile('utm_[0-z]+=[0-z_]+&', flags=re.A)
utm_regex2 = re.compile('[?&]utm_[0-z]+=[0-z_]+', flags=re.A)
slur_regex = re.compile(f"<[^>]*>|{single_words}", flags=re.I|re.A)
slur_regex_upper = re.compile(f"<[^>]*>|{single_words.upper()}", flags=re.A)
slur_regex = re.compile(f"<[^>]*>|{slur_single_words}", flags=re.I|re.A)
slur_regex_upper = re.compile(f"<[^>]*>|{slur_single_words.upper()}", flags=re.A)
profanity_regex = re.compile(f"<[^>]*>|{profanity_single_words}", flags=re.I|re.A)
profanity_regex_upper = re.compile(f"<[^>]*>|{profanity_single_words.upper()}", flags=re.A)
torture_regex = re.compile('(^|\s)(i|me) ', flags=re.I|re.A)
torture_regex2 = re.compile("(^|\s)i'm ", flags=re.I|re.A)
torture_regex_exclude = re.compile('^\s*>', flags=re.A)
@ -72,17 +78,15 @@ video_sub_regex = re.compile(f'(<p>[^<]*)(https:\/\/([a-z0-9-]+\.)*({hosts})\/[\
audio_regex_extensions = '|'.join(AUDIO_FORMATS)
audio_sub_regex = re.compile(f'(<p>[^<]*)(https:\/\/([a-z0-9-]+\.)*({hosts})\/[\w:~,()\-.#&\/=?@%;+]*?\.({audio_regex_extensions}))', flags=re.A)
image_regex = re.compile("(^|\s)(https:\/\/[\w\-.#&/=\?@%;+,:]{5,250}(\.png|\.jpg|\.jpeg|\.gif|\.webp)(\?[\w\-.#&/=\?@%;+,:]*)?)($|\s)", flags=re.I|re.A)
image_regex_extensions = '|'.join(IMAGE_FORMATS)
imgur_regex = re.compile(f'(https:\/\/i\.imgur\.com\/[a-z0-9]+)\.({image_regex_extensions})', flags=re.I|re.A)
giphy_regex = re.compile('(https:\/\/media\.giphy\.com\/media\/[a-z0-9]+\/giphy)\.gif', flags=re.I|re.A)
youtube_regex = re.compile('(<p>[^<]*)(https:\/\/youtube\.com\/watch\?v\=([a-z0-9-_]{5,20})[\w\-.#&/=\?@%+]*)', flags=re.I|re.A)
yt_id_regex = re.compile('[a-z0-9-_]{5,20}', flags=re.I|re.A)
image_regex = re.compile("(^|\s)(https:\/\/[\w\-.#&/=\?@%;+,:]{5,250}(\.png|\.jpg|\.jpeg|\.gif|\.webp)(\?[\w\-.#&/=\?@%;+,:]*)?)($|\s)", flags=re.I|re.A)
link_fix_regex = re.compile("(\[.*?\]\()(?!http|/)(.*?\))", flags=re.A)
css_url_regex = re.compile('url\(\s*[\'"]?(.*?)[\'"]?\s*\)', flags=re.I|re.A)
@ -96,7 +100,6 @@ greentext_regex = re.compile("(\n|^)>([^ >][^\n]*)", flags=re.A)
ascii_only_regex = re.compile("[ -~]+", flags=re.A)
reddit_to_vreddit_regex = re.compile('(^|>|")https:\/\/old.reddit.com\/(r|u)\/', flags=re.A)
reddit_domain_regex = re.compile("(^|\s|\()https?:\/\/(reddit\.com|(?:(?:[A-z]{2})(?:-[A-z]{2})" "?|beta|i|m|pay|ssl|www|new|alpha)\.reddit\.com|libredd\.it|teddit\.net)\/(r|u)\/", flags=re.A)
color_regex = re.compile("[a-z0-9]{6}", flags=re.A)
@ -113,20 +116,43 @@ pronouns_regex = re.compile("([a-z]{1,5})/[a-z]{1,5}(/[a-z]{1,5})?", flags=re.A|
knowledgebase_page_regex = re.compile("[a-zA-Z0-9_\-]+", flags=re.A)
def sub_matcher(match, upper=False):
def sub_matcher(match, upper=False, replace_with:Union[dict[str, str], dict[str, List[str]]]=SLURS):
if match.group(0).startswith('<'):
return match.group(0)
else:
repl = SLURS[match.group(0).lower()]
repl = replace_with[match.group(0).lower()]
if not isinstance(repl, str):
repl = random.choice(repl)
return repl if not upper or "<img" in repl else repl.upper()
def sub_matcher_upper(match):
return sub_matcher(match, upper=True)
def sub_matcher_upper(match, replace_with:Union[dict[str, str], dict[str, List[str]]]=SLURS):
return sub_matcher(match, upper=True, replace_with=replace_with)
def censor_slurs(body, logged_user):
# TODO: make censoring a bit better
def sub_matcher_slurs(match, upper=False):
return sub_matcher(match, upper, replace_with=SLURS)
def sub_matcher_slurs_upper(match):
return sub_matcher_slurs(match, upper=True)
def sub_matcher_profanities(match, upper=False):
return sub_matcher(match, upper, replace_with=PROFANITIES)
def sub_matcher_profanities_upper(match):
return sub_matcher_profanities(match, upper=True)
def censor_slurs(body:Optional[str], logged_user:Union[Optional[User], Literal['chat']]):
if not body: return ""
def replace_re(body:str, regex:re.Pattern, regex_upper:re.Pattern, sub_func, sub_func_upper):
body = regex_upper.sub(sub_func_upper, body)
return regex.sub(sub_func, body)
if not logged_user or logged_user == 'chat' or logged_user.slurreplacer:
body = slur_regex_upper.sub(sub_matcher_upper, body)
body = slur_regex.sub(sub_matcher, body)
body = replace_re(body, slur_regex, slur_regex_upper, sub_matcher_slurs, sub_matcher_slurs_upper)
if not logged_user or logged_user == 'chat' or logged_user.profanityreplacer:
body = replace_re(body, profanity_regex, profanity_regex_upper, sub_matcher_profanities, sub_matcher_profanities_upper)
return body
def torture_ap(body, username):

View File

@ -47,6 +47,10 @@ def settings_profile_post(v):
updated = True
v.slurreplacer = request.values.get("slurreplacer") == 'true'
elif request.values.get("profanityreplacer", v.profanityreplacer) != v.profanityreplacer:
updated = True
v.profanityreplacer = request.values.get("profanityreplacer") == 'true'
elif request.values.get("poor", v.poor) != v.poor:
updated = True
v.poor = request.values.get("poor") == 'true'

View File

@ -273,91 +273,72 @@
<h5>Content Filters</h5>
<div class="settings-section rounded">
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="sigs_disabled">Disable signatures</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="sigs_disabled" name="sigs_disabled"{% if v.sigs_disabled %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?sigs_disabled='+document.getElementById('sigs_disabled').checked);">
<label class="custom-control-label" for="sigs_disabled"></label>
</div>
<span class="text-small text-muted">Hide user signatures.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="slurreplacer">Disable +18 Warnings</label>
<label for="over18">Disable +18 Warnings</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="over18" name="over18"{% if v.over_18 %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?over18='+document.getElementById('over18').checked);">
<label class="custom-control-label" for="over18"></label>
</div>
<span class="text-small text-muted">Enable if you would like to not get a warning before viewing +18 content.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="slurreplacer">Slur Replacer</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="slurreplacer" name="slurreplacer"{% if v.slurreplacer %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?slurreplacer='+document.getElementById('slurreplacer').checked);">
<label class="custom-control-label" for="slurreplacer"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically replace slurs.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="profanityreplacer">Profanity Replacer</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="profanityreplacer" name="profanityreplacer"{% if v.slurreplacer %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?profanityreplacer='+document.getElementById('profanityreplacer').checked);">
<label class="custom-control-label" for="profanityreplacer"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically replace profanities.</span>
</div>
</div>
<div class="d-lg-flex border-bottom">
<div class="title w-lg-25">
<label for="hidevotedon">Hide Posts Voted On</label>
</div>
<div class="body w-lg-100">
<div class="custom-control custom-switch">
<input autocomplete="off" type="checkbox" class="custom-control-input" id="hidevotedon" name="hidevotedon"{% if v.hidevotedon %} checked{% endif %} onchange="postToastSwitch(this,'/settings/profile?hidevotedon='+document.getElementById('hidevotedon').checked);">
<label class="custom-control-label" for="hidevotedon"></label>
</div>
<span class="text-small text-muted">Enable if you would like to automatically hide posts you have voted on from your frontpage.</span>
</div>
</div>
<div class="d-lg-flex">
<div class="title w-lg-25">
<label for="filters-text">Custom Filters</label>
</div>
@ -374,23 +355,12 @@
<input autocomplete="off" class="btn btn-primary ml-auto" id="bioSave" type="submit" onclick="disable(this)" value="Save Changes">
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -954,6 +954,7 @@ CREATE TABLE public.users (
theme character varying(15) NOT NULL,
song character varying(50),
slurreplacer boolean DEFAULT true NOT NULL,
profanityreplacer boolean DEFAULT true NOT NULL,
shadowbanned character varying(25),
newtabexternal boolean DEFAULT true NOT NULL,
customtitleplain character varying(100),