forked from friendica/friendica-addons
Compare commits
16 commits
74c56c32b0
...
c2dfda5d72
Author | SHA1 | Date | |
---|---|---|---|
|
c2dfda5d72 | ||
|
9595760800 | ||
|
1c91ee200e | ||
|
00e30b5c2b | ||
|
5f5c53ab49 | ||
|
6a46d05bca | ||
|
8d3d0f267b | ||
|
66fdd31915 | ||
|
607cc9238c | ||
|
2a782b512e | ||
|
a75c9ba373 | ||
|
77765ff6ed | ||
|
9c53c0c8d1 | ||
|
43c46ae6d9 | ||
|
c7e06bfa53 | ||
|
6948a15f1c |
|
@ -455,7 +455,7 @@ function advancedcontentfilter_prepare_item_row(array $item_row): array
|
||||||
$item_row['tags'] = $tags['tags'];
|
$item_row['tags'] = $tags['tags'];
|
||||||
$item_row['hashtags'] = $tags['hashtags'];
|
$item_row['hashtags'] = $tags['hashtags'];
|
||||||
$item_row['mentions'] = $tags['mentions'];
|
$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;
|
return $item_row;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,11 +32,11 @@ use Friendica\Core\Hook;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
use Friendica\Core\Protocol;
|
use Friendica\Core\Protocol;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
use Friendica\Core\System;
|
|
||||||
use Friendica\Core\Worker;
|
use Friendica\Core\Worker;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
|
use Friendica\Model\GServer;
|
||||||
use Friendica\Model\Item;
|
use Friendica\Model\Item;
|
||||||
use Friendica\Model\ItemURI;
|
use Friendica\Model\ItemURI;
|
||||||
use Friendica\Model\Photo;
|
use Friendica\Model\Photo;
|
||||||
|
@ -50,9 +50,15 @@ use Friendica\Util\DateTimeFormat;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
|
||||||
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
|
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];
|
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()
|
function bluesky_install()
|
||||||
{
|
{
|
||||||
Hook::register('load_config', __FILE__, 'bluesky_load_config');
|
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') {
|
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
|
||||||
$did = $hookData['uri'];
|
$did = $hookData['uri'];
|
||||||
} elseif (preg_match('#^' . BLUESKY_HOST . '/profile/(.+)#', $hookData['uri'], $matches)) {
|
} elseif (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $hookData['uri'], $matches)) {
|
||||||
$did = bluesky_get_did($pconfig['uid'], $matches[1]);
|
$did = bluesky_get_did($matches[1]);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -128,6 +134,8 @@ function bluesky_probe_detect(array &$hookData)
|
||||||
|
|
||||||
$hookData['result'] = bluesky_get_contact_fields($data, 0, false);
|
$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
|
// Preparing probe data. This differs slightly from the contact array
|
||||||
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
|
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
|
||||||
$hookData['result']['photo'] = $data->avatar ?? '';
|
$hookData['result']['photo'] = $data->avatar ?? '';
|
||||||
|
@ -153,11 +161,11 @@ function bluesky_item_by_link(array &$hookData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preg_match('#^' . BLUESKY_HOST . '/profile/(.+)/post/(.+)#', $hookData['uri'], $matches)) {
|
if (!preg_match('#^' . BLUESKY_WEB . '/profile/(.+)/post/(.+)#', $hookData['uri'], $matches)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$did = bluesky_get_did($hookData['uid'], $matches[1]);
|
$did = bluesky_get_did($matches[1]);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -307,7 +315,7 @@ function bluesky_settings(array &$data)
|
||||||
|
|
||||||
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
|
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
|
||||||
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? 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');
|
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
|
||||||
$did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
$did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
||||||
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
|
$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],
|
'$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' => ['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.')],
|
'$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],
|
'$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'],
|
'$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.")],
|
'$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;
|
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_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
|
||||||
$old_did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
$old_did = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
||||||
|
|
||||||
$host = $_POST['bluesky_host'];
|
|
||||||
$handle = $_POST['bluesky_handle'];
|
$handle = $_POST['bluesky_handle'];
|
||||||
|
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'post', intval($_POST['bluesky']));
|
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', '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', 'handle', $handle);
|
||||||
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import', intval($_POST['bluesky_import']));
|
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']));
|
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds', intval($_POST['bluesky_import_feeds']));
|
||||||
|
|
||||||
if (!empty($host) && !empty($handle)) {
|
if (!empty($host) && !empty($handle)) {
|
||||||
if (empty($old_did) || $old_host != $host || $old_handle != $handle) {
|
if (empty($old_did) || $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')));
|
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 {
|
} else {
|
||||||
DI::pConfig()->delete(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
DI::pConfig()->delete(DI::userSession()->getLocalUserId(), 'bluesky', 'did');
|
||||||
|
DI::pConfig()->delete(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($_POST['bluesky_password'])) {
|
if (!empty($_POST['bluesky_password'])) {
|
||||||
|
@ -611,6 +621,13 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
|
||||||
return;
|
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');
|
$did = DI::pConfig()->get($uid, 'bluesky', 'did');
|
||||||
$urls = bluesky_get_urls(Post\Media::removeFromBody($item['body']));
|
$urls = bluesky_get_urls(Post\Media::removeFromBody($item['body']));
|
||||||
$item['body'] = $urls['body'];
|
$item['body'] = $urls['body'];
|
||||||
|
@ -622,10 +639,14 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
|
||||||
|
|
||||||
$record = [
|
$record = [
|
||||||
'text' => $facets['body'],
|
'text' => $facets['body'],
|
||||||
|
'$type' => 'app.bsky.feed.post',
|
||||||
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
|
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
|
||||||
'$type' => 'app.bsky.feed.post'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (!empty($language)) {
|
||||||
|
$record['langs'] = [$language];
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($facets['facets'])) {
|
if (!empty($facets['facets'])) {
|
||||||
$record['facets'] = $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
|
function bluesky_get_urls(string $body): array
|
||||||
{
|
{
|
||||||
// Remove all hashtag and mention links
|
// 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);
|
$body = BBCode::expandVideoLinks($body);
|
||||||
$urls = [];
|
$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
|
// Search for pure links
|
||||||
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
|
if (preg_match_all("/\[url\](https?:.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
|
||||||
foreach ($matches as $match) {
|
foreach ($matches as $match) {
|
||||||
|
@ -742,9 +772,17 @@ function bluesky_get_facets(string $body, array $urls): array
|
||||||
$facet->index->byteStart = $pos;
|
$facet->index->byteStart = $pos;
|
||||||
|
|
||||||
$feature = new stdClass;
|
$feature = new stdClass;
|
||||||
$feature->uri = $url['url'];
|
|
||||||
$type = '$type';
|
$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';
|
$feature->$type = 'app.bsky.richtext.facet#link';
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$facet->features = [$feature];
|
$facet->features = [$feature];
|
||||||
$facets[] = $facet;
|
$facets[] = $facet;
|
||||||
|
@ -983,7 +1021,10 @@ function bluesky_fetch_feed(int $uid, string $feed)
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (array_reverse($data->feed) as $entry) {
|
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]);
|
Logger::debug('Unwanted language detected', ['text' => $entry->post->record->text]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1095,6 +1136,7 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
|
||||||
|
|
||||||
$item['body'] = bluesky_get_text($record);
|
$item['body'] = bluesky_get_text($record);
|
||||||
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
|
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
|
||||||
|
$item['transmitted-languages'] = $record->langs ?? [];
|
||||||
return $item;
|
return $item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1137,8 +1179,13 @@ function bluesky_get_text(stdClass $record): string
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'app.bsky.richtext.facet#tag';
|
||||||
|
$url = DI::baseUrl() . '/search?tag=' . urlencode($feature->tag);
|
||||||
|
$linktext = '#' . $feature->tag;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Logger::notice('Unhandled feature type', ['type' => $feature->$type, 'record' => $record]);
|
Logger::notice('Unhandled feature type', ['type' => $feature->$type, 'feature' => $feature, 'record' => $record]);
|
||||||
break;
|
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
|
function bluesky_get_uri(stdClass $post): string
|
||||||
{
|
{
|
||||||
if (empty($post->cid)) {
|
if (empty($post->cid)) {
|
||||||
Logger::info('Invalid URI', ['post' => $post, 'callstack' => System::callstack(10, 0, true)]);
|
Logger::info('Invalid URI', ['post' => $post]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return $post->uri . ':' . $post->cid;
|
return $post->uri . ':' . $post->cid;
|
||||||
|
@ -1308,7 +1355,7 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $causer, int $lev
|
||||||
return $fallback;
|
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) {
|
if ($causer != 0) {
|
||||||
$cdata = Contact::getPublicAndUserContactID($causer, $uid);
|
$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
|
function bluesky_process_thread(stdClass $thread, int $uid, array $cdata, int $level): string
|
||||||
{
|
{
|
||||||
if (empty($thread->post)) {
|
if (empty($thread->post)) {
|
||||||
Logger::info('Invalid post', ['post' => $thread, 'callstack' => System::callstack(10, 0, true)]);
|
Logger::info('Invalid post', ['post' => $thread]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
$uri = bluesky_get_uri($thread->post);
|
$uri = bluesky_get_uri($thread->post);
|
||||||
|
@ -1438,10 +1485,9 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, bool $update): a
|
||||||
'blocked' => false,
|
'blocked' => false,
|
||||||
'readonly' => false,
|
'readonly' => false,
|
||||||
'pending' => false,
|
'pending' => false,
|
||||||
'baseurl' => BLUESKY_HOST,
|
|
||||||
'url' => $author->did,
|
'url' => $author->did,
|
||||||
'nurl' => $author->did,
|
'nurl' => $author->did,
|
||||||
'alias' => BLUESKY_HOST . '/profile/' . $author->handle,
|
'alias' => BLUESKY_WEB . '/profile/' . $author->handle,
|
||||||
'name' => $author->displayName ?? $author->handle,
|
'name' => $author->displayName ?? $author->handle,
|
||||||
'nick' => $author->handle,
|
'nick' => $author->handle,
|
||||||
'addr' => $author->handle,
|
'addr' => $author->handle,
|
||||||
|
@ -1452,6 +1498,12 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, bool $update): a
|
||||||
return $fields;
|
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]);
|
$data = bluesky_xrpc_get($uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
Logger::debug('Error fetching contact fields', ['uid' => $uid, 'url' => $fields['url']]);
|
Logger::debug('Error fetching contact fields', ['uid' => $uid, 'url' => $fields['url']]);
|
||||||
|
@ -1510,9 +1562,9 @@ function bluesky_get_preferences(int $uid): stdClass
|
||||||
return $data;
|
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)) {
|
if (empty($data)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -1520,6 +1572,33 @@ function bluesky_get_did(int $uid, string $handle): string
|
||||||
return $data->did;
|
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
|
function bluesky_get_token(int $uid): string
|
||||||
{
|
{
|
||||||
$token = DI::pConfig()->get($uid, 'bluesky', 'access_token');
|
$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
|
function bluesky_post(int $uid, string $url, string $params, array $headers): ?stdClass
|
||||||
{
|
{
|
||||||
try {
|
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) {
|
} catch (\Exception $e) {
|
||||||
Logger::notice('Exception on post', ['exception' => $e]);
|
Logger::notice('Exception on post', ['exception' => $e]);
|
||||||
return null;
|
return null;
|
||||||
|
@ -1594,13 +1673,13 @@ function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdCl
|
||||||
$url .= '?' . http_build_query($parameters);
|
$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 {
|
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) {
|
} catch (\Exception $e) {
|
||||||
Logger::notice('Exception on get', ['exception' => $e]);
|
Logger::notice('Exception on get', ['exception' => $e]);
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -17,70 +17,74 @@ msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
|
||||||
#: bluesky.php:314
|
#: bluesky.php:325
|
||||||
msgid ""
|
msgid ""
|
||||||
"You are authenticated to Bluesky. For security reasons the password isn't "
|
"You are authenticated to Bluesky. For security reasons the password isn't "
|
||||||
"stored."
|
"stored."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:314
|
#: bluesky.php:325
|
||||||
msgid "You are not authenticated. Please enter the app password."
|
msgid "You are not authenticated. Please enter the app password."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:318
|
#: bluesky.php:329
|
||||||
msgid "Enable Bluesky Post Addon"
|
msgid "Enable Bluesky Post Addon"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:319
|
#: bluesky.php:330
|
||||||
msgid "Post to Bluesky by default"
|
msgid "Post to Bluesky by default"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:320
|
#: bluesky.php:331
|
||||||
msgid "Import the remote timeline"
|
msgid "Import the remote timeline"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:321
|
#: bluesky.php:332
|
||||||
msgid "Import the pinned feeds"
|
msgid "Import the pinned feeds"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:321
|
#: bluesky.php:332
|
||||||
msgid ""
|
msgid ""
|
||||||
"When activated, Posts will be imported from all the feeds that you pinned in "
|
"When activated, Posts will be imported from all the feeds that you pinned in "
|
||||||
"Bluesky."
|
"Bluesky."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:322
|
#: bluesky.php:333
|
||||||
msgid "Bluesky host"
|
msgid "Personal Data Server"
|
||||||
msgstr ""
|
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"
|
msgid "Bluesky handle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:324
|
#: bluesky.php:335
|
||||||
msgid "Bluesky DID"
|
msgid "Bluesky DID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:324
|
#: bluesky.php:335
|
||||||
msgid ""
|
msgid ""
|
||||||
"This is the unique identifier. It will be fetched automatically, when the "
|
"This is the unique identifier. It will be fetched automatically, when the "
|
||||||
"handle is entered."
|
"handle is entered."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:325
|
#: bluesky.php:336
|
||||||
msgid "Bluesky app password"
|
msgid "Bluesky app password"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:325
|
#: bluesky.php:336
|
||||||
msgid ""
|
msgid ""
|
||||||
"Please don't add your real password here, but instead create a specific app "
|
"Please don't add your real password here, but instead create a specific app "
|
||||||
"password in the Bluesky settings."
|
"password in the Bluesky settings."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:331
|
#: bluesky.php:342
|
||||||
msgid "Bluesky Import/Export"
|
msgid "Bluesky Import/Export"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: bluesky.php:382
|
#: bluesky.php:395
|
||||||
msgid "Post to Bluesky"
|
msgid "Post to Bluesky"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{{include file="field_checkbox.tpl" field=$bydefault}}
|
{{include file="field_checkbox.tpl" field=$bydefault}}
|
||||||
{{include file="field_checkbox.tpl" field=$import}}
|
{{include file="field_checkbox.tpl" field=$import}}
|
||||||
{{include file="field_checkbox.tpl" field=$import_feeds}}
|
{{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=$handle}}
|
||||||
{{include file="field_input.tpl" field=$did}}
|
{{include file="field_input.tpl" field=$did}}
|
||||||
{{include file="field_input.tpl" field=$password}}
|
{{include file="field_input.tpl" field=$password}}
|
33
cld/cld.php
33
cld/cld.php
|
@ -35,35 +35,10 @@ function cld_detect_languages(array &$data)
|
||||||
$original = '';
|
$original = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$detected = $result['language_code'];
|
$detected = DI::l10n()->toISO6391($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';
|
|
||||||
}
|
|
||||||
|
|
||||||
// languages that aren't supported via the base language detection
|
// languages that aren't supported via the base language detection or tend to false detections
|
||||||
if (in_array($detected, ['ceb', 'hmn', 'ht', 'kk', 'ky', 'mg', 'mk', 'ml', 'ny', 'or', 'pa', 'rw', 'su', 'st', 'tg', 'ts', 'xx-Qaai'])) {
|
if ((strlen($detected) == 3) || in_array($detected, ['ht', 'kk', 'ku', 'ky', 'lg', 'mg', 'mk', 'mt', 'ny', 'rw', 'st', 'su', 'tg', 'ts', 'xx'])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +50,7 @@ function cld_detect_languages(array &$data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$available = array_keys(DI::l10n()->convertForLanguageDetection(DI::l10n()->getAvailableLanguages(true)));
|
$available = array_keys(DI::l10n()->getLanguageCodes());
|
||||||
|
|
||||||
if (!in_array($detected, $available)) {
|
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']]);
|
Logger::debug('Unsupported language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
|
||||||
|
|
|
@ -163,7 +163,7 @@ function langfilter_prepare_body_content_filter(&$hook_data)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$lang = $iso639->languageByCode1($iso2);
|
$lang = $iso639->languageByCode1(substr($iso2, 0, 2));
|
||||||
} else {
|
} else {
|
||||||
$opts = $hook_data['item']['postopts'];
|
$opts = $hook_data['item']['postopts'];
|
||||||
if (!$opts) {
|
if (!$opts) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ function smileybutton_jot_tool(string &$body)
|
||||||
for ($x = 0; $x < count($params['texts']); $x++) {
|
for ($x = 0; $x < count($params['texts']); $x++) {
|
||||||
$icon = $params['icons'][$x];
|
$icon = $params['icons'][$x];
|
||||||
$s .= '<td onclick="smileybutton_addsmiley(\'' . $params['texts'][$x] . '\')">' . $icon . '</td>';
|
$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>';
|
$s .= '</tr><tr>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue