| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- require('dotenv').config();
- const { BskyAgent, RichText } = require('@atproto/api');
- const BasePlatformService = require('./utils/BasePlatformService');
- const { getDb } = require('./utils/MongoDBConnector');
- const BLUESKY_IDENTIFIER = process.env.BLUESKY_IDENTIFIER || '';
- const BLUESKY_APP_PASSWORD = process.env.BLUESKY_APP_PASSWORD || '';
- const BLUESKY_SERVICE = process.env.BLUESKY_SERVICE || 'https://bsky.social';
- class BlueskyService extends BasePlatformService {
- constructor() {
- super('bluesky');
- this.agent = new BskyAgent({ service: BLUESKY_SERVICE });
- this.loggedIn = false;
- }
- async _ensureLoggedIn() {
- if (this.loggedIn) return;
- if (!BLUESKY_IDENTIFIER || !BLUESKY_APP_PASSWORD) {
- throw new Error('Bluesky credentials not configured');
- }
- await this.agent.login({
- identifier: BLUESKY_IDENTIFIER,
- password: BLUESKY_APP_PASSWORD,
- });
- this.loggedIn = true;
- }
- async getStatus() {
- if (!BLUESKY_IDENTIFIER || !BLUESKY_APP_PASSWORD) {
- return { connected: false, platform: 'bluesky', error: 'Credentials not configured' };
- }
- try {
- await this._ensureLoggedIn();
- const profile = await this.agent.getProfile({ actor: BLUESKY_IDENTIFIER });
- return {
- connected: true,
- platform: 'bluesky',
- username: profile.data.handle,
- displayName: profile.data.displayName,
- avatar: profile.data.avatar,
- };
- } catch (err) {
- this.loggedIn = false;
- return { connected: false, platform: 'bluesky', error: err.message };
- }
- }
- async fetchFeed({ limit = 50 } = {}) {
- await this._ensureLoggedIn();
- const response = await this.agent.getTimeline({ limit: Number(limit) });
- const items = response.data.feed
- .filter((entry) => entry.post)
- .map((entry) => {
- const post = entry.post;
- const author = post.author;
- const record = post.record;
- return this.normalizeFeedItem({
- originalId: post.uri,
- author: {
- name: author.displayName || author.handle,
- username: author.handle,
- avatar: author.avatar,
- profileUrl: `https://bsky.app/profile/${author.handle}`,
- },
- content: record.text || '',
- media: _extractMedia(post.embed),
- platformTags: _extractTags(record.facets),
- metrics: {
- likes: post.likeCount || 0,
- shares: post.repostCount || 0,
- comments: post.replyCount || 0,
- },
- url: `https://bsky.app/profile/${author.handle}/post/${post.uri.split('/').pop()}`,
- createdAt: record.createdAt,
- });
- });
- // MongoDB'ye kaydet (upsert)
- try {
- const db = await getDb();
- const col = db.collection('feeds');
- for (const item of items) {
- await col.updateOne(
- { platform: 'bluesky', originalId: item.originalId },
- { $set: item },
- { upsert: true }
- );
- }
- } catch (err) {
- console.error('[Bluesky] MongoDB write error:', err.message);
- }
- return items;
- }
- async publishPost({ content, media = [] } = {}) {
- await this._ensureLoggedIn();
- const rt = new RichText({ text: content });
- await rt.detectFacets(this.agent);
- const postData = { text: rt.text, facets: rt.facets };
- if (media.length > 0) {
- postData.embed = { $type: 'app.bsky.embed.images', images: media };
- }
- const result = await this.agent.post(postData);
- return { uri: result.uri, cid: result.cid };
- }
- }
- function _extractMedia(embed) {
- if (!embed) return [];
- if (embed.$type === 'app.bsky.embed.images#view') {
- return (embed.images || []).map((img) => ({
- url: img.fullsize || img.thumb,
- type: 'image',
- thumbnail: img.thumb,
- alt: img.alt,
- }));
- }
- return [];
- }
- function _extractTags(facets = []) {
- if (!facets) return [];
- return facets
- .filter((f) => f.features?.some((feat) => feat.$type === 'app.bsky.richtext.facet#tag'))
- .flatMap((f) => f.features.filter((feat) => feat.$type === 'app.bsky.richtext.facet#tag').map((feat) => feat.tag));
- }
- const service = new BlueskyService();
- service.start(process.env.PORT || 3004);
|