小宇宙播客音频下载

基于CC-BY-4.0协议的小宇宙音频下载工具,允许修改但需署名

  1. // ==UserScript==
  2. // @name 小宇宙播客音频下载
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.5
  5. // @description 基于CC-BY-4.0协议的小宇宙音频下载工具,允许修改但需署名
  6. // @author YourName
  7. // @match *://*.xiaoyuzhoufm.com/*
  8. // @match *://*.xyzcdn.net/*
  9. // @grant GM_xmlhttpRequest
  10. // @require https://cdn.jsdelivr.net/npm/file-saver@2.0.5/dist/FileSaver.min.js
  11. // @connect xyzcdn.net
  12. // @license CC-BY-4.0
  13. // ==/UserScript==
  14.  
  15. /*
  16. * 本脚本遵循 Creative Commons Attribution 4.0 International License (CC-BY-4.0) 协议
  17. * 您可以自由地:
  18. * - 共享:在任何媒介以任何形式复制、发行本作品
  19. * - 修改:修改、转换或以本作品为基础进行创作
  20. *
  21. * 惟须遵守以下条件:
  22. * - 署名:您必须给出适当的署名,提供指向本许可协议的链接,
  23. * 同时标明是否(对原始作品)作了修改。您可以用任何合理的方式
  24. * 来署名,但不得以任何方式暗示许可人为您或您的使用背书。
  25. *
  26. * 完整协议文本:https://creativecommons.org/licenses/by/4.0/legalcode
  27. */
  28.  
  29. (function() {
  30. 'use strict';
  31.  
  32. // 等待页面加载完成
  33. window.addEventListener('load', function() {
  34. // 检查是否已存在下载按钮
  35. if (document.getElementById('xyz-download-btn')) return;
  36.  
  37. // 创建下载按钮
  38. const downloadBtn = document.createElement('button');
  39. downloadBtn.id = 'xyz-download-btn';
  40. downloadBtn.innerHTML = '⬇️ 下载音频';
  41. Object.assign(downloadBtn.style, {
  42. position: 'fixed',
  43. bottom: '20px',
  44. right: '20px',
  45. zIndex: '9999',
  46. padding: '10px 15px',
  47. backgroundColor: '#ff2442',
  48. color: 'white',
  49. border: 'none',
  50. borderRadius: '5px',
  51. cursor: 'pointer',
  52. fontSize: '14px',
  53. fontWeight: 'bold',
  54. boxShadow: '0 2px 5px rgba(0,0,0,0.2)'
  55. });
  56.  
  57. // 添加按钮到页面
  58. document.body.appendChild(downloadBtn);
  59.  
  60. // 点击事件处理
  61. downloadBtn.addEventListener('click', async function() {
  62. // 查找音频元素
  63. const audioElement = document.querySelector('audio');
  64. if (!audioElement) {
  65. alert('未找到音频元素!请先播放节目');
  66. return;
  67. }
  68.  
  69. // 获取音频URL
  70. const audioUrl = audioElement.src;
  71. if (!audioUrl) {
  72. alert('未找到音频链接!');
  73. return;
  74. }
  75.  
  76. // 获取节目标题作为文件名
  77. let podcastTitle = '小宇宙播客';
  78. const titleElement = document.querySelector('header h1');
  79. if (titleElement) {
  80. podcastTitle = titleElement.textContent.trim();
  81. // 清理文件名中的非法字符
  82. podcastTitle = podcastTitle.replace(/[\\/:*?"<>|]/g, '');
  83. }
  84.  
  85. // 从URL中提取文件扩展名
  86. let fileExt = '.m4a';
  87. const extMatch = audioUrl.match(/\.(m4a|mp3|aac|ogg|wav)(?=\?|$)/i);
  88. if (extMatch) {
  89. fileExt = extMatch[0];
  90. }
  91.  
  92. // 更新按钮状态
  93. downloadBtn.disabled = true;
  94. downloadBtn.innerHTML = '⏳ 下载中...';
  95.  
  96. try {
  97. // 使用GM_xmlhttpRequest获取音频数据(避免CORS问题)
  98. GM_xmlhttpRequest({
  99. method: 'GET',
  100. url: audioUrl,
  101. responseType: 'blob',
  102. onload: function(response) {
  103. const blob = response.response;
  104. // 使用FileSaver保存文件
  105. saveAs(blob, `${podcastTitle}${fileExt}`);
  106. downloadBtn.innerHTML = '✅ 下载完成';
  107. setTimeout(() => {
  108. downloadBtn.innerHTML = '⬇️ 下载音频';
  109. downloadBtn.disabled = false;
  110. }, 2000);
  111. },
  112. onerror: function(error) {
  113. console.error('下载失败:', error);
  114. downloadBtn.innerHTML = '❌ 下载失败';
  115. setTimeout(() => {
  116. downloadBtn.innerHTML = '⬇️ 下载音频';
  117. downloadBtn.disabled = false;
  118. }, 2000);
  119. // 尝试备用方法
  120. fallbackDownload(audioUrl, `${podcastTitle}${fileExt}`);
  121. }
  122. });
  123. } catch (e) {
  124. console.error('下载出错:', e);
  125. // 尝试备用方法
  126. fallbackDownload(audioUrl, `${podcastTitle}${fileExt}`);
  127. }
  128. });
  129.  
  130. // 备用下载方法
  131. function fallbackDownload(url, filename) {
  132. const a = document.createElement('a');
  133. a.href = url;
  134. a.download = filename;
  135. a.target = '_blank';
  136. document.body.appendChild(a);
  137. a.click();
  138. setTimeout(() => {
  139. document.body.removeChild(a);
  140. downloadBtn.innerHTML = '✅ 下载完成';
  141. setTimeout(() => {
  142. downloadBtn.innerHTML = '⬇️ 下载音频';
  143. downloadBtn.disabled = false;
  144. }, 2000);
  145. }, 100);
  146. }
  147. });
  148.  
  149. // 监听音频元素变化(动态加载内容)
  150. const observer = new MutationObserver(function(mutations) {
  151. if (!document.getElementById('xyz-download-btn') && document.querySelector('audio')) {
  152. // 如果音频元素后加载,重新触发按钮创建
  153. const event = new Event('load');
  154. window.dispatchEvent(event);
  155. }
  156. });
  157. observer.observe(document.body, { childList: true, subtree: true });
  158. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址