ControlC
· Pastebin
Login
Register
ControlC
/
Create paste
Paste content
Up to 100 KB of text. BBCode formatting is supported.
Title
- optional
Content
B
I
U
S
</>
Colors ↓
Sizes ↓
Size 1
Size 2
Size 3
Size 4
Size 5
Size 6
Size 7
// ==UserScript== // @name Neochan extension // @namespace http://tampermonkey.net/ // @version 1.4 // @description Расширение неочана // @match https://neochan.org/*/* // @match https://neochan.net/*/* // @grant none // ==/UserScript== (function() { 'use strict'; console.log('DEBUGGG') function resetPreviewFileBlock(fileBlock) { // Удаляем добавленные элементы fileBlock.querySelectorAll('.post-file-name-visible').forEach(el => el.remove()); fileBlock.querySelectorAll('.tiktok-icon').forEach(el => el.remove()); // Убираем флаг обработки fileBlock.classList.remove('fnAdded'); } function decodeHtml(str) { const parser = new DOMParser(); const doc = parser.parseFromString(str, "text/html"); return doc.documentElement.textContent; } function processFiles() { document.querySelectorAll('.post-file').forEach(fileBlock => { const article = fileBlock.closest('article'); const isPreview = article && article.classList.contains('hover'); // Если это превью — всегда очищаем и обрабатываем заново if (isPreview) { if (fileBlock.dataset.fnPreviewAdded) return; fileBlock.dataset.fnPreviewAdded = "1"; resetPreviewFileBlock(fileBlock); } else { if (fileBlock.dataset.fnAdded) return; fileBlock.dataset.fnAdded = "1"; } const link = fileBlock.querySelector('.post-file-link'); if (!link) return; const originalName = decodeHtml(link.getAttribute('name')); if (!originalName) return; const infoDiv = link.getAttribute('data-func') !== 'PlayFirstEmbed' ? link.parentElement.querySelector('.post-file-info') : null; if (!infoDiv) return; // === Создаём блок с названием === const nameDiv = document.createElement('div'); // === Клик по названию файла → скачать оригинал === nameDiv.style.cursor = 'pointer'; nameDiv.addEventListener('click', () => { const a = document.createElement('a'); a.href = link.href; a.download = originalName; document.body.appendChild(a); a.click(); a.remove(); }); // === Правый клик → копировать имя файла === nameDiv.addEventListener('contextmenu', (e) => { e.preventDefault(); navigator.clipboard.writeText(nameDiv.textContent) .then(() => { const toast = document.createElement('div'); toast.className = 'copy-toast'; toast.textContent = 'Скопировано!'; // Позиционируем рядом с элементом const rect = nameDiv.getBoundingClientRect(); toast.style.left = rect.left + window.scrollX + 'px'; toast.style.top = rect.top + window.scrollY - 30 + 'px'; document.body.appendChild(toast); // Плавное появление requestAnimationFrame(() => { toast.classList.add('visible'); }); // Удаление setTimeout(() => { toast.classList.remove('visible'); setTimeout(() => toast.remove(), 200); }, 1000); }); }); nameDiv.className = 'post-file-name-visible'; nameDiv.textContent = originalName; nameDiv.title = originalName; // Цвет как у post-file-info const computed = getComputedStyle(infoDiv); nameDiv.style.color = computed.color; // Ширина как у превью const preview = fileBlock.querySelector('img.preview'); if (preview) nameDiv.style.maxWidth = preview.width + 'px'; // Учитываем настройку const showNames = localStorage.getItem('showFilenames') === '1'; nameDiv.style.display = showNames ? '' : 'none'; infoDiv.insertAdjacentElement('afterend', nameDiv); // === TikTok ID === const showTikTok = localStorage.getItem('showTikTokIcons') === '1'; const match = originalName.match(/[67]\d{18}/); if (match && showTikTok) { const id = match[0]; const icon = document.createElement('span'); icon.className = 'tiktok-icon'; icon.title = "Открыть TikTok видео"; icon.style.cursor = 'pointer'; icon.style.marginLeft = '6px'; icon.style.opacity = '0.8'; // SVG иконка TikTok icon.innerHTML = ` <svg width="16" height="16" viewBox="0 0 48 48"> <path fill="currentColor" d="M30 4h6c0 4 3 8 8 8v6c-4 0-8-2-11-5v17a14 14 0 1 1-14-14h2v6h-2a8 8 0 1 0 8 8V4z"/> </svg> `; icon.addEventListener('click', () => { window.open(`https://www.tiktok.com/@/video/${id}`, '_blank'); }); infoDiv.appendChild(icon); } // === GIF превью === const showGIFs = localStorage.getItem('showGIFs') === '1'; const href = link.getAttribute('href'); if (href?.endsWith('.gif') && showGIFs) { const img = fileBlock.querySelector('img.preview'); if (img) { const marker = fileBlock.querySelector('.post-gif-marker'); if (marker) marker.remove(); img.src = img.src .replace('/thumb/', '/src/') .replace(/\.\w+$/, '.gif'); } } }); } function toggleFilenames(enabled) { document.querySelectorAll('.post-file-name-visible').forEach(el => { el.style.display = enabled ? '' : 'none'; }); } function toggleGIFs(enabled) { document.querySelectorAll('.post-file').forEach(fileBlock => { const link = fileBlock.querySelector('.post-file-link'); if (!link) return; const href = link.getAttribute('href'); if (!href || !href.endsWith('.gif')) return; const img = fileBlock.querySelector('img.preview'); const marker = fileBlock.querySelector('.post-gif-marker'); if (enabled) { if (marker) marker.style.display = 'none'; if (img) { img.src = img.src .replace('/thumb/', '/src/') .replace(/\.\w+$/, '.gif'); } } else { if (marker) marker.style.display = ''; if (img) { img.src = img.src .replace('/src/', '/thumb/') .replace(/\.gif$/, '.jpg'); } } }); } function toggleTikTokIcons(enabled) { document.querySelectorAll('.tiktok-icon').forEach(el => { el.style.display = enabled ? '' : 'none'; }); } function fixPlayerDownloadButton() { const player = document.querySelector('#player-container'); if (!player) return; const video = player.querySelector('video'); if (!video) return; const source = video.querySelector('source'); if (!source) return; const src = source.getAttribute('src'); if (!src) return; // Ищем превью с таким же src const previewLink = document.querySelector(`.post-file-link[href="${src}"]`); if (!previewLink) return; const originalName = previewLink.getAttribute('name'); if (!originalName) return; // Ищем кнопку Plyr const btn = player.querySelector('#plyr-download'); if (!btn) return; // Заменяем действие кнопки const parentButton = btn.closest('button'); if (!parentButton) return; parentButton.onclick = (e) => { e.stopPropagation(); e.preventDefault(); const a = document.createElement('a'); a.href = src; a.download = originalName; document.body.appendChild(a); a.click(); a.remove(); }; } function addOptionCheckbox() { const options = document.querySelector('#options .options-tab'); if (!options || document.querySelector('#optionShowFilenames')) return; // Заголовок секции const header = document.createElement('div'); header.className = 'options-item'; header.style.marginTop = '10px'; header.innerHTML = `<span style="font-weight: bold; opacity: 0.8;">Расширение</span>`; options.appendChild(header); const hr = document.createElement('hr'); hr.style.margin = '5px 0 10px 0'; options.appendChild(hr); // Чекбокс: имена файлов const item1 = document.createElement('div'); item1.className = 'options-item'; item1.innerHTML = ` <label class="checktainer_xs"> Показывать имена файлов <input type="checkbox" id="optionShowFilenames"> <span class="checkmark_xs"></span> </label> `; options.appendChild(item1); // Чекбокс: TikTok иконки const item2 = document.createElement('div'); item2.className = 'options-item'; item2.innerHTML = ` <label class="checktainer_xs"> Показывать соус TikTok-ов <input type="checkbox" id="optionShowTikTokIcons"> <span class="checkmark_xs"></span> </label> `; options.appendChild(item2); // Состояния const showNames = localStorage.getItem('showFilenames') === '1'; const showTikTok = localStorage.getItem('showTikTokIcons') === '1'; const cb1 = document.querySelector('#optionShowFilenames'); const cb2 = document.querySelector('#optionShowTikTokIcons'); cb1.checked = showNames; cb2.checked = showTikTok; cb1.addEventListener('change', e => { const state = e.target.checked; localStorage.setItem('showFilenames', state ? '1' : '0'); toggleFilenames(state); }); cb2.addEventListener('change', e => { const state = e.target.checked; localStorage.setItem('showTikTokIcons', state ? '1' : '0'); toggleTikTokIcons(state); }); // Чекбокс: GIF → оригинал const item3 = document.createElement('div'); item3.className = 'options-item'; item3.innerHTML = ` <label class="checktainer_xs"> Показывать GIF <input type="checkbox" id="optionShowGIFs"> <span class="checkmark_xs"></span> </label> `; options.appendChild(item3); const showGIFs = localStorage.getItem('showGIFs') === '1'; const cb3 = document.querySelector('#optionShowGIFs'); cb3.checked = showGIFs; cb3.addEventListener('change', e => { const state = e.target.checked; localStorage.setItem('showGIFs', state ? '1' : '0'); toggleGIFs(state); }); // Чекбокс: рандомизация имён файлов const item4 = document.createElement('div'); item4.className = 'options-item'; item4.innerHTML = ` <label class="checktainer_xs"> Удалять имена загружаемых файлов <input type="checkbox" id="optionRandomizeFilenames"> <span class="checkmark_xs"></span> </label> `; options.appendChild(item4); const randomEnabled = localStorage.getItem('randomizeFilenames') === '1'; const cb4 = document.querySelector('#optionRandomizeFilenames'); cb4.checked = randomEnabled; cb4.addEventListener('change', e => { const state = e.target.checked; localStorage.setItem('randomizeFilenames', state ? '1' : '0'); }); } // Стили const style = document.createElement('style'); style.textContent = ` .post-file-name-visible { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: smaller; font-style: italic; padding-right: 5px; transition: filter 0.15s ease-in-out; cursor: pointer; } .post-file-name-visible:hover { transform: scale(1.05); } .tiktok-icon svg { vertical-align: middle; } .copy-toast { position: absolute; padding: 6px 12px; background: rgba(0, 0, 0, 0.75); color: #fff; border-radius: 6px; font-size: 13px; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; z-index: 9999; } .copy-toast.visible { opacity: 1; } `; document.head.appendChild(style); const styleFix = document.createElement('style'); styleFix.textContent = ` .plyr__poster { pointer-events: none !important; } `; document.head.appendChild(styleFix); // Запуск processFiles(); toggleFilenames(localStorage.getItem('showFilenames') === '1'); toggleTikTokIcons(localStorage.getItem('showTikTokIcons') === '1'); toggleGIFs(localStorage.getItem('showGIFs') === '1'); addOptionCheckbox(); const observer = new MutationObserver(() => { processFiles(); addOptionCheckbox(); fixPlayerDownloadButton(); }); observer.observe(document.body, { childList: true, subtree: true }); })(); function unixtimeFilename(ext) { const ts = Math.floor(Date.now() / 1000); // unixtime return ts + ext; } (function interceptXHR() { const origSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function(body) { try { const enabled = localStorage.getItem('randomizeFilenames') === '1'; if (body instanceof FormData) { const newForm = new FormData(); for (const [key, value] of body.entries()) { if (value instanceof File) { // 1. Определяем расширение let ext = value.name.match(/\.[a-zA-Z0-9]+$/)?.[0] || ''; // 2. Если .mov → заменяем на .mp4 (всегда) if (ext.toLowerCase() === '.mov') { ext = '.mp4'; } // 3. Выбираем имя файла let newName; if (enabled) { // Рандомизация включена → генерируем новое имя newName = unixtimeFilename(ext); } else { // Рандомизация выключена → просто меняем расширение newName = value.name.replace(/\.[a-zA-Z0-9]+$/, ext); } // 4. Создаём новый файл const newFile = new File([value], newName, { type: value.type }); newForm.append(key, newFile); } else { newForm.append(key, value); } } return origSend.call(this, newForm); } } catch (e) { console.error("Filename randomizer error:", e); } return origSend.call(this, body); }; })();
Password
Anyone with the link will still need this password to view.
Expires
1 hour
3 hours
6 hours
12 hours
24 hours
48 hours
72 hours
Sign in to enable "Never expires".
Create paste
Please verify you are human
Cancel