Bobby's Pixiv Utils

7/2/2024, 8:37:14 PM

目前为 2025-02-02 提交的版本。查看 最新版本

// ==UserScript==
// @name        Bobby's Pixiv Utils
// @namespace   https://github.com/BobbyWibowo
// @match       *://www.pixiv.net/*
// @match       *://pixiv.net/*
// @icon        https://www.google.com/s2/favicons?sz=64&domain=pixiv.net
// @grant       GM_addStyle
// @run-at      document-end
// @version     1.0.8
// @author      Bobby Wibowo
// @license     MIT
// @description 7/2/2024, 8:37:14 PM
// @noframes
// ==/UserScript==

(function () {
  'use strict'

  /** CONFIG **/

  const SELECTORS_IMAGE = '.jtUPOE > li, .gmoaNn > li, .hjtPnz > li, .boBnlf > div, .hkzusx > div, .ranking-item';
  const SELECTORS_ILLUST_CONTROLS = '.gMEAWM';
  const SELECTORS_BOTTOM_RIGHT_CONTROLS = '.iHfghO, .cGfNRT, ._layout-thumbnail';

  const DATE_CONVERSION = true;
  const SELECTORS_DATE = '.dqHJfP';

  /** STYLES **/

  const mainStyle = `
.pu_edit_bookmark {
  color: rgb(245, 245, 245);
  background: rgba(0, 0, 0, 0.32);
  display: block;
  box-sizing: border-box;
  padding: 0px 6px;
  margin-top: 7px;
  margin-right: 2px;
  border-radius: 10px;
  font-weight: bold;
  font-size: 10px;
  line-height: 20px;
  height: 20px;
}

.gMEAWM .pu_edit_bookmark {
  font-size: 12px;
  height: 24px;
  line-height: 24px;
  margin-top: 5px;
  margin-right: 7px;
}

._layout-thumbnail .pu_edit_bookmark {
  position: absolute;
  right: calc(50% - 71px);
  bottom: 4px;
  z-index: 2;
}

.iHfghO, .cGfNRT {
  display: flex;
  justify-content: flex-end;
}`;

  const addPageStyle = `
.bookmark-detail-unit .meta {
  display: block;
  font-size: 16px;
  font-weight: bold;
  color: inherit;
  margin-left: 0;
  margin-top: 10px;
}`;

  /** UTILS **/

  const log = (message, ...args) => {
    console.log(`[Bobby's Pixiv Utils]: ${message}`, ...args)
  }

  const logError = (message, ...args) => {
    console.error(`[Bobby's Pixiv Utils]: ${message}`, ...args)
  }

  const convertDate = elem => {
    if (elem.classList.contains('pu_date_converted')) {
      return;
    }

    const date = new Date(elem.innerText);
    if (date) {
      elem.innerText = date.toLocaleString("en-GB", {
        hour12: true,
        year: 'numeric',
        month: 'long',
        day: 'numeric',
        hour: '2-digit',
        minute: '2-digit'
      });
      elem.classList.add('pu_date_converted');
    }
  }

  /** INTERCEPT SOME PAGES **/

  const path = location.pathname;

  if (path.startsWith('/bookmark_add.php')) {
    GM_addStyle(addPageStyle);

    const date = document.querySelector('.bookmark-detail-unit .meta');
    convertDate(date);

    log(`${path}: Applied customization, and disabled mutation observer.`)
    return;
  }

  /** MAIN **/

  GM_addStyle(mainStyle);

  const observerFactory = function (option) {
    let options;
    if (typeof option === 'function') {
      options = {
        callback: option,
        node: document.getElementsByTagName('body')[0],
        option: { childList: true, subtree: true }
      };
    } else {
      options = $.extend({
        callback: () => {},
        node: document.getElementsByTagName('body')[0],
        option: { childList: true, subtree: true }
      }, option);
    }
    const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;

    const observer = new MutationObserver((mutations, observer) => {
      options.callback.call(this, mutations, observer);
    });

    observer.observe(options.node, options.option);
    return observer;
  };

  const doIllustControls = element => {
    // Skip if already modified
    if (element.getElementsByClassName('pu_edit_bookmark').length) {
      return;
    }

    const match = window.location.href.match(/artworks\/(\d+)/);
    if (!match || !match[1]) {
      return;
    }

    const elemContainer = document.createElement('div');
    const elem = document.createElement('a');
    elem.className = 'pu_edit_bookmark';
    elem.href = `https://www.pixiv.net/bookmark_add.php?type=illust&illust_id=${match[1]}`;
    elem.innerText = 'Edit bookmark';

    elemContainer.appendChild(elem);
    element.appendChild(elemContainer);
  }

  observerFactory((mutations, observer) => {
    for (let i = 0, len = mutations.length; i < len; i++) {
      const mutation = mutations[i];

      // Whether to change nodes
      if (mutation.type !== 'childList') {
        continue;
      }

      // Find all images
      const images = mutation.target.querySelectorAll(SELECTORS_IMAGE);
      for (const image of images) {
        // Skip if already modified
        if (image.getElementsByClassName('pu_edit_bookmark').length) {
            continue;
        }

        const link = image.querySelector('a[href*="artworks/"]');
        const bottomRightControls = image.querySelector(SELECTORS_BOTTOM_RIGHT_CONTROLS);
        console.log(link, bottomRightControls);
        if (!link || !bottomRightControls) {
          continue;
        }

        const match = link.href.match(/artworks\/(\d+)/);
        if (!match || !match[1]) {
          continue;
        }

        const elemContainer = document.createElement('div');
        const elem = document.createElement('a');
        elem.className = 'pu_edit_bookmark';
        elem.href = `https://www.pixiv.net/bookmark_add.php?type=illust&illust_id=${match[1]}`;
        elem.innerText = 'Edit bookmark';

        elemContainer.appendChild(elem);
        bottomRightControls.insertBefore(elemContainer, bottomRightControls.firstChild);
      }

      // Find all dates
      const dates = mutation.target.querySelectorAll(SELECTORS_DATE);
      for (const date of dates) {
        convertDate(date);
      }

      // Find illust controls
      const illustControls = mutation.target.querySelector(SELECTORS_ILLUST_CONTROLS);
      if (illustControls) {
        doIllustControls(illustControls);
      }
    }
  });

})()