@manhgdev/spotifyweb
Version:
Spotify library in typescript without using the Spotify Web API. No authentication required with automatic internal token generation.
52 lines (51 loc) • 3.97 kB
JavaScript
import { SpotiflyBase } from "./base.js";
import { Parse } from "./parse.js";
export class SpotiflyPlaylist extends SpotiflyBase {
id = "";
constructor(cookie) {
super(cookie);
}
async create(name) {
const [myProfileId, newPlaylist] = await Promise.all([
this.getMyProfileId(),
this.post("https://spclient.wg.spotify.com/playlist/v2/playlist", `{"ops":[{"kind":6,"updateListAttributes":{"newAttributes":{"values":{"name":"${name}","formatAttributes":[],"pictureSize":[]},"noValue":[]}}}]}`)
]);
await this.post(`https://spclient.wg.spotify.com/playlist/v2/user/${myProfileId}/rootlist/changes`, `{"deltas":[{"ops":[{"kind":2,"add":{"items":[{"uri":"${newPlaylist.uri}","attributes":{"timestamp":"${Date.now()}","formatAttributes":[],"availableSignals":[]}}],"addFirst":true}}],"info":{"source":{"client":5}}}],"wantResultingRevisions":false,"wantSyncResult":false,"nonces":[]}`);
this.id = Parse.uriToId(newPlaylist.uri);
return newPlaylist;
}
async rename(newName) {
return this.post(`https://spclient.wg.spotify.com/playlist/v2/playlist/${this.id}/changes`, `{"deltas":[{"ops":[{"kind":6,"updateListAttributes":{"newAttributes":{"values":{"name":"${newName}","formatAttributes":[],"pictureSize":[]},"noValue":[]}}}],"info":{"source":{"client":5}}}],"wantResultingRevisions":false,"wantSyncResult":false,"nonces":[]}`);
}
async changeDescription(newDescription) {
return this.post(`https://spclient.wg.spotify.com/playlist/v2/playlist/${this.id}/changes`, `{"deltas":[{"ops":[{"kind":6,"updateListAttributes":{"newAttributes":{"values":{"description":"${newDescription}","formatAttributes":[],"pictureSize":[]},"noValue":[]}}}],"info":{"source":{"client":5}}}],"wantResultingRevisions":false,"wantSyncResult":false,"nonces":[]}`);
}
async fetchMetadata(limit = 50) {
return (await this.getPlaylistMetadata(this.id, limit)).data.playlistV2;
}
async fetchContents(limit = 50) {
return (await this.getPlaylistContents(this.id, limit)).data.playlistV2.content.items;
}
async add(...trackUris) {
return this.post("https://api-partner.spotify.com/pathfinder/v1/query", `{"variables":{"uris":${JSON.stringify(trackUris)},"playlistUri":"spotify:playlist:${this.id}","newPosition":{"moveType":"BOTTOM_OF_PLAYLIST","fromUid":null}},"operationName":"addToPlaylist","extensions":{"persistedQuery":{"version":1,"sha256Hash":"200b7618afd05364c4aafb95e2070249ed87ee3f08fc4d2f1d5d04fdf1a516d9"}}}`);
}
async remove(...trackUris) {
const contents = await this.fetchContents();
const uids = [];
contents.forEach(x => { if (trackUris.includes(x.itemV2.data.uri))
uids.push(x.uid); });
return this.post("https://api-partner.spotify.com/pathfinder/v1/query", `{"variables":{"playlistUri":"spotify:playlist:${this.id}","uids":${JSON.stringify(uids)}},"operationName":"removeFromPlaylist","extensions":{"persistedQuery":{"version":1,"sha256Hash":"c0202852f3743f013eb453bfa15637c9da2d52a437c528960f4d10a15f6dfb49"}}}`);
}
async cloneFrom(id, config) {
const metadata = await this.getPlaylistMetadata(id, config?.limit ?? 50);
await this.create(config?.name ?? metadata.data.playlistV2.name);
this.changeDescription(config?.description ?? metadata.data.playlistV2.description);
this.add(...metadata.data.playlistV2.content.items.map(x => x.itemV2.data.uri));
}
async delete() {
const myProfileId = await this.getMyProfileId();
const response = await this.post(`https://spclient.wg.spotify.com/playlist/v2/user/${myProfileId}/rootlist/changes`, `{"deltas":[{"ops":[{"kind":3,"rem":{"items":[{"uri":"spotify:playlist:${this.id}"}],"itemsAsKey":true}}],"info":{"source":{"client":5}}}],"wantResultingRevisions":false,"wantSyncResult":false,"nonces":[]}`);
this.id = "";
return response;
}
}