Files
KiraTV-APP-NodeCast-Modific…/server/services/xtreamApi.js
T
Trevor Mears 4f9ec55874 Initial commit
2025-12-27 14:16:40 -08:00

162 lines
4.1 KiB
JavaScript

/**
* Xtream Codes API v2 Client
* Handles authentication and API calls to Xtream servers
*/
class XtreamApi {
constructor(baseUrl, username, password) {
// Clean up base URL
this.baseUrl = baseUrl.replace(/\/+$/, '');
this.username = username;
this.password = password;
}
/**
* Build API URL with authentication
*/
buildApiUrl(action, params = {}) {
const url = new URL(`${this.baseUrl}/player_api.php`);
url.searchParams.set('username', this.username);
url.searchParams.set('password', this.password);
if (action) {
url.searchParams.set('action', action);
}
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null) {
url.searchParams.set(key, value);
}
}
return url.toString();
}
/**
* Make API request
*/
async request(action, params = {}) {
const url = this.buildApiUrl(action, params);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Xtream API error: ${response.status} ${response.statusText}`);
}
return response.json();
}
/**
* Authenticate and get server/user info
*/
async authenticate() {
const data = await this.request(null);
if (!data.user_info) {
throw new Error('Invalid credentials or server response');
}
return data;
}
/**
* Get live channel categories
*/
async getLiveCategories() {
return this.request('get_live_categories');
}
/**
* Get live streams, optionally filtered by category
*/
async getLiveStreams(categoryId = null) {
return this.request('get_live_streams', { category_id: categoryId });
}
/**
* Get VOD categories
*/
async getVodCategories() {
return this.request('get_vod_categories');
}
/**
* Get VOD streams, optionally filtered by category
*/
async getVodStreams(categoryId = null) {
return this.request('get_vod_streams', { category_id: categoryId });
}
/**
* Get VOD info
*/
async getVodInfo(vodId) {
return this.request('get_vod_info', { vod_id: vodId });
}
/**
* Get series categories
*/
async getSeriesCategories() {
return this.request('get_series_categories');
}
/**
* Get series, optionally filtered by category
*/
async getSeries(categoryId = null) {
return this.request('get_series', { category_id: categoryId });
}
/**
* Get series info
*/
async getSeriesInfo(seriesId) {
return this.request('get_series_info', { series_id: seriesId });
}
/**
* Get short EPG for a stream
*/
async getShortEpg(streamId, limit = 10) {
return this.request('get_short_epg', { stream_id: streamId, limit });
}
/**
* Get full EPG for a stream
*/
async getSimpleDateTable(streamId) {
return this.request('get_simple_data_table', { stream_id: streamId });
}
/**
* Build stream URL for playback
*/
buildStreamUrl(streamId, type = 'live', container = 'ts') {
const typeMap = {
live: 'live',
vod: 'movie',
series: 'series'
};
const streamType = typeMap[type] || 'live';
return `${this.baseUrl}/${streamType}/${this.username}/${this.password}/${streamId}.${container}`;
}
/**
* Get XMLTV EPG URL
*/
getXmltvUrl() {
return `${this.baseUrl}/xmltv.php?username=${this.username}&password=${this.password}`;
}
}
/**
* Factory function to create API instance from source
*/
function createFromSource(source) {
return new XtreamApi(source.url, source.username, source.password);
}
/**
* Static authenticate for testing
*/
async function authenticate(url, username, password) {
const api = new XtreamApi(url, username, password);
return api.authenticate();
}
module.exports = { XtreamApi, createFromSource, authenticate };