用腳本插件將NicoNico標題與上傳者移到影片上方

又用AI產了個腳本
因為上次那個自動連續播放分頁的腳本
最近刷曲改另外開個視窗 用Powertoys的always-on-top的功能
把那個視窗變成類似Picture-in-Picture的方式浮在右下角
但由於nico網頁佈局的關係 這樣基本上只看得到影片的左上角

我就想把標題跟上傳者移上來讓我能一眼看到
同時我也能直接用滑鼠手勢關閉分頁以切歌

感覺這個可能比較沒人用得到
但反正弄出來了就分享
一樣AI做的code使用就自己評估
話不多說 上code

// ==UserScript==
// @name         NicoVideo - Title Above Player (Flow Correct)
// @namespace    https://tampermonkey.net/
// @version      1.3.0
// @description  Move existing title block so that player is below it (normal flow, no overlay, SPA-safe)
// @match        https://www.nicovideo.jp/watch/*
// @match        https://nicovideo.jp/watch/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(() => {
  'use strict';

  const MOVED_FLAG = 'data-nico-title-moved';

  /* ---------- finders ---------- */

  function findVideo() {
    return document.querySelector('video[data-name="video-content"]');
  }

  // 播放器本體 container(只用來定位,不插在裡面)
  function findPlayerContainer(video) {
    let el = video?.parentElement;
    while (el) {
      if (el.tagName === 'DIV' && el.classList.contains('pos_relative')) {
        return el;
      }
      el = el.parentElement;
    }
    return null;
  }

  // 播放器「外層文流容器」(安全插入點)
  function findFlowWrapper(playerContainer) {
    let el = playerContainer?.parentElement;
    while (el) {
      if (el.tagName === 'DIV') {
        // 避開會是 absolute / overlay 的層
        const style = getComputedStyle(el);
        if (style.position === 'static' || style.position === 'relative') {
          return el;
        }
      }
      el = el.parentElement;
    }
    return null;
  }

  function findTitleBlock() {
    const tokens = [
      'd_flex',
      'jc_space-between',
      'ai_flex-start',
      'w_100%',
      'gap_var(--watch-video-information-gap)',
    ];

    for (const div of document.querySelectorAll('div')) {
      const cls = div.classList;
      if (cls && tokens.every(t => cls.contains(t))) {
        return div;
      }
    }
    return null;
  }

  /* ---------- core ---------- */

  function moveOnceReady() {
    const title = findTitleBlock();
    const video = findVideo();
    if (!title || !video) return;

    const playerContainer = findPlayerContainer(video);
    if (!playerContainer) return;

    const flowWrapper = findFlowWrapper(playerContainer);
    if (!flowWrapper) return;

    // 已正確放置就不再動
    if (
      title.getAttribute(MOVED_FLAG) === '1' &&
      title.nextElementSibling === playerContainer
    ) {
      return;
    }

    // 移到播放器「前面」(同層文流)
    flowWrapper.insertBefore(title, playerContainer);
    title.setAttribute(MOVED_FLAG, '1');
  }

  /* ---------- SPA observer ---------- */

  const observer = new MutationObserver(() => {
    moveOnceReady();
  });

  function start() {
    if (!document.body) {
      setTimeout(start, 200);
      return;
    }

    observer.observe(document.body, {
      childList: true,
      subtree: true,
    });

    moveOnceReady();
  }

  start();
})();

留言

這個網誌中的熱門文章

小魔女DoReMi 第二部+劇場版