Compare commits

..

69 commits

Author SHA1 Message Date
Tobias Diekershoff 5638e7f065 Merge pull request 'Bluesky: Fix probe mistake' (#1560) from heluecht/friendica-addons:bluesky-full-path into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1560
2024-10-30 07:33:34 +01:00
Michael 4165479079 Bluesky: Fix probe mistake 2024-10-30 05:11:50 +00:00
Tobias Diekershoff fca2d609c9 Merge pull request 'Bluesky: Fix following of a contact and adding a post' (#1559) from heluecht/friendica-addons:bluesky-fix-follow into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1559
2024-10-27 08:42:34 +01:00
Michael 8b694fbb4c Bluesky: Fix following of a contact and adding a post 2024-10-27 04:50:45 +00:00
Tobias Diekershoff 5a9dafec70 Merge pull request 'Bluesky: "block" now works / label names are now displayed' (#1558) from heluecht/friendica-addons:bluesky-block into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1558
2024-10-24 19:09:54 +02:00
Michael 586ebe9699 Bluesky: "block" now works / label names are now displayed 2024-10-23 12:14:40 +00:00
Tobias Diekershoff 10bd219bd1 Merge pull request 'Bluesky: Fixes "E_WARNING: Undefined property: stdClass::$post"' (#1557) from heluecht/friendica-addons:warning into 2024.09-rc
Reviewed-on: friendica/friendica-addons#1557
2024-10-20 21:45:55 +02:00
Michael 08c17c9dd4 Bluesky: Fixes "E_WARNING: Undefined property: stdClass::$post" 2024-10-19 07:41:24 +00:00
Tobias Diekershoff feb7722f72 Merge pull request 'Bluesky: New option to complete threads' (#1556) from heluecht/friendica-addons:bluesky-complete-threads into develop
Reviewed-on: friendica/friendica-addons#1556
2024-10-06 15:07:14 +02:00
Michael f8f63532f4 Bluesky: New option to complete threads 2024-10-02 07:54:58 +00:00
Tobias Diekershoff ef37aa60e3 Merge pull request 'Bluesky: Preparation for video posts' (#1554) from heluecht/friendica-addons:hls into develop
Reviewed-on: friendica/friendica-addons#1554
2024-09-17 07:02:47 +02:00
Michael 6f3ba10466 Bluesky: Preparation for video posts 2024-09-17 07:02:47 +02:00
Tobias Diekershoff 778b9e3f61 Merge pull request 'More and updated icons for the smiley pack' (#1555) from heluecht/friendica-addons:loma-patch into develop
Reviewed-on: friendica/friendica-addons#1555
2024-09-17 07:02:03 +02:00
loma-one 10521115c4 More and updated icons for the smiley pack 2024-09-16 21:20:11 +00:00
Tobias Diekershoff 956233ff1d Merge pull request 'Bluesky: Fix for the handling of invalid profiles' (#1553) from heluecht/friendica-addons:bluesky-fix into develop
Reviewed-on: friendica/friendica-addons#1553
2024-09-11 19:42:59 +02:00
Michael 14e1c96775 Bluesky: Fix for the handling of invalid profiles 2024-09-10 10:26:05 +00:00
Tobias Diekershoff 7a7dbb579d Merge pull request 'invidious updated' (#1537) from loma-one/friendica-addons:develop into develop
Reviewed-on: friendica/friendica-addons#1537
2024-09-08 08:50:39 +02:00
loma-one 712edf4236 invidious/invidious.php aktualisiert
Further addresses have been added, which are now redirected.
2024-09-08 08:50:39 +02:00
Tobias Diekershoff 5c0cddfc1d Merge pull request 'unicode_smilies updated' (#1536) from loma-one/friendica-addons:loma-one-patch-1 into develop
Reviewed-on: friendica/friendica-addons#1536
2024-09-08 08:50:12 +02:00
loma-one 3dc77b2102 unicode_smilies/unicode_smilies.php aktualisiert
Addition of the unicode character ‘asterism’ & ‘outlines white star’
2024-09-07 21:04:43 +02:00
Tobias Diekershoff 6c43a14198 Merge pull request '"fetchFull" is replaced by "get"' (#1535) from heluecht/friendica-addons:fetchfull into develop
Reviewed-on: friendica/friendica-addons#1535
2024-09-06 07:22:58 +02:00
Michael 0dfb345f85 "fetchFull" is replaced by "get" 2024-09-06 07:22:58 +02:00
Tobias Diekershoff ab837dfec5 Merge pull request 'Bluesky: probing for bluesky handles' (#1534) from heluecht/friendica-addons:bluesky-handle into develop
Reviewed-on: friendica/friendica-addons#1534
2024-09-06 07:20:55 +02:00
Michael 2f9076bffd Bluesky: probing for bluesky handles 2024-09-04 04:02:30 +00:00
Tobias Diekershoff 454e9834bf Merge pull request 'Bluesky: Improve DID detection for custom PDS' (#1533) from heluecht/friendica-addons:bluesky-pds into develop
Reviewed-on: friendica/friendica-addons#1533
2024-09-02 06:32:54 +02:00
Michael 50930c301d Bluesky: Improve DID detection for custom PDS 2024-09-02 06:32:54 +02:00
Philipp Holzer 3457ab2f3f Merge pull request 'Add safe.directory config' (#1532) from nupplaPhil/friendica-addons:bug/ci into develop
Reviewed-on: friendica/friendica-addons#1532
2024-08-23 20:24:16 +02:00
Philipp Holzer 276c27678f
[CI] Add safe.directory config 2024-08-20 18:07:51 +02:00
Tobias Diekershoff cd95ca1a0a Merge branch 'stable' into develop 2024-08-17 16:55:10 +02:00
Tobias Diekershoff 5c04e7136f Merge branch '2024.06-rc' into stable 2024-08-17 16:54:44 +02:00
heluecht 179382d8a9 Merge pull request 'updated translations' (#1531) from tobias/friendica-addons:20240815-lng into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1531
2024-08-15 07:55:36 +02:00
Tobias Diekershoff a55f80cb39 updated translations 2024-08-15 07:55:36 +02:00
Tobias Diekershoff 4ad7d61893 Merge pull request 'Bluesky/Tumblr: Improved statistics' (#1530) from heluecht/friendica-addons:stats2 into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1530
2024-08-14 08:09:37 +02:00
Michael 4bfdb45e81 Bluesky/Tumblr: Improved statistics 2024-08-12 20:24:09 +00:00
Tobias Diekershoff 4414471100 Merge pull request 'Ratioed: add help text' (#1528) from mexon/friendica-addons:mat/ratioed-help into develop
Reviewed-on: friendica/friendica-addons#1528
2024-08-09 13:58:48 +02:00
Matthew Exon 46a55f13f7 Ratioed: add help text 2024-08-09 13:58:48 +02:00
Tobias Diekershoff a97cccb6b2 Merge pull request 'Statistics: inbound / outbound for Tumblr and Bluesky' (#1529) from heluecht/friendica-addons:stats into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1529
2024-08-09 13:55:51 +02:00
Michael c0535db742 Statistics: inbound / outbound for Tumblr and Bluesky 2024-08-09 13:55:51 +02:00
Tobias Diekershoff 0c04b086cb Merge pull request 'Remove old version conversion code' (#1526) from mexon/friendica-addons:mat/remove-conversion into develop
Reviewed-on: friendica/friendica-addons#1526
2024-07-29 19:17:39 +02:00
Matthew Exon 589cf712cc Remove old version conversion code 2024-07-20 13:00:07 +02:00
heluecht ce53e48cb2 Merge pull request 'More comprehensible check for root user contact' (#1525) from mexon/friendica-addons:mat/mailstream-clarify-log into develop
Reviewed-on: friendica/friendica-addons#1525
2024-07-20 11:57:32 +02:00
Matthew Exon f3db763c59 More comprehensible check for root user contact 2024-07-14 18:50:56 +02:00
heluecht 4e5998c73d Merge pull request 'Mailstream: streamline log lines' (#1522) from mexon/friendica-addons:mat/mailstream-log into develop
Reviewed-on: friendica/friendica-addons#1522
2024-07-14 18:10:10 +02:00
Tobias Diekershoff b0a95ca2d2 Merge pull request 'fix for curweather' (#1521) from haheute/friendica-addons:fix-curweather into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1521
2024-06-28 18:27:26 +02:00
Hannes Heute b2108c7a4c fix for curweather 2024-06-27 11:44:15 +02:00
Hypolite Petovan abca07b29d Merge pull request 'Add Relatica to blockbot fediverse client list' (#1520) from hankg/friendica-addons:2024.06-rc into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1520
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-06-25 01:07:09 +02:00
hankg 14e7413eb2 Add Relatica to blockbot fediverse client list 2024-06-24 22:20:35 +02:00
Hypolite Petovan 39567cf701 Merge pull request 'translation updates' (#1517) from tobias/friendica-addons:20240621-lng into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1517
2024-06-22 03:40:13 +02:00
Tobias Diekershoff 2789e880dc translation updates
AR, CS, DE, IT, PL, SV for various addons
2024-06-21 20:38:42 +02:00
Tobias Diekershoff 1556ebfb33 Merge pull request 'Leave failed image URLs in place' (#1516) from mexon/friendica-addons:mat/mailstream-fetch-failure into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1516
2024-06-17 06:54:06 +02:00
Matthew Exon 3e1b98d5d9 Leave failed image URLs in place 2024-06-17 06:54:06 +02:00
Tobias Diekershoff ed07c987a6 Merge pull request 'JS Uploader: "jpg" added to the list of allowed file extensions' (#1515) from heluecht/friendica-addons:jsupload into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1515
2024-06-16 16:47:11 +02:00
Michael af868f45ab JS Uploader: "jpg" added to the list of allowed file extensions 2024-06-16 14:35:19 +00:00
Tobias Diekershoff 7f0cf2527c Merge pull request 'Tumblr: Add link for quoted post' (#1514) from heluecht/friendica-addons:tumblr-quoted into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1514
2024-06-16 09:37:58 +02:00
Michael 9525259fc8 Tumblr: Add link for quoted post 2024-06-15 13:51:47 +00:00
Tobias Diekershoff f7ca152754 Merge pull request 'Bluesky: Handle API error when fetching feeds' (#1513) from heluecht/friendica-addons:bluesky into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1513
2024-06-13 07:19:43 +02:00
Michael 6f56932f12 Bluesky: Handle API error when fetching feeds 2024-06-13 04:32:00 +00:00
Tobias Diekershoff b6f2e7dd50 Merge pull request 'Bluesky: more logging added' (#1512) from heluecht/friendica-addons:bluesky-logging into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1512
2024-06-10 08:00:39 +02:00
Michael fa16adccaf Bluesky: more logging added 2024-06-10 05:43:35 +00:00
Tobias Diekershoff 252f3e222a Merge pull request 'Bluesky: Fix overwritten handle when "friendica handles" is selected' (#1511) from heluecht/friendica-addons:blockbot-fixes into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1511
2024-06-10 06:59:58 +02:00
Michael 231d830db0 Bluesky: Fix overwritten handle when "friendica handles" is selected 2024-06-09 20:41:18 +00:00
Tobias Diekershoff 27e362213f Merge pull request 'Blockbot: Logging of AP actors' (#1510) from heluecht/friendica-addons:ap-actor-logging into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1510
2024-06-07 07:00:33 +02:00
Michael 734d35d22b Blockbot: Logging of AP actors 2024-06-07 04:19:53 +00:00
Hypolite Petovan 722fdc07fb Merge pull request 'Bluesky: Fix error on restricted posts / improve performance' (#1509) from heluecht/friendica-addons:bluesky-fix into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1509
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-06-06 16:29:24 +02:00
Michael 77c471ab4d Bluesky: Fix error on restricted posts / improve performance 2024-06-06 16:29:24 +02:00
heluecht bac665864e Merge pull request 'FR translation updates - nsfw, securemail, tumblr' (#1508) from tobias/friendica-addons:20240603-fr into 2024.06-rc
Reviewed-on: friendica/friendica-addons#1508
2024-06-05 05:43:24 +02:00
Tobias Diekershoff c7f4d183b1 FR translation updates - nsfw, securemail, tumblr 2024-06-03 08:13:08 +02:00
Hypolite Petovan 010261c1dc Merge pull request '[Hotfix] Fix REPO_URL for woodpecker' (#1490) from nupplaPhil/friendica-addons:bug/repo_link into stable
Reviewed-on: friendica/friendica-addons#1490
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-03-22 16:03:06 +01:00
Philipp Holzer 3f26f9785e
[Hotfix] Fix REPO_URL for woodpecker 2024-03-22 15:53:47 +01:00
114 changed files with 1259 additions and 716 deletions

View file

@ -4,6 +4,9 @@ pipeline:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
when:

View file

@ -9,6 +9,9 @@ pipeline:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
when:

View file

@ -4,6 +4,9 @@ pipeline:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
when:

View file

@ -21,6 +21,9 @@ pipeline:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
clone_friendica_addon:

View file

@ -9,6 +9,9 @@ pipeline:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
when:

View file

@ -5,7 +5,7 @@
#
# Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2018
# Sylke Vicious <silkevicious@gmail.com>, 2021
# Sylke Vicious <silkevicious@gmail.com>, 2023
#
#, fuzzy
msgid ""
@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-05-11 08:54-0400\n"
"PO-Revision-Date: 2018-05-24 06:41+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2023\n"
"Language-Team: Italian (https://app.transifex.com/Friendica/teams/12172/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -125,7 +125,7 @@ msgstr "Annulla"
#: advancedcontentfilter.php:295
msgid "This addon requires this node having at least one post"
msgstr ""
msgstr "Questo addon richiede che questo nodo abbia almeno un messaggio"
#: advancedcontentfilter.php:325 advancedcontentfilter.php:336
#: advancedcontentfilter.php:347 advancedcontentfilter.php:383

View file

@ -27,6 +27,7 @@ $a->strings['Add new rule'] = 'Aggiungi nuova regola';
$a->strings['Rule Name'] = 'Nome Regola';
$a->strings['Rule Expression'] = 'Espressione Regola';
$a->strings['Cancel'] = 'Annulla';
$a->strings['This addon requires this node having at least one post'] = 'Questo addon richiede che questo nodo abbia almeno un messaggio';
$a->strings['You must be logged in to use this method'] = 'Devi essere autenticato per usare questo metodo';
$a->strings['Invalid form security token, please refresh the page.'] = 'Token di sicurezza invalido, aggiorna la pagina.';
$a->strings['The rule name and expression are required.'] = 'Il nome e l\'espressione della regola sono richiesti.';

View file

@ -15,6 +15,7 @@ use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Network\HTTPException\ForbiddenException;
use Friendica\Util\HTTPSignature;
use Friendica\Util\Network;
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
@ -76,6 +77,8 @@ function blockbot_init_1()
return;
}
blockbot_log_activitypub($_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT']);
if (blockbot_is_crawler($parts)) {
Logger::debug('Crawler found - reject', $logdata);
blockbot_reject();
@ -169,7 +172,7 @@ function blockbot_init_1()
function blockbot_save($database, $userAgent)
{
if (!DI::config()->get('blockbot', 'training') || !function_exists('dba_open')) {
if (!DI::config()->get('blockbot', 'logging') || !function_exists('dba_open')) {
return;
}
@ -181,6 +184,36 @@ function blockbot_save($database, $userAgent)
dba_close($resource);
}
function blockbot_log_activitypub(string $url, string $agent)
{
if (!DI::config()->get('blockbot', 'logging')) {
return;
}
$bot = ['/.well-known/nodeinfo', '/nodeinfo/2.0', '/nodeinfo/1.0'];
if (in_array($url, $bot)) {
blockbot_save('activitypub-stats', $agent);
}
$bot = ['/api/v1/instance', '/api/v2/instance', '/api/v1/instance/extended_description',
'/api/v1/instance/peers'];
if (in_array($url, $bot)) {
blockbot_save('activitypub-api-stats', $agent);
}
if (substr($url, 0, 6) == '/api/v') {
blockbot_save('activitypub-api', $agent);
}
if (($_SERVER['REQUEST_METHOD'] == 'POST') && in_array('inbox', explode('/', parse_url($url, PHP_URL_PATH)))) {
blockbot_save('activitypub-inbox-agents', $agent);
}
if (!empty($_SERVER['HTTP_SIGNATURE']) && !empty(HTTPSignature::getSigner('', $_SERVER))) {
blockbot_save('activitypub-signature-agents', $agent);
}
}
function blockbot_check_login_attempt(string $url, array $logdata)
{
if (in_array(trim(parse_url($url, PHP_URL_PATH), '/'), ['login', 'lostpass', 'register'])) {
@ -466,6 +499,7 @@ function blockbot_is_fediverse_client(array $parts): bool
'megalodonandroid', 'fedilab', 'mastodonapp', 'toot!', 'intravnews',
'pixeldroid', 'greatnews', 'protopage', 'newsfox', 'vienna', 'wp-urldetails', 'husky',
'activitypub-go-http-client', 'mobilesafari', 'mastodon-ios', 'mastodonpy', 'techniverse',
'relatica',
];
foreach ($parts as $part) {

View file

@ -1,7 +1,7 @@
<?php
/**
* Name: Bluesky Connector
* Description: Post to Bluesky
* Description: Post to Bluesky, import timelines and feeds
* Version: 1.1
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*
@ -10,6 +10,8 @@
* - Outgoing mentions
*
* At some point in time:
* - post videos
* - direct messages
* - Sending Quote shares https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecord and https://atproto.com/lexicons/app-bsky-embed#appbskyembedrecordwithmedia
*
* Possibly not possible:
@ -45,10 +47,12 @@ use Friendica\Model\Tag;
use Friendica\Model\User;
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
use Friendica\Object\Image;
use Friendica\Protocol\Activity;
use Friendica\Protocol\Relay;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\Strings;
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
@ -68,6 +72,7 @@ const BLUEKSY_STATUS_TOKEN_FAIL = 13;
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
const BLUESKY_HOSTNAME = 'bsky.social'; // Host name to be added to the handle if incomplete
function bluesky_install()
{
@ -128,8 +133,13 @@ function bluesky_probe_detect(array &$hookData)
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
$did = $hookData['uri'];
} elseif (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $hookData['uri'], $matches)) {
$did = bluesky_get_did($matches[1]);
} elseif (parse_url($hookData['uri'], PHP_URL_PATH) == $hookData['uri'] && strpos($hookData['uri'], '@') === false) {
$did = bluesky_get_did($hookData['uri'], $pconfig['uid']);
if (empty($did)) {
return;
}
} elseif (Network::isValidHttpUrl($hookData['uri'])) {
$did = bluesky_get_did_by_profile($hookData['uri'], $pconfig['uid']);
if (empty($did)) {
return;
}
@ -143,23 +153,18 @@ function bluesky_probe_detect(array &$hookData)
}
$data = bluesky_xrpc_get($pconfig['uid'], 'app.bsky.actor.getProfile', ['actor' => $did]);
if (empty($data)) {
if (empty($data) || empty($data->did)) {
return;
}
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], false);
$hookData['result']['baseurl'] = bluesky_get_pds($did);
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], true);
// Preparing probe data. This differs slightly from the contact array
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
$hookData['result']['photo'] = $data->avatar ?? '';
$hookData['result']['header'] = $data->banner ?? '';
$hookData['result']['batch'] = '';
$hookData['result']['notify'] = '';
$hookData['result']['poll'] = '';
$hookData['result']['poco'] = '';
$hookData['result']['pubkey'] = '';
$hookData['result']['priority'] = 0;
$hookData['result']['guid'] = '';
}
@ -180,17 +185,17 @@ function bluesky_item_by_link(array &$hookData)
return;
}
$did = bluesky_get_did($matches[1]);
$did = bluesky_get_did($matches[1], $hookData['uid']);
if (empty($did)) {
return;
}
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'handle' => $matches[1], 'did' => $did, 'cid' => $matches[2]]);
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'did' => $did, 'cid' => $matches[2]]);
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[2];
$uri = bluesky_fetch_missing_post($uri, $hookData['uid'], $hookData['uid'], Item::PR_FETCHED, 0, 0, 0);
Logger::debug('Got post', ['profile' => $matches[1], 'cid' => $matches[2], 'result' => $uri]);
Logger::debug('Got post', ['did' => $did, 'cid' => $matches[2], 'result' => $uri]);
if (!empty($uri)) {
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
if (!empty($item['id'])) {
@ -273,14 +278,12 @@ function bluesky_block(array &$hook_data)
return;
}
Logger::debug('Check if contact is bluesky', ['data' => $hook_data]);
$contact = DBA::selectFirst('contact', [], ['network' => Protocol::BLUESKY, 'url' => $hook_data['url'], 'uid' => [0, $hook_data['uid']]]);
if (empty($contact)) {
if ($hook_data['contact']['network'] != Protocol::BLUESKY) {
return;
}
$record = [
'subject' => $contact['url'],
'subject' => $hook_data['contact']['url'],
'createdAt' => DateTimeFormat::utcNow(DateTimeFormat::ATOM),
'$type' => 'app.bsky.graph.block'
];
@ -293,9 +296,9 @@ function bluesky_block(array &$hook_data)
$activity = bluesky_xrpc_post($hook_data['uid'], 'com.atproto.repo.createRecord', $post);
if (!empty($activity->uri)) {
$cdata = Contact::getPublicAndUserContactID($hook_data['contact']['id'], $hook_data['uid']);
if (!empty($cdata['user'])) {
Contact::remove($cdata['user']);
$ucid = Contact::getUserContactId($hook_data['contact']['id'], $hook_data['uid']);
if ($ucid) {
Contact::remove($ucid);
}
Logger::debug('Successfully blocked contact', ['url' => $hook_data['contact']['url'], 'uri' => $activity->uri]);
}
@ -343,36 +346,41 @@ function bluesky_settings(array &$data)
return;
}
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? false;
$pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId());
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
$import = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import') ?? false;
$import_feeds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds') ?? false;
$custom_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle') ?? false;
$enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post') ?? false;
$def_enabled = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'post_by_default') ?? false;
$pds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'pds');
$handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'handle');
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId());
$token = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'access_token');
$import = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import') ?? false;
$import_feeds = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'import_feeds') ?? false;
$complete_threads = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'complete_threads') ?? false;
$custom_handle = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle') ?? false;
if (DI::config()->get('bluesky', 'friendica_handles')) {
$self = User::getById(DI::userSession()->getLocalUserId(), ['nickname']);
$handle = $self['nickname'] . '.' . DI::baseUrl()->getHost();
$friendica_handle = ['bluesky_friendica_handle', DI::l10n()->t('Allow to use %s as your Bluesky handle.', $handle), $custom_handle, DI::l10n()->t('When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select "No DNS Panel". Then select "Verify Text File".', $handle, $handle)];
$host_handle = $self['nickname'] . '.' . DI::baseUrl()->getHost();
$friendica_handle = ['bluesky_friendica_handle', DI::l10n()->t('Allow to use %s as your Bluesky handle.', $host_handle), $custom_handle, DI::l10n()->t('When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select "No DNS Panel". Then select "Verify Text File".', $host_handle, $host_handle)];
if ($custom_handle) {
$handle = $host_handle;
}
} else {
$friendica_handle = [];
}
$t = Renderer::getMarkupTemplate('connector_settings.tpl', 'addon/bluesky/');
$html = Renderer::replaceMacros($t, [
'$enable' => ['bluesky', DI::l10n()->t('Enable Bluesky Post Addon'), $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_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.')],
'$custom_handle' => $friendica_handle,
'$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.")],
'$status' => bluesky_get_status($handle, $did, $pds, $token),
'$enable' => ['bluesky', DI::l10n()->t('Enable Bluesky Post Addon'), $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_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.')],
'$complete_threads' => ['bluesky_complete_threads', DI::l10n()->t('Complete the threads'), $complete_threads, DI::l10n()->t('When activated, the system fetches additional replies for the posts in the timeline. This leads to more complete threads.')],
'$custom_handle' => $friendica_handle,
'$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, '', '', $custom_handle ? '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.")],
'$status' => bluesky_get_status($handle, $did, $pds, $token),
]);
$data = [
@ -440,7 +448,8 @@ function bluesky_settings_post(array &$b)
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']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle', intval($_POST['bluesky_friendica_handle']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'complete_threads', intval($_POST['bluesky_complete_threads']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'bluesky', 'friendica_handle', intval($_POST['bluesky_friendica_handle'] ?? false));
if (!empty($handle)) {
$did = bluesky_get_user_did(DI::userSession()->getLocalUserId(), empty($old_did) || $old_handle != $handle);
@ -510,9 +519,10 @@ function bluesky_cron()
$abandon_limit = date(DateTimeFormat::MYSQL, time() - $abandon_days * 86400);
$pconfigs = DBA::selectToArray('pconfig', [], ['cat' => 'bluesky', 'k' => 'import', 'v' => true]);
$pconfigs = DBA::selectToArray('pconfig', [], ["`cat` = ? AND `k` IN (?, ?) AND `v`", 'bluesky', 'import', 'import_feeds']);
foreach ($pconfigs as $pconfig) {
if (empty(bluesky_get_user_did($pconfig['uid']))) {
Logger::debug('User has got no valid DID', ['uid' => $pconfig['uid']]);
continue;
}
@ -524,19 +534,27 @@ function bluesky_cron()
}
// Refresh the token now, so that it doesn't need to be refreshed in parallel by the following workers
Logger::debug('Refresh the token', ['uid' => $pconfig['uid']]);
bluesky_get_token($pconfig['uid']);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_notifications.php', $pconfig['uid'], $last);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid'], $last);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_notifications.php', $pconfig['uid']);
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import')) {
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid']);
}
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import_feeds')) {
Logger::debug('Fetch feeds for user', ['uid' => $pconfig['uid']]);
$feeds = bluesky_get_feeds($pconfig['uid']);
foreach ($feeds as $feed) {
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed, $last);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed);
}
}
Logger::debug('Polling done for user', ['uid' => $pconfig['uid']]);
}
Logger::notice('Polling done for all users');
DI::keyValue()->set('bluesky_last_poll', time());
$last_clean = DI::keyValue()->get('bluesky_last_clean');
if (empty($last_clean) || ($last_clean + 86400 < time())) {
Logger::notice('Start contact cleanup');
@ -550,8 +568,6 @@ function bluesky_cron()
}
Logger::notice('cron_end');
DI::keyValue()->set('bluesky_last_poll', time());
}
function bluesky_hook_fork(array &$b)
@ -697,7 +713,7 @@ function bluesky_create_activity(array $item, stdClass $parent = null)
}
$activity = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
if (empty($activity)) {
if (empty($activity->uri)) {
return;
}
Logger::debug('Activity done', ['return' => $activity]);
@ -781,7 +797,7 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
];
$parent = bluesky_xrpc_post($uid, 'com.atproto.repo.createRecord', $post);
if (empty($parent)) {
if (empty($parent->uri)) {
if ($part == 0) {
Worker::defer();
}
@ -959,11 +975,12 @@ function bluesky_upload_blob(int $uid, array $photo): ?stdClass
Logger::info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
$data = bluesky_post($uid, '/xrpc/com.atproto.repo.uploadBlob', $content, ['Content-type' => $photo['type'], 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
if (empty($data)) {
if (empty($data) || empty($data->blob)) {
Logger::info('Uploading failed', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
return null;
}
Item::incrementOutbound(Protocol::BLUESKY);
Logger::debug('Uploaded blob', ['return' => $data, 'uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
return $data->blob;
}
@ -979,7 +996,7 @@ function bluesky_delete_post(string $uri, int $uid)
Logger::debug('Deleted', ['parts' => $parts]);
}
function bluesky_fetch_timeline(int $uid, int $last_poll)
function bluesky_fetch_timeline(int $uid)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getTimeline');
if (empty($data)) {
@ -990,15 +1007,44 @@ function bluesky_fetch_timeline(int $uid, int $last_poll)
return;
}
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
foreach (array_reverse($data->feed) as $entry) {
$causer = bluesky_get_contact($entry->post->author, 0, $uid);
if (!empty($entry->reply)) {
if (!empty($entry->reply->root)) {
bluesky_complete_post($entry->reply->root, $uid, Item::PR_COMMENT, $causer['id'], $last_poll);
}
if (!empty($entry->reply->parent)) {
bluesky_complete_post($entry->reply->parent, $uid, Item::PR_COMMENT, $causer['id'], $last_poll);
}
}
bluesky_process_post($entry->post, $uid, $uid, Item::PR_NONE, 0, 0, $last_poll);
if (!empty($entry->reason)) {
bluesky_process_reason($entry->reason, bluesky_get_uri($entry->post), $uid);
}
}
}
// @todo Support paging
// [cursor] => 1684670516000::bafyreidq3ilwslmlx72jf5vrk367xcc63s6lrhzlyup2bi3zwcvso6w2vi
function bluesky_complete_post(stdClass $post, int $uid, int $post_reason, int $causer, int $last_poll): int
{
$complete = DI::pConfig()->get($uid, 'bluesky', 'complete_threads');
$existing_uri = bluesky_fetch_post(bluesky_get_uri($post), $uid);
if (!empty($existing_uri)) {
$comments = Post::countPosts(['thr-parent' => $existing_uri, 'gravity' => Item::GRAVITY_COMMENT]);
if (($post->replyCount <= $comments) || !$complete) {
return bluesky_fetch_uri_id($existing_uri, $uid);
}
}
if ($complete) {
$uri = bluesky_fetch_missing_post($post->uri, $uid, $uid, $post_reason, $causer, 0, $last_poll, '', true);
$uri_id = bluesky_fetch_uri_id($uri, $uid);
} else {
$uri_id = bluesky_process_post($post, $uid, $uid, $post_reason, $causer, 0, $last_poll);
}
return $uri_id;
}
function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
@ -1037,17 +1083,21 @@ function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
$item['owner-link'] = $item['author-link'];
$item['owner-avatar'] = $item['author-avatar'];
if (Item::insert($item)) {
$cdata = Contact::getPublicAndUserContactID($contact['id'], $uid);
Item::update(['post-reason' => Item::PR_ANNOUNCEMENT, 'causer-id' => $cdata['public']], ['uri' => $uri, 'uid' => $uid]);
$pcid = Contact::getPublicContactId($contact['id'], $uid);
Item::update(['post-reason' => Item::PR_ANNOUNCEMENT, 'causer-id' => $pcid], ['uri' => $uri, 'uid' => $uid]);
}
}
function bluesky_fetch_notifications(int $uid, int $last_poll)
function bluesky_fetch_notifications(int $uid)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.notification.listNotifications');
if (empty($data->notifications)) {
return;
}
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
foreach ($data->notifications as $notification) {
$uri = bluesky_get_uri($notification);
if (Post::exists(['uri' => $uri, 'uid' => $uid]) || Post::exists(['extid' => $uri, 'uid' => $uid])) {
@ -1057,7 +1107,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
Logger::debug('Process notification', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
switch ($notification->reason) {
case 'like':
$item = bluesky_get_header($notification, $uri, $uid, $uid);
$item = bluesky_get_header($notification, $uri, $uid, $uid, $last_poll);
$item['gravity'] = Item::GRAVITY_ACTIVITY;
$item['body'] = $item['verb'] = Activity::LIKE;
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
@ -1071,7 +1121,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
break;
case 'repost':
$item = bluesky_get_header($notification, $uri, $uid, $uid);
$item = bluesky_get_header($notification, $uri, $uid, $uid, $last_poll);
$item['gravity'] = Item::GRAVITY_ACTIVITY;
$item['body'] = $item['verb'] = Activity::ANNOUNCE;
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
@ -1114,7 +1164,7 @@ function bluesky_fetch_notifications(int $uid, int $last_poll)
}
}
function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
function bluesky_fetch_feed(int $uid, string $feed)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeed', ['feed' => $feed]);
if (empty($data)) {
@ -1125,8 +1175,11 @@ function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
return;
}
$last_post = DBA::selectFirst('post-thread-user', ['received'], ['network' => Protocol::BLUESKY, 'uid' => $uid], ['order' => ['received' => true]]);
$last_poll = !empty($last_post['received']) ? strtotime($last_post['received']) : 0;
$feeddata = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeedGenerator', ['feed' => $feed]);
if (!empty($feeddata)) {
if (!empty($feeddata) && !empty($feeddata->view)) {
$feedurl = $feeddata->view->uri;
$feedname = $feeddata->view->displayName;
} else {
@ -1139,10 +1192,11 @@ function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
$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', ['languages' => $languages, 'text' => $entry->post->record->text]);
continue;
}
$uri_id = bluesky_process_post($entry->post, $uid, $uid, Item::PR_TAG, 0, 0, $last_poll);
$causer = bluesky_get_contact($entry->post->author, 0, $uid);
$uri_id = bluesky_complete_post($entry->post, $uid, Item::PR_TAG, $causer['id'], $last_poll);
if (!empty($uri_id)) {
$stored = Post\Category::storeFileByURIId($uri_id, $uid, Post\Category::SUBCRIPTION, $feedname, $feedurl);
Logger::debug('Stored tag subscription for user', ['uri-id' => $uri_id, 'uid' => $uid, 'name' => $feedname, 'url' => $feedurl, 'stored' => $stored]);
@ -1170,7 +1224,7 @@ function bluesky_process_post(stdClass $post, int $uid, int $fetch_uid, int $pos
Logger::debug('Importing post', ['uid' => $uid, 'indexedAt' => $post->indexedAt, 'uri' => $post->uri, 'cid' => $post->cid, 'root' => $post->record->reply->root ?? '']);
$item = bluesky_get_header($post, $uri, $uid, $fetch_uid);
$item = bluesky_get_header($post, $uri, $uid, $fetch_uid, $last_poll);
$item = bluesky_get_content($item, $post->record, $uri, $uid, $fetch_uid, $level, $last_poll);
if (empty($item)) {
return 0;
@ -1194,7 +1248,7 @@ function bluesky_process_post(stdClass $post, int $uid, int $fetch_uid, int $pos
return bluesky_fetch_uri_id($uri, $uid);
}
function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_uid): array
function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_uid, int $last_poll = 0): array
{
$parts = bluesky_get_uri_parts($uri);
if (empty($post->author) || empty($post->cid) || empty($parts->rkey)) {
@ -1207,6 +1261,7 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
'wall' => false,
'uri' => $uri,
'guid' => $post->cid,
'received' => DateTimeFormat::utc($post->indexedAt, DateTimeFormat::MYSQL),
'private' => Item::UNLISTED,
'verb' => Activity::POST,
'contact-id' => $contact['id'],
@ -1217,7 +1272,15 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
'source' => json_encode($post),
];
if (($last_poll != 0) && strtotime($item['received']) < $last_poll) {
unset($item['received']);
}
$account = Contact::selectFirstAccountUser(['pid'], ['id' => $contact['id']]);
$item['author-id'] = $account['pid'];
$item['uri-id'] = ItemURI::getIdByURI($uri);
$item['owner-id'] = $item['author-id'];
$item['owner-name'] = $item['author-name'];
$item['owner-link'] = $item['author-link'];
$item['owner-avatar'] = $item['author-avatar'];
@ -1232,6 +1295,7 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
// When "ver" is set to "1" it was flagged by some automated process.
if (empty($label->ver)) {
$item['sensitive'] = true;
$item['content-warning'] = $label->val ?? '';
Logger::debug('Sensitive content', ['uri-id' => $item['uri-id'], 'label' => $label]);
}
}
@ -1311,10 +1375,6 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
$item['created'] = DateTimeFormat::utc($record->createdAt, DateTimeFormat::MYSQL);
$item['transmitted-languages'] = $record->langs ?? [];
if (($last_poll != 0) && strtotime($item['created']) > $last_poll) {
$item['received'] = $item['created'];
}
return $item;
}
@ -1392,6 +1452,19 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
}
break;
case 'app.bsky.embed.video#view':
$media = [
'uri-id' => $item['uri-id'],
'type' => Post\Media::HLS,
'url' => $embed->playlist,
'preview' => $embed->thumbnail,
'description' => $embed->alt ?? '',
'height' => $embed->aspectRatio->height,
'width' => $embed->aspectRatio->width,
];
Post\Media::insert($media);
break;
case 'app.bsky.embed.external#view':
$media = [
'uri-id' => $item['uri-id'],
@ -1491,10 +1564,10 @@ function bluesky_get_uri_parts(string $uri): ?stdClass
return $class;
}
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $post_reason, int $causer, int $level, int $last_poll, string $fallback = ''): string
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $post_reason, int $causer, int $level, int $last_poll, string $fallback = '', bool $always_fetch = false): string
{
$fetched_uri = bluesky_fetch_post($uri, $uid);
if (!empty($fetched_uri)) {
if (!$always_fetch && !empty($fetched_uri)) {
return $fetched_uri;
}
@ -1514,7 +1587,7 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $
Logger::debug('Fetch missing post', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.feed.getPostThread', ['uri' => $fetch_uri]);
if (empty($data)) {
if (empty($data) || empty($data->thread)) {
Logger::info('Thread was not fetched', ['level' => $level, 'uid' => $uid, 'uri' => $uri, 'fallback' => $fallback]);
return $fallback;
}
@ -1522,13 +1595,34 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $
Logger::debug('Reply count', ['level' => $level, 'uid' => $uid, 'uri' => $uri]);
if ($causer != 0) {
$cdata = Contact::getPublicAndUserContactID($causer, $uid);
$causer = $cdata['public'] ?? 0;
$causer = Contact::getPublicContactId($causer, $uid);
}
if (!empty($data->thread->parent)) {
$parents = bluesky_fetch_parents($data->thread->parent, $uid);
foreach ($parents as $parent) {
$uri_id = bluesky_process_post($parent, $uid, $fetch_uid, Item::PR_FETCHED, $causer, $level, $last_poll);
Logger::debug('Parent created', ['uri-id' => $uri_id]);
}
}
return bluesky_process_thread($data->thread, $uid, $fetch_uid, $post_reason, $causer, $level, $last_poll);
}
function bluesky_fetch_parents(stdClass $parent, int $uid, array $parents = []): array
{
if (!empty($parent->parent)) {
$parents = bluesky_fetch_parents($parent->parent, $uid, $parents);
}
if (!empty($parent->post) && empty(bluesky_fetch_post(bluesky_get_uri($parent->post), $uid))) {
$parents[] = $parent->post;
}
return $parents;
}
function bluesky_fetch_post(string $uri, int $uid): string
{
if (Post::exists(['uri' => $uri, 'uid' => [$uid, 0]])) {
@ -1592,7 +1686,7 @@ function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, int
function bluesky_get_contact(stdClass $author, int $uid, int $fetch_uid): array
{
$condition = ['network' => Protocol::BLUESKY, 'uid' => 0, 'url' => $author->did];
$condition = ['network' => Protocol::BLUESKY, 'uid' => 0, 'nurl' => $author->did];
$contact = Contact::selectFirst(['id', 'updated'], $condition);
$update = empty($contact) || $contact['updated'] < DateTimeFormat::utc('now -24 hours');
@ -1610,7 +1704,7 @@ function bluesky_get_contact(stdClass $author, int $uid, int $fetch_uid): array
}
if ($uid != 0) {
$condition = ['network' => Protocol::BLUESKY, 'uid' => $uid, 'url' => $author->did];
$condition = ['network' => Protocol::BLUESKY, 'uid' => $uid, 'nurl' => $author->did];
$contact = Contact::selectFirst(['id', 'rel', 'uid'], $condition);
if (!isset($fields['rel']) && isset($contact['rel'])) {
@ -1663,10 +1757,14 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, int $fetch_uid,
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_get(BLUESKY_DIRECTORY . '/' . $author->did);
if (!empty($data)) {
$fields['baseurl'] = bluesky_get_pds('', $data);
if (!empty($fields['baseurl'])) {
GServer::check($fields['baseurl'], Protocol::BLUESKY);
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
}
$fields['pubkey'] = bluesky_get_public_key('', $data);
}
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
@ -1705,6 +1803,9 @@ function bluesky_get_feeds(int $uid): array
{
$type = '$type';
$preferences = bluesky_get_preferences($uid);
if (empty($preferences) || empty($preferences->preferences)) {
return [];
}
foreach ($preferences->preferences as $preference) {
if ($preference->$type == 'app.bsky.actor.defs#savedFeedsPref') {
return $preference->pinned ?? [];
@ -1713,7 +1814,7 @@ function bluesky_get_feeds(int $uid): array
return [];
}
function bluesky_get_preferences(int $uid): stdClass
function bluesky_get_preferences(int $uid): ?stdClass
{
$cachekey = 'bluesky:preferences:' . $uid;
$data = DI::cache()->get($cachekey);
@ -1722,11 +1823,63 @@ function bluesky_get_preferences(int $uid): stdClass
}
$data = bluesky_xrpc_get($uid, 'app.bsky.actor.getPreferences');
if (empty($data)) {
return null;
}
DI::cache()->set($cachekey, $data, Duration::HOUR);
return $data;
}
function bluesky_get_did_by_profile(string $url, int $uid): string
{
if (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $url, $matches)) {
$did = bluesky_get_did($matches[1], $uid);
if (!empty($did)) {
return $did;
}
}
try {
$curlResult = DI::httpClient()->get($url, HttpClientAccept::HTML, [HttpClientOptions::REQUEST => HttpClientRequest::CONTACTINFO]);
} catch (\Throwable $th) {
return '';
}
if (!$curlResult->isSuccess()) {
return '';
}
$profile = $curlResult->getBodyString();
if (empty($profile)) {
return '';
}
$doc = new DOMDocument();
try {
@$doc->loadHTML($profile);
} catch (\Throwable $th) {
return '';
}
$xpath = new DOMXPath($doc);
$list = $xpath->query('//p[@id]');
foreach ($list as $node) {
foreach ($node->attributes as $attribute) {
if ($attribute->name == 'id') {
$ids[$attribute->value] = $node->textContent;
}
}
}
if (empty($ids['bsky_handle']) || empty($ids['bsky_did'])) {
return '';
}
if (!bluesky_valid_did($ids['bsky_did'], $ids['bsky_handle'])) {
Logger::notice('Invalid DID', ['handle' => $ids['bsky_handle'], 'did' => $ids['bsky_did']]);
return '';
}
return $ids['bsky_did'];
}
function bluesky_get_did_by_wellknown(string $handle): string
{
$curlResult = DI::httpClient()->get('http://' . $handle . '/.well-known/atproto-did');
@ -1736,7 +1889,6 @@ function bluesky_get_did_by_wellknown(string $handle): string
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
return '';
}
Logger::debug('Got DID by wellknown', ['handle' => $handle, 'did' => $did]);
return $did;
}
return '';
@ -1755,32 +1907,55 @@ function bluesky_get_did_by_dns(string $handle): string
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
return '';
}
Logger::debug('Got DID by DNS', ['handle' => $handle, 'did' => $did]);
return $did;
}
}
return '';
}
function bluesky_get_did(string $handle): string
function bluesky_get_did(string $handle, int $uid): string
{
// Deactivated at the moment, since it isn't reliable by now
//$did = bluesky_get_did_by_dns($handle);
//if ($did != '') {
// return $did;
//}
//$did = bluesky_get_did_by_wellknown($handle);
//if ($did != '') {
// return $did;
//}
$data = bluesky_get(BLUESKY_PDS . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
if (empty($data) || empty($data->did)) {
if ($handle == '') {
return '';
}
Logger::debug('Got DID by PDS call', ['handle' => $handle, 'did' => $data->did]);
return $data->did;
if (strpos($handle, '.') === false) {
$handle .= '.' . BLUESKY_HOSTNAME;
}
// At first we use the user PDS. That should cover most cases.
$pds = DI::pConfig()->get($uid, 'bluesky', 'pds');
if (!empty($pds)) {
$data = bluesky_get($pds . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
if (!empty($data) && !empty($data->did)) {
Logger::debug('Got DID by user PDS call', ['handle' => $handle, 'did' => $data->did]);
return $data->did;
}
}
// Then we query the DNS, which is used for third party handles (DNS should be faster than wellknown)
$did = bluesky_get_did_by_dns($handle);
if ($did != '') {
Logger::debug('Got DID by DNS', ['handle' => $handle, 'did' => $did]);
return $did;
}
// Then we query wellknown, which should mostly cover the rest.
$did = bluesky_get_did_by_wellknown($handle);
if ($did != '') {
Logger::debug('Got DID by wellknown', ['handle' => $handle, 'did' => $did]);
return $did;
}
// And finally we use the default PDS from Bluesky.
$data = bluesky_get(BLUESKY_PDS . '/xrpc/com.atproto.identity.resolveHandle?handle=' . urlencode($handle));
if (!empty($data) && !empty($data->did)) {
Logger::debug('Got DID by system PDS call', ['handle' => $handle, 'did' => $data->did]);
return $data->did;
}
Logger::notice('No DID detected', ['handle' => $handle]);
return '';
}
function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
@ -1797,7 +1972,7 @@ function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
return null;
}
$did = bluesky_get_did($handle);
$did = bluesky_get_did($handle, $uid);
if (empty($did)) {
return null;
}
@ -1828,9 +2003,11 @@ function bluesky_get_user_pds(int $uid): ?string
return $pds;
}
function bluesky_get_pds(string $did): ?string
function bluesky_get_pds(string $did, stdClass $data = null): ?string
{
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
if (empty($data)) {
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
}
if (empty($data) || empty($data->service)) {
return null;
}
@ -1844,6 +2021,22 @@ function bluesky_get_pds(string $did): ?string
return null;
}
function bluesky_get_public_key(string $did, stdClass $data = null): ?string
{
if (empty($data)) {
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
}
if (empty($data) || empty($data->verificationMethod)) {
return null;
}
foreach ($data->verificationMethod as $method) {
if (!empty($method->publicKeyMultibase)) {
return $method->publicKeyMultibase;
}
}
return null;
}
function bluesky_valid_did(string $did, string $handle): bool
{
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
@ -1873,7 +2066,7 @@ function bluesky_refresh_token(int $uid): string
$token = DI::pConfig()->get($uid, 'bluesky', 'refresh_token');
$data = bluesky_post($uid, '/xrpc/com.atproto.server.refreshSession', '', ['Authorization' => ['Bearer ' . $token]]);
if (empty($data)) {
if (empty($data) || empty($data->accessJwt)) {
return '';
}
@ -1892,7 +2085,7 @@ function bluesky_create_token(int $uid, string $password): string
}
$data = bluesky_post($uid, '/xrpc/com.atproto.server.createSession', json_encode(['identifier' => $did, 'password' => $password]), ['Content-type' => 'application/json']);
if (empty($data)) {
if (empty($data) || empty($data->accessJwt)) {
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_TOKEN_FAIL);
return '';
}
@ -1907,7 +2100,11 @@ function bluesky_create_token(int $uid, string $password): string
function bluesky_xrpc_post(int $uid, string $url, $parameters): ?stdClass
{
return bluesky_post($uid, '/xrpc/' . $url, json_encode($parameters), ['Content-type' => 'application/json', 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
$data = bluesky_post($uid, '/xrpc/' . $url, json_encode($parameters), ['Content-type' => 'application/json', 'Authorization' => ['Bearer ' . bluesky_get_token($uid)]]);
if (!empty($data)) {
Item::incrementOutbound(Protocol::BLUESKY);
}
return $data;
}
function bluesky_post(int $uid, string $url, string $params, array $headers): ?stdClass
@ -1925,14 +2122,18 @@ function bluesky_post(int $uid, string $url, string $params, array $headers): ?s
return null;
}
$data = json_decode($curlResult->getBodyString());
if (!$curlResult->isSuccess()) {
Logger::notice('API Error', ['error' => json_decode($curlResult->getBodyString()) ?: $curlResult->getBodyString()]);
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_API_FAIL);
return null;
Logger::notice('API Error', ['url' => $url, 'code' => $curlResult->getReturnCode(), 'error' => $data ?: $curlResult->getBodyString()]);
if (!$data) {
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_API_FAIL);
return null;
}
$data->code = $curlResult->getReturnCode();
}
DI::pConfig()->set($uid, 'bluesky', 'status', BLUEKSY_STATUS_SUCCESS);
return json_decode($curlResult->getBodyString());
return $data;
}
function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdClass
@ -1946,7 +2147,14 @@ function bluesky_xrpc_get(int $uid, string $url, array $parameters = []): ?stdCl
return null;
}
$data = bluesky_get($pds . '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]]]);
$headers = ['Authorization' => ['Bearer ' . bluesky_get_token($uid)]];
$languages = User::getWantedLanguages($uid);
if (!empty($languages)) {
$headers['Accept-Language'] = implode(',', $languages);
}
$data = bluesky_get($pds . '/xrpc/' . $url, HttpClientAccept::JSON, [HttpClientOptions::HEADERS => $headers]);
DI::pConfig()->set($uid, 'bluesky', 'status', is_null($data) ? BLUEKSY_STATUS_API_FAIL : BLUEKSY_STATUS_SUCCESS);
return $data;
}
@ -1960,10 +2168,15 @@ function bluesky_get(string $url, string $accept_content = HttpClientAccept::DEF
return null;
}
$data = json_decode($curlResult->getBodyString());
if (!$curlResult->isSuccess()) {
Logger::notice('API Error', ['url' => $url, 'error' => json_decode($curlResult->getBodyString()) ?: $curlResult->getBodyString()]);
return null;
Logger::notice('API Error', ['url' => $url, 'code' => $curlResult->getReturnCode(), 'error' => $data ?: $curlResult->getBodyString()]);
if (!$data) {
return null;
}
$data->code = $curlResult->getReturnCode();
}
return json_decode($curlResult->getBodyString());
Item::incrementInbound(Protocol::BLUESKY);
return $data;
}

View file

@ -6,11 +6,11 @@ function bluesky_feed_run($argv, $argc)
{
require_once 'addon/bluesky/bluesky.php';
if ($argc != 4) {
if ($argc < 3) {
return;
}
Logger::debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2], 'last_poll' => $argv[3]]);
bluesky_fetch_feed($argv[1], $argv[2], $argv[3]);
Logger::debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2], 'last_poll' => $argv[3]]);
Logger::debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2]]);
bluesky_fetch_feed($argv[1], $argv[2]);
Logger::debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2]]);
}

View file

@ -6,11 +6,11 @@ function bluesky_notifications_run($argv, $argc)
{
require_once 'addon/bluesky/bluesky.php';
if ($argc != 3) {
if ($argc < 2) {
return;
}
Logger::notice('importing notifications - start', ['user' => $argv[1], 'last_poll' => $argv[2]]);
bluesky_fetch_notifications($argv[1], $argv[2]);
Logger::notice('importing notifications - done', ['user' => $argv[1], 'last_poll' => $argv[2]]);
Logger::notice('importing notifications - start', ['user' => $argv[1]]);
bluesky_fetch_notifications($argv[1]);
Logger::notice('importing notifications - done', ['user' => $argv[1]]);
}

View file

@ -6,11 +6,11 @@ function bluesky_timeline_run($argv, $argc)
{
require_once 'addon/bluesky/bluesky.php';
if ($argc != 3) {
if ($argc < 2) {
return;
}
Logger::notice('importing timeline - start', ['user' => $argv[1], 'last_poll' => $argv[2]]);
bluesky_fetch_timeline($argv[1], $argv[2]);
Logger::notice('importing timeline - done', ['user' => $argv[1], 'last_poll' => $argv[2]]);
Logger::notice('importing timeline - start', ['user' => $argv[1]]);
bluesky_fetch_timeline($argv[1]);
Logger::notice('importing timeline - done', ['user' => $argv[1]]);
}

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-03-22 05:31+0000\n"
"POT-Creation-Date: 2024-09-29 18:16+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,131 +17,117 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: bluesky.php:325
#: bluesky.php:335
msgid "Save Settings"
msgstr ""
#: bluesky.php:326
#: bluesky.php:336
msgid "Allow your users to use your hostname for their Bluesky handles"
msgstr ""
#: bluesky.php:326
#: bluesky.php:336
#, php-format
msgid ""
"Before enabling this option, you have to setup a wildcard domain "
"configuration and you have to enable wildcard requests in your webserver "
"configuration. On Apache this is done by adding \"ServerAlias *.%s\" to your "
"HTTP configuration. You don't need to change the HTTPS configuration."
msgid "Before enabling this option, you have to setup a wildcard domain configuration and you have to enable wildcard requests in your webserver configuration. On Apache this is done by adding \"ServerAlias *.%s\" to your HTTP configuration. You don't need to change the HTTPS configuration."
msgstr ""
#: bluesky.php:354
#: bluesky.php:365
#, php-format
msgid "Allow to use %s as your Bluesky handle."
msgstr ""
#: bluesky.php:354
#: bluesky.php:365
#, php-format
msgid ""
"When enabled, you can use %s as your Bluesky handle. After you enabled this "
"option, please go to https://bsky.app/settings and select to change your "
"handle. Select that you have got your own domain. Then enter %s and select "
"\"No DNS Panel\". Then select \"Verify Text File\"."
msgstr ""
#: bluesky.php:361
msgid "Enable Bluesky Post Addon"
msgstr ""
#: bluesky.php:362
msgid "Post to Bluesky by default"
msgstr ""
#: bluesky.php:363
msgid "Import the remote timeline"
msgstr ""
#: bluesky.php:364
msgid "Import the pinned feeds"
msgstr ""
#: bluesky.php:364
msgid ""
"When activated, Posts will be imported from all the feeds that you pinned in "
"Bluesky."
msgstr ""
#: bluesky.php:366
msgid "Personal Data Server"
msgstr ""
#: bluesky.php:366
msgid "The personal data server (PDS) is the system that hosts your profile."
msgstr ""
#: bluesky.php:367
msgid "Bluesky handle"
msgstr ""
#: bluesky.php:368
msgid "Bluesky DID"
msgstr ""
#: bluesky.php:368
msgid ""
"This is the unique identifier. It will be fetched automatically, when the "
"handle is entered."
msgstr ""
#: bluesky.php:369
msgid "Bluesky app password"
msgstr ""
#: bluesky.php:369
msgid ""
"Please don't add your real password here, but instead create a specific app "
"password in the Bluesky settings."
msgid "When enabled, you can use %s as your Bluesky handle. After you enabled this option, please go to https://bsky.app/settings and select to change your handle. Select that you have got your own domain. Then enter %s and select \"No DNS Panel\". Then select \"Verify Text File\"."
msgstr ""
#: bluesky.php:375
msgid "Enable Bluesky Post Addon"
msgstr ""
#: bluesky.php:376
msgid "Post to Bluesky by default"
msgstr ""
#: bluesky.php:377
msgid "Import the remote timeline"
msgstr ""
#: bluesky.php:378
msgid "Import the pinned feeds"
msgstr ""
#: bluesky.php:378
msgid "When activated, Posts will be imported from all the feeds that you pinned in Bluesky."
msgstr ""
#: bluesky.php:379
msgid "Complete the threads"
msgstr ""
#: bluesky.php:379
msgid "When activated, the system fetches additional replies for the posts in the timeline. This leads to more complete threads."
msgstr ""
#: bluesky.php:381
msgid "Personal Data Server"
msgstr ""
#: bluesky.php:381
msgid "The personal data server (PDS) is the system that hosts your profile."
msgstr ""
#: bluesky.php:382
msgid "Bluesky handle"
msgstr ""
#: bluesky.php:383
msgid "Bluesky DID"
msgstr ""
#: bluesky.php:383
msgid "This is the unique identifier. It will be fetched automatically, when the handle is entered."
msgstr ""
#: bluesky.php:384
msgid "Bluesky app password"
msgstr ""
#: bluesky.php:384
msgid "Please don't add your real password here, but instead create a specific app password in the Bluesky settings."
msgstr ""
#: bluesky.php:390
msgid "Bluesky Import/Export"
msgstr ""
#: bluesky.php:385
msgid ""
"You are not authenticated. Please enter your handle and the app password."
#: bluesky.php:400
msgid "You are not authenticated. Please enter your handle and the app password."
msgstr ""
#: bluesky.php:405
msgid ""
"You are authenticated to Bluesky. For security reasons the password isn't "
"stored."
#: bluesky.php:420
msgid "You are authenticated to Bluesky. For security reasons the password isn't stored."
msgstr ""
#: bluesky.php:407
msgid ""
"The communication with the personal data server service (PDS) is established."
#: bluesky.php:422
msgid "The communication with the personal data server service (PDS) is established."
msgstr ""
#: bluesky.php:409
#: bluesky.php:424
msgid "Communication issues with the personal data server service (PDS)."
msgstr ""
#: bluesky.php:411
msgid ""
"The DID for the provided handle could not be detected. Please check if you "
"entered the correct handle."
#: bluesky.php:426
msgid "The DID for the provided handle could not be detected. Please check if you entered the correct handle."
msgstr ""
#: bluesky.php:413
#: bluesky.php:428
msgid "The personal data server service (PDS) could not be detected."
msgstr ""
#: bluesky.php:415
msgid ""
"The authentication with the provided handle and password failed. Please "
"check if you entered the correct password."
#: bluesky.php:430
msgid "The authentication with the provided handle and password failed. Please check if you entered the correct password."
msgstr ""
#: bluesky.php:484
#: bluesky.php:492
msgid "Post to Bluesky"
msgstr ""

View file

@ -3,6 +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_checkbox.tpl" field=$complete_threads}}
{{if $custom_handle}}
{{include file="field_checkbox.tpl" field=$custom_handle}}
{{/if}}

View file

@ -6,55 +6,55 @@
# Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2018
# Davide Pesenti <mrjive@mrjive.it>, 2018
# Sylke Vicious <silkevicious@gmail.com>, 2021
# Sylke Vicious <silkevicious@gmail.com>, 2023
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-29 00:53+0000\n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2018-04-07 05:23+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021\n"
"Language-Team: Italian (https://www.transifex.com/Friendica/teams/12172/it/)\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2023\n"
"Language-Team: Italian (https://app.transifex.com/Friendica/teams/12172/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: catavatar.php:48
msgid "Use Cat as Avatar"
msgstr "Usa il Gatto come avatar"
#: catavatar.php:49
msgid "More Random Cat!"
msgstr "Altro Gatto a caso!"
#: catavatar.php:50
msgid "Reset to email Cat"
msgstr "Reimposta Gatto"
#: catavatar.php:52
msgid "Cat Avatar Settings"
msgstr "Impostazioni Avatar Gatto"
#: catavatar.php:53
msgid "Set default profile avatar or randomize the cat."
msgstr "Imposta l'immagine di profilo predefinita o crea un gatto casuale."
#: catavatar.php:78
#: catavatar.php:53
msgid "Cat Avatar Settings"
msgstr "Impostazioni Avatar Gatto"
#: catavatar.php:56
msgid "Use Cat as Avatar"
msgstr "Usa il Gatto come avatar"
#: catavatar.php:57
msgid "Another random Cat!"
msgstr "Un altro Gatto casuale!"
#: catavatar.php:58
msgid "Reset to email Cat"
msgstr "Reimposta Gatto"
#: catavatar.php:77
msgid "The cat hadn't found itself."
msgstr "Il gatto non ha trovato sé stesso."
#: catavatar.php:87
#: catavatar.php:86
msgid "There was an error, the cat ran away."
msgstr "Si è verificato un errore, il gatto è scappato."
#: catavatar.php:93
#: catavatar.php:92
msgid "Profile Photos"
msgstr "Foto del profilo"
#: catavatar.php:108
#: catavatar.php:102
msgid "Meow!"
msgstr "Miao!"

View file

@ -3,13 +3,13 @@
if(! function_exists("string_plural_select_it")) {
function string_plural_select_it($n){
$n = intval($n);
return intval($n != 1);
if ($n == 1) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Use Cat as Avatar'] = 'Usa il Gatto come avatar';
$a->strings['More Random Cat!'] = 'Altro Gatto a caso!';
$a->strings['Reset to email Cat'] = 'Reimposta Gatto';
$a->strings['Cat Avatar Settings'] = 'Impostazioni Avatar Gatto';
$a->strings['Set default profile avatar or randomize the cat.'] = 'Imposta l\'immagine di profilo predefinita o crea un gatto casuale.';
$a->strings['Cat Avatar Settings'] = 'Impostazioni Avatar Gatto';
$a->strings['Use Cat as Avatar'] = 'Usa il Gatto come avatar';
$a->strings['Another random Cat!'] = 'Un altro Gatto casuale!';
$a->strings['Reset to email Cat'] = 'Reimposta Gatto';
$a->strings['The cat hadn\'t found itself.'] = 'Il gatto non ha trovato sé stesso.';
$a->strings['There was an error, the cat ran away.'] = 'Si è verificato un errore, il gatto è scappato.';
$a->strings['Profile Photos'] = 'Foto del profilo';

View file

@ -152,7 +152,7 @@ function curweather_network_mod_init(string &$body)
function curweather_addon_settings_post($post)
{
if (!DI::userSession()->getLocalUserId() || empty($_POST['curweather-settings-submit'])) {
if (!DI::userSession()->getLocalUserId() || empty($_POST['curweather-submit'])) {
return;
}

View file

@ -5,6 +5,7 @@
#
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# cracrayol, 2024
# Hypolite Petovan <hypolite@mrpetovan.com>, 2022
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
# ea1cd8241cb389ffb6f92bc6891eff5d_dc12308 <70dced5587d47e18d88f9298024d96f8_93383>, 2015
@ -15,8 +16,8 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2014-06-22 11:34+0000\n"
"Last-Translator: Hypolite Petovan <hypolite@mrpetovan.com>, 2022\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -45,7 +46,7 @@ msgstr "Vent"
#: curweather.php:140
msgid "Last Updated"
msgstr "Dernière mise-à-jour"
msgstr "Dernière mise à jour"
#: curweather.php:141
msgid "Data by"

View file

@ -10,7 +10,7 @@ $a->strings['Current Weather'] = 'Météo actuelle';
$a->strings['Relative Humidity'] = 'Humidité relative';
$a->strings['Pressure'] = 'Pression';
$a->strings['Wind'] = 'Vent';
$a->strings['Last Updated'] = 'Dernière mise-à-jour';
$a->strings['Last Updated'] = 'Dernière mise à jour';
$a->strings['Data by'] = 'Données de';
$a->strings['Show on map'] = 'Montrer sur la carte';
$a->strings['There was a problem accessing the weather data. But have a look'] = 'Une erreur est survenue lors de l\'accès aux données météo. Vous pouvez quand même jeter un oeil';

View file

@ -5,27 +5,27 @@
#
# Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2014-2015
# Sylke Vicious <silkevicious@gmail.com>, 2021
# Sylke Vicious <silkevicious@gmail.com>, 2021,2023
# Tobias Diekershoff <tobias.diekershoff@gmx.net>, 2016
msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-01 18:15+0100\n"
"PO-Revision-Date: 2021-02-16 12:57+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.com/Friendica/friendica/language/it/)\n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2014-06-22 11:34+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021,2023\n"
"Language-Team: Italian (http://app.transifex.com/Friendica/friendica/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: curweather.php:47
msgid "Error fetching weather data. Error was: "
msgstr "Errore durante il recupero dei dati meteo. L'errore è stato:"
#: curweather.php:130 curweather.php:192
#: curweather.php:130
msgid "Current Weather"
msgstr "Meteo"
@ -61,66 +61,66 @@ msgstr "C'è stato un problema accedendo ai dati meteo, ma dai un'occhiata"
msgid "at OpenWeatherMap"
msgstr "a OpenWeatherMap"
#: curweather.php:179
#: curweather.php:178
msgid "No APPID found, please contact your admin to obtain one."
msgstr "APPID non trovata, contatta il tuo amministratore per averne una."
#: curweather.php:191 curweather.php:229
msgid "Save Settings"
msgstr "Salva Impostazioni"
#: curweather.php:192
msgid "Settings"
msgstr "Impostazioni"
#: curweather.php:194
#: curweather.php:188
msgid "Enter either the name of your location or the zip code."
msgstr "Inserisci il nome della tua posizione o il CAP"
#: curweather.php:195
#: curweather.php:189
msgid "Your Location"
msgstr "La tua Posizione"
#: curweather.php:195
#: curweather.php:189
msgid ""
"Identifier of your location (name or zip code), e.g. <em>Berlin,DE</em> or "
"<em>14476,DE</em>."
msgstr "Identificatore della tua posizione (nome o CAP), p.e. <em>Roma, IT</em> or <em>00186,IT</em>."
#: curweather.php:196
#: curweather.php:190
msgid "Units"
msgstr "Unità"
#: curweather.php:196
#: curweather.php:190
msgid "select if the temperature should be displayed in &deg;C or &deg;F"
msgstr "scegli se la temperatura deve essere mostrata in °C o in °F"
#: curweather.php:197
#: curweather.php:191
msgid "Show weather data"
msgstr "Mostra dati meteo"
#: curweather.php:232
#: curweather.php:196
msgid "Current Weather Settings"
msgstr "Impostazioni Meteo"
#: curweather.php:227
msgid "Save Settings"
msgstr "Salva Impostazioni"
#: curweather.php:230
msgid "Caching Interval"
msgstr "Intervallo di cache"
#: curweather.php:234
#: curweather.php:232
msgid ""
"For how long should the weather data be cached? Choose according your "
"OpenWeatherMap account type."
msgstr "Per quanto tempo i dati meteo devono essere memorizzati? Scegli a seconda del tuo tipo di account su OpenWeatherMap."
#: curweather.php:235
#: curweather.php:233
msgid "no cache"
msgstr "nessuna cache"
#: curweather.php:236 curweather.php:237 curweather.php:238 curweather.php:239
#: curweather.php:234 curweather.php:235 curweather.php:236 curweather.php:237
msgid "minutes"
msgstr "minuti"
#: curweather.php:242
#: curweather.php:240
msgid "Your APPID"
msgstr "Il tuo APPID"
#: curweather.php:242
#: curweather.php:240
msgid "Your API key provided by OpenWeatherMap"
msgstr "La tua chiave API da OpenWeatherMap"

View file

@ -3,7 +3,7 @@
if(! function_exists("string_plural_select_it")) {
function string_plural_select_it($n){
$n = intval($n);
return intval($n != 1);
if ($n == 1) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Error fetching weather data. Error was: '] = 'Errore durante il recupero dei dati meteo. L\'errore è stato:';
$a->strings['Current Weather'] = 'Meteo';
@ -16,14 +16,14 @@ $a->strings['Show on map'] = 'Mostra sulla mappa';
$a->strings['There was a problem accessing the weather data. But have a look'] = 'C\'è stato un problema accedendo ai dati meteo, ma dai un\'occhiata';
$a->strings['at OpenWeatherMap'] = 'a OpenWeatherMap';
$a->strings['No APPID found, please contact your admin to obtain one.'] = 'APPID non trovata, contatta il tuo amministratore per averne una.';
$a->strings['Save Settings'] = 'Salva Impostazioni';
$a->strings['Settings'] = 'Impostazioni';
$a->strings['Enter either the name of your location or the zip code.'] = 'Inserisci il nome della tua posizione o il CAP';
$a->strings['Your Location'] = 'La tua Posizione';
$a->strings['Identifier of your location (name or zip code), e.g. <em>Berlin,DE</em> or <em>14476,DE</em>.'] = 'Identificatore della tua posizione (nome o CAP), p.e. <em>Roma, IT</em> or <em>00186,IT</em>.';
$a->strings['Units'] = 'Unità';
$a->strings['select if the temperature should be displayed in &deg;C or &deg;F'] = 'scegli se la temperatura deve essere mostrata in °C o in °F';
$a->strings['Show weather data'] = 'Mostra dati meteo';
$a->strings['Current Weather Settings'] = 'Impostazioni Meteo';
$a->strings['Save Settings'] = 'Salva Impostazioni';
$a->strings['Caching Interval'] = 'Intervallo di cache';
$a->strings['For how long should the weather data be cached? Choose according your OpenWeatherMap account type.'] = 'Per quanto tempo i dati meteo devono essere memorizzati? Scegli a seconda del tuo tipo di account su OpenWeatherMap.';
$a->strings['no cache'] = 'nessuna cache';

View file

@ -5,45 +5,41 @@
#
# Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2014,2018
# Sylke Vicious <silkevicious@gmail.com>, 2020-2021
# Sylke Vicious <silkevicious@gmail.com>, 2020-2021,2023
msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-01 18:15+0100\n"
"PO-Revision-Date: 2021-02-16 12:55+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.com/Friendica/friendica/language/it/)\n"
"POT-Creation-Date: 2021-11-21 19:17-0500\n"
"PO-Revision-Date: 2014-06-22 11:41+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2020-2021,2023\n"
"Language-Team: Italian (http://app.transifex.com/Friendica/friendica/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: dwpost.php:41
#: dwpost.php:43
msgid "Post to Dreamwidth"
msgstr "Invia a Dreamwidth"
#: dwpost.php:72 dwpost.php:76
msgid "Dreamwidth Export"
msgstr "Esporta Dreamwidth"
#: dwpost.php:63
msgid "Enable Dreamwidth Post Addon"
msgstr "Abilita il componente aggiuntivo di pubblicazione Dreamwidth"
#: dwpost.php:80
msgid "Enable dreamwidth Post Addon"
msgstr "Abilita il componente aggiuntivo di invio a Dreamwidth"
#: dwpost.php:85
msgid "dreamwidth username"
#: dwpost.php:64
msgid "Dreamwidth username"
msgstr "Nome utente Dreamwidth"
#: dwpost.php:90
msgid "dreamwidth password"
msgstr "password Dreamwidth"
#: dwpost.php:65
msgid "Dreamwidth password"
msgstr "Password Dreamwidth"
#: dwpost.php:95
msgid "Post to dreamwidth by default"
msgstr "Invia sempre a Dreamwidth"
#: dwpost.php:66
msgid "Post to Dreamwidth by default"
msgstr "Pubblica su dreamwidth per impostazione predefinita"
#: dwpost.php:100
msgid "Save Settings"
msgstr "Salva Impostazioni"
#: dwpost.php:71
msgid "Dreamwidth Export"
msgstr "Esporta Dreamwidth"

View file

@ -3,12 +3,11 @@
if(! function_exists("string_plural_select_it")) {
function string_plural_select_it($n){
$n = intval($n);
return intval($n != 1);
if ($n == 1) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Post to Dreamwidth'] = 'Invia a Dreamwidth';
$a->strings['Enable Dreamwidth Post Addon'] = 'Abilita il componente aggiuntivo di pubblicazione Dreamwidth';
$a->strings['Dreamwidth username'] = 'Nome utente Dreamwidth';
$a->strings['Dreamwidth password'] = 'Password Dreamwidth';
$a->strings['Post to Dreamwidth by default'] = 'Pubblica su dreamwidth per impostazione predefinita';
$a->strings['Dreamwidth Export'] = 'Esporta Dreamwidth';
$a->strings['Enable dreamwidth Post Addon'] = 'Abilita il componente aggiuntivo di invio a Dreamwidth';
$a->strings['dreamwidth username'] = 'Nome utente Dreamwidth';
$a->strings['dreamwidth password'] = 'password Dreamwidth';
$a->strings['Post to dreamwidth by default'] = 'Invia sempre a Dreamwidth';
$a->strings['Save Settings'] = 'Salva Impostazioni';

View file

@ -6,6 +6,7 @@
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# ButterflyOfFire, 2020
# cracrayol, 2024
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
msgid ""
msgstr ""
@ -13,8 +14,8 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2014-06-23 08:27+0000\n"
"Last-Translator: bob lebonche <lebonche@tutanota.com>, 2021\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -29,7 +30,7 @@ msgstr "Remplacer les coordonnées par le nom de la localité la plus proche dan
#: geonames.php:136
msgid "Enable Geonames Addon"
msgstr "Activer l'application complémentaire Geonames"
msgstr "Activer l'extension Geonames"
#: geonames.php:141
msgid "Geonames Settings"

View file

@ -6,5 +6,5 @@ function string_plural_select_fr($n){
if (($n == 0 || $n == 1)) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Replace numerical coordinates by the nearest populated location name in your posts.'] = 'Remplacer les coordonnées par le nom de la localité la plus proche dans votre publication.';
$a->strings['Enable Geonames Addon'] = 'Activer l\'application complémentaire Geonames';
$a->strings['Enable Geonames Addon'] = 'Activer l\'extension Geonames';
$a->strings['Geonames Settings'] = 'Paramètres Geonames';

View file

@ -6,6 +6,7 @@
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# ButterflyOfFire, 2020
# cracrayol, 2024
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
msgid ""
msgstr ""
@ -13,8 +14,8 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2014-06-23 08:30+0000\n"
"Last-Translator: bob lebonche <lebonche@tutanota.com>, 2021\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -29,7 +30,7 @@ msgstr "Permettre le filtrage des notifications de commentaires par courriel sur
#: gnot.php:64
msgid "Enable this addon?"
msgstr "Activer cette application complémentaire ?"
msgstr "Activer cette extension ?"
#: gnot.php:69
msgid "Gnot Settings"

View file

@ -6,6 +6,6 @@ function string_plural_select_fr($n){
if (($n == 0 || $n == 1)) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Allows threading of email comment notifications on Gmail and anonymising the subject line.'] = 'Permettre le filtrage des notifications de commentaires par courriel sur Gmail et l\'anonymisation de l\'objet.';
$a->strings['Enable this addon?'] = 'Activer cette application complémentaire ?';
$a->strings['Enable this addon?'] = 'Activer cette extension ?';
$a->strings['Gnot Settings'] = 'Paramètres Gnot';
$a->strings['[Friendica:Notify] Comment to conversation #%d'] = '[Friendica:Notify] Commentaire vers conversation #%d';

View file

@ -5,6 +5,7 @@
#
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# cracrayol, 2024
# Marie Olive <lacellule101@gmail.com>, 2018
# ea1cd8241cb389ffb6f92bc6891eff5d_dc12308 <70dced5587d47e18d88f9298024d96f8_93383>, 2015
msgid ""
@ -13,8 +14,8 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-01 18:15+0100\n"
"PO-Revision-Date: 2014-06-23 08:33+0000\n"
"Last-Translator: bob lebonche <lebonche@tutanota.com>, 2021\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -50,7 +51,7 @@ msgid ""
"Libravatar addon is installed, too. Please disable Libravatar addon or this "
"Gravatar addon.<br>The Libravatar addon will fall back to Gravatar if "
"nothing was found at Libravatar."
msgstr "L'application complémentaire Libravatar est aussi installée. Merci de désactiver l'application complémentaire Libravatar ou cette application complémentaire Gravatar. L'application complémentaire se repliera sur Gravatar si rien n'est trouvé dans Libravatar."
msgstr "L'extension Libravatar est aussi installée. Merci de désactiver l'extension Libravatar ou cette extension Gravatar. L'extension se repliera sur Gravatar si rien n'est trouvé dans Libravatar."
#: gravatar.php:102
msgid "Save Settings"

View file

@ -11,7 +11,7 @@ $a->strings['monster face'] = 'Face de monstre';
$a->strings['computer generated face'] = 'visage généré par ordinateur';
$a->strings['retro arcade style face'] = 'Face style retro arcade';
$a->strings['Information'] = 'Information';
$a->strings['Libravatar addon is installed, too. Please disable Libravatar addon or this Gravatar addon.<br>The Libravatar addon will fall back to Gravatar if nothing was found at Libravatar.'] = 'L\'application complémentaire Libravatar est aussi installée. Merci de désactiver l\'application complémentaire Libravatar ou cette application complémentaire Gravatar. L\'application complémentaire se repliera sur Gravatar si rien n\'est trouvé dans Libravatar.';
$a->strings['Libravatar addon is installed, too. Please disable Libravatar addon or this Gravatar addon.<br>The Libravatar addon will fall back to Gravatar if nothing was found at Libravatar.'] = 'L\'extension Libravatar est aussi installée. Merci de désactiver l\'extension Libravatar ou cette extension Gravatar. L\'extension se repliera sur Gravatar si rien n\'est trouvé dans Libravatar.';
$a->strings['Save Settings'] = 'Sauvegarder les paramètres.';
$a->strings['Default avatar image'] = 'Image par défaut d\'avatar';
$a->strings['Select default avatar image if none was found at Gravatar. See README'] = 'Sélectionner l\'avatar par défaut, si aucun n\'est trouvé sur Gravatar. Voir Lisezmoi.';

View file

@ -5,6 +5,7 @@
#
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# cracrayol, 2024
# Hypolite Petovan <hypolite@mrpetovan.com>, 2016
msgid ""
msgstr ""
@ -12,8 +13,8 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:17-0500\n"
"PO-Revision-Date: 2014-06-23 08:37+0000\n"
"Last-Translator: bob lebonche <lebonche@tutanota.com>, 2021\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -26,7 +27,7 @@ msgstr "Publier sur Insanejournal"
#: ijpost.php:61
msgid "Enable InsaneJournal Post Addon"
msgstr "Activer l'application complémentaire InsaneJournalPost"
msgstr "Activer l'extension InsaneJournal"
#: ijpost.php:62
msgid "InsaneJournal username"

View file

@ -6,7 +6,7 @@ function string_plural_select_fr($n){
if (($n == 0 || $n == 1)) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Post to Insanejournal'] = 'Publier sur Insanejournal';
$a->strings['Enable InsaneJournal Post Addon'] = 'Activer l\'application complémentaire InsaneJournalPost';
$a->strings['Enable InsaneJournal Post Addon'] = 'Activer l\'extension InsaneJournal';
$a->strings['InsaneJournal username'] = 'Identifiant du InsaneJournal';
$a->strings['InsaneJournal password'] = 'Mot de passe du InsaneJournal';
$a->strings['Post to InsaneJournal by default'] = 'Publier sur le InsaneJournal par défaut';

View file

@ -96,6 +96,8 @@ function invidious_render(array &$b)
$b['html'] = preg_replace("~https?://(?:www\.)?youtube\.com/watch\?v=(.*?)~ism", $server . '/watch?v=$1', $b['html']);
$b['html'] = preg_replace("~https?://(?:www\.)?youtube\.com/embed/(.*?)~ism", $server . '/embed/$1', $b['html']);
$b['html'] = preg_replace("~https?://(?:www\.)?youtube\.com/shorts/(.*?)~ism", $server . '/shorts/$1', $b['html']);
$b['html'] = preg_replace ("/https?:\/\/music.youtube.com\/(.*?)/ism", $server . '/watch?v=$1', $b['html']);
$b['html'] = preg_replace ("/https?:\/\/m.youtube.com\/(.*?)/ism", $server . '/watch?v=$1', $b['html']);
$b['html'] = preg_replace("/https?:\/\/youtu.be\/(.*?)/ism", $server . '/watch?v=$1', $b['html']);
if ($original != $b['html']) {

View file

@ -50,7 +50,11 @@ function js_upload_post_init(array &$b)
// list of valid extensions
$allowedExtensions = [];
foreach (Images::IMAGETYPES as $type) {
$allowedExtensions[] = image_type_to_extension($type, false);
$extension = image_type_to_extension($type, false);
if ($extension == 'jpeg') {
$allowedExtensions[] = 'jpg';
}
$allowedExtensions[] = $extension;
}
// max file size in bytes
@ -216,9 +220,9 @@ class qqFileUploader
return ['error' => DI::l10n()->t('Uploaded file is empty')];
}
// if ($size > $this->sizeLimit) {
// return array('error' => DI::l10n()->t('Uploaded file is too large'));
// }
// if ($size > $this->sizeLimit) {
// return array('error' => DI::l10n()->t('Uploaded file is too large'));
// }
$maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));

View file

@ -5,14 +5,15 @@
#
# Translators:
# bob lebonche <lebonche@tutanota.com>, 2021
# cracrayol, 2024
msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:14-0500\n"
"PO-Revision-Date: 2015-07-07 15:14+0000\n"
"Last-Translator: bob lebonche <lebonche@tutanota.com>, 2021\n"
"Language-Team: French (http://www.transifex.com/Friendica/friendica/language/fr/)\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -21,7 +22,7 @@ msgstr ""
#: krynn.php:127
msgid "Enable Krynn Addon"
msgstr "Activer l'application complémentaire Krynn"
msgstr "Activer l'extension Krynn"
#: krynn.php:132
msgid "Krynn Settings"

View file

@ -5,5 +5,5 @@ function string_plural_select_fr($n){
$n = intval($n);
if (($n == 0 || $n == 1)) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Enable Krynn Addon'] = 'Activer l\'application complémentaire Krynn';
$a->strings['Enable Krynn Addon'] = 'Activer l\'extension Krynn';
$a->strings['Krynn Settings'] = 'Paramètres de Krynn';

View file

@ -5,45 +5,41 @@
#
# Translators:
# fabrixxm <fabrix.xm@gmail.com>, 2014-2015,2018
# Sylke Vicious <silkevicious@gmail.com>, 2021
# Sylke Vicious <silkevicious@gmail.com>, 2021,2023
msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-02-01 18:15+0100\n"
"PO-Revision-Date: 2021-02-16 12:47+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>\n"
"Language-Team: Italian (http://www.transifex.com/Friendica/friendica/language/it/)\n"
"POT-Creation-Date: 2023-06-03 15:49-0400\n"
"PO-Revision-Date: 2014-06-23 09:44+0000\n"
"Last-Translator: Sylke Vicious <silkevicious@gmail.com>, 2021,2023\n"
"Language-Team: Italian (http://app.transifex.com/Friendica/friendica/language/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: it\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: libertree.php:37
#: libertree.php:39
msgid "Post to libertree"
msgstr "Invia a Libertree"
#: libertree.php:71 libertree.php:75
msgid "libertree Export"
msgstr "Esporta libertree"
#: libertree.php:79
#: libertree.php:59
msgid "Enable Libertree Post Addon"
msgstr "Abilita il componente aggiuntivo di invio a Libertree"
#: libertree.php:84
msgid "Libertree API token"
msgstr "Token API Libertree"
#: libertree.php:89
#: libertree.php:60
msgid "Libertree site URL"
msgstr "Indirizzo sito Libertree"
#: libertree.php:94
#: libertree.php:61
msgid "Libertree API token"
msgstr "Token API Libertree"
#: libertree.php:62
msgid "Post to Libertree by default"
msgstr "Invia sempre a Libertree"
#: libertree.php:100
msgid "Save Settings"
msgstr "Salva Impostazioni"
#: libertree.php:67
msgid "Libertree Export"
msgstr "Esporta Libertree"

View file

@ -3,12 +3,11 @@
if(! function_exists("string_plural_select_it")) {
function string_plural_select_it($n){
$n = intval($n);
return intval($n != 1);
if ($n == 1) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Post to libertree'] = 'Invia a Libertree';
$a->strings['libertree Export'] = 'Esporta libertree';
$a->strings['Enable Libertree Post Addon'] = 'Abilita il componente aggiuntivo di invio a Libertree';
$a->strings['Libertree API token'] = 'Token API Libertree';
$a->strings['Libertree site URL'] = 'Indirizzo sito Libertree';
$a->strings['Libertree API token'] = 'Token API Libertree';
$a->strings['Post to Libertree by default'] = 'Invia sempre a Libertree';
$a->strings['Save Settings'] = 'Salva Impostazioni';
$a->strings['Libertree Export'] = 'Esporta Libertree';

View file

@ -5,16 +5,18 @@
#
# Translators:
# Andreas H., 2014
# foss <oss@disr.it>, 2022
# Raroun, 2023
# Tobias Diekershoff <tobias.diekershoff@gmx.net>, 2018
# Ulf Rompe <transifex.com@rompe.org>, 2019
msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-11 19:13+0100\n"
"PO-Revision-Date: 2019-02-18 15:05+0000\n"
"Last-Translator: Ulf Rompe <transifex.com@rompe.org>\n"
"Language-Team: German (http://www.transifex.com/Friendica/friendica/language/de/)\n"
"POT-Creation-Date: 2021-11-21 19:15-0500\n"
"PO-Revision-Date: 2014-06-23 09:54+0000\n"
"Last-Translator: Raroun, 2023\n"
"Language-Team: German (http://app.transifex.com/Friendica/friendica/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@ -29,72 +31,76 @@ msgstr "Absender"
msgid "Email address that stream items will appear to be from."
msgstr "E-Mail-Adresse, die in hochgeladenen Artikeln erscheint."
#: mailstream.php:82 mailstream.php:380
#: mailstream.php:82
msgid "Save Settings"
msgstr "Einstellungen speichern"
#: mailstream.php:223
#: mailstream.php:311
msgid "Re:"
msgstr "Re:"
#: mailstream.php:231
#: mailstream.php:324 mailstream.php:327
msgid "Friendica post"
msgstr "Friendica-Veröffentlichung"
#: mailstream.php:234
#: mailstream.php:330
msgid "Diaspora post"
msgstr "Diaspora-Veröffentlichung"
#: mailstream.php:244
#: mailstream.php:340
msgid "Feed item"
msgstr "Artikel-Feed"
#: mailstream.php:247
#: mailstream.php:343
msgid "Email"
msgstr "E-Mail"
#: mailstream.php:249
#: mailstream.php:345
msgid "Friendica Item"
msgstr "Friendica-Artikel"
#: mailstream.php:293
#: mailstream.php:419
msgid "Upstream"
msgstr "Upstream"
#: mailstream.php:294
#: mailstream.php:420
msgid "URI"
msgstr "URI"
#: mailstream.php:421
msgid "Local"
msgstr "Lokal"
#: mailstream.php:362
#: mailstream.php:499
msgid "Enabled"
msgstr "eingeschaltet"
msgstr "Aktiv"
#: mailstream.php:366
#: mailstream.php:504
msgid "Email Address"
msgstr "E-Mail-Adresse"
#: mailstream.php:368
#: mailstream.php:506
msgid "Leave blank to use your account email address"
msgstr "Leer lassen für deine Konto-E-Mail-Addresse"
#: mailstream.php:371
#: mailstream.php:510
msgid "Exclude Likes"
msgstr "Likes ignorieren"
#: mailstream.php:373
#: mailstream.php:512
msgid "Check this to omit mailing \"Like\" notifications"
msgstr "Diese Option verhindert das Versenden von \"Like\"-Benachrichtigungen per E-Mail."
#: mailstream.php:376
#: mailstream.php:516
msgid "Attach Images"
msgstr "Bilder anhängen"
#: mailstream.php:378
#: mailstream.php:518
msgid ""
"Download images in posts and attach them to the email. Useful for reading "
"email while offline."
msgstr "Sollen Bilder, die im Beitrag eingebettet sind, als Dateianhang in den E-Mails verschickt werden?"
#: mailstream.php:379
#: mailstream.php:525
msgid "Mail Stream Settings"
msgstr "Mail-Nachrichten-Einstellungen"

View file

@ -15,8 +15,9 @@ $a->strings['Feed item'] = 'Artikel-Feed';
$a->strings['Email'] = 'E-Mail';
$a->strings['Friendica Item'] = 'Friendica-Artikel';
$a->strings['Upstream'] = 'Upstream';
$a->strings['URI'] = 'URI';
$a->strings['Local'] = 'Lokal';
$a->strings['Enabled'] = 'eingeschaltet';
$a->strings['Enabled'] = 'Aktiv';
$a->strings['Email Address'] = 'E-Mail-Adresse';
$a->strings['Leave blank to use your account email address'] = 'Leer lassen für deine Konto-E-Mail-Addresse';
$a->strings['Exclude Likes'] = 'Likes ignorieren';

View file

@ -6,7 +6,6 @@
* Author: Matthew Exon <http://mat.exon.name>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
@ -16,12 +15,11 @@ use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Model\User;
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Protocol\Activity;
use Friendica\Util\DateTimeFormat;
/**
* Sets up the addon hooks and the database table
@ -37,25 +35,6 @@ function mailstream_install()
Logger::info("installed mailstream");
}
/**
* Enforces that mailstream_install has set up the current version
*/
function mailstream_check_version()
{
if (!is_null(DI::config()->get('mailstream', 'dbversion'))) {
DI::config()->delete('mailstream', 'dbversion');
Logger::info("old version detected, reinstalling");
mailstream_install();
Hook::loadHooks();
Hook::add(
'mailstream_convert_table_entries',
'addon/mailstream/mailstream.php',
'mailstream_convert_table_entries'
);
Hook::fork(Worker::PRIORITY_LOW, 'mailstream_convert_table_entries');
}
}
/**
* This is a statement rather than an actual function definition. The simple
* existence of this method is checked to figure out if the addon offers a
@ -72,10 +51,12 @@ function mailstream_addon_admin(string &$o)
{
$frommail = DI::config()->get('mailstream', 'frommail');
$template = Renderer::getMarkupTemplate('admin.tpl', 'addon/mailstream/');
$config = ['frommail',
$config = [
'frommail',
DI::l10n()->t('From Address'),
$frommail,
DI::l10n()->t('Email address that stream items will appear to be from.')];
DI::l10n()->t('Email address that stream items will appear to be from.')
];
$o .= Renderer::replaceMacros($template, [
'$frommail' => $config,
'$submit' => DI::l10n()->t('Save Settings')
@ -120,7 +101,7 @@ function mailstream_send_hook(array $data)
$user = User::getById($item['uid']);
if (empty($user)) {
Logger::error('could not find user', ['uid' => $item['uid']]);
Logger::error('could not find user', ['uid' => $item['uid']]);
return;
}
@ -142,14 +123,12 @@ function mailstream_send_hook(array $data)
*/
function mailstream_post_hook(array &$item)
{
mailstream_check_version();
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
Logger::debug('mailstream not enabled.', ['item' => $item['id'], 'uid' => $item['uid']]);
if ($item['uid'] === 0) {
Logger::debug('mailstream: root user, skipping item ' . $item['id']);
return;
}
if (!$item['uid']) {
Logger::debug('no uid', ['item' => $item['id']]);
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
Logger::debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
return;
}
if (!$item['contact-id']) {
@ -219,7 +198,15 @@ function mailstream_do_images(array &$item, array &$attachments)
$cookiejar = tempnam(System::getTempPath(), 'cookiejar-mailstream-');
try {
$curlResult = DI::httpClient()->fetchFull($url, HttpClientAccept::DEFAULT, 0, $cookiejar);
$curlResult = DI::httpClient()->get($url, HttpClientAccept::DEFAULT, [HttpClientOptions::COOKIEJAR => $cookiejar]);
if (!$curlResult->isSuccess()) {
Logger::debug('mailstream: fetch image url failed', [
'url' => $url,
'item_id' => $item['id'],
'return_code' => $curlResult->getReturnCode()
]);
continue;
}
} catch (InvalidArgumentException $e) {
Logger::error('exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
continue;
@ -377,7 +364,7 @@ function mailstream_send(string $message_id, array $item, array $user): bool
return true;
}
require_once (dirname(__file__) . '/phpmailer/class.phpmailer.php');
require_once(dirname(__file__) . '/phpmailer/class.phpmailer.php');
$item['body'] = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
@ -422,10 +409,11 @@ function mailstream_send(string $message_id, array $item, array $user): bool
$item['body'] = BBCode::convertForUriId($item['uri-id'], $item['body'], BBCode::CONNECTORS);
$item['url'] = DI::baseUrl() . '/display/' . $item['guid'];
$mail->Body = Renderer::replaceMacros($template, [
'$upstream' => DI::l10n()->t('Upstream'),
'$uri' => DI::l10n()->t('URI'),
'$local' => DI::l10n()->t('Local'),
'$item' => $item]);
'$upstream' => DI::l10n()->t('Upstream'),
'$uri' => DI::l10n()->t('URI'),
'$local' => DI::l10n()->t('Local'),
'$item' => $item
]);
$mail->Body = mailstream_html_wrap($mail->Body);
if (!$mail->Send()) {
throw new Exception($mail->ErrorInfo);
@ -462,29 +450,6 @@ function mailstream_html_wrap(string &$text)
return $text;
}
/**
* Convert v1 mailstream table entries to v2 workerqueue items
*/
function mailstream_convert_table_entries()
{
$ms_item_ids = DBA::selectToArray('mailstream_item', [], ['message-id', 'uri', 'uid', 'contact-id'], ["`mailstream_item`.`completed` IS NULL"]);
Logger::debug('processing items', ['count' => count($ms_item_ids)]);
foreach ($ms_item_ids as $ms_item_id) {
$send_hook_data = array('uid' => $ms_item_id['uid'],
'contact-id' => $ms_item_id['contact-id'],
'uri' => $ms_item_id['uri'],
'message_id' => $ms_item_id['message-id'],
'tries' => 0);
if (!$ms_item_id['message-id'] || !strlen($ms_item_id['message-id'])) {
Logger::info('item has no message-id', ['item' => $ms_item_id['id'], 'uri' => $ms_item_id['uri']]);
continue;
}
Logger::info('convert item to workerqueue', $send_hook_data);
Hook::fork(Worker::PRIORITY_LOW, 'mailstream_send_hook', $send_hook_data);
}
DBA::e('DROP TABLE `mailstream_item`');
}
/**
* Form for configuring mailstream features for a user
*

View file

@ -1,5 +1,4 @@
<?php
/*
* Name: Mastodon Custom Emojis
* Description: Replace emojis shortcodes in Mastodon posts with their originating server custom emojis images.
@ -9,7 +8,6 @@
* Status: Unsupported
*/
use Friendica\App;
use Friendica\Content\Smilies;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Hook;
@ -78,7 +76,7 @@ function mastodoncustomemojis_fetch_custom_emojis_for_url($api_base_url)
$api_url = $api_base_url . '/api/v1/custom_emojis';
$fetchResult = DI::httpClient()->fetchFull($api_url);
$fetchResult = DI::httpClient()->get($api_url);
if ($fetchResult->isSuccess()) {
$emojis_array = json_decode($fetchResult->getBodyString(), true);

View file

@ -4,7 +4,7 @@
#
#
# Translators:
# Florent C., 2023
# cracrayol, 2023-2024
# Nicolas Derive, 2022-2023
# StefOfficiel <pichard.stephane@free.fr>, 2015
# Vincent Vindarel <vindarel@mailz.org>, 2018
@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-10 14:42-0500\n"
"PO-Revision-Date: 2014-06-23 10:34+0000\n"
"Last-Translator: Florent C., 2023\n"
"Last-Translator: cracrayol, 2023-2024\n"
"Language-Team: French (http://app.transifex.com/Friendica/friendica/language/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -42,7 +42,7 @@ msgstr "Liste de mots-clés - séparés par des virgules - à cacher"
msgid ""
"Use /expression/ to provide regular expressions, #tag to specfically match "
"hashtags (case-insensitive), or regular words (case-sensitive)"
msgstr "Utiliser /expression/ pour fournir des expressions régulières, #tag pour correspondre à un tag (insensible à la casse), ou des mots classiques (sensible à la casse)"
msgstr "Utiliser /expression/ pour fournir des expressions régulières, #etiquette pour correspondre à une étiquette (insensible à la casse), ou des mots classiques (sensible à la casse)"
#: nsfw.php:72
msgid "Content Filter (NSFW and more)"

View file

@ -8,7 +8,7 @@ function string_plural_select_fr($n){
$a->strings['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.'] = 'Cette extension recherche des mots/textes spécifiés dans les publications et les masque. Elle peut être utilisée pour filtrer le contenu étiqueté par exemple avec #NSFW qui peut être considéré comme inapproprié à certains moments ou endroits, comme par exemple au travail. Elle est aussi utile pour cacher du contenu non pertinent ou ennuyeux d\'une vue directe.';
$a->strings['Enable Content filter'] = 'Activer le filtrage de contenu';
$a->strings['Comma separated list of keywords to hide'] = 'Liste de mots-clés - séparés par des virgules - à cacher';
$a->strings['Use /expression/ to provide regular expressions, #tag to specfically match hashtags (case-insensitive), or regular words (case-sensitive)'] = 'Utiliser /expression/ pour fournir des expressions régulières, #tag pour correspondre à un tag (insensible à la casse), ou des mots classiques (sensible à la casse)';
$a->strings['Use /expression/ to provide regular expressions, #tag to specfically match hashtags (case-insensitive), or regular words (case-sensitive)'] = 'Utiliser /expression/ pour fournir des expressions régulières, #etiquette pour correspondre à une étiquette (insensible à la casse), ou des mots classiques (sensible à la casse)';
$a->strings['Content Filter (NSFW and more)'] = 'Filtre de contenu (NSFW et autres)';
$a->strings['Regular expression "%s" fails to compile'] = 'La compilation de l\'expression régulière "%s" a échoué';
$a->strings['Filtered tag: %s'] = 'Tag filtré : %s';

View file

@ -6,6 +6,7 @@ use Friendica\Content\Pager;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Module\Moderation\Users\Active;
@ -18,6 +19,11 @@ class RatioedPanel extends Active
{
Active::content();
if (isset(DI::args()->getArgv()[1]) and DI::args()->getArgv()[1] === 'help') {
$template = Renderer::getMarkupTemplate('/help.tpl', 'addon/ratioed/');
return Renderer::replaceMacros($template, array('$config' => DI::baseUrl() . '/settings/addon'));
}
$action = $this->parameters['action'] ?? '';
$uid = $this->parameters['uid'] ?? 0;
@ -111,6 +117,7 @@ class RatioedPanel extends Active
return self::getTabsHTML('ratioed') . Renderer::replaceMacros($t, [
// strings //
'$title' => $this->t('Moderation'),
'$help_url' => $this->baseUrl . '/ratioed/help',
'$page' => $this->t('Behaviour'),
'$select_all' => $this->t('select all'),
'$delete' => $this->t('Delete'),

View file

@ -0,0 +1,92 @@
<div class="panel 'help-content-wrapper">
<div class="panel-body">
<h2>Ratioed Plugin Help</h2>
<p>
This plugin provides administrators with additional statistics about
the behaviour of users. These may be useful as early warning signs
that warrant more carefully watching the behaviour of a user. They
are <em>not</em> suitable as a trigger for instantly blocking,
muting, or reporting a user, since they lack context.
</p>
<p>
The name of the plugin comes
from <a href="https://knowyourmeme.com/editorials/guides/what-is-the-ratio-and-what-does-it-mean-to-get-ratioed-twitters-1-rule-explained">"The
Ratio"</a>, a well-known quick rule of thumb:
</p>
<blockquote>
If the Replies:RT ratio is greater than 2:1, you done messed up.
</blockquote>
<p>
To "get ratioed" is to receive a large number of comments in a short
space of time, with relatively few likes or boosts. If commenters
were enthusiastic about the posts, they would also have liked or
boosted them. Receiving many comments without such likes or boosts
indicates the comments were probably angry. This anger may or may
not be justified, but either way this is probably something
moderators should be aware of.
</p>
<p>
This plugin allows viewing of an actual ratio, calculated over the
last 24 hours. This is a useful timeframe for sudden dogpiling
events that administrators might not otherwise notice. The plugin
also calculates other statistics.
</p>
<h3>Explanation of Statistics</h3>
<h4>Blocked by</h4>
<p>
This summarises the number of users on remote servers that have
blocked this user.
</p>
<p>
Note that the ActivityPub spec expressly says that
implementations "SHOULD NOT" forward such block messages to
remote servers. Nevertheless some implementations do this
anyway, notably Mastodon. This statistic can only count block
messages from servers that do this, as well as blocks from local
users. As such, it is usually an undercount.
</p>
<p>
The reason the spec recommends against forwarding these messages
is that they can lead to retaliation. For this reason, this
plugin deliberately does not provide any way to investigate
exactly who blocked the user.
</p>
<h4>Comments last 24h</h4>
<p>
This gives the number of comments made on the top-level posts that
this user made within the last 24 hours.
</p>
<h4>Reactions last 24h</h4>
<p>
This collects the number of likes, boosts, or other "one-click"
interactions made on the user's top-level posts within the last 24
hours.
</p>
<h4>Ratio last 24h</h4>
<p>
This is the ratio between "Comments last 24h" and "Reactions last
24h". It is intended to approximate the traditional ratio as
understood on Twitter.
</p>
<h3>Performance</h3>
<p>
The statistics are computed from scratch each time the page loads.
It's possible that this might put a heavy load on the database. and
the page may take a long time to load.
</p>
<h3>Extending</h3>
<p>
Suggestions for additional statistics are welcome, especially from
moderators. This plugin should be considered a sandbox for
experimentation, so it is not necessary to prove that any statistic
is correlated with unwanted behaviour.
</p>
<p>
However, this plugin does deal with potentially sensitive
information. Even if moderators do in principle have access to all
information, it should not necessarily be highlighted. Statistics
should be kept anonymous and neutral. Also, they should be
presented only to moderators, not to the users themselves.
</p>
</div>
</div>

View file

@ -5,7 +5,7 @@
#
# Translators:
# Hypolite Petovan <hypolite@mrpetovan.com>, 2022
# Florent C., 2023
# cracrayol, 2024
#
#, fuzzy
msgid ""
@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-21 19:16-0500\n"
"PO-Revision-Date: 2018-03-20 07:26+0000\n"
"Last-Translator: Florent C., 2023\n"
"Last-Translator: cracrayol, 2024\n"
"Language-Team: French (https://app.transifex.com/Friendica/teams/12172/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@ -24,7 +24,7 @@ msgstr ""
#: securemail.php:50
msgid "Enable Secure Mail"
msgstr "Activer l'extension des emails sécurisés"
msgstr "Activer l'extension des courriels sécurisés"
#: securemail.php:51
msgid "Public key"
@ -36,7 +36,7 @@ msgstr "Votre clé publique PGP formatée compatible ASCII"
#: securemail.php:56
msgid "\"Secure Mail\" Settings"
msgstr "Paramètres des emails sécurisés"
msgstr "Paramètres des courriels sécurisés"
#: securemail.php:59
msgid "Save Settings"

View file

@ -5,10 +5,10 @@ function string_plural_select_fr($n){
$n = intval($n);
if (($n == 0 || $n == 1)) { return 0; } else if ($n != 0 && $n % 1000000 == 0) { return 1; } else { return 2; }
}}
$a->strings['Enable Secure Mail'] = 'Activer l\'extension des emails sécurisés';
$a->strings['Enable Secure Mail'] = 'Activer l\'extension des courriels sécurisés';
$a->strings['Public key'] = 'Clé publique';
$a->strings['Your public PGP key, ascii armored format'] = 'Votre clé publique PGP formatée compatible ASCII';
$a->strings['"Secure Mail" Settings'] = 'Paramètres des emails sécurisés';
$a->strings['"Secure Mail" Settings'] = 'Paramètres des courriels sécurisés';
$a->strings['Save Settings'] = 'Enregistrer les paramètres';
$a->strings['Save and send test'] = 'Enregistrer et envoyer un message de test';
$a->strings['Test email sent'] = 'Courriel de test envoyé avec succès';

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 405 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

@ -2,30 +2,28 @@
/*
* Name: Smiley Pack
* Description: Pack of smileys that make master too AOLish.
* Version: 1.05
* Version: 1.06
* Author: Thomas Willingham (based on Mike Macgirvin's Adult Smile template)
* Author: Matthias Ebers <https://loma.ml/profile/one>
* All smileys from sites offering them as Public Domain
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
function smiley_pack_install() {
function smiley_pack_install()
{
Hook::register('smilie', 'addon/smiley_pack/smiley_pack.php', 'smiley_pack_smilies');
}
function smiley_pack_smilies(array &$b)
{
#Smileys are split into various directories by the intended range of emotions. This is in case we get too big and need to modularise things. We can then cut and paste the right lines, move the right directory, and just change the name of the addon to happy_smilies or whatever.
#Smileys are split into various directories by the intended range of emotions. This is in case we get too big and need to modularise things. We can then cut and paste the right lines, move the right directory, and just change the name of the addon to happy_smilies or whatever.
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#when all else fails.
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#when all else fails.
#Animal smileys.
#Animal smileys.
$b['texts'][] = ':bunnyflowers:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/bunnyflowers.gif' . '" alt="' . ':bunnyflowers:' . '" />';
@ -50,7 +48,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':cow:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/cow.gif' . '" alt="' . ':cow:' . '" />';
$b['texts'][] = ':crab:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/crab.gif' . '" alt="' . ':crab:' . '" />';
@ -71,7 +69,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':horse:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/horse.gif' . '" alt="' . ':horse:' . '" />';
$b['texts'][] = ':parrot:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/parrot.gif' . '" alt="' . ':parrot:' . '" />';
@ -99,16 +97,13 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':pig:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/pig.gif' . '" alt="' . ':pig:' . '" />';
#Baby Smileys
#Baby Smileys
$b['texts'][] = ':baby:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/baby.gif' . '" alt="' . ':baby:' . '" />';
$b['texts'][] = ':babycot:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/babycot.gif' . '" alt="' . ':babycot:' . '" />';
$b['texts'][] = ':pregnant:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/pregnant.gif' . '" alt="' . ':pregnant:' . '" />';
@ -116,11 +111,10 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':stork:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/stork.gif' . '" alt="' . ':stork:' . '" />';
#Confused Smileys
#Confused Smileys
$b['texts'][] = ':confused:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/confused.gif' . '" alt="' . ':confused:' . '" />';
$b['texts'][] = ':shrug:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/shrug.gif' . '" alt="' . ':shrug:' . '" />';
@ -130,13 +124,12 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':dazed:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/dazed.gif' . '" alt="' . ':dazed:' . '" />';
#Cool Smileys
#Cool Smileys
$b['texts'][] = ':affro:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/cool/affro.gif' . '" alt="' . ':affro:' . '" />';
#Devil/Angel Smileys
#Devil/Angel Smileys
$b['texts'][] = ':angel:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/angel.gif' . '" alt="' . ':angel:' . '" />';
@ -152,20 +145,20 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':devillish:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/devil.gif' . '" alt="' . ':devillish:' . '" />';
$b['texts'][] = ':daseesaw:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/daseesaw.gif' . '" alt="' . ':daseesaw:' . '" />';
$b['texts'][] = ':turnevil:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/turnevil.gif' . '" alt="' . ':turnevil:' . '" />';
$b['texts'][] = ':saint:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/saint.gif' . '" alt="' . ':saint:' . '" />';
$b['texts'][] = ':graveside:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/graveside.gif' . '" alt="' . ':graveside:' . '" />';
#Unpleasent smileys.
#Unpleasent smileys.
$b['texts'][] = ':toilet:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/disgust/toilet.gif' . '" alt="' . ':toilet:' . '" />';
@ -176,7 +169,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':fartblush:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/disgust/fartblush.gif' . '" alt="' . ':fartblush:' . '" />';
#Drinks
#Drinks
$b['texts'][] = ':tea:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/drink/tea.gif' . '" alt="' . ':tea:' . '" />';
@ -184,7 +177,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':drool:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/drool/drool.gif' . '" alt="' . ':drool:' . '" />';
#Sad smileys
#Sad smileys
$b['texts'][] = ':crying:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sad/crying.png' . '" alt="' . ':crying:' . '" />';
@ -195,12 +188,12 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':sigh:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sad/sigh.gif' . '" alt="' . ':sigh:' . '" />';
#Smoking - only one smiley in here, maybe it needs moving elsewhere?
#Smoking - only one smiley in here, maybe it needs moving elsewhere?
$b['texts'][] = ':smoking:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/smoking/smoking.gif' . '" alt="' . ':smoking:' . '" />';
#Sport smileys
#Sport smileys
$b['texts'][] = ':basketball:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/basketball.gif' . '" alt="' . ':basketball:' . '" />';
@ -231,11 +224,11 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':snooker:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/snooker.gif' . '" alt="' . ':snooker:' . '" />';
$b['texts'][] = ':horseriding:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/horseriding.gif' . '" alt="' . ':horseriding:' . '" />';
#Love smileys
#Love smileys
$b['texts'][] = ':iloveyou:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/love/iloveyou.gif' . '" alt="' . ':iloveyou:' . '" />';
@ -255,7 +248,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':loveheart:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/love/loveheart.gif' . '" alt="' . ':loveheart:' . '" />';
#Tired/Sleep smileys
#Tired/Sleep smileys
$b['texts'][] = ':countsheep';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/tired/countsheep.gif' . '" alt="' . ':countsheep:' . '" />';
@ -269,7 +262,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':yawn:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/tired/yawn.gif' . '" alt="' . ':yawn:' . '" />';
#Fight/Flame/Violent smileys
#Fight/Flame/Violent smileys
$b['texts'][] = ':2guns:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fight/2guns.gif' . '" alt="' . ':2guns:' . '" />';
@ -313,7 +306,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':acid:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fight/acid.gif' . '" alt="' . ':acid:' . '" />';
#Fantasy smileys - monsters and dragons fantasy. The other type of fantasy belongs in adult smileys
#Fantasy smileys - monsters and dragons fantasy. The other type of fantasy belongs in adult smileys
$b['texts'][] = ':alienmonster:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fantasy/alienmonster.gif' . '" alt="' . ':alienmonster:' . '" />';
@ -336,7 +329,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':mummy:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fantasy/mummy.gif' . '" alt="' . ':mummy:' . '" />';
#Food smileys
#Food smileys
$b['texts'][] = ':apple:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/food/apple.gif' . '" alt="' . ':apple:' . '" />';
@ -368,7 +361,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':birthdaycake:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/food/birthdaycake.gif' . '" alt="' . ':birthdaycake:' . '" />';
#Happy smileys
#Happy smileys
$b['texts'][] = ':cloud9:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/happy/cloud9.gif' . '" alt="' . ':cloud9:' . '" />';
@ -376,7 +369,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':tearsofjoy:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/happy/tearsofjoy.gif' . '" alt="' . ':tearsofjoy:' . '" />';
#Repsect smileys
#Repsect smileys
$b['texts'][] = ':bow:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/bow.gif' . '" alt="' . ':bow:' . '" />';
@ -390,7 +383,19 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':number1:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/number1.gif' . '" alt="' . ':number1:' . '" />';
#Laugh smileys
$b['texts'][] = ':cc_cc:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/cc.png' . '" alt="' . ':cc_cc:' . '" />';
$b['texts'][] = ':cc_by:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/ccby.png' . '" alt="' . ':cc_by:' . '" />';
$b['texts'][] = ':cc_sa:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/ccsa.png' . '" alt="' . ':cc_sa:' . '" />';
$b['texts'][] = ':cc_0:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/cc0.png' . '" alt="' . ':cc_0:' . '" />';
#Laugh smileys
$b['texts'][] = ':hahaha:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/laugh/hahaha.gif' . '" alt="' . ':hahaha:' . '" />';
@ -401,24 +406,23 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':rofl:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/laugh/rofl.gif' . '" alt="' . ':rofl:' . '" />';
#Music smileys
#Music smileys
$b['texts'][] = ':drums:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/drums.gif' . '" alt="' . ':drums:' . '" />';
$b['texts'][] = ':guitar:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/guitar.gif' . '" alt="' . ':guitar:' . '" />';
$b['texts'][] = ':trumpet:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/trumpet.gif' . '" alt="' . ':trumpet:' . '" />';
#Smileys that used to be in core
#Smileys that used to be in core
$b['texts'][] = ':headbang:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/oldcore/headbang.gif' . '" alt="' . ':headbang:' . '" />';
$b['texts'][] = ':beard:';
$b['texts'][] = ':beard:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/oldcore/beard.png' . '" alt="' . ':beard:' . '" />';
$b['texts'][] = ':whitebeard:';
@ -436,7 +440,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':headdesk:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/oldcore/headbang.gif' . '" alt="' . ':headdesk:' . '" />';
#These two are still in core, so oldcore isn't strictly right, but we don't want too many directories
#These two are still in core, so oldcore isn't strictly right, but we don't want too many directories
$b['texts'][] = ':-d';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/oldcore/laughing.gif' . '" alt="' . ':-d' . '" />';
@ -444,8 +448,8 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':-o';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/oldcore/surprised.gif' . '" alt="' . ':-o' . '" />';
# Regex killers - stick these at the bottom so they appear at the end of the English and
# at the start of $OtherLanguage.
# Regex killers - stick these at the bottom so they appear at the end of the English and
# at the start of $OtherLanguage.
$b['texts'][] = ':cool:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/cool/cool.gif' . '" alt="' . ':cool:' . '" />';
@ -455,7 +459,7 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':golf:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/golf.gif' . '" alt="' . ':golf:' . '" />';
$b['texts'][] = ':football:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/football.gif' . '" alt="' . ':football:' . '" />';
@ -480,63 +484,167 @@ function smiley_pack_smilies(array &$b)
$b['texts'][] = ':gangs:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fight/gangs.gif' . '" alt="' . ':gangs:' . '" />';
$b['texts'][] = ':dj:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/dj.gif' . '" alt="' . ':dj:' . '" />';
$b['texts'][] = ':elvis:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/elvis.gif' . '" alt="' . ':elivs:' . '" />';
$b['texts'][] = ':violin:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/violin.gif' . '" alt="' . ':violin:' . '" />';
# New Gif Emoji (@one@loma.ml)
# Fediverse
# New Gif Emoji (@one@loma.ml)
# Fediverse
$b['texts'][] = ':friendica:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/friendica.gif' . '" alt="' . ':friendica:' . '" />';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/friendica.png' . '" alt="' . ':friendica:' . '" />';
$b['texts'][] = ':fediverse:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/fediverse.gif' . '" alt="' . ':fediverse:' . '" />';
$b['texts'][] = ':mastodon:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/mastodon.gif' . '" alt="' . ':mastodon:' . '" />';
$b['texts'][] = ':pleroma:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/pleroma.gif' . '" alt="' . ':pleroma:' . '" />';
$b['texts'][] = ':misskey:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/misskey.gif' . '" alt="' . ':misskey:' . '" />';
$b['texts'][] = ':diaspora:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/diaspora.gif' . '" alt="' . ':diaspora:' . '" />';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/diaspora.png' . '" alt="' . ':diaspora:' . '" />';
$b['texts'][] = ':hubzilla:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/hubzilla.gif' . '" alt="' . ':hubzilla:' . '" />';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/hubzilla.png' . '" alt="' . ':hubzilla:' . '" />';
$b['texts'][] = ':pixelfed:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/pixelfed.gif' . '" alt="' . ':pixelfeed:' . '" />';
$b['texts'][] = ':nextcloud:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/nextcloud.gif' . '" alt="' . ':nextcloud:' . '" />';
$b['texts'][] = ':activitypub:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/ap.gif' . '" alt="' . ':activitypub:' . '" />';
# ccc
# ccc
$b['texts'][] = ':ccc event:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/ccc/ccc.gif' . '" alt="' . ':ccc event:' . '" />';
# Commercial
# Commercial
$b['texts'][] = ':youtube:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/youtube.gif' . '" alt="' . ':youtube:' . '" />';
$b['texts'][] = ':spotify:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/spotify.gif' . '" alt="' . ':spotify:' . '" />';
$b['texts'][] = ':twitter:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/twitter.gif' . '" alt="' . ':twitter:' . '" />';
$b['texts'][] = ':twitch:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/twitch.gif' . '" alt="' . ':twitch:' . '" />';
$b['texts'][] = ':facebook:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/facebook.gif' . '" alt="' . ':facebook:' . '" />';
$b['texts'][] = ':threads:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/threads.png' . '" alt="' . ':threads:' . '" />';
$b['texts'][] = ':google:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/google.gif' . '" alt="' . ':google:' . '" />';
$b['texts'][] = ':signal:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/signal.gif' . '" alt="' . ':signal:' . '" />';
$b['texts'][] = ':tiktok:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/tiktok.gif' . '" alt="' . ':tiktok:' . '" />';
$b['texts'][] = ':whatsapp:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/whatsapp.gif' . '" alt="' . ':whatsapp:' . '" />';
$b['texts'][] = ':instagram:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/instagram.gif' . '" alt="' . ':instagram:' . '" />';
$b['texts'][] = ':telegram:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/telegram.gif' . '" alt="' . ':telegram:' . '" />';
$b['texts'][] = ':windows:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/windows.png' . '" alt="' . ':windows:' . '" />';
$b['texts'][] = ':github:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/github.png' . '" alt="' . ':github:' . '" />';
$b['texts'][] = ':threema:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/threema.png' . '" alt="' . ':threema:' . '" />';
# nonCommercial
$b['texts'][] = ':invidious:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/noncommercial/invidious.gif' . '" alt="' . ':invidious:' . '" />';
$b['texts'][] = ':bluesky:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/noncommercial/bluesky.png' . '" alt="' . ':bluesky:' . '" />';
$b['texts'][] = ':vivaldi:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/noncommercial/vivaldi.png' . '" alt="' . ':vivaldi:' . '" />';
# opensource
$b['texts'][] = ':firefox:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/firefox.png' . '" alt="' . ':firefox:' . '" />';
$b['texts'][] = ':linuxopensuse:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/opensuse.png' . '" alt="' . ':linuxopensuse:' . '" />';
$b['texts'][] = ':linuxdebian:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/debian.png' . '" alt="' . ':linuxdebian:' . '" />';
$b['texts'][] = ':linuxfedora:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/fedora.png' . '" alt="' . ':linuxfedora:' . '" />';
$b['texts'][] = ':linuxubuntu:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/ubuntu.png' . '" alt="' . ':linuxubuntu:' . '" />';
$b['texts'][] = ':linuxmint:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/mint.png' . '" alt="' . ':linuxmint:' . '" />';
$b['texts'][] = ':fdroid:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/fdroid.png' . '" alt="' . ':fdroid:' . '" />';
$b['texts'][] = ':tutanota:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/tutanota.png' . '" alt="' . ':tutanota:' . '" />';
$b['texts'][] = ':raspi:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/raspi.png' . '" alt="' . ':raspi:' . '" />';
$b['texts'][] = ':linux:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/linux.png' . '" alt="' . ':linux:' . '" />';
$b['texts'][] = ':kde:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/kde.png' . '" alt="' . ':kde:' . '" />';
$b['texts'][] = ':firefoxnightly:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/firefoxnightly.png' . '" alt="' . ':firefoxnightly:' . '" />';
$b['texts'][] = ':archlinux:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/archlinux.png' . '" alt="' . ':archlinux:' . '" />';
$b['texts'][] = ':thunderbird:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/thunderbird.png' . '" alt="' . ':thunderbird:' . '" />';
$b['texts'][] = ':vivaldi:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/vivaldi.png' . '" alt="' . ':vivaldi:' . '" />';
$b['texts'][] = ':jabber:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/jabber.png' . '" alt="' . ':jabber:' . '" />';
$b['texts'][] = ':matrix:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/matrix.png' . '" alt="' . ':matrix:' . '" />';
$b['texts'][] = ':xmpp:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/xmpp.png' . '" alt="' . ':xmpp:' . '" />';
$b['texts'][] = ':foss:';
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/opensource/foss.png' . '" alt="' . ':foss:' . '" />';
}

View file

@ -8,64 +8,81 @@ msgid ""
msgstr ""
"Project-Id-Version: friendica\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-07-25 13:15+0000\n"
"PO-Revision-Date: 2021-02-20 00:23+0000\n"
"Last-Translator: Farida Khalaf <faridakhalaf@hotmail.com>\n"
"Language-Team: Arabic (http://www.transifex.com/Friendica/friendica/language/ar/)\n"
"POT-Creation-Date: 2023-04-29 06:56+0000\n"
"PO-Revision-Date: 2014-06-23 12:58+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: Arabic (http://app.transifex.com/Friendica/friendica/language/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: ar\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
#: tumblr.php:40
#: tumblr.php:243
msgid "Permission denied."
msgstr "الطلب مرفوض."
#: tumblr.php:70 tumblr.php:284
#: tumblr.php:296
msgid "Save Settings"
msgstr "Save Settings"
#: tumblr.php:72
#: tumblr.php:297
msgid "Consumer Key"
msgstr ""
#: tumblr.php:73
#: tumblr.php:298
msgid "Consumer Secret"
msgstr ""
#: tumblr.php:178
msgid "You are now authenticated to tumblr."
#: tumblr.php:299
msgid "Maximum tags"
msgstr ""
#: tumblr.php:179
msgid "return to the connector page"
msgstr "الرجوع إلى صفحة الموصل"
#: tumblr.php:195
msgid "Post to Tumblr"
#: tumblr.php:299
msgid ""
"Maximum number of tags that a user can follow. Enter 0 to deactivate the "
"feature."
msgstr ""
#: tumblr.php:225 tumblr.php:229
msgid "Tumblr Export"
msgstr ""
#: tumblr.php:233
msgid "(Re-)Authenticate your tumblr page"
msgstr ""
#: tumblr.php:237
msgid "Enable Tumblr Post Addon"
msgstr ""
#: tumblr.php:243
msgid "Post to Tumblr by default"
msgstr ""
#: tumblr.php:264
#: tumblr.php:336
msgid "Post to page:"
msgstr ""
#: tumblr.php:278
#: tumblr.php:342
msgid "(Re-)Authenticate your tumblr page"
msgstr ""
#: tumblr.php:343
msgid "You are not authenticated to tumblr"
msgstr ""
#: tumblr.php:348
msgid "Enable Tumblr Post Addon"
msgstr ""
#: tumblr.php:349
msgid "Post to Tumblr by default"
msgstr ""
#: tumblr.php:350
msgid "Import the remote timeline"
msgstr ""
#: tumblr.php:351
msgid "Subscribed tags"
msgstr ""
#: tumblr.php:351
#, php-format
msgid ""
"Comma separated list of up to %d tags that will be imported additionally to "
"the timeline"
msgstr ""
#: tumblr.php:357
msgid "Tumblr Import/Export"
msgstr ""
#: tumblr.php:375
msgid "Post to Tumblr"
msgstr ""

View file

@ -7,4 +7,3 @@ function string_plural_select_ar($n){
}}
$a->strings['Permission denied.'] = 'الطلب مرفوض.';
$a->strings['Save Settings'] = 'Save Settings';
$a->strings['return to the connector page'] = 'الرجوع إلى صفحة الموصل';

Some files were not shown because too many files have changed in this diff Show more