B站表情包下载

批量下载B站表情包

目前為 2024-07-27 提交的版本,檢視 最新版本

// ==UserScript==
// @name         B站表情包下载
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  批量下载B站表情包
// @author       jzh
// @match        https://message.bilibili.com/*
// @icon         https://www.bilibili.com/favicon.ico
// @require      https://cdnjs.cloudflare.com/ajax/libs/jszip/2.6.1/jszip.min.js
// @license      MIT
// ==/UserScript==

;(function () {
  'use strict'
  const buttons = [
    {
      selector: '.emoji-list .emoji div',
      innerHTML: '下载选中系列的表情包',
      alertMessage: '请先点击表情选项并选中需要下载的表情包'
      // <div title="[xxx]" style="background-image: url("https://xxx.png");"></div>
    },
    {
      selector: '.bili-im .right .dialog:not(.hide) .send-box .input-box .core-style img',
      innerHTML: '下载输入框内表情包',
      alertMessage: '输入框内没有表情包'
      // <img src="https://xxx.png" alt="[xxx]">
    },
    {
      selector: '.message-list-content .msg-item .emotion-items',
      innerHTML: '下载对话内所有表情包',
      alertMessage: '对话框内没有表情包'
      // <a title="xxx">
      //  <div style="background-image:url(http://xxx.png);"></div>
      // </a>
    }
  ]
  const div = document.createElement('div')
  div.style.display = 'flex'
  div.style.flexDirection = 'column'
  div.style.justifyContent = 'center'
  for (let i = 0; i < 3; i++) {
    const { selector, innerHTML, alertMessage } = buttons[i]
    const button = document.createElement('button')
    button.innerHTML = innerHTML
    button.style.width = '200px'
    button.style.marginBottom = '20px'
    button.style.cursor = 'pointer'
    button.onclick = () => {
      const emojis = Array.from(document.querySelectorAll(selector))
      if (emojis.length === 0) {
        alert(alertMessage)
        return
      }
      let zipName = ''
      // eslint-disable-next-line no-undef
      const zip = new JSZip()
      const promises = emojis.map((item, imgIndex) => {
        if (imgIndex === 0) {
          zipName = getZipName(item, i)
        }
        return fetch(getUrl(item, i))
          .then(response => response.blob())
          .then(async blob => {
            zip.file(getImgName(item, i) + '.png', await blobToBinary(blob))
          })
      })
      Promise.all(promises).then(() => {
        const content = zip.generate({ type: 'blob' })
        const blob = new Blob([content], { type: 'application/zip' })
        const url = URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = zipName + '.zip'
        document.body.appendChild(a)
        a.click()
        document.body.removeChild(a)
        URL.revokeObjectURL(url)
      })
    }
    div.appendChild(button)
  }
  document.querySelector('.container')?.appendChild(div)
  function getUrl(item, type) {
    let backgroundImage
    switch (type) {
      case 0:
        // url("https://i0.hdslb.com/bfs/emote/xxx.png")
        backgroundImage = item.style.backgroundImage
        // return item.style.backgroundImage.match(/url\((")(.*?)\1\)/)?.[2]
        return backgroundImage.replace('url("', '').replace('")', '') || backgroundImage
      case 1:
        return item.src
      case 2:
        // 'url("http://i0.hdslb.com/bfs/emote/xxx.png")'
        backgroundImage = item.children[0].style.backgroundImage
        // return backgroundImage.match(/url\((")(.*?)\1\)/)?.[2].replace('http:', 'https:')
        return (
          backgroundImage.replace('url("', '').replace('")', '').replace('http:', 'https:') ||
          backgroundImage
        )
    }
  }
  function getImgName(item, type) {
    switch (type) {
      case 0:
        return item.title.slice(1, -1) || item.title
      case 1:
        return item.alt.slice(1, -1) || item.alt
      case 2:
        return item.title
    }
  }
  function getZipName(item, type) {
    switch (type) {
      case 0:
        return item.title.slice(1, -1).match(/^(.*?)_/)?.[1] || item.title
      case 1:
        return (item.alt.slice(1, -1) || item.alt) + '等'
      case 2:
        return item.title + '等'
    }
  }
  function blobToBinary(blob) {
    return new Promise((resolve, reject) => {
      let fileReader = new FileReader()
      fileReader.readAsArrayBuffer(blob)
      fileReader.onloadend = e => {
        resolve(new Uint8Array(e.target.result))
      }
      fileReader.onerror = () => {
        reject(new Error('blobToBinary failure'))
      }
    })
  }
  // 评论区
  // eslint-disable-next-line no-undef
  // $0.querySelector('bili-rich-text').shadowRoot.querySelectorAll('#contents img')
  // <img src="//xxx.png@yyy" alt="[xxx]">
})()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址