feat: add ElevenLabs Firebase token emulation

This commit is contained in:
2026-01-29 01:04:19 -03:00
parent 123ed75b60
commit b246afdc7f
3 changed files with 67 additions and 17 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ services:
DISCORD_TOKEN:
TTS_TIKTOK_SESSIONID:
TTS_ELEVENLABS_KEY:
TTS_ELEVENLABS_TOKEN:
TTS_ELEVENLABS_REFRESHTOKEN:
restart: unless-stopped
volumes:
- ./db.sqlite:/app/db.sqlite
+64 -14
View File
@@ -5,6 +5,10 @@ import * as https from 'https';
const ELEVENLABS_API_ENDPOINT = 'api.elevenlabs.io';
const FIREBASE_API_KEY = "AIzaSyBSsRE_1Os04-bxpd5JTLIniy3UK4OqKys";
const FIREBASE_URL = `https://securetoken.googleapis.com/v1/token?key=${FIREBASE_API_KEY}`;
/*
TO-DO: Implement previous text
*/
@@ -39,6 +43,12 @@ interface ElevenLabsStreamRequest {
voice_settings: ElevenLabsVoiceSettings;
}
interface FirebaseSession {
idToken: string;
refreshToken: string;
expiresAt: number;
}
export class ElevenLabsTTS implements TTSModule {
private voices: Array<ElevenLabsVoice> | undefined = undefined;
private models: Array<ElevenLabsModel> | undefined = undefined;
@@ -48,29 +58,38 @@ export class ElevenLabsTTS implements TTSModule {
public settings: ElevenLabsVoiceSettings;
public modelId: string;
private session: FirebaseSession | undefined = undefined;
private initializationPromise: Promise<void> | undefined = undefined;
public static readonly DEFAULT_SETTINGS: ElevenLabsVoiceSettings = {
stability: 0.5,
stability: 0.0,
similarity_boost: 0.5,
style: 0.0,
style: 1.0,
speed: 1.0,
user_speaker_boost: true
};
constructor() {
if (this.canBeUsed()) {
this.fetchVoices();
this.fetchModels();
}
this.settings = ElevenLabsTTS.DEFAULT_SETTINGS;
this.modelId = 'eleven_flash_v2_5';
if (this.canBeUsed())
this.initializationPromise = this.init();
this.setSettings = this.setSettings.bind(this);
this.setModel = this.setModel.bind(this);
this.getModels = this.getModels.bind(this);
}
private async init(): Promise<void> {
await this.ensureSession();
await Promise.all([
this.fetchVoices(),
this.fetchModels()
]);
}
/*
TTSModule methods
*/
@@ -79,7 +98,11 @@ export class ElevenLabsTTS implements TTSModule {
}
async generate(voice: string, text: string): Promise<TTSResponse> {
if (!this.voices) return {};
await this.initializationPromise;
await this.ensureSession();
if (!this.voices) return { error: 'no voices' };
if (!this.session) return { error: 'no session' };
const voiceData = this.voices.find((entry) => entry.name === voice);
if (!voiceData) return { error: 'Invalid voice' };
@@ -100,10 +123,8 @@ export class ElevenLabsTTS implements TTSModule {
'Sec-Fetch-Site': 'same-site',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Dest': 'empty',
host: 'api.us.elevenlabs.io',
...(config.tts_elevenlabs_token
? { Authorization: `Bearer ${config.tts_elevenlabs_token}` }
: { 'xi-api-key': config.tts_elevenlabs_key })
host: 'api.elevenlabs.io',
Authorization: `Bearer ${this.session.idToken}`
}
};
@@ -132,7 +153,7 @@ export class ElevenLabsTTS implements TTSModule {
}
canBeUsed(): boolean {
return config.tts_elevenlabs_key != undefined;
return config.tts_elevenlabs_refreshtoken != undefined && config.tts_elevenlabs_key != undefined;
}
/*
@@ -221,6 +242,35 @@ export class ElevenLabsTTS implements TTSModule {
});
});
}
private async ensureSession(): Promise<void> {
if (this.session && Date.now() < this.session.expiresAt - 300000)
return;
const refreshToken = this.session?.refreshToken || config.tts_elevenlabs_refreshtoken;
if (!refreshToken) throw new Error("No refresh token available");
const response = await fetch(FIREBASE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Referer': 'https://elevenlabs.io/',
'Origin': 'https://elevenlabs.io'
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
}),
});
if (!response.ok) throw new Error(`Auth Refresh Failed: ${await response.text()}`);
const data = await response.json();
this.session = {
idToken: data.id_token,
refreshToken: data.refresh_token,
expiresAt: Date.now() + (parseInt(data.expires_in) * 1000)
};
}
}
export default new ElevenLabsTTS();
+2 -2
View File
@@ -7,7 +7,7 @@ export interface Config {
tts_default_voice: string | undefined;
tts_elevenlabs_key: string | undefined;
tts_elevenlabs_token: string | undefined;
tts_elevenlabs_refreshtoken: string | undefined;
tts_tiktok_sessionid: string | undefined;
steam_webapi_key: string | undefined;
@@ -31,7 +31,7 @@ function loadConfig(): Config {
tts_default_mode: process.env.DEFAULT_TTS_MODE,
tts_default_voice: process.env.DEFAULT_TTS_VOICE,
tts_elevenlabs_key: process.env.TTS_ELEVENLABS_KEY,
tts_elevenlabs_token: process.env.TTS_ELEVENLABS_TOKEN,
tts_elevenlabs_refreshtoken: process.env.TTS_ELEVENLABS_REFRESHTOKEN,
steam_webapi_key: process.env.STEAM_WEBAPI_KEY,
aws_access_id: process.env.AWS_ACCESS_ID,
aws_access_key: process.env.AWS_ACCESS_KEY,