// ==UserScript== // @name Nijiura Video Popup Player (CyTube + NicoNico, hide inline thumb) // @namespace http://tampermonkey.net/ // @version 1.1 // @description CyTubeとニコニコ動画をポップアップ再生+ニコの自動サムネは隠す // @match https://nijiurachan.net/pc/thread.php* // @run-at document-end // @grant none // ==/UserScript== (function() { 'use strict'; const processed = new WeakSet(); let popup, popupFrame, popupHeader, resizeHandle; // ===== ポップアップ生成 ===== function createPopup() { if (popup) return; popup = document.createElement('div'); popup.style.position = 'fixed'; popup.style.top = '10%'; popup.style.left = '50%'; popup.style.transform = 'translateX(-50%)'; popup.style.width = '900px'; popup.style.height = '520px'; popup.style.background = '#000'; popup.style.border = '1px solid #666'; popup.style.zIndex = '99999'; popup.style.display = 'none'; popup.style.boxShadow = '0 4px 16px rgba(0,0,0,0.6)'; popup.style.overflow = 'hidden'; // ---- ヘッダー(ドラッグ移動) ---- popupHeader = document.createElement('div'); popupHeader.textContent = 'Video Player'; popupHeader.style.height = '30px'; popupHeader.style.lineHeight = '30px'; popupHeader.style.padding = '0 8px'; popupHeader.style.background = '#333'; popupHeader.style.color = '#fff'; popupHeader.style.cursor = 'move'; popupHeader.style.userSelect = 'none'; popup.appendChild(popupHeader); const closeBtn = document.createElement('button'); closeBtn.textContent = '✖'; closeBtn.style.float = 'right'; closeBtn.style.marginTop = '4px'; closeBtn.style.marginRight= '4px'; closeBtn.style.cursor = 'pointer'; closeBtn.addEventListener('click', () => { popup.style.display = 'none'; popupFrame.src = 'about:blank'; }); popupHeader.appendChild(closeBtn); // ---- iframe本体 ---- popupFrame = document.createElement('iframe'); popupFrame.style.width = '100%'; popupFrame.style.height = 'calc(100% - 30px)'; popupFrame.style.border = 'none'; popupFrame.allowFullscreen = true; popup.appendChild(popupFrame); // ---- 右下リサイズハンドル ---- resizeHandle = document.createElement('div'); resizeHandle.style.position = 'absolute'; resizeHandle.style.right = '0'; resizeHandle.style.bottom = '0'; resizeHandle.style.width = '18px'; resizeHandle.style.height = '18px'; resizeHandle.style.cursor = 'nwse-resize'; resizeHandle.style.background = 'rgba(255,255,255,0.2)'; resizeHandle.style.borderTop = '1px solid #888'; resizeHandle.style.borderLeft = '1px solid #888'; popup.appendChild(resizeHandle); document.body.appendChild(popup); // ==== ドラッグ移動 ==== let dragging = false; let offsetX = 0, offsetY = 0; popupHeader.addEventListener('mousedown', (e) => { dragging = true; const rect = popup.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; document.body.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (!dragging) return; popup.style.top = (e.clientY - offsetY) + 'px'; popup.style.left = (e.clientX - offsetX) + 'px'; popup.style.transform = ''; }); document.addEventListener('mouseup', () => { dragging = false; document.body.style.userSelect = ''; }); // ==== 右下ハンドルでリサイズ ==== let resizing = false; let startW, startH, startX, startY, pointerId; resizeHandle.addEventListener('pointerdown', (e) => { resizing = true; pointerId = e.pointerId; const rect = popup.getBoundingClientRect(); startW = rect.width; startH = rect.height; startX = e.clientX; startY = e.clientY; resizeHandle.setPointerCapture(pointerId); e.preventDefault(); }); resizeHandle.addEventListener('pointermove', (e) => { if (!resizing) return; const diffX = e.clientX - startX; const diffY = e.clientY - startY; const newW = Math.max(400, startW + diffX); const newH = Math.max(300, startH + diffY); popup.style.width = newW + 'px'; popup.style.height = newH + 'px'; e.preventDefault(); }); resizeHandle.addEventListener('pointerup', (e) => { if (!resizing) return; resizing = false; try { resizeHandle.releasePointerCapture(pointerId); } catch(_) {} }); resizeHandle.addEventListener('pointercancel', () => { resizing = false; }); } // ===== URL → 実際の埋め込みURL ===== function toEmbedUrl(rawUrl) { if (rawUrl.includes('nicovideo.jp/watch/')) { const m = rawUrl.match(/nicovideo\.jp\/watch\/([^?&#]+)/); if (m && m[1]) { return 'https://embed.nicovideo.jp/watch/' + m[1]; } } return rawUrl; // CyTubeはそのまま } function openPopup(rawUrl) { createPopup(); popupFrame.src = toEmbedUrl(rawUrl); popup.style.display = 'block'; } // ===== ニコニコの「元サムネ埋め込み」を隠す ===== function hideInlineNicoThumb(anchor) { // リンクのすぐ下にある iframe / div から最大3つ先までチェック let el = anchor.nextElementSibling; let steps = 0; while (el && steps < 4) { if (el.tagName === 'IFRAME' && el.src && el.src.includes('nicovideo.jp')) { el.style.display = 'none'; break; } // ニコニコの埋め込みが divラッパ+その中にiframe 形式の場合 const innerIframe = el.querySelector && el.querySelector('iframe[src*="nicovideo.jp"]'); if (innerIframe) { el.style.display = 'none'; break; } el = el.nextElementSibling; steps++; } } // ===== 各リンクにボタン付与 ===== function setupForLink(a) { if (processed.has(a)) return; if (!a.href) return; const href = a.href; const isCyTube = href.includes('cytube.mm428.net/r/'); const isNico = href.includes('nicovideo.jp/watch/'); if (!isCyTube && !isNico) return; processed.add(a); const btn = document.createElement('button'); btn.textContent = isNico ? '▶ ニコ動ポップアップ' : '▶ CyTubeポップアップ'; btn.style.marginLeft = '8px'; btn.style.cursor = 'pointer'; btn.style.fontSize = '0.8em'; btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); openPopup(href); }); a.insertAdjacentElement('afterend', btn); // ニコニコの場合は、元の自動サムネiframeを隠す if (isNico) { hideInlineNicoThumb(a); } } // ===== ページ内スキャン ===== function scan() { const links = document.querySelectorAll('a[href]'); links.forEach(setupForLink); } scan(); const observer = new MutationObserver(scan); observer.observe(document.body, { childList: true, subtree: true }); })();