style: run format:apply
This commit is contained in:
+4
-1
@@ -255,7 +255,10 @@ export class CommandManager {
|
|||||||
|
|
||||||
if (command.requiresAdmin) {
|
if (command.requiresAdmin) {
|
||||||
const member = interaction.member as GuildMember;
|
const member = interaction.member as GuildMember;
|
||||||
if (!member.permissions.has(PermissionFlagsBits.Administrator) && member.id != config.owner_id) {
|
if (
|
||||||
|
!member.permissions.has(PermissionFlagsBits.Administrator) &&
|
||||||
|
member.id != config.owner_id
|
||||||
|
) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content:
|
content:
|
||||||
"You don't have the permissions required to execute this command.",
|
"You don't have the permissions required to execute this command.",
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ export class MixedStream {
|
|||||||
});
|
});
|
||||||
|
|
||||||
transcoder.on('end', () => {
|
transcoder.on('end', () => {
|
||||||
const durationMs = (totalBytes / 192000) * 1000 * (1 + DURATION_MARGIN_PCT);
|
const durationMs =
|
||||||
|
(totalBytes / 192000) * 1000 * (1 + DURATION_MARGIN_PCT);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
source.unpipe(transcoder);
|
source.unpipe(transcoder);
|
||||||
@@ -153,7 +154,6 @@ export class MixedStream {
|
|||||||
});
|
});
|
||||||
|
|
||||||
source.pipe(transcoder).pipe(mixerInput);
|
source.pipe(transcoder).pipe(mixerInput);
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,118 +1,118 @@
|
|||||||
import { config } from "../../utils/config";
|
import { config } from '../../utils/config';
|
||||||
import { TTSModule, TTSResponse } from "../tts"
|
import { TTSModule, TTSResponse } from '../tts';
|
||||||
|
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import * as zlib from 'zlib';
|
import * as zlib from 'zlib';
|
||||||
|
|
||||||
import TIKTOK_TTS_VOICES from './tiktok_voices.json';
|
import TIKTOK_TTS_VOICES from './tiktok_voices.json';
|
||||||
const TIKTOK_TTS_ENDPOINT = 'https://api16-normal-v6.tiktokv.com/media/api/text/speech/invoke'
|
const TIKTOK_TTS_ENDPOINT =
|
||||||
|
'https://api16-normal-v6.tiktokv.com/media/api/text/speech/invoke';
|
||||||
|
|
||||||
class TikTokTTS implements TTSModule {
|
class TikTokTTS implements TTSModule {
|
||||||
public name: string = 'TikTok';
|
public name: string = 'TikTok';
|
||||||
public defaultVoice: string = 'en_us_001';
|
public defaultVoice: string = 'en_us_001';
|
||||||
|
|
||||||
async getVoices(): Promise<Array<string> | undefined> {
|
async getVoices(): Promise<Array<string> | undefined> {
|
||||||
return TIKTOK_TTS_VOICES.voices;
|
return TIKTOK_TTS_VOICES.voices;
|
||||||
}
|
}
|
||||||
|
|
||||||
async generate(voice: string, text: string): Promise<TTSResponse> {
|
async generate(voice: string, text: string): Promise<TTSResponse> {
|
||||||
const reqText = encodeURIComponent(text);
|
const reqText = encodeURIComponent(text);
|
||||||
const path = `/?text_speaker=${voice}&req_text=${reqText}&speaker_map_type=0&aid=1233`;
|
const path = `/?text_speaker=${voice}&req_text=${reqText}&speaker_map_type=0&aid=1233`;
|
||||||
|
|
||||||
const endpoint = new URL(TIKTOK_TTS_ENDPOINT);
|
const endpoint = new URL(TIKTOK_TTS_ENDPOINT);
|
||||||
|
|
||||||
const options: https.RequestOptions = {
|
const options: https.RequestOptions = {
|
||||||
hostname: endpoint.hostname,
|
hostname: endpoint.hostname,
|
||||||
path: endpoint.pathname + path,
|
path: endpoint.pathname + path,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'User-Agent': 'com.zhiliaoapp.musically/2022600030 (Linux; U; Android 7.1.2; es_ES; SM-G988N; Build/NRD90M;tt-ok/3.12.13.1)',
|
'User-Agent':
|
||||||
'Cookie': `sessionid=${config.tiktok_session_id}`,
|
'com.zhiliaoapp.musically/2022600030 (Linux; U; Android 7.1.2; es_ES; SM-G988N; Build/NRD90M;tt-ok/3.12.13.1)',
|
||||||
'Accept-Encoding': 'gzip,deflate,compress',
|
Cookie: `sessionid=${config.tiktok_session_id}`,
|
||||||
'Content-Type': 'application/x-www-form-urlencoded'
|
'Accept-Encoding': 'gzip,deflate,compress',
|
||||||
}
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const req = https.request(options, (res) => {
|
const req = https.request(options, (res) => {
|
||||||
const chunks: Buffer[] = [];
|
const chunks: Buffer[] = [];
|
||||||
|
|
||||||
const encoding = res.headers['content-encoding'];
|
const encoding = res.headers['content-encoding'];
|
||||||
|
|
||||||
res.on('data', (chunk) => chunks.push(chunk));
|
res.on('data', (chunk) => chunks.push(chunk));
|
||||||
res.on('end', () => {
|
res.on('end', () => {
|
||||||
try {
|
try {
|
||||||
const buffer = Buffer.concat(chunks);
|
const buffer = Buffer.concat(chunks);
|
||||||
|
|
||||||
// Handle decompression if needed
|
const decompressBuffer = (buf: Buffer): Promise<Buffer> => {
|
||||||
const decompressBuffer = (buf: Buffer): Promise<Buffer> => {
|
return new Promise((decompressResolve, decompressReject) => {
|
||||||
return new Promise((decompressResolve, decompressReject) => {
|
if (encoding === 'gzip' || encoding === 'deflate') {
|
||||||
if (encoding === 'gzip' || encoding === 'deflate') {
|
zlib.unzip(buf, (err: Error | null, decompressed: Buffer) => {
|
||||||
zlib.unzip(buf, (err: any, decompressed: Buffer<ArrayBufferLike> | PromiseLike<Buffer<ArrayBufferLike>>) => {
|
if (err) decompressReject(err);
|
||||||
if (err) decompressReject(err);
|
else decompressResolve(decompressed);
|
||||||
else decompressResolve(decompressed);
|
});
|
||||||
});
|
} else {
|
||||||
} else {
|
decompressResolve(buf);
|
||||||
decompressResolve(buf);
|
}
|
||||||
}
|
});
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
decompressBuffer(buffer)
|
decompressBuffer(buffer)
|
||||||
.then((decompressed) => {
|
.then((decompressed) => {
|
||||||
const result = JSON.parse(decompressed.toString());
|
const result = JSON.parse(decompressed.toString());
|
||||||
const statusCode = result?.status_code;
|
const statusCode = result?.status_code;
|
||||||
|
|
||||||
if (statusCode !== 0) {
|
if (statusCode !== 0) {
|
||||||
const errorMsg = this.handleStatusError(statusCode);
|
const errorMsg = this.handleStatusError(statusCode);
|
||||||
return resolve({ error: errorMsg });
|
return resolve({ error: errorMsg });
|
||||||
}
|
}
|
||||||
|
|
||||||
const voiceStr = result?.data?.v_str;
|
const voiceStr = result?.data?.v_str;
|
||||||
if (!voiceStr) {
|
if (!voiceStr) {
|
||||||
return resolve({ error: 'No audio data received' });
|
return resolve({ error: 'No audio data received' });
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve({ data: Buffer.from(voiceStr, 'base64') });
|
resolve({ data: Buffer.from(voiceStr, 'base64') });
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
resolve({ error: `Decompression/Parse error: ${err.message}` });
|
resolve({ error: `Decompression/Parse error: ${err.message}` });
|
||||||
});
|
});
|
||||||
|
} catch (err) {
|
||||||
|
resolve({ error: `Parse error: ${err}` });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
} catch (err) {
|
req.on('error', (err) => resolve({ error: err.message }));
|
||||||
resolve({ error: `Parse error: ${err}` });
|
req.on('timeout', () => {
|
||||||
}
|
req.destroy();
|
||||||
});
|
resolve({ error: 'timed out' });
|
||||||
});
|
});
|
||||||
|
|
||||||
req.on('error', (err) => resolve({ error: err.message }));
|
req.write('');
|
||||||
req.on('timeout', () => {
|
req.end();
|
||||||
req.destroy();
|
});
|
||||||
resolve({ error: 'timed out' });
|
}
|
||||||
});
|
|
||||||
|
|
||||||
req.write('');
|
canBeUsed(): boolean {
|
||||||
req.end();
|
return config.tiktok_session_id != undefined;
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
canBeUsed(): boolean {
|
handleStatusError(code: number): string {
|
||||||
return config.tiktok_session_id != undefined;
|
switch (code) {
|
||||||
}
|
case 1:
|
||||||
|
return 'Session ID may be invalid or expired';
|
||||||
handleStatusError(code: number): string {
|
case 2:
|
||||||
switch (code) {
|
return 'Text is too long';
|
||||||
case 1:
|
case 4:
|
||||||
return "Session ID may be invalid or expired";
|
return 'Invalid voice';
|
||||||
case 2:
|
case 5:
|
||||||
return "Text is too long";
|
return 'No session id.';
|
||||||
case 4:
|
}
|
||||||
return "Invalid voice";
|
return `Unknown error code: ${code}`;
|
||||||
case 5:
|
}
|
||||||
return "No session id.";
|
|
||||||
}
|
|
||||||
return `Unknown error code: ${code}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new TikTokTTS();
|
export default new TikTokTTS();
|
||||||
@@ -1,99 +1,99 @@
|
|||||||
{
|
{
|
||||||
"voices": [
|
"voices": [
|
||||||
"en_us_ghostface",
|
"en_us_ghostface",
|
||||||
"en_us_chewbacca",
|
"en_us_chewbacca",
|
||||||
"en_us_c3po",
|
"en_us_c3po",
|
||||||
"en_us_stitch",
|
"en_us_stitch",
|
||||||
"en_us_stormtrooper",
|
"en_us_stormtrooper",
|
||||||
"en_us_rocket",
|
"en_us_rocket",
|
||||||
"en_female_madam_leota",
|
"en_female_madam_leota",
|
||||||
"en_male_ghosthost",
|
"en_male_ghosthost",
|
||||||
"en_male_pirate",
|
"en_male_pirate",
|
||||||
"en_au_001",
|
"en_au_001",
|
||||||
"en_au_002",
|
"en_au_002",
|
||||||
"en_uk_001",
|
"en_uk_001",
|
||||||
"en_uk_003",
|
"en_uk_003",
|
||||||
"en_us_001",
|
"en_us_001",
|
||||||
"en_us_002",
|
"en_us_002",
|
||||||
"en_us_006",
|
"en_us_006",
|
||||||
"en_us_007",
|
"en_us_007",
|
||||||
"en_us_009",
|
"en_us_009",
|
||||||
"en_us_010",
|
"en_us_010",
|
||||||
"en_male_jomboy",
|
"en_male_jomboy",
|
||||||
"en_male_cody",
|
"en_male_cody",
|
||||||
"en_female_samc",
|
"en_female_samc",
|
||||||
"en_female_makeup",
|
"en_female_makeup",
|
||||||
"en_female_richgirl",
|
"en_female_richgirl",
|
||||||
"en_male_grinch",
|
"en_male_grinch",
|
||||||
"en_male_deadpool",
|
"en_male_deadpool",
|
||||||
"en_male_jarvis",
|
"en_male_jarvis",
|
||||||
"en_male_ashmagic",
|
"en_male_ashmagic",
|
||||||
"en_male_olantekkers",
|
"en_male_olantekkers",
|
||||||
"en_male_ukneighbor",
|
"en_male_ukneighbor",
|
||||||
"en_male_ukbutler",
|
"en_male_ukbutler",
|
||||||
"en_female_shenna",
|
"en_female_shenna",
|
||||||
"en_female_pansino",
|
"en_female_pansino",
|
||||||
"en_male_trevor",
|
"en_male_trevor",
|
||||||
"en_female_betty",
|
"en_female_betty",
|
||||||
"en_male_cupid",
|
"en_male_cupid",
|
||||||
"en_female_grandma",
|
"en_female_grandma",
|
||||||
"en_male_m2_xhxs_m03_christmas",
|
"en_male_m2_xhxs_m03_christmas",
|
||||||
"en_male_santa_narration",
|
"en_male_santa_narration",
|
||||||
"en_male_sing_deep_jingle",
|
"en_male_sing_deep_jingle",
|
||||||
"en_male_santa_effect",
|
"en_male_santa_effect",
|
||||||
"en_female_ht_f08_newyear",
|
"en_female_ht_f08_newyear",
|
||||||
"en_male_wizard",
|
"en_male_wizard",
|
||||||
"en_female_ht_f08_halloween",
|
"en_female_ht_f08_halloween",
|
||||||
"fr_001",
|
"fr_001",
|
||||||
"fr_002",
|
"fr_002",
|
||||||
"de_001",
|
"de_001",
|
||||||
"de_002",
|
"de_002",
|
||||||
"es_002",
|
"es_002",
|
||||||
"es_mx_002",
|
"es_mx_002",
|
||||||
"br_001",
|
"br_001",
|
||||||
"br_003",
|
"br_003",
|
||||||
"br_004",
|
"br_004",
|
||||||
"br_005",
|
"br_005",
|
||||||
"bp_female_ivete",
|
"bp_female_ivete",
|
||||||
"bp_female_ludmilla",
|
"bp_female_ludmilla",
|
||||||
"pt_female_lhays",
|
"pt_female_lhays",
|
||||||
"pt_female_laizza",
|
"pt_female_laizza",
|
||||||
"pt_male_bueno",
|
"pt_male_bueno",
|
||||||
"id_001",
|
"id_001",
|
||||||
"jp_001",
|
"jp_001",
|
||||||
"jp_003",
|
"jp_003",
|
||||||
"jp_005",
|
"jp_005",
|
||||||
"jp_006",
|
"jp_006",
|
||||||
"kr_002",
|
"kr_002",
|
||||||
"kr_003",
|
"kr_003",
|
||||||
"kr_004",
|
"kr_004",
|
||||||
"jp_female_fujicochan",
|
"jp_female_fujicochan",
|
||||||
"jp_female_hasegawariona",
|
"jp_female_hasegawariona",
|
||||||
"jp_male_keiichinakano",
|
"jp_male_keiichinakano",
|
||||||
"jp_female_oomaeaika",
|
"jp_female_oomaeaika",
|
||||||
"jp_male_yujinchigusa",
|
"jp_male_yujinchigusa",
|
||||||
"jp_female_shirou",
|
"jp_female_shirou",
|
||||||
"jp_male_tamawakazuki",
|
"jp_male_tamawakazuki",
|
||||||
"jp_female_kaorishoji",
|
"jp_female_kaorishoji",
|
||||||
"jp_female_yagishaki",
|
"jp_female_yagishaki",
|
||||||
"jp_male_hikakin",
|
"jp_male_hikakin",
|
||||||
"jp_female_rei",
|
"jp_female_rei",
|
||||||
"jp_male_shuichiro",
|
"jp_male_shuichiro",
|
||||||
"jp_male_matsudake",
|
"jp_male_matsudake",
|
||||||
"jp_female_machikoriiita",
|
"jp_female_machikoriiita",
|
||||||
"jp_male_matsuo",
|
"jp_male_matsuo",
|
||||||
"jp_male_osada",
|
"jp_male_osada",
|
||||||
"en_female_f08_salut_damour",
|
"en_female_f08_salut_damour",
|
||||||
"en_male_m03_lobby",
|
"en_male_m03_lobby",
|
||||||
"en_female_f08_warmy_breeze",
|
"en_female_f08_warmy_breeze",
|
||||||
"en_male_m03_sunshine_soon",
|
"en_male_m03_sunshine_soon",
|
||||||
"en_female_ht_f08_glorious",
|
"en_female_ht_f08_glorious",
|
||||||
"en_male_sing_funny_it_goes_up",
|
"en_male_sing_funny_it_goes_up",
|
||||||
"en_male_m2_xhxs_m03_silly",
|
"en_male_m2_xhxs_m03_silly",
|
||||||
"en_female_ht_f08_wonderful_world",
|
"en_female_ht_f08_wonderful_world",
|
||||||
"en_male_sing_funny_thanksgiving",
|
"en_male_sing_funny_thanksgiving",
|
||||||
"en_male_narration",
|
"en_male_narration",
|
||||||
"en_male_funny",
|
"en_male_funny",
|
||||||
"en_female_emotional"
|
"en_female_emotional"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user