b站直播表情下载

下载b站直播间的表情

// ==UserScript==
// @name         b站直播表情下载
// @description  下载b站直播间的表情
// @namespace    https://noxplay.us.to/
// @version      0.2
// @author       lovegaoshi
// @match        https://live.bilibili.com/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// @grant        GM.getValue
// @grant        GM.setValue
// @grant        GM.xmlHttpRequest
// @grant        GM.info
// @require      https://cdn.bootcss.com/jszip/3.1.4/jszip.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js
// @icon         https://www.google.com/s2/favicons?domain=bilibili.com
// @license      GPLv3
// ==/UserScript==

// GreaseMonkey 4.x compatible
var loadSetting;
if (
  typeof GM !== "undefined" &&
  ((GM.info || {}).scriptHandler || "").toLowerCase().indexOf("greasemonkey") >=
    0
) {
  loadSetting = GM.getValue.bind(this, "ehD-setting");
  self.GM_setValue = GM.setValue;
  self.GM_xmlhttpRequest = GM.xmlHttpRequest;
  self.GM_info = GM.info;
} else {
  loadSetting = function (key, init) {
    return new Promise(function (resolve, reject) {
      try {
        resolve(GM_getValue("ehD-setting"));
      } catch (e) {
        reject(e);
      }
    });
  };
}

const extractWith = function extractWith(filename, reExpressions = []) {
  for (let i = 0, n = reExpressions.length; i < n; i++) {
    let extracted = reExpressions[i].exec(filename);
    if (extracted !== null) {
      return extracted[1];
    }
  }
  return null;
};

async function getRealBiliRoomID(roomID, callback) {
  return new Promise((resolve) => {
    GM_xmlhttpRequest({
      method: "GET",
      url: `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${roomID}`,
      onload: (val) => {
        const data = JSON.parse(val.response).data.room_id;
        //const emoticons = data.map(val => val.emoticons);
        resolve(callback(data));
      },
    });
  });
}

async function getBiliRoomEmoticons(roomID) {
  return new Promise((resolve) => {
    GM_xmlhttpRequest({
      method: "GET",
      url: `https://api.live.bilibili.com/xlive/web-ucenter/v2/emoticon/GetEmoticons?platform=pc&room_id=${roomID}`,
      onload: (val) => {
        const data = JSON.parse(val.response).data.data.slice(2);
        //const emoticons = data.map(val => val.emoticons);
        resolve(data);
      },
    });
  });
}

async function downloadBiliEmoticons(emoticons, zipfile = null) {
  /*
	{
        "emoji": "早上好",
        "descript": "",
        "url": "http://i0.hdslb.com/bfs/garb/f1a8c2f4c3ad7b0c311eeb2cc3db2dc937c69e53.png",
        "is_dynamic": 1,
        "in_player_area": 1,
        "width": 162,
        "height": 162,
        "identity": 4,
        "unlock_need_gift": 31164,
        "perm": 0,
        "unlock_need_level": 1,
        "emoticon_value_type": 0,
        "bulge_display": 1,
        "unlock_show_text": "粉丝团",
        "unlock_show_color": "#FF6699",
        "emoticon_unique": "room_282208_898",
        "unlock_show_image": "",
        "emoticon_id": 898
    }
	*/
  if (emoticons.length === 0) {
    alert("没有房间专属表情!");
    return;
  }
  if (zipfile === null) zipfile = new JSZip();
  let promises = [];
  emoticons.map((emoticonColle) => {
    emoticonColle.emoticons.map((emoticon) =>
      promises.push(
        new Promise((resolve, reject) => {
          GM_xmlhttpRequest({
            method: "GET",
            url: emoticon.url,
            responseType: "arraybuffer",
            onload: (val) => {
              const blobdata = new Blob([val.response]);
              zipfile.file(
                `${emoticonColle.pkg_name}-${emoticon.emoji}.png`,
                blobdata,
                { binary: true }
              );
              resolve(true);
            },
          });
        })
      )
    );
  });
  await Promise.all(promises);
  return zipfile;
}

async function downloadEmoticons() {
  const roomID = extractWith(window.location.href, [
    /live\.bilibili\.com\/(\d+)/,
  ]);
  if (roomID !== null) {
    const emoticonList = await getRealBiliRoomID(roomID, getBiliRoomEmoticons);
    const emoticonZip = await downloadBiliEmoticons(emoticonList);
    emoticonZip
      .generateAsync({ type: "blob", base64: true })
      .then((content) => saveAs(content, `emoticons_${roomID}.zip`));
  } else {
    console.warn(
      `current bililive room url ${window.location.href} is not valid.`
    );
  }
}

function test() {
  // chrome 110 must use jszip/3.1.4?
  // https://raw.githubusercontent.com/Stuk/jszip/master/dist/jszip.js does not work.
  let zipfile = new JSZip();
  GM_xmlhttpRequest({
    method: "GET",
    url: `http://i0.hdslb.com/bfs/garb/f1a8c2f4c3ad7b0c311eeb2cc3db2dc937c69e53.png`,
    responseType: "arraybuffer",
    onload: (val) => {
      const blobdata = new Blob([val.response]);
      zipfile.file("test.png", blobdata, { binary: true });
      console.log(zipfile);
      zipfile
        .generateAsync({ type: "blob", base64: true })
        .then((content) => saveAs(content, "test.zip"));
    },
  });
}

function makeButton() {
  let a = document.createElement("button");
  a.textContent = "下载表情包";
  a.onclick = downloadEmoticons;
  document.getElementsByClassName("follow-ctnr")[0].appendChild(a);
}

(function () {
  "use strict";
  // https://live.bilibili.com/p/html/live-web-mng/index.html?roomid=282208&arae_id=192&parent_area_id=5&ruid=529249
  makeButton();
})();