Наше решение для размытия контента NSFW

На форуме Blender Artists у нас довольно либеральная политика контента, которая допускает изображение наготы и насилия (в определенных пределах). Хотя большинство участников не возражают против такого контента, существуют аудитории и ситуации, где это неприемлемо (для нас в основном школы и дети). Поскольку мы активно используем плиточные галереи с помощью плагина Topic List Preview, нам потребовался способ сделать такой контент опциональным и скрыть его по умолчанию.

Решение оказалось проще в реализации, чем мы ожидали, и я решил поделиться им здесь, на случай если кому-то это пригодится. Честное предупреждение: здесь будут ссылки на контент 18+ (NSFW). Поехали!

Мы уже требовали использования тега #nsfw для всех соответствующих сообщений и строго соблюдали это в течение последних нескольких месяцев. Наш плагин AdSense настроен так, чтобы не показывать рекламу на таких страницах, так как это (и уже приводило!) к проблемам с Google. (Огромная благодарность @neil за добавление этой функции!)

С помощью CSS мы добавили размытие и текст-наложение для всех медиафайлов в таких темах. Размытие исчезает при наведении курсора:

/* отображение размытия и текста-наложения для контента 18+ в тегах #nsfw */
.tag-nsfw { 
	.topic-body .cooked img, 
	.topic-body .cooked iframe, 
	.topic-body .cooked .lazyYT-container, 
	.topic-thumbnail img {
        filter: blur(10px);	
        -webkit-transition: .3s ease-in-out;
        transition: .2s ease-in-out;
	}

	.topic-body:hover .cooked img, 
	.topic-body:hover .cooked iframe,
	.topic-body:hover .cooked .lazyYT-container, 		
	.topic-thumbnail:hover img {
        filter: blur(0);	
        -webkit-transition: .3s ease-in-out;
        transition: .2s ease-in-out;
	}

	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before,
	.topic-thumbnail a:before {
	    z-index:2;
        padding: 5px;
        font-size:1em;
        position:absolute;

        color:#fff;
        content: '⚠️ Контент для взрослых — наведите курсор для просмотра';
        background: #e86800;

	}
	
	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before {
        top: 15px;
        left: 10px;
	}

	.topic-thumbnail a:before {
        top: 65px;
        left: 20px;
	}
	
	.topic-body .cooked a.lightbox:hover:before, 
	.topic-body .cooked iframe:hover:before,
	.topic-thumbnail a:hover:before {		
	    display:none;
	}
}

Теперь изображения и видео в темах выглядят так:

А в любых плиточных галереях TLP мы видим:

Далее мы добавили настройку, позволяющую пользователям отключать размытие для своего аккаунта. Оказалось, что это проще реализовать, чем я думал, используя пользовательские поля.

Сначала мы создали пользовательское поле с флажком:

Затем мы переиспользовали часть кода, чтобы добавлять тег ‘nsfw-always-show’ в класс body для таких пользователей:

<!-- добавление предпочтений текущего пользователя в тег body -->
<script type="text/discourse-plugin" version="0.8">

// https://meta.discourse.org/t/css-classes-for-group-membership-for-simplified-ui-mode/60838/2
if (window.jQuery) {
    window.jQuery(function ($) {
        var u = Discourse.User.current();

        // всегда показывать NSFW
        if (u.custom_fields.user_field_2) {
            console.log('показывать NSFW для пользователя');
            $('body').addClass('nsfw-always-show' );
        }

    });
};

</script>

Небольшой фрагмент CSS убирает размытие для таких пользователей:

/* скрытие пользовательских полей из формы регистрации */

.login-form .user-fields {display:none;}

/* отключение размытия NSFW для пользователей, включивших это в настройках */

.nsfw-always-show .tag-nsfw {
	.topic-body .cooked img, 
	.topic-body .cooked iframe, 
	.topic-body .cooked .lazyYT-container, 
	.topic-thumbnail img {
        filter: blur(0px);	
	}
	
	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before,
	.topic-thumbnail a:before {
	    display:none;
	    content: none;
	}
}

Известная проблема этого подхода заключается в том, что он пока плохо работает на мобильных устройствах, так как там не поддерживается псевдокласс :hover.

Если вы хотите увидеть это в действии, вы можете посетить нашу страницу тега #nsfw, но, возможно, там вы увидите контент 18+ :slight_smile:

Надеюсь, это было полезно для кого-то!

55 лайков

Также на десктопе, если изображение занимает место на экране, его легко случайно навести курсором.
Вместо наведения для снятия размытия, как насчёт динамического добавления кнопки «Показать NSFW-изображение» над или под каждым таким изображением?

4 лайка

На krita-artists.org мы немного изменили это: теперь разблокировка происходит по клику, а не при наведении. Однако настройка, используемая в профиле, не работает. Даже если пользователь установил показ контента 18+, он всё равно видит размытый контент. Есть ли решение этой проблемы?

Я больше не могу редактировать свой первый пост, но вот обновлённый код. Не могли бы вы также поделиться своим решением для «on click»?

<!-- добавить предпочтения текущего пользователя по NSFW к тегу body -->
<script type="text/discourse-plugin" version="0.8.7">

// https://meta.discourse.org/t/css-classes-for-group-membership-for-simplified-ui-mode/60838/2
if (window.jQuery) {
    window.jQuery(function ($) {

        let currentUser = api.getCurrentUser();
        
        if (currentUser) {
            api.container.lookup('store:main').find('user', currentUser.username).then((user) => {

                if (user.user_fields[2]) {
                    $('body').addClass('nsfw-always-show' );
                }
            });
        }
    });
};
</script>
2 лайка

Наше решение с onlick выглядит кустарным, и я считаю, что оно может быть не идеальным: мы просто убрали размытие при наведении и добавили его по умолчанию. Сообщение также было изменено на то, что пользователю нужно кликнуть, чтобы перейти к посту. Теперь пользователю приходится кликать, чтобы перейти к посту, и кликать ещё раз, чтобы увидеть размытое NSFW-изображение в лайтбоксе. Это неудобно, но предотвращает случайное наведение и показ. Возможно, стоит использовать JS для снятия размытия при клике.

/* отображать размытие NSFW и текст оверлея для любых медиа в темах #nsfw */
.tag-nsfw { 
.topic-thumbnail {
    overflow:hidden;
}

	.topic-body .cooked .lightbox img, 
	.topic-body .cooked iframe, 
	.topic-body .cooked .lazyYT-container, 
	.topic-thumbnail img {
    filter: blur(30px);	
    -webkit-transition: .3s ease-in-out;
    transition: .2s ease-in-out;
	}

	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before,
	.topic-thumbnail a:before {
	    z-index:2;
    padding: 5px;
    font-size:1em;
    position:absolute;

    color:#fff;
    content: '⚠️ Контент для взрослых — нажмите, чтобы увидеть изображение';
    background: #000;

	}
	
	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before {
    top: 50%;
    left: 10px;
    right: 10px;
    text-align:center;
	}

	.topic-thumbnail a:before {
    top: 65px;
    left: 20px;
	}
	
}

/* скрыть пользовательские поля из формы регистрации */
.login-form .user-fields {display:none;}

/* отключить размытие NSFW для пользователей, установивших это в своих настройках */
.nsfw-always-show .tag-nsfw {
	.topic-body .cooked img, 
	.topic-body .cooked iframe, 
	.topic-body .cooked .lazyYT-container, 
	.topic-thumbnail img {
    filter: blur(0px);	
	}
	
	.topic-body .cooked a.lightbox:before, 
	.topic-body .cooked iframe:before,
	.topic-thumbnail a:before {
	    display:none;
	    content: none;
	}
}

@bartv @Terrapop

Если кто-то захочет взяться за это, можно использовать Discourse Image Filter для создания плагина auto nsfw blurring (автоматическое размытие контента для взрослых).

4 лайка

Привет! Что нужно сделать, чтобы убрать размытие и сделать текст гиперссылкой, так как мы хотим, чтобы он вел на внешний сайт для пожертвований?

1 лайк

К сожалению, только с помощью CSS это не сделать; вам придётся добавить свой собственный код для этого.

2 лайка

Просто удалите строки filter: blur(10px); из CSS.

5 лайков

@bartv Я сделал первую запись в вики, пожалуйста, не стесняйтесь обновлять её по мере необходимости! :folded_hands:

10 лайков