您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Установка своего аватара на Табуне!
// ==UserScript== // @name TabunAva Reborn // @namespace http://tampermonkey.net/ // @version 1.5.9 // @description Установка своего аватара на Табуне! // @author (IntelRug && (Kujivunia || Niko_de_Andjelo) && makise_homura) // @match https://tabun.everypony.ru/* // @grant none // @license MIT // ==/UserScript== // Tabun Swarm: https://tabun.everypony.ru/blog/uniblog/194538.html // IDENTICON: https://avatars.dicebear.com/styles/identicon const GRemoteSettingsLink = 'https://raw.githubusercontent.com/Kujivunia/TabunAva-Reborn/main/settings.json'; const GEveryponyCdnStorageRegex = /(https?:)?\/\/cdn\.everypony\.ru\/storage\//; const GEveryponyCdnStorageLink = '//cdn.everypony.ru/storage/'; let GAvaDictionary = {}; let GSettings = {}; function isTabunAvaSettingsPage() { return window.location.search.includes('tabun-ava'); } function addLinkToNavigation() { const navPillsNode = document.querySelector('.nav-pills'); if (!navPillsNode) return; const navItemNode = document.createElement('li'); const navAnchorNode = document.createElement('a'); navAnchorNode.setAttribute('href', '/settings/account?tabun-ava'); navAnchorNode.innerHTML = 'TabunAva'; navItemNode.appendChild(navAnchorNode); navPillsNode.appendChild(navItemNode); if (isTabunAvaSettingsPage()) { const activeNavItemNode = document.querySelector('.nav-pills li.active'); if (activeNavItemNode) activeNavItemNode.classList.remove('active'); navItemNode.classList.add('active'); } } function getDefaultSettings() { return { faceless: 'default', faceless_picture: '', faceless_picture_f: '', blacklist: '', usercss: '', header_text: '', refresh_period: 10, refresh_unit: 'minutes', animated: true, priority: true, noregularava: false, fixavacorners: false, oldauthor: false, notabunava: false, }; } function updateSettingsForm(settings = {}) { const mergedSettings = Object.assign({}, settings); Object.keys(mergedSettings).forEach((key) => { const node = document.getElementById(key); if (node) { if (node.type === 'checkbox') { node.checked = mergedSettings[key]; } else { node.value = mergedSettings[key]; } } }); } /** * Достает локальные настройки из localStorage и объединяет их с внешними настройками с гитхаба * Если пришло время обновлять базу, получает внешние настройки с гитхаба, иначе загружает их * сохранённую копию из localStorage */ function getSettings() { // Достаём локальные настройки из localStorage let settings = {}; const jsonString = localStorage.getItem('TabunAvaReborn_Settings'); if (jsonString) { try { settings = JSON.parse(jsonString); } catch (e) { settings = {}; } } // Объединяем с настройками по-умолчанию, на случай, если в localStorage отсутствуют настройки settings = Object.assign({}, getDefaultSettings(), settings); const oldSettings = Object.assign({}, GSettings); GSettings = settings; const shouldUpdate = shouldUpdateAvatarsStorage(); GSettings = oldSettings; // Получаем внешние настройки и объединяем с ними локальные настройки if (shouldUpdate) { return getRemoteSettings() .then((remoteSettings) => { settings.remote = remoteSettings; localStorage.setItem('TabunAvaReborn_Settings', JSON.stringify(settings)); return settings; }); } else { if (!settings.remote) { settings.remote = getDefaultRemoteSettings(); } return Promise.resolve(settings); } } function getRefreshMillis() { let millis = 1000 * +GSettings.refresh_period; // 1 second if (GSettings.refresh_unit === 'minutes') { millis *= 60; } else if (GSettings.refresh_unit === 'hours') { millis *= 60 * 60; } else if (GSettings.refresh_unit === 'days') { millis *= 60 * 60 * 24; } return millis; } function saveSettings() { const settings = { remote: GSettings.remote || getDefaultRemoteSettings(), }; Object.keys(getDefaultSettings()).forEach((key) => { const node = document.getElementById(key); if (node) { if (node.type === 'checkbox') { settings[key] = node.checked; } else { settings[key] = node.value; } } }); localStorage.setItem('TabunAvaReborn_Settings', JSON.stringify(settings)); alert('Настройки сохранены'); } function getDefaultRemoteSettings() { return { post: 'https://tabun.everypony.ru/blog/TabunAva/203681.html', blacklist: [], }; } function getRemoteSettings() { return fetch(GRemoteSettingsLink) .then((response) => { if (!response.ok) { return getDefaultRemoteSettings(); } return response.json(); }) .then((settings) => { return Object.assign({}, getDefaultRemoteSettings(), settings); }) .catch(() => { return getDefaultRemoteSettings(); }) } function replaceSettingsForm(formNode) { const securityLsKey = document.querySelector('[name=security_ls_key]'); const node = formNode || document.querySelector('form.wrapper-content'); node.innerHTML = getSettingsTemplate(); if (securityLsKey) { node.innerHTML += '<input type="hidden" name="security_ls_key" value="' + securityLsKey.value + '">'; } updateSettingsForm(GSettings); const saveButtonNode = document.querySelector('#save_button'); saveButtonNode.addEventListener('click', (event) => { event.preventDefault(); saveSettings(saveButtonNode); }); const refreshButtonNode = document.querySelector('#refresh_button'); refreshButtonNode.addEventListener('click', (event) => { event.preventDefault(); refreshAvatarsStorage() .then(() => { alert('База данных обновлена'); }); }); } function getSettingsButtonTemplate() { return '\ <style>\ .ta-button {\ height: 27px !important;\ display: inline-block;\ width: 27px !important;\ vertical-align: bottom;\ background: linear-gradient(0deg, #f4f4f4, #f9fbfb);\ color: #8a9198;\ border-radius: 4px;\ border: 1px solid #e3e6eb;\ box-sizing: border-box;\ }\ \ .ta-button > svg {\ fill: currentColor;\ width: 21px;\ height: 21px;\ margin-top: 2px;\ margin-left: 2px;\ }\ \ .ta-button:hover {\ background: linear-gradient(0deg, #23b2fe, #4cc3ff);\ border-color: #28adea;\ color: #ffffff;\ }\ </style>\ <a class="ta-button">\ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px">\ <path d="M0 0h24v24H0V0z" fill="none"></path>\ <path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86l-3 3.87L9 13.14 6 17h12l-3.86-5.14z"></path>\ </svg>\ </a>\ '; } function getSettingsTemplate() { return '\ <div class="wrapper-content">\ <dl class="form-item">\ <a href="https://tabun.everypony.ru/settings/account?tabun-ava" id="avatar-upload">Загрузить аватар</a>\ </dl>\ <dl class="form-item">\ <label for="faceless" style="margin-bottom: 7px">Как отображать безликих пони:</label>\ <select name="faceless" id="faceless" class="input-width-200">\ <option value="default" selected="">Не изменять</option>\ <option value="identicon">IDENTICON</option>\ <option value="swarm">Swarm</option>\ <option value="other">Своя картинка</option>\ </select>\ </dl>\ <dl class="form-item">\ <label for="faceless_picture" style="margin-bottom: 7px">\ Своя картинка безликого пони:\ </label>\ <input\ type="text"\ name="faceless_picture"\ id="faceless_picture"\ class="input-text input-width-200"\ placeholder="https://..."\ >\ </dl>\ <dl class="form-item">\ <label for="faceless_picture_f" style="margin-bottom: 7px">\ Своя картинка безликой кобылки (если отличается от предыдущей):\ </label>\ <input\ type="text"\ name="faceless_picture_f"\ id="faceless_picture_f"\ class="input-text input-width-200"\ placeholder="https://..."\ >\ </dl>\ <dl class="form-item">\ <label for="header_text" style="margin-bottom: 7px">\ Заголовок Табуна:\ </label>\ <input\ type="text"\ name="header_text"\ id="header_text"\ class="input-text input-width-200"\ placeholder="Да, это — Табун!"\ >\ </dl>\ <dl class="form-item">\ <label for="blacklist" style="margin-bottom: 7px">\ Чёрный список:\ </label>\ <textarea\ name="blacklist"\ id="blacklist"\ class="input-text input-width-200"\ rows="2"\ placeholder="Pony, Pony2, Pony3"\ style="resize: vertical"\ ></textarea>\ </dl>\ <dl class="form-item">\ <label for="refresh_period" style="margin-bottom: 7px">\ Частота обновления базы аватарок:\ </label>\ <input\ type="text"\ name="refresh_period"\ id="refresh_period"\ class="input-text"\ placeholder="30"\ style="width: 36px; margin-right: 4px;"\ >\ <select\ name="refresh_unit"\ id="refresh_unit"\ style="width: 70px; margin-right: 4px;"\ >\ <option value="minutes" selected="">минут</option>\ <option value="hours">часов</option>\ <option value="days">дней</option>\ </select>\ <button\ type="submit"\ id="refresh_button"\ name="refresh_button"\ class="button button-primary"\ style="width: 80px; height: 26px; margin-top: -4px;"\ >\ Обновить\ </button>\ </dl>\ <dl class="form-item">\ <label for="usercss" style="margin-bottom: 7px">\ Свой CSS:\ </label>\ <textarea\ name="usercss"\ id="usercss"\ class="input-text input-width-400"\ rows="4"\ placeholder="body {\n background: #000;\n}"\ style="resize: vertical"\ ></textarea>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="fixavacorners" name="priority" value="0" class="input-checkbox">\ вернуть квадратные аватарки\ </label>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="oldauthor" name="priority" value="0" class="input-checkbox">\ вернуть старую индикацию автора\ </label>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="animated" name="animated" value="1" class="input-checkbox">\ анимированные аватарки\ </label>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="priority" name="priority" value="1" class="input-checkbox">\ приоритет аватарок из темы над аватарками из профиля\ </label>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="noregularava" name="priority" value="0" class="input-checkbox">\ игнорировать аватар табуна\ </label>\ </dl>\ <dl class="form-item">\ <label>\ <input type="checkbox" id="notabunava" name="priority" value="0" class="input-checkbox">\ игнорировать аватар TabunAva\ </label>\ </dl>\ <button id="save_button" type="submit" name="submit" class="button button-primary">Сохранить</button>\ </div>\ <style>\ form > .wrapper-content > .form-item #avatar-upload {\ font-size: 18px;\ line-height: 1.4;\ font-weight: 600;\ color: indianred;\ padding: 10px 0;\ display: block;\ }\ </style>\ '; } function initSettingsPage() { if (!isTabunAvaSettingsPage()) { const widemodeNode = document.querySelector('#widemode'); const span = document.createElement('span'); span.innerHTML = getSettingsButtonTemplate().trim(); widemodeNode.appendChild(span); const popup = document.createElement('div'); popup.classList.add('ta-popup'); popup.style.display = 'none'; popup.innerHTML = '\ <style>\ .ta-popup {\ position: fixed;\ bottom: 50px;\ right: 0;\ width: 276px;\ z-index: 999;\ background: #ffffff;\ border-radius: 10px 0 0 10px;\ padding: 16px;\ box-sizing: border-box;\ border: 1px solid #ccc;\ }\ </style>\ <div id="settings-popup-content"></div>\ '; document.body.appendChild(popup); widemodeNode.querySelector('.ta-button') .addEventListener('click', () => { if (popup.style.display === 'none') { popup.style.display = 'block'; } else { popup.style.display = 'none'; } }); const settingsNode = document.querySelector('#settings-popup-content'); replaceSettingsForm(settingsNode); } if (window.location.href.includes('/settings')) { addLinkToNavigation(); if (isTabunAvaSettingsPage()) { replaceSettingsForm(); } } } function getAvatarsDocument() { return fetch(GSettings.remote.post) .then((response) => { return response.text(); }) .then((text) => { let domParser = new DOMParser(); return domParser.parseFromString(text, "text/html"); }); } function fillAvatarsDictionary(avaDocument) { GAvaDictionary = {}; const commentNodes = avaDocument.querySelectorAll('#comments .comment'); commentNodes.forEach((commentNode) => { const authorNode = commentNode.querySelector('.comment-author'); const username = authorNode && authorNode.textContent.trim(); if (!username) return; const contentNode = commentNode.querySelector('.comment-content'); const imageNode = contentNode && contentNode.querySelector('.text > img'); if (imageNode && imageNode.hasAttribute('src')) { GAvaDictionary[username] = imageNode .getAttribute('src') .replace(GEveryponyCdnStorageRegex, ''); // Сокращаем количество сохраняемых символов } }); } // Сохранить список аватаров в локальное хранилище браузера function saveAvatarsDictionary() { const jsonString = JSON.stringify(GAvaDictionary); localStorage.setItem('TabunAvaReborn_Avatars', jsonString); localStorage.setItem('TabunAvaReborn_LastUpdate', Date.now().toString()); } function refreshAvatarsStorage() { return getRemoteSettings() .then((remoteSettings) => { GSettings.remote = remoteSettings; localStorage.setItem('TabunAvaReborn_Settings', JSON.stringify(GSettings)); return getAvatarsDocument(); }) .then((avaDocument) => { fillAvatarsDictionary(avaDocument); saveAvatarsDictionary(); }); } function shouldUpdateAvatarsStorage() { const lastUpdate = +(localStorage.getItem('TabunAvaReborn_LastUpdate') || '0'); return (Date.now() - lastUpdate) > getRefreshMillis(); // прошло больше 10 минут с последнего обновления } // Достать список аватаров из локального хранилища браузера или обновить из поста function loadAvatarsDictionary() { if (shouldUpdateAvatarsStorage()) { return refreshAvatarsStorage(); } else { const jsonString = localStorage.getItem('TabunAvaReborn_Avatars'); if (jsonString) { try { GAvaDictionary = JSON.parse(jsonString); return Promise.resolve(); } catch (e) { return refreshAvatarsStorage(); } } } } function isDefaultAvatar(link) { if(GSettings.noregularava) return true; return /(\/local\/avatar_male_)/.test(link) || /(\/local\/avatar_female)/.test(link); } function getIdenticonAvatar(username) { return 'https://api.dicebear.com/8.x/identicon/svg?seed=' + username + '&scale=100&size=48'; } function getNewTabunAvatar(username) { if(GSettings.notabunava) return false; if (GAvaDictionary[username]) { if (!/^(https?:)?\/\//.test(GAvaDictionary[username])) { return GEveryponyCdnStorageLink + GAvaDictionary[username]; } return GAvaDictionary[username]; } return false; } function isGIF(src) { return src.includes('.gif'); } function freezeGIF(imageNode) { const c = document.createElement('canvas'); const w = c.width = imageNode.width; const h = c.height = imageNode.height; c.getContext('2d').drawImage(imageNode, 0, 0, w, h); try { imageNode.src = c.toDataURL("image/gif"); // if possible, retain all css aspects } catch (e) { // cross-domain -- mimic original with all its tag attributes for (let j = 0, a; a = imageNode.attributes[j]; j++) c.setAttribute(a.name, a.value); imageNode.parentNode.replaceChild(c, imageNode); } } function getBlackList() { let blacklist = GSettings.blacklist .replace(/ /g, '') .split(','); if (Array.isArray(GSettings.remote && GSettings.remote.blacklist)) { blacklist = blacklist.concat(GSettings.remote.blacklist); } return blacklist; } function replaceAvatarInImageNode(imageNode, username) { const ignore = getBlackList(); const tabunAvatar = getNewTabunAvatar(username); if (tabunAvatar && !ignore.includes(username)) { if(GSettings.priority || !imageNode.getAttribute('src') || isDefaultAvatar(imageNode.getAttribute('src'))) { imageNode.setAttribute('src', tabunAvatar); if (!GSettings.animated && isGIF(tabunAvatar)) { freezeGIF(imageNode); } } } else if ( !imageNode.getAttribute('src') || isDefaultAvatar(imageNode.getAttribute('src')) ) { if (GSettings.faceless === 'identicon') { imageNode.setAttribute('src', getIdenticonAvatar(username)); } else if (GSettings.faceless === 'swarm') { const domain = '//cdn.everypony.ru/storage/00/28/16/2020/03/19/'; const src = imageNode.getAttribute('src'); if (src.includes('female_48x48.png')) { imageNode.setAttribute('src', domain + 'be9038d210.jpg'); } else if (src.includes('male_48x48.png')) { imageNode.setAttribute('src', domain + '02dcb0e9c1.jpg'); } else if (src.includes('female_24x24.png')) { imageNode.setAttribute('src', domain + 'f46f457af7.jpg'); } else if (src.includes('male_24x24.png')) { imageNode.setAttribute('src', domain + 'b76b8f4e75.jpg'); } else if (src.includes('female')) { imageNode.setAttribute('src', domain + '4d43849b81.jpg'); } else if (src.includes('male')) { imageNode.setAttribute('src', domain + '4dac2ae27e.jpg'); } } else if (GSettings.faceless === 'other' && GSettings.faceless_picture) { if (imageNode.getAttribute('src').includes('female') && GSettings.faceless_picture_f) { imageNode.setAttribute('src', GSettings.faceless_picture_f); } else { imageNode.setAttribute('src', GSettings.faceless_picture); } } } } // Замена собственного аватара пользователя в шапке страницы function replaceHeaderAvatar() { const imageNode = document.querySelector('#dropdown-user img'); if (!imageNode) return; const usernameNode = document.querySelector("#dropdown-user .username"); const username = usernameNode && usernameNode.textContent.trim(); if (!username) return; replaceAvatarInImageNode(imageNode, username); } // Замена аватара пользователя в профиле function replaceProfileAvatar() { const imageNode = document.querySelector('.profile img.avatar'); if (!imageNode) return; const usernameNode = document.querySelector(".profile [itemprop=nickname]"); const username = usernameNode && usernameNode.textContent.trim(); if (!username) return; replaceAvatarInImageNode(imageNode, username); } // Замена аватара друзей в профиле function replaceProfileFriendAvatars() { const userNodes = document.querySelectorAll('.user-list-avatar > *'); userNodes.forEach((userNode) => { const imageNode = userNode.querySelector('img'); if (!imageNode) return; const username = userNode.textContent.trim(); if (!username) return; imageNode.width = 48; imageNode.height = 48; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватара автора поста function replaceTopicAuthorAvatars() { const topicNodes = document.querySelectorAll('.topic'); topicNodes.forEach((topicNode) => { const imageNode = topicNode.querySelector('.avatar'); if (!imageNode) return; const usernameNode = topicNode.querySelector("[rel=author]"); const username = usernameNode && usernameNode.textContent.trim(); if (!username) return; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в комментариях function replaceCommentAvatars() { const commentNodes = document.querySelectorAll('.comment'); commentNodes.forEach((commentNode) => { const authorNode = commentNode.querySelector('.comment-author'); const username = authorNode && authorNode.textContent.trim(); if (!username) return; const imageNode = commentNode.querySelector('img.comment-avatar'); if (!imageNode) return; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в ленте активности function replaceStreamAvatars() { const streamNodes = document.querySelectorAll('.stream-item'); streamNodes.forEach((streamNode) => { const authorNode = streamNode.querySelector('.info a'); const username = authorNode && authorNode.textContent.trim(); if (!username) return; const imageNode = streamNode.querySelector('img'); if (!imageNode) return; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в окошках просмотра оценок function replaceVoteAvatars() { const voteNodes = document.querySelectorAll('.vote-list-item'); voteNodes.forEach((voteNode) => { const authorNode = voteNode.querySelector('.ls-user'); const username = authorNode && authorNode.textContent.trim(); if (!username) return; const imageNode = authorNode.querySelector('img'); if (!imageNode) return; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в разделе "Брони" function replacePeopleAvatars() { const userNodes = document.querySelectorAll('.table-users .cell-name'); userNodes.forEach((userNode) => { const authorNode = userNode.querySelector('.username'); const username = authorNode && authorNode.textContent.trim(); if (!username) return; const imageNode = userNode.querySelector('img'); if (!imageNode) return; imageNode.width = 48; imageNode.height = 48; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в блоке "Пожертвования" function replaceDonationAvatars() { const userNodes = document.querySelectorAll('.donation-list > *'); userNodes.forEach((userNode) => { const username = userNode.textContent.trim(); if (!username) return; const imageNode = userNode.querySelector('img'); if (!imageNode) return; imageNode.width = 24; imageNode.height = 24; replaceAvatarInImageNode(imageNode, username); }); } // Замена аватаров в блоке "Пожертвования" function replaceProfileSettingsAvatar() { const imageNode = document.querySelector('#avatar-img'); if (!imageNode) return; const usernameNode = document.querySelector("#dropdown-user .username"); const username = usernameNode && usernameNode.textContent.trim(); if (!username) return; replaceAvatarInImageNode(imageNode, username); } function replaceAvatarsOnCommentsRefresh() { const countCommentsNode = document.querySelector('#count-comments'); if (!countCommentsNode) return; countCommentsNode.addEventListener('DOMSubtreeModified', () => { replaceCommentAvatars(); }); } function replaceAvatarsOnVotesRefresh() { document.addEventListener('DOMSubtreeModified', () => { replaceVoteAvatars(); }); } function replaceAvatarsOnRepliesRefresh() { const avatarNodes = document.querySelectorAll('.tabun-replies-container img.comment-avatar') avatarNodes.forEach((imageNode) => { const authorNode = imageNode.parentElement if(!authorNode || !authorNode.getAttribute('href')) return; const username = authorNode.getAttribute('href').replace('/profile/', '').replace('/', '') if (!username) return; replaceAvatarInImageNode(imageNode, username); }) } function getFileBase64(file) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = (e) => { resolve(e.target.result); }; reader.onerror = reject; }) } function getImageDimensions(url) { const img = document.createElement('img'); const promise = new Promise((resolve, reject) => { img.onload = () => { // Natural size is the actual image size regardless of rendering. // The 'normal' width/height are for the **rendered** size. const width = img.naturalWidth; const height = img.naturalHeight; // Resolve promise with the width and height resolve({ width, height }); }; // Reject promise on error img.onerror = reject; }); // Setting the source makes it start downloading and eventually call onload img.src = url; return promise; } function initAvatarUpload() { const avatarUploadNode = document.querySelector('#avatar-upload'); const avatarRemoveNode = document.querySelector('#avatar-remove'); const securityLsKey = document.querySelector('[name=security_ls_key]'); if (!securityLsKey || !avatarUploadNode) return; if (avatarRemoveNode) { avatarRemoveNode.style.display = 'none'; } const input = document.createElement('input') input.type = 'file'; input.accept = 'image/jpeg,image/png,image/gif'; input.addEventListener('change', () => { if (!input.files[0]) return; getFileBase64(input.files[0]) .then((base64) => { return getImageDimensions(base64) }) .then((dimensions) => { if (dimensions.width > 100 || dimensions.height > 100) { throw new Error('Максимальный размер картинки - 100x100 пикселей'); } const uploadBody = new FormData(); uploadBody.append('img_file', input.files[0]); uploadBody.append('security_ls_key', securityLsKey.value); return fetch('https://tabun.everypony.ru/ajax/upload/image/', { method: 'POST', body: uploadBody, }); }) .then((response) => { if (!response.ok) { throw new Error('Не удалось загрузить автар, обратитесь к создателю скрипта. Код ошибки: UPLOAD_IMAGE_ERR'); } return response.text(); }) .then((text) => { if (!text) { throw new Error('Не удалось загрузить автар, обратитесь к создателю скрипта. Код ошибки: UPLOAD_IMAGE_EMPTY'); } text = text.replace(/"/g, '"') .replace(/\\\//g, '/'); const match = text.match(/src=\\"([^ ]+)\\"/); if (!(match && match[1])) { throw new Error('Не удалось загрузить автар, обратитесь к создателю скрипта. Код ошибки: NO_MATCH'); } const postIdMatches = GSettings.remote.post.match(/(\d+).html$/); if (!postIdMatches || !postIdMatches[1]) { throw new Error('Не удалось загрузить автар, обратитесь к создателю скрипта. Код ошибки: NO_POST_ID'); } const commentBody = new FormData(); commentBody.append('comment_text', '<img src="' + match[1] + '" alt="avatar">'); commentBody.append('reply', '0'); commentBody.append('cmt_target_id', postIdMatches[1]); commentBody.append('security_ls_key', securityLsKey.value); return fetch('https://tabun.everypony.ru/blog/ajaxaddcomment/', { method: 'POST', body: commentBody, }) }) .then((response) => { if (!response.ok) { throw new Error('Не удалось загрузить автар, обратитесь к создателю скрипта. Код ошибки: ADD_COMMENT_ERR'); } localStorage.setItem('TabunAvaReborn_LastUpdate', '0'); window.location.reload(); }) .catch((error) => { alert(error.message); }); }); avatarUploadNode.addEventListener('click', (e) => { e.preventDefault(); input.click(); }); } function replaceHeaderText() { if (GSettings.header_text) { const logoNode = document.querySelector('a#logolink'); if (!logoNode) return; logoNode.text = GSettings.header_text; } } function fixStyles() { var styleSheet = document.createElement("style"); styleSheet.innerText = GSettings.usercss; if (GSettings.fixavacorners) { styleSheet.innerText += "img.comment-avatar {border-radius: 0px !important; } "; } if (GSettings.oldauthor) { styleSheet.innerText += ".comment-info .comment-author.comment-topic-author span { color: #4b5468; } "; styleSheet.innerText += ".comment-info .comment-author.comment-topic-author::after { display: none; } "; } document.head.appendChild(styleSheet); } function updateMargins() { const itm = document.querySelectorAll("dl.form-item"); if (!itm) return; if (window.innerHeight > 1200) { itm.forEach((i) => { i.style['marginBottom'] = '' }); } else { itm.forEach((i) => { i.style['marginBottom'] = '2px' }); } } getSettings() .then((settings) => { GSettings = settings; initSettingsPage(); initAvatarUpload(); replaceHeaderText(); fixStyles(); updateMargins(); window.addEventListener('resize', updateMargins); loadAvatarsDictionary() .then(() => { var commentsNode = document.querySelector('#content-wrapper'); var repliesNode = document.querySelector('.tabun-replies-container'); if (commentsNode) new MutationObserver(replaceAvatarsOnCommentsRefresh).observe(commentsNode, {childList: true, subtree: true}); if (commentsNode) new MutationObserver(replaceAvatarsOnVotesRefresh).observe(commentsNode, {childList: true, subtree: true}); if (repliesNode) new MutationObserver(replaceAvatarsOnRepliesRefresh).observe(repliesNode, {childList: true, subtree: true}); replaceHeaderAvatar(); replaceCommentAvatars(); replaceTopicAuthorAvatars(); replaceProfileAvatar(); replaceProfileFriendAvatars(); replaceStreamAvatars(); replacePeopleAvatars(); replaceDonationAvatars(); replaceProfileSettingsAvatar(); }); })