Compare commits
32 commits
Author | SHA1 | Date | |
---|---|---|---|
Tobias Diekershoff | ef37aa60e3 | ||
Michael | 6f3ba10466 | ||
Tobias Diekershoff | 778b9e3f61 | ||
loma-one | 10521115c4 | ||
Tobias Diekershoff | 956233ff1d | ||
Michael | 14e1c96775 | ||
Tobias Diekershoff | 7a7dbb579d | ||
loma-one | 712edf4236 | ||
Tobias Diekershoff | 5c0cddfc1d | ||
loma-one | 3dc77b2102 | ||
Tobias Diekershoff | 6c43a14198 | ||
Michael | 0dfb345f85 | ||
Tobias Diekershoff | ab837dfec5 | ||
Michael | 2f9076bffd | ||
Tobias Diekershoff | 454e9834bf | ||
Michael | 50930c301d | ||
Philipp Holzer | 3457ab2f3f | ||
Philipp Holzer | 276c27678f | ||
Tobias Diekershoff | cd95ca1a0a | ||
Tobias Diekershoff | 4414471100 | ||
46a55f13f7 | |||
Tobias Diekershoff | 0c04b086cb | ||
589cf712cc | |||
heluecht | ce53e48cb2 | ||
f3db763c59 | |||
heluecht | 4e5998c73d | ||
5f27f72b0d | |||
Hypolite Petovan | d3dcd5428c | ||
18e512cc8b | |||
7d5446a778 | |||
Hypolite Petovan | 38ea90104d | ||
08b46e5536 |
|
@ -4,6 +4,9 @@ pipeline:
|
||||||
clone_friendica_base:
|
clone_friendica_base:
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
commands:
|
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 clone https://github.com/friendica/friendica.git .
|
||||||
- git checkout $CI_COMMIT_BRANCH
|
- git checkout $CI_COMMIT_BRANCH
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -9,6 +9,9 @@ pipeline:
|
||||||
clone_friendica_base:
|
clone_friendica_base:
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
commands:
|
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 clone https://github.com/friendica/friendica.git .
|
||||||
- git checkout $CI_COMMIT_BRANCH
|
- git checkout $CI_COMMIT_BRANCH
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -4,6 +4,9 @@ pipeline:
|
||||||
clone_friendica_base:
|
clone_friendica_base:
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
commands:
|
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 clone https://github.com/friendica/friendica.git .
|
||||||
- git checkout $CI_COMMIT_BRANCH
|
- git checkout $CI_COMMIT_BRANCH
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -21,6 +21,9 @@ pipeline:
|
||||||
clone_friendica_base:
|
clone_friendica_base:
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
commands:
|
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 clone https://github.com/friendica/friendica.git .
|
||||||
- git checkout $CI_COMMIT_BRANCH
|
- git checkout $CI_COMMIT_BRANCH
|
||||||
clone_friendica_addon:
|
clone_friendica_addon:
|
||||||
|
|
|
@ -9,6 +9,9 @@ pipeline:
|
||||||
clone_friendica_base:
|
clone_friendica_base:
|
||||||
image: alpine/git
|
image: alpine/git
|
||||||
commands:
|
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 clone https://github.com/friendica/friendica.git .
|
||||||
- git checkout $CI_COMMIT_BRANCH
|
- git checkout $CI_COMMIT_BRANCH
|
||||||
when:
|
when:
|
||||||
|
|
|
@ -45,10 +45,12 @@ use Friendica\Model\Tag;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||||
|
use Friendica\Network\HTTPClient\Client\HttpClientRequest;
|
||||||
use Friendica\Object\Image;
|
use Friendica\Object\Image;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Protocol\Relay;
|
use Friendica\Protocol\Relay;
|
||||||
use Friendica\Util\DateTimeFormat;
|
use Friendica\Util\DateTimeFormat;
|
||||||
|
use Friendica\Util\Network;
|
||||||
use Friendica\Util\Strings;
|
use Friendica\Util\Strings;
|
||||||
|
|
||||||
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
|
const BLUESKY_DEFAULT_POLL_INTERVAL = 10; // given in minutes
|
||||||
|
@ -129,8 +131,13 @@ function bluesky_probe_detect(array &$hookData)
|
||||||
|
|
||||||
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
|
if (parse_url($hookData['uri'], PHP_URL_SCHEME) == 'did') {
|
||||||
$did = $hookData['uri'];
|
$did = $hookData['uri'];
|
||||||
} elseif (preg_match('#^' . BLUESKY_WEB . '/profile/(.+)#', $hookData['uri'], $matches)) {
|
} elseif (parse_url($hookData['uri'], PHP_URL_PATH) == $hookData['uri'] && strpos($hookData['uri'], '@') === false) {
|
||||||
$did = bluesky_get_did($matches[1]);
|
$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']);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -148,19 +155,14 @@ function bluesky_probe_detect(array &$hookData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], false);
|
$hookData['result'] = bluesky_get_contact_fields($data, 0, $pconfig['uid'], true);
|
||||||
|
|
||||||
$hookData['result']['baseurl'] = bluesky_get_pds($did);
|
|
||||||
|
|
||||||
// Preparing probe data. This differs slightly from the contact array
|
// Preparing probe data. This differs slightly from the contact array
|
||||||
$hookData['result']['about'] = HTML::toBBCode($data->description ?? '');
|
|
||||||
$hookData['result']['photo'] = $data->avatar ?? '';
|
$hookData['result']['photo'] = $data->avatar ?? '';
|
||||||
$hookData['result']['header'] = $data->banner ?? '';
|
|
||||||
$hookData['result']['batch'] = '';
|
$hookData['result']['batch'] = '';
|
||||||
$hookData['result']['notify'] = '';
|
$hookData['result']['notify'] = '';
|
||||||
$hookData['result']['poll'] = '';
|
$hookData['result']['poll'] = '';
|
||||||
$hookData['result']['poco'] = '';
|
$hookData['result']['poco'] = '';
|
||||||
$hookData['result']['pubkey'] = '';
|
|
||||||
$hookData['result']['priority'] = 0;
|
$hookData['result']['priority'] = 0;
|
||||||
$hookData['result']['guid'] = '';
|
$hookData['result']['guid'] = '';
|
||||||
}
|
}
|
||||||
|
@ -177,21 +179,21 @@ function bluesky_item_by_link(array &$hookData)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!preg_match('#^' . BLUESKY_WEB . '/profile/(.+)/post/(.+)#', $hookData['uri'], $matches)) {
|
$did = bluesky_get_did_by_profile($hookData['uri']);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$did = bluesky_get_did($matches[1]);
|
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'handle' => $matches[1], 'did' => $did, 'cid' => $matches[2]]);
|
if (!preg_match('#/profile/.+/post/(.+)#', $hookData['uri'], $matches)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[2];
|
Logger::debug('Found bluesky post', ['url' => $hookData['uri'], 'did' => $did, 'cid' => $matches[1]]);
|
||||||
|
|
||||||
|
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[1];
|
||||||
|
|
||||||
$uri = bluesky_fetch_missing_post($uri, $hookData['uid'], $hookData['uid'], Item::PR_FETCHED, 0, 0, 0);
|
$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[1], 'result' => $uri]);
|
||||||
if (!empty($uri)) {
|
if (!empty($uri)) {
|
||||||
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
|
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
|
||||||
if (!empty($item['id'])) {
|
if (!empty($item['id'])) {
|
||||||
|
@ -1408,6 +1410,19 @@ function bluesky_add_media(stdClass $embed, array $item, int $fetch_uid, int $le
|
||||||
}
|
}
|
||||||
break;
|
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':
|
case 'app.bsky.embed.external#view':
|
||||||
$media = [
|
$media = [
|
||||||
'uri-id' => $item['uri-id'],
|
'uri-id' => $item['uri-id'],
|
||||||
|
@ -1678,11 +1693,15 @@ function bluesky_get_contact_fields(stdClass $author, int $uid, int $fetch_uid,
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields['baseurl'] = bluesky_get_pds($author->did);
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $author->did);
|
||||||
|
if (!empty($data)) {
|
||||||
|
$fields['baseurl'] = bluesky_get_pds('', $data);
|
||||||
if (!empty($fields['baseurl'])) {
|
if (!empty($fields['baseurl'])) {
|
||||||
GServer::check($fields['baseurl'], Protocol::BLUESKY);
|
GServer::check($fields['baseurl'], Protocol::BLUESKY);
|
||||||
$fields['gsid'] = GServer::getID($fields['baseurl'], true);
|
$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]);
|
$data = bluesky_xrpc_get($fetch_uid, 'app.bsky.actor.getProfile', ['actor' => $author->did]);
|
||||||
if (empty($data)) {
|
if (empty($data)) {
|
||||||
|
@ -1748,6 +1767,49 @@ function bluesky_get_preferences(int $uid): ?stdClass
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bluesky_get_did_by_profile(string $url): string
|
||||||
|
{
|
||||||
|
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
|
function bluesky_get_did_by_wellknown(string $handle): string
|
||||||
{
|
{
|
||||||
$curlResult = DI::httpClient()->get('http://' . $handle . '/.well-known/atproto-did');
|
$curlResult = DI::httpClient()->get('http://' . $handle . '/.well-known/atproto-did');
|
||||||
|
@ -1757,7 +1819,6 @@ function bluesky_get_did_by_wellknown(string $handle): string
|
||||||
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Logger::debug('Got DID by wellknown', ['handle' => $handle, 'did' => $did]);
|
|
||||||
return $did;
|
return $did;
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
|
@ -1776,14 +1837,13 @@ function bluesky_get_did_by_dns(string $handle): string
|
||||||
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
Logger::notice('Invalid DID', ['handle' => $handle, 'did' => $did]);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
Logger::debug('Got DID by DNS', ['handle' => $handle, 'did' => $did]);
|
|
||||||
return $did;
|
return $did;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_did(string $handle): string
|
function bluesky_get_did(string $handle, int $uid): string
|
||||||
{
|
{
|
||||||
if ($handle == '') {
|
if ($handle == '') {
|
||||||
return '';
|
return '';
|
||||||
|
@ -1793,24 +1853,40 @@ function bluesky_get_did(string $handle): string
|
||||||
$handle .= '.' . BLUESKY_HOSTNAME;
|
$handle .= '.' . BLUESKY_HOSTNAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deactivated at the moment, since it isn't reliable by now
|
// At first we use the user PDS. That should cover most cases.
|
||||||
//$did = bluesky_get_did_by_dns($handle);
|
$pds = DI::pConfig()->get($uid, 'bluesky', 'pds');
|
||||||
//if ($did != '') {
|
if (!empty($pds)) {
|
||||||
// return $did;
|
$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]);
|
||||||
//$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)) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
Logger::debug('Got DID by PDS call', ['handle' => $handle, 'did' => $data->did]);
|
|
||||||
return $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
|
function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
|
||||||
{
|
{
|
||||||
|
@ -1826,7 +1902,7 @@ function bluesky_get_user_did(int $uid, bool $refresh = false): ?string
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$did = bluesky_get_did($handle);
|
$did = bluesky_get_did($handle, $uid);
|
||||||
if (empty($did)) {
|
if (empty($did)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1857,9 +1933,11 @@ function bluesky_get_user_pds(int $uid): ?string
|
||||||
return $pds;
|
return $pds;
|
||||||
}
|
}
|
||||||
|
|
||||||
function bluesky_get_pds(string $did): ?string
|
function bluesky_get_pds(string $did, stdClass $data = null): ?string
|
||||||
{
|
{
|
||||||
|
if (empty($data)) {
|
||||||
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
||||||
|
}
|
||||||
if (empty($data) || empty($data->service)) {
|
if (empty($data) || empty($data->service)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1873,6 +1951,22 @@ function bluesky_get_pds(string $did): ?string
|
||||||
return null;
|
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
|
function bluesky_valid_did(string $did, string $handle): bool
|
||||||
{
|
{
|
||||||
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
$data = bluesky_get(BLUESKY_DIRECTORY . '/' . $did);
|
||||||
|
|
|
@ -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/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/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?://(?: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']);
|
$b['html'] = preg_replace("/https?:\/\/youtu.be\/(.*?)/ism", $server . '/watch?v=$1', $b['html']);
|
||||||
|
|
||||||
if ($original != $b['html']) {
|
if ($original != $b['html']) {
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* Author: Matthew Exon <http://mat.exon.name>
|
* Author: Matthew Exon <http://mat.exon.name>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Friendica\App;
|
|
||||||
use Friendica\Content\Text\BBCode;
|
use Friendica\Content\Text\BBCode;
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\Core\Logger;
|
use Friendica\Core\Logger;
|
||||||
|
@ -16,12 +15,11 @@ use Friendica\Core\Worker;
|
||||||
use Friendica\Database\DBA;
|
use Friendica\Database\DBA;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Model\Contact;
|
use Friendica\Model\Contact;
|
||||||
use Friendica\Model\Item;
|
|
||||||
use Friendica\Model\Post;
|
use Friendica\Model\Post;
|
||||||
use Friendica\Model\User;
|
use Friendica\Model\User;
|
||||||
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
use Friendica\Network\HTTPClient\Client\HttpClientAccept;
|
||||||
|
use Friendica\Network\HTTPClient\Client\HttpClientOptions;
|
||||||
use Friendica\Protocol\Activity;
|
use Friendica\Protocol\Activity;
|
||||||
use Friendica\Util\DateTimeFormat;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the addon hooks and the database table
|
* Sets up the addon hooks and the database table
|
||||||
|
@ -34,26 +32,7 @@ function mailstream_install()
|
||||||
Hook::register('post_remote_end', 'addon/mailstream/mailstream.php', 'mailstream_post_hook');
|
Hook::register('post_remote_end', 'addon/mailstream/mailstream.php', 'mailstream_post_hook');
|
||||||
Hook::register('mailstream_send_hook', 'addon/mailstream/mailstream.php', 'mailstream_send_hook');
|
Hook::register('mailstream_send_hook', 'addon/mailstream/mailstream.php', 'mailstream_send_hook');
|
||||||
|
|
||||||
Logger::info("mailstream: installed");
|
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("mailstream_check_version: 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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -72,10 +51,12 @@ function mailstream_addon_admin(string &$o)
|
||||||
{
|
{
|
||||||
$frommail = DI::config()->get('mailstream', 'frommail');
|
$frommail = DI::config()->get('mailstream', 'frommail');
|
||||||
$template = Renderer::getMarkupTemplate('admin.tpl', 'addon/mailstream/');
|
$template = Renderer::getMarkupTemplate('admin.tpl', 'addon/mailstream/');
|
||||||
$config = ['frommail',
|
$config = [
|
||||||
|
'frommail',
|
||||||
DI::l10n()->t('From Address'),
|
DI::l10n()->t('From Address'),
|
||||||
$frommail,
|
$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, [
|
$o .= Renderer::replaceMacros($template, [
|
||||||
'$frommail' => $config,
|
'$frommail' => $config,
|
||||||
'$submit' => DI::l10n()->t('Save Settings')
|
'$submit' => DI::l10n()->t('Save Settings')
|
||||||
|
@ -105,7 +86,7 @@ function mailstream_generate_id(string $uri): string
|
||||||
$host = DI::baseUrl()->getHost();
|
$host = DI::baseUrl()->getHost();
|
||||||
$resource = hash('md5', $uri);
|
$resource = hash('md5', $uri);
|
||||||
$message_id = "<" . $resource . "@" . $host . ">";
|
$message_id = "<" . $resource . "@" . $host . ">";
|
||||||
Logger::debug('mailstream: Generated message ID ' . $message_id . ' for URI ' . $uri);
|
Logger::debug('generated message ID', ['id' => $message_id, 'uri' => $uri]);
|
||||||
return $message_id;
|
return $message_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,20 +95,20 @@ function mailstream_send_hook(array $data)
|
||||||
$criteria = array('uid' => $data['uid'], 'contact-id' => $data['contact-id'], 'uri' => $data['uri']);
|
$criteria = array('uid' => $data['uid'], 'contact-id' => $data['contact-id'], 'uri' => $data['uri']);
|
||||||
$item = Post::selectFirst([], $criteria);
|
$item = Post::selectFirst([], $criteria);
|
||||||
if (empty($item)) {
|
if (empty($item)) {
|
||||||
Logger::error('mailstream_send_hook could not find item');
|
Logger::error('could not find item');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = User::getById($item['uid']);
|
$user = User::getById($item['uid']);
|
||||||
if (empty($user)) {
|
if (empty($user)) {
|
||||||
Logger::error('mailstream_send_hook could not fund user', ['uid' => $item['uid']]);
|
Logger::error('could not find user', ['uid' => $item['uid']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mailstream_send($data['message_id'], $item, $user)) {
|
if (!mailstream_send($data['message_id'], $item, $user)) {
|
||||||
Logger::debug('mailstream_send_hook send failed, will retry', $data);
|
Logger::debug('send failed, will retry', $data);
|
||||||
if (!Worker::defer()) {
|
if (!Worker::defer()) {
|
||||||
Logger::error('mailstream_send_hook failed and could not defer', $data);
|
Logger::error('failed and could not defer', $data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,35 +123,33 @@ function mailstream_send_hook(array $data)
|
||||||
*/
|
*/
|
||||||
function mailstream_post_hook(array &$item)
|
function mailstream_post_hook(array &$item)
|
||||||
{
|
{
|
||||||
mailstream_check_version();
|
if ($item['uid'] === 0) {
|
||||||
|
Logger::debug('mailstream: root user, skipping item ' . $item['id']);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
|
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
|
||||||
Logger::debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
|
Logger::debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$item['uid']) {
|
|
||||||
Logger::debug('mailstream: no uid for item ' . $item['id']);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!$item['contact-id']) {
|
if (!$item['contact-id']) {
|
||||||
Logger::debug('mailstream: no contact-id for item ' . $item['id']);
|
Logger::debug('no contact-id', ['item' => $item['id']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!$item['uri']) {
|
if (!$item['uri']) {
|
||||||
Logger::debug('mailstream: no uri for item ' . $item['id']);
|
Logger::debug('no uri', ['item' => $item['id']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($item['verb'] == Activity::ANNOUNCE) {
|
if ($item['verb'] == Activity::ANNOUNCE) {
|
||||||
Logger::debug('mailstream: announce item ', ['item' => $item['id']]);
|
Logger::debug('ignoring announce', ['item' => $item['id']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DI::pConfig()->get($item['uid'], 'mailstream', 'nolikes')) {
|
if (DI::pConfig()->get($item['uid'], 'mailstream', 'nolikes')) {
|
||||||
if ($item['verb'] == Activity::LIKE) {
|
if ($item['verb'] == Activity::LIKE) {
|
||||||
Logger::debug('mailstream: like item ' . $item['id']);
|
Logger::debug('ignoring like', ['item' => $item['id']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ($item['verb'] == Activity::DISLIKE) {
|
if ($item['verb'] == Activity::DISLIKE) {
|
||||||
Logger::debug('mailstream: dislike item ' . $item['id']);
|
Logger::debug('ignoring dislike', ['item' => $item['id']]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,14 +198,17 @@ function mailstream_do_images(array &$item, array &$attachments)
|
||||||
|
|
||||||
$cookiejar = tempnam(System::getTempPath(), 'cookiejar-mailstream-');
|
$cookiejar = tempnam(System::getTempPath(), 'cookiejar-mailstream-');
|
||||||
try {
|
try {
|
||||||
$curlResult = DI::httpClient()->fetchFull($url, HttpClientAccept::DEFAULT, 0, $cookiejar);
|
$curlResult = DI::httpClient()->get($url, HttpClientAccept::DEFAULT, [HttpClientOptions::COOKIEJAR => $cookiejar]);
|
||||||
if (!$curlResult->isSuccess()) {
|
if (!$curlResult->isSuccess()) {
|
||||||
Logger::debug('mailstream: fetch image url failed', [
|
Logger::debug('mailstream: fetch image url failed', [
|
||||||
'url' => $url, 'item_id' => $item['id'], 'return_code' => $curlResult->getReturnCode()]);
|
'url' => $url,
|
||||||
|
'item_id' => $item['id'],
|
||||||
|
'return_code' => $curlResult->getReturnCode()
|
||||||
|
]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
Logger::error('mailstream_do_images exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
|
Logger::error('exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$attachments[$url] = [
|
$attachments[$url] = [
|
||||||
|
@ -327,13 +309,12 @@ function mailstream_subject(array $item): string
|
||||||
}
|
}
|
||||||
$contact = Contact::selectFirst([], ['id' => $item['contact-id'], 'uid' => $item['uid']]);
|
$contact = Contact::selectFirst([], ['id' => $item['contact-id'], 'uid' => $item['uid']]);
|
||||||
if (!DBA::isResult($contact)) {
|
if (!DBA::isResult($contact)) {
|
||||||
Logger::error(
|
Logger::error('no contact', [
|
||||||
'mailstream_subject no contact for item',
|
'item' => $item['id'],
|
||||||
['id' => $item['id'],
|
|
||||||
'plink' => $item['plink'],
|
'plink' => $item['plink'],
|
||||||
'contact id' => $item['contact-id'],
|
'contact id' => $item['contact-id'],
|
||||||
'uid' => $item['uid']]
|
'uid' => $item['uid']
|
||||||
);
|
]);
|
||||||
return DI::l10n()->t("Friendica post");
|
return DI::l10n()->t("Friendica post");
|
||||||
}
|
}
|
||||||
if ($contact['network'] === 'dfrn') {
|
if ($contact['network'] === 'dfrn') {
|
||||||
|
@ -370,17 +351,16 @@ function mailstream_subject(array $item): string
|
||||||
function mailstream_send(string $message_id, array $item, array $user): bool
|
function mailstream_send(string $message_id, array $item, array $user): bool
|
||||||
{
|
{
|
||||||
if (!is_array($item)) {
|
if (!is_array($item)) {
|
||||||
Logger::error('mailstream_send item is empty', ['message_id' => $message_id]);
|
Logger::error('item is empty', ['message_id' => $message_id]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$item['visible']) {
|
if (!$item['visible']) {
|
||||||
Logger::debug('mailstream_send item not yet visible', ['item uri' => $item['uri']]);
|
Logger::debug('item not yet visible', ['item uri' => $item['uri']]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!$message_id) {
|
if (!$message_id) {
|
||||||
Logger::error('mailstream_send no message ID supplied', ['item uri' => $item['uri'],
|
Logger::error('no message ID supplied', ['item uri' => $item['uri'], 'user email' => $user['email']]);
|
||||||
'user email' => $user['email']]);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -432,18 +412,21 @@ function mailstream_send(string $message_id, array $item, array $user): bool
|
||||||
'$upstream' => DI::l10n()->t('Upstream'),
|
'$upstream' => DI::l10n()->t('Upstream'),
|
||||||
'$uri' => DI::l10n()->t('URI'),
|
'$uri' => DI::l10n()->t('URI'),
|
||||||
'$local' => DI::l10n()->t('Local'),
|
'$local' => DI::l10n()->t('Local'),
|
||||||
'$item' => $item]);
|
'$item' => $item
|
||||||
|
]);
|
||||||
$mail->Body = mailstream_html_wrap($mail->Body);
|
$mail->Body = mailstream_html_wrap($mail->Body);
|
||||||
if (!$mail->Send()) {
|
if (!$mail->Send()) {
|
||||||
throw new Exception($mail->ErrorInfo);
|
throw new Exception($mail->ErrorInfo);
|
||||||
}
|
}
|
||||||
Logger::debug('mailstream_send sent message', ['message ID' => $mail->MessageID,
|
Logger::debug('sent message', [
|
||||||
|
'message ID' => $mail->MessageID,
|
||||||
'subject' => $mail->Subject,
|
'subject' => $mail->Subject,
|
||||||
'address' => $address]);
|
'address' => $address
|
||||||
|
]);
|
||||||
} catch (phpmailerException $e) {
|
} catch (phpmailerException $e) {
|
||||||
Logger::debug('mailstream_send PHPMailer exception sending message ' . $message_id . ': ' . $e->errorMessage());
|
Logger::debug('PHPMailer exception sending message', ['id' => $message_id, 'error' => $e->errorMessage()]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
Logger::debug('mailstream_send exception sending message ' . $message_id . ': ' . $e->getMessage());
|
Logger::debug('exception sending message', ['id' => $message_id, 'error' => $e->getMessage()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -467,29 +450,6 @@ function mailstream_html_wrap(string &$text)
|
||||||
return $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('mailstream_convert_table_entries processing ' . count($ms_item_ids) . ' items');
|
|
||||||
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('mailstream_convert_table_entries: item has no message-id.', ['item' => $ms_item_id['id'], 'uri' => $ms_item_id['uri']]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Logger::info('mailstream_convert_table_entries: 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
|
* Form for configuring mailstream features for a user
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Name: Mastodon Custom Emojis
|
* Name: Mastodon Custom Emojis
|
||||||
* Description: Replace emojis shortcodes in Mastodon posts with their originating server custom emojis images.
|
* Description: Replace emojis shortcodes in Mastodon posts with their originating server custom emojis images.
|
||||||
|
@ -9,7 +8,6 @@
|
||||||
* Status: Unsupported
|
* Status: Unsupported
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Friendica\App;
|
|
||||||
use Friendica\Content\Smilies;
|
use Friendica\Content\Smilies;
|
||||||
use Friendica\Core\Cache\Enum\Duration;
|
use Friendica\Core\Cache\Enum\Duration;
|
||||||
use Friendica\Core\Hook;
|
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';
|
$api_url = $api_base_url . '/api/v1/custom_emojis';
|
||||||
|
|
||||||
$fetchResult = DI::httpClient()->fetchFull($api_url);
|
$fetchResult = DI::httpClient()->get($api_url);
|
||||||
|
|
||||||
if ($fetchResult->isSuccess()) {
|
if ($fetchResult->isSuccess()) {
|
||||||
$emojis_array = json_decode($fetchResult->getBodyString(), true);
|
$emojis_array = json_decode($fetchResult->getBodyString(), true);
|
||||||
|
|
213
ratioed/RatioedPanel.php
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Friendica\Addon\ratioed;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements the "Behaviour" panel in Moderation/Users
|
||||||
|
*/
|
||||||
|
class RatioedPanel extends Active
|
||||||
|
{
|
||||||
|
protected function content(array $request = []): string
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
if ($uid) {
|
||||||
|
$user = User::getById($uid, ['username', 'blocked']);
|
||||||
|
if (!$user) {
|
||||||
|
$this->systemMessages->addNotice($this->t('User not found'));
|
||||||
|
$this->baseUrl->redirect('moderation/users');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($action) {
|
||||||
|
case 'delete':
|
||||||
|
if ($this->session->getLocalUserId() != $uid) {
|
||||||
|
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
|
||||||
|
// delete user
|
||||||
|
User::remove($uid);
|
||||||
|
|
||||||
|
$this->systemMessages->addNotice($this->t('User "%s" deleted', $user['username']));
|
||||||
|
} else {
|
||||||
|
$this->systemMessages->addNotice($this->t('You can\'t remove yourself'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->baseUrl->redirect('moderation/users/active');
|
||||||
|
break;
|
||||||
|
case 'block':
|
||||||
|
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
|
||||||
|
User::block($uid);
|
||||||
|
$this->systemMessages->addNotice($this->t('User "%s" blocked', $user['username']));
|
||||||
|
$this->baseUrl->redirect('moderation/users/active');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$pager = new Pager($this->l10n, $this->args->getQueryString(), 100);
|
||||||
|
|
||||||
|
$valid_orders = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'register_date',
|
||||||
|
'last-activity',
|
||||||
|
'last-item',
|
||||||
|
'page-flags',
|
||||||
|
];
|
||||||
|
|
||||||
|
$order = 'last-item';
|
||||||
|
$order_direction = '-';
|
||||||
|
if (!empty($request['o'])) {
|
||||||
|
$new_order = $request['o'];
|
||||||
|
if ($new_order[0] === '-') {
|
||||||
|
$order_direction = '-';
|
||||||
|
$new_order = substr($new_order, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($new_order, $valid_orders)) {
|
||||||
|
$order = $new_order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$users = User::getList($pager->getStart(), $pager->getItemsPerPage(), 'active', $order, ($order_direction == '-'));
|
||||||
|
|
||||||
|
$users = array_map($this->setupUserCallback(), $users);
|
||||||
|
|
||||||
|
$header_titles = [
|
||||||
|
$this->t('Name'),
|
||||||
|
$this->t('Email'),
|
||||||
|
$this->t('Register date'),
|
||||||
|
$this->t('Last login'),
|
||||||
|
$this->t('Last public item'),
|
||||||
|
$this->t('Type'),
|
||||||
|
$this->t('Blocked by'),
|
||||||
|
$this->t('Comments last 24h'),
|
||||||
|
$this->t('Reactions last 24h'),
|
||||||
|
$this->t('Ratio last 24h'),
|
||||||
|
];
|
||||||
|
$field_names = [
|
||||||
|
'name',
|
||||||
|
'email',
|
||||||
|
'register_date',
|
||||||
|
'login_date',
|
||||||
|
'lastitem_date',
|
||||||
|
'page_flags',
|
||||||
|
'blocked_by',
|
||||||
|
'comments',
|
||||||
|
'reactions',
|
||||||
|
'ratio',
|
||||||
|
];
|
||||||
|
$th_users = array_map(null, $header_titles, $valid_orders, $field_names);
|
||||||
|
|
||||||
|
$count = $this->database->count('user', ["`verified` AND NOT `blocked` AND NOT `account_removed` AND NOT `account_expired` AND `uid` != ?", 0]);
|
||||||
|
|
||||||
|
$t = Renderer::getMarkupTemplate('ratioed.tpl', 'addon/ratioed');
|
||||||
|
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'),
|
||||||
|
'$block' => $this->t('Block'),
|
||||||
|
'$blocked' => $this->t('User blocked'),
|
||||||
|
'$siteadmin' => $this->t('Site admin'),
|
||||||
|
'$accountexpired' => $this->t('Account expired'),
|
||||||
|
'$h_newuser' => $this->t('Create a new user'),
|
||||||
|
|
||||||
|
'$th_users' => $th_users,
|
||||||
|
'$order_users' => $order,
|
||||||
|
'$order_direction_users' => $order_direction,
|
||||||
|
|
||||||
|
'$confirm_delete_multi' => $this->t('Selected users will be deleted!\n\nEverything these users had posted on this site will be permanently deleted!\n\nAre you sure?'),
|
||||||
|
'$confirm_delete' => $this->t('The user {0} will be deleted!\n\nEverything this user has posted on this site will be permanently deleted!\n\nAre you sure?'),
|
||||||
|
|
||||||
|
'$form_security_token' => self::getFormSecurityToken('moderation_users_active'),
|
||||||
|
|
||||||
|
// values //
|
||||||
|
'$baseurl' => $this->baseUrl,
|
||||||
|
'$query_string' => $this->args->getQueryString(),
|
||||||
|
|
||||||
|
'$users' => $users,
|
||||||
|
'$count' => $count,
|
||||||
|
'$pager' => $pager->renderFull($count),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setupUserCallback(): \Closure
|
||||||
|
{
|
||||||
|
Logger::debug("ratioed: setupUserCallback");
|
||||||
|
$parentCallback = parent::setupUserCallback();
|
||||||
|
return function ($user) use ($parentCallback) {
|
||||||
|
$blocked_count = DBA::count('user-contact', ['uid' => $user['uid'], 'is-blocked' => 1]);
|
||||||
|
$user['blocked_by'] = $blocked_count;
|
||||||
|
|
||||||
|
$self_contact_result = DBA::p('SELECT admin_contact.id AS user_contact_uid FROM contact AS admin_contact JOIN contact AS user_contact ON admin_contact.`uri-id` = user_contact.`uri-id` AND admin_contact.self = 0 AND user_contact.self = 1 WHERE user_contact.uid = ?', $user['uid']);
|
||||||
|
if (DBA::isResult($self_contact_result)) {
|
||||||
|
$self_contact_result_row = DBA::fetch($self_contact_result);
|
||||||
|
$user['user_contact_uid'] = $self_contact_result_row['user_contact_uid'];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$user['user_contact_uid'] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user['user_contact_uid']) {
|
||||||
|
$post_engagement_result = DBA::p('SELECT SUM(`comments`) AS `comment_count`, SUM(`activities`) AS `activities_count` FROM `post-engagement` WHERE `post-engagement`.created > DATE_SUB(now(), INTERVAL 1 DAY) AND `post-engagement`.`owner-id` = ?', $user['user_contact_uid']);
|
||||||
|
if (DBA::isResult($post_engagement_result)) {
|
||||||
|
$post_engagement_result_row = DBA::fetch($post_engagement_result);
|
||||||
|
$user['comments'] = $post_engagement_result_row['comment_count'];
|
||||||
|
$user['reactions'] = $post_engagement_result_row['activities_count'];
|
||||||
|
if ($user['reactions'] > 0) {
|
||||||
|
$user['ratio'] = number_format($user['comments'] / $user['reactions'], 1, '.', '');
|
||||||
|
$user['ratioed'] = (float)($user['ratio']) >= 2.0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ($user['comments'] == 0) {
|
||||||
|
$user['ratio'] = '0';
|
||||||
|
$user['ratioed'] = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$user['ratio'] = '∞';
|
||||||
|
$user['ratioed'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$user['comments'] = 'error';
|
||||||
|
$user['reactions'] = 'error';
|
||||||
|
$user['ratio'] = 'error';
|
||||||
|
$user['ratioed'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$user['comments'] = 'error';
|
||||||
|
$user['reactions'] = 'error';
|
||||||
|
$user['ratio'] = 'error';
|
||||||
|
$user['ratioed'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = $parentCallback($user);
|
||||||
|
Logger::debug("ratioed: setupUserCallback", [
|
||||||
|
'uid' => $user['uid'],
|
||||||
|
'blocked_by' => $user['blocked_by'],
|
||||||
|
'comments' => $user['comments'],
|
||||||
|
'reactions' => $user['reactions'],
|
||||||
|
'ratio' => $user['ratio'],
|
||||||
|
'ratioed' => $user['ratioed'],
|
||||||
|
]);
|
||||||
|
return $user;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
58
ratioed/ratioed.php
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Name: Ratioed
|
||||||
|
* Description: Additional moderation user table with statistics about user behaviour
|
||||||
|
* Version: 0.1
|
||||||
|
* Author: Matthew Exon <http://mat.exon.name>
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Friendica\Addon\ratioed\RatioedPanel;
|
||||||
|
use Friendica\Core\Hook;
|
||||||
|
use Friendica\Core\Logger;
|
||||||
|
use Friendica\DI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the addon hooks and updates data in the database if needed
|
||||||
|
*/
|
||||||
|
function ratioed_install()
|
||||||
|
{
|
||||||
|
Hook::register('moderation_users_tabs', 'addon/ratioed/ratioed.php', 'ratioed_users_tabs');
|
||||||
|
|
||||||
|
Logger::info("ratioed: installed");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* module.
|
||||||
|
*/
|
||||||
|
function ratioed_module() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds additional users tab to the moderation panel
|
||||||
|
*
|
||||||
|
* @param array $arr Parameters, including "tabs" which is the list to modify, and "selectedTab", which is the currently selected tab ID
|
||||||
|
*/
|
||||||
|
function ratioed_users_tabs(array &$arr) {
|
||||||
|
Logger::debug("ratioed: users tabs");
|
||||||
|
|
||||||
|
array_push($arr['tabs'], [
|
||||||
|
'label' => DI::l10n()->t('Behaviour'),
|
||||||
|
'url' => 'ratioed',
|
||||||
|
'sel' => $arr['selectedTab'] == 'ratioed' ? 'active' : '',
|
||||||
|
'title' => DI::l10n()->t('Statistics about users behaviour'),
|
||||||
|
'id' => 'admin-users-ratioed',
|
||||||
|
'accesskey' => 'r',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Displays the ratioed tab in the moderation panel
|
||||||
|
*/
|
||||||
|
function ratioed_content() {
|
||||||
|
Logger::debug("ratioed: content");
|
||||||
|
|
||||||
|
$ratioed = DI::getDice()->create(RatioedPanel::class, [$_SERVER]);
|
||||||
|
$httpException = DI::getDice()->create(Friendica\Module\Special\HTTPException::class);
|
||||||
|
$ratioed->run($httpException);
|
||||||
|
}
|
92
ratioed/templates/help.tpl
Normal 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>
|
164
ratioed/templates/ratioed.tpl
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
<script type="text/javascript" src="view/theme/frio/js/mod_admin.js?v={{constant('\Friendica\App::VERSION')}}"></script>
|
||||||
|
<link rel="stylesheet" href="view/theme/frio/css/mod_admin.css?v={{constant('\Friendica\App::VERSION')}}" type="text/css" media="screen"/>
|
||||||
|
|
||||||
|
<div id="admin-users" class="adminpage generic-page-wrapper">
|
||||||
|
<h1>{{$title}} - {{$page}} ({{$count}})</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{{$base_url}}/moderation/users/create" class="btn btn-primary"><i class="fa fa-user-plus"></i> {{$h_newuser}}</a>
|
||||||
|
</p>
|
||||||
|
<form action="{{$baseurl}}/{{$query_string}}" method="post">
|
||||||
|
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
|
||||||
|
<table id="users" class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" id="admin-settings-users-select" class="selecttoggle" data-select-class="users_ckbx"/>
|
||||||
|
<label for="admin-settings-users-select"></label>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
<th></th>
|
||||||
|
{{foreach $th_users as $k=>$th}}
|
||||||
|
{{if $k < 2 || $order_users == $th.1 || ($k==5 && !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1])) }}
|
||||||
|
<th class="th-{{$k}}">
|
||||||
|
<a href="{{$baseurl}}/moderation/users/active?o={{if $order_direction_users == "+"}}-{{/if}}{{$th.1}}" class="table-order">
|
||||||
|
{{if $order_users == $th.1}}
|
||||||
|
{{if $order_direction_users == "+"}}
|
||||||
|
↓
|
||||||
|
{{else}}
|
||||||
|
↑
|
||||||
|
{{/if}}
|
||||||
|
{{else}}
|
||||||
|
↕
|
||||||
|
{{/if}}
|
||||||
|
{{$th.0}}
|
||||||
|
</a>
|
||||||
|
</th>
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{foreach $users as $u}}
|
||||||
|
<tr id="user-{{$u.uid}}" class="{{if $u.ratioed}}blocked{{/if}}">
|
||||||
|
<td>
|
||||||
|
{{if $u.is_deletable}}
|
||||||
|
<div class="checkbox">
|
||||||
|
<input type="checkbox" class="users_ckbx" id="id_user_{{$u.uid}}" name="user[]" value="{{$u.uid}}"/>
|
||||||
|
<label for="id_user_{{$u.uid}}"></label>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
<td><img class="avatar-nano" src="{{$u.micro}}" title="{{$u.nickname}}"></td>
|
||||||
|
<td><a href="{{$u.url}}" title="{{$u.nickname}}"> {{$u.name}}</a></td>
|
||||||
|
<td>{{$u.email}}</td>
|
||||||
|
{{if $order_users == $th_users.2.1}}
|
||||||
|
<td>{{$u.register_date}}</td>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if $order_users == $th_users.3.1}}
|
||||||
|
<td>{{$u.login_date}}</td>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if $order_users == $th_users.4.1}}
|
||||||
|
<td>{{$u.lastitem_date}}</td>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1]) }}
|
||||||
|
<td>
|
||||||
|
<i class="fa
|
||||||
|
{{if $u.page_flags_raw==0}}fa-user{{/if}} {{* PAGE_NORMAL *}}
|
||||||
|
{{if $u.page_flags_raw==1}}fa-bullhorn{{/if}} {{* PAGE_SOAPBOX *}}
|
||||||
|
{{if $u.page_flags_raw==2}}fa-users{{/if}} {{* PAGE_COMMUNITY *}}
|
||||||
|
{{if $u.page_flags_raw==3}}fa-heart{{/if}} {{* PAGE_FREELOVE *}}
|
||||||
|
{{if $u.page_flags_raw==4}}fa-rss{{/if}} {{* PAGE_BLOG *}}
|
||||||
|
{{if $u.page_flags_raw==5}}fa-user-secret{{/if}} {{* PAGE_PRVGROUP *}}
|
||||||
|
" title="{{$u.page_flags}}">
|
||||||
|
</i>
|
||||||
|
{{if $u.page_flags_raw==0 && $u.account_type_raw > 0}}
|
||||||
|
<i class="fa
|
||||||
|
{{if $u.account_type_raw==1}}fa-sitemap{{/if}} {{* ACCOUNT_TYPE_ORGANISATION *}}
|
||||||
|
{{if $u.account_type_raw==2}}fa-newspaper-o{{/if}} {{* ACCOUNT_TYPE_NEWS *}}
|
||||||
|
{{if $u.account_type_raw==3}}fa-comments{{/if}} {{* ACCOUNT_TYPE_COMMUNITY *}}
|
||||||
|
" title="{{$u.account_type}}">
|
||||||
|
</i>
|
||||||
|
{{/if}}
|
||||||
|
{{if $u.is_admin}}<i class="fa fa-user-secret text-primary" title="{{$siteadmin}}"></i>{{/if}}
|
||||||
|
{{if $u.account_expired}}<i class="fa fa-clock-o text-warning" title="{{$accountexpired}}"></i>{{/if}}
|
||||||
|
</td>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<td class="text-right">
|
||||||
|
<button type="button" class="btn-link admin-settings-action-link" onclick="return details({{$u.uid}})"><span class="caret"></span></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr id="user-{{$u.uid}}-detail" class=" details hidden {{if $u.blocked != 0}}blocked{{/if}}">
|
||||||
|
<td> </td>
|
||||||
|
<td colspan="4">
|
||||||
|
{{if $order_users != $th_users.2.1}}
|
||||||
|
<p>
|
||||||
|
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.2.1}}" class="btn-link table-order">
|
||||||
|
↕ {{$th_users.2.0}}</a> : {{$u.register_date}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if $order_users != $th_users.3.1}}
|
||||||
|
<p>
|
||||||
|
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.3.1}}" class="btn-link table-order">
|
||||||
|
↕ {{$th_users.3.0}}</a> : {{$u.login_date}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if $order_users != $th_users.4.1}}
|
||||||
|
<p>
|
||||||
|
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.4.1}}" class="btn-link table-order">
|
||||||
|
↕ {{$th_users.4.0}}</a> : {{$u.lastitem_date}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{if in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1]) }}
|
||||||
|
<p>
|
||||||
|
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th_users.5.1}}" class="btn-link table-order">
|
||||||
|
↕ {{$th_users.5.0}}</a> : {{$u.page_flags}}{{if $u.page_flags_raw==0 && $u.account_type_raw > 0}}, {{$u.account_type}}{{/if}} {{if $u.is_admin}}({{$siteadmin}}){{/if}} {{if $u.account_expired}}({{$accountexpired}}){{/if}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{foreach $th_users as $k=>$th}}
|
||||||
|
{{if $order_users != $th.1 && $k > 5}}
|
||||||
|
<p>
|
||||||
|
{{$th.0}} : {{$u[$th.2]}}
|
||||||
|
</p>
|
||||||
|
{{/if}}
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
<td class="text-right">
|
||||||
|
{{if $u.is_deletable}}
|
||||||
|
<a href="{{$baseurl}}/moderation/users/active/block/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$block}}">
|
||||||
|
<i class="fa fa-ban" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
<a href="{{$baseurl}}/moderation/users/active/delete/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$delete}}" onclick="return confirm_delete('{{$confirm_delete}}','{{$u.name}}')">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i>
|
||||||
|
</a>
|
||||||
|
{{else}}
|
||||||
|
|
||||||
|
{{/if}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/foreach}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="panel-footer">
|
||||||
|
<button type="submit" name="page_users_block" value="1" class="btn btn-warning">
|
||||||
|
<i class="fa fa-ban" aria-hidden="true"></i> {{$block}}
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="page_users_delete" value="1" class="btn btn-danger" onclick="return confirm_delete('{{$confirm_delete_multi}}')">
|
||||||
|
<i class="fa fa-trash" aria-hidden="true"></i> {{$delete}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{$pager nofilter}}
|
||||||
|
</form>
|
||||||
|
</div>
|
BIN
smiley_pack/icons/commercial/facebook.gif
Normal file
After Width: | Height: | Size: 269 B |
BIN
smiley_pack/icons/commercial/github.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
smiley_pack/icons/commercial/google.gif
Normal file
After Width: | Height: | Size: 270 B |
BIN
smiley_pack/icons/commercial/instagram.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
smiley_pack/icons/commercial/signal.gif
Normal file
After Width: | Height: | Size: 339 B |
BIN
smiley_pack/icons/commercial/telegram.gif
Normal file
After Width: | Height: | Size: 627 B |
BIN
smiley_pack/icons/commercial/threads.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
smiley_pack/icons/commercial/threema.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
smiley_pack/icons/commercial/tiktok.gif
Normal file
After Width: | Height: | Size: 257 B |
BIN
smiley_pack/icons/commercial/whatsapp.gif
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
smiley_pack/icons/commercial/windows.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 79 B After Width: | Height: | Size: 1.1 KiB |
BIN
smiley_pack/icons/fediverse/diaspora.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
smiley_pack/icons/fediverse/fediverse.gif
Normal file
After Width: | Height: | Size: 444 B |
BIN
smiley_pack/icons/fediverse/friendica.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
smiley_pack/icons/fediverse/funkwhale.gif
Normal file
After Width: | Height: | Size: 471 B |
BIN
smiley_pack/icons/fediverse/gnusocial.gif
Normal file
After Width: | Height: | Size: 135 B |
BIN
smiley_pack/icons/fediverse/hubzilla.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
smiley_pack/icons/fediverse/lemmy.gif
Normal file
After Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 1.1 KiB |
BIN
smiley_pack/icons/fediverse/peertube.gif
Normal file
After Width: | Height: | Size: 137 B |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 100 B After Width: | Height: | Size: 180 B |
BIN
smiley_pack/icons/fediverse/plume.gif
Normal file
After Width: | Height: | Size: 410 B |
BIN
smiley_pack/icons/fediverse/writefreely.gif
Normal file
After Width: | Height: | Size: 112 B |
BIN
smiley_pack/icons/noncommercial/bluesky.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
smiley_pack/icons/noncommercial/invidious.gif
Normal file
After Width: | Height: | Size: 908 B |
BIN
smiley_pack/icons/noncommercial/vivaldi.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
smiley_pack/icons/opensource/archlinux.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
smiley_pack/icons/opensource/debian.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
smiley_pack/icons/opensource/fdroid.png
Normal file
After Width: | Height: | Size: 7.7 KiB |
BIN
smiley_pack/icons/opensource/fedora.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
smiley_pack/icons/opensource/firefox.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
smiley_pack/icons/opensource/firefoxnightly.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
smiley_pack/icons/opensource/foss.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
smiley_pack/icons/opensource/jabber.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
smiley_pack/icons/opensource/kde.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
smiley_pack/icons/opensource/linux.png
Normal file
After Width: | Height: | Size: 5 KiB |
BIN
smiley_pack/icons/opensource/matrix.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
smiley_pack/icons/opensource/mint.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
smiley_pack/icons/opensource/opensuse.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
smiley_pack/icons/opensource/raspi.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
smiley_pack/icons/opensource/thunderbird.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
smiley_pack/icons/opensource/tutanota.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
smiley_pack/icons/opensource/ubuntu.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
smiley_pack/icons/opensource/xmpp.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
smiley_pack/icons/respect/cc.png
Normal file
After Width: | Height: | Size: 4.4 KiB |
BIN
smiley_pack/icons/respect/cc0.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
smiley_pack/icons/respect/ccby.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
smiley_pack/icons/respect/ccsa.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
|
@ -2,17 +2,17 @@
|
||||||
/*
|
/*
|
||||||
* Name: Smiley Pack
|
* Name: Smiley Pack
|
||||||
* Description: Pack of smileys that make master too AOLish.
|
* 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: Thomas Willingham (based on Mike Macgirvin's Adult Smile template)
|
||||||
* Author: Matthias Ebers <https://loma.ml/profile/one>
|
* Author: Matthias Ebers <https://loma.ml/profile/one>
|
||||||
* All smileys from sites offering them as Public Domain
|
* All smileys from sites offering them as Public Domain
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Friendica\App;
|
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
|
||||||
function smiley_pack_install() {
|
function smiley_pack_install()
|
||||||
|
{
|
||||||
Hook::register('smilie', 'addon/smiley_pack/smiley_pack.php', 'smiley_pack_smilies');
|
Hook::register('smilie', 'addon/smiley_pack/smiley_pack.php', 'smiley_pack_smilies');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,6 @@ function smiley_pack_smilies(array &$b)
|
||||||
#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 :
|
#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.
|
#when all else fails.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#Animal smileys.
|
#Animal smileys.
|
||||||
|
|
||||||
$b['texts'][] = ':bunnyflowers:';
|
$b['texts'][] = ':bunnyflowers:';
|
||||||
|
@ -99,8 +97,6 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':pig:';
|
$b['texts'][] = ':pig:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/pig.gif' . '" alt="' . ':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['texts'][] = ':baby:';
|
||||||
|
@ -109,14 +105,12 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':babycot:';
|
$b['texts'][] = ':babycot:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/babycot.gif' . '" alt="' . ':babycot:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/babycot.gif' . '" alt="' . ':babycot:' . '" />';
|
||||||
|
|
||||||
|
|
||||||
$b['texts'][] = ':pregnant:';
|
$b['texts'][] = ':pregnant:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/pregnant.gif' . '" alt="' . ':pregnant:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/pregnant.gif' . '" alt="' . ':pregnant:' . '" />';
|
||||||
|
|
||||||
$b['texts'][] = ':stork:';
|
$b['texts'][] = ':stork:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/stork.gif' . '" alt="' . ':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['texts'][] = ':confused:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/confused.gif' . '" alt="' . ':confused:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/confused.gif' . '" alt="' . ':confused:' . '" />';
|
||||||
|
@ -130,7 +124,6 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':dazed:';
|
$b['texts'][] = ':dazed:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/dazed.gif' . '" alt="' . ':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['texts'][] = ':affro:';
|
||||||
|
@ -390,6 +383,18 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':number1:';
|
$b['texts'][] = ':number1:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/number1.gif' . '" alt="' . ':number1:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/respect/number1.gif' . '" alt="' . ':number1:' . '" />';
|
||||||
|
|
||||||
|
$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
|
#Laugh smileys
|
||||||
|
|
||||||
$b['texts'][] = ':hahaha:';
|
$b['texts'][] = ':hahaha:';
|
||||||
|
@ -406,7 +411,6 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':drums:';
|
$b['texts'][] = ':drums:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/drums.gif' . '" alt="' . ':drums:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/drums.gif' . '" alt="' . ':drums:' . '" />';
|
||||||
|
|
||||||
|
|
||||||
$b['texts'][] = ':guitar:';
|
$b['texts'][] = ':guitar:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/guitar.gif' . '" alt="' . ':guitar:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/guitar.gif' . '" alt="' . ':guitar:' . '" />';
|
||||||
|
|
||||||
|
@ -480,11 +484,9 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['texts'][] = ':gangs:';
|
$b['texts'][] = ':gangs:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fight/gangs.gif' . '" alt="' . ':gangs:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fight/gangs.gif' . '" alt="' . ':gangs:' . '" />';
|
||||||
|
|
||||||
|
|
||||||
$b['texts'][] = ':dj:';
|
$b['texts'][] = ':dj:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/dj.gif' . '" alt="' . ':dj:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/dj.gif' . '" alt="' . ':dj:' . '" />';
|
||||||
|
|
||||||
|
|
||||||
$b['texts'][] = ':elvis:';
|
$b['texts'][] = ':elvis:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/elvis.gif' . '" alt="' . ':elivs:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/music/elvis.gif' . '" alt="' . ':elivs:' . '" />';
|
||||||
|
|
||||||
|
@ -495,7 +497,10 @@ function smiley_pack_smilies(array &$b)
|
||||||
# Fediverse
|
# Fediverse
|
||||||
|
|
||||||
$b['texts'][] = ':friendica:';
|
$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['texts'][] = ':mastodon:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/mastodon.gif' . '" alt="' . ':mastodon:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/mastodon.gif' . '" alt="' . ':mastodon:' . '" />';
|
||||||
|
@ -507,10 +512,10 @@ function smiley_pack_smilies(array &$b)
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/misskey.gif' . '" alt="' . ':misskey:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/misskey.gif' . '" alt="' . ':misskey:' . '" />';
|
||||||
|
|
||||||
$b['texts'][] = ':diaspora:';
|
$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['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['texts'][] = ':pixelfed:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/pixelfed.gif' . '" alt="' . ':pixelfeed:' . '" />';
|
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/fediverse/pixelfed.gif' . '" alt="' . ':pixelfeed:' . '" />';
|
||||||
|
@ -539,4 +544,107 @@ function smiley_pack_smilies(array &$b)
|
||||||
|
|
||||||
$b['texts'][] = ':twitch:';
|
$b['texts'][] = ':twitch:';
|
||||||
$b['icons'][] = '<img class="smiley" src="' . DI::baseUrl() . '/addon/smiley_pack/icons/commercial/twitch.gif' . '" alt="' . ':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:' . '" />';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1293,6 +1293,8 @@ function unicode_smilies_smilies(array &$b)
|
||||||
Smilies::add($b, ':microscope:', '🔬');
|
Smilies::add($b, ':microscope:', '🔬');
|
||||||
Smilies::add($b, ':telescope:', '🔭');
|
Smilies::add($b, ':telescope:', '🔭');
|
||||||
Smilies::add($b, ':satellite antenna:', '📡');
|
Smilies::add($b, ':satellite antenna:', '📡');
|
||||||
|
Smilies::add($b, ':asterism:', '⁂');
|
||||||
|
Smilies::add($b, ':outlines white star:', '⚝');
|
||||||
|
|
||||||
// medical
|
// medical
|
||||||
Smilies::add($b, ':syringe:', '💉');
|
Smilies::add($b, ':syringe:', '💉');
|
||||||
|
|