// ==UserScript==
// @name B站表情包下载
// @namespace http://tampermonkey.net/
// @version 1.0
// @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
// @downloadURL none
// ==/UserScript==
;(function () {
'use strict'
const buttons = [
{
selector: '.emoji-list .emoji div',
innerHTML: '下载选中系列的表情包',
alertMessage: '请先点击表情选项并选中需要下载的表情包'
//
},
{
selector: '.bili-im .right .dialog:not(.hide) .send-box .input-box .core-style img',
innerHTML: '下载输入框内表情包',
alertMessage: '输入框内没有表情包'
//
},
{
selector: '.message-list-content .msg-item .emotion-items',
innerHTML: '下载对话内所有表情包',
alertMessage: '对话框内没有表情包'
//
//
//
}
]
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')
//
})()