Überblick
Feed Generator ist der Mechanismus für „algorithmische Feeds” auf Bluesky. Sie können eigene Feeds veröffentlichen, die auf bestimmte Keywords oder Nutzerkriterien zugeschnitten sind. Mit laravel-bluesky lassen sich Feed Generators einfach in einer Laravel-Anwendung implementieren.
Feed-Generator-Algorithmus registrieren
Die einfachste Verwendung besteht darin, den Algorithmus als Closure in AppServiceProvider::boot() zu registrieren.
// In AppServiceProvider::boot() registrieren
use Illuminate\Http\Request;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\FeedGenerator\FeedGenerator;
FeedGenerator::register(name: 'artisan', algo: function(int $limit, ?string $cursor, ?string $user, Request $request): array {
// Die Implementierung können Sie frei gestalten.
// Aufgrund einer temporären API-Einschränkung ist Authentifizierung nötig
$response = Bluesky::login(identifier: config('bluesky.identifier'), password: config('bluesky.password'))
->searchPosts(q: '#laravel', until: $cursor, limit: $limit);
$cursor = data_get($response->collect('posts')->last(), 'indexedAt');
$feed = $response->collect('posts')->map(function(array $post) {
return ['post' => data_get($post, 'uri')];
})->toArray();
// Sie können auch das Request-Objekt nutzen, um nutzerabhängige Ergebnisse zurückzugeben.
info('user: '.$user); // DID des anfragenden Nutzers. 'did:plc:***'
info('header', $request->header());
return compact('cursor', 'feed');
});
Verwenden Sie für name einen URL-sicheren String.
Der Rückgabewert des Algorithmus ist ein Array mit cursor und feed.
[
'cursor' => '',
'feed' => [
['post' => 'at://'],
['post' => 'at://'],
],
]
Alle vom Paket benötigten Routen werden automatisch registriert.
http://localhost/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:web:example.com/app.bsky.feed.generator/artisan
http://localhost/xrpc/app.bsky.feed.describeFeedGenerator
http://localhost/.well-known/did.json
- Die Service-DID wird automatisch aus der aktuellen URL abgeleitet (z. B.
did:web:example.com).
Sie müssen nur den name und die Implementierung des Feed Generators selbst festlegen.
Feed veröffentlichen (Kommando erstellen)
Nur die Implementierung eines Feed Generators in der Laravel-Anwendung veröffentlicht ihn noch nicht auf Bluesky. Erstellen und führen Sie ein Kommando aus, das publishFeedGenerator aufruft.
Kommando erzeugen
php artisan make:command PublishGeneratorCommand
Kommando implementieren
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Record\Generator;
class PublishGeneratorCommand extends Command
{
protected $signature = 'bluesky:publish-generator';
protected $description = 'Feed Generator auf Bluesky veröffentlichen';
public function handle()
{
$generator = Generator::create(did: 'did:web:example.com', displayName: 'Feed name')
->description('Feed description');
$res = Bluesky::login(identifier: config('bluesky.identifier'), password: config('bluesky.password'))
->publishFeedGenerator(name: 'artisan', generator: $generator);
dump($res->json());
return 0;
}
}
Kommando ausführen
php artisan bluesky:publish-generator
Bei Erfolg wird in der Feed-Liste Ihres Bluesky-Profils ein Link ergänzt. publishFeedGenerator aktualisiert lediglich Informationen, sodass Sie es beliebig oft ausführen können.
Mehrere Feed Generators erstellen
Sie können mehrere Feeds erstellen, indem Sie register mit unterschiedlichen name-Werten mehrfach aufrufen.
// AppServiceProvider::boot()
use Revolution\Bluesky\FeedGenerator\FeedGenerator;
FeedGenerator::register(name: 'feed1', algo: function() {
// Implementierung von feed1
});
FeedGenerator::register(name: 'feed2', algo: function() {
// Implementierung von feed2
});
Rufen Sie im Publish-Kommando entsprechend mehrfach publishFeedGenerator auf.
// PublishGeneratorCommand
Bluesky::login(identifier: config('bluesky.identifier'), password: config('bluesky.password'));
$generator1 = Generator::create(did: 'did:web:example.com', displayName: 'Feed 1')
->description('Feed 1');
Bluesky::publishFeedGenerator(name: 'feed1', generator: $generator1);
$generator2 = Generator::create(did: 'did:web:example.com', displayName: 'Feed 2')
->description('Feed 2');
Bluesky::publishFeedGenerator(name: 'feed2', generator: $generator2);
Algorithmus-Klassen auslagern
Statt einer Closure sorgt eine eigenständige Klasse für aufgeräumten Code. Erstellen Sie eine callable Klasse, die den Contract FeedGeneratorAlgorithm implementiert, und registrieren Sie sie im AppServiceProvider.
// An beliebigem Ort ablegen
namespace App\FeedGenerator;
use Illuminate\Http\Request;
use Revolution\Bluesky\Facades\Bluesky;
use Revolution\Bluesky\Contracts\FeedGeneratorAlgorithm;
class ArtisanFeed implements FeedGeneratorAlgorithm
{
public function __invoke(int $limit, ?string $cursor, ?string $user, Request $request): array
{
// Aufgrund einer temporären API-Einschränkung ist Authentifizierung nötig
$response = Bluesky::login(identifier: config('bluesky.identifier'), password: config('bluesky.password'))
->searchPosts(q: '#laravel', until: $cursor, limit: $limit);
$cursor = data_get($response->collect('posts')->last(), 'indexedAt');
$feed = $response->collect('posts')->map(function (array $post) {
return ['post' => data_get($post, 'uri')];
})->toArray();
info('user: '.$user);
info('header', $request->header());
return compact('cursor', 'feed');
}
}
// AppServiceProvider::boot()
use Revolution\Bluesky\FeedGenerator\FeedGenerator;
use App\FeedGenerator\ArtisanFeed;
FeedGenerator::register(name: 'artisan', algo: ArtisanFeed::class);
Authentifizierung
Die Authentifizierungsfunktion des offiziellen Starter-Kits ist standardmäßig aktiv. Zum Deaktivieren geben Sie an validateAuthUsing eine Closure, die einfach die Nutzer-DID zurückgibt.
// AppServiceProvider::boot()
use Illuminate\Http\Request;
use Revolution\Bluesky\Crypto\JsonWebToken;
use Revolution\Bluesky\FeedGenerator\FeedGenerator;
FeedGenerator::validateAuthUsing(function (?string $jwt, Request $request): ?string {
[, $payload] = JsonWebToken::explode($jwt);
return data_get($payload, 'iss');
});
Der Feed unterliegt den Spracheinstellungen des Accounts. Wenn der Feed Generator zwar Posts abruft, der Feed aber auf Bluesky nicht angezeigt wird, prüfen Sie die Spracheinstellungen Ihres Accounts.
Fortgeschrittene Verwendung
Speichern Sie Posts über ein Artisan-Kommando und Task-Scheduling in einer Datenbank und lassen Sie den Algorithmus lediglich aus der DB lesen – so erreichen Sie ohne API-Aufrufe schnelle Feeds.
// Beispiel: Der Algorithmus gibt einen Feed aus der DB zurück
FeedGenerator::register(name: 'cached-feed', algo: function(int $limit, ?string $cursor): array {
$query = \App\Models\Post::query()
->orderByDesc('indexed_at')
->limit($limit);
if ($cursor) {
$query->where('indexed_at', '<', $cursor);
}
$posts = $query->get();
$cursor = $posts->last()?->indexed_at;
$feed = $posts->map(fn ($post) => ['post' => $post->uri])->toArray();
return compact('cursor', 'feed');
});
// Beispiel: Posts regelmäßig per Scheduler sammeln (routes/console.php)
use Illuminate\Support\Facades\Schedule;
Schedule::command('bluesky:collect-posts')->everyFiveMinutes();
Zuletzt geändert am 13. Juli 2026