Greasy Fork 还支持 简体中文。

vrbdl

UserScript version of this extension https://github.com/dvick/vrbdownres

  1. // ==UserScript==
  2. // @name vrbdl
  3. // @namespace Violentmonkey Scripts
  4. // @match *://vrbangers.com/video/*
  5. // @grant none
  6. // @version 1.0
  7. // @author -
  8. // @run-at document-end
  9. // @description UserScript version of this extension https://github.com/dvick/vrbdownres
  10. // ==/UserScript==
  11. (function() {
  12. 'use strict';
  13.  
  14. function doInjectButton() {
  15. if (document.querySelector('.video-download-button__activator')) {
  16. return;
  17. }
  18. const button = document.createElement('button');
  19. button.className = 'video-download-button__activator app-link app-link__button app-link__button--block --single-video';
  20. button.setAttribute('data-v-d6d564ee', '');
  21. button.innerText = 'Download';
  22. const appMenuActivator = document.querySelector('.single-video-info__download-button > .app-menu__activator');
  23. if (appMenuActivator) {
  24. appMenuActivator.appendChild(button);
  25. }
  26. }
  27.  
  28. function injectButton() {
  29. const preview = document.querySelector('.single-video-poster__preview');
  30.  
  31. if (preview && preview.classList.contains('--loading')) {
  32. const observer = new MutationObserver((mutations, observer) => {
  33. if (!preview.classList.contains('--loading')) {
  34. observer.disconnect();
  35. doInjectButton();
  36. }
  37. });
  38. observer.observe(preview, {
  39. attributes: true,
  40. attributeFilter: ['class']
  41. });
  42. } else {
  43. doInjectButton();
  44. }
  45. }
  46.  
  47. function observePage() {
  48. const target = document.querySelector('main.app-content') || document.getElementById('__nuxt');
  49. if (target) {
  50. const observer = new MutationObserver((mutations, observer) => {
  51. for (const mutation of mutations) {
  52. for (const node of mutation.addedNodes) {
  53. if (node.id === '__layout' || node.classList.contains('single-video-info__download-button')) {
  54. observer.disconnect();
  55. injectButton();
  56. return;
  57. }
  58. }
  59. }
  60. });
  61. observer.observe(target, { childList: true });
  62. }
  63. }
  64.  
  65. // Initial button injection on page load
  66. if (window.location.pathname.startsWith('/video/')) {
  67. injectButton();
  68. observePage();
  69. }
  70.  
  71. // Observe history changes and re-inject button if necessary
  72. const historyPushState = history.pushState;
  73. history.pushState = function() {
  74. historyPushState.apply(this, arguments);
  75. if (window.location.pathname.startsWith('/video/')) {
  76. injectButton();
  77. observePage();
  78. }
  79. };
  80. })();