tsadult-dl

tsadult post saver

目前为 2024-11-05 提交的版本。查看 最新版本

// ==UserScript==
// @name         tsadult-dl
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  tsadult post saver
// @author       You
// @match        https://*.tsadult.net/*/res/*.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tsadult.net
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/3.8.0/jszip.min.js
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==


const CSS = `
  #dl-btn {
    position: fixed;
    bottom: 64px;
    right: 32px;
    font-size: 16pt;
    text-align: right;
  }
  #dl-msg {
   font-size: 12pt;
   color: black;
  }
`

function addDownloadButton() {
  var count = 0;
  const post = getPost();
  const imageTask = post.filter(it => it.image != null);

  const container = document.createElement('div');
  container.id = 'dl-btn';

  const message = document.createElement('div');
  message.id = 'dl-msg';
  const printMessage = (msg) => { message.innerText = msg };
  printMessage(`image: (0/${imageTask.length})`);

  const button = document.createElement('button');
  button.innerText = '💾';
  button.onclick = () => {
    if (downloading) {
      return;
    }
    var downloading = true;
    console.log('get post', post);

    var zip = new JSZip();
    var tasks = imageTask.map(it => {
        const name = it.image.name;
        const url = it.image.url;
        console.log('download image', it);
        return fetch(url)
          .then(resp => resp.blob())
          .then(blob => {
            zip.file(name, blob);
            count++;
            printMessage(`image: (${count}/${imageTask.length})`);
            return Promise.resolve();
          })
      });

    const article = post.map(it => it.content)
      .filter(it => it!=null && it.length > 0)
      .join('\n\r---\n\r');
    Promise.all(tasks)
      .then(() => zip.file('article.md', article))
      .then(() => zip.generateAsync({ type: 'blob' }))
      .then(blob => {
        const download = document.createElement('a');
        document.body.appendChild(download);
        download.style.display = 'none';

        const fileUrl = window.URL.createObjectURL(blob);
        download.href = fileUrl;
        download.download = 'tsadult_' + new Date().getTime();
        download.click();
        window.URL.revokeObjectURL(fileUrl);
        download.remove();
        downloading = false;
      })
  }
  container.appendChild(message);
  container.appendChild(button);
  return container;
}

function getPost() {
  const url = location.host;
  if (url.includes('2021')) {
    const post = document.querySelector('.op');

    const tables = document.querySelectorAll('#posts > table');
    const contents = Array.from(tables).map(it => convertTo(it));

    return [convertTo(post), ...contents]
  } else {
    const imagesEle = document.querySelectorAll('.thread > .files .fileinfo > a');
    const images = Array.from(imagesEle)
      .map(e => {
        const url = new URL(e.href, location.href).href.toString();
        const name = e.innerText;

        const image = { url, name };
        const content = `![](${name})`;
        return { image, content }
      });
    const posts = Array.from(document.querySelectorAll('.thread > .post'))
      .map(e => convertTo2(e))
      .flat();

    return [...images, ...posts]
  }
}

/**
 *
 * @param {HTMLElement} fragment
 * @returns
 */
function convertTo(fragment) {

  const message = fragment.querySelector('.message');
  var content = message?.innerText?.replace(/^#/gm, '> ');

  var image = null;
  const img = fragment.querySelector('img');
  if (img) {
    const url = new URL(img.parentElement.href, location.href).href.toString();
    const suffixIndex = url.lastIndexOf('/');
    image = { url, name: url.slice(suffixIndex + 1) }
    content = `![](${image.name})\n\n` + content;
  }

  return { image, content }
}

/**
 *
 * @param {HTMLElement} fragment
 */
function convertTo2(fragment) {
  const imagesEle = fragment.querySelectorAll('.files .fileinfo > a');

  const images = Array.from(imagesEle)
    .map(e => {
      const url = new URL(e.href, location.href).href.toString();
      const name = e.innerText;

      const image = { url, name };
      const content = `![](${name})\n\n`;
      return { image, content }
    });


  const text = fragment.querySelector('.body')?.innerText?.replace(/^#/gm, '> ') ?? '';
  return [...images, { image: null, content: text }]
}


(function () {
  'use strict';
  GM_addStyle(CSS);
  const button = addDownloadButton();
  document.body.appendChild(button);
})();