const { parseDate, withinDates } = require('../util');
const RotatingPlaylist = require('./RotatingPlaylist');
const SplitPlaylist = require('./SplitPlaylist');
const SingleItemPlaylist = require('./SingleItemPlaylist');
const PlaylistItem = require('./PlaylistItem');
const Playlist = require('./Playlist');
/** Represents a Apex Legends season. */
class Season {
/**
* Parse a Season object from JSON.
* @param {seasonData} seasonData Apex Legends season data
*/
constructor (seasonData) {
/**
* The season number (e.g. `12`).
* @type {number}
*/
this.id = seasonData.id;
/**
* The title of the season (e.g. `Defiance`).
* @type {string}
*/
this.name = seasonData.name;
/**
* The time at which the season starts.
* @type {date}
*/
this.startTime = parseDate(seasonData.startTime);
/**
* The time at which the season ends.
* @type {date}
*/
this.endTime = parseDate(seasonData.endTime);
/**
* Array of {@link Playlist}s for this season.
* @type {Playlist[]}
*/
this.playlists = (()=>{
// Array of standard playlists
const availablePlaylists = [...seasonData.playlists]
.map(playlist => this.parsePlaylist(playlist));
// Array of LTM playlists if available, else empty array
const availableLTMs = seasonData.LTMs
? [...seasonData.LTMs]
.map(ltm => this.parsePlaylist({...ltm, LTM: true}))
: [];
// return combined standard and LTM playlists
return [
...availablePlaylists,
...availableLTMs,
];
})();
};
/**
* Alias for Play Apex mode.
*
* @readonly
* @memberof Season
* @deprecated
* @todo remove this alias?
*/
get unranked() {
return {
battleRoyale: this.playlists
.find(playlist => playlist.mode == 'Play Apex')
};
};
/**
* Alias for Ranked Leagues.
*
* @readonly
* @memberof Season
* @deprecated
* @todo remove this alias?
*/
get ranked() {
return {
battleRoyale: this.playlists
.find(playlist => playlist.mode == 'Ranked Leagues')
};
};
/**
* Gets an array of current playlists via this instance's
* [getPlaylistsByDate]{@link Season#getPlaylistsByDate} method.
*
* @readonly
* @memberof Season
*/
get currentPlaylists() {
return this.getPlaylistsByDate();
};
/**
* Gets an array of current maps from this instance's
* [getMapsByDate]{@link Season#getMapsByDate} method.
*
* @readonly
* @memberof Season
*/
get currentMaps() {
return this.getMapsByDate();
};
/**
* Gets an array containing the upcoming {@link PlaylistItem}s for each
* {@link Playlist} by calling the `.nextMap` method on each instance
* (depending on playlist type, e.g. {@link RotatingPlaylist#nextMap}).
* Takes into account whether a takeover LTM is about to end and will
* attempt to replace this entry with the 'regular' mode map.
*
* @readonly
* @memberof Season
* @type {?PlaylistItem[]}
*/
get nextMaps() {
let nextMaps = this.playlists
.map(playlist => playlist.nextMap)
.filter(map => map !== null);
if (this.currentTakeovers) this.currentTakeovers.forEach(takeover => {
nextMaps = nextMaps.filter(map => map.mode !== takeover.replaces);
nextMaps.push(this.playlists
.find(playlist => playlist.mode === takeover.replaces)
.getMapByDate(takeover.endTime)
);
});
if (!nextMaps.length) return null;
return nextMaps;
};
/**
* Array of limited time modes for this season, or {@link null} if none found.
*
* @readonly
* @memberof Season
* @type {?Playlist[]}
*/
get LTMs() {
const availableLTMs = this.playlists.filter(playlist => playlist.LTM);
if (!availableLTMs.length) return null;
return availableLTMs;
};
/**
* Array of currently-active limited time modes, or {@link null} if none found.
*
* @readonly
* @memberof Season
* @type {?Playlist[]}
*/
get currentLTMs() {
if (!this.LTMs) return null;
const currentLTMs = this.LTMs
.filter(ltm => withinDates(ltm));
if (currentLTMs.length === 0) return null;
return currentLTMs;
};
/**
* Array of limited time modes in this season which replace another mode, or
* {@link null} if none found.
*
* @readonly
* @memberof Season
* @type {?Playlist[]}
*/
get takeovers() {
if (!this.LTMs) return null;
const takeovers = this.LTMs.filter(ltm => ltm.takeover);
if (!takeovers.length) return null;
return takeovers;
};
/**
* Array of currently-active limited time modes which replace another
* playlist in the season, or {@link null} if none found.
*
* @readonly
* @memberof Season
* @type {?Playlist[]}
*/
get currentTakeovers() {
if (!this.takeovers) return null;
const now = new Date();
const currentTakeovers = this.takeovers
.filter(takeover => withinDates(takeover));
if (!currentTakeovers.length) return null;
return currentTakeovers;
};
/**
* Take playlist data and parse into an instance of a {@link Playlist}
* subclass, determined by querying sections of the data.
*
* @todo move into a private or static method
* @param {playlistData} playlistData data for this playlist
* @returns {SingleItemPlaylist|RotatingPlaylist|SplitPlaylist}
*/
parsePlaylist(playlistData) {
if (playlistData.splitTime)
return new SplitPlaylist(playlistData, this);
if (playlistData.mapDurations)
return new RotatingPlaylist(playlistData, this);
if (playlistData.maps.length === 1)
return new SingleItemPlaylist(playlistData, this);
};
/**
* Get an array of {@link Playlist} subclass instances active during the
* provided date, or the current date if not provided. Returns {@link null}
* if none found.
*
* @param {parseableDate} date the query date
* @returns {?Playlist[]} active playlists or {@link null}
*/
getPlaylistsByDate(date) {
const targetDate = parseDate(date);
let availablePlaylists = this.playlists
.filter(playlist => withinDates(playlist, targetDate));
const takeovers = availablePlaylists
.filter(playlist => playlist.takeover);
takeovers.forEach(takeover => availablePlaylists = availablePlaylists
.filter(playlist => playlist.mode !== takeover.replaces));
if (availablePlaylists.length === 0) return null;
return availablePlaylists;
};
/**
* Get an Array of maps active at a given date, or the current date if not
* provided. Returns {@link null} if outside of season date boundaries.
*
* @todo should return null if no maps found.
*
* @param {parseableDate} [date=new Date()] the query date
* @returns {?ScheduledPlaylistItem[]} an array of maps or {@link null}
*/
getMapsByDate(date) {
if (!withinDates(this, date)) return null;
const targetDate = parseDate(date);
return this.getPlaylistsByDate(targetDate)
.map(playlist => playlist.getMapByDate(targetDate));
};
};
module.exports = Season;
Source