Example #1
0
def nudity_blur(image):
    detector = NudeDetector()
    classes = [
        'EXPOSED_ANUS', 'EXPOSED_BUTTOCKS', 'COVERED_BREAST_F',
        'EXPOSED_BREAST_F', 'EXPOSED_GENITALIA_F', 'EXPOSED_GENITALIA_M',
        'EXPOSED_BUTTOCKS', 'EXPOSED_BREAST_F', 'EXPOSED_GENITALIA_F',
        'EXPOSED_GENITALIA_M', 'EXPOSED_BREAST_M', 'COVERED_GENITALIA_F',
        'COVERED_BREAST_F'
    ]
    for i in detector.detect(image):
        if i['label'] in classes:
            #             if i['label'] in []
            x, y, w, h = i['box']
            Img = cv2.medianBlur(image[y:h, x:w], ksize=41)
            image[y:h, x:w] = Img
    return image
Example #2
0
def ImageDescribing(tSourceImage,
                    tDetector='',
                    CENSORING_LABELS=[
                        "EXPOSED_BREAST_F", "EXPOSED_GENITALIA_F",
                        "EXPOSED_GENITALIA_M"
                    ]):
    """
    tSourceImage:   Path, or BytesIO Object
    tDetector:      NudeNet.Detector. If not provided, one will be created.

    """

    if not tDetector:
        tDetector = NudeDetector()
    tDescription = tDetector.detect(tSourceImage)

    return [
        tDetail for tDetail in tDescription
        if tDetail['label'] in CENSORING_LABELS
    ]
Example #3
0
        'filename', 'file_size', 'file_attributes', 'region_count',
        'region_id', 'region_shape_attributes', 'region_attributes'
    ])  #CSV
    for f in files:
        try:
            while True:
                print("Working on " + f)
                img_C = Image.open(f).convert("RGB")
                x, y = img_C.size
                img_C = np.array(img_C)
                image = img_C[:, :, ::-1].copy()
                img_rgb = img_C[:, :, ::-1].copy()

                color = rand_color()

                detection = detector.detect(f)
                label = ['F_GENITALIA', 'M_GENITALIA']  #
                all_regions = [
                    i['box'] for i in detection if i['label'] in label
                ]  #

                if all_regions == []:
                    # skip entire detection, avoid saving
                    #os.remove(f, )    #to remove file from input
                    os.rename(f, f.replace(
                        rootdir, rejected,
                        1))  #to remove file from input to rejected
                    print('skipping image with failed nudenet detection')
                    break
                print(all_regions)  #
                interp = random.choices(
Example #4
0
from nudenet import NudeClassifier
from nudenet import NudeDetector
from tqdm import tqdm
from shutil import copyfile
# classifier = NudeClassifier('models/classifier_model')
detector = NudeDetector('models/detector_model')

# print(classifier.classify(
#     'splitted/_momoiroiro_Cute_or_sexy__😆_c4h2ar_2.jpg'))


def is_naked(features):
    naked_label = ['F_BREAST', 'F_GENITALIA', 'M_GENITALIA', 'M_BREAST']
    for feature in features:
        if feature['label'] in naked_label:
            return True

    return False


files = os.listdir('splitted')
for filename in tqdm(files):
    path = os.path.join('splitted', filename)
    out_dir = None
    if is_naked(detector.detect(path)):
        out_dir = 'naked'
    else:
        out_dir = 'not_naked'
    out_path = os.path.join(out_dir, filename)
    copyfile(path, out_path)
Example #5
0
class Detections(commands.Cog):
    def __init__(self, bot: rainbot) -> None:
        self.bot = bot
        self.spam_detection: DefaultDict[str, List[int]] = defaultdict(list)
        self.repetitive_message: DefaultDict[str,
                                             Counter] = defaultdict(Counter)
        self.INVITE_REGEX = re.compile(
            r'((http(s|):\/\/|)(discord)(\.(gg|io|me)\/|app\.com\/invite\/)([0-z]+))'
        )
        self.ENGLISH_REGEX = re.compile(
            r'(?:\(╯°□°\)╯︵ ┻━┻)|[ -~]|(?:' + UNICODE_EMOJI +
            r')|(?:\U00002018|\U00002019|\s)|[.!?\\\-\(\)]|ツ|¯|(?:┬─┬ ノ\( ゜-゜ノ\))'
        )  # U2018 and U2019 are iOS quotes

        self.nude_detector = NudeDetector()

        self.nude_image_cache: LFUCache[str, List[str]] = LFUCache(50)

        self.detections = []

        for func in self.__class__.__dict__.values():
            if isinstance(func, Detection):
                self.detections.append(func)

    @Cog.listener()
    async def on_message(self, m: MessageWrapper) -> None:
        if self.bot.dev_mode:
            if m.guild and m.guild.id != 733697261065994320:
                return
        if (self.bot.dev_mode and
            (m.guild and m.guild.id != 733697261065994320)
            ) or m.type != discord.MessageType.default:
            return

        for func in self.detections:
            await func.trigger(self, m)

    @detection('sexually_explicit', require_attachment=True)
    async def sexually_explicit(self, m: MessageWrapper) -> None:
        for i in m.attachments:
            if i.filename.endswith('.png') or i.filename.endswith(
                    '.jpg') or i.filename.endswith('.jpeg'):
                with NamedTemporaryFile(mode='wb+', delete=False) as fp:
                    async with self.bot.session.get(i.url) as resp:
                        fp.write(await resp.read())
                await self.bot.loop.run_in_executor(
                    None,
                    functools.partial(self.get_nudenet_classifications, m,
                                      fp.name))

    @detection('mention_limit')
    async def mention_limit(self, m: MessageWrapper) -> None:
        mentions = []
        for i in m.mentions:
            if i not in mentions and i != m.author and not i.bot:
                mentions.append(i)

        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(mentions) >= guild_config.detections.mention_limit:
            await m.detection.punish(
                self.bot, m, reason=f'Mass mentions ({len(m.mentions)})')

    @detection('max_lines')
    async def max_lines(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content.splitlines()) > guild_config.detections.max_lines:
            await m.detection.punish(self.bot, m)

    @detection('max_words')
    async def max_words(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content.split(' ')) > guild_config.detections.max_words:
            await m.detection.punish(self.bot, m)

    @detection('max_characters')
    async def max_characters(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content) > guild_config.detections.max_characters:
            await m.detection.punish(self.bot, m)

    @detection('filters')
    async def filtered_words(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        words = [
            i for i in guild_config.detections.filters
            if i in m.content.lower()
        ]
        if words:
            await m.detection.punish(
                self.bot, m, reason=f'Sent a filtered word: {words[0]}')

    @detection('regex_filters')
    async def regex_filter(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        matches = [
            i for i in guild_config.detections.regex_filters
            if re.search(i, m.content)
        ]
        if matches:
            await m.detection.punish(self.bot,
                                     m,
                                     reason='Sent a filtered message.')

    @detection('image_filters', require_attachment=True)
    async def image_filters(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        for i in m.attachments:
            stream = io.BytesIO()
            await i.save(stream)
            try:
                img = Image.open(stream)
            except UnidentifiedImageError:
                pass
            else:
                image_hash = str(average_hash(img))
                img.close()

                if image_hash in guild_config.detections.image_filters:
                    await m.detection.punish(self.bot,
                                             m,
                                             reason='Sent a filtered image')
                    break

    @detection('block_invite')
    async def block_invite(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        invite_match = self.INVITE_REGEX.findall(m.content)
        if invite_match:
            for i in invite_match:
                try:
                    invite = await self.bot.fetch_invite(i[-1])
                except discord.NotFound:
                    pass
                else:
                    if not (invite.guild.id == m.guild.id
                            or str(invite.guild.id)
                            in guild_config.whitelisted_guilds):
                        await m.detection.punish(
                            self.bot,
                            m,
                            reason=
                            f'Advertising discord server `{invite.guild.name}` (<{invite.url}>)'
                        )

    @detection('english_only')
    async def english_only(self, m: MessageWrapper) -> None:
        english_text = ''.join(self.ENGLISH_REGEX.findall(m.content))
        if english_text != m.content:
            await m.detection.punish(self.bot, m)

    @detection('spam_detection')
    async def spam_detection(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        limit = guild_config.detections.spam_detection
        if len(self.spam_detection.get(str(m.author.id), [])) >= limit:
            reason = f'Exceeding spam detection ({limit} messages/5s)'
            await m.detection.punish(self.bot,
                                     m,
                                     reason=reason,
                                     purge_limit=len(self.spam_detection[str(
                                         m.author.id)]))

            try:
                del self.spam_detection[str(m.author.id)]
            except KeyError:
                pass
        else:
            self.spam_detection[str(m.author.id)].append(m.id)
            await asyncio.sleep(5)
            try:
                self.spam_detection[str(m.author.id)].remove(m.id)

                if not self.spam_detection[str(m.author.id)]:
                    del self.spam_detection[str(m.author.id)]
            except ValueError:
                pass

    @detection('repetitive_message')
    async def repetitive_message(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        limit = guild_config.detections.repetitive_message
        if self.get_most_common_count_repmessage(m.author.id) >= limit:
            reason = f'Repetitive message detection ({limit} identical messages/1m)'
            await m.detection.punish(
                self.bot,
                m,
                reason=reason,
                purge_limit=self.get_most_common_count_repmessage(m.author.id))

            try:
                del self.repetitive_message[str(m.author.id)]
            except KeyError:
                pass
        else:
            self.repetitive_message[str(m.author.id)][m.content] += 1
            await asyncio.sleep(60)
            try:
                self.repetitive_message[str(m.author.id)][m.content] -= 1

                if not self.repetitive_message[str(m.author.id)].values():
                    del self.repetitive_message[str(m.author.id)]
            except KeyError:
                pass

    @detection('repetitive_characters')
    async def repetitive_characters(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        limit = guild_config.detections.repetitive_characters

        counter = Counter(m.content)
        for c, n in counter.most_common(None):
            if n > limit:
                reason = f'Repetitive character detection ({n} > {limit} of {c} in message)'
                await m.detection.punish(self.bot, m, reason=reason)
                break

    @detection('caps_message', check_enabled=False)
    async def caps_message(self, m: MessageWrapper) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        percent = guild_config.detections.caps_message_percent
        min_words = guild_config.detections.caps_message_min_words

        if all((percent, min_words)):
            # this is the check enabled
            english_text = ''.join(self.ENGLISH_REGEX.findall(m.content))
            if english_text and len(m.content.split(' ')) >= min_words and (
                    len([i for i in english_text if i.upper() == i]) /
                    len(english_text)) >= percent:
                await m.detection.punish(self.bot, m)

    def get_most_common_count_repmessage(self, id_: int) -> int:
        most_common = self.repetitive_message.get(str(id_),
                                                  Counter()).most_common(1)
        if most_common:
            if most_common[0]:
                return most_common[0][1]
        return 0

    def get_nudenet_classifications(self, m, path) -> None:
        try:
            img = Image.open(path)
        except UnidentifiedImageError:
            os.remove(path)
            return

        image_hash = str(average_hash(img))
        img.close()

        try:
            labels = self.nude_image_cache[image_hash]
        except KeyError:
            result = self.nude_detector.detect(path, min_prob=0.8)
            labels = []

            for i in result:
                labels.append(i['label'])

        os.remove(path)
        if labels:
            self.nude_image_cache[image_hash] = labels
            self.bot.loop.create_task(self.nudenet_callback(m, labels))

    async def nudenet_callback(self, m, labels) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)

        for i in guild_config.detections.sexually_explicit:
            if i in labels:
                await m.detection.punish(
                    self.bot,
                    m,
                    reason=f'Explicit image detection {tuple(labels)}')
                break
Example #6
0
import json
import os
import tensorflow as tf
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow as tf

import warnings
warnings.filterwarnings("ignore")

#tf.logging.set_verbosity(tf.logging.ERROR)
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

#img_path = 'output/frames/BEBE.mkv/frame0034.jpg'
img_path = 'output/frames/test/test.jpg'
detector = NudeDetector('models/detector_model')
result = detector.detect(img_path, min_prob=0.48)
## [{'box': [352, 688, 550, 858], 'score': 0.9603578, 'label': 'BELLY'}, {'box': [507, 896, 586, 1055], 'score': 0.94103414, 'label': 'F_GENITALIA'}, {'box': [221, 467, 552, 650], 'score': 0.8011624, 'label': 'F_BREAST'}, {'box': [359, 464, 543, 626], 'score': 0.6324697, 'label': 'F_BREAST'}]

#[{'box': [204, 260, 362, 360], 'score': 0.6535794, 'label': 'BELLY'}, {'box': [190, 160, 360, 267], 'score': 0.5245675, 'label': 'F_BREAST'}, {'box': [162, 264, 233, 327], 'score': 0.3220556, 'label': 'F_BREAST'}]

cv_image = cv2.imread(img_path)
#json_result = json.loads()
#print(json_result)

#print(result)

print("")
print("")
print("--------------------------------------------")
for item in result:
    left = item['box'][0]
Example #7
0
import os
import json
import tensorflow as tf
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)

from nudenet import NudeDetector
detector = NudeDetector()

# Performing detection
result = detector.detect('/nsfw/one.jpg')
result2 = detector.detect('/nsfw/two.xjpg')

print('')
print('')
print('TEST RESULTS:')
print('********************************************')
print('')

print('one.jpg')
print(result)
print('')
print('two.jpg')
print(result2)

print('')
print('********************************************')
print('')
def filter(fr, scenes, removal):
    video = fr.src_video
    fileext = os.path.splitext(os.path.basename(video.url))[1]
    src_name = str(uuid.uuid4()) + '_' + str(current_millis())
    src_path = os.path.join(settings.MEDIA_ROOT, src_name + fileext)
    print('##### start download  %s' % src_path)
    client = storage.Client.from_service_account_json(settings.GCP_KEY_PATH)
    bucket = client.get_bucket(settings.BUCKET_NAME)
    blob = Blob(gcp_path(video.url), bucket)
    blob.download_to_filename(src_path)
    print('##### complete download %s' % src_path)

    video = cv2.VideoCapture(src_path)
    fps = video.get(cv2.CAP_PROP_FPS)
    num_frames = video.get(cv2.CAP_PROP_FRAME_COUNT)
    duration = int((num_frames / fps) * 1000)

    out_name = str(uuid.uuid4()) + '_' + str(current_millis())
    out_path = os.path.join(settings.MEDIA_ROOT, out_name + fileext)
    infile = ffmpeg.input(src_path)
    if removal:
        print('##### start removing %d scenes' % len(scenes))
        start_times = sorted(
            [scene['start_millis'] / 1000 for scene in scenes])
        end_times = sorted([scene['end_millis'] / 1000 for scene in scenes])
        times_length = len(start_times)
        times = []
        print(start_times, end_times)
        for idx in range(times_length):
            print(start_times[idx], end_times[idx])
            if idx == 0:
                if start_times[idx] != 0:
                    times.append((0, start_times[idx]))
            if idx == times_length - 1:
                times.append((end_times[idx], None))
            if 0 < idx and times_length > 1:
                times.append((end_times[idx - 1], start_times[idx]))
        trims = []
        print(times)
        for time in times:
            start = time[0]
            end = time[1]
            if end is None:
                trims.append(infile.trim(start=start).setpts('N/FR/TB'))
            else:
                trims.append(
                    infile.trim(start=start, end=end).setpts('N/FR/TB'))
        print(trims)
        ffmpeg.concat(*trims).output(out_path).run(overwrite_output=True)
    else:
        # extract frames for detecting
        print('##### start extracting frames for detecting blurbox')
        detector = NudeDetector(settings.NUDE_NET_DETECTOR_MODEL_PATH)
        frames_dir = os.path.join(settings.MEDIA_ROOT, src_name)
        if not os.path.exists(frames_dir):
            os.makedirs(frames_dir)
        try:
            interval = 250
            for scene in scenes:
                cur_millis = scene['start_millis']
                while (True):
                    video.set(cv2.CAP_PROP_POS_MSEC, cur_millis)
                    ret, frame = video.read()
                    if ret:
                        frame_path = os.path.join(frames_dir,
                                                  str(cur_millis) + '.jpg')
                        cv2.imwrite(frame_path, frame)
                    else:
                        break
                    cur_millis += interval
                    if cur_millis >= scene[
                            'end_millis'] or cur_millis > duration:
                        break
            print('##### complete extracting frames for detecting blurbox')
            print('##### start detecting blurbox %s' % frames_dir)
            bps = BlurPointSet()
            for frame in sorted(os.listdir(frames_dir),
                                key=lambda f: int(os.path.splitext(f)[0])):
                censors = detector.detect(os.path.join(frames_dir, frame))
                print('detected blur box point %d from %s' %
                      (len(censors), frame))
                start_millis = int(os.path.splitext(frame)[0])
                end_millis = start_millis + interval
                bps.add_censors(censors, start_millis, end_millis)
            print('##### complete detecting blurbox')

            print('##### start blur')
            blur_op = infile
            for overlay in bps.list_for_overlay():
                blur_op = blur_op.overlay(infile.crop(
                    x=overlay['x'],
                    y=overlay['y'],
                    width=overlay['width'],
                    height=overlay['height']).filter_('boxblur',
                                                      luma_radius=10,
                                                      luma_power=10),
                                          x=overlay['x'],
                                          y=overlay['y'],
                                          enable=overlay['enable'])
            blur_op.output(out_path).run(overwrite_output=True)
            print('##### complete blur')
            shutil.rmtree(frames_dir)
            os.remove(src_path)
        except Exception as e:
            print('##### detect and blur failed %s', str(e))
            os.remove(src_path)
            shutil.rmtree(frames_dir)
            raise e
    video.release()
    cv2.destroyAllWindows()
    return out_path
Example #9
0
class Detections(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.spam_detection = defaultdict(list)
        self.repetitive_message = defaultdict(Counter)
        self.INVITE_REGEX = re.compile(
            r'((http(s|):\/\/|)(discord)(\.(gg|io|me)\/|app\.com\/invite\/)([0-z]+))'
        )
        self.ENGLISH_REGEX = re.compile(
            r'[ -~]|(?:' + UNICODE_EMOJI +
            r')|(?:\U00002018|\U00002019|\s)|[.!?\\\-\(\)]|ツ|(?:\(╯°□°\)╯︵ ┻━┻)|(?:┬─┬ ノ\( ゜-゜ノ\))'
        )  # U2018 and U2019 are iOS quotes

        self.nude_detector = NudeDetector()
        self.nude_graph = tf.get_default_graph()

        self.nude_image_cache = LFUCache(50)

    @Cog.listener()
    async def on_message(self, m):
        if not m.guild or m.type != discord.MessageType.default or m.author.bot or self.bot.dev_mode:
            return

        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if get_perm_level(m.author, guild_config)[0] >= 5:
            return

        detection_config = guild_config.detections
        ignored_channels = guild_config.ignored_channels
        filtered_words = [
            i for i in detection_config.filters if i in m.content.lower()
        ]
        invite_match = self.INVITE_REGEX.findall(m.content)
        english_text = ''.join(self.ENGLISH_REGEX.findall(m.content))

        mentions = []
        for i in m.mentions:
            if i not in mentions and i != m.author and not i.bot:
                mentions.append(i)

        warn_cmd = self.bot.get_command('warn add')
        ctx = await self.bot.get_context(m)
        ctx.author = m.guild.me
        ctx.command = warn_cmd

        # images
        if guild_config.detections.sexually_explicit:
            for i in m.attachments:
                if i.filename.endswith('.png') or i.filename.endswith(
                        '.jpg') or i.filename.endswith('.jpeg'):
                    with NamedTemporaryFile(mode='wb+', delete=False) as fp:
                        async with self.bot.session.get(i.url) as resp:
                            fp.write(await resp.read())
                    await self.bot.loop.run_in_executor(
                        None,
                        functools.partial(self.get_nudenet_classifications, m,
                                          fp.name))

        if detection_config.mention_limit and len(
                mentions) >= detection_config.mention_limit and str(
                    m.channel.id) not in ignored_channels.mention_limit:
            await m.delete()
            await ctx.invoke(warn_cmd,
                             m.author,
                             reason=f'Mass mentions ({len(m.mentions)})')
            await self.bot.mute(m.author,
                                timedelta(minutes=10),
                                reason=f'Mass mentions ({len(m.mentions)})')

        elif len(filtered_words) != 0 and str(
                m.channel.id) not in ignored_channels.filter:
            await m.delete()

        elif detection_config.block_invite and invite_match and str(
                m.channel.id) not in ignored_channels.block_invite:
            for i in invite_match:
                try:
                    invite = await self.bot.fetch_invite(i[-1])
                except discord.NotFound:
                    pass
                else:
                    if not (invite.guild.id == m.guild.id
                            or str(invite.guild.id)
                            in guild_config.whitelisted_guilds):
                        await m.delete()
                        await ctx.invoke(
                            warn_cmd,
                            m.author,
                            reason=
                            f'Advertising discord server (<{invite.url}>)')
                        await self.bot.mute(
                            m.author,
                            timedelta(minutes=10),
                            reason=
                            f'Advertising discord server (<{invite.url}>)')

        elif detection_config.english_only and english_text != m.content and str(
                m.channel.id) not in ignored_channels.english_only:
            await m.delete()

        elif detection_config.spam_detection and len(
                self.spam_detection.get(
                    str(m.author.id),
                    [])) >= detection_config.spam_detection and str(
                        m.channel.id) not in ignored_channels.spam_detection:
            await ctx.invoke(
                warn_cmd,
                m.author,
                reason=
                f'Exceeding spam detection ({detection_config.spam_detection} messages/5s)'
            )
            await self.bot.mute(
                m.author,
                timedelta(minutes=10),
                reason=
                f'Exceeding spam detection ({detection_config.spam_detection} messages/5s)'
            )

            await m.delete()
            for i in self.spam_detection[str(m.author.id)]:
                try:
                    msg = await m.channel.fetch_message(i)
                    await msg.delete()
                except discord.NotFound:
                    pass

        elif detection_config.repetitive_message and self.get_most_common_count(
                m.author.id) >= detection_config.repetitive_message and str(
                    m.channel.id) not in ignored_channels.repetitive_message:
            await ctx.invoke(
                warn_cmd,
                m.author,
                reason=
                f'Repetitive message detection ({detection_config.repetitive_message} identical messages/1m)'
            )
            await ctx.invoke(self.bot.get_command('purge'),
                             limit=self.get_most_common_count(m.author.id),
                             member=m.author)
            await self.bot.mute(
                m.author,
                timedelta(minutes=10),
                reason=
                f'Repetitive message detection ({detection_config.repetitive_message} identical messages/1m)'
            )

        if str(m.channel.id) not in ignored_channels.spam_detection:
            self.spam_detection[str(m.author.id)].append(m.id)
            await asyncio.sleep(5)
            self.spam_detection[str(m.author.id)].remove(m.id)

            if not self.spam_detection[str(m.author.id)]:
                del self.spam_detection[str(m.author.id)]

        if str(m.channel.id) not in ignored_channels.repetitive_message:
            self.repetitive_message[str(m.author.id)][m.content] += 1
            await asyncio.sleep(60)
            self.repetitive_message[str(m.author.id)][m.content] -= 1

            if not self.repetitive_message[str(m.author.id)].values():
                del self.repetitive_message[str(m.author.id)]

    def get_most_common_count(self, id):
        most_common = self.repetitive_message.get(str(id),
                                                  Counter()).most_common(1)
        if most_common:
            if most_common[0]:
                return most_common[0][1]
        return 0

    def get_nudenet_classifications(self, m, path):
        img = Image.open(path)
        image_hash = str(average_hash(img))
        img.close()

        try:
            labels = self.nude_image_cache[image_hash]
        except KeyError:
            with self.nude_graph.as_default():
                result = self.nude_detector.detect(path)
            labels = []

            for i in result:
                labels.append(i['label'])

        os.remove(path)
        if labels:
            self.nude_image_cache[image_hash] = labels
            self.bot.loop.create_task(self.nudenet_callback(m, labels))

    async def nudenet_callback(self, m, labels):
        guild_config = await self.bot.db.get_guild_config(m.guild.id)

        for i in guild_config.detections.sexually_explicit:
            if i in labels:
                await m.delete()
                await self.bot.mute(
                    m.author,
                    timedelta(minutes=10),
                    reason=f'Explicit image detection {tuple(labels)}')

                break
Example #10
0
class Detections(commands.Cog):
    def __init__(self, bot: rainbot) -> None:
        self.bot = bot
        self.spam_detection: DefaultDict[str, List[int]] = defaultdict(list)
        self.repetitive_message: DefaultDict[str, Counter] = defaultdict(Counter)
        self.INVITE_REGEX = re.compile(r'((http(s|):\/\/|)(discord)(\.(gg|io|me)\/|app\.com\/invite\/)([0-z]+))')
        self.ENGLISH_REGEX = re.compile(r'[ -~]|(?:' + UNICODE_EMOJI + r')|(?:\U00002018|\U00002019|\s)|[.!?\\\-\(\)]|ツ|(?:\(╯°□°\)╯︵ ┻━┻)|(?:┬─┬ ノ\( ゜-゜ノ\))')  # U2018 and U2019 are iOS quotes

        self.nude_detector = NudeDetector()
        self.nude_graph = tf.get_default_graph()

        self.nude_image_cache: LFUCache[str, List[str]] = LFUCache(50)

        self.detections = []

        for func in self.__class__.__dict__.values():
            if isinstance(func, Detection):
                self.detections.append(func)

    @Cog.listener()
    async def on_message(self, m: discord.Message) -> None:
        if self.bot.dev_mode:
            if m.guild.id != 733697261065994320:
                return
        if (self.bot.dev_mode and (m.guild and m.guild.id != 733697261065994320)) or m.type != discord.MessageType.default:
            return

        for func in self.detections:
            await func.trigger(self, m)

    @detection('auto_purge_trickocord', require_user=755580145078632508, allow_bot=True)
    async def auto_purge_trickocord(self, m: discord.Message) -> None:
        print(self, m)
        if m.embeds and m.embeds[0].title == 'A trick-or-treater has stopped by!':
            await asyncio.sleep(90)
            await m.delete()

    @detection('sexually_explicit', require_attachment=True)
    async def sexually_explicit(self, m: discord.Message) -> None:
        for i in m.attachments:
            if i.filename.endswith('.png') or i.filename.endswith('.jpg') or i.filename.endswith('.jpeg'):
                with NamedTemporaryFile(mode='wb+', delete=False) as fp:
                    async with self.bot.session.get(i.url) as resp:
                        fp.write(await resp.read())
                await self.bot.loop.run_in_executor(None, functools.partial(self.get_nudenet_classifications, m, fp.name))

    @detection('mention_limit')
    async def mention_limit(self, m: discord.Message) -> None:
        mentions = []
        for i in m.mentions:
            if i not in mentions and i != m.author and not i.bot:
                mentions.append(i)

        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(mentions) >= guild_config.detections.mention_limit:
            await m.delete()
            await self.invoke('warn add', m, member=m.author, reason=f'Mass mentions ({len(m.mentions)})')
            await self.bot.mute(m.author, timedelta(minutes=10), reason=f'Mass mentions ({len(m.mentions)})')

    @detection('max_lines')
    async def max_lines(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content.splitlines()) > guild_config.detections.max_lines:
            await m.delete()
            return True

    @detection('max_words')
    async def max_words(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content.split(' ')) > guild_config.detections.max_words:
            await m.delete()
            return True

    @detection('max_characters')
    async def max_characters(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        if len(m.content) > guild_config.detections.max_characters:
            await m.delete()
            return True

    @detection('filter', check_enabled=False)
    async def filtered_words(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        words = [i for i in guild_config.detections.filters if i in m.content.lower()]
        if words:
            await m.delete()
            return True

    @detection('regex_filter', check_enabled=False)
    async def regex_filter(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        matches = [i for i in guild_config.detections.regex_filters if re.match(i, m.content)]
        if matches:
            await m.delete()
            return True

    @detection('block_invite')
    async def block_invite(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        invite_match = self.INVITE_REGEX.findall(m.content)
        if invite_match:
            for i in invite_match:
                try:
                    invite = await self.bot.fetch_invite(i[-1])
                except discord.NotFound:
                    pass
                else:
                    if not (invite.guild.id == m.guild.id or str(invite.guild.id) in guild_config.whitelisted_guilds):
                        await m.delete()
                        await self.invoke('warn add', m, member=m.author, reason=f'Advertising discord server {invite.guild.name} (<{invite.url}>)')
                        await self.bot.mute(m.author, timedelta(minutes=10), reason=f'Advertising discord server {invite.guild.name} (<{invite.url}>)')

    @detection('english_only')
    async def english_only(self, m: discord.Message) -> None:
        english_text = ''.join(self.ENGLISH_REGEX.findall(m.content))
        if english_text != m.content:
            await m.delete()

    @detection('spam_detection')
    async def spam_detection(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        limit = guild_config.detections.spam_detection
        if len(self.spam_detection.get(str(m.author.id), [])) >= limit:
            reason = f'Exceeding spam detection ({limit} messages/5s)'
            await self.bot.mute(m.author, timedelta(minutes=10), reason=reason)
            await self.invoke('warn add', m, member=m.author, reason=reason)
            await self.invoke('purge', m, member=m.author, limit=len(self.spam_detection[str(m.author.id)]))

            try:
                del self.spam_detection[str(m.author.id)]
            except KeyError:
                pass
        else:
            self.spam_detection[str(m.author.id)].append(m.id)
            await asyncio.sleep(5)
            try:
                self.spam_detection[str(m.author.id)].remove(m.id)

                if not self.spam_detection[str(m.author.id)]:
                    del self.spam_detection[str(m.author.id)]
            except ValueError:
                pass

    @detection('repetitive_message')
    async def repetitive_message(self, m: discord.Message) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)
        limit = guild_config.detections.repetitive_message
        if self.get_most_common_count_repmessage(m.author.id) >= limit:
            reason = f'Repetitive message detection ({limit} identical messages/1m)'
            await self.bot.mute(m.author, timedelta(minutes=10), reason=reason)
            await self.invoke('warn add', m, member=m.author, reason=reason)
            await self.invoke('purge', m, member=m.author, limit=self.get_most_common_count_repmessage(m.author.id))

            try:
                del self.repetitive_message[str(m.author.id)]
            except KeyError:
                pass
        else:
            self.repetitive_message[str(m.author.id)][m.content] += 1
            await asyncio.sleep(60)
            try:
                self.repetitive_message[str(m.author.id)][m.content] -= 1

                if not self.repetitive_message[str(m.author.id)].values():
                    del self.repetitive_message[str(m.author.id)]
            except KeyError:
                pass

    async def invoke(self, command, message: discord.Message, **kwargs) -> None:
        ctx = await self.bot.get_context(message)
        ctx.author = message.guild.me
        await ctx.invoke(self.bot.get_command(command), **kwargs)

    def get_most_common_count_repmessage(self, id_: int) -> int:
        most_common = self.repetitive_message.get(str(id_), Counter()).most_common(1)
        if most_common:
            if most_common[0]:
                return most_common[0][1]
        return 0

    def get_nudenet_classifications(self, m, path) -> None:
        img = Image.open(path)
        image_hash = str(average_hash(img))
        img.close()

        try:
            labels = self.nude_image_cache[image_hash]
        except KeyError:
            with self.nude_graph.as_default():
                result = self.nude_detector.detect(path, min_prob=0.8)
            labels = []

            for i in result:
                labels.append(i['label'])

        os.remove(path)
        if labels:
            self.nude_image_cache[image_hash] = labels
            self.bot.loop.create_task(self.nudenet_callback(m, labels))

    async def nudenet_callback(self, m, labels) -> None:
        guild_config = await self.bot.db.get_guild_config(m.guild.id)

        for i in guild_config.detections.sexually_explicit:
            if i in labels:
                await m.delete()
                await self.bot.mute(m.author, timedelta(minutes=10), reason=f'Explicit image detection {tuple(labels)}')

                break
Example #11
0
# Import module
from nudenet import NudeDetector

# initialize detector (downloads the checkpoint file automatically the first time)
detector = NudeDetector() # detector = NudeDetector('base') for the "base" version of detector.
dic = detector.detect('test.jpg')

score = 0
count = 0
for part in dic:
    if part['score'] < 0.6:
        print(part['label'], "P**n")
        break
    else:
        print(part['label'], ':', part['score'])