Forvo Direct Download

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

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

  1. // ==UserScript==
  2. // @name Forvo Direct Download
  3. // @namespace https://github.com/Artemis-chan
  4. // @version 0.1
  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. var args = /\(\s*([^)]+?)\s*\)/.exec(plays[0].attributes.onclick.textContent);
  67. if (args[1]) {
  68. args = args[1].split(/\s*,\s*/);
  69. var scrape = scrapeSound(args[1], args[2], args[4], args[5]);
  70. for(const s of scrape)
  71. {
  72. if(isNull(s)) continue;
  73.  
  74. var htmlString = `<a target="_blank" href="` + s + `" download="` + trimChars(args[7], "'") + /\.([^.]+)$/.exec(s)[0] + `">[ DL ]</a>`;
  75.  
  76. var tempDiv = document.createElement('div');
  77. tempDiv.innerHTML = htmlString;
  78.  
  79. var newElement = tempDiv.firstElementChild;
  80.  
  81. var referenceElement = play.parentNode;
  82. var parentElement = referenceElement.parentNode;
  83.  
  84. parentElement.insertBefore(newElement, referenceElement.nextSibling);
  85. }
  86. console.log(scrape)
  87. }
  88. }
  89. })();