MATRIX RESORTED

ランキングの動画を「投稿が新しい順」に並び変える

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         MATRIX RESORTED
// @namespace    https://github.com/segabito/
// @version      0.0.6
// @description  ランキングの動画を「投稿が新しい順」に並び変える
// @author       segabito macmoto
// @match        *://www.nicovideo.jp/ranking*
// @grant        none
// @run-at       document-start
// @noframes
// @license      public domain
// ==/UserScript==

(function() {
  'use strict';
    const sortMatrix = app => {
      const data = JSON.parse(app.dataset.app);
      const lanes = data.lanes;
      const column = 'registeredAt';
      const ad = -1;
      const callback = (a, b) => (a[column] < b[column] ? -1 : 1) * ad;

      lanes.forEach(lane => {
        lane.videoList.filter(v => !v._originalIndex).forEach((v, i) => {
          v._originalIndex = i + 1;
          v.title = `${(i + 1).toString().padStart(3, '0')}. ${v.title}`;
        });
        lane.videoList.sort(callback);
      });
      app.setAttribute('data-app', JSON.stringify(data, null, 2));
    }

    const sortSingle = () => {
      const videos = Array.from(document.querySelectorAll('.MediaObject.RankingMainVideo'));
      videos.forEach(v => { v.date = v.querySelector('.RankingMainVideo-metaItem:last-child').textContent.trim()});
      videos.sort((a, b) => a.date < b.date ? 1 : -1);
      videos.forEach((v, i) => {
        const rank = i + 1;
        const originalRank = v.querySelector('.RankingRowRank').textContent * 1;
        const t = v.querySelector('.RankingMainVideo-title');
        const title = t.textContent;
        v.querySelector('.RankingRowRank').textContent = `${rank}`;
        t.textContent = `${originalRank.toString().padStart(3, '0')}. ${title}`;
      });
      const frag = document.createDocumentFragment();
      frag.append(...videos);
      document.querySelector('.RankingVideoListContainer').prepend(frag);
    };

    const _ruler_ = `
      <style>
        .jump-ruler {
          position: fixed;
          top: 30vh;
          right: 24px;
          border: 1px solid #888;
          border-width: 0px 1px 0px 0;
          height: 40vh;
          min-width: 48px;
          white-space: nowrap;
          user-select: none;
          cursor: pointer;
        }
        .jump-ruler-label {
          position: absolute;
          width: 100%;
          text-align: right;
          font-size: 16px;
          font-weight: bold;
          font-style: italic;
          color: #888;
          cursor: pointer;
          transform: translateY(-50%);
        }
        .jump-ruler-label:hover {
          background: #888;
          color: #fff;
        }

        .jump-ruler-label[data-param="1"] {
        }
        .jump-ruler-label[data-param="25"] {
          top: 25%;
        }
        .jump-ruler-label[data-param="50"] {
          top: 50%;
        }
        .jump-ruler-label[data-param="75"] {
          top: 75%;
        }
        .jump-ruler-label[data-param="100"] {
          top: 100%;
        }
      </style>
      <div class="jump-ruler" data-command="relative-scroll">
        <div class="jump-ruler-label"
            data-command="scrollTo"
            data-param="1">1 -</div>
        <div class="jump-ruler-label"
            data-command="scrollTo"
            data-param="25">25 -</div>
        <div class="jump-ruler-label"
            data-command="scrollTo"
            data-param="50">50 -</div>
        <div class="jump-ruler-label"
            data-command="scrollTo"
            data-param="75">75 -</div>
        <div class="jump-ruler-label"
            data-command="scrollTo"
            data-param="100">100 -</div>
      </div>
    `;

    const scrollTo = rank => {
      const target = Array.from(document.querySelectorAll('.RankingRowRank'));
      if (!target.length || !target[rank - 1]) {
        return;
      }

      target[rank - 1].scrollIntoView({behavior: 'instant', block: 'start', inline: 'center'});
      document.documentElement.scrollTop -= 120;
    };

    const initRuler = () => {
      document.body.insertAdjacentHTML('beforeend', _ruler_);
      const ruler = document.querySelector('.jump-ruler');

      ruler.addEventListener('click', e => {
        const target = e.target.closest('[data-command]');
        if (!target) {
          return;
        }
        const {command, param} = target.dataset;
        if (!command) {
          return;
        }
        switch (command) {
          case 'scrollTo':
            scrollTo(param * 1);
            break;
          case 'relative-scroll':
            const rank = Math.round(e.offsetY / target.getBoundingClientRect().height * 100);
            scrollTo(rank);
            break;
        }
        e.preventDefault();
        e.stopPropagation();
      });
    };

    if (document.body.classList.contains('MatrixRanking-body') && !document.gi) {
      document.gi = document.getElementById;
      document.getElementById = function(id) {
        if (id === 'MatrixRanking-app') {
          console.info('%cMATRIX RESORTED',`
            font-size: 150%;
            letter-spacing: 120%;
            background: black;
            color: lightgreen;
            font-family: "Baskerville","Arial Black";
            padding: 4px 8px;
            text-shadow:
              2px 0 4px rgba(0, 255, 0, 0.5),
              -2px 0 4px rgba(0, 255, 0, 0.5),
              4px 0 4px rgba(0, 255, 0, 0.5),
              -4px 0 4px rgba(0, 255, 0, 0.5)
          `);
          const elm = document.gi(id);
          sortMatrix(elm);
          document.getElementById = document.gi;
          delete document.gi;
          return elm;c
        }
        return document.gi(id);
      };
    }

    window.addEventListener('DOMContentLoaded', () => {
      if (document.querySelector('.RankingVideoListContainer')) {
        sortSingle();
        initRuler();
        window.dispatchEvent(new CustomEvent('MatrixResorted'));
      } else
      if (document.body.classList.contains('MatrixRanking-body')) {
        initRuler();
      }
    });
})();