// ==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: '输入框内没有表情包' // [xxx] }, { 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') // [xxx] })()