channel groups
This commit is contained in:
@@ -137,12 +137,91 @@ App.videos = App.videos || {};
|
||||
});
|
||||
};
|
||||
|
||||
// Each channel in a group sends back a different number of videos per
|
||||
// page, so a small per-channel count keeps any one channel from
|
||||
// dominating a single interleaved batch.
|
||||
const GROUP_CHANNEL_PAGE_SIZE = 4;
|
||||
|
||||
// Fetches one page from every channel in a group and zips the results
|
||||
// together round-robin so the feed alternates between sources instead of
|
||||
// running through one channel's videos before moving to the next.
|
||||
App.videos.loadGroupVideos = async function(session) {
|
||||
const group = session.channel;
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const query = searchInput ? searchInput.value : "";
|
||||
|
||||
if (!state.groupCursors || state.groupCursors.groupId !== group.id || state.groupCursors.query !== query) {
|
||||
state.groupCursors = {
|
||||
groupId: group.id,
|
||||
query: query,
|
||||
channels: group.channelIds.map((id) => ({ id, page: 1, hasNextPage: true }))
|
||||
};
|
||||
}
|
||||
|
||||
const active = state.groupCursors.channels.filter((cursor) => cursor.hasNextPage);
|
||||
if (active.length === 0) {
|
||||
state.hasNextPage = false;
|
||||
App.videos.updateLoadMoreState();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
state.isLoading = true;
|
||||
App.videos.updateLoadMoreState();
|
||||
state.currentLoadController = new AbortController();
|
||||
|
||||
const results = await Promise.all(active.map(async (cursor) => {
|
||||
const response = await fetch('/api/videos', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
channel: cursor.id,
|
||||
query: query || "",
|
||||
page: cursor.page,
|
||||
perPage: GROUP_CHANNEL_PAGE_SIZE,
|
||||
server: session.server
|
||||
}),
|
||||
signal: state.currentLoadController.signal
|
||||
});
|
||||
const data = await response.json();
|
||||
const items = data && Array.isArray(data.items) ? data.items : [];
|
||||
cursor.page++;
|
||||
cursor.hasNextPage = items.length > 0 && (data && data.pageInfo ? data.pageInfo.hasNextPage !== false : true);
|
||||
return items;
|
||||
}));
|
||||
|
||||
const interleaved = [];
|
||||
const maxLen = results.reduce((max, items) => Math.max(max, items.length), 0);
|
||||
for (let i = 0; i < maxLen; i++) {
|
||||
results.forEach((items) => {
|
||||
if (items[i]) interleaved.push(items[i]);
|
||||
});
|
||||
}
|
||||
|
||||
App.videos.renderVideos({ items: interleaved });
|
||||
state.hasNextPage = state.groupCursors.channels.some((cursor) => cursor.hasNextPage);
|
||||
App.videos.ensureViewportFilled();
|
||||
} catch (err) {
|
||||
if (err.name !== 'AbortError') {
|
||||
console.error("Failed to load group videos:", err);
|
||||
}
|
||||
} finally {
|
||||
state.isLoading = false;
|
||||
state.currentLoadController = null;
|
||||
App.videos.updateLoadMoreState();
|
||||
}
|
||||
};
|
||||
|
||||
// Fetches the next page of videos and renders them into the grid.
|
||||
App.videos.loadVideos = async function() {
|
||||
const session = App.storage.getSession();
|
||||
if (!session) return;
|
||||
if (!session || !session.channel) return;
|
||||
if (state.isLoading || !state.hasNextPage) return;
|
||||
|
||||
if (session.channel.isGroup) {
|
||||
return App.videos.loadGroupVideos(session);
|
||||
}
|
||||
|
||||
const searchInput = document.getElementById('search-input');
|
||||
const query = searchInput ? searchInput.value : "";
|
||||
|
||||
@@ -338,6 +417,7 @@ App.videos = App.videos || {};
|
||||
state.hasNextPage = true;
|
||||
state.renderedVideoIds.clear();
|
||||
state.loadedVideos = [];
|
||||
state.groupCursors = null;
|
||||
const grid = document.getElementById('video-grid');
|
||||
if (grid) grid.innerHTML = "";
|
||||
if (App.feed && typeof App.feed.reset === 'function') {
|
||||
@@ -357,6 +437,7 @@ App.videos = App.videos || {};
|
||||
state.hasNextPage = true;
|
||||
state.renderedVideoIds.clear();
|
||||
state.loadedVideos = [];
|
||||
state.groupCursors = null;
|
||||
const grid = document.getElementById('video-grid');
|
||||
if (grid) grid.innerHTML = "";
|
||||
if (App.feed && typeof App.feed.reset === 'function') {
|
||||
|
||||
Reference in New Issue
Block a user