bilibili 视频弹幕下载

bilibili 视频弹幕下载,支持各类视频弹幕下载,包括需要会员的视频以及需要大会员的番剧

  1. // ==UserScript==
  2. // @name bilibili 视频弹幕下载
  3. // @namespace https://github.com/LesslsMore/bili-utils
  4. // @version 0.1.1
  5. // @author lesslsmore
  6. // @description bilibili 视频弹幕下载,支持各类视频弹幕下载,包括需要会员的视频以及需要大会员的番剧
  7. // @license MIT
  8. // @icon https://i0.hdslb.com/bfs/static/jinkela/long/images/favicon.ico
  9. // @match *://*.bilibili.com/bangumi/*
  10. // @match *://*.bilibili.com/video/*
  11. // @require https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js
  12. // ==/UserScript==
  13.  
  14. (function (saveAs) {
  15. 'use strict';
  16.  
  17. create_button();
  18. function create_button() {
  19. const button = document.createElement("button");
  20. button.textContent = "下载弹幕";
  21. button.style.position = "fixed";
  22. button.style.left = "10px";
  23. button.style.top = "50%";
  24. button.style.transform = "translateY(-50%)";
  25. button.style.zIndex = "9999";
  26. button.style.padding = "10px 20px";
  27. button.style.backgroundColor = "#fb7299";
  28. button.style.color = "#fff";
  29. button.style.border = "none";
  30. button.style.borderRadius = "5px";
  31. button.style.cursor = "pointer";
  32. button.style.boxShadow = "0 2px 5px rgba(0, 0, 0, 0.2)";
  33. button.addEventListener("click", async () => {
  34. await down_danmu();
  35. });
  36. document.body.appendChild(button);
  37. }
  38. async function down_danmu() {
  39. let url = window.location.href;
  40. let epMatch = url.match(/(ep\d+)/) || url.match(/(ss\d+)/);
  41. let bvMatch = url.match(/video\/(BV\w+)/);
  42. if (epMatch) {
  43. const id = epMatch[1];
  44. console.log(id);
  45. const { cid, title, long_title } = await fetchInfo(id);
  46. await downloadFile(cid, `${title} - ${long_title}`);
  47. } else if (bvMatch) {
  48. const bv = bvMatch[1];
  49. console.log(bv);
  50. const { cid, title, long_title } = await fetchVideoData(bv);
  51. await downloadFile(cid, `${title}`);
  52. }
  53. }
  54. async function getText(url) {
  55. try {
  56. const response = await fetch(url);
  57. if (!response.ok) {
  58. throw new Error(`HTTP 错误: ${response.status}`);
  59. }
  60. return await response.text();
  61. } catch (error) {
  62. console.error("请求失败:", error);
  63. throw error;
  64. }
  65. }
  66. async function fetchInfo(ep) {
  67. const data = await getText(`https://www.bilibili.com/bangumi/play/${ep}/`);
  68. const str = data.match(/const playurlSSRData = (\{.*?\}\n)/s)[1];
  69. const json = JSON.parse(str);
  70. console.log(json);
  71. return {
  72. cid: json.result.play_view_business_info.episode_info.cid,
  73. long_title: json.result.play_view_business_info.episode_info.long_title,
  74. title: json.result.play_view_business_info.episode_info.title
  75. };
  76. }
  77. async function fetchVideoData(id) {
  78. const data = await getText(`https://www.bilibili.com/video/${id}/`);
  79. const str = data.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){/)[1];
  80. const json = JSON.parse(str);
  81. console.log(json);
  82. return {
  83. cid: json.videoData.cid,
  84. long_title: json.videoData.title,
  85. title: json.videoData.title
  86. };
  87. }
  88. async function downloadFile(cid, title) {
  89. const url = `https://comment.bilibili.com/${cid}.xml`;
  90. try {
  91. const response = await fetch(url);
  92. if (!response.ok) {
  93. throw new Error(`HTTP 错误: ${response.status}`);
  94. }
  95. const blob = await response.blob();
  96. saveAs(blob, `${title}.xml`);
  97. console.log("文件下载完成");
  98. } catch (error) {
  99. console.error("下载失败:", error.message);
  100. }
  101. }
  102.  
  103. })(saveAs);

QingJ © 2025

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