teknolis / app /Services /SocialPublisherService.php
OpenAI Codex
Fix storage symlink and adapt cron status for Spaces
1501522
Raw
History Blame Contribute Delete
6.53 kB
<?php
namespace App\Services;
use App\Models\SocialPlatformCredential;
use App\Models\SocialPost;
use Illuminate\Support\Facades\Http;
use RuntimeException;
class SocialPublisherService
{
public function publish(SocialPost $post, SocialPlatformCredential $credential): array
{
return match ($post->platform) {
'facebook' => $this->publishFacebook($post, $credential),
'instagram' => $this->publishInstagram($post, $credential),
'x' => $this->publishX($post, $credential),
'tiktok' => $this->publishTikTok($post, $credential),
default => throw new RuntimeException('Platform tidak dikenali: '.$post->platform),
};
}
private function publishFacebook(SocialPost $post, SocialPlatformCredential $credential): array
{
$pageId = trim((string) $credential->account_id);
$token = trim((string) $credential->access_token);
if ($pageId === '' || $token === '') {
throw new RuntimeException('Facebook butuh PAGE_ID dan PAGE_ACCESS_TOKEN.');
}
$payload = [
'message' => $post->fullCaption(),
'access_token' => $token,
];
if (! empty($post->image_url)) {
$payload['link'] = $post->image_url;
}
$response = Http::asForm()
->timeout(45)
->post("https://graph.facebook.com/v22.0/{$pageId}/feed", $payload);
if (! $response->successful()) {
$message = data_get($response->json(), 'error.message', $response->body());
throw new RuntimeException('Facebook publish gagal: '.$response->status().' - '.$message);
}
return [
'external_post_id' => (string) data_get($response->json(), 'id', ''),
'payload' => $response->json(),
];
}
private function publishInstagram(SocialPost $post, SocialPlatformCredential $credential): array
{
$igAccountId = trim((string) $credential->account_id);
$token = trim((string) $credential->access_token);
if ($igAccountId === '' || $token === '') {
throw new RuntimeException('Instagram butuh IG_BUSINESS_ACCOUNT_ID dan ACCESS_TOKEN.');
}
if (empty($post->image_url)) {
throw new RuntimeException('Instagram saat ini butuh image_url publik. Isi URL gambar dulu.');
}
$createContainer = Http::asForm()
->timeout(60)
->post("https://graph.facebook.com/v22.0/{$igAccountId}/media", [
'image_url' => $post->image_url,
'caption' => $post->fullCaption(),
'access_token' => $token,
]);
if (! $createContainer->successful()) {
$message = data_get($createContainer->json(), 'error.message', $createContainer->body());
throw new RuntimeException('Instagram create media gagal: '.$createContainer->status().' - '.$message);
}
$creationId = (string) data_get($createContainer->json(), 'id');
if ($creationId === '') {
throw new RuntimeException('Instagram creation_id kosong.');
}
$publish = Http::asForm()
->timeout(60)
->post("https://graph.facebook.com/v22.0/{$igAccountId}/media_publish", [
'creation_id' => $creationId,
'access_token' => $token,
]);
if (! $publish->successful()) {
$message = data_get($publish->json(), 'error.message', $publish->body());
throw new RuntimeException('Instagram media_publish gagal: '.$publish->status().' - '.$message);
}
return [
'external_post_id' => (string) data_get($publish->json(), 'id', ''),
'payload' => [
'creation' => $createContainer->json(),
'publish' => $publish->json(),
],
];
}
private function publishX(SocialPost $post, SocialPlatformCredential $credential): array
{
$token = trim((string) $credential->access_token);
if ($token === '') {
throw new RuntimeException('X/Twitter butuh ACCESS_TOKEN OAuth2 user context (scope tweet.write).');
}
$response = Http::timeout(45)
->withToken($token)
->acceptJson()
->post('https://api.x.com/2/tweets', [
'text' => $post->fullCaption(),
]);
if (! $response->successful()) {
$message = data_get($response->json(), 'detail', $response->body());
throw new RuntimeException('X publish gagal: '.$response->status().' - '.$message);
}
return [
'external_post_id' => (string) data_get($response->json(), 'data.id', ''),
'payload' => $response->json(),
];
}
private function publishTikTok(SocialPost $post, SocialPlatformCredential $credential): array
{
$token = trim((string) $credential->access_token);
if ($token === '') {
throw new RuntimeException('TikTok butuh OAuth access token user (scope video.publish).');
}
if (empty($post->video_url)) {
throw new RuntimeException('TikTok butuh video_url publik. Isi URL video pada form post.');
}
$title = trim((string) ($post->title ?: 'Konten terbaru'));
if ($title === '') {
$title = 'Konten terbaru';
}
$response = Http::timeout(90)
->withToken($token)
->acceptJson()
->post('https://open.tiktokapis.com/v2/post/publish/video/init/', [
'post_info' => [
'title' => mb_substr($title, 0, 90),
'privacy_level' => 'SELF_ONLY',
'disable_duet' => false,
'disable_comment' => false,
'disable_stitch' => false,
],
'source_info' => [
'source' => 'PULL_FROM_URL',
'video_url' => $post->video_url,
],
]);
if (! $response->successful()) {
$message = data_get($response->json(), 'error.message', $response->body());
throw new RuntimeException('TikTok init publish gagal: '.$response->status().' - '.$message);
}
return [
'external_post_id' => (string) data_get($response->json(), 'data.publish_id', ''),
'payload' => $response->json(),
];
}
}