Forvo Direct Download

Download audio from forvo without going through sign up process. Right click on [ DL ] and press save.

目前为 2025-03-10 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Forvo Direct Download
  3. // @namespace https://github.com/Artemis-chan
  4. // @version 0.2
  5. // @description Download audio from forvo without going through sign up process. Right click on [ DL ] and press save.
  6. // @author Artemis
  7. // @match *://forvo.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=forvo.com
  9. // @grant none
  10. // @run-at document-end
  11. // @license MIT
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16.  
  17. var plays = document.getElementsByClassName("play")
  18.  
  19. function trimChars (str, c) {
  20. var re = new RegExp("^[" + c + "]+|[" + c + "]+$", "g");
  21. return str.replace(re,"");
  22. }
  23.  
  24. function isNull(x){
  25. const nul = [null, undefined, ''];
  26. return nul.includes(x);
  27. }
  28.  
  29. function base64Decode(base64) {
  30. const binString = atob(base64);
  31. const bytesU8 = Uint8Array.from(binString, (m) => m.codePointAt(0));
  32. return new TextDecoder().decode(bytesU8);
  33. }
  34.  
  35. function scrapeSound(b, c, e, f) {
  36. b = trimChars(b, '\'');
  37. c = trimChars(c, '\'');
  38. e = trimChars(e, '\'');
  39. f = trimChars(f, '\'');
  40.  
  41. const _AUDIO_HTTP_HOST = "audio12.forvo.com";
  42. const defaultProtocol = "http:";
  43.  
  44. if(!isNull(b))
  45. {
  46. b = defaultProtocol + '//' + _AUDIO_HTTP_HOST + '/mp3/' + base64Decode(b);
  47. }
  48. if(!isNull(c))
  49. {
  50. c = defaultProtocol + '//' + _AUDIO_HTTP_HOST + '/ogg/' + base64Decode(c);
  51. }
  52. if(!isNull(e))
  53. {
  54. e = defaultProtocol + '//' + _AUDIO_HTTP_HOST + '/audios/mp3/' + base64Decode(e);
  55. }
  56. if(!isNull(f))
  57. {
  58. f = defaultProtocol + '//' + _AUDIO_HTTP_HOST + '/audios/ogg/' + base64Decode(f);
  59. }
  60.  
  61. return [b, c, e, f]
  62. }
  63.  
  64. for(const play of plays)
  65. {
  66. console.log(play)
  67. var args = /\(\s*([^)]+?)\s*\)/.exec(play.attributes.onclick.textContent);
  68. if (args[1]) {
  69. args = args[1].split(/\s*,\s*/);
  70. var scrape = scrapeSound(args[1], args[2], args[4], args[5]);
  71. for(const s of scrape)
  72. {
  73. if(isNull(s)) continue;
  74.  
  75. var htmlString = `<a target="_blank" href="` + s + `" download="` + trimChars(args[7], "'") + /\.([^.]+)$/.exec(s)[0] + `">[ DL ]</a>`;
  76.  
  77. var tempDiv = document.createElement('div');
  78. tempDiv.innerHTML = htmlString;
  79.  
  80. var newElement = tempDiv.firstElementChild;
  81.  
  82. var referenceElement = play.parentNode;
  83. var parentElement = referenceElement.parentNode;
  84.  
  85. parentElement.insertBefore(newElement, referenceElement.nextSibling);
  86. }
  87. console.log(scrape)
  88. }
  89. }
  90. })();