From b9f49530e4ef3c2c6291174441cfc4ff00d6ce36 Mon Sep 17 00:00:00 2001 From: Simon Date: Sun, 8 Feb 2026 14:43:00 +0000 Subject: [PATCH] more upgrade --- frontend/app.js | 39 ++++++++++++++++++++++++++++++++++----- frontend/favicon.ico | Bin 0 -> 523 bytes frontend/index.html | 3 +++ frontend/style.css | 2 ++ 4 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 frontend/favicon.ico diff --git a/frontend/app.js b/frontend/app.js index ece54f9..b97451a 100644 --- a/frontend/app.js +++ b/frontend/app.js @@ -2,7 +2,8 @@ let currentPage = 1; const perPage = 12; const renderedVideoIds = new Set(); -let currentQuery = ""; +let hasNextPage = true; +let isLoading = false; // 2. Observer Definition (Must be defined before initApp uses it) const observer = new IntersectionObserver((entries) => { @@ -74,11 +75,15 @@ async function InitializeServerStatus() { async function loadVideos() { const session = JSON.parse(localStorage.getItem('session')); if (!session) return; + if (isLoading || !hasNextPage) return; + + const searchInput = document.getElementById('search-input'); + const query = searchInput ? searchInput.value : ""; // Build the request body let body = { channel: session.channel.id, - query: currentQuery, + query: query || "", page: currentPage, perPage: perPage, server: session.server @@ -94,6 +99,7 @@ async function loadVideos() { }); try { + isLoading = true; const response = await fetch('/api/videos', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -101,17 +107,22 @@ async function loadVideos() { }); const videos = await response.json(); renderVideos(videos); + hasNextPage = videos && videos.pageInfo ? videos.pageInfo.hasNextPage !== false : true; currentPage++; + ensureViewportFilled(); } catch (err) { console.error("Failed to load videos:", err); + } finally { + isLoading = false; } } function renderVideos(videos) { const grid = document.getElementById('video-grid'); 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; const card = document.createElement('div'); @@ -170,8 +181,8 @@ function closePlayer() { } function handleSearch(value) { - currentQuery = value || ""; currentPage = 1; + hasNextPage = true; renderedVideoIds.clear(); const grid = document.getElementById('video-grid'); if (grid) grid.innerHTML = ""; @@ -224,12 +235,23 @@ function buildDefaultOptions(channel) { function resetAndReload() { currentPage = 1; + hasNextPage = true; renderedVideoIds.clear(); const grid = document.getElementById('video-grid'); if (grid) grid.innerHTML = ""; 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() { const session = getSession(); const serverEntries = getServerEntries(); @@ -239,6 +261,7 @@ function renderMenu() { const sourcesList = document.getElementById('sources-list'); const addSourceBtn = document.getElementById('add-source-btn'); const sourceInput = document.getElementById('source-input'); + const reloadChannelBtn = document.getElementById('reload-channel-btn'); if (!sourceSelect || !channelSelect || !filtersContainer) return; @@ -389,6 +412,12 @@ function renderMenu() { } }; } + + if (reloadChannelBtn) { + reloadChannelBtn.onclick = () => { + resetAndReload(); + }; + } } function renderFilters(container, session) { diff --git a/frontend/favicon.ico b/frontend/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4f487019b0da45ed4671d1210613d8be698a0cef GIT binary patch literal 523 zcmV+m0`&a=0096201yxW0000W0QCU?02TlM0EtjeM-2)Z3IG5A4M|8uQUCw|5C8xG z5C{eU001BJ|6u?C0lY~>K~#90rBmBZ!axu`+ir_!LMRZVn#d>Mx8S>cj(&#zhCY&z zXb3-`PedOqO@L5}z3i@;!4?xtOmNceWiosAoHJ9=>s=Zg7y^Ja=HUIHol`pU=mr@FjuIH`Qu2%z^;3FocvgBr!=o6ZoAD?(XkUsZ^K=F)QT>!ORFCNfHdM z2Y7pbhixBkB`B?+w1(@tOp%J|#6kk;CEZj@d6HWkAW27>Y#C4lK>#V`o|yzj%-ZcX zy4?#rKRuyZtwK`r=%|X(XoT^24A1kJ=5Im3VHjdEnZR``P-MDdS0$#?DIOjkv0AM# zpU<&guMtHNqIJaY%jJ@v!{HDwFRyT22f0$)E~HxH_~Zng(^K5u+#;CG(C|F=#S(() z$8iklNc8(x@alEMn+91-QN(+#mn| N002ovPDHLkV1jdQ-^~C3 literal 0 HcmV?d00001 diff --git a/frontend/index.html b/frontend/index.html index eb43f06..0fe109b 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -13,6 +13,9 @@
+ diff --git a/frontend/style.css b/frontend/style.css index 91c66f3..8e631e8 100644 --- a/frontend/style.css +++ b/frontend/style.css @@ -327,6 +327,8 @@ body.theme-light .input-row input:focus { cursor: pointer; font-size: 13px; transition: all 0.2s ease; + width: 100%; + text-align: center; } .btn-secondary:hover {