UNPKG

pipebomb.js

Version:

Library for interacting with Pipe Bomb servers

251 lines 9.39 kB
import Track from "../music/Track.js"; export default class Playlist { constructor(context, collectionID, name, owner, trackList) { this.trackList = null; this.isDeleted = false; this.updateCallbacks = []; this.suggestedTracks = []; this.suggestedTracksUpdated = null; this.checkTimer = null; this.lastChecked = Date.now(); this.context = context; this.rawCollectionID = collectionID; this.collectionID = context.prefixAddress(collectionID); this.name = name; this.owner = owner; this.trackList = trackList; } async getTrackList() { this.checkDeletion(); if (this.trackList == null) { const info = await this.context.makeRequest("get", `v1/playlists/${this.rawCollectionID}`); if (info.statusCode != 200) return null; const newCollection = Playlist.convertJsonToPlaylist(this.context, info.response); if (!newCollection) return null; this.trackList = newCollection.trackList; } return Array.from(this.trackList); } async getSuggestedTracks() { this.checkDeletion(); const trackCache = this.context.instance.trackCache; if (this.suggestedTracksUpdated && this.suggestedTracksUpdated < Date.now() / 1000 - 600) { return Array.from(this.suggestedTracks); } try { const suggestions = await this.context.makeRequest("get", `v1/playlists/${this.rawCollectionID}/suggested`); if (suggestions.statusCode != 200 || !Array.isArray(suggestions.response)) throw "invalid response"; const out = []; for (let json of suggestions.response) { const track = Track.convertJsonToTrack(this.context, json); if (track) { trackCache.updateTrack(track); out.push(track); } } this.suggestedTracks = out; this.suggestedTracksUpdated = Math.floor(Date.now() / 1000); return Array.from(out); } catch { } return []; } getName() { return this.name; } async addTracks(...tracks) { this.checkDeletion(); const response = await this.context.makeRequest("patch", `v1/playlists/${this.rawCollectionID}`, { tracks: { add: tracks.map(track => { return track.trackID; }) } }); if (response.statusCode != 200) throw response; const newCollection = Playlist.convertJsonToPlaylist(this.context, response.response); if (!newCollection) return; this.copyFromOtherPlaylist(newCollection); } async removeTracks(...tracks) { this.checkDeletion(); const response = await this.context.makeRequest("patch", `v1/playlists/${this.rawCollectionID}`, { tracks: { remove: tracks.map(track => { return track.trackID; }) } }); if (response.statusCode != 200) throw response; const newCollection = Playlist.convertJsonToPlaylist(this.context, response.response); if (!newCollection) return; this.copyFromOtherPlaylist(newCollection); } async setName(name) { this.checkDeletion(); const response = await this.context.makeRequest("patch", `v1/playlists/${this.rawCollectionID}`, { name }); if (response.statusCode != 200) throw response; const newCollection = Playlist.convertJsonToPlaylist(this.context, response.response); if (!newCollection) return; this.copyFromOtherPlaylist(newCollection); } async deleteCollection() { const response = await this.context.makeRequest("delete", `v1/playlists/${this.rawCollectionID}`); if (response.statusCode != 204) throw response; this.isDeleted = true; this.trackList = []; this.pushToCallbacks(); } copyFromOtherPlaylist(collection) { this.checkDeletion(); if (this.collectionID != collection.collectionID) return; let changed = false; if (this.name != collection.name) { changed = true; this.name = collection.name; } if (collection.trackList !== null) { if (this.trackList !== null && this.trackList.length == collection.trackList.length) { for (let i = 0; i < this.trackList.length; i++) { if (this.trackList[i].trackID != collection.trackList[i].trackID) { changed = true; break; } } } else { changed = true; } this.trackList = collection.trackList; } if (changed) { this.pushToCallbacks(); } } static convertJsonToPlaylist(context, json) { const trackCache = context.instance.trackCache; const collectionCache = context.instance.collectionCache; const criteria = [ ["string", "number"].includes(typeof json?.collectionID), typeof json?.name == "string", json?.owner == null || (typeof json?.owner?.userID == "string" && typeof json?.owner?.username == "string"), !(json?.trackList) || (() => { if (!Array.isArray(json.trackList)) return false; for (let track of json.trackList) { if (typeof track?.trackID != "string") return false; } return true; })() ]; for (let option of criteria) { if (!option) return null; } let owner = json?.owner ? { userID: context.prefixAddress(json.owner.userID), username: json.owner.username, rawID: json.owner.userID } : null; let trackList = null; if (json?.trackList) { trackList = []; for (let track of json.trackList) { let trackObject = Track.convertJsonToTrack(context, track); if (!trackObject) continue; trackList.push(trackObject); trackCache.updateTrack(trackObject); } } const collection = new Playlist(context, json.collectionID, json.name, owner, trackList); const existingCollection = collectionCache.getCollection(collection.collectionID); if (existingCollection instanceof Playlist) { existingCollection.copyFromOtherPlaylist(collection); return existingCollection; } const output = collectionCache.setCollection(collection); if (output instanceof Playlist) return output; return collection; } checkDeletion() { if (this.isDeleted) throw "Collection is deleted"; } pushToCallbacks() { for (let callback of this.updateCallbacks) { callback(this); } if (this.updateCallbacks.length) this.setLoop(); } isCollectionDeleted() { return this.isDeleted; } registerUpdateCallback(callback) { if (this.updateCallbacks.indexOf(callback) >= 0) return; this.updateCallbacks.push(callback); if (this.updateCallbacks.length == 1) this.setLoop(); } unregisterUpdateCallback(callback) { const index = this.updateCallbacks.indexOf(callback); if (index >= 0) this.updateCallbacks.splice(index, 1); if (!this.updateCallbacks.length && this.checkTimer) { clearTimeout(this.checkTimer); this.checkTimer = null; } } setLoop() { if (this.checkTimer) clearTimeout(this.checkTimer); this.checkTimer = setTimeout(async () => { try { await this.checkForUpdates(0); } catch (e) { } }, this.context.playlistUpdateFrequency * 1000); } async checkForUpdates(outOfDateThreshold) { if (outOfDateThreshold && Date.now() - outOfDateThreshold * 1000 < this.lastChecked) return; if (this.checkTimer) clearTimeout(this.checkTimer); try { const response = await this.context.makeRequest("get", `v1/playlists/${this.rawCollectionID}`); this.lastChecked = Date.now(); if (response.statusCode != 200) throw response; const collection = Playlist.convertJsonToPlaylist(this.context, response.response); this.copyFromOtherPlaylist(collection); if (this.updateCallbacks.length) this.setLoop(); } catch (e) { if (this.updateCallbacks.length) this.setLoop(); throw e; } } getThumbnailUrl() { return `${this.context.getHost()}/v1/playlists/${this.rawCollectionID}/thumbnail`; } } //# sourceMappingURL=Playlist.js.map