UNPKG

captivate-fm-api-client

Version:

A Node.js client for the Captivate.fm API. Upload media, create episodes, and manage authentication.

536 lines (498 loc) 17.1 kB
const axios = require("axios"); const FormData = require("form-data"); const fs = require("fs"); /** * Creates a new Captivate API client. * * @param {string} userId - The user ID for authentication. * @param {string} apiKey - The API key for authentication. * @function Captivate#authenticateUser * @function Captivate#createEpisode * @function Captivate#listEpisodes * @function Captivate#uploadEpisode * @function Captivate#getAnalyticsOverview * @function Captivate#getEpisodeAnalyticsOverview * @function Captivate#getAnalyticsAverages * @function Captivate#getAnalyticsTotal * @function Captivate#getEpisodeAnalyticsTotal * @function Captivate#getAnalyticsMonthly * @function Captivate#getEpisodeAnalyticsMonthly * @function Captivate#getAnalyticsRange * @function Captivate#getEpisodeAnalyticsRange * @function Captivate#getAnalyticsComparison * @function Captivate#getWebPlayerAnalytics */ class Captivate { constructor(userId, apiKey) { this.token = ""; this.apiBase = "https://api.captivate.fm"; this.userId = userId; this.apiKey = apiKey; } /** * Retrieves a list of shows associated with the authenticated user. * * @returns {Promise<Array>} A promise that resolves to an array of shows. * @throws Will throw an error if the request fails. */ async getUserShows() { var config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/users/${this.userId}/shows`, headers: {}, }; try { const response = await axios(config); return response.data.shows; } catch (error) { console.error(error); } } /** * Retrieves a list of episodes for a given show. * * @param {string} showId - The ID of the show for which to list episodes. * * @returns {Promise<Object>} A promise that resolves to the response data containing the list of episodes. * @throws Will throw an error if the request fails. */ async listEpisodes(showId) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/shows/${showId}/episodes`, headers: { Authorization: `Bearer ${this.token}` }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Uploads an episode media file to a given show. * * @param {string} filePath - The path to the media file to be uploaded. * @param {string} showId - The ID of the show to which the media file will be uploaded. * * @returns {Promise<string>} A promise that resolves when the media file is uploaded and the media ID is set. * @throws Will throw an error if the upload request fails. */ async uploadEpisode(filePath, showId) { const data = new FormData(); data.append("file", fs.createReadStream(filePath)); const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/shows/${showId}/media`, headers: { "Content-Type": "multipart/form-data", ...data.getHeaders(), Authorization: `Bearer ${this.token}`, }, data: data, }; try { const response = await axios(config); return response.data.media.id; } catch (error) { console.error(error); } } /** * Creates a new episode for a given show. * * @param {Object} params - The parameters for creating an episode. * @param {string} params.showId - The ID of the show. * @param {string} params.title - The title of the episode. * @param {string} params.mediaId - The media ID of the episode. * @param {string} params.showNotes - The show notes for the episode. * @param {string} params.publishDate - The publish date of the episode. * @param {string} params.summary - The summary of the episode. * @param {string} params.episodeType - The type of the episode. * @param {string} [params.subtitle=null] - The subtitle of the episode. * @param {string} [params.author=null] - The author of the episode. * @param {boolean} [params.explicit=null] - Whether the episode is explicit. * @param {string} [params.status=null] - The status of the episode. * @param {number} [params.episodeSeason=null] - The season number of the episode. * @param {string} [params.donationLink=null] - The donation link for the episode. * @param {string} [params.donationText=null] - The donation text for the episode. * @param {string} [params.episodeUrl=null] - The URL of the episode. * @param {string} [params.episodeArt=null] - The artwork for the episode. * @param {number} params.episodeNumber - The episode number. * @param {boolean} [params.itunesBlock=false] - Whether to block the episode on iTunes. * * @returns {Promise<Object>} The response data from the API. */ async createEpisode({ showId, title, mediaId, showNotes, publishDate, summary, episodeType, subtitle = null, author = null, explicit = null, status = null, episodeSeason = null, donationLink = null, donationText = null, episodeUrl = null, episodeArt = null, episodeNumber, itunesBlock = false, }) { const data = new FormData(); data.append("shows_id", showId); data.append("title", title); data.append("itunes_title", title); data.append("media_id", mediaId); data.append("date", publishDate); data.append("episode_number", episodeNumber); data.append("episode_type", episodeType); data.append("shownotes", showNotes); data.append("summary", summary); status ? data.append("status", status) : null; subtitle ? data.append("itunes_subtitle", subtitle) : null; author ? data.append("author", author) : null; episodeArt ? data.append("episode_art", episodeArt) : null; explicit ? data.append("explicit", explicit) : null; episodeSeason ? data.append("episode_season", episodeSeason) : null; donationLink ? data.append("donation_link", donationLink) : null; donationText ? data.append("donation_text", donationText) : null; episodeUrl ? data.append("link", episodeUrl) : null; itunesBlock ? data.append("itunes_block", itunesBlock) : null; const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/episodes`, headers: { ...data.getHeaders(), Authorization: `Bearer ${this.token}`, }, data: data, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Authenticates the user with the provided userId and apiKey. * * @returns {Promise<string>} A promise that resolves when the user is authenticated and the token is set. * @throws Will throw an error if the authentication request fails. */ async authenticateUser() { const data = new FormData(); data.append("username", this.userId); data.append("token", this.apiKey); const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/authenticate/token`, headers: { ...data.getHeaders(), }, data: data, }; try { const response = await axios(config); this.token = response.data.user.token; } catch (error) { console.error(error); } } // ─── Analytics / Insights ─────────────────────────────────────────── /** * Gets an overview of analytics for a show within a date range. * * @param {string} showId - The show ID. * @param {string} start - Start date (YYYY-MM-DD). * @param {string} end - End date (YYYY-MM-DD). * @param {boolean} [includeTopEpisodes=true] - Include top episodes in the response. * @returns {Promise<Object>} Overview analytics data. */ async getAnalyticsOverview(showId, start, end, includeTopEpisodes = true) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/overview`, headers: { Authorization: `Bearer ${this.token}` }, params: { start, end, includeTopEpisodes }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets an overview of analytics for a specific episode within a date range. * * @param {string} showId - The show ID. * @param {string} episodeId - The episode ID. * @param {string} start - Start date (YYYY-MM-DD). * @param {string} end - End date (YYYY-MM-DD). * @returns {Promise<Object>} Episode overview analytics data. */ async getEpisodeAnalyticsOverview(showId, episodeId, start, end) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/overview/${episodeId}`, headers: { Authorization: `Bearer ${this.token}` }, params: { start, end }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets average analytics for a show over a given interval. * * @param {string} showId - The show ID. * @param {number} [intervalDays=28] - Number of days for the averaging interval. * @returns {Promise<Object>} Average analytics data. */ async getAnalyticsAverages(showId, intervalDays = 28) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/averages`, headers: { Authorization: `Bearer ${this.token}` }, params: { intervalDays }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets the all-time total downloads for a show. * * @param {string} showId - The show ID. * @returns {Promise<Object>} Total download data. */ async getAnalyticsTotal(showId) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/total`, headers: { Authorization: `Bearer ${this.token}` }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets the all-time total downloads for a specific episode. * * @param {string} showId - The show ID. * @param {string} episodeId - The episode ID. * @returns {Promise<Object>} Episode total download data. */ async getEpisodeAnalyticsTotal(showId, episodeId) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/total/${episodeId}`, headers: { Authorization: `Bearer ${this.token}` }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets month-by-month download analytics for a show. * * @param {string} showId - The show ID. * @returns {Promise<Object>} Monthly analytics data. */ async getAnalyticsMonthly(showId) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/monthly`, headers: { Authorization: `Bearer ${this.token}` }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets month-by-month download analytics for a specific episode. * * @param {string} showId - The show ID. * @param {string} episodeId - The episode ID. * @returns {Promise<Object>} Episode monthly analytics data. */ async getEpisodeAnalyticsMonthly(showId, episodeId) { const config = { method: "get", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/monthly/${episodeId}`, headers: { Authorization: `Bearer ${this.token}` }, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets analytics for a show within a custom date range with breakdowns. * * @param {string} showId - The show ID. * @param {Object} params - Range query parameters. * @param {string} params.start - Start date. * @param {string} params.end - End date. * @param {string} [params.interval='1d'] - Aggregation interval. * @param {string} [params.timezone='America/New_York'] - Timezone for date calculations. * @param {string|null} [params.countryCode=null] - Country code filter. * @param {string[]} [params.types] - Breakdown types (e.g. byLocation, byUserAgentBrowser). * @returns {Promise<Object>} Range analytics data. */ async getAnalyticsRange(showId, params) { const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/range`, headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.token}`, }, data: params, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets analytics for a specific episode within a custom date range. * * @param {string} showId - The show ID. * @param {string} episodeId - The episode ID. * @param {Object} params - Range query parameters (same shape as getAnalyticsRange). * @returns {Promise<Object>} Episode range analytics data. */ async getEpisodeAnalyticsRange(showId, episodeId, params) { const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/range/${episodeId}`, headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.token}`, }, data: params, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Compares analytics between multiple episodes. * * @param {string} showId - The show ID. * @param {Array<{id: string, title: string, published_date: string}>} episodes - Episodes to compare. * @returns {Promise<Object>} Comparison analytics data. */ async getAnalyticsComparison(showId, episodes) { const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/compare`, headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.token}`, }, data: episodes, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } /** * Gets web player analytics for a specific episode. * * @param {string} showId - The show ID. * @param {string} episodeId - The episode ID. * @param {Object} params - Web player query parameters. * @param {Object} params.dateRange - Date range with gte and lte properties. * @param {string} [params.duration] - Duration filter. * @param {string} [params.timezone='America/New_York'] - Timezone for date calculations. * @returns {Promise<Object>} Web player analytics data. */ async getWebPlayerAnalytics(showId, episodeId, params) { const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/insights/${showId}/web-player/${episodeId}`, headers: { "Content-Type": "application/json", Authorization: `Bearer ${this.token}`, }, data: params, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } async createShowArtwork(filePath, showId) { const data = new FormData(); data.append("file", fs.createReadStream(filePath)); const config = { method: "post", maxBodyLength: Infinity, url: `${this.apiBase}/shows/${showId}/artwork`, headers: { "Content-Type": "multipart/form-data", ...data.getHeaders(), Authorization: `Bearer ${this.token}`, }, data: data, }; try { const response = await axios(config); return response.data; } catch (error) { console.error(error); } } } module.exports = Captivate;