Compare commits

...

16 commits

Author SHA1 Message Date
Hypolite Petovan c2dfda5d72 Merge pull request 'Bluesky: Tags are now supported' (#1438) from heluecht/friendica-addons:bluesky-tag into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1438
2023-11-21 16:50:06 +01:00
Michael 9595760800 Bluesky: Tags are now supported 2023-11-20 21:07:09 +00:00
Hypolite Petovan 1c91ee200e Merge pull request 'Bluesky: Support personal data servers' (#1437) from heluecht/friendica-addons:bluesky-pds into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1437
2023-11-20 00:48:07 +01:00
Michael 00e30b5c2b Bluesky: Support personal data servers 2023-11-19 18:55:05 +00:00
heluecht 5f5c53ab49 Merge pull request '[advancedcontentfilter] Fix obsolete reference to Repository\PostMedia->splitAttachments' (#1436) from MrPetovan/friendica-addons:bug/1434-advancedcontentfilter-splitAttachments into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1436
2023-11-15 20:05:31 +01:00
Benjamin Lorteau 6a46d05bca [advancedcontentfilter] Fix obsolete reference to Repository\PostMedia->splitAttachments 2023-11-14 16:25:06 -05:00
Hypolite Petovan 8d3d0f267b Merge pull request 'Bluesky: Support for transmitted languages' (#1435) from heluecht/friendica-addons:languages into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1435
2023-11-13 01:15:45 +01:00
Michael 66fdd31915 Bluesky: Support for transmitted languages 2023-11-11 05:30:07 +00:00
Hypolite Petovan 607cc9238c Merge pull request 'CLD2: Use ISO-639-1 for the language detection' (#1433) from heluecht/friendica-addons:ISO-639-1 into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1433
2023-11-03 19:07:04 +01:00
Michael 2a782b512e CLD2: Use ISO-639-1 for the language detection 2023-11-02 22:54:19 +00:00
Hypolite Petovan a75c9ba373 Merge pull request 'Bluesky: Fix warnings' (#1432) from heluecht/friendica-addons:warnings into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1432
2023-10-29 16:11:19 +01:00
Michael 77765ff6ed Bluesky: Fix warnings 2023-10-29 16:11:19 +01:00
heluecht 9c53c0c8d1 Merge pull request '[smileybutton] Add explicit conversion from float to int' (#1431) from warnings into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1431
2023-10-29 12:40:31 +01:00
Hypolite Petovan 43c46ae6d9 [smileybutton] Add explicit conversion from float to int
Address part of https://github.com/friendica/friendica/issues/13157#issuecomment-1771572442
2023-10-29 12:40:31 +01:00
Hypolite Petovan c7e06bfa53 Merge pull request 'Langfilter: Use two letter code for the language / Bluesky: Remove callstack' (#1430) from heluecht/friendica-addons:callstack-language into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1430
2023-10-18 22:30:52 +02:00
Michael 6948a15f1c Langfilter: Use two letter code for the language / Bluesky: Remove callstack 2023-10-18 22:30:52 +02:00
7 changed files with 140 additions and 82 deletions

View file

@ -455,7 +455,7 @@ function advancedcontentfilter_prepare_item_row(array $item_row): array
$item_row['tags'] = $tags['tags'];
$item_row['hashtags'] = $tags['hashtags'];
$item_row['mentions'] = $tags['mentions'];
$item_row['attachments'] = Post\Media::splitAttachments($item_row['uri-id']);
$item_row['attachments'] = DI::postMediaRepository()->splitAttachments($item_row['uri-id']);
return $item_row;
}

View file

@ -32,11 +32,11 @@ use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\GServer;
use Friendica\Model\Item;
use Friendica\Model\ItemURI;
use Friendica\Model\Photo;
@ -50,9 +50,15 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
const BLUESKY_HOST = 'https://bsky.app'; // Hard wired until Bluesky will run on multiple systems
const BLUESKY_IMAGE_SIZE = [1000000, 500000, 100000, 50000];
/*
* (Currently) hard wired paths for Bluesky services
*/
const BLUESKY_DIRECTORY = 'https://plc.directory'; // Path to the directory server service to fetch the PDS of a given DID
const BLUESKY_PDS = 'https://bsky.social'; // Path to the personal data server service (PDS) to fetch the DID for a given handle
const BLUESKY_WEB = 'https://bsky.app'; // Path to the web interface with the user profile and posts
function bluesky_install()
{
Hook::register('load_config', __FILE__, 'bluesky_load_config');
@ -107,8 +113,8 @@ function bluesky_probe_detect(array &$hookData)
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
$did = $hookData['uri'];
} elseif (preg_match('#^' . BLUESKY_HOST . '/profile/(.+)#', $hookData['uri'], $matches)) {
$did = bluesky_get_did($pconfig['uid'], $matches[1]);
} elseif (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $hookData['uri'], $matches)) {
$did = bluesky_get_did($matches[1]);
if (empty($did)) {
return;
}
@ -128,6 +134,8 @@ function bluesky_probe_detect(array &$hookData)
$hookData['result'] = bluesky_get_contact_fields($data, 0, false);
$hookData['result']['baseurl'] = bluesky_get_pds($did);
// Preparing probe data. This differs slightly from the contact array
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
$hookData['result']['photo'] = $data->avatar ?? '';
@ -153,11 +161,11 @@ function bluesky_item_by_link(array &$hookData)
return;
}
if (!preg_match('#^' . BLUESKY_HOST . '/profile/(.+)/post/(.+)#', $hookData['uri'], $matches)) {
if (!preg_match('#^' . BLUESKY_WEB . '/profile/(.+)/post/(.+)#', $hookData['uri'], $matches)) {
return;
}
$did = bluesky_get_did($hookData['uid'], $matches[1]);
$did = bluesky_get_did($matches[1]);
if (empty($did)) {
return;
}
@ -307,7 +315,7 @@ function bluesky_settings(array &$data)
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? false;
$host = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'host') ?: 'https://bsky.social';
$pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
$did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
@ -322,7 +330,7 @@ function bluesky_settings(array &$data)
'$bydefault' => ['bluesky_bydefault', DI::l10n()->t('Post to Bluesky by default'), $def_enabled],
'$import' => ['bluesky_import', DI::l10n()->t('Import the remote timeline'), $import],
'$import_feeds' => ['bluesky_import_feeds', DI::l10n()->t('Import the pinned feeds'), $import_feeds, DI::l10n()->t('When activated, Posts will be imported from all the feeds that you pinned in Bluesky.')],
'$host' => ['bluesky_host', DI::l10n()->t('Bluesky host'), $host, '', '', 'readonly'],
'$pds' => ['bluesky_pds', DI::l10n()->t('Personal Data Server'), $pds, DI::l10n()->t('The personal data server (PDS) is the system that hosts your profile.'), '', 'readonly'],
'$handle' => ['bluesky_handle', DI::l10n()->t('Bluesky handle'), $handle],
'$did' => ['bluesky_did', DI::l10n()->t('Bluesky DID'), $did, DI::l10n()->t('This is the unique identifier. It will be fetched automatically, when the handle is entered.'), '', 'readonly'],
'$password' => ['bluesky_password', DI::l10n()->t('Bluesky app password'), '', DI::l10n()->t("Please don't add your real password here, but instead create a specific app password in the Bluesky settings.")],
@ -344,26 +352,28 @@ function bluesky_settings_post(array &$b)
return;
}
$old_host = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'host');
$old_pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
$old_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
$old_did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
$host = $_POST['bluesky_host'];
$handle = $_POST['bluesky_handle'];
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'post', intval($_POST['bluesky']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default', intval($_POST['bluesky_bydefault']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'host', $host);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'handle', $handle);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import', intval($_POST['bluesky_import']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds', intval($_POST['bluesky_import_feeds']));
if (!empty($host) && !empty($handle)) {
if (empty($old_did) || $old_host != $host || $old_handle != $handle) {
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'did', bluesky_get_did(DI::userSession()->getLocalUserId(), DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle')));
if (empty($old_did) || $old_handle != $handle) {
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'did', bluesky_get_did(DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle')));
}
if (empty($old_pds) || $old_handle != $handle) {
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'pds', bluesky_get_pds(DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did')));
}
} else {
DI::pConfig()->delete(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
DI::pConfig()->delete(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
}
if (!empty($_POST['bluesky_password'])) {
@ -611,6 +621,13 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
return;
}
// Try to fetch the language from the post itself
if (!empty($item['language'])) {
$language = array_key_first(json_decode($item['language'], true));
} else {
$language = '';
}
$did = DI::pConfig()->get($uid, 'bluesky', 'did');
$urls = bluesky_get_urls(Post\Media::removeFromBody($item['body']));
$item['body'] = $urls['body'];
@ -622,10 +639,14 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
$record = [
'text' => $facets['body'],
'$type' => 'app.bsky.feed.post',
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
'$type' => 'app.bsky.feed.post'
];
if (!empty($language)) {
$record['langs'] = [$language];
}
if (!empty($facets['facets'])) {
$record['facets'] = $facets['facets'];
}
@ -672,11 +693,20 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
function bluesky_get_urls(string $body): array
{
// Remove all hashtag and mention links
$body = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $body);
$body = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $body);
$body = BBCode::expandVideoLinks($body);
$urls = [];
// Search for hash tags
if (preg_match_all("/#\[url\=(https?:.*?)\](.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$text = '#' . $match[2];
$urls[] = ['tag' => $match[2], 'text' => $text, 'hash' => $text];
$body = str_replace($match[0], $text, $body);
}
}
// Search for pure links
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
@ -742,9 +772,17 @@ function bluesky_get_facets(string $body, array $urls): array
$facet->index->byteStart = $pos;
$feature = new stdClass;
$feature->uri = $url['url'];
$type = '$type';
if (!empty($url['tag'])) {
$feature->tag = $url['tag'];
$feature->$type = 'app.bsky.richtext.facet#tag';
} elseif (!empty($url['url'])) {
$feature->uri = $url['url'];
$feature->$type = 'app.bsky.richtext.facet#link';
} else {
continue;
}
$facet->features = [$feature];
$facets[] = $facet;
@ -983,7 +1021,10 @@ function bluesky_fetch_feed(int $uid, string $feed)
}
foreach (array_reverse($data->feed) as $entry) {
if (!Relay::isWantedLanguage($entry->post->record->text)) {
$contact = bluesky_get_contact($entry->post->author, 0, $uid);
$languages = $entry->post->record->langs ?? [];
if (!Relay::isWantedLanguage($entry->post->record->text, 0, $contact['id'] ?? 0, $languages)) {
Logger::debug('Unwanted language detected', ['text' => $entry->post->record->text]);
continue;
}
@ -1095,6 +1136,7 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
$item['body'] = bluesky_get_text($record);
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
$item['transmitted-languages'] = $record->langs ?? [];
return $item;
}
@ -1137,8 +1179,13 @@ function bluesky_get_text(stdClass $record): string
}
break;
case 'app.bsky.richtext.facet#tag';
$url = DI::baseUrl() . '/search?tag=' . urlencode($feature->tag);
$linktext = '#' . $feature->tag;
break;
default:
Logger::notice('Unhandled feature type', ['type' => $feature->$type, 'record' => $record]);
Logger::notice('Unhandled feature type', ['type' => $feature->$type, 'feature' => $feature, 'record' => $record]);
break;
}
}
@ -1235,7 +1282,7 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
function bluesky_get_uri(stdClass $post): string
{
if (empty($post->cid)) {
Logger::info('Invalid URI', ['post' => $post, 'callstack' => System::callstack(10, 0, true)]);
Logger::info('Invalid URI', ['post' => $post]);
return '';
}
return $post->uri . ':' . $post->cid;
@ -1308,7 +1355,7 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $causer, int $lev
return $fallback;
}
Logger::debug('Reply count', ['replies' => $data->thread->post->replyCount, 'level' => $level, 'uid' => $uid, 'uri' => $uri]);
Logger::debug('Reply count', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
if ($causer != 0) {
$cdata = Contact::getPublicAndUserContactID($causer, $uid);
@ -1337,7 +1384,7 @@ function bluesky_fetch_post(string $uri, int $uid): string
function bluesky_process_thread(stdClass $thread, int $uid, array $cdata, int $level): string
{
if (empty($thread->post)) {
Logger::info('Invalid post', ['post' => $thread, 'callstack' => System::callstack(10, 0, true)]);
Logger::info('Invalid post', ['post' => $thread]);
return '';
}
$uri = bluesky_get_uri($thread->post);
@ -1438,10 +1485,9 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, bool $update): a
'blocked' => false,
'readonly' => false,
'pending' => false,
'baseurl' => BLUESKY_HOST,
'url' => $author->did,
'nurl' => $author->did,
'alias' => BLUESKY_HOST . '/profile/' . $author->handle,
'alias' => BLUESKY_WEB . '/profile/' . $author->handle,
'name' => $author->displayName ?? $author->handle,
'nick' => $author->handle,
'addr' => $author->handle,
@ -1452,6 +1498,12 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, bool $update): a
return $fields;
}
$fields['baseurl'] = bluesky_get_pds($author->did);
if (!empty($fields['baseurl'])) {
GServer::check($fields['baseurl'], Protocol::BLUESKY);
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
}
$data = bluesky_xrpc_get($uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
if (empty($data)) {
Logger::debug('Error fetching contact fields', ['uid' => $uid, 'url' => $fields['url']]);
@ -1510,9 +1562,9 @@ function bluesky_get_preferences(int $uid): stdClass
return $data;
}
function bluesky_get_did(int $uid, string $handle): string
function bluesky_get_did(string $handle): string
{
$data = bluesky_get($uid, '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
$data = bluesky_get(BLUESKY_PDS . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
if (empty($data)) {
return '';
}
@ -1520,6 +1572,33 @@ function bluesky_get_did(int $uid, string $handle): string
return $data->did;
}
function bluesky_get_user_pds(int $uid): string
{
$pds = DI::pConfig()->get($uid, 'bluesky', 'pds');
if (!empty($pds)) {
return $pds;
}
$pds = bluesky_get_pds(DI::pConfig()->get($uid, 'bluesky', 'did'));
DI::pConfig()->set($uid, 'bluesky', 'pds', $pds);
return $pds;
}
function bluesky_get_pds(string $did): ?string
{
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
if (empty($data) || empty($data->service)) {
return null;
}
foreach ($data->service as $service) {
if (($service->id == '#atproto_pds') && ($service->type == 'AtprotoPersonalDataServer') && !empty($service->serviceEndpoint)) {
return $service->serviceEndpoint;
}
}
return null;
}
function bluesky_get_token(int $uid): string
{
$token = DI::pConfig()->get($uid, 'bluesky', 'access_token');
@ -1574,7 +1653,7 @@ function bluesky_xrpc_post(int $uid, string $url, $parameters): ?stdClass
function bluesky_post(int $uid, string $url, string $params, array $headers): ?stdClass
{
try {
$curlResult = DI::httpClient()->post(DI::pConfig()->get($uid, 'bluesky', 'host') . $url, $params, $headers);
$curlResult = DI::httpClient()->post(bluesky_get_user_pds($uid) . $url, $params, $headers);
} catch (\Exception $e) {
Logger::notice('Exception on post', ['exception' => $e]);
return null;
@ -1594,13 +1673,13 @@ function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdCl
$url .= '?' . http_build_query($parameters);
}
return bluesky_get($uid, '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]]]);
return bluesky_get(bluesky_get_user_pds($uid) . '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]]]);
}
function bluesky_get(int $uid, string $url, string $accept_content = HttpClientAccept::DEFAULT, array $opts = []): ?stdClass
function bluesky_get(string $url, string $accept_content = HttpClientAccept::DEFAULT, array $opts = []): ?stdClass
{
try {
$curlResult = DI::httpClient()->get(DI::pConfig()->get($uid, 'bluesky', 'host') . $url, $accept_content, $opts);
$curlResult = DI::httpClient()->get($url, $accept_content, $opts);
} catch (\Exception $e) {
Logger::notice('Exception on get', ['exception' => $e]);
return null;

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-06-05 04:34+0000\n"
"POT-Creation-Date: 2023-11-19 18:51+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,70 +17,74 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: bluesky.php:314
#: bluesky.php:325
msgid ""
"You are authenticated to Bluesky. For security reasons the password isn't "
"stored."
msgstr ""
#: bluesky.php:314
#: bluesky.php:325
msgid "You are not authenticated. Please enter the app password."
msgstr ""
#: bluesky.php:318
#: bluesky.php:329
msgid "Enable Bluesky Post Addon"
msgstr ""
#: bluesky.php:319
#: bluesky.php:330
msgid "Post to Bluesky by default"
msgstr ""
#: bluesky.php:320
#: bluesky.php:331
msgid "Import the remote timeline"
msgstr ""
#: bluesky.php:321
#: bluesky.php:332
msgid "Import the pinned feeds"
msgstr ""
#: bluesky.php:321
#: bluesky.php:332
msgid ""
"When activated, Posts will be imported from all the feeds that you pinned in "
"Bluesky."
msgstr ""
#: bluesky.php:322
msgid "Bluesky host"
#: bluesky.php:333
msgid "Personal Data Server"
msgstr ""
#: bluesky.php:323
#: bluesky.php:333
msgid "The personal data server (PDS) is the system that hosts your profile."
msgstr ""
#: bluesky.php:334
msgid "Bluesky handle"
msgstr ""
#: bluesky.php:324
#: bluesky.php:335
msgid "Bluesky DID"
msgstr ""
#: bluesky.php:324
#: bluesky.php:335
msgid ""
"This is the unique identifier. It will be fetched automatically, when the "
"handle is entered."
msgstr ""
#: bluesky.php:325
#: bluesky.php:336
msgid "Bluesky app password"
msgstr ""
#: bluesky.php:325
#: bluesky.php:336
msgid ""
"Please don't add your real password here, but instead create a specific app "
"password in the Bluesky settings."
msgstr ""
#: bluesky.php:331
#: bluesky.php:342
msgid "Bluesky Import/Export"
msgstr ""
#: bluesky.php:382
#: bluesky.php:395
msgid "Post to Bluesky"
msgstr ""

View file

@ -3,7 +3,7 @@
{{include file="field_checkbox.tpl" field=$bydefault}}
{{include file="field_checkbox.tpl" field=$import}}
{{include file="field_checkbox.tpl" field=$import_feeds}}
{{include file="field_input.tpl" field=$host}}
{{include file="field_input.tpl" field=$pds}}
{{include file="field_input.tpl" field=$handle}}
{{include file="field_input.tpl" field=$did}}
{{include file="field_input.tpl" field=$password}}

View file

@ -35,35 +35,10 @@ function cld_detect_languages(array &$data)
$original = '';
}
$detected = $result['language_code'];
if ($detected == 'pt') {
$detected = 'pt-PT';
} elseif ($detected == 'az') {
$detected = 'az-Latn';
} elseif ($detected == 'bs') {
$detected = 'bs-Latn';
} elseif ($detected == 'el') {
$detected = 'el-monoton';
} elseif ($detected == 'ht') {
$detected = 'fr';
} elseif ($detected == 'iw') {
$detected = 'he';
} elseif ($detected == 'jw') {
$detected = 'jv';
} elseif ($detected == 'ms') {
$detected = 'ms-Latn';
} elseif ($detected == 'no') {
$detected = 'nb';
} elseif ($detected == 'sr') {
$detected = 'sr-Cyrl';
} elseif ($detected == 'zh') {
$detected = 'zh-Hans';
} elseif ($detected == 'zh-Hant') {
$detected = 'zh-hant';
}
$detected = DI::l10n()->toISO6391($result['language_code']);
// languages that aren't supported via the base language detection
if (in_array($detected, ['ceb', 'hmn', 'ht', 'kk', 'ky', 'mg', 'mk', 'ml', 'ny', 'or', 'pa', 'rw', 'su', 'st', 'tg', 'ts', 'xx-Qaai'])) {
// languages that aren't supported via the base language detection or tend to false detections
if ((strlen($detected) == 3) || in_array($detected, ['ht', 'kk', 'ku', 'ky', 'lg', 'mg', 'mk', 'mt', 'ny', 'rw', 'st', 'su', 'tg', 'ts', 'xx'])) {
return;
}
@ -75,7 +50,7 @@ function cld_detect_languages(array &$data)
return;
}
$available = array_keys(DI::l10n()->convertForLanguageDetection(DI::l10n()->getAvailableLanguages(true)));
$available = array_keys(DI::l10n()->getLanguageCodes());
if (!in_array($detected, $available)) {
Logger::debug('Unsupported language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);

View file

@ -163,7 +163,7 @@ function langfilter_prepare_body_content_filter(&$hook_data)
return;
}
$lang = $iso639->languageByCode1($iso2);
$lang = $iso639->languageByCode1(substr($iso2, 0, 2));
} else {
$opts = $hook_data['item']['postopts'];
if (!$opts) {

View file

@ -90,7 +90,7 @@ function smileybutton_jot_tool(string &$body)
for ($x = 0; $x < count($params['texts']); $x++) {
$icon = $params['icons'][$x];
$s .= '<td onclick="smileybutton_addsmiley(\'' . $params['texts'][$x] . '\')">' . $icon . '</td>';
if (($x + 1) % (sqrt(count($params['texts'])) + 1) == 0) {
if (($x + 1) % (floor(sqrt(count($params['texts']))) + 1) == 0) {
$s .= '</tr><tr>';
}
}