UNPKG

@jkt48/core

Version:

Official JKT48 Connect API client for Node.js and browsers

682 lines (598 loc) 17.6 kB
import axios from 'axios'; /** * Constants used throughout the JKT48 API client */ const BASE_URL = 'https://v2.jkt48connect.com/api'; const ENDPOINTS = { // Member endpoints MEMBERS: '/jkt48/members', BIRTHDAY: '/jkt48/birthday', MEMBER_DETAIL: (name) => `/jkt48/member/${encodeURIComponent(name)}`, // Event endpoints EVENTS: '/jkt48/events', THEATER: '/jkt48/theater', THEATER_DETAIL: (id) => `/jkt48/theater/${id}`, // Live streaming endpoints RECENT: '/jkt48/recent', REPLAY: '/jkt48/replay', RECENT_DETAIL: (liveId) => `/jkt48/recent/${liveId}`, LIVE: '/jkt48/live', LIVE_YOUTUBE: '/jkt48/live/youtube', LIVE_IDN: '/jkt48/live/idn', LIVE_SHOWROOM: '/jkt48/live/showroom', // Media endpoints YOUTUBE: '/jkt48/youtube', NEWS: '/jkt48/news', NEWS_DETAIL: (id) => `/jkt48/news/${id}`, // Chat endpoints CHAT_STREAM: (username, slug) => `/jkt48/chat-stream?username=${encodeURIComponent(username)}&slug=${encodeURIComponent(slug)}`, CHAT_STREAM_SR: (roomId) => `/jkt48/chat-stream-sr?room_id=${encodeURIComponent(roomId)}`, // Video call endpoints VIDEO_CALL: (sesi = '', date = '', member = '') => { let endpoint = `/jkt48/videocall`; const params = []; if (sesi) params.push(`sesi=${encodeURIComponent(sesi)}`); if (date) params.push(`date=${encodeURIComponent(date)}`); if (member) params.push(`member=${encodeURIComponent(member)}`); return params.length > 0 ? `${endpoint}?${params.join('&')}` : endpoint; }, VIDEO_CALL_TODAY: '/jkt48/videocall/today', // System endpoints CHECK: '/zenova/check', // Admin endpoints ADMIN_KEYS: '/admin/keys', ADMIN_KEY_DETAIL: (key) => `/admin/key/${encodeURIComponent(key)}`, ADMIN_UPDATE_KEY: (key, active, type) => `/admin/update-key?key=${encodeURIComponent(key)}&active=${active}&type=${encodeURIComponent(type)}`, ADMIN_DELETE_KEY: (key) => `/admin/key/${encodeURIComponent(key)}`, ADMIN_STATS: '/admin/stats', ADMIN_CREATE_KEY: (owner, email, type = '', apikey = '') => { let endpoint = `/admin/create-key?owner=${encodeURIComponent(owner)}&email=${encodeURIComponent(email)}`; if (type) endpoint += `&type=${encodeURIComponent(type)}`; if (apikey) endpoint += `&apikey=${encodeURIComponent(apikey)}`; return endpoint; }, ADMIN_ADD_LIMIT: (key, additionalLimit) => `/admin/add-limit?key=${encodeURIComponent(key)}&additionalLimit=${encodeURIComponent(additionalLimit)}`, ADMIN_ADD_EXPIRY: (key, additionalDays) => `/admin/add-expiry?key=${encodeURIComponent(key)}&additionalDays=${encodeURIComponent(additionalDays)}`, // Changelog endpoints CREATE_CHANGELOG: '/database/create-changelog', CHANGELOGS: '/database/changelogs', CHANGELOG_DETAIL: (id) => `/database/changelog/${id}`, UPDATE_CHANGELOG: (id) => `/database/changelog/${id}`, DELETE_CHANGELOG: (id) => `/database/changelog/${id}`, // Grow A Garden endpoints STOCK: '/growagarden/stock', WEATHER: '/growagarden/weather', RESTOCK: '/growagarden/restock-timer', ALL: '/growagarden/all' }; /** * HTTP Client for making API requests */ class HttpClient { constructor(apiKey, priorityToken = null, adminCredentials = null) { this.apiKey = apiKey; this.priorityToken = priorityToken; this.adminCredentials = adminCredentials; this.baseURL = BASE_URL; } /** * Build request config with authentication */ buildConfig(config = {}) { const headers = { 'Content-Type': 'application/json', ...config.headers }; // Add priority token if available if (this.priorityToken) { headers['x-priority-token'] = this.priorityToken; } return { ...config, headers }; } /** * Build URL with query parameters */ buildUrl(endpoint, params = {}) { const url = new URL(`${this.baseURL}${endpoint}`); // Add API key url.searchParams.append('apikey', this.apiKey); // Add priority token as query param if available if (this.priorityToken && !params.priority_token) { url.searchParams.append('priority_token', this.priorityToken); } // Add admin credentials if available if (this.adminCredentials) { url.searchParams.append('username', this.adminCredentials.username); url.searchParams.append('password', this.adminCredentials.password); } // Add other parameters Object.keys(params).forEach(key => { if (params[key] !== undefined && params[key] !== null) { url.searchParams.append(key, params[key]); } }); return url.toString(); } /** * Make GET request */ async get(endpoint, params = {}, config = {}) { try { const url = this.buildUrl(endpoint, params); const response = await axios.get(url, this.buildConfig(config)); return response.data; } catch (error) { this.handleError(error); } } /** * Make POST request */ async post(endpoint, data = {}, params = {}, config = {}) { try { const url = this.buildUrl(endpoint, params); // Add priority token to body if available if (this.priorityToken && !data.priority_token) { data.priority_token = this.priorityToken; } const response = await axios.post(url, data, this.buildConfig(config)); return response.data; } catch (error) { this.handleError(error); } } /** * Make PUT request */ async put(endpoint, data = {}, params = {}, config = {}) { try { const url = this.buildUrl(endpoint, params); // Add priority token to body if available if (this.priorityToken && !data.priority_token) { data.priority_token = this.priorityToken; } const response = await axios.put(url, data, this.buildConfig(config)); return response.data; } catch (error) { this.handleError(error); } } /** * Make DELETE request */ async delete(endpoint, params = {}, config = {}) { try { const url = this.buildUrl(endpoint, params); const response = await axios.delete(url, this.buildConfig(config)); return response.data; } catch (error) { this.handleError(error); } } /** * Handle API errors */ handleError(error) { if (error.response) { // Server responded with error const errorMessage = error.response.data?.message || error.response.statusText; throw new Error(`API Error (${error.response.status}): ${errorMessage}`); } else if (error.request) { // Request made but no response throw new Error('Network Error: No response from server'); } else { // Something else happened throw new Error(`Request Error: ${error.message}`); } } } /** * Service for member-related API endpoints */ class MembersService { constructor(httpClient) { this.client = httpClient; } /** * Get all JKT48 members * @returns {Promise<Object>} List of all members */ async getMembers() { return this.client.get(ENDPOINTS.MEMBERS); } /** * Get member details by name * @param {string} name - Member name * @returns {Promise<Object>} Member details */ async getMemberDetail(name) { return this.client.get(ENDPOINTS.MEMBER_DETAIL(name)); } /** * Get members with birthdays * @returns {Promise<Object>} Members birthday information */ async getBirthdays() { return this.client.get(ENDPOINTS.BIRTHDAY); } } /** * Service for live streaming related API endpoints */ class LiveService { constructor(httpClient) { this.client = httpClient; } /** * Get current live streams * @returns {Promise<Object>} Current live streams */ async getLive() { return this.client.get(ENDPOINTS.LIVE); } /** * Get YouTube live streams * @returns {Promise<Object>} YouTube live streams */ async getYoutubeLive() { return this.client.get(ENDPOINTS.LIVE_YOUTUBE); } /** * Get IDN live streams * @returns {Promise<Object>} IDN live streams */ async getIdnLive() { return this.client.get(ENDPOINTS.LIVE_IDN); } /** * Get Showroom live streams * @returns {Promise<Object>} Showroom live streams */ async getShowroomLive() { return this.client.get(ENDPOINTS.LIVE_SHOWROOM); } /** * Get recent streams * @returns {Promise<Object>} Recent streams */ async getRecent() { return this.client.get(ENDPOINTS.RECENT); } /** * Get recent stream detail * @param {string} liveId - Live stream ID * @returns {Promise<Object>} Recent stream details */ async getRecentDetail(liveId) { return this.client.get(ENDPOINTS.RECENT_DETAIL(liveId)); } /** * Get replay streams * @returns {Promise<Object>} Replay streams */ async getReplay() { return this.client.get(ENDPOINTS.REPLAY); } /** * Get chat stream * @param {string} username - Username * @param {string} slug - Stream slug * @returns {Promise<Object>} Chat stream data */ async getChatStream(username, slug) { return this.client.get(ENDPOINTS.CHAT_STREAM(username, slug)); } /** * Get Showroom chat stream * @param {string} roomId - Room ID * @returns {Promise<Object>} Showroom chat stream data */ async getChatStreamShowroom(roomId) { return this.client.get(ENDPOINTS.CHAT_STREAM_SR(roomId)); } } /** * Service for events and theater related API endpoints */ class EventsService { constructor(httpClient) { this.client = httpClient; } /** * Get all events * @returns {Promise<Object>} List of events */ async getEvents() { return this.client.get(ENDPOINTS.EVENTS); } /** * Get theater schedule * @returns {Promise<Object>} Theater schedule */ async getTheater() { return this.client.get(ENDPOINTS.THEATER); } /** * Get theater detail * @param {string} id - Theater ID * @returns {Promise<Object>} Theater details */ async getTheaterDetail(id) { return this.client.get(ENDPOINTS.THEATER_DETAIL(id)); } /** * Get video call schedules * @param {string} sesi - Session * @param {string} date - Date * @param {string} member - Member name * @returns {Promise<Object>} Video call schedules */ async getVideoCall(sesi = '', date = '', member = '') { return this.client.get(ENDPOINTS.VIDEO_CALL(sesi, date, member)); } /** * Get today's video call schedules * @returns {Promise<Object>} Today's video call schedules */ async getVideoCallToday() { return this.client.get(ENDPOINTS.VIDEO_CALL_TODAY); } } /** * Service for media related API endpoints */ class MediaService { constructor(httpClient) { this.client = httpClient; } /** * Get YouTube videos * @returns {Promise<Object>} YouTube videos */ async getYoutube() { return this.client.get(ENDPOINTS.YOUTUBE); } /** * Get news articles * @returns {Promise<Object>} News articles */ async getNews() { return this.client.get(ENDPOINTS.NEWS); } /** * Get news detail * @param {string} id - News ID * @returns {Promise<Object>} News details */ async getNewsDetail(id) { return this.client.get(ENDPOINTS.NEWS_DETAIL(id)); } } /** * Service for admin related API endpoints * Requires admin credentials to be set in the client */ class AdminService { constructor(httpClient) { this.client = httpClient; } /** * Get all API keys * @returns {Promise<Object>} List of all API keys */ async getKeys() { return this.client.get(ENDPOINTS.ADMIN_KEYS); } /** * Get API key details * @param {string} key - API key * @returns {Promise<Object>} API key details */ async getKeyDetail(key) { return this.client.get(ENDPOINTS.ADMIN_KEY_DETAIL(key)); } /** * Create new API key * @param {string} owner - Owner name * @param {string} email - Owner email * @param {string} type - Key type * @param {string} apikey - Custom API key (optional) * @returns {Promise<Object>} Created API key */ async createKey(owner, email, type = '', apikey = '') { return this.client.post(ENDPOINTS.ADMIN_CREATE_KEY(owner, email, type, apikey)); } /** * Update API key * @param {string} key - API key * @param {boolean} active - Active status * @param {string} type - Key type * @returns {Promise<Object>} Updated API key */ async updateKey(key, active, type) { return this.client.put(ENDPOINTS.ADMIN_UPDATE_KEY(key, active, type)); } /** * Delete API key * @param {string} key - API key * @returns {Promise<Object>} Deletion result */ async deleteKey(key) { return this.client.delete(ENDPOINTS.ADMIN_DELETE_KEY(key)); } /** * Add request limit to API key * @param {string} key - API key * @param {number} additionalLimit - Additional limit to add * @returns {Promise<Object>} Updated API key */ async addLimit(key, additionalLimit) { return this.client.post(ENDPOINTS.ADMIN_ADD_LIMIT(key, additionalLimit)); } /** * Add expiry days to API key * @param {string} key - API key * @param {number} additionalDays - Additional days to add * @returns {Promise<Object>} Updated API key */ async addExpiry(key, additionalDays) { return this.client.post(ENDPOINTS.ADMIN_ADD_EXPIRY(key, additionalDays)); } /** * Get admin statistics * @returns {Promise<Object>} Admin statistics */ async getStats() { return this.client.get(ENDPOINTS.ADMIN_STATS); } } /** * Service for changelog related API endpoints */ class ChangelogService { constructor(httpClient) { this.client = httpClient; } /** * Get all changelogs * @returns {Promise<Object>} List of changelogs */ async getChangelogs() { return this.client.get(ENDPOINTS.CHANGELOGS); } /** * Get changelog detail * @param {string} id - Changelog ID * @returns {Promise<Object>} Changelog details */ async getChangelogDetail(id) { return this.client.get(ENDPOINTS.CHANGELOG_DETAIL(id)); } /** * Create new changelog * @param {Object} data - Changelog data * @returns {Promise<Object>} Created changelog */ async createChangelog(data) { return this.client.post(ENDPOINTS.CREATE_CHANGELOG, data); } /** * Update changelog * @param {string} id - Changelog ID * @param {Object} data - Updated changelog data * @returns {Promise<Object>} Updated changelog */ async updateChangelog(id, data) { return this.client.put(ENDPOINTS.UPDATE_CHANGELOG(id), data); } /** * Delete changelog * @param {string} id - Changelog ID * @returns {Promise<Object>} Deletion result */ async deleteChangelog(id) { return this.client.delete(ENDPOINTS.DELETE_CHANGELOG(id)); } } /** * Service for Grow A Garden game related API endpoints */ class GardenService { constructor(httpClient) { this.client = httpClient; } /** * Get stock information * @returns {Promise<Object>} Stock information */ async getStock() { return this.client.get(ENDPOINTS.STOCK); } /** * Get weather information * @returns {Promise<Object>} Weather information */ async getWeather() { return this.client.get(ENDPOINTS.WEATHER); } /** * Get restock timer * @returns {Promise<Object>} Restock timer */ async getRestockTimer() { return this.client.get(ENDPOINTS.RESTOCK); } /** * Get all garden information * @returns {Promise<Object>} All garden data */ async getAll() { return this.client.get(ENDPOINTS.ALL); } } /** * JKT48 Connect API Client */ class JKT48Client { /** * Initialize JKT48 API Client * @param {Object} config - Configuration object * @param {string} config.apiKey - API key (required) * @param {string} config.priorityToken - Priority token (optional) * @param {Object} config.adminCredentials - Admin credentials (optional) * @param {string} config.adminCredentials.username - Admin username * @param {string} config.adminCredentials.password - Admin password */ constructor(config) { if (!config || !config.apiKey) { throw new Error('API key is required'); } this.httpClient = new HttpClient( config.apiKey, config.priorityToken || null, config.adminCredentials || null ); // Initialize services this.members = new MembersService(this.httpClient); this.live = new LiveService(this.httpClient); this.events = new EventsService(this.httpClient); this.media = new MediaService(this.httpClient); this.admin = new AdminService(this.httpClient); this.changelog = new ChangelogService(this.httpClient); this.garden = new GardenService(this.httpClient); } /** * Check API status * @returns {Promise<Object>} API status */ async check() { return this.httpClient.get(ENDPOINTS.CHECK); } /** * Update API key * @param {string} newApiKey - New API key */ setApiKey(newApiKey) { this.httpClient.apiKey = newApiKey; } /** * Update priority token * @param {string} newPriorityToken - New priority token */ setPriorityToken(newPriorityToken) { this.httpClient.priorityToken = newPriorityToken; } /** * Update admin credentials * @param {Object} credentials - Admin credentials * @param {string} credentials.username - Admin username * @param {string} credentials.password - Admin password */ setAdminCredentials(credentials) { this.httpClient.adminCredentials = credentials; } } export { JKT48Client as default };