xdl-node
Version:
A library for retrieving audio streams and other data from X Spaces, built on Node.js and TypeScript.
155 lines (154 loc) • 6.72 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Twspace = void 0;
// twspace.ts
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
class Twspace {
/**
* Конструктор принимает объект metadata, полученный от API.
* @param metadata - объект с данными Space
*/
constructor(metadata) {
// Инициализация полей по умолчанию
this.id = "";
this.url = "";
this.title = "";
this.creator_name = "";
this.creator_id = "";
this.creator_screen_name = "";
this.creator_profile_image_url = "";
this.start_date = "";
this.state = "";
this.available_for_replay = "";
this.media_key = "";
if (metadata) {
const root = (metadata.data &&
metadata.data.audioSpace &&
metadata.data.audioSpace.metadata) || {};
const creatorResults = root.creator_results &&
root.creator_results.result &&
root.creator_results.result.legacy;
if (creatorResults) {
this.creator_name = creatorResults.name;
this.creator_screen_name = creatorResults.screen_name;
// Убираем подстроку "_normal" из URL аватара
this.creator_profile_image_url = creatorResults.profile_image_url_https.replace("_normal", "");
// Для creator_id можно было бы вызвать API.graphql_api.userId, здесь оставляем пустым
}
this.source = metadata;
this.root = root;
this.id = root.rest_id;
this.url = "https://x.com/i/spaces/" + this.id;
this.title = root.title;
try {
const ts = parseInt(root.started_at) / 1000;
const date = new Date(ts * 1000);
this.start_date = date.toISOString().split('T')[0];
}
catch (err) {
const ts = parseInt(root.scheduled_start) / 1000;
const date = new Date(ts * 1000);
throw new Error(`Space should start at ${date.toISOString()}, try again later`);
}
this.state = root.state;
this.available_for_replay = root.is_space_available_for_replay;
this.media_key = root.media_key;
}
}
/**
* Функция для "санитаризации" имени файла.
* @param value - исходное имя файла.
* @returns Допустимое имя файла.
*/
static sterilizeFn(value) {
let ext = path_1.default.extname(value);
let name = path_1.default.basename(value, ext);
name = name.replace(/\0/g, "");
if (name.startsWith(".")) {
name = "_" + name;
}
// Заменяем запрещённые символы
name = name.replace(/[\/\\:*?"<>|]/g, "_").trim();
const invalidFilenames = [
"CON", "PRN", "AUX", "NUL",
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
];
if (invalidFilenames.includes(name)) {
name = "_" + name;
}
return name + ext;
}
/**
* Формирует имя файла по заданному шаблону.
* Пример шаблона: "(%(creator_name)s)%(title)s-%(id)s"
* @param formatStr - шаблон имени файла.
* @returns Полный путь к файлу.
*/
format(formatStr) {
const actualFormatStr = path_1.default.basename(formatStr);
const absDir = path_1.default.dirname(formatStr);
// Заменяем подстроки вида %(property)s на значения из объекта
let formatted = actualFormatStr.replace(/%\((\w+)\)s/g, (match, p1) => {
return this[p1] || "";
});
formatted = Twspace.sterilizeFn(formatted);
return path_1.default.join(absDir, formatted);
}
/**
* Создаёт экземпляр Twspace по URL твиттер-спейса.
* @param url - URL твиттер-спейса.
* @param apiInstance - экземпляр TwitterAPI.
* @returns Promise с экземпляром Twspace.
*/
static async fromSpaceUrl(url, apiInstance) {
const regex = /spaces\/(\w+)/;
const match = url.match(regex);
if (!match) {
throw new Error("Input URL is not valid. The URL format should be 'https://x.com/i/spaces/<space_id>'");
}
const space_id = match[1];
if (!apiInstance.graphql_api) {
throw new Error("GraphQL API is not initialized.");
}
const metadata = await apiInstance.graphql_api.audioSpaceById(space_id);
return new Twspace(metadata);
}
/**
* Создаёт экземпляр Twspace по URL пользователя (ищется текущий эфир).
* @param user_url - URL пользователя.
* @param apiInstance - экземпляр TwitterAPI.
* @returns Promise с экземпляром Twspace.
*/
static async fromUserAvatar(user_url, apiInstance) {
if (!apiInstance.graphql_api || !apiInstance.fleets_api) {
throw new Error("APIs are not initialized.");
}
const user_id = await apiInstance.graphql_api.userIdFromUrl(user_url);
const avatarContent = await apiInstance.fleets_api.avatarContent(user_id);
let broadcast_id;
try {
broadcast_id = avatarContent.users[user_id].spaces.live_content.audiospace.broadcast_id;
}
catch (err) {
throw new Error("Broadcast ID is not available. User is probably not live");
}
const metadata = await apiInstance.graphql_api.audioSpaceById(broadcast_id);
return new Twspace(metadata);
}
/**
* Создаёт экземпляр Twspace из файла с metadata.
* @param filePath - путь к файлу.
* @returns Экземпляр Twspace.
*/
static fromFile(filePath) {
const data = fs_1.default.readFileSync(filePath, 'utf8');
const metadata = JSON.parse(data);
return new Twspace(metadata);
}
}
exports.Twspace = Twspace;