Skip to content

Commit

Permalink
🥅 Check if user deleted playlist without 403 code
Browse files Browse the repository at this point in the history
  • Loading branch information
bkeys818 committed Jul 5, 2023
1 parent 957e6d9 commit 3d41048
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 60 deletions.
38 changes: 18 additions & 20 deletions functions/src/spotify/error.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import type { Response } from 'node-fetch'

export const handleRepsonse = async <T>(method: () => Promise<Response>): Promise<T> => {
try {
const res = await method()
if (res.status < 300) {
if (res.headers.get('content-type')?.startsWith('application/json'))
return await res.json()
else return true as T
} else {
let error: any
try {
error = (await res.json()).error
} catch {
error = { status: res.status, statusText: res.statusText }
}
throw error;
}
} catch (error) {
throw error
}
try {
const res = await method()
if (res.status < 300) {
if (res.headers.get('content-type')?.startsWith('application/json'))
return await res.json()
else return true as T
} else {
let error: any
try {
error = (await res.json()).error
} catch {
error = { status: res.status, statusText: res.statusText }
}
throw error
}
} catch (error) {
throw error
}
}

export class PlaylistDeletedError extends Error {}
27 changes: 14 additions & 13 deletions functions/src/spotify/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { handleRepsonse, PlaylistDeletedError } from './error'
import { handleRepsonse } from './error'
import fetch, { BodyInit } from 'node-fetch'
import { isObjWith } from '../utils'

export { PlaylistDeletedError }

export class Spotify {
private credentials: Credentials
Expand Down Expand Up @@ -119,20 +116,18 @@ export class Spotify {
}

createPlaylist(userId: string, details: PlaylistDetails) {
return this.request<SpotifyApi.PlaylistObjectFull>(`users/${userId}/playlists`, 'POST', details)
return this.request<SpotifyApi.PlaylistObjectFull>(
`users/${userId}/playlists`,
'POST',
details
)
}

async changePlaylistDetails(playlistId: string, details: Partial<PlaylistDetails>) {
try {
return await this.request<void>('playlists/' + playlistId, 'PUT', details)
} catch (error) {
if (isObjWith(error, 'status') && error.status == 403)
throw new PlaylistDeletedError()
}
changePlaylistDetails(playlistId: string, details: Partial<PlaylistDetails>) {
return this.request<void>('playlists/' + playlistId, 'PUT', details)
}

getPlaylistTracks(playlistId: string) {

return this.requestAll<SpotifyApi.PlaylistTrackObject>(`playlists/${playlistId}/tracks`)
}

Expand All @@ -151,6 +146,12 @@ export class Spotify {
{ uris }
)
}

usersFollowPlaylist(playlistId: string, userIds: string[]) {
return this.request<boolean[]>(`playlists/${playlistId}/followers/contains`, 'GET', {
ids: userIds.join()
})
}
}

type Primative = string | number | boolean | undefined
Expand Down
35 changes: 17 additions & 18 deletions functions/src/tools/public-liked-songs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as functions from 'firebase-functions'
import { db } from '../firestore'
import { Spotify, PlaylistDeletedError } from '../spotify'
import { Spotify } from '../spotify'
import { forEvery } from '../utils'
import { secrets } from '../env'

Expand Down Expand Up @@ -36,10 +36,12 @@ export const createPublicLikedSongs = functions
docData = doc.data() as Document
}

const user = await spotify.getMe()

// Don't have playlist id
if (!docData.playlist_id) {
// check to see if playlist already exists
const [playlists, user] = await Promise.all([spotify.getMyPlaylists(), spotify.getMe()])
const playlists = await spotify.getMyPlaylists()
const playlistName = name(user.display_name)
for (const playlist of playlists) {
if (playlist.name == playlistName) docData.playlist_id = playlist.id
Expand All @@ -56,16 +58,17 @@ export const createPublicLikedSongs = functions
await ref.update({ playlist_id: docData.playlist_id })
}

if (!(await spotify.usersFollowPlaylist(docData.playlist_id, [user.id]))[0]) {
await ref.delete()
throw new functions.https.HttpsError(
'not-found',
'You may have deleted the synced playlist. Refresh to restore it.'
)
}

try {
return await update(spotify, docData.playlist_id)
} catch (error) {
if (error instanceof PlaylistDeletedError) {
await ref.delete()
throw new functions.https.HttpsError(
'not-found',
'Synced playlist was deleted. Refresh to Create a new one.'
)
}
let msg = 'Spotify Error'
functions.logger.warn(error)
if (typeof error == 'object' && error && 'statusCode' in error) {
Expand Down Expand Up @@ -96,15 +99,11 @@ export const syncPublicLikedSongs = functions
})
await spotify.refreshAccessToken()
if (data.playlist_id) {
try {
return await update(spotify, data.playlist_id)
} catch (error) {
if (error instanceof PlaylistDeletedError)
return await ref.delete()
else throw error
}
}
else return
const user = await spotify.getMe()
if (!(await spotify.usersFollowPlaylist(data.playlist_id, [user.id]))[0])
return await ref.delete()
else return await update(spotify, data.playlist_id)
} else return await ref.delete()
})
)
})
Expand Down
9 changes: 0 additions & 9 deletions functions/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,3 @@ export async function forEvery<T>(
await method(items.slice(i, i + limit))
}
}

export function isObjWith<K extends string>(value: unknown, ...keys: K[]): value is { [k in K]: any } {
if (typeof value == 'object' && value) {
for (const key of keys)
if (!(key in value)) return false
return true
}
return false;
}

0 comments on commit 3d41048

Please sign in to comment.