Skip to content

Commit

Permalink
notify service when playing track is not successful
Browse files Browse the repository at this point in the history
  • Loading branch information
xiduzo committed Jan 28, 2024
1 parent 3bc0ba3 commit 5f5aa30
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 19 deletions.
16 changes: 11 additions & 5 deletions packages/api/src/service/FissaService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import {
biasSort,
differenceInMilliseconds,
FissaIsPaused,
ForceStopFissa,
NoNextTrack,
NotAbleToAccessSpotify,
NotTheHost,
randomize,
sleep,
sortFissaTracksOrder,
UnableToCreateFissa,
type SpotifyService,
} from "@fissa/utils";

Expand All @@ -31,7 +33,7 @@ export class FissaService extends ServiceWithContext {
};

create = async (tracks: { trackId: string; durationMs: number }[], userId: string) => {
if (!tracks[0]) throw new Error("No tracks");
if (!tracks[0]) throw new UnableToCreateFissa("No tracks");

const { access_token } = await this.db.account.findFirstOrThrow({
where: { userId },
Expand Down Expand Up @@ -66,7 +68,7 @@ export class FissaService extends ServiceWithContext {
}
} while (!fissa && tries < 50);

if (!fissa) throw new Error("Failed to create fissa");
if (!fissa) throw new UnableToCreateFissa("No unique pin found");

if (tracks.length <= TRACKS_BEFORE_ADDING_RECOMMENDATIONS) {
await this.addRecommendedTracks(fissa.pin, tracks, access_token);
Expand Down Expand Up @@ -144,7 +146,7 @@ export class FissaService extends ServiceWithContext {
try {
const isPlaying = await this.spotifyService.isStillPlaying(access_token);

if (!instantPlay && (!currentlyPlayingId || !isPlaying)) throw new Error("Stop fissa");
if (!instantPlay && (!currentlyPlayingId || !isPlaying)) throw new ForceStopFissa();

const nextTracks = this.getNextTracks(tracks, currentlyPlayingId);
if (!nextTracks[0]) throw new NoNextTrack();
Expand Down Expand Up @@ -217,15 +219,19 @@ export class FissaService extends ServiceWithContext {
{ trackId, durationMs }: Pick<Track, "trackId" | "durationMs">,
accessToken: string,
) => {
await this.spotifyService.playTrack(accessToken, trackId);
const playing = await this.spotifyService.playTrack(accessToken, trackId);

return this.db.fissa.update({
await this.db.fissa.update({
where: { pin },
data: {
currentlyPlaying: { connect: { pin_trackId: { pin, trackId } } },
expectedEndTime: addMilliseconds(new Date(), durationMs),
},
});

// TODO: We should ban this track from being played again
// as apparently it's not playable
if (!playing) return this.playNextTrack(pin);
};

private getNextTracks = (tracks: Track[], currentlyPlayingId?: string | null) => {
Expand Down
28 changes: 28 additions & 0 deletions packages/utils/classes/Error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,31 @@ export class NoNextTrack extends Error {
this.name = NoNextTrack.name;
}
}

export class UnableToPlayTrack extends Error {
public constructor(message = "Unable to play track") {
super(message);
this.name = UnableToPlayTrack.name;
}
}

export class NotImplemented extends Error {
public constructor(message = "Not implemented") {
super(message);
this.name = NotImplemented.name;
}
}

export class ForceStopFissa extends Error {
public constructor(message = "Forcefully stop fissa") {
super(message);
this.name = ForceStopFissa.name;
}
}

export class UnableToCreateFissa extends Error {
public constructor(message = "Unable to create fissa") {
super(message);
this.name = UnableToCreateFissa.name;
}
}
6 changes: 4 additions & 2 deletions packages/utils/classes/Toaster.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { NotImplemented } from "./Error";

export class Toaster {
protected defaultIcon(type: ToastType) {
switch (type) {
Expand Down Expand Up @@ -31,11 +33,11 @@ export class Toaster {
}

protected show(_: ToasterProps) {
throw new Error("Not implemented");
throw new NotImplemented();
}

public hide() {
throw new Error("Not implemented");
throw new NotImplemented();
}
}

Expand Down
29 changes: 17 additions & 12 deletions packages/utils/services/SpotifyService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import SpotifyWebApi from "spotify-web-api-node";

import { UnableToPlayTrack } from "../classes";
import { sleep } from "../sleep";

const TRIES_TO_PLAY = 3;

export class SpotifyService {
private spotify = new SpotifyWebApi({
clientId: process.env.SPOTIFY_CLIENT_ID,
Expand Down Expand Up @@ -29,31 +32,33 @@ export class SpotifyService {
return body.is_playing;
};

playTrack = async (accessToken: string, trackId: string, triesLeft = 3): Promise<unknown> => {
playTrack = async (accessToken: string, trackId: string, trial = 0): Promise<boolean> => {
this.spotify.setAccessToken(accessToken);

try {
await this.spotify.play({ uris: [`spotify:track:${trackId}`] });
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
if ((e as { body: { error: { reason: string } } }).body.error.reason === "NO_ACTIVE_DEVICE") {
await sleep(500); // Arbitrary wait time, sue me
const { body } = await this.spotify.getMyCurrentPlaybackState();
return Promise.resolve(body.is_playing);
} catch (e: unknown) {
if (trial > TRIES_TO_PLAY) throw new UnableToPlayTrack("Could not play track");

const error = e as { body: { error: { reason: string } } };
const reason = error?.body?.error?.reason ?? "";
if (reason === "NO_ACTIVE_DEVICE") {
console.log("No active device found, trying to transfer playback");
const { body } = await this.spotify.getMyDevices();

const firstDevice = body.devices[0];

if (!firstDevice?.id) throw new Error("No playback device(s) found");

if (triesLeft === 0) throw new Error("Could not transfer playback");
if (!firstDevice?.id) throw new UnableToPlayTrack("No playback device(s) found");

await this.spotify.transferMyPlayback([firstDevice.id]);
await sleep(250 + (3 % (triesLeft + 1)));
return this.playTrack(accessToken, trackId, triesLeft - 1);
await sleep(500); // Arbitrary wait time, sue me
return this.playTrack(accessToken, trackId, trial + 1);
}

console.error(JSON.stringify(e));

return Promise.resolve();
return Promise.resolve(false);
}
};

Expand Down

1 comment on commit 5f5aa30

@vercel
Copy link

@vercel vercel bot commented on 5f5aa30 Jan 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.