Official Addons for the Friendica Communications Platform. (please note that this is a clone of the repository at github, issues are handled there)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.5 KiB

  1. <?php
  2. /**
  3. * Name: NSFW
  4. * Description: Collapse posts with inappropriate content
  5. * Version: 1.0
  6. * Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
  7. *
  8. */
  9. use Friendica\Core\Hook;
  10. use Friendica\DI;
  11. function nsfw_install()
  12. {
  13. Hook::register('prepare_body_content_filter', 'addon/nsfw/nsfw.php', 'nsfw_prepare_body_content_filter', 10);
  14. Hook::register('addon_settings', 'addon/nsfw/nsfw.php', 'nsfw_addon_settings');
  15. Hook::register('addon_settings_post', 'addon/nsfw/nsfw.php', 'nsfw_addon_settings_post');
  16. }
  17. // This function isn't perfect and isn't trying to preserve the html structure - it's just a
  18. // quick and dirty filter to pull out embedded photo blobs because 'nsfw' seems to come up
  19. // inside them quite often. We don't need anything fancy, just pull out the data blob so we can
  20. // check against the rest of the body.
  21. function nsfw_extract_photos($body)
  22. {
  23. $new_body = '';
  24. $img_start = strpos($body, 'src="data:');
  25. $img_end = (($img_start !== false) ? strpos(substr($body, $img_start), '>') : false);
  26. $cnt = 0;
  27. while ($img_end !== false) {
  28. $img_end += $img_start;
  29. $new_body = $new_body . substr($body, 0, $img_start);
  30. $cnt ++;
  31. $body = substr($body, 0, $img_end);
  32. $img_start = strpos($body, 'src="data:');
  33. $img_end = (($img_start !== false) ? strpos(substr($body, $img_start), '>') : false);
  34. }
  35. if (!$cnt) {
  36. return $body;
  37. }
  38. return $new_body;
  39. }
  40. function nsfw_addon_settings(&$a, &$s)
  41. {
  42. if (!local_user()) {
  43. return;
  44. }
  45. /* Add our stylesheet to the page so we can make our settings look nice */
  46. DI::page()['htmlhead'] .= '<link rel="stylesheet" type="text/css" href="' . DI::baseUrl()->get() . '/addon/nsfw/nsfw.css' . '" media="all" />' . "\r\n";
  47. $enable_checked = (intval(DI::pConfig()->get(local_user(), 'nsfw', 'disable')) ? '' : ' checked="checked" ');
  48. $words = DI::pConfig()->get(local_user(), 'nsfw', 'words');
  49. if (!$words) {
  50. $words = 'nsfw,';
  51. }
  52. $s .= '<span id="settings_nsfw_inflated" class="settings-block fakelink" style="display: block;" onclick="openClose(\'settings_nsfw_expanded\'); openClose(\'settings_nsfw_inflated\');">';
  53. $s .= '<h3>' . DI::l10n()->t('Content Filter (NSFW and more)') . '</h3>';
  54. $s .= '</span>';
  55. $s .= '<div id="settings_nsfw_expanded" class="settings-block" style="display: none;">';
  56. $s .= '<span class="fakelink" onclick="openClose(\'settings_nsfw_expanded\'); openClose(\'settings_nsfw_inflated\');">';
  57. $s .= '<h3>' . DI::l10n()->t('Content Filter (NSFW and more)') . '</h3>';
  58. $s .= '</span>';
  59. $s .= '<div id="nsfw-wrapper">';
  60. $s .= '<p>' . 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.') . '</p>';
  61. $s .= '<label id="nsfw-enable-label" for="nsfw-enable">' . DI::l10n()->t('Enable Content filter') . ' </label>';
  62. $s .= '<input id="nsfw-enable" type="checkbox" name="nsfw-enable" value="1"' . $enable_checked . ' />';
  63. $s .= '<div class="clear"></div>';
  64. $s .= '<label id="nsfw-label" for="nsfw-words">' . DI::l10n()->t('Comma separated list of keywords to hide') . ' </label>';
  65. $s .= '<textarea id="nsfw-words" type="text" name="nsfw-words">' . $words . '</textarea>';
  66. $s .= '</div><div class="clear"></div>';
  67. $s .= '<div class="settings-submit-wrapper" ><input type="submit" id="nsfw-submit" name="nsfw-submit" class="settings-submit" value="' . DI::l10n()->t('Save Settings') . '" /></div>';
  68. $s .= '<div class="nsfw-desc">' . DI::l10n()->t('Use /expression/ to provide regular expressions') . '</div></div>';
  69. return;
  70. }
  71. function nsfw_addon_settings_post(&$a, &$b)
  72. {
  73. if (!local_user()) {
  74. return;
  75. }
  76. if (!empty($_POST['nsfw-submit'])) {
  77. DI::pConfig()->set(local_user(), 'nsfw', 'words', trim($_POST['nsfw-words']));
  78. $enable = (!empty($_POST['nsfw-enable']) ? intval($_POST['nsfw-enable']) : 0);
  79. $disable = 1 - $enable;
  80. DI::pConfig()->set(local_user(), 'nsfw', 'disable', $disable);
  81. }
  82. }
  83. function nsfw_prepare_body_content_filter(\Friendica\App $a, &$hook_data)
  84. {
  85. $words = null;
  86. if (DI::pConfig()->get(local_user(), 'nsfw', 'disable')) {
  87. return;
  88. }
  89. if (local_user()) {
  90. $words = DI::pConfig()->get(local_user(), 'nsfw', 'words');
  91. }
  92. if ($words) {
  93. $word_list = explode(',', $words);
  94. } else {
  95. $word_list = ['nsfw'];
  96. }
  97. $found = false;
  98. if (count($word_list)) {
  99. $body = $hook_data['item']['title'] . "\n" . nsfw_extract_photos($hook_data['item']['body']);
  100. foreach ($word_list as $word) {
  101. $word = trim($word);
  102. if (!strlen($word)) {
  103. continue;
  104. }
  105. $tag_search = false;
  106. switch ($word[0]) {
  107. case '/'; // Regular expression
  108. $found = preg_match($word, $body);
  109. break;
  110. case '#': // Hashtag-only search
  111. $tag_search = true;
  112. $found = nsfw_find_word_in_item_tags($hook_data['item']['hashtags'], substr($word, 1));
  113. break;
  114. default:
  115. $found = stripos($body, $word) !== false || nsfw_find_word_in_item_tags($hook_data['item']['tags'], $word);
  116. break;
  117. }
  118. if ($found) {
  119. break;
  120. }
  121. }
  122. }
  123. if ($found) {
  124. if ($tag_search) {
  125. $hook_data['filter_reasons'][] = DI::l10n()->t('Filtered tag: %s', $word);
  126. } else {
  127. $hook_data['filter_reasons'][] = DI::l10n()->t('Filtered word: %s', $word);
  128. }
  129. }
  130. }
  131. function nsfw_find_word_in_item_tags($item_tags, $word)
  132. {
  133. if (is_array($item_tags)) {
  134. foreach ($item_tags as $tag) {
  135. if (stripos($tag, '>' . $word . '<') !== false) {
  136. return true;
  137. }
  138. }
  139. }
  140. return false;
  141. }