Spaces:
Runtime error
Runtime error
Update files/constituent-server.js
Browse files- files/constituent-server.js +11 -4
files/constituent-server.js
CHANGED
|
@@ -969,8 +969,10 @@ function enqueueToStream(streamId, songInfo) {
|
|
| 969 |
stream.queue.push(songInfo);
|
| 970 |
stream.lastActivity = Date.now();
|
| 971 |
const position = stream.queue.length;
|
| 972 |
-
|
| 973 |
-
|
|
|
|
|
|
|
| 974 |
if (!hlsState[streamId] || hlsState[streamId].totalDuration > 0) {
|
| 975 |
if (hlsState[streamId]) {
|
| 976 |
const hlsDir = path.join(HLS_DIR, streamId);
|
|
@@ -1057,6 +1059,8 @@ async function showplayEnqueueLink(streamId, pendingLink, pendingTitle, thumbnai
|
|
| 1057 |
streams[streamId] = { queue: [], songStartTime: null, streamTimeOffset: 0, users: new Map(), ownerId: streamId, lastActivity: Date.now(), isActive: false };
|
| 1058 |
}
|
| 1059 |
streams[streamId]._showplayInProgress = (streams[streamId]._showplayInProgress || 0) + 1;
|
|
|
|
|
|
|
| 1060 |
|
| 1061 |
// Notify listeners that download is starting
|
| 1062 |
io.to(`stream:${streamId}`).emit('message', { type: 'showplay_progress', stage: 'downloading', title: pendingTitle });
|
|
@@ -1095,8 +1099,6 @@ async function showplayEnqueueLink(streamId, pendingLink, pendingTitle, thumbnai
|
|
| 1095 |
throw new Error(`Video too long. Max 6 hours.`);
|
| 1096 |
}
|
| 1097 |
|
| 1098 |
-
if (streams[streamId]) streams[streamId]._showplayInProgress = Math.max(0, (streams[streamId]._showplayInProgress || 1) - 1);
|
| 1099 |
-
|
| 1100 |
const effectivePoster = tmdbInfo?.poster || thumbnail || DEFAULT_ARTWORK;
|
| 1101 |
const songInfo = {
|
| 1102 |
fileName,
|
|
@@ -1113,7 +1115,10 @@ async function showplayEnqueueLink(streamId, pendingLink, pendingTitle, thumbnai
|
|
| 1113 |
isShowplay: true,
|
| 1114 |
};
|
| 1115 |
|
|
|
|
|
|
|
| 1116 |
enqueueToStream(streamId, songInfo);
|
|
|
|
| 1117 |
return { title: songInfo.meta.title, duration: mediaMeta.duration, thumbnail: effectivePoster };
|
| 1118 |
}
|
| 1119 |
|
|
@@ -1168,6 +1173,8 @@ setInterval(() => {
|
|
| 1168 |
const now = Date.now(), toDelete = [];
|
| 1169 |
for (const streamId in streams) {
|
| 1170 |
const stream = streams[streamId];
|
|
|
|
|
|
|
| 1171 |
if ((!stream.users || stream.users.size === 0) && (now - (stream.lastActivity || 0)) > STREAM_CLEANUP_INTERVAL) {
|
| 1172 |
toDelete.push(streamId);
|
| 1173 |
}
|
|
|
|
| 969 |
stream.queue.push(songInfo);
|
| 970 |
stream.lastActivity = Date.now();
|
| 971 |
const position = stream.queue.length;
|
| 972 |
+
|
| 973 |
+
// Start encoding if the stream is idle (no active content).
|
| 974 |
+
// Showplay items are always appended — they must never evict existing content.
|
| 975 |
+
if (!stream.isActive && position === 1) {
|
| 976 |
if (!hlsState[streamId] || hlsState[streamId].totalDuration > 0) {
|
| 977 |
if (hlsState[streamId]) {
|
| 978 |
const hlsDir = path.join(HLS_DIR, streamId);
|
|
|
|
| 1059 |
streams[streamId] = { queue: [], songStartTime: null, streamTimeOffset: 0, users: new Map(), ownerId: streamId, lastActivity: Date.now(), isActive: false };
|
| 1060 |
}
|
| 1061 |
streams[streamId]._showplayInProgress = (streams[streamId]._showplayInProgress || 0) + 1;
|
| 1062 |
+
// Keep the stream warm so the inactivity cleanup never evicts it mid-download
|
| 1063 |
+
streams[streamId].lastActivity = Date.now();
|
| 1064 |
|
| 1065 |
// Notify listeners that download is starting
|
| 1066 |
io.to(`stream:${streamId}`).emit('message', { type: 'showplay_progress', stage: 'downloading', title: pendingTitle });
|
|
|
|
| 1099 |
throw new Error(`Video too long. Max 6 hours.`);
|
| 1100 |
}
|
| 1101 |
|
|
|
|
|
|
|
| 1102 |
const effectivePoster = tmdbInfo?.poster || thumbnail || DEFAULT_ARTWORK;
|
| 1103 |
const songInfo = {
|
| 1104 |
fileName,
|
|
|
|
| 1115 |
isShowplay: true,
|
| 1116 |
};
|
| 1117 |
|
| 1118 |
+
// Enqueue BEFORE decrementing _showplayInProgress so the cleanup timer
|
| 1119 |
+
// never sees a zero-count window between "file ready" and "item in queue".
|
| 1120 |
enqueueToStream(streamId, songInfo);
|
| 1121 |
+
if (streams[streamId]) streams[streamId]._showplayInProgress = Math.max(0, (streams[streamId]._showplayInProgress || 1) - 1);
|
| 1122 |
return { title: songInfo.meta.title, duration: mediaMeta.duration, thumbnail: effectivePoster };
|
| 1123 |
}
|
| 1124 |
|
|
|
|
| 1173 |
const now = Date.now(), toDelete = [];
|
| 1174 |
for (const streamId in streams) {
|
| 1175 |
const stream = streams[streamId];
|
| 1176 |
+
// Never evict a stream that is still actively downloading/encoding media
|
| 1177 |
+
if (stream._showplayInProgress > 0) continue;
|
| 1178 |
if ((!stream.users || stream.users.size === 0) && (now - (stream.lastActivity || 0)) > STREAM_CLEANUP_INTERVAL) {
|
| 1179 |
toDelete.push(streamId);
|
| 1180 |
}
|