картинки
// ==UserScript==
// @name @gif
// @namespace нету
// @version 0
// @description картинки
// @author жди
// @match *://lolz.live/*
// @match *://zelenka.guru/*
// @match *://lolz.guru/*
// @match *://lolz.market/*
// @match *://zelenka.market/*
// @match *://lzt.market/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=lolz.live
// @license MIT
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant unsafeWindow
// ==/UserScript==
(function () {
'use strict';
const AUTOSEND_SETTING_KEY = "autosend_enabled";
let autoSendEnabled = GM_getValue(AUTOSEND_SETTING_KEY, false);
let lastQuery = '';
let debounceTimer = null;
let suppressObserver = false;
let randomId = null;
let cmdId = null;
init();
function initObserver() {
const observer = new MutationObserver(() => {
if (suppressObserver) return;
const editor = document.querySelector('.tiptap.ProseMirror');
if (!editor) return;
const text = editor.innerText.trim();
if (!text.startsWith('@gif ')) {
removeResults();
lastQuery = '';
return;
}
const query = text.slice('@gif '.length).trim();
if (!query) {
removeResults();
lastQuery = '';
return;
}
if (query === lastQuery && document.querySelector('.gif-results-renderer')) {
return;
}
clearTimeout(debounceTimer);
debounceTimer = setTimeout(async () => {
const currentEditor = document.querySelector('.tiptap.ProseMirror');
if (!currentEditor) return;
const currentText = currentEditor.innerText.trim();
if (!currentText.startsWith('@gif ')) {
removeResults();
lastQuery = '';
return;
}
const currentQuery = currentText.slice('@gif '.length).trim();
if (!currentQuery) {
removeResults();
lastQuery = '';
return;
}
if (currentQuery === lastQuery && document.querySelector('.gif-results-renderer')) {
return;
}
try {
const images = await getGifs(currentQuery);
lastQuery = currentQuery;
renderImages(images);
} catch (err) {
console.error('[gif] req failed:', err);
removeResults();
}
}, 400);
});
observer.observe(document.body, {
childList: true, subtree: true, characterData: true
});
}
function addStyles() {
GM_addStyle(`
.gif-results-renderer {
position: absolute;
left: 60px;
bottom: calc(100% + 8px);
z-index: 9999;
pointer-events: none;
}
.gif-popup {
pointer-events: auto;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
gap: 8px;
width: min(360px, calc(100vw - 80px));
max-height: 700px;
overflow-y: auto;
padding: 8px;
border-radius: 8px;
background: #2b2b2b;
border: 1px solid rgba(255,255,255,0.08);
box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}
.gif-result {
width: 100%;
aspect-ratio: 1 / 1;
border-radius: 8px;
overflow: hidden;
cursor: pointer;
background: rgba(255,255,255,0.04);
}
.gif-result:hover {
outline: 2px solid rgba(255,255,255,0.35);
}
.gif-result img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
`);
}
function registerSetting() {
if (cmdId !== null) {
GM_unregisterMenuCommand(cmdId);
}
const commandTitle = (autoSendEnabled ? "Выключить" : "Включить") + " автоотправку";
cmdId = GM_registerMenuCommand(commandTitle, () => {
autoSendEnabled = !autoSendEnabled;
GM_setValue(AUTOSEND_SETTING_KEY, autoSendEnabled);
registerSetting();
});
}
function removeResults() {
suppressObserver = true;
document.querySelectorAll('.gif-results-renderer').forEach(el => el.remove());
queueMicrotask(() => {
suppressObserver = false;
});
}
function renderImages(images) {
removeResults();
if (!images || !images.length) return;
const editor = document.querySelector('.tiptap.ProseMirror');
if (!editor) return;
const wrapper = document.querySelector('.editor-box-wrapper') || editor.parentElement;
if (!wrapper) return;
if (getComputedStyle(wrapper).position === 'static') {
wrapper.style.position = 'relative';
}
const renderer = document.createElement('div');
renderer.className = 'gif-results-renderer';
const popup = document.createElement('div');
popup.className = 'gif-popup';
images.forEach(src => {
const item = document.createElement('div');
item.className = 'gif-result';
const img = document.createElement('img');
img.src = src.preview;
img.alt = src.title;
img.title = src.original;
item.appendChild(img);
item.addEventListener('click', () => {
insertImg(src.original);
removeResults();
});
popup.appendChild(item);
});
renderer.appendChild(popup);
suppressObserver = true;
wrapper.appendChild(renderer);
queueMicrotask(() => {
suppressObserver = false;
});
}
function insertImg(src) {
const editor = document.querySelector('.tiptap.ProseMirror');
if (!editor) return;
const text = editor.innerText;
const newText = text.replace(/^@gif(?:\s+.*)?$/m, `[IMG]${src}[/IMG]`);
editor.focus();
editor.innerText = newText;
editor.dispatchEvent(new Event('input', {bubbles: true}));
if (autoSendEnabled) setTimeout(() => unsafeWindow.$('[aria-label="send-message"]').trigger('click'), 200);
}
function request(url) {
return new Promise((resolve, reject) => {
toggleProgress('PseudoAjaxStart');
GM_xmlhttpRequest({
method: 'GET',
url,
headers: {
Accept: 'application/json'
},
onload: res => {
toggleProgress('PseudoAjaxStop');
resolve(JSON.parse(res.responseText));
},
onerror: err => {
toggleProgress('PseudoAjaxStop');
reject(err);
},
ontimeout: err => {
toggleProgress('PseudoAjaxStop');
reject(err);
},
onabort: err => {
toggleProgress('PseudoAjaxStop');
reject(err);
}
});
});
}
async function getRandomId() {
if (randomId) return randomId;
const url = `https://api.giphy.com/v1/randomid?api_key=3eFQvabDx69SMoOemSPiYfh9FY0nzO9x`; // (лолзовский ключ)
const data = await request(url);
randomId = data?.data?.random_id || '';
return randomId;
}
async function getGifs(query) {
const rid = await getRandomId();
const params = new URLSearchParams({
random_id: rid,
offset: '0',
limit: '25',
bundle: 'messaging_non_clips',
rating: 'g',
api_key: "3eFQvabDx69SMoOemSPiYfh9FY0nzO9x"
});
let url;
params.set('q', query);
params.set('lang', 'ru');
url = `https://api.giphy.com/v1/gifs/search?${params.toString()}`;
const data = await request(url);
return parse(data);
}
function parse(data) {
if (!data || !Array.isArray(data.data)) return [];
const results = [];
const seen = new Set();
for (const item of data.data) {
const preview =
item?.images?.fixed_width_small?.url ||
item?.images?.fixed_height_small?.url ||
item?.images?.fixed_width?.url ||
item?.images?.original?.url;
const original =
item?.images?.original?.url ||
item?.images?.fixed_width?.url ||
preview;
if (!preview || !original) continue;
if (seen.has(original)) continue;
seen.add(original);
results.push({
preview,
original,
title: item.title || 'gif'
});
}
return results;
}
function toggleProgress(eventName) {
const $ = unsafeWindow.jQuery || unsafeWindow.$;
if ($) {
$(unsafeWindow.document).trigger(eventName);
}
}
function init() {
initObserver();
addStyles();
registerSetting();
}
})();