diff --git a/.env.example b/.env.example index 4235fe34..eb423aaa 100644 --- a/.env.example +++ b/.env.example @@ -81,5 +81,3 @@ LOG_SLACK_WEBHOOK_URL= FLARE_KEY= IGNITION_OPEN_AI_KEY= - -BRIDGY_MASTODON_TOKEN= diff --git a/app/Console/Commands/ReprocessMediaImages.php b/app/Console/Commands/ReprocessMediaImages.php index 299f0103..c5e22d1b 100644 --- a/app/Console/Commands/ReprocessMediaImages.php +++ b/app/Console/Commands/ReprocessMediaImages.php @@ -25,18 +25,20 @@ class ReprocessMediaImages extends Command $dryRun = $this->option('dry-run'); - $this->info("Found {$media->count()} images to reprocess." . ($dryRun ? ' (dry run)' : '')); + $this->info("Found {$media->count()} images to reprocess.".($dryRun ? ' (dry run)' : '')); foreach ($media as $item) { $path = $item->path; if (! Storage::disk('public')->exists($path)) { $this->warn("{$path}: original not found on public disk, skipping."); + continue; } if ($dryRun) { $this->line("{$path} ({$item->image_widths}px wide)"); + continue; } @@ -46,7 +48,8 @@ class ReprocessMediaImages extends Command $file = Storage::disk('public')->get($path); $image = $manager->read($file); } catch (DecoderException) { - $this->warn(" Could not decode image, skipping."); + $this->warn(' Could not decode image, skipping.'); + continue; } @@ -60,9 +63,9 @@ class ReprocessMediaImages extends Command $small = $image->scale(width: 500); Storage::disk('public')->put($basename.'-small.'.$extension, (string) $small->encode()); - $this->info(" Done."); + $this->info(' Done.'); } - $this->info('Reprocessing complete.' . ($dryRun ? ' (dry run — no files were changed)' : '')); + $this->info('Reprocessing complete.'.($dryRun ? ' (dry run — no files were changed)' : '')); } } diff --git a/app/Jobs/SyndicateNoteToBluesky.php b/app/Jobs/SyndicateNoteToBluesky.php index f9f2486b..a306801b 100644 --- a/app/Jobs/SyndicateNoteToBluesky.php +++ b/app/Jobs/SyndicateNoteToBluesky.php @@ -17,6 +17,11 @@ class SyndicateNoteToBluesky implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + /** + * Only try once — retrying would send Bridgy a duplicate publish webmention. + */ + public int $tries = 1; + /** * Create a new job instance. */ @@ -31,32 +36,32 @@ class SyndicateNoteToBluesky implements ShouldQueue */ public function handle(Client $guzzle): void { - // We can only make the request if we have an access token - if (config('bridgy.bluesky_token') === null) { - return; - } - - // Make micropub request $response = $guzzle->request( 'POST', - 'https://brid.gy/micropub', + 'https://brid.gy/publish/webmention', [ 'headers' => [ - 'Authorization' => 'Bearer '.config('bridgy.bluesky_token'), + 'Accept' => 'application/json', ], - 'json' => [ - 'type' => ['h-entry'], - 'properties' => [ - 'content' => [$this->note->getRawOriginal('note')], - ], + 'form_params' => [ + 'source' => $this->note->uri, + 'target' => 'https://brid.gy/publish/bluesky', ], + 'http_errors' => false, ] ); - // Parse for syndication URL + $body = json_decode((string) $response->getBody(), true); + if ($response->getStatusCode() === 201) { - $this->note->bluesky_url = $response->getHeader('Location')[0]; + $this->note->bluesky_url = $body['url']; $this->note->save(); + + return; } + + throw new \RuntimeException( + 'Bridgy publish to Bluesky failed: '.($body['error'] ?? (string) $response->getBody()) + ); } } diff --git a/app/Jobs/SyndicateNoteToMastodon.php b/app/Jobs/SyndicateNoteToMastodon.php index 07ea3b71..456680e2 100644 --- a/app/Jobs/SyndicateNoteToMastodon.php +++ b/app/Jobs/SyndicateNoteToMastodon.php @@ -17,6 +17,11 @@ class SyndicateNoteToMastodon implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + /** + * Only try once — retrying would send Bridgy a duplicate publish webmention. + */ + public int $tries = 1; + /** * Create a new job instance. */ @@ -31,33 +36,32 @@ class SyndicateNoteToMastodon implements ShouldQueue */ public function handle(Client $guzzle): void { - // We can only make the request if we have an access token - if (config('bridgy.mastodon_token') === null) { - return; - } - - // Make micropub request $response = $guzzle->request( 'POST', - 'https://brid.gy/micropub', + 'https://brid.gy/publish/webmention', [ 'headers' => [ - 'Authorization' => 'Bearer '.config('bridgy.mastodon_token'), + 'Accept' => 'application/json', ], - 'json' => [ - 'type' => ['h-entry'], - 'properties' => [ - 'content' => [$this->note->getRawOriginal('note')], - ], + 'form_params' => [ + 'source' => $this->note->uri, + 'target' => 'https://brid.gy/publish/mastodon', ], + 'http_errors' => false, ] ); - // Parse for syndication URL + $body = json_decode((string) $response->getBody(), true); + if ($response->getStatusCode() === 201) { - $mastodonUrl = $response->getHeader('Location')[0]; - $this->note->mastodon_url = $mastodonUrl; + $this->note->mastodon_url = $body['url']; $this->note->save(); + + return; } + + throw new \RuntimeException( + 'Bridgy publish to Mastodon failed: '.($body['error'] ?? (string) $response->getBody()) + ); } } diff --git a/config/bridgy.php b/config/bridgy.php deleted file mode 100644 index 5314afa4..00000000 --- a/config/bridgy.php +++ /dev/null @@ -1,31 +0,0 @@ - env('BRIDGY_MASTODON_TOKEN'), - - /* - |-------------------------------------------------------------------------- - | Bluesky Token - |-------------------------------------------------------------------------- - | - | When syndicating posts to Bluesky using Brid.gy’s Micropub endpoint, we - | need to provide an access token. This token can be generated by going to - | https://brid.gy/bluesky and clicking the “Get token” button. - | - */ - - 'bluesky_token' => env('BRIDGY_BLUESKY_TOKEN'), - -]; diff --git a/resources/views/templates/note.blade.php b/resources/views/templates/note.blade.php index b0893387..8e83d5d8 100644 --- a/resources/views/templates/note.blade.php +++ b/resources/views/templates/note.blade.php @@ -1,4 +1,10 @@