Ищу решение как это сделать. Конкретно интересует изменить только на домене https://nztcdn.com/ * Пример гифки: https://nztcdn.com/avatar/l/1704925982/4797939.webp Имеет формат .webp Надо сделать статичное изображение
eternal, webp вроде универсальная хуйня, можно заменить расширение и не будет выебонов по идее если я не даун
жди, так ты ссылаешься на файл на cdn, а я говорю о хуке. перехватываешь и уже потом перехваченное меняешь
(function() { 'use strict'; function convertWebPtoStatic() { const images = document.querySelectorAll('img[src*=".webp"]'); images.forEach(img => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const webpImage = new Image(); webpImage.src = img.src; webpImage.onload = () => { canvas.width = webpImage.width; canvas.height = webpImage.height; ctx.drawImage(webpImage, 0, 0); const staticDataUrl = canvas.toDataURL("image/webp"); img.src = staticDataUrl; }; }); } window.addEventListener('load', convertWebPtoStatic); })(); JS (function() { 'use strict'; function convertWebPtoStatic() { const images = document.querySelectorAll('img[src*=".webp"]'); images.forEach(img => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const webpImage = new Image(); webpImage.src = img.src; webpImage.onload = () => { canvas.width = webpImage.width; canvas.height = webpImage.height; ctx.drawImage(webpImage, 0, 0); const staticDataUrl = canvas.toDataURL("image/webp"); img.src = staticDataUrl; }; }); } window.addEventListener('load', convertWebPtoStatic); })(); Отрисовывать в canvas первый кадр, потом через toDataURL (https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) конвертить в dataURL и заменять src внутри тега img
TOPCHEK, // ==UserScript== // @name Convert WebP to Static Image // @namespace http://tampermonkey.net/ // @version 2024-06-07 // @description Convert WebP images to static images // @author webcache // @match https://nztcdn.com/* // @match https://lolz.live/* // @icon https://www.google.com/s2/favicons?sz=64&domain=zelenka.guru // @grant none // ==/UserScript== (function() { 'use strict'; const observerConfig = { childList: true, subtree: true, }; function convertWebPtoStatic() { const images = document.querySelectorAll('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]'); images.forEach(img => { if (!img.dataset.converted) { intersectionObserver.observe(img); } }); } function extractBackgroundImageUrl(img) { return img.style.backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/, '$1'); } function forceImageLoad(url) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'anonymous'; img.src = url; img.onload = () => resolve(img); img.onerror = () => reject(`Failed to load image: ${url}`); }); } async function convertImage(img) { if (img.dataset.converted) { return; } const isBackgroundImage = img.style.backgroundImage && img.style.backgroundImage.includes('.webp'); const url = isBackgroundImage ? extractBackgroundImageUrl(img) : (img.dataset.url || img.src); try { const webpImage = await forceImageLoad(url); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = webpImage.width; canvas.height = webpImage.height; ctx.drawImage(webpImage, 0, 0); const staticDataUrl = canvas.toDataURL('image/png'); if (img.tagName === 'IMG') { img.src = staticDataUrl; img.dataset.url = staticDataUrl; } else { img.style.backgroundImage = `url('${staticDataUrl}')`; } img.dataset.converted = 'true'; } catch (error) { console.error(error); } img.removeAttribute('loading'); } function handleMutations(mutations) { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]')) { intersectionObserver.observe(node); } else { const webpImages = node.querySelectorAll('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]'); webpImages.forEach(img => { intersectionObserver.observe(img); }); } } }); }); } const intersectionObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { convertImage(entry.target); intersectionObserver.unobserve(entry.target); } }); }); const mutationObserver = new MutationObserver(handleMutations); mutationObserver.observe(document.body, observerConfig); window.addEventListener('load', convertWebPtoStatic); })(); JS // ==UserScript== // @name Convert WebP to Static Image // @namespace http://tampermonkey.net/ // @version 2024-06-07 // @description Convert WebP images to static images // @author webcache // @match https://nztcdn.com/* // @match https://lolz.live/* // @icon https://www.google.com/s2/favicons?sz=64&domain=zelenka.guru // @grant none // ==/UserScript== (function() { 'use strict'; const observerConfig = { childList: true, subtree: true, }; function convertWebPtoStatic() { const images = document.querySelectorAll('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]'); images.forEach(img => { if (!img.dataset.converted) { intersectionObserver.observe(img); } }); } function extractBackgroundImageUrl(img) { return img.style.backgroundImage.replace(/url\(['"]?(.*?)['"]?\)/, '$1'); } function forceImageLoad(url) { return new Promise((resolve, reject) => { const img = new Image(); img.crossOrigin = 'anonymous'; img.src = url; img.onload = () => resolve(img); img.onerror = () => reject(`Failed to load image: ${url}`); }); } async function convertImage(img) { if (img.dataset.converted) { return; } const isBackgroundImage = img.style.backgroundImage && img.style.backgroundImage.includes('.webp'); const url = isBackgroundImage ? extractBackgroundImageUrl(img) : (img.dataset.url || img.src); try { const webpImage = await forceImageLoad(url); const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); canvas.width = webpImage.width; canvas.height = webpImage.height; ctx.drawImage(webpImage, 0, 0); const staticDataUrl = canvas.toDataURL('image/png'); if (img.tagName === 'IMG') { img.src = staticDataUrl; img.dataset.url = staticDataUrl; } else { img.style.backgroundImage = `url('${staticDataUrl}')`; } img.dataset.converted = 'true'; } catch (error) { console.error(error); } img.removeAttribute('loading'); } function handleMutations(mutations) { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === Node.ELEMENT_NODE) { if (node.matches('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]')) { intersectionObserver.observe(node); } else { const webpImages = node.querySelectorAll('img[data-url*=".webp"], img[src*=".webp"], [style*=".webp"]'); webpImages.forEach(img => { intersectionObserver.observe(img); }); } } }); }); } const intersectionObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { convertImage(entry.target); intersectionObserver.unobserve(entry.target); } }); }); const mutationObserver = new MutationObserver(handleMutations); mutationObserver.observe(document.body, observerConfig); window.addEventListener('load', convertWebPtoStatic); })(); Работает, получилось без дополнительных запросов, но вообще думаю от браузера зависит, потому что ошибки из-за CORS все равно выкидывает в консоль, но на хроме работает у меня нормально