// ==UserScript== // @name Neochan autoplay // @namespace http://tampermonkey.net/ // @version 0.1 // @description Adds media controls for neochan // @author You // @match https://*.neochan.ru/* // @match https://*.neochan.net/* // @icon https://www.google.com/s2/favicons?sz=64&domain=neochan.net // @grant GM_addStyle // ==/UserScript== (function() { 'use strict'; GM_addStyle( ".ap-arrow a {display: block;}" + ".ap-arrow {position: fixed; top: 50%; font-size: x-large; cursor: pointer; background-color: rgba(255, 255, 255, 0.2); width: 50px;padding-top: 5px;padding-bottom: 5px;text-align: center; left:0;} " + ".ap-arrow-right {right: 0; left: unset;}"+ ".ap-media-button { display: block; margin-left: 14px;margin-top: 10px; margin-bottom: 5px; border: 0; background: transparent; box-sizing: border-box;width: 0; height: 35px; border-color: transparent transparent transparent #202020; transition: 100ms all ease; "+ "cursor: pointer; border-style: solid; border-width: 16px 0 16px 23px;}" + " .ap-media-button.paused { border-style: double; border-width: 0px 0 0px 23px; } .ap-media-button:hover { border-color: transparent transparent transparent #404040; }" ) const PlayVidLinks = true, ReplaceGifs = true, AddCustomSmiles = true, Smiles = { "enid_wink": { 'smileHtml': '<ul class="smile-tab smile-tab-enid_wink" style="list-style: none; text-align: left; display: none;"><div class="smile" style="display: inline"><i class="s42 s42-enid_wink smiles-icon" data-func="AddSmile" data-arg1="enid_wink"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_amazed smiles-icon" data-func="AddSmile" data-arg1="emma_amazed"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_angry smiles-icon" data-func="AddSmile" data-arg1="emma_angry"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_beauty smiles-icon" data-func="AddSmile" data-arg1="emma_beauty"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_braces smiles-icon" data-func="AddSmile" data-arg1="emma_braces"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_cool smiles-icon" data-func="AddSmile" data-arg1="emma_cool"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_crying smiles-icon" data-func="AddSmile" data-arg1="emma_crying"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_duck smiles-icon" data-func="AddSmile" data-arg1="emma_duck"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_duck2 smiles-icon" data-func="AddSmile" data-arg1="emma_duck2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_scared smiles-icon" data-func="AddSmile" data-arg1="emma_scared"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_serious smiles-icon" data-func="AddSmile" data-arg1="emma_serious"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_serious2 smiles-icon" data-func="AddSmile" data-arg1="emma_serious2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_smile smiles-icon" data-func="AddSmile" data-arg1="emma_smile"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_smile2 smiles-icon" data-func="AddSmile" data-arg1="emma_smile2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_swag smiles-icon" data-func="AddSmile" data-arg1="emma_swag"></i></div><div class="smile" style="display: inline"><i class="s42 s42-emma_tongue smiles-icon" data-func="AddSmile" data-arg1="emma_tongue"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_cat smiles-icon" data-func="AddSmile" data-arg1="enid_cat"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_cute smiles-icon" data-func="AddSmile" data-arg1="enid_cute"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_disgust smiles-icon" data-func="AddSmile" data-arg1="enid_disgust"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_eating smiles-icon" data-func="AddSmile" data-arg1="enid_eating"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_rage smiles-icon" data-func="AddSmile" data-arg1="enid_rage"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_sad smiles-icon" data-func="AddSmile" data-arg1="enid_sad"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_scared smiles-icon" data-func="AddSmile" data-arg1="enid_scared"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_scared2 smiles-icon" data-func="AddSmile" data-arg1="enid_scared2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_scared3 smiles-icon" data-func="AddSmile" data-arg1="enid_scared3"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_smile smiles-icon" data-func="AddSmile" data-arg1="enid_smile"></i></div><div class="smile" style="display: inline"><i class="s42 s42-enid_smile2 smiles-icon" data-func="AddSmile" data-arg1="enid_smile2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_beaten smiles-icon" data-func="AddSmile" data-arg1="jenna_beaten"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_cringe smiles-icon" data-func="AddSmile" data-arg1="jenna_cringe"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_facepalm smiles-icon" data-func="AddSmile" data-arg1="jenna_facepalm"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_kiss smiles-icon" data-func="AddSmile" data-arg1="jenna_kiss"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_laugh smiles-icon" data-func="AddSmile" data-arg1="jenna_laugh"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_nose smiles-icon" data-func="AddSmile" data-arg1="jenna_nose"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_sick smiles-icon" data-func="AddSmile" data-arg1="jenna_sick"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_smile smiles-icon" data-func="AddSmile" data-arg1="jenna_smile"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_smoke smiles-icon" data-func="AddSmile" data-arg1="jenna_smoke"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_think smiles-icon" data-func="AddSmile" data-arg1="jenna_think"></i></div><div class="smile" style="display: inline"><i class="s42 s42-jenna_what_ smiles-icon" data-func="AddSmile" data-arg1="jenna_what_"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_cold smiles-icon" data-func="AddSmile" data-arg1="wedn_cold"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_crying smiles-icon" data-func="AddSmile" data-arg1="wedn_crying"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_eyes smiles-icon" data-func="AddSmile" data-arg1="wedn_eyes"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_growl smiles-icon" data-func="AddSmile" data-arg1="wedn_growl"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_mad smiles-icon" data-func="AddSmile" data-arg1="wedn_mad"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_sad smiles-icon" data-func="AddSmile" data-arg1="wedn_sad"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_smile smiles-icon" data-func="AddSmile" data-arg1="wedn_smile"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_smile2 smiles-icon" data-func="AddSmile" data-arg1="wedn_smile2"></i></div><div class="smile" style="display: inline"><i class="s42 s42-wedn_tired smiles-icon" data-func="AddSmile" data-arg1="wedn_tired"></i></div><div class="smile" style="display: inline"><i class="s42 s42-puppy smiles-icon" data-func="AddSmile" data-arg1="puppy"></i></div></ul>', 'smileIcHtml': '<div class="sc-item" data-func="changeSmileTab" data-arg1="enid_wink"><i class="smile-category-image s42-enid_wink"></i></div>' } } let mediaElems = [], curIndex =0, maxIndex = 0, plrPause = false, musToVid = false; function htmlToElements(html) { var template = document.createElement('template'); template.innerHTML = html; return template.content; } function createArrow(rightSide) { const arrow = htmlToElements(`<div class="ap-nav ap-arrow ${rightSide ? 'ap-arrow-right' : ''}"><a ><i class="fa fa-chevron-${rightSide ? 'right' : 'left'}"></i></a></div>`); arrow.querySelector("a").addEventListener('click', (e) => { if (curIndex == 0 && !rightSide) return; if (curIndex == maxIndex-1 && rightSide) curIndex = -1; let elem = ""; if (plrPause){ const fM = rightSide ? mediaElems.find(e => curIndex < e.getAttribute('ap-index') && e.classList.contains('ap-media')) : mediaElems.filter(e => curIndex > e.getAttribute('ap-index') && e.classList.contains('ap-media'))?.slice(-1)?.[0]; if (fM){ elem = fM; curIndex = +fM.getAttribute('ap-index');} else{ // elem = mediaElems.filter(e => maxIndex > e.getAttribute('ap-index') && e.classList.contains('ap-media'))?.slice(-1)?.[0]; elem = rightSide ? mediaElems.find(e => 0 <= e.getAttribute('ap-index') && e.classList.contains('ap-media')) : mediaElems.filter(e => maxIndex > e.getAttribute('ap-index') && e.classList.contains('ap-media'))?.slice(-1)?.[0]; } }else{ const video = document.querySelector('video'); if (video) video.loop = true; curIndex = curIndex + (rightSide ? 1 : -1); elem = mediaElems.find(e => curIndex == e.getAttribute('ap-index')); } if (!elem) return; document.querySelector("#close-plyr__audio")?.click(); elem.click(); elem.scrollIntoView({block: "center", inline: "nearest"}); switchPlBut(); }); return arrow; } function switchPlBut(val){ const mB = document.querySelector('.ap-media-button') if (!mB) return; if (val !== undefined){ mB.style.display = val ? 'block' : 'none'; return; } if (document.querySelector('#player-container img')?.tagName == 'IMG') { mB.style.display = 'none'; } else { mB.style.display = 'block'; } } function render(){ if(window.location.href.match(/usermod\.php\?|mod\.php\?/)){ const art = document.querySelectorAll('article.post'), controls = document.querySelector('.view-inline-pc'); for (let i = 0; i < art.length; i++) { const a = art[i]; if(a.querySelector('.view-inline-pc')) continue; const header = a.querySelector('header'), postNum = header.querySelector('.post_anchor').name, contrDup = controls.cloneNode(true), links = contrDup.querySelectorAll('a'); for (let j = 0; j < links.length; j++) { const l = links[j]; l.href = l.href.replace(/\/\d+\//, `/${postNum}/`); } header.insertBefore(contrDup, header.querySelector('time')); } } const mE = document.querySelectorAll(`.audio-url, img.webm-file, .img.preview${PlayVidLinks ? ', .y-link' : ""}`); if (mE.length == mediaElems.length) return; let index = 0; mediaElems = [...mE]; mE.forEach(e => { //, vimeo-link const ind = index++, p = e.parentNode; if(e.hasAttribute('ap-parsed')) return; e.setAttribute("ap-index", ind); const classNames = ['webm-file', 'audio-url']; if (PlayVidLinks) classNames.push('y-link'); //, 'vimeo-link' if(classNames.some(cN => e.classList.contains(cN))) { e.classList.add('ap-media'); } if(e.classList.contains("img")){ if(p.name == "ClipboardImage.png"){ const ext = p.href?.match(/\.\w+$/)?.[0]; if (ext && ext != '.png') p.setAttribute("name", p.name.replace(/\.png$/, ext)); } if(ReplaceGifs && p.href.endsWith('.gif')){ p.querySelector('.post-gif-marker').remove(); e.src = e.src.replace(/\/thumb\//, '/src/').replace(/\.\w+$/, '.gif'); } } e.addEventListener('click', e => { const t = e.currentTarget; curIndex = +t.getAttribute('ap-index'); const plClose = document.querySelector("#close-plyr__audio"); if (plClose){ musToVid = true; plClose.click(); } if (e.currentTarget.classList.contains('ap-media')) switchPlBut(true); else switchPlBut(false); }); e.toggleAttribute('ap-parsed'); }) maxIndex = index; } function obsBody(){ const navElems = document.querySelectorAll('.ap-nav'), player = document.querySelector('video, #player-container img, .plyr'), smilePan = document.querySelector(".smile-picker"), navDisplayed = ['none', undefined].includes(navElems[0]?.style?.display)? false : true; if (AddCustomSmiles && smilePan && !document.querySelector(".user-smiles-added")){ const smList = smilePan.querySelector('.smile-picker-box'), smCat = smilePan.querySelector('.smile-category'), smLength = Object.keys(Smiles).length; for(let key in Smiles){ if(smCat.querySelector(`[data-arg1="${key}"]`)) continue; smList.insertBefore(htmlToElements(Smiles[key].smileHtml), smList.firstChild); smCat.insertBefore(htmlToElements(Smiles[key].smileIcHtml), smCat.firstChild); } smList.querySelectorAll('.button').forEach((b)=>{ const n = +b.getAttribute('data-arg2') + smLength; b.id = `btn-more-${n}`; b.setAttribute('data-arg2', n); }); smCat.classList.add('user-smiles-added'); } if (navElems.length && (!player && navDisplayed || player && !navDisplayed)){ if (navDisplayed) { render(); } navElems.forEach(e => {e.style.display = e.style.display == 'none' ? '' : 'none';}); if (musToVid && !navDisplayed) { musToVid = false; } else if (!musToVid){ document.querySelector('.ap-media-button')?.classList.remove("paused"); plrPause = false; } } else { if(player && navElems.length && plrPause) setNextEvent(); if (navDisplayed || !player) return; render(); createNav(); } switchPlBut(); } function createNav(){ const rightArrow = createArrow(true), leftArrow = createArrow(), navElem = document.querySelector(".page-nav"), l = navElem.appendChild(leftArrow), btn = htmlToElements("<button class='ap-media-button ap-nav'></button>"); navElem.appendChild(rightArrow); document.querySelector('.ap-arrow-right').appendChild(btn); document.querySelector('.ap-media-button').addEventListener('click', e => { plrPause = e.currentTarget.classList.toggle("paused"); setNextEvent(); return false; }); } function crMediaObserver(element, checkFunc){ const plInp = document.querySelector('.plyr__progress > input'); if (element && !element.hasAttribute('ap-parsed')) { const observer = new MutationObserver(() => { if(!plrPause) { element.toggleAttribute('ap-parsed'); observer.disconnect(); return; } if (checkFunc()){ document.querySelector('.ap-arrow-right a')?.click(); observer.disconnect(); } }); observer.observe(element, {attributes: true}); element.toggleAttribute('ap-parsed'); }; } function setNextEvent(){ const video = document.querySelector('video'); if (video){ video?.toggleAttribute('loop'); if(video.hasAttribute('ap-parsed')) return; video?.addEventListener("ended", (event) => { document.querySelector('.ap-arrow-right a')?.click(); }); video.toggleAttribute('ap-parsed'); return; } const plInp = document.querySelector('.plyr__progress > input'); crMediaObserver(plInp, () => plInp.style.cssText == '--value: 100%;'); if (PlayVidLinks){ const ytPlr = document.querySelector('#youtubevideo'); crMediaObserver(ytPlr, () => ytPlr.classList.contains('plyr--stopped') && ytPlr.classList.contains('plyr__poster-enabled')); } } function waitForElm(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { observer.disconnect(); resolve(document.querySelector(selector)); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } render(); const threadObserver = new MutationObserver(render), bodyObserver = new MutationObserver(obsBody), article = document.querySelector("article.thread"); if (!article) return; threadObserver.observe(article, {childList: true}); bodyObserver.observe(document.body, {childList: true}); waitForElm('#player-container').then(() => { bodyObserver.observe(document.querySelector('#player-container'), {attributes: true}) }) })();