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 if (type === 'coverVar') { dom.style.setProperty('--cover', 'url("' + url + '")'); } else { dom.src = url; } } function applyPlaceholder(dom, type, fallback) { var url = fallback || IMG_PLACEHOLDER; applyImageResult(dom, type, url); if (dom && dom.setAttribute) { dom.setAttribute('data-decrypt-failed', '1'); } } 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) { reject(xhr.status); return; } try { var buffer = xhr.response; if (!buffer || !buffer.byteLength) { reject('empty'); return; } var blobUrl = imgEncrypt(buffer); if (!blobUrl) { reject('decrypt'); return; } decryptedURLCache[url] = blobUrl; resolve(blobUrl); } catch (err) { reject(err || 'decrypt'); } }; 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 isAvatarLazyNode(node) { if (!node || !node.classList) return false; return ( node.classList.contains('user-chip__avatar') || node.classList.contains('user-menu__avatar') || node.classList.contains('drawer__avatar') || node.classList.contains('play-composer__avatar-img') || node.classList.contains('play-comment__avatar') ); } function processImage(url, dom, type, fallback) { if (!url || !dom) { return Promise.resolve(''); } var placeholder = fallback || IMG_PLACEHOLDER; if (!shouldDecryptImage(url)) { applyImageResult(dom, type, url); if (dom.tagName === 'IMG') { dom.onerror = function () { dom.onerror = null; applyPlaceholder(dom, type, placeholder); }; } return Promise.resolve(url); } var priority = !!dom && (dom.getAttribute('fetchpriority') === 'high' || dom.getAttribute('data-lazy-eager') === '1' || isAvatarLazyNode(dom)); return fetchDecrypt(url, priority) .then(function (blobUrl) { applyImageResult(dom, type, blobUrl); if (dom.tagName === 'IMG') { dom.onerror = function () { dom.onerror = null; applyPlaceholder(dom, type, placeholder); }; } return blobUrl; }) .catch(function () { applyPlaceholder(dom, type, placeholder); return ''; }); } function loadLazyNode(node) { if (!node || node.getAttribute('data-decrypted') === '1') { return; } var src = node.getAttribute('data-src'); var isCoverVar = node.classList && (node.classList.contains('card__cover') || node.classList.contains('series-card__cover') || node.classList.contains('series-list-card__cover') || node.classList.contains('rank-card__cover') || node.classList.contains('play-player')); if (!src) { if (isCoverVar) { applyPlaceholder(node, 'coverVar'); node.setAttribute('data-decrypted', '1'); } return; } node.setAttribute('data-decrypted', '1'); if (isCoverVar) { if (!node.style.getPropertyValue('--cover')) { applyPlaceholder(node, 'coverVar'); } processImage(src, node, 'coverVar'); return; } if (node.tagName === 'IMG') { if (!node.getAttribute('src')) { node.src = IMG_PLACEHOLDER; } processImage(src, node, 'img', node.getAttribute('data-fallback')); 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[data-src]:not([data-decrypted]):not([data-hero-poster])').forEach(function (img) { observeLazyNode(img, eager); }); root.querySelectorAll('.blog-background.lazy[data-src]:not([data-decrypted])').forEach(function (node) { observeLazyNode(node, eager); }); root.querySelectorAll('.card__cover.lazy[data-src]:not([data-decrypted]), .series-card__cover.lazy[data-src]:not([data-decrypted]), .series-list-card__cover.lazy[data-src]:not([data-decrypted]), .rank-card__cover.lazy[data-src]:not([data-decrypted]), .search-card__cover.lazy[data-src]:not([data-decrypted]), .play-player.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;