Build an Apple Music to Spotify Converter for Raycast

I like to share my music with others. And, as an Apple Music listener, I often find myself manually searching Spotify’s library to get a sharable link compatible with others’ preferred music apps. After unsuccessful attempts to convert my friends to Apple Music users, I decided it was time to automate the process. Raycast is a multifunctional app launcher for macOS with a multitude of user-created extensions. We can use the Raycast API to create our own extension that takes the current track in Apple Music and generates a sharable Spotify link.

Getting started

First, open Raycast and run the “Create Extension” command. We’ll use the “Script” template, which bootstraps a simple extension to run a script when we open it. Give the extension a name, description, and location of your choice. In the “Command Name” field, type “Get Spotify Link”.

Build an Apple Music to Spotify Converter for Raycast

Next, open the created repository and run npm i to install the required dependencies. In src/index.ts, you’ll notice a sample script that copies the current date to the clipboard. Start the Raycast development server using npm run dev, run the “Get Spotify Link” command, and see that it works as expected.

Getting the current track

The first step of our script is to get the current track from Apple Music. To do this, we’ll use some old-school AppleScript. First, install the run-applescript package using npm:

npm i run-applescript

Next, we’ll create a helper called getPropertyOfCurrentTrack and implement it as follows.


const getPropertyOfCurrentTrack = async (property: string) => {
  return await runAppleScript(`
    tell application "Music"
      get ${property} of current track
    end tell
  `);
};

Then, inside of main, we can invoke our helper:


const trackName = await getPropertyOfCurrentTrack("name");
const artistName = await getPropertyOfCurrentTrack("artist");
const albumName = await getPropertyOfCurrentTrack("album");

console.log({ trackName, artistName, albumName });

Try running the command now. You’ll see that it correctly prints out the current track, artist, and album to the console. We’ll use these as our inputs to the Spotify search.

Searching Spotify for the track

Next, we’ll install the spotify-web-api-node package to access Spotify’s API from our script:

npm i spotify-web-api-node @types/spotify-web-api-node

Following the package documentation, we’ll initialize the Spotify client using secrets retrieved from the Spotify developer dashboard. We’ll encapsulate this in a function called initializeSpotifyApi. (Make sure to define SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET somewhere outside of this function.)


const initializeSpotifyApi = async (): Promise => {
  const credentials = {
    clientId: SPOTIFY_CLIENT_ID,
    clientSecret: SPOTIFY_CLIENT_SECRET,
  }; 

  const spotifyApi = new SpotifyWebApi(credentials);

  const data = await spotifyApi.clientCredentialsGrant();
  spotifyApi.setAccessToken(data.body["access_token"]);

  return spotifyApi;
};

In main, we’ll initialize our Spotify client and call its searchTracks method.


const spotify = await initializeSpotifyApi();

const tracksResponse = await spotify.searchTracks(`track:${trackName} artist:${artistName} album:${albumName}`);

const tracks = tracksResponse.body.tracks?.items || [];

console.log(tracks)

Running the program now, we should see a list of Spotify tracks that match the name, artist, and album of the current track in Apple Music.

Buttoning it up

Finally, we’ll check to see whether the program found the track and, if so, copy its URL to the clipboard.


if (tracks.length === 0) {
  await showHUD("No tracks found");
} else {
  const url = tracks[0].external_urls.spotify;
  await Clipboard.copy(url);
  await showHUD("Copied URL to clipboard");
}

You may also notice that the script currently crashes if the Music app isn’t open, or if no track is playing. To mitigate this, simply wrap the contents of main in a try/catch block.

Now you’ve built a functioning Apple-to-Spotify music converter! From here, you can explore more options like sharing an album, creating a playlist, or even converting from Spotify back to Apple Music.

This should give you a good framework for building your own Raycast extensions. You can also publish your extensions to the Raycast Store for others to use.

What will you create?

Conversation
  • Mislav says:

    Hi, thank you for sharing this useful Raycast extension tutorial!

    I went over the code examples and I would just like to suggest correcting some JavaScript anti-patterns so that readers don’t repeat them in their code.

    First, the async function `getPropertyOfCurrentTrack` isn’t really async in its current implementation since it does `return await`. If the implementation is to be async, it could do just `return`, i.e. be allowed to return a Promise, which would then allow the caller of `getPropertyOfCurrentTrack` to perform `await` as needed.

    Second, the three invocations necessary to fetch trackName, artistName, and albumName are all done serially with each having `await`, but the entire point of async/await feature is that operations like these could be performed in parallel. The block could be rewritten like this:

    “`ts
    const [trackName, artistName, albumName] = await Promise.all(
    getPropertyOfCurrentTrack(“name”),
    getPropertyOfCurrentTrack(“artist”),
    getPropertyOfCurrentTrack(“album”),
    )
    “`

  • Comments are closed.