splatoon3.ink/app/social/clients/TwitterClient.mjs
Matt Isenhower 94aa3d7ece Replace # private class members with _ prefix convention for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 16:01:09 -08:00

60 lines
1.5 KiB
JavaScript

import { TwitterApi } from 'twitter-api-v2';
import Client from './Client.mjs';
export default class TwitterClient extends Client
{
key = 'twitter';
name = 'Twitter';
/** @member {TwitterApi} */
_api;
async canSend() {
return process.env.TWITTER_CONSUMER_KEY
&& process.env.TWITTER_CONSUMER_SECRET
&& process.env.TWITTER_ACCESS_TOKEN_KEY
&& process.env.TWITTER_ACCESS_TOKEN_SECRET;
}
api() {
if (!this._api) {
this._api = new TwitterApi({
appKey: process.env.TWITTER_CONSUMER_KEY,
appSecret: process.env.TWITTER_CONSUMER_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN_KEY,
accessSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});
}
return this._api;
}
async send(status, generator) {
if (!status.media?.length) {
console.error(`[${this.name}] No media provided for ${generator.key}`);
return;
}
try {
// Upload images
let mediaIds = await Promise.all(
status.media.map(async m => {
let id = await this.api().v1.uploadMedia(Buffer.from(m.file), { mimeType: m.type });
if (m.altText) {
await this.api().v1.createMediaMetadata(id, { alt_text: { text: m.altText } });
}
return id;
}),
);
// Send status
await this.api().v2.tweet(status.status, { media: { media_ids: mediaIds } });
} catch (error) {
console.error(`[${this.name}] Failed to post ${generator.key}:`, error.message);
throw error;
}
}
}