2015-07-24 17:02:42 +00:00
< ? php
/*
* Name : Language Filter
* Version : 0.1
* Description : Filters out postings in languages not spoken by the users
* Author : Tobias Diekershoff < https :// f . diekershoff . de / u / tobias >
* License : MIT
*/
2018-04-21 22:47:18 +00:00
use Friendica\Content\Text\BBCode ;
2018-12-26 07:28:16 +00:00
use Friendica\Core\Hook ;
2018-10-31 14:55:15 +00:00
use Friendica\Core\Renderer ;
2019-12-16 00:05:14 +00:00
use Friendica\DI ;
2017-10-05 12:58:44 +00:00
2015-07-24 17:02:42 +00:00
/* Define the hooks we want to use
* that is , we have settings , we need to save the settings and we want
* to modify the content of a posting when friendica prepares it .
*/
2017-11-05 13:59:45 +00:00
function langfilter_install ()
{
2018-12-26 07:28:16 +00:00
Hook :: register ( 'prepare_body_content_filter' , 'addon/langfilter/langfilter.php' , 'langfilter_prepare_body_content_filter' , 10 );
Hook :: register ( 'addon_settings' , 'addon/langfilter/langfilter.php' , 'langfilter_addon_settings' );
Hook :: register ( 'addon_settings_post' , 'addon/langfilter/langfilter.php' , 'langfilter_addon_settings_post' );
2015-07-24 17:02:42 +00:00
}
2017-11-05 13:59:45 +00:00
2015-07-24 17:02:42 +00:00
/* The settings
* 1 st check if somebody logged in is calling
* 2 nd get the current settings
* 3 rd parse a SMARTY3 template , replacing some translateable strings for the form
*/
2017-11-05 13:59:45 +00:00
2023-01-14 02:16:09 +00:00
function langfilter_addon_settings ( array & $data )
2017-11-05 13:59:45 +00:00
{
2022-10-20 21:51:49 +00:00
if ( ! DI :: userSession () -> getLocalUserId ()) {
2015-07-24 17:02:42 +00:00
return ;
2017-11-05 13:59:45 +00:00
}
2022-10-20 21:51:49 +00:00
$enabled = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'enable' ,
! DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'disable' ));
2020-02-01 19:14:22 +00:00
2022-10-20 21:51:49 +00:00
$languages = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'languages' );
$minconfidence = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minconfidence' , 0 ) * 100 ;
$minlength = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minlength' , 32 );
2015-07-24 17:02:42 +00:00
2021-11-20 09:56:55 +00:00
$t = Renderer :: getMarkupTemplate ( 'settings.tpl' , 'addon/langfilter/' );
$html = Renderer :: replaceMacros ( $t , [
2021-03-24 22:33:42 +00:00
'$intro' => DI :: l10n () -> t ( 'This addon tries to identify the language posts are written in. If it does not match any language specified below, posts will be hidden by collapsing them.' ),
2021-11-20 09:56:55 +00:00
'$enabled' => [ 'langfilter_enable' , DI :: l10n () -> t ( 'Use the language filter' ), $enabled ],
2020-10-04 02:02:05 +00:00
'$languages' => [ 'langfilter_languages' , DI :: l10n () -> t ( 'Able to read' ), $languages , DI :: l10n () -> t ( 'List of abbreviations (ISO 639-1 codes) for languages you speak, comma separated. For example "de,it".' )],
2020-01-18 19:52:33 +00:00
'$minconfidence' => [ 'langfilter_minconfidence' , DI :: l10n () -> t ( 'Minimum confidence in language detection' ), $minconfidence , DI :: l10n () -> t ( 'Minimum confidence in language detection being correct, from 0 to 100. Posts will not be filtered when the confidence of language detection is below this percent value.' )],
'$minlength' => [ 'langfilter_minlength' , DI :: l10n () -> t ( 'Minimum length of message body' ), $minlength , DI :: l10n () -> t ( 'Minimum number of characters in message body for filter to be used. Posts shorter than this will not be filtered. Note: Language detection is unreliable for short content (<200 characters).' )],
2018-01-15 13:15:33 +00:00
]);
2015-07-24 17:02:42 +00:00
2021-11-20 09:56:55 +00:00
$data = [
'addon' => 'langfilter' ,
'title' => DI :: l10n () -> t ( 'Language Filter' ),
'html' => $html ,
'submit' => [ 'langfilter-settings-submit' => DI :: l10n () -> t ( 'Save Settings' )],
];
2015-07-24 17:02:42 +00:00
}
2017-11-05 13:59:45 +00:00
2015-07-24 17:02:42 +00:00
/* Save the settings
* 1 st check it ' s a logged in user calling
* 2 nd check the langfilter form is to be saved
* 3 rd save the settings to the DB for later usage
*/
2017-11-05 13:59:45 +00:00
2023-01-14 02:16:09 +00:00
function langfilter_addon_settings_post ( array & $b )
2017-11-05 13:59:45 +00:00
{
2022-10-20 21:51:49 +00:00
if ( ! DI :: userSession () -> getLocalUserId ()) {
2015-07-24 17:02:42 +00:00
return ;
2017-11-05 13:59:45 +00:00
}
2015-07-24 17:02:42 +00:00
2018-08-08 06:24:47 +00:00
if ( ! empty ( $_POST [ 'langfilter-settings-submit' ])) {
2020-02-01 19:14:22 +00:00
$enable = intval ( $_POST [ 'langfilter_enable' ] ? ? 0 );
$languages = trim ( $_POST [ 'langfilter_languages' ] ? ? '' );
$minconfidence = max ( 0 , min ( 100 , intval ( $_POST [ 'langfilter_minconfidence' ] ? ? 0 ))) / 100 ;
$minlength = intval ( $_POST [ 'langfilter_minlength' ] ? ? 32 );
if ( $minlength <= 0 ) {
2017-11-05 13:59:45 +00:00
$minlength = 32 ;
}
2022-10-20 21:51:49 +00:00
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'enable' , $enable );
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'languages' , $languages );
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minconfidence' , $minconfidence );
DI :: pConfig () -> set ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minlength' , $minlength );
2015-07-24 17:02:42 +00:00
}
}
2017-11-05 13:59:45 +00:00
2015-07-24 17:02:42 +00:00
/* Actually filter postings by their language
* 1 st check if the user wants to filter postings
* 2 nd get the user settings which languages shall be not filtered out
2015-09-22 10:29:06 +00:00
* 3 rd extract the language of a posting
2015-07-24 17:02:42 +00:00
* 4 th if the determined language does not fit to the spoken languages
* of the user , then collapse the posting , but provide a link to
* expand it again .
*/
2023-01-14 02:16:09 +00:00
function langfilter_prepare_body_content_filter ( & $hook_data )
2017-11-05 13:59:45 +00:00
{
2022-10-20 21:51:49 +00:00
$logged_user = DI :: userSession () -> getLocalUserId ();
2017-11-05 13:59:45 +00:00
if ( ! $logged_user ) {
return ;
}
2015-09-09 17:41:38 +00:00
2017-11-05 13:59:45 +00:00
// Never filter own messages
// TODO: find a better way to extract this
2023-02-18 19:57:09 +00:00
$logged_user_profile = DI :: baseUrl () . '/profile/' . DI :: userSession () -> getLocalUserNickname ();
2018-04-01 06:31:37 +00:00
if ( $logged_user_profile == $hook_data [ 'item' ][ 'author-link' ]) {
2017-11-05 13:59:45 +00:00
return ;
}
2015-07-24 17:02:42 +00:00
2017-11-05 13:59:45 +00:00
// Don't filter if language filter is disabled
2020-02-01 19:14:22 +00:00
if ( ! DI :: pConfig () -> get ( $logged_user , 'langfilter' , 'enable' ,
! DI :: pConfig () -> get ( $logged_user , 'langfilter' , 'disable' ))
) {
2017-11-05 13:59:45 +00:00
return ;
}
2015-09-10 07:54:26 +00:00
2022-01-19 14:49:56 +00:00
$naked_body = strip_tags (
$hook_data [ 'item' ][ 'rendered-html' ]
? ? '' ? : // Equivalent of !empty()
2023-07-16 10:37:33 +00:00
BBCode :: convertForUriId ( $hook_data [ 'item' ][ 'uri-id' ], $hook_data [ 'item' ][ 'body' ], BBCode :: ACTIVITYPUB )
2022-01-19 14:49:56 +00:00
);
$naked_body = preg_replace ( '#\s+#' , ' ' , trim ( $naked_body ));
2018-04-21 08:13:53 +00:00
2017-11-05 13:59:45 +00:00
// Don't filter if body lenght is below minimum
2022-10-20 21:51:49 +00:00
$minlen = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minlength' , 32 );
2017-11-05 13:59:45 +00:00
if ( ! $minlen ) {
$minlen = 32 ;
}
2018-04-21 08:13:53 +00:00
if ( strlen ( $naked_body ) < $minlen ) {
2017-11-05 13:59:45 +00:00
return ;
}
2016-10-01 16:15:32 +00:00
2022-10-20 21:51:49 +00:00
$read_languages_string = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'languages' );
$minconfidence = DI :: pConfig () -> get ( DI :: userSession () -> getLocalUserId (), 'langfilter' , 'minconfidence' );
2015-09-22 10:29:06 +00:00
2017-11-05 13:59:45 +00:00
// Don't filter if no spoken languages are configured
2018-04-01 06:31:37 +00:00
if ( ! $read_languages_string ) {
2017-11-05 13:59:45 +00:00
return ;
2018-04-01 06:31:37 +00:00
}
$read_languages_array = explode ( ',' , $read_languages_string );
2015-09-22 10:29:06 +00:00
2020-10-04 02:00:44 +00:00
$iso639 = new Matriphe\ISO639\ISO639 ;
2024-11-30 19:35:19 +00:00
$confidence = null ;
2017-11-05 13:59:45 +00:00
// Extract the language of the post
2018-06-30 05:20:17 +00:00
if ( ! empty ( $hook_data [ 'item' ][ 'language' ])) {
$languages = json_decode ( $hook_data [ 'item' ][ 'language' ], true );
if ( ! is_array ( $languages )) {
return ;
}
2018-04-01 06:31:37 +00:00
2018-06-30 05:20:17 +00:00
foreach ( $languages as $iso2 => $confidence ) {
break ;
}
2015-09-22 10:29:06 +00:00
2018-08-31 05:10:53 +00:00
if ( empty ( $iso2 )) {
return ;
}
2023-10-18 20:16:59 +00:00
$lang = $iso639 -> languageByCode1 ( substr ( $iso2 , 0 , 2 ));
2018-06-30 05:20:17 +00:00
} else {
$opts = $hook_data [ 'item' ][ 'postopts' ];
if ( ! $opts ) {
// no options associated to post
return ;
}
if ( ! preg_match ( '/\blang=([^;]*);([^:]*)/' , $opts , $matches )) {
// no lang options associated to post
return ;
}
$lang = $matches [ 1 ];
$confidence = $matches [ 2 ];
2020-10-04 02:00:44 +00:00
$iso2 = $iso639 -> code1ByLanguage ( $lang );
2018-06-30 05:20:17 +00:00
}
2015-09-22 10:29:06 +00:00
2017-11-05 13:59:45 +00:00
// Do not filter if language detection confidence is too low
if ( $minconfidence && $confidence < $minconfidence ) {
return ;
}
2015-09-22 10:29:06 +00:00
2017-11-05 13:59:45 +00:00
if ( ! $iso2 ) {
return ;
}
2015-09-22 10:29:06 +00:00
2018-04-01 06:31:37 +00:00
if ( ! in_array ( $iso2 , $read_languages_array )) {
2020-01-18 19:52:33 +00:00
$hook_data [ 'filter_reasons' ][] = DI :: l10n () -> t ( 'Filtered language: %s' , ucfirst ( $lang ));
2017-11-05 13:59:45 +00:00
}
2015-07-24 17:02:42 +00:00
}