Files
fish03andClaude Opus 5.5 bef9f8b4ed Initial commit
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 14:43:16 +07:00

229 lines
5.9 KiB
JavaScript

function imgEncrypt(buffer) {
var bytes = new Uint8Array(buffer);
var encoder = new TextEncoder();
var KEY = encoder.encode('2019ysapp7527');
for (var i = 0; i < Math.min(100, bytes.length); i++) {
bytes[i] ^= KEY[i % KEY.length];
}
var mime = 'image/jpeg';
if (bytes[0] === 0x47 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x38) {
mime = 'image/gif';
} else if (bytes[0] === 0x89 && bytes[1] === 0x50 && bytes[2] === 0x4e && bytes[3] === 0x47) {
mime = 'image/png';
} else if (
bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46 &&
bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50
) {
mime = 'image/webp';
}
var blob = new Blob([bytes], {
type: mime,
});
return URL.createObjectURL(blob);
}
var IMG_PLACEHOLDER = '/static/images/placeholder.png?v=2';
var lazyImageObserver = null;
var decryptedURLCache = Object.create(null);
var decryptInflight = Object.create(null);
var decryptQueue = [];
var decryptActive = 0;
// H5 弱网降低并发,优先完成 LCP 主图;PC 保持 4
var DECRYPT_CONCURRENCY =
window.matchMedia && window.matchMedia("(max-width: 767px)").matches ? 2 : 4;
function shouldDecryptImage(url) {
if (!url) return false;
var u = String(url).trim();
if (!u) return false;
if (u.indexOf('data:') === 0 || u.indexOf('blob:') === 0) return false;
if (u.indexOf('/static/') === 0) return false;
if (u.indexOf('placehold.co') >= 0) return false;
return true;
}
function applyImageResult(dom, type, url) {
if (!dom || !url) return;
if (type === 'bgImg') {
dom.style.setProperty('background-image', 'url("' + url + '")');
} else {
dom.src = url;
}
}
function fetchDecrypt(url, priority) {
if (decryptedURLCache[url]) {
return Promise.resolve(decryptedURLCache[url]);
}
if (decryptInflight[url]) {
return decryptInflight[url];
}
decryptInflight[url] = new Promise(function (resolve, reject) {
var run = function () {
decryptActive += 1;
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function () {
decryptActive -= 1;
pumpDecryptQueue();
if (xhr.status === 200) {
var blobUrl = imgEncrypt(xhr.response);
decryptedURLCache[url] = blobUrl;
resolve(blobUrl);
return;
}
reject(xhr.status);
};
xhr.onerror = function () {
decryptActive -= 1;
pumpDecryptQueue();
reject('network');
};
xhr.send();
};
if (decryptActive < DECRYPT_CONCURRENCY) {
run();
} else if (priority) {
decryptQueue.unshift(run);
} else {
decryptQueue.push(run);
}
});
decryptInflight[url].then(
function () { delete decryptInflight[url]; },
function () { delete decryptInflight[url]; }
);
return decryptInflight[url];
}
function pumpDecryptQueue() {
while (decryptActive < DECRYPT_CONCURRENCY && decryptQueue.length) {
var next = decryptQueue.shift();
if (typeof next === 'function') next();
}
}
function processImage(url, dom, type, fallback) {
if (!url || !dom) {
return Promise.resolve('');
}
if (!shouldDecryptImage(url)) {
applyImageResult(dom, type, url);
return Promise.resolve(url);
}
var priority =
!!dom &&
(dom.getAttribute('fetchpriority') === 'high' ||
dom.getAttribute('data-lazy-eager') === '1');
return fetchDecrypt(url, priority)
.then(function (blobUrl) {
applyImageResult(dom, type, blobUrl);
return blobUrl;
})
.catch(function () {
if (dom.tagName === 'IMG') {
dom.src = fallback || IMG_PLACEHOLDER;
}
return '';
});
}
function loadLazyNode(node) {
if (!node || node.getAttribute('data-decrypted') === '1') {
return;
}
var src = node.getAttribute('data-src');
if (!src) {
return;
}
node.setAttribute('data-decrypted', '1');
if (node.tagName === 'IMG') {
if (!node.getAttribute('src')) {
node.src = IMG_PLACEHOLDER;
}
processImage(src, node);
return;
}
if (node.classList && node.classList.contains('blog-background')) {
processImage(src, node, 'bgImg');
}
}
function getLazyImageObserver() {
if (lazyImageObserver) {
return lazyImageObserver;
}
if (!('IntersectionObserver' in window)) {
return null;
}
lazyImageObserver = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
if (!entry.isIntersecting) {
return;
}
var node = entry.target;
lazyImageObserver.unobserve(node);
loadLazyNode(node);
});
},
{
rootMargin: '180px 0px',
threshold: 0.01,
}
);
return lazyImageObserver;
}
function observeLazyNode(node, eager) {
if (!node || node.getAttribute('data-decrypted') === '1') {
return;
}
if (
eager ||
node.getAttribute('fetchpriority') === 'high' ||
node.getAttribute('data-lazy-eager') === '1'
) {
loadLazyNode(node);
return;
}
var observer = getLazyImageObserver();
if (!observer) {
loadLazyNode(node);
return;
}
observer.observe(node);
}
function initLazyImages(root, options) {
root = root || document;
options = options || {};
var eager = !!options.eager;
root.querySelectorAll('img.lazy[data-src]:not([data-decrypted])').forEach(function (img) {
observeLazyNode(img, eager);
});
root.querySelectorAll('.blog-background.lazy[data-src]:not([data-decrypted])').forEach(function (node) {
observeLazyNode(node, eager);
});
}
document.addEventListener('DOMContentLoaded', function () {
initLazyImages();
});
window.initLazyImages = initLazyImages;
window.__lazyLoadImages = initLazyImages;
window.loadLazyNode = loadLazyNode;
window.processImage = processImage;
window.imgEncrypt = imgEncrypt;
window.shouldDecryptImage = shouldDecryptImage;