Greasy Fork is available in English.
Download audio files directly from Forvo website without account.
// ==UserScript==// @name ForvoDDL// @namespace https://yveone.com/ForvoDDL// @version 1.0.4// @description Download audio files directly from Forvo website without account.// @author YveOne (Yvonne P.)// @license MIT; https://opensource.org/licenses/MIT// @include https://*.forvo.com/*// @include https://audio00.forvo.com/*// @grant none// ==/UserScript==/*global_SERVER_HOST_AUDIO_HTTP_HOSTdefaultProtocol*/(function() {'use strict';if (location.host === "audio00.forvo.com") {if (location.hash) {let [file, name] = JSON.parse(decodeURIComponent(location.hash.substr(1)));let a = document.createElement('a');a.setAttribute('href', file);a.setAttribute('download', name);a.style.display = 'none';document.body.appendChild(a);a.click();document.body.removeChild(a);}return;}const rePlayData = /^play\((\d+),'([[A-Za-z0-9+\/=]+)?','([[A-Za-z0-9+\/=]+)?',(true|false),'([[A-Za-z0-9+\/=]+)?','([[A-Za-z0-9+\/=]+)?','([\w]+)?'\);.*?$/i;const selectorPlayButton = "span.play[onclick]";const reSearchTranslationLocation = /https\:\/\/(?:\w+\.)forvo\.com\/search-translation\/(.*?)\/(.*?)\//i;const reSearchLocation = /https\:\/\/(?:\w+\.)forvo\.com\/search\/(.*?)\//i;const reWordLocation = /https\:\/\/(?:\w+\.)forvo\.com\/word\/(.*?)\//i;const reUserLocation = /https\:\/\/(?:\w+\.)forvo\.com\/user\/(.*?)\/.*?\//i;const rePhraseLocation = /https\:\/\/(?:\w+\.)forvo\.com\/phrase\/(.*?)\//i;const reLangPronLocation = /https\:\/\/(?:\w+\.)forvo\.com\/languages-pronunciations\/.*?\//i;const reTagListLocation = /https\:\/\/(?:\w+\.)forvo\.com\/tag\/.*?\//i;function getPlayData(playButton) {let m = playButton.getAttribute("onclick").match(rePlayData);if (!m) {return false;}//m = [_, id, mp3, ogg, b, _mp3, _ogg, u]let id = parseInt(m[1]);let mp3 = defaultProtocol + "//" + _AUDIO_HTTP_HOST + "/mp3/" + atob(m[2]);let ogg = defaultProtocol + "//" + _AUDIO_HTTP_HOST + "/ogg/" + atob(m[3]);return {id, mp3, ogg};}function downloadAudio(href, filename) {let i = document.createElement('iframe');i.setAttribute('src', defaultProtocol + "//" + _AUDIO_HTTP_HOST + "#" + JSON.stringify([href, filename]));i.style.display = 'none';document.body.appendChild(i);setTimeout(function() {document.body.removeChild(i);}, 1000);}function decUrl(str) {return decodeURIComponent(str).replace(/_/g, " ");}function onclick(e) {let row = e.target.parentNode.parentNode;let playButton = row.querySelector(selectorPlayButton);let fileType = e.target.getAttribute("data-type");let audioData = getPlayData(playButton);let filename = `audio.${fileType}`;if (reSearchTranslationLocation.test(location.href)) {let m = location.href.match(reSearchTranslationLocation);let search = decUrl(m[1]);let lang = m[2];let word = row.querySelector("a.word").innerHTML;filename = `${search} - ${word}.${fileType}`;} else if (reSearchLocation.test(location.href)) {let search = row.querySelector("a.word").innerHTML;filename = `${search}.${fileType}`;} else if (reWordLocation.test(location.href)) {let m = location.href.match(reWordLocation);let word = decUrl(m[1]);let user = row.querySelector("span.ofLink").innerHTML;filename = `${word} (by ${user}).${fileType}`;} else if (reUserLocation.test(location.href)) {let m = location.href.match(reUserLocation);let user = decUrl(m[1]);row = row.parentNode;let word = row.querySelector("a.word").innerHTML;filename = `${word} (by ${user}).${fileType}`;} else if (rePhraseLocation.test(location.href)) {let m = location.href.match(rePhraseLocation);let phrase = decUrl(m[1]);let user = row.querySelector("span.ofLink").innerHTML;filename = `${phrase} (by ${user}).${fileType}`;} else if (reLangPronLocation.test(location.href)) {let m = location.href.match(reLangPronLocation);let word = row.querySelector("a.word").innerHTML;filename = `${word}.${fileType}`;} else if (reTagListLocation.test(location.href)) {let m = location.href.match(reTagListLocation);let word = row.querySelector("a.word").innerHTML;filename = `${word}.${fileType}`;}downloadAudio(audioData[fileType], filename);}function readDoc(doc) {Array.from(doc.querySelectorAll(selectorPlayButton)).forEach((playBtn, i) => {playBtn.setAttribute("style", "position: relative;");playBtn.parentNode.setAttribute("style", "padding-left: 0;");let mp3 = document.createElement("a");mp3.appendChild(document.createTextNode("mp3"));mp3.setAttribute("data-type", "mp3");mp3.setAttribute("style", "cursor: pointer;");mp3.addEventListener("click", onclick);let ogg = document.createElement("a");ogg.appendChild(document.createTextNode("ogg"));ogg.setAttribute("data-type", "ogg");ogg.setAttribute("style", "cursor: pointer;");ogg.addEventListener("click", onclick);let span = document.createElement("span");span.appendChild(document.createTextNode("["));span.appendChild(mp3);span.appendChild(document.createTextNode("]"));span.appendChild(document.createTextNode("["));span.appendChild(ogg);span.appendChild(document.createTextNode("]"));playBtn.parentNode.insertBefore(span, playBtn);});}readDoc(document);})();