UNPKG

trackmania.io

Version:

Node.js inplementation of Trackmania Live services (trackmania.io)

455 lines (404 loc) 11.5 kB
const Player = require('./Player'); // eslint-disable-line no-unused-vars const Client = require('../client/Client'); // eslint-disable-line no-unused-vars const TMMap = require('./TMMap'); // eslint-disable-line no-unused-vars const Club = require('./Club'); // eslint-disable-line no-unused-vars const ReqUtil = require('../util/ReqUtil'); const EventEmitter = require('events'); /** * The Campaign class represents a campaign. */ class Campaign extends EventEmitter { constructor(client, data) { super(); /** * The client object of the campaign. * @type {Client} */ this.client = client; /** * The data object * @type {Object} * @private */ this._data = data; /** * The leaderboard of the campaign * @type {Array<CampaignLeaderboard>} */ this.leaderboard = []; } /** * The id of the campaign. * @type {number} */ get id() { return this._data.id; } /** * The name of the campaign. * @type {string} */ get name() { return this._data.name; } /** * Whether the campaign is official. * @type {boolean} */ get isOfficial() { return this._data.clubid === 0; } /** * The image URL of the campaign. If this is an official campaign, the decal image URL is returned. * @type {string} */ get image() { if (this.isOfficial) { const ReqUtil = require('../util/ReqUtil'); return new ReqUtil(this.client).tmioURL + this._data.mediae.decal; } else return this._data.media; } /** * The creation date of the campaign. * @type {Date} */ get createdAt() { return new Date(this._data.creationtime*1000); } /** * The last update date of the campaign. * @type {Date} */ get updatedAt() { return new Date(this._data.lastupdatetime*1000); } /** * The club that owns the campaign. (if it's not an official campaign) * @returns {?Promise<Club>} */ async club() { if (this.isOfficial) return null; else return this.client.clubs.get(this._data.clubid); } /** * The leaderboard id of the campaign. * @type {string} */ get leaderboardId() { return this._data.leaderboarduid; } /** * Get the number of maps in the campaign. * @type {number} */ get mapCount() { return this._data.playlist.length; } /** * Get a specific map of the campaign. * @param {number} index The index of the map. * @returns {Promise<TMMap>} */ async map(index) { return await this.client.maps.get(this._data.playlist[index].mapUid); } /** * The list of maps in the campaign. * @returns {Promise<Array<TMMap>>} * @example * Client.campaigns.get(0, 11612).then(async campaign => { * const maps = await campaign.maps(); * maps.forEach(map => console.log(map.name)); * }); */ async maps() { const array = []; for (let i = 0; i < this._data.playlist.length; i++) { let map = await this.client.maps.get(this._data.playlist[i].mapUid); array.push(map); } return array; } /** * Load more results in the leaderboard. * @param {number} [nbOfResults=100] The number of results to load. (max 100) * @returns {Promise<?Array<CampaignLeaderboard>>} */ async leaderboardLoadMore(nbOfResults = 100) { if (nbOfResults > 100) nbOfResults = 100; if (nbOfResults < 1) nbOfResults = 1; const leaderboard = this.client.options.api.paths.tmio.tabs.leaderboard, params = new URLSearchParams(); params.append('offset', this.leaderboard.length); params.append('length', nbOfResults); const leaderboardRes = await this.client._apiReq(`${new ReqUtil(this.client).tmioAPIURL}/${leaderboard}/${this.leaderboardId}?${params.toString()}`); if (leaderboardRes.tops != null){ for (let i = 0; i < leaderboardRes.tops.length; i++) { this.leaderboard.push(new CampaignLeaderboard(this, leaderboardRes.tops[i])); } } return this.leaderboard; } /** * The media images of the campaign, if this is an official campaign. * @type {?CampaignMedia} */ get media() { if (this.isOfficial) { return new CampaignMedia(this.client, this._data.mediae); } else return null; } /** * Whether the campaign is tracked. * @type {boolean} */ get isTracked() { return this._data.tracked; } /** * Gets the campaign activity. * <info>{@link Campaign#isTracked} must be true.</info> * @returns {Promise<Array<CampaignRecordActivity>>} */ async activity(page = 0) { if (!this.isTracked) throw 'Campaign is not tracked.'; const activity = this.client.options.api.paths.tmio.tabs.activity, leaderboard = this.client.options.api.paths.tmio.tabs.leaderboard, activityRes = await this.client._apiReq(`${new ReqUtil(this.client).tmioAPIURL}/${leaderboard}/${activity}/${this.leaderboardId}/${page}`); return activityRes.map(activity => new CampaignRecordActivity(this, activity)); } /** * Subscribe to the campaign WR updates. * <info>{@link Campaign#isTracked} must be true.</info> * <info>When a new WR is set, the event {@link Campaign#e-wr} will be fired</info> * @returns {Promise<void>} * @example * Client.campaigns.currentSeason().then(campaign => { * campaign.subWR(); * campaign.on('wr', (map, record) => { * console.log(`New WR on ${campaign.name} in ${map.name} is ${record.playerName} (${record.time})`); * }); * }); */ async subWR() { if (!this.isTracked) throw 'The campaign is not tracked'; let actualWR = await this.activity(); setInterval(async ()=>{ let newWR = await this.activity(); if (actualWR[0].id != newWR[0].id) { let map = await newWR[0].map(); /** * Emitted when a new WR is set. * <info>This event is emitted only if the method {@link Campaign#subWR} is called</info> * @event Campaign#wr * @param {TMMap} map The map where the new WR is set. * @param {CampaignRecordActivity} newWR The new WR. */ this.emit('wr', map, newWR); actualWR = newWR; } }, this.client.options.cache.ttl * 60 * 1000); } } /** * The media images of an official campaign. */ class CampaignMedia { constructor(client, data) { const ReqUtil = require('../util/ReqUtil'), tmioURL = new ReqUtil(client).tmioURL; /** * The client object of the campaign. * @type {Client} */ this.client = client; /** * The decal image URL of the campaign. * @type {string} */ this.decal = tmioURL + data.decal; /** * The button background image URL of the campaign. * @type {string} */ this.buttonBackground = tmioURL + data.buttonbackground; /** * The button foreground image URL of the campaign. * @type {string} */ this.buttonForeground = tmioURL + data.buttonforeground; /** * The live button background image URL of the campaign. * @type {string} */ this.liveButtonBackground = tmioURL + data.livebuttonbackground; /** * The live button foreground image URL of the campaign. * @type {string} */ this.liveButtonForeground = tmioURL + data.livebuttonforeground; /** * The popup background image URL of the campaign. * @type {string} */ this.popupBackground = data.popupbackground; /** * The popup foreground image URL of the campaign. * @type {string} */ this.popup = data.popup; } } /** * The leaderboard of a campaign */ class CampaignLeaderboard{ constructor(campaign, data){ /** * The campaign * @type {Campaign} */ this.campaign = campaign; /** * The client instance. * @type {Client} */ this.client = this.campaign.client; /** * The data * @type {Object} * @private */ this._data = data; } /** * Fetches the player * @returns {Promise<Player>} */ async player(){ let player = await this.client.players.get(this._data.player.id); return player; } /** * The player name * @type {string} */ get playerName(){ return this._data.player.name; } /** * The position * @type {number} */ get position(){ return this._data.position; } /** * The number of points * @type {number} */ get points(){ return this._data.points; } } /** * The WR activity of a campaign */ class CampaignRecordActivity{ constructor(campaign, data){ /** * The Campaign * @type {Campaign} */ this.campaign = campaign; /** * The client instance. * @type {Client} */ this.client = this.campaign.client; /** * The data * @type {Object} * @private */ this._data = data; } /** * The ID of the activity * @type {number} */ get id(){ return this._data.id; } /** * The leaderboard UID of the campaign * @type {string} */ get leaderboardId(){ return this._data.group; } /** * The map of the activity * @returns {Promise<TMMap>} */ async map(){ return await this.client.maps.get(this._data.map.mapUid); } /** * The map name * @type {string} */ get mapName(){ return this._data.map.name; } /** * The map author * @returns {Promise<Player>} */ async mapAuthor(){ return await this.client.players.get(this._data.map.author); } /** * The map author name * @type {string} */ get mapAuthorName(){ return this._data.map.authorplayer.name; } /** * The player who set the record * @returns {Promise<Player>} */ async player(){ return await this.client.players.get(this._data.player.id); } /** * The player name who set the record * @type {string} */ get playerName(){ return this._data.player.name; } /** * The date of the record * @type {Date} */ get date(){ return new Date(this._data.drivenat); } /** * The time of the record * @type {number} */ get time(){ return this._data.time; } /** * The difference between the record and the previous one * @type {number} */ get difference(){ return this._data.timediff; } } module.exports = Campaign;