trypost/app/Services/Post/PostMetricsFetcher.php
Paulo Castellano cc8f6625a1 feat(channels): Discord post-level engagement metrics
Add per-post Discord metrics (server member count, thread replies as comments,
and reaction counts) read live with the bot token via GET message + guild
with_counts, wired into PostMetricsFetcher. Redesign the shared post metrics
row: monochrome line icons for member/comment counts vs clean reaction pills,
so audience stats read distinctly from reactions. Applies to Telegram too.
2026-06-16 17:05:13 -03:00

80 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Post;
use App\Enums\SocialAccount\Platform;
use App\Models\Post;
use App\Models\PostPlatform;
use App\Services\Social\BlueskyAnalytics;
use App\Services\Social\Discord\DiscordAnalytics;
use App\Services\Social\FacebookAnalytics;
use App\Services\Social\InstagramAnalytics;
use App\Services\Social\LinkedInPageAnalytics;
use App\Services\Social\MastodonAnalytics;
use App\Services\Social\PinterestAnalytics;
use App\Services\Social\Telegram\TelegramAnalytics;
use App\Services\Social\ThreadsAnalytics;
use App\Services\Social\XAnalytics;
use App\Services\Social\YouTubeAnalytics;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
/**
* Fetches per-platform post metrics. Used by the web controller, the REST
* API controller, and the MCP `GetPostMetricsTool` so that the per-platform
* dispatch and 5-minute cache stay in one place.
*/
class PostMetricsFetcher
{
/**
* @return Collection<int, array{
* post_platform_id: string,
* platform: string,
* status: string,
* platform_post_id: ?string,
* platform_url: ?string,
* metrics: array<int, array{label: string, value: int}>|array{unsupported: true, reason: string}
* }>
*/
public function forPost(Post $post): Collection
{
return $post->postPlatforms
->where('enabled', true)
->values()
->map(fn (PostPlatform $pp) => [
'post_platform_id' => $pp->id,
'platform' => $pp->platform->value,
'status' => $pp->status->value,
'platform_post_id' => $pp->platform_post_id,
'platform_url' => $pp->platform_url,
'metrics' => $this->forPlatform($pp),
]);
}
/**
* @return array<int, array{label: string, value: int}>|array{unsupported: true, reason: string}
*/
public function forPlatform(PostPlatform $postPlatform): array
{
if ($postPlatform->status->value !== 'published' || ! $postPlatform->platform_post_id) {
return ['unsupported' => true, 'reason' => 'not_published'];
}
return Cache::remember("post_metrics:{$postPlatform->id}", 300, fn () => match ($postPlatform->platform) {
Platform::X => app(XAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Bluesky => app(BlueskyAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Mastodon => app(MastodonAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Telegram => app(TelegramAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Discord => app(DiscordAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Instagram, Platform::InstagramFacebook => app(InstagramAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Facebook => app(FacebookAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Threads => app(ThreadsAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::LinkedInPage => app(LinkedInPageAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::YouTube => app(YouTubeAnalytics::class)->fetchPostMetrics($postPlatform),
Platform::Pinterest => app(PinterestAnalytics::class)->fetchPostMetrics($postPlatform),
default => ['unsupported' => true, 'reason' => 'platform_not_supported'],
});
}
}