diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php
index bea98b9de..34fb256f1 100644
--- a/app/Http/Controllers/Api/ApiV1Controller.php
+++ b/app/Http/Controllers/Api/ApiV1Controller.php
@@ -4204,4 +4204,26 @@ class ApiV1Controller extends Controller
return $this->json([]);
}
+
+ /**
+ * GET /api/v1/instance/peers
+ *
+ *
+ * @return array
+ */
+ public function instancePeers(Request $request)
+ {
+ if ((bool) config('instance.show_peers') == false) {
+ return $this->json([]);
+ }
+
+ return $this->json(
+ Cache::remember(InstanceService::CACHE_KEY_API_PEERS_LIST, now()->addHours(24), function () {
+ return Instance::whereNotNull('nodeinfo_last_fetched')
+ ->whereBanned(false)
+ ->where('nodeinfo_last_fetched', '>', now()->subDays(8))
+ ->pluck('domain');
+ })
+ );
+ }
}
diff --git a/app/Services/InstanceService.php b/app/Services/InstanceService.php
index 2ad991063..c07e17521 100644
--- a/app/Services/InstanceService.php
+++ b/app/Services/InstanceService.php
@@ -2,76 +2,84 @@
namespace App\Services;
-use Cache;
use App\Instance;
use App\Util\Blurhash\Blurhash;
-use App\Services\ConfigCacheService;
+use Cache;
class InstanceService
{
const CACHE_KEY_BY_DOMAIN = 'pf:services:instance:by_domain:';
- const CACHE_KEY_BANNED_DOMAINS = 'instances:banned:domains';
- const CACHE_KEY_UNLISTED_DOMAINS = 'instances:unlisted:domains';
- const CACHE_KEY_NSFW_DOMAINS = 'instances:auto_cw:domains';
- const CACHE_KEY_STATS = 'pf:services:instances:stats';
- const CACHE_KEY_BANNER_BLURHASH = 'pf:services:instance:header-blurhash:v1';
- public function __construct()
- {
- ini_set('memory_limit', config('pixelfed.memory_limit', '1024M'));
- }
+ const CACHE_KEY_BANNED_DOMAINS = 'instances:banned:domains';
- public static function getByDomain($domain)
- {
- return Cache::remember(self::CACHE_KEY_BY_DOMAIN.$domain, 3600, function() use($domain) {
- return Instance::whereDomain($domain)->first();
- });
- }
+ const CACHE_KEY_UNLISTED_DOMAINS = 'instances:unlisted:domains';
- public static function getBannedDomains()
- {
- return Cache::remember(self::CACHE_KEY_BANNED_DOMAINS, 1209600, function() {
- return Instance::whereBanned(true)->pluck('domain')->toArray();
- });
- }
+ const CACHE_KEY_NSFW_DOMAINS = 'instances:auto_cw:domains';
- public static function getUnlistedDomains()
- {
- return Cache::remember(self::CACHE_KEY_UNLISTED_DOMAINS, 1209600, function() {
- return Instance::whereUnlisted(true)->pluck('domain')->toArray();
- });
- }
+ const CACHE_KEY_STATS = 'pf:services:instances:stats';
- public static function getNsfwDomains()
- {
- return Cache::remember(self::CACHE_KEY_NSFW_DOMAINS, 1209600, function() {
- return Instance::whereAutoCw(true)->pluck('domain')->toArray();
- });
- }
+ const CACHE_KEY_BANNER_BLURHASH = 'pf:services:instance:header-blurhash:v1';
- public static function software($domain)
- {
- $key = 'instances:software:' . strtolower($domain);
- return Cache::remember($key, 86400, function() use($domain) {
- $instance = Instance::whereDomain($domain)->first();
- if(!$instance) {
- return;
- }
- return $instance->software;
- });
- }
+ const CACHE_KEY_API_PEERS_LIST = 'pf:services:instance:api:peers:list:v0';
- public static function stats()
- {
- return Cache::remember(self::CACHE_KEY_STATS, 86400, function() {
- return [
- 'total_count' => Instance::count(),
- 'new_count' => Instance::where('created_at', '>', now()->subDays(14))->count(),
- 'banned_count' => Instance::whereBanned(true)->count(),
- 'nsfw_count' => Instance::whereAutoCw(true)->count()
- ];
- });
- }
+ public function __construct()
+ {
+ ini_set('memory_limit', config('pixelfed.memory_limit', '1024M'));
+ }
+
+ public static function getByDomain($domain)
+ {
+ return Cache::remember(self::CACHE_KEY_BY_DOMAIN.$domain, 3600, function () use ($domain) {
+ return Instance::whereDomain($domain)->first();
+ });
+ }
+
+ public static function getBannedDomains()
+ {
+ return Cache::remember(self::CACHE_KEY_BANNED_DOMAINS, 1209600, function () {
+ return Instance::whereBanned(true)->pluck('domain')->toArray();
+ });
+ }
+
+ public static function getUnlistedDomains()
+ {
+ return Cache::remember(self::CACHE_KEY_UNLISTED_DOMAINS, 1209600, function () {
+ return Instance::whereUnlisted(true)->pluck('domain')->toArray();
+ });
+ }
+
+ public static function getNsfwDomains()
+ {
+ return Cache::remember(self::CACHE_KEY_NSFW_DOMAINS, 1209600, function () {
+ return Instance::whereAutoCw(true)->pluck('domain')->toArray();
+ });
+ }
+
+ public static function software($domain)
+ {
+ $key = 'instances:software:'.strtolower($domain);
+
+ return Cache::remember($key, 86400, function () use ($domain) {
+ $instance = Instance::whereDomain($domain)->first();
+ if (! $instance) {
+ return;
+ }
+
+ return $instance->software;
+ });
+ }
+
+ public static function stats()
+ {
+ return Cache::remember(self::CACHE_KEY_STATS, 86400, function () {
+ return [
+ 'total_count' => Instance::count(),
+ 'new_count' => Instance::where('created_at', '>', now()->subDays(14))->count(),
+ 'banned_count' => Instance::whereBanned(true)->count(),
+ 'nsfw_count' => Instance::whereAutoCw(true)->count(),
+ ];
+ });
+ }
public static function refresh()
{
@@ -79,6 +87,7 @@ class InstanceService
Cache::forget(self::CACHE_KEY_UNLISTED_DOMAINS);
Cache::forget(self::CACHE_KEY_NSFW_DOMAINS);
Cache::forget(self::CACHE_KEY_STATS);
+ Cache::forget(self::CACHE_KEY_API_PEERS_LIST);
self::getBannedDomains();
self::getUnlistedDomains();
@@ -89,50 +98,50 @@ class InstanceService
public static function headerBlurhash()
{
- return Cache::rememberForever(self::CACHE_KEY_BANNER_BLURHASH, function() {
- if(str_ends_with(config_cache('app.banner_image'), 'headers/default.jpg')) {
- return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
- }
- $cached = config_cache('instance.banner.blurhash');
+ return Cache::rememberForever(self::CACHE_KEY_BANNER_BLURHASH, function () {
+ if (str_ends_with(config_cache('app.banner_image'), 'headers/default.jpg')) {
+ return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
+ }
+ $cached = config_cache('instance.banner.blurhash');
- if($cached) {
- return $cached;
- }
+ if ($cached) {
+ return $cached;
+ }
- $file = config_cache('app.banner_image') ?? url(Storage::url('public/headers/default.jpg'));
+ $file = config_cache('app.banner_image') ?? url(Storage::url('public/headers/default.jpg'));
- $image = imagecreatefromstring(file_get_contents($file));
- if(!$image) {
- return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
- }
- $width = imagesx($image);
- $height = imagesy($image);
+ $image = imagecreatefromstring(file_get_contents($file));
+ if (! $image) {
+ return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
+ }
+ $width = imagesx($image);
+ $height = imagesy($image);
- $pixels = [];
- for ($y = 0; $y < $height; ++$y) {
- $row = [];
- for ($x = 0; $x < $width; ++$x) {
- $index = imagecolorat($image, $x, $y);
- $colors = imagecolorsforindex($image, $index);
+ $pixels = [];
+ for ($y = 0; $y < $height; $y++) {
+ $row = [];
+ for ($x = 0; $x < $width; $x++) {
+ $index = imagecolorat($image, $x, $y);
+ $colors = imagecolorsforindex($image, $index);
- $row[] = [$colors['red'], $colors['green'], $colors['blue']];
- }
- $pixels[] = $row;
- }
+ $row[] = [$colors['red'], $colors['green'], $colors['blue']];
+ }
+ $pixels[] = $row;
+ }
- // Free the allocated GdImage object from memory:
- imagedestroy($image);
+ // Free the allocated GdImage object from memory:
+ imagedestroy($image);
- $components_x = 4;
- $components_y = 4;
- $blurhash = Blurhash::encode($pixels, $components_x, $components_y);
- if(strlen($blurhash) > 191) {
- return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
- }
+ $components_x = 4;
+ $components_y = 4;
+ $blurhash = Blurhash::encode($pixels, $components_x, $components_y);
+ if (strlen($blurhash) > 191) {
+ return 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt';
+ }
- ConfigCacheService::put('instance.banner.blurhash', $blurhash);
+ ConfigCacheService::put('instance.banner.blurhash', $blurhash);
- return $blurhash;
- });
+ return $blurhash;
+ });
}
}
diff --git a/config/instance.php b/config/instance.php
index cfc0468ab..3c931cf7e 100644
--- a/config/instance.php
+++ b/config/instance.php
@@ -1,136 +1,136 @@
env('FORCE_HTTPS_URLS', true),
+ 'force_https_urls' => env('FORCE_HTTPS_URLS', true),
- 'description' => env('INSTANCE_DESCRIPTION', 'Pixelfed - Photo sharing for everyone'),
+ 'description' => env('INSTANCE_DESCRIPTION', 'Pixelfed - Photo sharing for everyone'),
- 'contact' => [
- 'enabled' => env('INSTANCE_CONTACT_FORM', false),
- 'max_per_day' => env('INSTANCE_CONTACT_MAX_PER_DAY', 1),
- ],
+ 'contact' => [
+ 'enabled' => env('INSTANCE_CONTACT_FORM', false),
+ 'max_per_day' => env('INSTANCE_CONTACT_MAX_PER_DAY', 1),
+ ],
- 'discover' => [
- 'public' => env('INSTANCE_DISCOVER_PUBLIC', false),
- 'loops' => [
- 'enabled' => env('EXP_LOOPS', false),
- ],
- 'tags' => [
- 'is_public' => env('INSTANCE_PUBLIC_HASHTAGS', false)
- ],
- ],
+ 'discover' => [
+ 'public' => env('INSTANCE_DISCOVER_PUBLIC', false),
+ 'loops' => [
+ 'enabled' => env('EXP_LOOPS', false),
+ ],
+ 'tags' => [
+ 'is_public' => env('INSTANCE_PUBLIC_HASHTAGS', false),
+ ],
+ ],
- 'email' => env('INSTANCE_CONTACT_EMAIL'),
+ 'email' => env('INSTANCE_CONTACT_EMAIL'),
- 'timeline' => [
- 'home' => [
- 'cached' => env('PF_HOME_TIMELINE_CACHE', false),
- 'cache_ttl' => env('PF_HOME_TIMELINE_CACHE_TTL', 900)
- ],
+ 'timeline' => [
+ 'home' => [
+ 'cached' => env('PF_HOME_TIMELINE_CACHE', false),
+ 'cache_ttl' => env('PF_HOME_TIMELINE_CACHE_TTL', 900),
+ ],
- 'local' => [
- 'cached' => env('INSTANCE_PUBLIC_TIMELINE_CACHED', false),
- 'is_public' => env('INSTANCE_PUBLIC_LOCAL_TIMELINE', false)
- ],
+ 'local' => [
+ 'cached' => env('INSTANCE_PUBLIC_TIMELINE_CACHED', false),
+ 'is_public' => env('INSTANCE_PUBLIC_LOCAL_TIMELINE', false),
+ ],
- 'network' => [
- 'cached' => env('PF_NETWORK_TIMELINE') ? env('INSTANCE_NETWORK_TIMELINE_CACHED', false) : false,
- 'cache_dropoff' => env('INSTANCE_NETWORK_TIMELINE_CACHE_DROPOFF', 100),
- 'max_hours_old' => env('INSTANCE_NETWORK_TIMELINE_CACHE_MAX_HOUR_INGEST', 6)
- ]
- ],
+ 'network' => [
+ 'cached' => env('PF_NETWORK_TIMELINE') ? env('INSTANCE_NETWORK_TIMELINE_CACHED', false) : false,
+ 'cache_dropoff' => env('INSTANCE_NETWORK_TIMELINE_CACHE_DROPOFF', 100),
+ 'max_hours_old' => env('INSTANCE_NETWORK_TIMELINE_CACHE_MAX_HOUR_INGEST', 6),
+ ],
+ ],
- 'page' => [
- '404' => [
- 'header' => env('PAGE_404_HEADER', 'Sorry, this page isn\'t available.'),
- 'body' => env('PAGE_404_BODY', 'The link you followed may be broken, or the page may have been removed. Go back to Pixelfed.')
- ],
- '503' => [
- 'header' => env('PAGE_503_HEADER', 'Service Unavailable'),
- 'body' => env('PAGE_503_BODY', 'Our service is in maintenance mode, please try again later.')
- ]
- ],
+ 'page' => [
+ '404' => [
+ 'header' => env('PAGE_404_HEADER', 'Sorry, this page isn\'t available.'),
+ 'body' => env('PAGE_404_BODY', 'The link you followed may be broken, or the page may have been removed. Go back to Pixelfed.'),
+ ],
+ '503' => [
+ 'header' => env('PAGE_503_HEADER', 'Service Unavailable'),
+ 'body' => env('PAGE_503_BODY', 'Our service is in maintenance mode, please try again later.'),
+ ],
+ ],
- 'username' => [
- 'banned' => env('BANNED_USERNAMES'),
- 'remote' => [
- 'formats' => ['@', 'from', 'custom'],
- 'format' => in_array(env('USERNAME_REMOTE_FORMAT', '@'), ['@','from','custom']) ? env('USERNAME_REMOTE_FORMAT', '@') : '@',
- 'custom' => env('USERNAME_REMOTE_CUSTOM_TEXT', null)
- ]
- ],
+ 'username' => [
+ 'banned' => env('BANNED_USERNAMES'),
+ 'remote' => [
+ 'formats' => ['@', 'from', 'custom'],
+ 'format' => in_array(env('USERNAME_REMOTE_FORMAT', '@'), ['@', 'from', 'custom']) ? env('USERNAME_REMOTE_FORMAT', '@') : '@',
+ 'custom' => env('USERNAME_REMOTE_CUSTOM_TEXT', null),
+ ],
+ ],
- 'polls' => [
- 'enabled' => false
- ],
+ 'polls' => [
+ 'enabled' => false,
+ ],
- 'stories' => [
- 'enabled' => env('STORIES_ENABLED', false),
- ],
+ 'stories' => [
+ 'enabled' => env('STORIES_ENABLED', false),
+ ],
- 'restricted' => [
- 'enabled' => env('RESTRICTED_INSTANCE', false),
- 'level' => 1
- ],
+ 'restricted' => [
+ 'enabled' => env('RESTRICTED_INSTANCE', false),
+ 'level' => 1,
+ ],
- 'oauth' => [
- 'token_expiration' => env('OAUTH_TOKEN_DAYS', 365),
- 'refresh_expiration' => env('OAUTH_REFRESH_DAYS', 400),
- 'pat' => [
- 'enabled' => env('OAUTH_PAT_ENABLED', false),
- 'id' => env('OAUTH_PAT_ID'),
- ]
- ],
+ 'oauth' => [
+ 'token_expiration' => env('OAUTH_TOKEN_DAYS', 365),
+ 'refresh_expiration' => env('OAUTH_REFRESH_DAYS', 400),
+ 'pat' => [
+ 'enabled' => env('OAUTH_PAT_ENABLED', false),
+ 'id' => env('OAUTH_PAT_ID'),
+ ],
+ ],
- 'label' => [
- 'covid' => [
- 'enabled' => env('ENABLE_COVID_LABEL', true),
- 'url' => env('COVID_LABEL_URL', 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/advice-for-public'),
- 'org' => env('COVID_LABEL_ORG', 'visit the WHO website')
- ]
- ],
+ 'label' => [
+ 'covid' => [
+ 'enabled' => env('ENABLE_COVID_LABEL', true),
+ 'url' => env('COVID_LABEL_URL', 'https://www.who.int/emergencies/diseases/novel-coronavirus-2019/advice-for-public'),
+ 'org' => env('COVID_LABEL_ORG', 'visit the WHO website'),
+ ],
+ ],
- 'enable_cc' => env('ENABLE_CONFIG_CACHE', true),
+ 'enable_cc' => env('ENABLE_CONFIG_CACHE', true),
- 'has_legal_notice' => env('INSTANCE_LEGAL_NOTICE', false),
+ 'has_legal_notice' => env('INSTANCE_LEGAL_NOTICE', false),
- 'embed' => [
- 'profile' => env('INSTANCE_PROFILE_EMBEDS', true),
- 'post' => env('INSTANCE_POST_EMBEDS', true),
- ],
+ 'embed' => [
+ 'profile' => env('INSTANCE_PROFILE_EMBEDS', true),
+ 'post' => env('INSTANCE_POST_EMBEDS', true),
+ ],
- 'hide_nsfw_on_public_feeds' => env('PF_HIDE_NSFW_ON_PUBLIC_FEEDS', false),
+ 'hide_nsfw_on_public_feeds' => env('PF_HIDE_NSFW_ON_PUBLIC_FEEDS', false),
- 'avatar' => [
- 'local_to_cloud' => env('PF_LOCAL_AVATAR_TO_CLOUD', false)
- ],
+ 'avatar' => [
+ 'local_to_cloud' => env('PF_LOCAL_AVATAR_TO_CLOUD', false),
+ ],
- 'admin_invites' => [
- 'enabled' => env('PF_ADMIN_INVITES_ENABLED', true)
- ],
+ 'admin_invites' => [
+ 'enabled' => env('PF_ADMIN_INVITES_ENABLED', true),
+ ],
- 'user_filters' => [
- 'max_user_blocks' => env('PF_MAX_USER_BLOCKS', 50),
- 'max_user_mutes' => env('PF_MAX_USER_MUTES', 50),
- 'max_domain_blocks' => env('PF_MAX_DOMAIN_BLOCKS', 50),
- ],
+ 'user_filters' => [
+ 'max_user_blocks' => env('PF_MAX_USER_BLOCKS', 50),
+ 'max_user_mutes' => env('PF_MAX_USER_MUTES', 50),
+ 'max_domain_blocks' => env('PF_MAX_DOMAIN_BLOCKS', 50),
+ ],
- 'reports' => [
- 'email' => [
- 'enabled' => env('INSTANCE_REPORTS_EMAIL_ENABLED', false),
- 'to' => env('INSTANCE_REPORTS_EMAIL_ADDRESSES'),
- 'autospam' => env('INSTANCE_REPORTS_EMAIL_AUTOSPAM', false)
- ]
- ],
+ 'reports' => [
+ 'email' => [
+ 'enabled' => env('INSTANCE_REPORTS_EMAIL_ENABLED', false),
+ 'to' => env('INSTANCE_REPORTS_EMAIL_ADDRESSES'),
+ 'autospam' => env('INSTANCE_REPORTS_EMAIL_AUTOSPAM', false),
+ ],
+ ],
- 'landing' => [
- 'show_directory' => env('INSTANCE_LANDING_SHOW_DIRECTORY', true),
- 'show_explore' => env('INSTANCE_LANDING_SHOW_EXPLORE', true),
- ],
+ 'landing' => [
+ 'show_directory' => env('INSTANCE_LANDING_SHOW_DIRECTORY', true),
+ 'show_explore' => env('INSTANCE_LANDING_SHOW_EXPLORE', true),
+ ],
- 'banner' => [
- 'blurhash' => env('INSTANCE_BANNER_BLURHASH', 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt')
- ],
+ 'banner' => [
+ 'blurhash' => env('INSTANCE_BANNER_BLURHASH', 'UzJR]l{wHZRjM}R%XRkCH?X9xaWEjZj]kAjt'),
+ ],
'parental_controls' => [
'enabled' => env('INSTANCE_PARENTAL_CONTROLS', false),
@@ -143,14 +143,14 @@ return [
],
'software-update' => [
- 'disable_failed_warning' => env('INSTANCE_SOFTWARE_UPDATE_DISABLE_FAILED_WARNING', false)
+ 'disable_failed_warning' => env('INSTANCE_SOFTWARE_UPDATE_DISABLE_FAILED_WARNING', false),
],
'notifications' => [
'gc' => [
'enabled' => env('INSTANCE_NOTIFY_AUTO_GC', false),
- 'delete_after_days' => env('INSTANCE_NOTIFY_AUTO_GC_DEL_AFTER_DAYS', 365)
- ]
+ 'delete_after_days' => env('INSTANCE_NOTIFY_AUTO_GC_DEL_AFTER_DAYS', 365),
+ ],
],
'curated_registration' => [
@@ -173,7 +173,9 @@ return [
'max_per_day' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_VERIFY_MPD', 10),
],
'on_user_response' => env('INSTANCE_CUR_REG_NOTIFY_ADMIN_ON_USER_RESPONSE', false),
- ]
+ ],
],
],
+
+ 'show_peers' => env('INSTANCE_SHOW_PEERS', false),
];
diff --git a/routes/api.php b/routes/api.php
index d2e581a37..7cee24869 100644
--- a/routes/api.php
+++ b/routes/api.php
@@ -26,6 +26,7 @@ Route::group(['prefix' => 'api'], function() use($middleware) {
Route::post('apps', 'Api\ApiV1Controller@apps');
Route::get('apps/verify_credentials', 'Api\ApiV1Controller@getApp')->middleware($middleware);
Route::get('instance', 'Api\ApiV1Controller@instance');
+ Route::get('instance/peers', 'Api\ApiV1Controller@instancePeers');
Route::get('bookmarks', 'Api\ApiV1Controller@bookmarks')->middleware($middleware);
Route::get('accounts/verify_credentials', 'Api\ApiV1Controller@verifyCredentials')->middleware($middleware);