Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion server/controllers/media/RemoveMedia.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import redisObj from "../../redis-sse/index.js";
import { Video } from "../../types/index.js";
import { getCredentials, getDroppedAsset } from "../../utils/index.js";
import { getCredentials, getDroppedAsset, World } from "../../utils/index.js";
import { Request, Response } from "express";
import { DroppedAssetMediaType } from "@rtsdk/topia";
import { getAvailableVideos } from "../../utils/youtube/index.js";

export default async function RemoveMedia(req: Request, res: Response) {
const credentials = getCredentials(req.query);
Expand All @@ -21,6 +23,7 @@ export default async function RemoveMedia(req: Request, res: Response) {
const jukeboxUpdate: {
catalog?: Video[];
queue?: string[];
nowPlaying?: string;
} = {};

if (type === "catalog") {
Expand All @@ -32,6 +35,65 @@ export default async function RemoveMedia(req: Request, res: Response) {
jukeboxUpdate.queue = jukeboxAsset.dataObject.queue.filter((videoId: string) => !videoIds.includes(videoId));
}

// If the currently playing song was removed, stop it and skip to next
const nowPlayingRemoved = videoIds.includes(jukeboxAsset.dataObject.nowPlaying);
if (nowPlayingRemoved) {
const remainingQueue = jukeboxUpdate.queue ?? jukeboxAsset.dataObject.queue;
const remainingCatalog = jukeboxUpdate.catalog ?? jukeboxAsset.dataObject.catalog;

// Find next available song from the remaining queue and catalog
let nextVideo: Video | null = null;
let nextIndex = -1;

if (remainingQueue.length > 0 && remainingCatalog.length > 0) {
const availableVideoIds = await getAvailableVideos(remainingCatalog);
for (let i = 0; i < remainingQueue.length; i++) {
const video = remainingCatalog.find((v: Video) => v.id.videoId === remainingQueue[i]);
if (video && availableVideoIds.includes(video.id.videoId)) {
nextVideo = video;
nextIndex = i;
break;
}
}
}

if (nextVideo) {
// Play the next song
const mediaLink = `https://www.youtube.com/watch?v=${nextVideo.id.videoId}`;
await jukeboxAsset.updateMediaType({
mediaLink,
isVideo:
(jukeboxAsset.dataObject.settings?.mode ?? (process.env.AUDIO_ONLY ? "jukebox" : "karaoke")) === "karaoke",
mediaName: "Jukebox",
mediaType: DroppedAssetMediaType.LINK,
audioSliderVolume: (jukeboxAsset as any).audioSliderVolume || 10,
audioRadius: (jukeboxAsset as any).audioRadius || 2,
portalName: "",
syncUserMedia: true,
});

jukeboxUpdate.nowPlaying = nextVideo.id.videoId;
jukeboxUpdate.queue = remainingQueue.slice(nextIndex + 1);

const world = World.create(urlSlug, { credentials });
world
.triggerParticle({
name: "musicNote_float",
duration: 10,
position: {
x: jukeboxAsset.position.x,
y: jukeboxAsset.position.y - 130,
},
})
.catch(() => console.error("Cannot trigger particle"));
} else {
// No next song — stop media
await jukeboxAsset.updateMediaType({ mediaType: DroppedAssetMediaType.NONE } as any);
jukeboxUpdate.nowPlaying = "-1";
jukeboxUpdate.queue = [];
}
}

await jukeboxAsset.updateDataObject(
{
...jukeboxAsset.dataObject,
Expand All @@ -45,6 +107,16 @@ export default async function RemoveMedia(req: Request, res: Response) {
},
);

// Publish appropriate SSE event
if (nowPlayingRemoved) {
redisObj.publish(`${process.env.INTERACTIVE_KEY}_JUKEBOX`, {
assetId: jukeboxAsset.id,
videoId: jukeboxUpdate.nowPlaying !== "-1" ? jukeboxUpdate.nowPlaying : "-1",
nextUpId: jukeboxUpdate.queue && jukeboxUpdate.queue.length > 0 ? jukeboxUpdate.queue[0] : null,
event: "nowPlaying",
});
}

redisObj.publish(`${process.env.INTERACTIVE_KEY}_JUKEBOX`, {
assetId: jukeboxAsset.id,
videos: videoIds,
Expand Down
Loading