def test_parent__submission(self): comment = Comment(self.reddit, "cklfmye") with self.recorder.use_cassette("TestComment.test_parent__submission"): parent = comment.parent() assert comment in parent.comments assert isinstance(parent, Submission) assert parent.fullname == comment.parent_id
def test_parent__submission(self): comment = Comment(self.reddit, 'cklfmye') with self.recorder.use_cassette('TestComment.test_parent__submission'): parent = comment.parent() assert comment in parent.comments assert isinstance(parent, Submission) assert parent.fullname == comment.parent_id
def on_comment(comment: models.Comment): try: parent = comment.parent() if type(parent) is models.Comment: # Did an uninfected person reply to an infected persons comment? if parent.author_flair_text and "INFECTED" in parent.author_flair_text and ( (comment.author_flair_text and "INFECTED" not in comment.author_flair_text) or not comment.author_flair_text): # infection! infect(comment, parent) else: # if type(parent) is models.Submission # Did an uninfected person reply to an infected persons submission? Roll dice for a 1 in 100 if parent.author_flair_text and "INFECTED" in parent.author_flair_text and ( (comment.author_flair_text and "INFECTED" not in comment.author_flair_text) or not comment.author_flair_text) and random.randint( 1, 100) == 69: infect(comment, parent) # if _debug: # print(comment) # TSV Format: Timestamp, Commentor Name, Commentor Comment ID, Commented on User, Commented on Item ID, Item Type, Commented on ?Infected? User _commentlog.write("{}\tu/{}\t{}\tu/{}\t{}\t{}\t{}\n".format( str(datetime.datetime.now()), comment.author.name, comment.id, "deleted" if not parent.author else parent.author.name, parent.id, "C" if type(parent) is models.Comment else "S", "I" if (parent.author_flair_text and "INFECTED" in parent.author_flair_text) else "N")) except Exception as ex: logger.info("ERROR IN ON_COMMENT") logger.info(str(ex)) pass
def test_parent__comment(self): comment = Comment(self.reddit, "cklhv0f") with self.recorder.use_cassette("TestComment.test_parent__comment"): parent = comment.parent() parent.refresh() assert comment in parent.replies assert isinstance(parent, Comment) assert parent.fullname == comment.parent_id
def test_parent__comment(self): comment = Comment(self.reddit, 'cklhv0f') with self.recorder.use_cassette('TestComment.test_parent__comment'): parent = comment.parent() parent.refresh() assert comment in parent.replies assert isinstance(parent, Comment) assert parent.fullname == comment.parent_id
def should_respond(self, comment: Comment) -> bool: if not isinstance(comment.parent(), Submission): return False if not re.findall(r'([A-Z]{1,2}[0-9]{4}\-?[A-Za-z0-9]*\:\ *\w+)', comment.body or ""): return False return comment.submission.link_flair_text in [ submission_types.EK_STEMMING, submission_types.TK_STEMMING, submission_types.EK_TK_STEMMING ]
def remove_post(reddit: Reddit, comment: Comment, message: str, mod_note: str, note_message: str, strike: bool): comment.parent().edit(message + f'\n\n{config["suffix"]}') comment.submission.mod.remove(spam=False, mod_note=mod_note) c.execute('DELETE FROM pendingposts WHERE submission_id=?', (comment.submission.id, )) conn.commit() # Time to update the usernotes... if strike: print("Updating usernotes...") usernotespage = reddit.subreddit(config['subreddit']).wiki["usernotes"] usernotescontent = json.loads(usernotespage.content_md) usernotes = decode_blob(usernotescontent['blob']) username = comment.submission.author.name mod_number = usernotescontent['constants']['users'].index( 'Enslaved_Horny_AI') if username in usernotes: usernotes[username]['ns'].append({ 'l': f'l,{comment.submission.id}', 'm': mod_number, 'n': note_message, 't': int(time.time()), 'w': 0 }) else: usernotes[username] = { 'ns': [{ 'l': f'l,{comment.submission.id}', 'm': mod_number, 'n': note_message, 't': int(time.time()), 'w': 0 }] } usernotescontent["blob"] = encode_blob(usernotes) usernotespage.edit( content=json.dumps(usernotescontent, separators=(',', ':'))) print('User notes updated.')
def test_parent__chain(self): comment = Comment(self.reddit, "dkk4qjd") counter = 0 with self.recorder.use_cassette("TestComment.test_parent__chain"): comment.refresh() parent = comment.parent() while parent != comment.submission: if counter % 9 == 0: parent.refresh() counter += 1 parent = parent.parent()
def test_parent__chain(self): comment = Comment(self.reddit, 'dkk4qjd') counter = 0 with self.recorder.use_cassette('TestComment.test_parent__chain'): comment.refresh() parent = comment.parent() while parent != comment.submission: if counter % 9 == 0: parent.refresh() counter += 1 parent = parent.parent()
def parse_comment(comment: Comment) -> list(): row = [] row.append(comment.fullname) # Comment Id row.append(comment.author.name) # Author Username row.append(datetime.fromtimestamp(comment.created)) # Timestamp row.append(comment.subreddit.display_name) # Subreddit Name row.append(str(comment.parent().author)) # User author replied to # Sentiment Analysis sentiment = TextBlob(comment.body).sentiment row.append(sentiment.polarity) # Comment Polarity (Positive / Negative) row.append(sentiment.subjectivity) # Comment Subjectivity # Thread length: how many other replies were made to same comment? if isinstance(comment.parent(), Comment): if comment.parent().replies is not None: row.append(len(comment.parent().replies)) elif isinstance(comment.parent(), Submission): row.append(len(comment.parent().comments)) else: row.append(0) # Something unexpected happened # Debugging: print(f"Thread Length: {row[-1]}") return row
def match_commands(comment: Comment, accents=True) -> set: """ Return a set with tuples of the form ((reward, reward_images), recipient), one for each match in the body of the provided comment. """ if accents: content = comment.body else: content = remove_accents(comment.body) return {(commands[m.group(1).lower()], m.group(2) or comment.parent().author.name) for m in PATTERN.finditer(content)}
async def process_comment(comment: Comment, reddit: Reddit): # Mod override - if the user is a moderator, has "override" in his comment, and if not comment.is_root and comment.author.name in comment.subreddit.moderator() and "override" in comment.body: print("Moderator override activated.") # get rid of any override leftovers body = comment.body.replace('override', '').strip() url = extract_url(body) if not url: # no URL present, so we execute the british comment.reply("That doesn't seem to be a valid URL. Try again?" f'\n\n{config["suffix"]}') return if 'nhentai.net' in url: nums_regex = re.compile(r"https://nhentai\.net/g/(\d+)/") nums_match = nums_regex.match(url) nums = nums_match.group(1) try: magazine, market, data = await nhentai_fetcher.check_link(url) except Exception: print("Invalid page.") comment.reply("That doesn't seem to be a valid nhentai page. Try again?" f'\n\n{config["suffix"]}') return parodies = '' if len(data[3]) == 0 else f"**Parodies:** \n{', '.join(data[3])}\n\n" characters = '' if len(data[4]) == 0 else f"**Characters:** \n{', '.join(data[4])}\n\n" tags = '**Tags:** \nNone\n\n' if len(data[2]) == 0 else f"**Tags:** \n{', '.join(data[2])}\n\n" god_list = "" try: has_entry, entry = await wholesomelist_fetcher.process_nums(nums) if has_entry: print(entry) god_list = f"\\-\\-\\-\n\n[Wholesome Hentai God List #{entry['id']}](https://wholesomelist.com/list/{entry['uuid']}) \n" \ '\n' + (# f'**Tier: {entry["tier"]}**\n\n' + ( '' if (entry['note'] == 'None') else f'**Note:** {entry["note"]} \n') + \ f'**Tags:** ' + ('None' if len(entry["tags"]) == 0 else entry['tags']) + "\n\n" except Exception: god_list = "" comment.parent().edit( f"The source OP provided: \n> <{url}>\n\nAlt link: [cubari.moe](https://cubari.moe/read/nhentai/{nums}/1/1/)\n\n" f'**{markdown_escape(data[0])}** \nby {data[1] if data[1] else "Unknown"}\n\n{data[5]} pages\n\n{parodies}{characters}{tags}{god_list}' f'{config["suffix"]}' ) else: imgur = re.compile(r"https://imgur\.com/a/(.{5,7})/") imgur_match = imgur.match(url) if imgur_match: comment.parent().edit( f"The source OP provided: \n> <{url}>\n\nAlt link: [cubari.moe](https://cubari.moe/read/imgur/{imgur_match.group(1)}/1/1/)\n\n" f'{config["suffix"]}' ) else: comment.parent().edit( f"The source OP provided: \n> <{url}>\n\n" f'{config["suffix"]}' ) # The post is good. print('Updating database and cleaning up...') c.execute('DELETE FROM posts WHERE source=?', (url,)) approve_post(reddit, comment, url) # Reapprove the post if it was removed if comment.submission.removed: print("This post was removed. Reapproving...") comment.submission.mod.approve() else: print("This post was not removed. Ignoring...") # If this is the reply to a sauce request, handle it elif not comment.is_root and c.execute('SELECT * FROM pendingposts WHERE submission_id=?', (comment.submission.id,)).fetchone(): c.execute('SELECT * FROM pendingposts WHERE submission_id=?', (comment.submission.id,)) submission_id, author, comment_id = c.fetchone() # Normal handling if comment_id == comment.parent_id[3:] and author == comment.author.name: # It's a reply to a sauce request. print("Sauce reply found.") print(comment.body) # If there is no applicable source... if comment.body.lower() == 'none': comment.parent().edit( 'OP has indicated that there is no applicable source.' f'\n\n{config["suffix"]}' ) c.execute('DELETE FROM pendingposts WHERE submission_id=?', (comment.submission.id,)) conn.commit() comment.submission.mod.approve() return url = extract_url(comment.body) if not url: # no URL present, so we execute the british comment.reply("That doesn't seem to be a valid URL. Try again?" f'\n\n{config["suffix"]}') return # Handle any licensed sites here for site in licensed_sites: if site in url: print("It's a licensed site.") remove_post(reddit, comment, 'The link you provided links to a site that solely rips licensed content. As such, it breaks rule 4.\n\n' 'Please read our [guide on how to spot licensed doujins](https://www.reddit.com/r/wholesomehentai/wiki/licensedguide)' ' to avoid making this mistake in the future.', 'Licensed link', 'Rule 4 - Linked to hentai.cafe/hentainexus/hentaimimi', True ) return # Check if the post is a repost or not c.execute('SELECT * FROM commonreposts WHERE source=?', (url,)) is_common_repost = c.fetchone() if is_common_repost: # if this tuple even exists, it's uh oh stinky # It's a really common repost. Kill it. print('Common repost detected!') remove_post(reddit, comment, 'The link you provided is a **very common repost** on this subreddit.\n\n' 'Please read our [list of common reposts](https://www.reddit.com/r/wholesomehentai/wiki/posts), to avoid ' 'posting common reposts in the future.', 'Really common repost.', 'Rule 10 - Common Repost', True ) return # Check if the post is a repost that isn't that common c.execute('SELECT * FROM posts WHERE source=?', (url,)) post = c.fetchone() if post: print('Post found in repost database.') # It's a repost. # Check how recently it was reposted (604800 seconds/week) if comment.submission.created_utc - post[2] > (12 * 604800): # It's already been enough since this was last posted. # Delete the entry, and we'll add it back later. (With the current timestamp) c.execute('DELETE FROM posts WHERE source=?', (url,)) conn.commit() print('It\'s been long enough since this was last posted!') else: old_submission = reddit.submission(url=f'https://reddit.com{post[0]}') if (not old_submission.removed) and ((not (old_submission and old_submission.author)) or (old_submission.author.name == author)): # It's the same person. It's fine. print('OP is the same person. Ignoring...') c.execute('DELETE FROM posts WHERE source=?', (url,)) conn.commit() else: if post[3] != 0: print('It\'s a recently removed repost. Removing...') remove_post(reddit, comment, f'The link you provided has already been [posted and removed](https://reddit.com{post[0]}) recently.\n\n' 'Please check the previous post to see why it was removed. If you believe that the previous post was wrongly removed ' f'or some other exception has occurred, please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}).\n\n' 'Otherwise, please make sure to [read the rules](https://reddit.com/r/wholesomehentai/wiki/rules) in the future.', 'Removed repost.', 'Reposting a removed post', True ) else: # It's not been long enough since the last post. Link them to the last post and delete the entry. print('It\'s a recent repost. Removing...') remove_post(reddit, comment, f'The link you provided has [already been posted](https://reddit.com{post[0]}) recently.\n\n' 'Please [check here](https://reddit.com/r/wholesomehentai/wiki/posts) before posting to avoid posting reposts in the future.', 'Repost.', 'Rule 10 - Repost', True ) return if 'nhentai.net' in url: # hoo boy print('nhentai URL detected, parsing info / magazines') if "nhentai.net/g/" not in url: comment.reply(f'That\'s not a valid nhentai page!\n\n{config["suffix"]}') return nums_regex = re.compile(r"https://nhentai\.net/g/(\d+)/") nums_match = nums_regex.match(url) nums = nums_match.group(1) for attempt in range(3): try: magazine, market, data = await nhentai_fetcher.check_link(url) break except Exception: if attempt == 2: print("Invalid page.") print(url) comment.reply("Either that isn't a valid nhentai page, or my connection to nhentai has a problem currently. Try again?" f'\n\n{config["suffix"]}') return else: await asyncio.sleep(1) if magazine: # It's licensed! print("Licensed magazine detected.") remove_post(reddit, comment, f'The provided source is licensed! It appears in the licensed magazine issue `{magazine}`.\n\n' f'Please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}) if you think this is a mistake. Otherwise, please read the ' '[guide on how to spot licensed doujins.](https://www.reddit.com/r/wholesomehentai/wiki/licensedguide)', f'Licensed, appears in magazine {magazine}', f'Rule 4 - Licensed (appears in {magazine})', True ) return if market: # It literally has 2d-market.com in the title. print("2d-market in title.") remove_post(reddit, comment, f'The provided source is licensed! It has `2d-market.com` in the title.\n\n' f'Please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}) if you think this is a mistake. Otherwise, please read the ' '[guide on how to spot licensed doujins.](https://www.reddit.com/r/wholesomehentai/wiki/licensedguide)', f'Licensed, has 2d-market.com in title', f'Rule 4 - Licensed (2d-market.com in title)', True ) return if "english" not in data[6]: print("The language of this doujin does not seem to be English.") remove_post(reddit, comment, 'The provided source does not seem to be in English.\n\n' 'This subreddit only allows English submissions, as most people cannot understand other languages.\n\n' f'If you believe this was a mistake, you can [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}).', 'Not English', 'Rule 2 - Non-English Source', False ) return detected_artists = [] for artist in licensed_artists: if artist in data[1].lower(): detected_artists.append(artist) if len(detected_artists) != 0: # Oh no, there's an illegal artist! print("Illegal artists detected: " + ', '.join(detected_artists)) remove_post(reddit, comment, f'The provided source has the following disallowed artists:\n```\n{", ".join(detected_artists)}\n```\n' 'These artists are banned because their works are always or almost always licensed. ' f'Please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}) if you think this is ' 'an unlicensed exception. ' 'Otherwise, make sure you understand Rule 4.', f'Has the licensed artist(s): {", ".join(detected_artists)}', f'Rule 4 - Has the artists {", ".join(detected_artists)}', True ) return detected_tags = [] for tag in data[2]: if tag in unwholesome_tags: detected_tags.append(tag) if len(detected_tags) != 0: # Oh no, there's an illegal tag! print("Illegal tags detected: " + ', '.join(detected_tags)) remove_post(reddit, comment, f'The provided source has the following disallowed tags:\n```\n{", ".join(detected_tags)}\n```\n' 'These tags are banned because they are either almost never wholesome or almost always licensed. ' f'Please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}) if you think this is either ' 'a mistagged doujin or a wholesome/unlicensed exception. ' 'Otherwise, make sure you understand Rules 1, 4, and 5.', f'Has the illegal tag(s): {", ".join(detected_tags)}', f'Rule 1/4/5 - Has the tags {", ".join(detected_tags)}', True ) return detected_characters = [] for character in data[4]: if character in underage_characters: cur_list = underage_characters[character] parodies = data[3] for parody in parodies: for item in cur_list: series_list = item['series'] for series in series_list: if series.lower().strip() == parody: detected_characters.append([character, series, item['age'], item['note']]) if len(detected_characters) != 0: # Oh no, there's an illegal character! chars_list = [] for character in detected_characters: chars_list.append(character[0]) chars_str = ', '.join(chars_list) print("Illegal characters detected: " + chars_str) remove_post(reddit, comment, f'The provided source has the following disallowed characters:\n\n{generate_character_string(detected_characters)}\n' 'These characters are banned because they are underage.\n\n' f'If you believe one of these characters is actually 18+ (because either the Note exception applies, or the mod team made a mistake), please [contact the mods](https://www.reddit.com/message/compose?to=/r/{config["subreddit"]}). ' 'Otherwise, make sure you understand Rule 1, and have checked our [spreadsheet of underage characters.](https://docs.google.com/spreadsheets/d/1rnTIzml80kQJPlNCQzluuKHK8Dzejk2Xg7J4YYN4FaM/)', f'Has the underage char(s): {chars_str}', f'Rule 1 - Has the chars {chars_str}', True ) return parodies = '' if len(data[3]) == 0 else f"**Parodies:** \n{', '.join(data[3])}\n\n" characters = '' if len(data[4]) == 0 else f"**Characters:** \n{', '.join(data[4])}\n\n" tags = '**Tags:** \nNone\n\n' if len(data[2]) == 0 else f"**Tags:** \n{', '.join(data[2])}\n\n" god_list = "" try: has_entry, entry = await wholesomelist_fetcher.process_nums(nums) if has_entry: print(entry) god_list = f"\\-\\-\\-\n\n[Wholesome Hentai God List #{entry['id']}](https://wholesomelist.com/list/{entry['uuid']}) \n" \ '\n' + ( # f'**Tier: {entry["tier"]}**\n\n' + ( '' if (entry['note'] == 'None') else f'**Note:** {entry["note"]} \n') + \ f'**Tags:** ' + ('None' if len(entry["tags"]) == 0 else entry['tags']) + "\n\n" except Exception: god_list = "" comment.parent().edit( f"The source OP provided: \n> <{url}>\n\nAlt link: [cubari.moe](https://cubari.moe/read/nhentai/{nums}/1/1/)\n\n" f'**{markdown_escape(data[0])}** \nby {data[1] if data[1] else "Unknown"}\n\n{data[5]} pages\n\n{parodies}{characters}{tags}{god_list}' f'{config["suffix"]}' ) else: imgur = re.compile(r"https://imgur\.com/a/(.{5,7})/") imgur_match = imgur.match(url) if imgur_match: comment.parent().edit( f"The source OP provided: \n> <{url}>\n\nAlt link: [cubari.moe](https://cubari.moe/read/imgur/{imgur_match.group(1)}/1/1/)\n\n" f'{config["suffix"]}' ) else: comment.parent().edit( f"The source OP provided: \n> <{url}>\n\n" f'{config["suffix"]}' ) # If we made it here, the post is good. Clean up any trackers and add a post entry to the database. print('Updating database and cleaning up...') approve_post(reddit, comment, url)