more upgrade

This commit is contained in:
Simon
2026-02-08 14:43:00 +00:00
parent 18cb317730
commit b9f49530e4
4 changed files with 39 additions and 5 deletions

View File

@@ -2,7 +2,8 @@
let currentPage = 1; let currentPage = 1;
const perPage = 12; const perPage = 12;
const renderedVideoIds = new Set(); const renderedVideoIds = new Set();
let currentQuery = ""; let hasNextPage = true;
let isLoading = false;
// 2. Observer Definition (Must be defined before initApp uses it) // 2. Observer Definition (Must be defined before initApp uses it)
const observer = new IntersectionObserver((entries) => { const observer = new IntersectionObserver((entries) => {
@@ -74,11 +75,15 @@ async function InitializeServerStatus() {
async function loadVideos() { async function loadVideos() {
const session = JSON.parse(localStorage.getItem('session')); const session = JSON.parse(localStorage.getItem('session'));
if (!session) return; if (!session) return;
if (isLoading || !hasNextPage) return;
const searchInput = document.getElementById('search-input');
const query = searchInput ? searchInput.value : "";
// Build the request body // Build the request body
let body = { let body = {
channel: session.channel.id, channel: session.channel.id,
query: currentQuery, query: query || "",
page: currentPage, page: currentPage,
perPage: perPage, perPage: perPage,
server: session.server server: session.server
@@ -94,6 +99,7 @@ async function loadVideos() {
}); });
try { try {
isLoading = true;
const response = await fetch('/api/videos', { const response = await fetch('/api/videos', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@@ -101,17 +107,22 @@ async function loadVideos() {
}); });
const videos = await response.json(); const videos = await response.json();
renderVideos(videos); renderVideos(videos);
hasNextPage = videos && videos.pageInfo ? videos.pageInfo.hasNextPage !== false : true;
currentPage++; currentPage++;
ensureViewportFilled();
} catch (err) { } catch (err) {
console.error("Failed to load videos:", err); console.error("Failed to load videos:", err);
} finally {
isLoading = false;
} }
} }
function renderVideos(videos) { function renderVideos(videos) {
const grid = document.getElementById('video-grid'); const grid = document.getElementById('video-grid');
if (!grid) return; if (!grid) return;
videos.items.forEach(v => { const items = videos && Array.isArray(videos.items) ? videos.items : [];
items.forEach(v => {
if (renderedVideoIds.has(v.id)) return; if (renderedVideoIds.has(v.id)) return;
const card = document.createElement('div'); const card = document.createElement('div');
@@ -170,8 +181,8 @@ function closePlayer() {
} }
function handleSearch(value) { function handleSearch(value) {
currentQuery = value || "";
currentPage = 1; currentPage = 1;
hasNextPage = true;
renderedVideoIds.clear(); renderedVideoIds.clear();
const grid = document.getElementById('video-grid'); const grid = document.getElementById('video-grid');
if (grid) grid.innerHTML = ""; if (grid) grid.innerHTML = "";
@@ -224,12 +235,23 @@ function buildDefaultOptions(channel) {
function resetAndReload() { function resetAndReload() {
currentPage = 1; currentPage = 1;
hasNextPage = true;
renderedVideoIds.clear(); renderedVideoIds.clear();
const grid = document.getElementById('video-grid'); const grid = document.getElementById('video-grid');
if (grid) grid.innerHTML = ""; if (grid) grid.innerHTML = "";
loadVideos(); loadVideos();
} }
function ensureViewportFilled() {
if (!hasNextPage || isLoading) return;
const grid = document.getElementById('video-grid');
if (!grid) return;
const contentHeight = grid.getBoundingClientRect().bottom;
if (contentHeight < window.innerHeight + 120) {
window.setTimeout(() => loadVideos(), 0);
}
}
function renderMenu() { function renderMenu() {
const session = getSession(); const session = getSession();
const serverEntries = getServerEntries(); const serverEntries = getServerEntries();
@@ -239,6 +261,7 @@ function renderMenu() {
const sourcesList = document.getElementById('sources-list'); const sourcesList = document.getElementById('sources-list');
const addSourceBtn = document.getElementById('add-source-btn'); const addSourceBtn = document.getElementById('add-source-btn');
const sourceInput = document.getElementById('source-input'); const sourceInput = document.getElementById('source-input');
const reloadChannelBtn = document.getElementById('reload-channel-btn');
if (!sourceSelect || !channelSelect || !filtersContainer) return; if (!sourceSelect || !channelSelect || !filtersContainer) return;
@@ -389,6 +412,12 @@ function renderMenu() {
} }
}; };
} }
if (reloadChannelBtn) {
reloadChannelBtn.onclick = () => {
resetAndReload();
};
}
} }
function renderFilters(container, session) { function renderFilters(container, session) {

BIN
frontend/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 523 B

View File

@@ -13,6 +13,9 @@
<input type="text" id="search-input" placeholder="Search videos..." oninput="handleSearch(this.value)"> <input type="text" id="search-input" placeholder="Search videos..." oninput="handleSearch(this.value)">
</div> </div>
<div class="actions"> <div class="actions">
<button class="icon-btn reload-toggle" id="reload-channel-btn" title="Reload Channel">
<img class="icon-svg" src="https://cdn.jsdelivr.net/npm/heroicons@2.0.13/24/outline/arrow-path.svg" alt="Reload">
</button>
<button class="icon-btn menu-toggle" onclick="toggleDrawer('menu')" title="Menu"> <button class="icon-btn menu-toggle" onclick="toggleDrawer('menu')" title="Menu">
<img class="icon-svg" src="https://cdn.jsdelivr.net/npm/heroicons@2.0.13/24/outline/bars-3.svg" alt="Menu"> <img class="icon-svg" src="https://cdn.jsdelivr.net/npm/heroicons@2.0.13/24/outline/bars-3.svg" alt="Menu">
</button> </button>

View File

@@ -327,6 +327,8 @@ body.theme-light .input-row input:focus {
cursor: pointer; cursor: pointer;
font-size: 13px; font-size: 13px;
transition: all 0.2s ease; transition: all 0.2s ease;
width: 100%;
text-align: center;
} }
.btn-secondary:hover { .btn-secondary:hover {