Vendored
+4
File diff suppressed because one or more lines are too long
Vendored
+2
File diff suppressed because one or more lines are too long
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -0,0 +1,298 @@
|
||||
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;
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
+13
File diff suppressed because one or more lines are too long
+14
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user