Compare commits

...

9 Commits

Author SHA1 Message Date
Hypolite Petovan 4dedd24320 Merge pull request 'Fix PHP warning and use quotes' (#1454) from toddy/friendica-addons:develop into develop
Reviewed-on: friendica/friendica-addons#1454
2024-01-08 13:24:46 +01:00
Dr. Tobias Quathamer bddb7f4d49 Fix PHP warning and use quotes 2024-01-08 10:36:21 +01:00
Tobias Diekershoff 82073db292 Merge pull request 'Initial commit of url_replace addon.' (#1453) from toddy/friendica-addons:develop into develop
Reviewed-on: friendica/friendica-addons#1453
2024-01-05 09:56:46 +01:00
Tobias Quathamer a26e90b202 Initial commit of url_replace addon.
This closes https://github.com/friendica/friendica/issues/13220
2024-01-05 00:21:39 +01:00
Hypolite Petovan b87588e371 Merge pull request 'Tumblr/Bluesky: Avoid problems on first fetch' (#1452) from heluecht/friendica-addons:first-fetch into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1452
2023-12-21 13:45:24 +01:00
Michael 96c70489f5 Tumblr/Bluesky: Avoid problems on first fetch 2023-12-21 05:23:38 +00:00
Hypolite Petovan 77ad52d1f4 Merge pull request 'Bluesky/Tumblr: Set "received" to "created" if fetched after previous poll' (#1451) from heluecht/friendica-addons:received into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1451
2023-12-21 05:21:43 +01:00
Michael 96a354bc65 Bluesky/Tumblr: Set "received" to "created" if fetched after previous poll 2023-12-20 20:46:24 +00:00
heluecht f32c90dc9f Merge pull request '[s3_storage] Bump version of akeeba/s3 to version 2.3.1' (#1450) from MrPetovan/friendica-addons:bug/deprecated into 2023.09-rc
Reviewed-on: friendica/friendica-addons#1450
2023-12-20 14:17:01 +01:00
10 changed files with 290 additions and 56 deletions

View File

@ -463,7 +463,7 @@ function bluesky_jot_nets(array &$jotnets_fields)
function bluesky_cron()
{
$last = DI::keyValue()->get('bluesky_last_poll');
$last = (int)DI::keyValue()->get('bluesky_last_poll');
$poll_interval = intval(DI::config()->get('bluesky', 'poll_interval'));
if (!$poll_interval) {
@ -498,13 +498,13 @@ function bluesky_cron()
// Refresh the token now, so that it doesn't need to be refreshed in parallel by the following workers
bluesky_get_token($pconfig['uid']);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid']);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_notifications.php', $pconfig['uid']);
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'], $last);
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import_feeds')) {
$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);
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed, $last);
}
}
}
@ -930,7 +930,7 @@ function bluesky_delete_post(string $uri, int $uid)
Logger::debug('Deleted', ['parts' => $parts]);
}
function bluesky_fetch_timeline(int $uid)
function bluesky_fetch_timeline(int $uid, int $last_poll)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getTimeline');
if (empty($data)) {
@ -942,7 +942,7 @@ function bluesky_fetch_timeline(int $uid)
}
foreach (array_reverse($data->feed) as $entry) {
bluesky_process_post($entry->post, $uid, Item::PR_NONE, 0);
bluesky_process_post($entry->post, $uid, Item::PR_NONE, 0, $last_poll);
if (!empty($entry->reason)) {
bluesky_process_reason($entry->reason, bluesky_get_uri($entry->post), $uid);
}
@ -993,7 +993,7 @@ function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
}
}
function bluesky_fetch_notifications(int $uid)
function bluesky_fetch_notifications(int $uid, int $last_poll)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.notification.listNotifications');
if (empty($data->notifications)) {
@ -1012,7 +1012,7 @@ function bluesky_fetch_notifications(int $uid)
$item['gravity'] = Item::GRAVITY_ACTIVITY;
$item['body'] = $item['verb'] = Activity::LIKE;
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $uid, $item['contact-id'], 0);
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $uid, $item['contact-id'], 0, $last_poll);
if (!empty($item['thr-parent'])) {
$data = Item::insert($item);
Logger::debug('Got like', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
@ -1026,7 +1026,7 @@ function bluesky_fetch_notifications(int $uid)
$item['gravity'] = Item::GRAVITY_ACTIVITY;
$item['body'] = $item['verb'] = Activity::ANNOUNCE;
$item['thr-parent'] = bluesky_get_uri($notification->record->subject);
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $uid, $item['contact-id'], 0);
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $uid, $item['contact-id'], 0, $last_poll);
if (!empty($item['thr-parent'])) {
$data = Item::insert($item);
Logger::debug('Got repost', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
@ -1041,17 +1041,17 @@ function bluesky_fetch_notifications(int $uid)
break;
case 'mention':
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0);
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0, $last_poll);
Logger::debug('Got mention', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
break;
case 'reply':
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0);
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0, $last_poll);
Logger::debug('Got reply', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
break;
case 'quote':
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0);
$data = bluesky_process_post($notification, $uid, Item::PR_PUSHED, 0, $last_poll);
Logger::debug('Got quote', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
break;
@ -1062,7 +1062,7 @@ function bluesky_fetch_notifications(int $uid)
}
}
function bluesky_fetch_feed(int $uid, string $feed)
function bluesky_fetch_feed(int $uid, string $feed, int $last_poll)
{
$data = bluesky_xrpc_get($uid, 'app.bsky.feed.getFeed', ['feed' => $feed]);
if (empty($data)) {
@ -1090,7 +1090,7 @@ function bluesky_fetch_feed(int $uid, string $feed)
Logger::debug('Unwanted language detected', ['text' => $entry->post->record->text]);
continue;
}
$id = bluesky_process_post($entry->post, $uid, Item::PR_TAG, 0);
$id = bluesky_process_post($entry->post, $uid, Item::PR_TAG, 0, $last_poll);
if (!empty($id)) {
$post = Post::selectFirst(['uri-id'], ['id' => $id]);
if (!empty($post['uri-id'])) {
@ -1106,7 +1106,7 @@ function bluesky_fetch_feed(int $uid, string $feed)
}
}
function bluesky_process_post(stdClass $post, int $uid, int $post_reason, $level): int
function bluesky_process_post(stdClass $post, int $uid, int $post_reason, int $level, int $last_poll): int
{
$uri = bluesky_get_uri($post);
@ -1121,20 +1121,20 @@ function bluesky_process_post(stdClass $post, int $uid, int $post_reason, $level
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, $uid);
$item = bluesky_get_content($item, $post->record, $uri, $uid, $uid, $level);
$item = bluesky_get_content($item, $post->record, $uri, $uid, $uid, $level, $last_poll);
if (empty($item)) {
return 0;
}
if (!empty($post->embed)) {
$item = bluesky_add_media($post->embed, $item, $uid, $level);
$item = bluesky_add_media($post->embed, $item, $uid, $level, $last_poll);
}
if (empty($item['post-reason'])) {
$item['post-reason'] = $post_reason;
}
return item::insert($item);
return Item::insert($item);
}
function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_uid): array
@ -1172,7 +1172,7 @@ function bluesky_get_header(stdClass $post, string $uri, int $uid, int $fetch_ui
return $item;
}
function bluesky_get_content(array $item, stdClass $record, string $uri, int $uid, int $fetch_uid, int $level): array
function bluesky_get_content(array $item, stdClass $record, string $uri, int $uid, int $fetch_uid, int $level, int $last_poll): array
{
if (empty($item)) {
return [];
@ -1181,7 +1181,7 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
if (!empty($record->reply)) {
$item['parent-uri'] = bluesky_get_uri($record->reply->root);
if ($item['parent-uri'] != $uri) {
$item['parent-uri'] = bluesky_fetch_missing_post($item['parent-uri'], $uid, $fetch_uid, $item['contact-id'], $level);
$item['parent-uri'] = bluesky_fetch_missing_post($item['parent-uri'], $uid, $fetch_uid, $item['contact-id'], $level, $last_poll);
if (empty($item['parent-uri'])) {
return [];
}
@ -1189,7 +1189,7 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
$item['thr-parent'] = bluesky_get_uri($record->reply->parent);
if (!in_array($item['thr-parent'], [$uri, $item['parent-uri']])) {
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $fetch_uid, $item['contact-id'], $level, $item['parent-uri']);
$item['thr-parent'] = bluesky_fetch_missing_post($item['thr-parent'], $uid, $fetch_uid, $item['contact-id'], $level, $last_poll, $item['parent-uri']);
if (empty($item['thr-parent'])) {
return [];
}
@ -1199,6 +1199,11 @@ function bluesky_get_content(array $item, stdClass $record, string $uri, int $ui
$item['body'] = bluesky_get_text($record, $item['uri-id']);
$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;
}
@ -1259,7 +1264,7 @@ function bluesky_get_text(stdClass $record, int $uri_id): string
return $text;
}
function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $level): array
function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $level, int $last_poll): array
{
$type = '$type';
switch ($embed->$type) {
@ -1296,11 +1301,11 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
break;
}
$shared = bluesky_get_header($embed->record, $uri, 0, $fetch_uid);
$shared = bluesky_get_content($shared, $embed->record->value, $uri, $item['uid'], $fetch_uid, $level);
$shared = bluesky_get_content($shared, $embed->record->value, $uri, $item['uid'], $fetch_uid, $level, $last_poll);
if (!empty($shared)) {
if (!empty($embed->record->embeds)) {
foreach ($embed->record->embeds as $single) {
$shared = bluesky_add_media($single, $shared, $fetch_uid, $level);
$shared = bluesky_add_media($single, $shared, $fetch_uid, $level, $last_poll);
}
}
Item::insert($shared);
@ -1316,11 +1321,11 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
$shared = Post::selectFirst(['uri-id'], ['uri' => $uri, 'uid' => $item['uid']]);
if (empty($shared)) {
$shared = bluesky_get_header($embed->record->record, $uri, 0, $fetch_uid);
$shared = bluesky_get_content($shared, $embed->record->record->value, $uri, $item['uid'], $fetch_uid, $level);
$shared = bluesky_get_content($shared, $embed->record->record->value, $uri, $item['uid'], $fetch_uid, $level, $last_poll);
if (!empty($shared)) {
if (!empty($embed->record->record->embeds)) {
foreach ($embed->record->record->embeds as $single) {
$shared = bluesky_add_media($single, $shared, $fetch_uid, $level);
$shared = bluesky_add_media($single, $shared, $fetch_uid, $level, $last_poll);
}
}
Item::insert($shared);
@ -1331,7 +1336,7 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
}
if (!empty($embed->media)) {
$item = bluesky_add_media($embed->media, $item, $fetch_uid, $level);
$item = bluesky_add_media($embed->media, $item, $fetch_uid, $level, $last_poll);
}
break;
@ -1394,7 +1399,7 @@ function bluesky_get_uri_parts(string $uri): ?stdClass
return $class;
}
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $causer, int $level, string $fallback = ''): string
function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $causer, int $level, int $last_poll = 0, string $fallback = ''): string
{
$fetched_uri = bluesky_fetch_post($uri, $uid);
if (!empty($fetched_uri)) {
@ -1426,7 +1431,7 @@ function bluesky_fetch_missing_post(string $uri, int $uid, int $fetch_uid, int $
$cdata = [];
}
return bluesky_process_thread($data->thread, $uid, $fetch_uid, $cdata, $level);
return bluesky_process_thread($data->thread, $uid, $fetch_uid, $cdata, $level, $last_poll);
}
function bluesky_fetch_post(string $uri, int $uid): string
@ -1444,7 +1449,7 @@ function bluesky_fetch_post(string $uri, int $uid): string
return '';
}
function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, array $cdata, int $level): string
function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, array $cdata, int $level, int $last_poll): string
{
if (empty($thread->post)) {
Logger::info('Invalid post', ['post' => $thread]);
@ -1456,7 +1461,7 @@ function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, arra
if (empty($fetched_uri)) {
Logger::debug('Process missing post', ['uri' => $uri]);
$item = bluesky_get_header($thread->post, $uri, $uid, $uid);
$item = bluesky_get_content($item, $thread->post->record, $uri, $uid, $fetch_uid, $level);
$item = bluesky_get_content($item, $thread->post->record, $uri, $uid, $fetch_uid, $level, $last_poll);
if (!empty($item)) {
$item['post-reason'] = Item::PR_FETCHED;
@ -1465,7 +1470,7 @@ function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, arra
}
if (!empty($thread->post->embed)) {
$item = bluesky_add_media($thread->post->embed, $item, $uid, $level);
$item = bluesky_add_media($thread->post->embed, $item, $uid, $level, $last_poll);
}
$id = Item::insert($item);
if (!$id) {
@ -1483,7 +1488,7 @@ function bluesky_process_thread(stdClass $thread, int $uid, int $fetch_uid, arra
}
foreach ($thread->replies ?? [] as $reply) {
$reply_uri = bluesky_process_thread($reply, $uid, $fetch_uid, $cdata, $level);
$reply_uri = bluesky_process_thread($reply, $uid, $fetch_uid, $cdata, $level, $last_poll);
Logger::debug('Reply has been processed', ['uri' => $uri, 'reply' => $reply_uri]);
}

View File

@ -6,11 +6,11 @@ function bluesky_feed_run($argv, $argc)
{
require_once 'addon/bluesky/bluesky.php';
if ($argc != 3) {
if ($argc != 4) {
return;
}
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]]);
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]]);
}

View File

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

View File

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

View File

@ -406,7 +406,7 @@ function tumblr_settings_post(array &$b)
function tumblr_cron()
{
$last = DI::keyValue()->get('tumblr_last_poll');
$last = (int)DI::keyValue()->get('tumblr_last_poll');
$poll_interval = intval(DI::config()->get('tumblr', 'poll_interval'));
if (!$poll_interval) {
@ -439,8 +439,8 @@ function tumblr_cron()
}
Logger::notice('importing timeline - start', ['user' => $pconfig['uid']]);
tumblr_fetch_dashboard($pconfig['uid']);
tumblr_fetch_tags($pconfig['uid']);
tumblr_fetch_dashboard($pconfig['uid'], $last);
tumblr_fetch_tags($pconfig['uid'], $last);
Logger::notice('importing timeline - done', ['user' => $pconfig['uid']]);
}
@ -719,10 +719,11 @@ function tumblr_get_post_from_uri(string $uri): array
/**
* Fetch posts for user defined hashtags for the given user
*
* @param integer $uid
* @param int $uid
* @param int $last_poll
* @return void
*/
function tumblr_fetch_tags(int $uid)
function tumblr_fetch_tags(int $uid, int $last_poll)
{
if (!DI::config()->get('tumblr', 'max_tags') ?? TUMBLR_DEFAULT_MAXIMUM_TAGS) {
return;
@ -731,7 +732,7 @@ function tumblr_fetch_tags(int $uid)
foreach (DI::pConfig()->get($uid, 'tumblr', 'tags') ?? [] as $tag) {
$data = tumblr_get($uid, 'tagged', ['tag' => $tag]);
foreach (array_reverse($data->response) as $post) {
$id = tumblr_process_post($post, $uid, Item::PR_TAG);
$id = tumblr_process_post($post, $uid, Item::PR_TAG, $last_poll);
if (!empty($id)) {
Logger::debug('Tag post imported', ['tag' => $tag, 'id' => $id]);
$post = Post::selectFirst(['uri-id'], ['id' => $id]);
@ -745,10 +746,11 @@ function tumblr_fetch_tags(int $uid)
/**
* Fetch the dashboard (timeline) for the given user
*
* @param integer $uid
* @param int $uid
* @param int $last_poll
* @return void
*/
function tumblr_fetch_dashboard(int $uid)
function tumblr_fetch_dashboard(int $uid, int $last_poll)
{
$parameters = ['reblog_info' => false, 'notes_info' => false, 'npf' => false];
@ -774,13 +776,13 @@ function tumblr_fetch_dashboard(int $uid)
Logger::debug('Importing post', ['uid' => $uid, 'created' => date(DateTimeFormat::MYSQL, $post->timestamp), 'id' => $post->id_string]);
tumblr_process_post($post, $uid, Item::PR_NONE);
tumblr_process_post($post, $uid, Item::PR_NONE, $last_poll);
DI::pConfig()->set($uid, 'tumblr', 'last_id', $last);
}
}
function tumblr_process_post(stdClass $post, int $uid, int $post_reason): int
function tumblr_process_post(stdClass $post, int $uid, int $post_reason, int $last_poll = 0): int
{
$uri = 'tumblr::' . $post->id_string . ':' . $post->reblog_key;
@ -798,7 +800,11 @@ function tumblr_process_post(stdClass $post, int $uid, int $post_reason): int
$item['post-reason'] = Item::PR_FOLLOWER;
}
$id = item::insert($item);
if (($last_poll != 0) && strtotime($item['created']) > $last_poll) {
$item['received'] = $item['created'];
}
$id = Item::insert($item);
if ($id) {
$stored = Post::selectFirst(['uri-id'], ['id' => $id]);

21
url_replace/LICENSE.md Normal file
View File

@ -0,0 +1,21 @@
# MIT License
Copyright © 2024 Dr. Tobias Quathamer <t.quathamer@mailbox.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17
url_replace/README.md Normal file
View File

@ -0,0 +1,17 @@
# URL replace
This addon will replace all occurrences of specified URLs with the address of
alternative servers in all displayed postings on a Friendica node.
You can use this to switch from Twitter (or X) to a nitter instance, from
YouTube to an invidious instance, or from some news sites to 12ft.io.
Note: If you are using the twitter connector on your server, the links to the
contacts profile pages will not be replaced by this addon. Only links in the
body of the postings are affected.
## Why
- Access a website without JavaScript enabled to prevent JavaScript analytics
and potential IP-based tracking
- Avoid seeing ads on YouTube videos

View File

@ -0,0 +1,50 @@
# ADDON url_replace
# Copyright (C)
# This file is distributed under the same license as the Friendica url_replace addon package.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-01-05 00:06+0100\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"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: url_replace.php:54
msgid "Nitter server"
msgstr ""
#: url_replace.php:56
msgid "Specify the URL with protocol. The default is https://nitter.net."
msgstr ""
#: url_replace.php:62
msgid "Invidious server"
msgstr ""
#: url_replace.php:64
msgid "Specify the URL with protocol. The default is https://yewtu.be."
msgstr ""
#: url_replace.php:70
msgid "Sites which are accessed through 12ft.io"
msgstr ""
#: url_replace.php:72
msgid "Specify the URLs with protocol, one per line."
msgstr ""
#: url_replace.php:76
msgid "Save settings"
msgstr ""
#: url_replace.php:125
msgid "(URL replace addon enabled for X, YouTube and some news sites.)"
msgstr ""

View File

@ -0,0 +1,5 @@
{{include file="field_input.tpl" field=$nitter_server}}
{{include file="field_input.tpl" field=$invidious_server}}
{{include file="field_textarea.tpl" field=$twelvefeet_sites}}
<div class="submit"><input type="submit" name="page_site" value="{{$submit}}" /></div>

130
url_replace/url_replace.php Normal file
View File

@ -0,0 +1,130 @@
<?php
/**
* Name: URL Replace
* Description: Replaces occurrences of specified URLs with the address of alternative servers in all displays of postings on a node.
* Version: 1.0
* Author: Dr. Tobias Quathamer <https://social.anoxinon.de/@toddy>
* Maintainer: Dr. Tobias Quathamer <https://social.anoxinon.de/@toddy>
*/
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
function url_replace_install()
{
Hook::register('prepare_body_final', 'addon/url_replace/url_replace.php', 'url_replace_render');
}
/**
* Handle sent data from admin settings
*/
function url_replace_addon_admin_post()
{
DI::config()->set('url_replace', 'nitter_server', rtrim(trim($_POST['nitter_server']), '/'));
DI::config()->set('url_replace', 'invidious_server', rtrim(trim($_POST['invidious_server']), '/'));
// Convert twelvefeet_sites into an array before setting the new value
$twelvefeet_sites = explode(PHP_EOL, $_POST['twelvefeet_sites']);
// Normalize URLs by using lower case, removing a trailing slash and whitespace
$twelvefeet_sites = array_map(fn ($value): string => rtrim(trim(strtolower($value)), '/'), $twelvefeet_sites);
// Do not store empty lines or duplicates
$twelvefeet_sites = array_filter($twelvefeet_sites, fn ($value): bool => !empty($value));
$twelvefeet_sites = array_unique($twelvefeet_sites);
// Ensure a protocol and default to HTTPS
$twelvefeet_sites = array_map(
fn ($value): string => substr($value, 0, 4) !== 'http' ? 'https://'.$value : $value,
$twelvefeet_sites
);
asort($twelvefeet_sites);
DI::config()->set('url_replace', 'twelvefeet_sites', $twelvefeet_sites);
}
/**
* Hook into admin settings to enable choosing a different server
* for twitter, youtube, and news sites.
*/
function url_replace_addon_admin(string &$o)
{
$nitter_server = DI::config()->get('url_replace', 'nitter_server');
$invidious_server = DI::config()->get('url_replace', 'invidious_server');
$twelvefeet_sites = implode(PHP_EOL, DI::config()->get('url_replace', 'twelvefeet_sites'));
$t = Renderer::getMarkupTemplate('admin.tpl', 'addon/url_replace/');
$o = Renderer::replaceMacros($t, [
'$nitter_server' => [
'nitter_server',
DI::l10n()->t('Nitter server'),
$nitter_server,
DI::l10n()->t('Specify the URL with protocol. The default is https://nitter.net.'),
null,
'placeholder="https://nitter.net"',
],
'$invidious_server' => [
'invidious_server',
DI::l10n()->t('Invidious server'),
$invidious_server,
DI::l10n()->t('Specify the URL with protocol. The default is https://yewtu.be.'),
null,
'placeholder="https://yewtu.be"',
],
'$twelvefeet_sites' => [
'twelvefeet_sites',
DI::l10n()->t('Sites which are accessed through 12ft.io'),
$twelvefeet_sites,
DI::l10n()->t('Specify the URLs with protocol, one per line.'),
null,
'rows="6"'
],
'$submit' => DI::l10n()->t('Save settings'),
]);
}
/**
* Replace proprietary URLs with their specified counterpart
*/
function url_replace_render(array &$b)
{
$replaced = false;
$nitter_server = DI::config()->get('url_replace', 'nitter_server');
if (empty($nitter_server)) {
$nitter_server = 'https://nitter.net';
}
$invidious_server = DI::config()->get('url_replace', 'invidious_server');
if (empty($invidious_server)) {
$invidious_server = 'https://yewtu.be';
}
// Handle some of twitter and youtube
$replacements = [
'https://mobile.twitter.com' => $nitter_server,
'https://twitter.com' => $nitter_server,
'https://mobile.x.com' => $nitter_server,
'https://x.com' => $nitter_server,
'https://www.youtube.com' => $invidious_server,
'https://youtube.com' => $invidious_server,
'https://m.youtube.com' => $invidious_server,
'https://youtu.be' => $invidious_server,
];
foreach ($replacements as $server => $replacement) {
if (strpos($b['html'], $server) !== false) {
$b['html'] = str_replace($server, $replacement, $b['html']);
$replaced = true;
}
}
$twelvefeet_sites = DI::config()->get('url_replace', 'twelvefeet_sites');
if (empty($twelvefeet_sites)) {
$twelvefeet_sites = [];
}
foreach ($twelvefeet_sites as $twelvefeet_site) {
if (strpos($b['html'], $twelvefeet_site) !== false) {
$b['html'] = str_replace($twelvefeet_site, 'https://12ft.io/'.$twelvefeet_site, $b['html']);
$replaced = true;
}
}
if ($replaced) {
$b['html'] .= '<hr><p><small>' . DI::l10n()->t('(URL replace addon enabled for X, YouTube and some news sites.)') . '</small></p>';
}
}