LINUX.ORG.RU

Что здесь можно сократить?

 , ,


0

1

У одного известного сайта конфликт с черногорским(?) регистратором доменов. В результате ему пришлось срочно переехать с домена t.me, на домен telegram.me. Часть веб-страниц поломалась, т.к. пытаются качать IFRAME-ы со старого домена.

Гугло-ИИ предложил короткий скрипт, который работал, но высота IFRAME была неверной. После долгой беседы DeepSeek выдал такой скрипт:

// ==UserScript==
// @name         t.me corrector
// @namespace    http://tampermonkey.net/
// @version      2026-07-14
// @description  replace "t.me" with "telegram.me"
// @author       DeepSeek
// @match        https://telegram.me/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Функция замены домена
    function replaceDomain(url) {
        try {
            const urlObj = new URL(url, window.location.href);
            if (urlObj.hostname.includes('t.me')) {
                urlObj.hostname = urlObj.hostname.replace(/t\.me/g, 'telegram.me');
                return urlObj.toString();
            }
        } catch (_) {}
        return url.replace(/t\.me/g, 'telegram.me');
    }

    // Функция подстройки высоты одного iframe
    function autoHeightIframe(iframe) {
        // Сначала убираем прокрутку и задаём начальную высоту
        iframe.style.overflow = 'hidden';
        //iframe.scrolling = 'no'; // для старых браузеров
        iframe.style.height = '100px'; // временная, чтобы сработало

        const adjustHeight = () => {
            try {
                // Доступ к содержимому возможен, т.к. домен совпадает
                const doc = iframe.contentDocument || iframe.contentWindow.document;
                if (!doc) return;

                // Вычисляем высоту содержимого (body + margin)
                const body = doc.body;
                const html = doc.documentElement;
                const height = Math.max(
                    body.scrollHeight,
                    body.offsetHeight,
                    html.clientHeight,
                    html.scrollHeight,
                    html.offsetHeight
                );

                // Устанавливаем новую высоту с небольшим запасом (опционально)
                iframe.style.height = height + 'px';
            } catch (e) {
                // Если доступ запрещён (неожиданно) – игнорируем
            }
        };

        // Подстраиваем после полной загрузки iframe
        iframe.addEventListener('load', () => {
            adjustHeight();
            // Настраиваем отслеживание изменений внутри iframe
            //setupObservers(iframe);
        });

        // Если iframe уже загружен (например, src установлен ранее)
        if (iframe.contentDocument && iframe.contentDocument.readyState === 'complete') {
            adjustHeight();
            //setupObservers(iframe);
        }
    }

    /*
    // Настройка наблюдателей за изменениями внутри iframe
    function setupObservers(iframe) {
        try {
            const doc = iframe.contentDocument;
            if (!doc) return;

            const target = doc.body;
            if (!target) return;

            // 1. ResizeObserver – отслеживает изменение размера элементов
            if (window.ResizeObserver) {
                const resizeObserver = new ResizeObserver(() => {
                    // При изменении размера пересчитываем высоту
                    const height = Math.max(
                        doc.body.scrollHeight,
                        doc.documentElement.scrollHeight,
                        doc.body.offsetHeight,
                        doc.documentElement.offsetHeight
                    );
                    iframe.style.height = height + 'px';
                });
                resizeObserver.observe(target);
                // Также наблюдаем за html, так как изменения могут быть там
                resizeObserver.observe(doc.documentElement);
            }

            // 2. MutationObserver – отслеживает добавление/удаление узлов
            const mutationObserver = new MutationObserver(() => {
                // Пересчёт высоты после изменения DOM
                const height = Math.max(
                    doc.body.scrollHeight,
                    doc.documentElement.scrollHeight,
                    doc.body.offsetHeight,
                    doc.documentElement.offsetHeight
                );
                iframe.style.height = height + 'px';
            });
            mutationObserver.observe(target, {
                childList: true,
                subtree: true,
                attributes: true,
                attributeFilter: ['style', 'class', 'height', 'width']
            });
        } catch (e) {
            // Если доступ запрещён – игнорируем
        }
    }
    */

    // Обработка одного элемента
    function processElement(el) {
        if (el.tagName === 'IFRAME') {
            // Заменяем src у iframe
            const src = el.getAttribute('src');
            if (src && src.includes('t.me')) {
                el.setAttribute('src', replaceDomain(src));
                // После замены src запускаем подстройку высоты
                autoHeightIframe(el);
            }
            return; // Не обрабатываем другие атрибуты у iframe
        }

        // Для остальных элементов заменяем href, src, action
        const attrs = ['href', 'src', 'action'];
        for (const attr of attrs) {
            if (el.hasAttribute(attr)) {
                const value = el.getAttribute(attr);
                if (value.includes('t.me')) {
                    el.setAttribute(attr, replaceDomain(value));
                }
            }
        }
    }

    // Обработка всех существующих элементов
    function processAllElements() {
        document.querySelectorAll('[href], [src], [action]').forEach(processElement);
    }

    // Запуск после загрузки DOM
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', processAllElements);
    } else {
        processAllElements();
    }

    /*// Наблюдаем за динамически добавляемыми элементами
    const observer = new MutationObserver((mutations) => {
        for (const mutation of mutations) {
            for (const node of mutation.addedNodes) {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    processElement(node);
                    node.querySelectorAll('[href], [src], [action]').forEach(processElement);
                }
            }
        }
    });
    observer.observe(document.body, {
        childList: true,
        subtree: true
    });*/
})();

Что в нём можно сократить? Помимо вызова observer.

UPD: В итоге досокращал до:

(function() {
    'use strict';

    const elements = document.querySelectorAll('iframe');
    // console.log(elements)
    elements.forEach((frame, index) => {
        if (frame.src.startsWith('https://t.me/')){
            // console.log(frame.src);
            frame.src = frame.src.replaceAll('://t.me/', '://telegram.me/');
            const adjustHeight = () => {
                const doc = frame.contentDocument || frame.contentWindow.document;
                const height = Math.max(doc.body.scrollHeight, doc.body.offsetHeight, doc.documentElement.clientHeight, doc.documentElement.scrollHeight, doc.documentElement.offsetHeight);
                frame.style.height = height + 'px';
            };
            frame.addEventListener('load', () => {
                adjustHeight();
            });
        };
    });
})();

Ничего важного не потерял?

★★★★★

Последнее исправление: question4 (всего исправлений: 3)

По диагонали глянул, не эксперт. Если смущают два конструктора завернутые в отдельных наблюдателей и что на них висит прослушивание событий, то возможно копать в сторону «из коробки» в браузере.

anonymous
()
Ответ на: комментарий от BACR

вот как это сделано у меня в glide-browser

// redirects {{{
glide.autocmds.create("ConfigLoaded", async () => { const redirectRules: Record<string, string> = {
	'^https?://t.me/(.*)':'https://telegram.me/$1',
	'^https?://(?:www\\.)?youtube\\.com/shorts/([A-Za-z0-9_-]+)':'https://youtube.com/watch?v=$1'
	};
	async function request( details: browser.webRequest.OnBeforeRequestDetailsType,):
	browser.webRequest.RedirectOption | browser.webRequest.CancelOption {
		const url = details.url;
		for (const [pattern, replacement] of Object.entries(redirectRules)) {
			const re = new RegExp(pattern);
			const match = url.match(re);
			if (!match) continue;
			const newUrl = replacement.replace(/\$(\d+)/g, (full, groupIndexStr) => {
				const idx = Number(groupIndexStr);
				return match[idx] ?? full; });
			return { redirectUrl: newUrl }};
	return { cancel: false }; }

	browser.webRequest.onBeforeRequest.addListener( request, { urls: ['<all_urls>'], types: ['main_frame'] }, ['blocking'],);
});
// }}}	
BACR
()

Гугло-ИИ предложил короткий скрипт, который работал, но высота IFRAME была неверной. После долгой беседы DeepSeek выдал такой скрипт:

Что в нём можно сократить? Помимо вызова observer.

Так у своих бредогенераторов и спрашивай, что можно сократить. Ну или в Job. Ладно ещё когда сам писал, но когда «вот LLM мне наговнокодила, ЛОРчик, доделай» — это на мой взгляд, совсем уже наглость.

CrX ★★★★★
()
Ответ на: комментарий от CrX

вот LLM мне наговнокодила

Разве подфорум не для обсуждения творчества LLM создавался?

ЛОРчик, доделай

Доделывать не прошу. Но если кто-то разбирающийся скажет, что какой-то блок здесь лишний — буду рад.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Разве подфорум не для обсуждения творчества LLM создавался?

Нет.

Во-первых, гораздо интереснее обсуждать сами LLM, чем их творчество. Во-вторых, ИИ далеко не ограничивается LLM.

Доделывать не прошу.

И сразу:

Но если кто-то разбирающийся скажет, что какой-то блок здесь лишний — буду рад.

Это и есть «доделывать». Ну, то есть, это 99% работы по доделыванию. Гордо выделить и нажать Del ты, конечно, соизволишь сам.

CrX ★★★★★
()
Ответ на: комментарий от CrX

Половина скрипта оказалась сделана для фич, которых сайт не имеет. Знающий человек сразу сказал бы, что observer не нужен. Возможно, кто-то твёрдо знает, что не нужна обработка action или img. Для них сказать это — минутное дело.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Знающий человек сразу сказал бы, что observer не нужен. Возможно, кто-то твёрдо знает, что не нужна обработка action или img. Для них сказать это — минутное дело.

Сказать — минутное дело. А не сказать — двухминутное, но принципиально и методологически более правильное, хоть и отнимает больше сил. Ибо нефиг.

CrX ★★★★★
()
Ответ на: комментарий от BACR

Существует glide-browser, в котором подобные вещи можно делать прямо в конфиге.

Как у него с перегруженными скриптами сайтами, вроде Youtube, Facebook или Twitter? Или с любителями вложенных таблиц и незакрытых тегов?

question4 ★★★★★
() автор топика
Ответ на: комментарий от cobold

На момент создания темы ещё было заблокировано.

И вообще пригодится для старых сайтов на поломанном WordPress.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

я мышевозю, не парюсь, так что не могу точно сказать, на yt сейчас проверил, вроде шустро работает

BACR
()
Ответ на: комментарий от question4

Да тут переделать проще чем нейрослоп править. Оно может и работает, но наговнокожено капитально.

ya-betmen ★★★★★
()
Ответ на: комментарий от LightDiver

Я сути вопрос не понял

Для замены домена в IFRAME достаточно скрипта в 4 строки (не считая бойлерплейта, отладочных сообщений, скобок и комментариев):

// ==UserScript==
// @name         t.me corrector
// @namespace    http://tampermonkey.net/
// @version      2026-07-14
// @description  replace "t.me" with "telegram.me"
// @author       You
// @match        https://telegram.me/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    var elements = document.querySelectorAll('iframe');
    //console.log(elements)
    elements.forEach((frame, index) => {
        if (frame.src.substring(0, 13) == 'https://t.me/')
        {
            //console.log(frame.src);
            frame.src = 'https://telegram.me/' + frame.src.substring(13);
            //console.log(frame.src);
        };
    });
})();

Но размер IFRAME получается неправильный. Кроме того, я не разобрался, требуется ли заменять домен в других элементах. Когда я пытался добавлять в elements другие теги, скрипт перестал работать.

DeepSeek сделал большой скрипт, который работает. Но какие его части необходимы, а что можно удалить?

Причина желания сократить — чтобы когда скрипт понадобится в следующий раз, было проще его допиливать.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Причина желания сократить — чтобы когда скрипт понадобится в следующий раз, было проще его допиливать.

А ты сделай каждую функцию скрипта отдельным модулем. Ну, то есть один обособленный модуль кода на каждую задачу. Одну задачу пилить проще, чем сразу всю сборную солянку.

LightDiver ★★★★★
()
Ответ на: комментарий от question4

Моё ограниченое познание js подсказывает что блок

{
        if (frame.src.substring(0, 13) == 'https://t.me/')
        {
            //console.log(frame.src);
            frame.src = 'https://telegram.me/' + frame.src.substring(13);
            //console.log(frame.src);
        };
    }

можно заменить на { frame.src = frame.src.replace("t.me", "telegraph.me"); }

tnray
()
Ответ на: комментарий от LightDiver

А ты сделай каждую функцию скрипта отдельным модулем.

В смысле? На каждый тег — свой скрипт? Или в одном скрипте по функции на каждый тег?

question4 ★★★★★
() автор топика
Ответ на: комментарий от tnray

можно заменить на { frame.src = frame.src.replace("t.me", "telegraph.me"); }

Да, я с этого начал. Но почему-то не заработало. Попробовал сейчас:

        if (frame.src.startsWith('https://t.me/'))
        {
            frame.src = frame.src.replace('https://t.me/', 'https://telegram.me/');
        };

Работает. Не знаю, что я неправильно сделал в прошлый раз. startsWith() нужна потому, что этот домен может быть не только в начале. Хотя я сейчас сделал без if, с одной frame.src = frame.src.replaceAll('://t.me/', '://telegram.me/'); — тоже работает.

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Не совсем, скорее каждому тегу по деятку функций, каждой функции по сотне скриптов, и каждому скрипту по тысяще внешних зависимостей. Объем должен быть не меньше двух веб-браузеров (например, links2 и dillo).

tnray
()
Ответ на: комментарий от tnray

Тогда замени в .replace «t.me» на /t.me/g (это можно узнать в MDN, например)

Какая разница, .replace с регулярным выражением с /g, или .replaceAll со стрингом?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Разница − в регулярке. Можно, например, подставить подстроку https?1 что будет соотвествовать и http и https

tnray
()
Ответ на: комментарий от anonymous

имелось ввиду, что API JS-движка в браузере или фреймворка в стеке, уже быть может имеет «встроенное» решение

Необходимость в данном скрипте возникла из-за захардкоженного домена во фреймворке, поэтому к нему доверия нет.

Что касается API JS браузера, есть ли сейчас разница между API Chrome, который фактический стандарт, API Firefox, который постоянно догоняет, и документацией на JS на том же MSDN?

question4 ★★★★★
() автор топика
Ответ на: комментарий от question4

Из ложности утверждения «данный раздел форума создавался для этого» не следует «это совсем не уместно в данном разделе форума».

CrX ★★★★★
()
Ответ на: комментарий от question4

Емнип, в FF используется nodejs. В целом не готов сказать. исхожу из логики от противного: если на самом движке, как сервер backend, хватает фичь; то почему эти фичи не могу быть на стороне клиента. К слову, а де если это фреймворк, - там же можно найти где это захардкожено и «пересобрать». Но не лезу поперек, - понял-принял

anonymous
()
Ответ на: комментарий от anonymous

В генте, по зависимостям тянет

Не поверил, полез проверять. Нашёл BDEPEND=" ... net-libs/nodejs ... BDEPEND означает, что пакет используется для сборки Firefox, но дальше не нужен.

question4 ★★★★★
() автор топика

Прикручиваешь playwright-mcp к своему агенту и спрашивай у него же, чего ты как маленький

Gary ★★★★★
()
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария