131 lines
4.8 KiB
TypeScript
131 lines
4.8 KiB
TypeScript
import {Inject, Injectable} from "@nestjs/common";
|
|
import {TwitterApi} from 'twitter-api-v2';
|
|
import {TwitterApiAutoTokenRefresher} from '@twitter-api-v2/plugin-token-refresher'
|
|
|
|
import {EUploadMimeType} from "twitter-api-v2/dist/esm/types";
|
|
import {MediaV2MediaCategory} from "twitter-api-v2/dist/esm/types/v2/media.v2.types";
|
|
import {XCacheService} from "../x-cache/x-cache.service";
|
|
|
|
@Injectable()
|
|
export class XApiService {
|
|
private clientId = process.env.TWITTER_CLIENT_ID + '';
|
|
private clientSecret = process.env.TWITTER_CLIENT_SECRET;
|
|
|
|
private readonly userClient: any;
|
|
|
|
constructor(
|
|
@Inject() private cacheService: XCacheService,
|
|
) {
|
|
}
|
|
|
|
async getTwitterClientV2() {
|
|
return new TwitterApi(
|
|
{
|
|
clientId: this.clientId,
|
|
clientSecret: this.clientSecret,
|
|
},
|
|
)
|
|
}
|
|
|
|
async getTwitterClientV2ViaAccessToken() {
|
|
const accessToken = await this.getCacheAccessToken() as string;
|
|
const refreshToken = await this.getCacheRefreshToken() as string;
|
|
// console.log({refreshToken});
|
|
|
|
// @ts-ignore
|
|
// @ts-ignore
|
|
return new TwitterApi(accessToken,
|
|
{
|
|
plugins: [
|
|
new TwitterApiAutoTokenRefresher({
|
|
refreshCredentials: {
|
|
clientId: '' + this.clientId,
|
|
clientSecret: this.clientSecret,
|
|
},
|
|
refreshToken,
|
|
// Hàm này được gọi tự động khi token được refresh thành công
|
|
onTokenUpdate: async (newTokens) => {
|
|
console.log('===> Token đã được làm mới:', newTokens);
|
|
await this.setCacheRefreshToken('' + newTokens.refreshToken);
|
|
await this.setCacheAccessToken(newTokens.accessToken);
|
|
},
|
|
// Hàm xử lý khi refresh thất bại (ví dụ: refresh token cũng hết hạn)
|
|
onTokenRefreshError: async (error) => {
|
|
console.error('Không thể refresh token:', error);
|
|
throw error;
|
|
},
|
|
}),
|
|
],
|
|
});
|
|
}
|
|
|
|
async uploadImageV1(media: Buffer, options: {
|
|
media_type: `${EUploadMimeType}` | EUploadMimeType;
|
|
media_category?: MediaV2MediaCategory;
|
|
additional_owners?: string[];
|
|
}, chunkSize?: number): Promise<string> {
|
|
const client = await this.getTwitterClientV2ViaAccessToken();
|
|
// return client.v2.uploadMedia(media, options, chunkSize);
|
|
return client.v2.uploadMedia(media, options, chunkSize);
|
|
}
|
|
|
|
async postSimpleTweet(content) {
|
|
const client = await this.getTwitterClientV2ViaAccessToken();
|
|
return client.v2.tweet(content)
|
|
}
|
|
|
|
async postReply(content: string, tweetId: string) {
|
|
const client = await this.getTwitterClientV2ViaAccessToken();
|
|
return client.v2.reply(content, tweetId)
|
|
}
|
|
|
|
async qoute(content: string, tweetId: string) {
|
|
const client = await this.getTwitterClientV2ViaAccessToken();
|
|
|
|
// @ts-ignore
|
|
if (content.indexOf(`https://x.com/${process.env.TWITTER_USERNAME}/status`) === -1) {
|
|
//hacking, use tweet instead of quote, because limit x
|
|
return client.v2.tweet(content)
|
|
}
|
|
return client.v2.quote(content, tweetId)
|
|
}
|
|
|
|
async setCacheAccessToken(accessToken: string) {
|
|
return this.cacheService.setCachedKey('tw_accesstoken', '' + accessToken, 24 * 3600);
|
|
}
|
|
|
|
async delCacheAccessToken() {
|
|
return this.cacheService.delCachedKey('tw_accesstoken');
|
|
}
|
|
|
|
async getCacheAccessToken() {
|
|
return this.cacheService.getCachedData('tw_accesstoken')
|
|
}
|
|
|
|
async getCacheRefreshToken() {
|
|
return this.cacheService.getCachedData('tw_refreshtoken')
|
|
}
|
|
|
|
async setCacheRefreshToken(refreshToken: string) {
|
|
//30day
|
|
return this.cacheService.setCachedKey('tw_refreshtoken', refreshToken, 30 * 24 * 3600);
|
|
}
|
|
|
|
async refreshAccessToken() {
|
|
const client = new TwitterApi({clientId: this.clientId, clientSecret: this.clientSecret});
|
|
const refreshToken = await this.getCacheRefreshToken();
|
|
|
|
const {
|
|
client: refreshedClient,
|
|
accessToken,
|
|
refreshToken: newRefreshToken
|
|
} = await client.refreshOAuth2Token('' + refreshToken);
|
|
|
|
await this.cacheService.setCachedKey('tw_accesstoken_time_add', Date.now(), 3 * 24 * 3600);
|
|
await this.setCacheAccessToken(accessToken);
|
|
await this.setCacheRefreshToken('' + refreshToken);
|
|
// Example request
|
|
await refreshedClient.v2.me();
|
|
}
|
|
}
|