Jisho Audio Downloader

Adds download audio button to Jisho.org pages which downloads word audio clips.

  1. // ==UserScript==
  2. // @name Jisho Audio Downloader
  3. // @namespace http://miere.ru/
  4. // @version 0.1
  5. // @description Adds download audio button to Jisho.org pages which downloads word audio clips.
  6. // @author Vladislav <miere> Vorobiev
  7. // @match http://jisho.org/search/*
  8. // @match http://jisho.org/word/*
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function() {
  13. 'use strict';
  14. function getWordNameFromAudioID(audioID) {
  15. if (!audioID || audioID.length < 7) return "unknown";
  16. var result = "";
  17. for (var i = 6; i < audioID.length && audioID[i] !== ':'; ++i) {
  18. result = result + audioID[i];
  19. }
  20. return result;
  21. }
  22.  
  23. function getFileExtension(file) {
  24. if (!file || file.length === 0) return "";
  25. var extension = [];
  26. var seperatorFound = false;
  27. for (var i = file.length - 1; i > 0; --i) {
  28. if (file[i] === '.') {
  29. extension.add(file[i]);
  30. extension.reverse();
  31. break;
  32. } else {
  33. extension.add(file[i]);
  34. }
  35. }
  36. return extension.join('');
  37. }
  38.  
  39. function insertNodeAfter(insertNode, afterNode) {
  40. afterNode.parentNode.insertBefore(insertNode, afterNode.nextSibling);
  41. }
  42.  
  43. function downloadFileWithFileName(url, fileName) {
  44. var URL = window.URL || window.webkitURL;
  45.  
  46. var xhr = new XMLHttpRequest(),
  47. a = document.createElement('a'), file;
  48.  
  49. xhr.open('GET', url, true);
  50. xhr.responseType = 'blob';
  51. xhr.onerror = function() {
  52. a.href = url;
  53. a.download = fileName;
  54. a.click();
  55. };
  56. xhr.onload = function() {
  57. file = new Blob([xhr.response], { type : 'application/octet-stream' });
  58. a.href = URL.createObjectURL(file);
  59. a.download = fileName;
  60. a.click();
  61. };
  62. xhr.send();
  63. }
  64.  
  65. var audioElements = document.getElementsByTagName('audio');
  66. for (var i = 0; i < audioElements.length; ++i) {
  67. var audioElement = audioElements[i];
  68. var audioID = audioElement.id;
  69. var audioLinkElement = audioElement.nextElementSibling;
  70. if (!audioLinkElement || !audioLinkElement.dataset || audioLinkElement.dataset.id != audioID) {
  71. continue; // @TODO: Site layout has changed, skip this or show alert?
  72. }
  73. var downloadAudioElement = document.createElement('a');
  74. downloadAudioElement.className = 'concept_light-status_link';
  75. downloadAudioElement.dataset.href = audioElement.children[0].src;
  76. downloadAudioElement.dataset.download = getWordNameFromAudioID(audioID) + getFileExtension(downloadAudioElement.dataset.href);
  77. downloadAudioElement.innerText = 'Download audio';
  78. downloadAudioElement.addEventListener('click', function(ev) {
  79. downloadFileWithFileName(ev.target.dataset.href, ev.target.dataset.download);
  80. });
  81. insertNodeAfter(downloadAudioElement, audioLinkElement);
  82. }
  83. })();