您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在Kemono或Coomer的post链接下添加video.js视频播放器。
// ==UserScript== // @name Kemono/Coomer-VideoPlayer // @namespace http://tampermonkey.net/ // @version 0.3.5 // @description 在Kemono或Coomer的post链接下添加video.js视频播放器。 // @description:en-US Add video.js player under Kemono or Coomer's post links. // @author dsx137 // @match https://coomer.party/* // @match https://kemono.party/* // @match https://coomer.su/* // @match https://kemono.su/* // @match https://nekohouse.su/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant GM_addStyle // @grant GM_getResourceText // @resource video.js_css https://cdnjs.cloudflare.com/ajax/libs/video.js/8.16.1/video-js.css // @require https://cdnjs.cloudflare.com/ajax/libs/video.js/8.16.1/video.min.js // @license AGPLv3 // ==/UserScript== const suffixes = ['.mp4', '.m4v'] function isSupportedVideoLink(link) { try { const path = new URL(link).pathname.toLowerCase(); return suffixes.some(suffix => path.endsWith(suffix)); } catch (error) { return false; } } function createPlayer(linkSrc) { let player = document.createElement("video"); player.className = "video-js vjs-theme-city"; player.style.width = "100%"; player.style.backgroundColor = "black" player.setAttribute("data-setup", '{"controls":true, "autoplay":false, "preload":"auto", "height":"800px"}'); let src = document.createElement("source"); src.type = "video/mp4"; src.src = linkSrc; player.appendChild(src); let volumePanelHoverCounter = 0; player.addEventListener('keydown', event => { let step = 5; let volumePanel = player.parentElement.querySelector('.vjs-volume-panel'); let volumePanelAdjust = () => { volumePanelHoverCounter++; setTimeout(() => { volumePanelHoverCounter--; if (volumePanelHoverCounter <= 0) { if (!volumePanel.matches(':hover')) { volumePanel.classList.remove('vjs-hover'); } } }, 1000); } switch (event.code) { case 'ArrowLeft': player.currentTime = Math.max(0, player.currentTime - step); break; case 'ArrowRight': player.currentTime = Math.min(player.duration, player.currentTime + step); break; case 'Space': player.paused ? player.play() : player.pause(); break; case 'ArrowUp': if (player.muted) { player.volume = 0 player.muted = false; } player.volume = Math.min(1, player.volume + 0.1); volumePanel.classList.add('vjs-hover'); volumePanelAdjust(); break; case 'ArrowDown': if (player.muted) { break; } player.volume = Math.max(0, player.volume - 0.1); volumePanel.classList.add('vjs-hover'); volumePanelAdjust(); break; case 'KeyM': player.muted = !player.muted; break; case 'KeyF': if (document.fullscreenElement) { document.exitFullscreen(); } else { player.requestFullscreen(); } break; default: return; } event.stopPropagation(); event.preventDefault(); }); return player } function attachPlayer() { let links = Array.from(document.querySelectorAll(".post__attachment-link, .scrape__attachment-link")).filter(it => !it.classList.contains('has-player')); if (links.length == 0) return false; for (let i in links) { let linkSrc = links[i].href; if (!isSupportedVideoLink(linkSrc)) break; links[i].classList.add('has-player'); let player = createPlayer(linkSrc) links[i].parentElement.appendChild(player); videojs(player) let observer = new MutationObserver(mutations => { mutations.forEach(mutation => { if (!mutation.target) { return; } let newLinkSrc = mutation.target.getAttribute("href"); if (!isSupportedVideoLink(newLinkSrc)) { videojs(player).dispose(); links[i].classList.remove('has-player'); return; } player.src = newLinkSrc; videojs(player) }); }); observer.observe(links[i], { attributes: true, attributeFilter: ['href'] }); } return true; } (function () { 'use strict'; GM_addStyle(GM_getResourceText("video.js_css")); attachPlayer(); let observer = new MutationObserver(mutations => { attachPlayer(); }); observer.observe(document.body, { childList: true, subtree: true }) })();