Search code examples
react-nativeoauth-2.0expospotify

How to use Spotify 30sec previews with Expo React native app


I have been trying to use the Spotify API in my expo app but every tutorial or wrapper I find doesn't seem to work.

I would specifically like to access the 30-second song previews and track/song searching features.

If anyone could provide some guidance or point me towards a working demo of any kind that would be awesome.

Thanks!


Solution

  • Found parts of the solution in https://docs.expo.dev/guides/authentication/#spotify

    const discovery = {
      authorizationEndpoint: 'https://accounts.spotify.com/authorize',
      tokenEndpoint: 'https://accounts.spotify.com/api/token',
    };
    
    var client_id = ''; // Your client id
    var client_secret = ''; // Your secret
    
    
    export default function spotifyLogin(props) {
        const [request, response, promptAsync] = useAuthRequest(
            {
                clientId: '',
                scopes: ['user-read-email', 'user-read-playback-state', 'playlist-modify-public','playlist-modify-private','playlist-modify-public','playlist-read-private','user-read-recently-played'],
                // In order to follow the "Authorization Code Flow" to fetch token after authorizationEndpoint
                // this must be set to false
                usePKCE: false,
                redirectUri: makeRedirectUri({
                  //scheme: 'your.app'
                  }),
              },
              discovery
        );
      
    React.useEffect(() => {
      if (response?.type === 'success') {
        const { code } = response.params;
        //save code to local storage
        props.saveLogin(code)
        }
    }, [response]);
    
    return (
      <Button
        disabled={!request}
        title="Login"
        onPress={() => {
          promptAsync();
          }}
      />
    );
      }
    
    export const getFirstTokenData = async (code) => {
        var dataToSend = { 
          code: code,
          redirect_uri: makeRedirectUri(),
          grant_type: 'authorization_code'};
        //making data to send on server
        var formBody = [];
        for (var key in dataToSend) {
          var encodedKey = encodeURIComponent(key);
          var encodedValue = encodeURIComponent(dataToSend[key]);
          formBody.push(encodedKey + '=' + encodedValue);
        }
        formBody = formBody.join('&');
        //POST request
        var response = await fetch('https://accounts.spotify.com/api/token', {
          method: 'POST', //Request Type
          body: formBody, //post body
          headers: {
            //Header Defination
            'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
          },
        })
        try{
            return await response.json()
        }catch (error){
            console.log(error)
        }
        
    }
    
    
    
    export const getRefreshTokenData = async (refreshToken) => {
        console.log(refreshToken)
        console.log(refreshToken + " going in for refresh")
        var dataToSend = { 
            refresh_token : refreshToken,
            grant_type: 'refresh_token'};
        //making data to send on server
        var formBody = [];
        for (var key in dataToSend) {
            var encodedKey = encodeURIComponent(key);
            var encodedValue = encodeURIComponent(dataToSend[key]);
            formBody.push(encodedKey + '=' + encodedValue);
        }
        formBody = formBody.join('&');
        //POST request
        var response = await fetch('https://accounts.spotify.com/api/token', {
            method: 'POST', //Request Type
            body: formBody, //post body
            headers: {
            //Header Defination
            'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64')),
            },
        })
        try{
            return await response.json()
        }catch (error){
            console.log(error)
        }
        
    }
    

    The above takes care of auth and getting refresh tokens, below takes care of searching for a track. To get 30 second previews there is a preview property in the return data for getTrack()

    const apiPrefix = 'https://api.spotify.com/v1';
    
    export default async ({
      offset,
      limit,
      q,
      token,
    }) => {
      const uri = `${apiPrefix}/search?type=track&limit=${limit}&offset=${offset}&q=${encodeURIComponent(q)}`;
      console.log('search begin, uri =', uri, 'token =', token);
      const res = await fetch(uri, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${token}`,
        }
      });
      const json = await res.json();
      //console.log('search got json', json);
    
      if (!res.ok) {
        return [];
      }
      return json
      // const {
      //   tracks: {
      //     items,
      //   }
      // } = json;
      // // const items = json.tracks.items;
      // return items.map(item => ({
      //   id: item.id,
      //   title: item.name,
      //   imageUri: item.album.images
      //     ? item.album.images[0].url
      //     : undefined
      // }));
      console.log('search end');
    };
    
    export const getTrack = async(trackID, token) => {
      const uri = `${apiPrefix}/tracks/${trackID}?market=ES`;
    
      const res = await fetch(uri, {
        method: 'GET',
        headers: {
          // Accept: `application/json`,
          // Content-Type: `application/json`,
          Authorization: `Bearer ${token}`,
        }
      });
      const json = await res.json();
      //console.log('search got json', json);
      
      if (!res.ok) {
        return [];
      }
      return json
    }