eliobros-dl-api
Version:
Cliente JavaScript/TypeScript para a API de download multi-plataforma (YouTube, TikTok, Instagram, Facebook)
365 lines (318 loc) • 9.71 kB
JavaScript
// src/client.js - Cliente principal da biblioteca eliobros-download-api
const axios = require('axios');
const { PLATFORMS, FORMATS, ERRORS } = require('./types');
const { validateUrl, detectPlatform, formatFileSize } = require('./utils');
/**
* Cliente para a Eliobros Download API
*/
class EliobrosDownloadClient {
/**
* @param {string} baseURL - URL base da API (padrão: http://localhost:3000)
* @param {Object} options - Opções adicionais
*/
constructor(baseURL = 'http://93.127.129.84:3000', options = {}) {
this.baseURL = baseURL;
this.token = null;
this.apiKey = null;
this.options = {
timeout: 180000, // 3 minutos
retries: 3,
retryDelay: 1000,
...options
};
// Configurar axios
this.api = axios.create({
baseURL: this.baseURL,
timeout: this.options.timeout,
headers: {
'Content-Type': 'application/json',
'User-Agent': 'eliobros-download-api/1.0.0'
}
});
// Interceptors
this._setupInterceptors();
}
/**
* Configurar interceptors do axios
* @private
*/
_setupInterceptors() {
// Request interceptor
this.api.interceptors.request.use((config) => {
// Adicionar token JWT para rotas de gerenciamento
if (this.token && (
config.url.startsWith('/api/keys') ||
config.url.startsWith('/auth/')
)) {
config.headers.Authorization = `Bearer ${this.token}`;
}
// Adicionar API Key para rotas de download
if (this.apiKey && (
config.url.startsWith('/api/download') ||
config.url === '/api/stats'
)) {
config.headers['X-API-Key'] = this.apiKey;
}
return config;
});
// Response interceptor para retry automático
this.api.interceptors.response.use(
(response) => response,
async (error) => {
const config = error.config;
if (!config || config.__isRetryRequest) {
return Promise.reject(error);
}
config.__retryCount = config.__retryCount || 0;
if (config.__retryCount >= this.options.retries) {
return Promise.reject(error);
}
config.__retryCount++;
config.__isRetryRequest = true;
// Aguardar antes de tentar novamente
await new Promise(resolve =>
setTimeout(resolve, this.options.retryDelay * config.__retryCount)
);
return this.api(config);
}
);
}
// ========== AUTENTICAÇÃO ==========
/**
* Registrar novo usuário
* @param {string} username - Nome de usuário
* @param {string} email - Email do usuário
* @param {string} password - Senha
* @returns {Promise<Object>} Resultado do registro
*/
async register(username, email, password) {
try {
const response = await this.api.post('/auth/register', {
username,
email,
password
});
return { success: true, ...response.data };
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro no registro');
}
}
/**
* Fazer login na API
* @param {string} username - Nome de usuário
* @param {string} password - Senha
* @returns {Promise<Object>} Dados do login (token, userId)
*/
async login(username, password) {
try {
const response = await this.api.post('/auth/login', {
username,
password
});
this.token = response.data.token;
return { success: true, ...response.data };
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro no login');
}
}
/**
* Fazer logout (limpa o token)
*/
logout() {
this.token = null;
this.apiKey = null;
}
// ========== GERENCIAMENTO DE API KEYS ==========
/**
* Gerar nova API Key
* @param {string} keyName - Nome para identificar a chave
* @returns {Promise<Object>} Dados da API Key gerada
*/
async generateApiKey(keyName) {
if (!this.token) {
throw new Error(ERRORS.AUTH_REQUIRED);
}
try {
const response = await this.api.post('/api/keys/generate', { keyName });
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro ao gerar API Key');
}
}
/**
* Listar API Keys do usuário
* @returns {Promise<Array>} Lista de API Keys
*/
async listApiKeys() {
if (!this.token) {
throw new Error(ERRORS.AUTH_REQUIRED);
}
try {
const response = await this.api.get('/api/keys');
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro ao listar API Keys');
}
}
/**
* Desativar uma API Key
* @param {string} keyId - ID da API Key
* @returns {Promise<Object>} Resultado da operação
*/
async deactivateApiKey(keyId) {
if (!this.token) {
throw new Error(ERRORS.AUTH_REQUIRED);
}
try {
const response = await this.api.put(`/api/keys/${keyId}/deactivate`);
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro ao desativar API Key');
}
}
/**
* Definir API Key para downloads
* @param {string} apiKey - Chave da API
*/
setApiKey(apiKey) {
if (!apiKey || typeof apiKey !== 'string') {
throw new Error(ERRORS.INVALID_API_KEY);
}
this.apiKey = apiKey;
}
// ========== DOWNLOADS ==========
/**
* Download genérico - detecta plataforma automaticamente
* @param {string} url - URL do conteúdo
* @param {string} format - Formato de download (mp4, mp3, m4a, wav)
* @returns {Promise<Object>} Resultado do download
*/
async download(url, format = FORMATS.MP4) {
if (!this.apiKey) {
throw new Error(ERRORS.API_KEY_REQUIRED);
}
// Validar URL
if (!validateUrl(url)) {
throw new Error(ERRORS.INVALID_URL);
}
// Validar formato
if (!Object.values(FORMATS).includes(format)) {
throw new Error(ERRORS.INVALID_FORMAT);
}
// Detectar plataforma
const platform = detectPlatform(url);
if (!platform) {
throw new Error(ERRORS.UNSUPPORTED_PLATFORM);
}
try {
const response = await this.api.post(`/api/download/${platform}`, {
url,
type: format
});
const result = response.data;
// Adicionar informações úteis ao resultado
if (result.success && result.file_size) {
result.formatted_size = formatFileSize(result.file_size);
}
return result;
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro no download');
}
}
/**
* Download específico do YouTube
* @param {string} url - URL do YouTube
* @param {string} format - Formato de download
* @returns {Promise<Object>} Resultado do download
*/
async downloadYoutube(url, format = FORMATS.MP4) {
if (!url.includes('youtube.com') && !url.includes('youtu.be')) {
throw new Error('URL deve ser do YouTube');
}
return this.download(url, format);
}
/**
* Download específico do TikTok
* @param {string} url - URL do TikTok
* @param {string} format - Formato de download
* @returns {Promise<Object>} Resultado do download
*/
async downloadTikTok(url, format = FORMATS.MP4) {
if (!url.includes('tiktok.com')) {
throw new Error('URL deve ser do TikTok');
}
return this.download(url, format);
}
/**
* Download específico do Instagram
* @param {string} url - URL do Instagram
* @param {string} format - Formato de download
* @returns {Promise<Object>} Resultado do download
*/
async downloadInstagram(url, format = FORMATS.MP4) {
if (!url.includes('instagram.com')) {
throw new Error('URL deve ser do Instagram');
}
return this.download(url, format);
}
/**
* Download específico do Facebook
* @param {string} url - URL do Facebook
* @param {string} format - Formato de download
* @returns {Promise<Object>} Resultado do download
*/
async downloadFacebook(url, format = FORMATS.MP4) {
if (!url.includes('facebook.com')) {
throw new Error('URL deve ser do Facebook');
}
return this.download(url, format);
}
// ========== ESTATÍSTICAS ==========
/**
* Obter estatísticas da API Key atual
* @returns {Promise<Object>} Estatísticas de uso
*/
async getStats() {
if (!this.apiKey) {
throw new Error(ERRORS.API_KEY_REQUIRED);
}
try {
const response = await this.api.get('/api/stats');
return response.data;
} catch (error) {
throw new Error(error.response?.data?.error || 'Erro ao obter estatísticas');
}
}
// ========== UTILITÁRIOS ==========
/**
* Testar conexão com a API
* @returns {Promise<boolean>} Status da conexão
*/
async ping() {
try {
const response = await axios.get(`${this.baseURL}/api/stats`, {
timeout: 5000,
headers: { 'X-API-Key': this.apiKey || 'test' }
});
return response.status === 200 || response.status === 401; // 401 é esperado sem API key
} catch (error) {
return false;
}
}
/**
* Obter informações sobre a API
* @returns {Object} Informações da configuração atual
*/
getInfo() {
return {
baseURL: this.baseURL,
hasToken: !!this.token,
hasApiKey: !!this.apiKey,
timeout: this.options.timeout,
retries: this.options.retries,
supportedPlatforms: Object.values(PLATFORMS),
supportedFormats: Object.values(FORMATS)
};
}
}
module.exports = EliobrosDownloadClient;