5 * Description: Collapse posts with inappropriate content
7 * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
12 use Friendica\Core\Hook;
13 use Friendica\Core\Renderer;
16 function nsfw_install()
18 Hook::register('prepare_body_content_filter', 'addon/nsfw/nsfw.php', 'nsfw_prepare_body_content_filter', 10);
19 Hook::register('addon_settings', 'addon/nsfw/nsfw.php', 'nsfw_addon_settings');
20 Hook::register('addon_settings_post', 'addon/nsfw/nsfw.php', 'nsfw_addon_settings_post');
23 // This function isn't perfect and isn't trying to preserve the html structure - it's just a
24 // quick and dirty filter to pull out embedded photo blobs because 'nsfw' seems to come up
25 // inside them quite often. We don't need anything fancy, just pull out the data blob so we can
26 // check against the rest of the body.
28 function nsfw_extract_photos($body)
32 $img_start = strpos($body, 'src="data:');
33 $img_end = (($img_start !== false) ? strpos(substr($body, $img_start), '>') : false);
37 while ($img_end !== false) {
38 $img_end += $img_start;
39 $new_body = $new_body . substr($body, 0, $img_start);
42 $body = substr($body, 0, $img_end);
44 $img_start = strpos($body, 'src="data:');
45 $img_end = (($img_start !== false) ? strpos(substr($body, $img_start), '>') : false);
54 function nsfw_addon_settings(App &$a, array &$data)
56 if (!DI::userSession()->getLocalUserId()) {
60 $enabled = !DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'disable');
61 $words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'words', 'nsfw,');
63 $t = Renderer::getMarkupTemplate('settings.tpl', 'addon/nsfw/');
64 $html = Renderer::replaceMacros($t, [
65 '$info' => DI::l10n()->t('This addon searches for specified words/text in posts and collapses them. It can be used to filter content tagged with for instance #NSFW that may be deemed inappropriate at certain times or places, such as being at work. It is also useful for hiding irrelevant or annoying content from direct view.'),
66 '$enabled' => ['nsfw-enable', DI::l10n()->t('Enable Content filter'), $enabled],
67 '$words' => ['nsfw-words', DI::l10n()->t('Comma separated list of keywords to hide'), $words, DI::l10n()->t('Use /expression/ to provide regular expressions, #tag to specfically match hashtags (case-insensitive), or regular words (case-sensitive)')],
72 'title' => DI::l10n()->t('Content Filter (NSFW and more)'),
77 function nsfw_addon_settings_post(App $a, array &$b)
79 if (!DI::userSession()->getLocalUserId()) {
83 if (!empty($_POST['nsfw-submit'])) {
84 DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'nsfw', 'words', trim($_POST['nsfw-words']));
85 $enable = (!empty($_POST['nsfw-enable']) ? intval($_POST['nsfw-enable']) : 0);
86 $disable = 1 - $enable;
87 DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'nsfw', 'disable', $disable);
91 function nsfw_prepare_body_content_filter(App $a, &$hook_data)
94 if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'disable')) {
98 if (DI::userSession()->getLocalUserId()) {
99 $words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'words');
103 $word_list = explode(',', $words);
105 $word_list = ['nsfw'];
109 if (count($word_list)) {
110 $body = $hook_data['item']['title'] . "\n" . nsfw_extract_photos($hook_data['item']['body']);
112 foreach ($word_list as $word) {
114 if (!strlen($word)) {
120 case '/'; // Regular expression
121 $found = preg_match($word, $body);
123 case '#': // Hashtag-only search
125 $found = nsfw_find_word_in_item_tags($hook_data['item']['hashtags'], substr($word, 1));
128 $found = strpos($body, $word) !== false || nsfw_find_word_in_item_tags($hook_data['item']['tags'], $word);
140 $hook_data['filter_reasons'][] = DI::l10n()->t('Filtered tag: %s', $word);
142 $hook_data['filter_reasons'][] = DI::l10n()->t('Filtered word: %s', $word);
147 function nsfw_find_word_in_item_tags($item_tags, $word)
149 if (is_array($item_tags)) {
150 foreach ($item_tags as $tag) {
151 if (stripos($tag, '>' . $word . '<') !== false) {