pipi kaka
This commit is contained in:
@@ -1351,6 +1351,71 @@ window.cancelAnimFrame = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const prefetchNextPrevItems = () => {
|
||||||
|
const nextBtn = document.getElementById('next');
|
||||||
|
const prevBtn = document.getElementById('prev');
|
||||||
|
|
||||||
|
[nextBtn, prevBtn].forEach(btn => {
|
||||||
|
if (!btn || !btn.href || btn.href.endsWith('#')) return;
|
||||||
|
|
||||||
|
const pathSegments = new URL(btn.href, window.location.origin).pathname.split('/');
|
||||||
|
const numericSegments = pathSegments.filter(s => /^\d+$/.test(s));
|
||||||
|
if (numericSegments.length === 0) return;
|
||||||
|
const itemId = numericSegments.pop();
|
||||||
|
|
||||||
|
let ajaxUrl = `/ajax/item/${itemId}`;
|
||||||
|
const params = new URLSearchParams();
|
||||||
|
params.append('mode', window.activeMode);
|
||||||
|
|
||||||
|
const tagMatch = btn.href.match(/\/tag\/([^/?]+)/);
|
||||||
|
if (tagMatch) params.append('tag', decodeURIComponent(tagMatch[1]));
|
||||||
|
|
||||||
|
const userHallMatch = btn.href.match(/\/user\/([^/]+)\/hall\/([^/]+)/);
|
||||||
|
if (userHallMatch) {
|
||||||
|
params.append('userHall', decodeURIComponent(userHallMatch[2]));
|
||||||
|
params.append('userHallOwner', decodeURIComponent(userHallMatch[1]));
|
||||||
|
} else {
|
||||||
|
const userMatch = btn.href.match(/\/user\/([^/]+)/);
|
||||||
|
if (userMatch) {
|
||||||
|
params.append('user', decodeURIComponent(userMatch[1]));
|
||||||
|
if (btn.href.match(/\/user\/[^/]+\/favs(\/|$|\?)/)) params.append('fav', 'true');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hallMatch = btn.href.match(/\/h\/([^/?]+)/);
|
||||||
|
if (hallMatch) params.append('hall', decodeURIComponent(hallMatch[1]));
|
||||||
|
|
||||||
|
const isStrict = window.f0ckSession?.strict_mode || (localStorage.getItem('search_strict') === 'true');
|
||||||
|
if (isStrict) params.append('strict', '1');
|
||||||
|
|
||||||
|
if (params.toString() !== '') {
|
||||||
|
ajaxUrl += (ajaxUrl.includes('?') ? '&' : '?') + params.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemCacheMap.has(ajaxUrl)) return;
|
||||||
|
|
||||||
|
fetch(ajaxUrl, { credentials: 'include', priority: 'low' })
|
||||||
|
.then(r => r.ok ? r.text() : null)
|
||||||
|
.then(rawText => {
|
||||||
|
if (!rawText) return;
|
||||||
|
let html = rawText;
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(rawText);
|
||||||
|
if (data && typeof data.html === 'string') html = data.html;
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
if (html) {
|
||||||
|
itemCacheMap.set(ajaxUrl, { html, ts: Date.now() });
|
||||||
|
if (itemCacheMap.size > ITEM_CACHE_MAX) {
|
||||||
|
itemCacheMap.delete(itemCacheMap.keys().next().value);
|
||||||
|
}
|
||||||
|
window.f0ckDebug('[prefetch] Cached AJAX template for item', itemId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const setupMedia = () => {
|
const setupMedia = () => {
|
||||||
const elem = document.querySelector("#my-video") || document.querySelector("audio#my-video");
|
const elem = document.querySelector("#my-video") || document.querySelector("audio#my-video");
|
||||||
if (elem) {
|
if (elem) {
|
||||||
@@ -1363,6 +1428,11 @@ window.cancelAnimFrame = (function () {
|
|||||||
// Initial Load
|
// Initial Load
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
setupMedia();
|
setupMedia();
|
||||||
|
if (typeof requestIdleCallback === 'function') {
|
||||||
|
requestIdleCallback(() => prefetchNextPrevItems());
|
||||||
|
} else {
|
||||||
|
setTimeout(prefetchNextPrevItems, 500);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export init function for dynamic calls
|
// Export init function for dynamic calls
|
||||||
@@ -3559,6 +3629,12 @@ window.cancelAnimFrame = (function () {
|
|||||||
console.error("updateStrictLinks error:", err);
|
console.error("updateStrictLinks error:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof requestIdleCallback === 'function') {
|
||||||
|
requestIdleCallback(() => prefetchNextPrevItems());
|
||||||
|
} else {
|
||||||
|
setTimeout(prefetchNextPrevItems, 200);
|
||||||
|
}
|
||||||
|
|
||||||
// After comments have rendered (f0ck:contentLoaded above triggers synchronous render),
|
// After comments have rendered (f0ck:contentLoaded above triggers synchronous render),
|
||||||
// constrain the comments-list height via direct measurement (flex chain unreliable in AJAX).
|
// constrain the comments-list height via direct measurement (flex chain unreliable in AJAX).
|
||||||
|
|
||||||
|
|||||||
@@ -342,9 +342,18 @@ class v0ck {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Loader events
|
// Loader events with debounce to prevent flicker on fast starts/seeking
|
||||||
const showLoader = () => loader.classList.remove('v0ck_hidden');
|
let loaderTimeout = null;
|
||||||
const hideLoader = () => loader.classList.add('v0ck_hidden');
|
const showLoader = () => {
|
||||||
|
if (loaderTimeout) clearTimeout(loaderTimeout);
|
||||||
|
loaderTimeout = setTimeout(() => {
|
||||||
|
loader.classList.remove('v0ck_hidden');
|
||||||
|
}, 250);
|
||||||
|
};
|
||||||
|
const hideLoader = () => {
|
||||||
|
if (loaderTimeout) clearTimeout(loaderTimeout);
|
||||||
|
loader.classList.add('v0ck_hidden');
|
||||||
|
};
|
||||||
video.addEventListener('waiting', showLoader);
|
video.addEventListener('waiting', showLoader);
|
||||||
video.addEventListener('stalled', showLoader);
|
video.addEventListener('stalled', showLoader);
|
||||||
video.addEventListener('canplay', hideLoader);
|
video.addEventListener('canplay', hideLoader);
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
</div>
|
</div>
|
||||||
@elseif(item.mime.startsWith("video"))
|
@elseif(item.mime.startsWith("video"))
|
||||||
<div class="embed-responsive embed-responsive-16by9">
|
<div class="embed-responsive embed-responsive-16by9">
|
||||||
<video id="my-video" class="embed-responsive-item" width="640" height="360" src="{{ item.dest }}" preload="metadata" data-size="{{ item.size }}" loop playsinline></video>
|
<video id="my-video" class="embed-responsive-item" width="640" height="360" src="{{ item.dest }}" preload="auto" data-size="{{ item.size }}" loop playsinline></video>
|
||||||
</div>
|
</div>
|
||||||
@elseif(item.mime.startsWith("audio"))
|
@elseif(item.mime.startsWith("audio"))
|
||||||
<div class="embed-responsive embed-responsive-16by9" style="background: url('@if(item.coverart)//w0bm.com{{ item.coverart }}@else/s/img/200.gif@endif') no-repeat center / contain black;">
|
<div class="embed-responsive embed-responsive-16by9" style="background: url('@if(item.coverart)//w0bm.com{{ item.coverart }}@else/s/img/200.gif@endif') no-repeat center / contain black;">
|
||||||
<audio id="my-video" class="embed-responsive-item" loop src="{{ item.dest }}" data-setup="{}" data-size="{{ item.size }}" poster="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" type="{{ item.mime }}"></audio>
|
<audio id="my-video" class="embed-responsive-item" preload="auto" loop src="{{ item.dest }}" data-setup="{}" data-size="{{ item.size }}" poster="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" type="{{ item.mime }}"></audio>
|
||||||
<img id="f0ck-audio-cover" src="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" style="display: none;">
|
<img id="f0ck-audio-cover" src="@if(item.coverart){{ item.coverart }}@else/s/img/200.gif@endif" style="display: none;">
|
||||||
</div>
|
</div>
|
||||||
@elseif(item.mime.startsWith("image"))
|
@elseif(item.mime.startsWith("image"))
|
||||||
|
|||||||
Reference in New Issue
Block a user