Skip to content

Commit

Permalink
refactor: minor improvements
Browse files Browse the repository at this point in the history
Release-As: 0.2.2
  • Loading branch information
dirkluijk committed Jan 4, 2025
1 parent 190a80e commit 38d3e7a
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 87 deletions.
14 changes: 9 additions & 5 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Command } from "@cliffy/command";
import denoJSON from "./deno.json" with { type: "json" };
import { defaultOptions, textToPlaylist } from './src/text-to-playlist.ts';
import { defaultOptions, textToPlaylist } from "./src/text-to-playlist.ts";

export { textToPlaylist } from "./src/text-to-playlist.ts";
export type { Options, Result } from "./src/text-to-playlist.ts";
Expand Down Expand Up @@ -31,15 +31,19 @@ if (import.meta.main) {
.arguments("<inputFileOrText>")
.parse(Deno.args);

const { tracksAdded, tracksRemoved } = await textToPlaylist(args[0], options.playlist, {
...options,
const [input] = args;
const { playlist, removeDuplicates, removeOtherTracks, debug } = options;
const { tracksAdded, tracksRemoved } = await textToPlaylist(input, playlist, {
removeDuplicates,
removeOtherTracks,
debug,
});

console.log(
`Added ${tracksAdded.length} tracks to playlist: ${options.playlist}`,
`Added ${tracksAdded.length} tracks to playlist: ${playlist}`,
);

console.log(
`Added ${tracksRemoved.length} tracks to playlist: ${options.playlist}`,
`Added ${tracksRemoved.length} tracks to playlist: ${playlist}`,
);
}
162 changes: 80 additions & 82 deletions src/text-to-playlist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,96 +13,94 @@ import { retrieveAccessToken } from "./utils/spotify-authorization.ts";
* @param options Additional options.
*/
export async function textToPlaylist(
textOrFile: string,
playlistUrl: string,
options: Partial<Options> = {},
textOrFile: string,
playlistUrl: string,
options: Partial<Options> = {},
): Promise<Result> {
const input = await exists(textOrFile) ? await Deno.readTextFile(textOrFile) : textOrFile;
const mergedOptions: Options = { ...defaultOptions, ...options, playlistUrl };
const accessToken = await retrieveAccessToken();
const playlist = Playlist.fromUrl(mergedOptions.playlistUrl);
const spotifyClient = new SpotifyClient(accessToken);

// Read input and extract Spotify track links
const SPOTIFY_TRACK_PATTERN = /https:\/\/open\.spotify\.com\/track\/\w+/g;
const trackUrls = mergedOptions.removeDuplicates
? Array.from(
new Set(input.match(SPOTIFY_TRACK_PATTERN) ?? []),
)
: input.match(SPOTIFY_TRACK_PATTERN) ?? [];

const tracks = trackUrls.map(Track.fromUrl);

if (mergedOptions.debug) {
console.debug("Found tracks:");
console.table(tracks.map((it) => it.toUrl()));
}

const currentTracks = await new PageIterator(
(offset) => getPlaylistTracks(spotifyClient, playlist.id, { limit: 50, offset }),
).collect().then((tracks) => tracks.map(({ track }) => new Track(track.id)));

// add everything that is in `tracks` but not in `currentTracks`
const trackUrisToAdd = withoutAll(
tracks.map((it) => it.toUri()),
currentTracks.map((it) => it.toUri()),
);

for (const batch of chunk(trackUrisToAdd, 50)) {
await addItemsToPlaylist(spotifyClient, playlist.id, batch);
}

// delete everything that is in `currentTrackURIs` but not in `trackURIs`
const trackURIsToRemove = options.removeOtherTracks
? withoutAll(
currentTracks.map((it) => it.toUri()),
tracks.map((it) => it.toUri()),
)
: [];

for (const batch of chunk(trackURIsToRemove, 50)) {
await removePlaylistItems(spotifyClient, playlist.id, batch);
}

return {
tracksAdded: trackUrisToAdd,
tracksRemoved: trackURIsToRemove,
};
const input = await exists(textOrFile) ? await Deno.readTextFile(textOrFile) : textOrFile;
const mergedOptions: Options = { ...defaultOptions, ...options };
const accessToken = await retrieveAccessToken();
const playlist = Playlist.fromUrl(playlistUrl);
const spotifyClient = new SpotifyClient(accessToken);

// Read input and extract Spotify track links
const SPOTIFY_TRACK_PATTERN = /https:\/\/open\.spotify\.com\/track\/\w+/g;
const trackUrls = mergedOptions.removeDuplicates
? Array.from(
new Set(input.match(SPOTIFY_TRACK_PATTERN) ?? []),
)
: input.match(SPOTIFY_TRACK_PATTERN) ?? [];

const tracks = trackUrls.map(Track.fromUrl);

if (mergedOptions.debug) {
console.debug("Found tracks:");
console.table(tracks.map((it) => it.toUrl()));
}

const currentTracks = await new PageIterator(
(offset) => getPlaylistTracks(spotifyClient, playlist.id, { limit: 50, offset }),
).collect().then((tracks) => tracks.map(({ track }) => new Track(track.id)));

// add everything that is in `tracks` but not in `currentTracks`
const trackUrisToAdd = withoutAll(
tracks.map((it) => it.toUri()),
currentTracks.map((it) => it.toUri()),
);

for (const batch of chunk(trackUrisToAdd, 50)) {
await addItemsToPlaylist(spotifyClient, playlist.id, batch);
}

// delete everything that is in `currentTrackURIs` but not in `trackURIs`
const trackURIsToRemove = options.removeOtherTracks
? withoutAll(
currentTracks.map((it) => it.toUri()),
tracks.map((it) => it.toUri()),
)
: [];

for (const batch of chunk(trackURIsToRemove, 50)) {
await removePlaylistItems(spotifyClient, playlist.id, batch);
}

return {
tracksAdded: trackUrisToAdd,
tracksRemoved: trackURIsToRemove,
};
}

export type Options = {
/**
* URL to Spotify playlist.
*/
playlistUrl: string;

/**
* Whether to filter out duplicates from input.
*/
removeDuplicates: boolean;

/**
* Whether to remove tracks from playlist that do not exit in input
*/
removeOtherTracks: boolean;

debug: boolean;
/**
* Whether to filter out duplicates from input.
*/
removeDuplicates: boolean;

/**
* Whether to remove tracks from playlist that do not exit in input.
*/
removeOtherTracks: boolean;

/**
* Outputs debugging logs.
*/
debug: boolean;
};

export type Result = {
/**
* Track URIs that were added.
*/
tracksAdded: string[];

/**
* Track URIs that were removed.
*/
tracksRemoved: string[];
/**
* Track URIs that were added.
*/
tracksAdded: string[];

/**
* Track URIs that were removed.
*/
tracksRemoved: string[];
};

export const defaultOptions = {
debug: false,
removeDuplicates: true,
removeOtherTracks: false,
debug: false,
removeDuplicates: true,
removeOtherTracks: false,
} satisfies Partial<Options>;

0 comments on commit 38d3e7a

Please sign in to comment.