GitHub Folder Downloader

To add a download button for a GitHub folder, which allows easy downloading of a specific folder, you can follow these steps

Mint 2024.08.27.. Lásd a legutóbbi verzió

  1. // ==UserScript==
  2. // @name GitHub Folder Downloader
  3. // @name:en GitHub Folder Downloader
  4. // @name:zh-CN GitHub 文件夹下载器
  5. // @name:zh-TW GitHub 文件夾下載器
  6. // @name:ja GitHub フォルダー ダウンローダー
  7. // @name:vi Trình tải xuống thư mục GitHub
  8. // @name:ko GitHub 폴더 다운로더
  9. // @description To add a download button for a GitHub folder, which allows easy downloading of a specific folder, you can follow these steps
  10. // @description:en To add a download button for a GitHub folder, which allows easy downloading of a specific folder, you can follow these steps
  11. // @description:zh-CN 添加一个下载按钮,允许轻松下载特定的 GitHub 文件夹。
  12. // @description:zh-TW 添加一個下載按鈕,允許輕鬆下載特定的 GitHub 文件夾。
  13. // @description:ja 特定の GitHub フォルダーを簡単にダウンロードできるダウンロードボタンを追加します。
  14. // @description:vi Thêm một nút tải xuống cho phép tải xuống thư mục GitHub cụ thể một cách dễ dàng.
  15. // @description:ko 특정 GitHub 폴더를 쉽게 다운로드할 수 있는 다운로드 버튼을 추가합니다.
  16. // @namespace https://github.com/ChinaGodMan/UserScripts
  17. // @version 0.7
  18. // @author EricKwok,人民的勤务员 <toniaiwanowskiskr47@gmail.com>
  19. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  20. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  21. // @match *://github.com/*
  22. // @icon https://i.loli.net/2021/03/30/ULV9XunaHesqGIR.png
  23. // @run-at document-idle
  24. // @grant none
  25. // @license MIT
  26. // ==/UserScript==
  27. // 记录页面宽度是否允许 GitHub 展开完整页面的变量
  28. var isFold = false
  29. //检查被收缩元素
  30. const parentElement = document.querySelector('#__primerPortalRoot__')
  31. const observer = new MutationObserver((mutationsList) => {
  32. for (const mutation of mutationsList) {
  33. if (mutation.addedNodes.length > 0) {
  34. for (const node of mutation.addedNodes) {
  35. const ulElement = parentElement.querySelector('ul[role="menu"]')
  36. if (document.querySelector('.github-folder-download')) return
  37. console.log(node)
  38. if (ulElement) {
  39. let _html = `
  40. <li class="github-folder-download">
  41. <p style="padding:0px 8px 2px 10px; color:grey; margin:0; font-size:10px;">Download folder with..</p>
  42. </li>
  43. <a class="dropdown-item" target="_blank" href="https://download-directory.github.io?url=${window.location.href}">
  44. download-directory
  45. </a>
  46. <a class="dropdown-item" target="_blank" href="https://downgit.github.io/#/home?url=${window.location.href}">
  47. DownGit
  48. </a>
  49. <li class="d-block d-md-none dropdown-divider github-folder-download" role="none"></li>`
  50. ulElement.insertAdjacentHTML("beforeend", _html)
  51. }
  52. return
  53. }
  54. }
  55. }
  56. })
  57. const config = { childList: true, subtree: true }
  58. observer.observe(parentElement, config)
  59. // 注入下载文件夹按钮
  60. function injectDownloadFolderBtn() {
  61. if (document.querySelector('.github-folder-download')) return
  62. if (!isFold) {
  63. // 展开状态(PC端)
  64. let html = document.querySelector('[data-testid="tree-overflow-menu-anchor"]')//.types__StyledButton-sc-ws60qy-0.feqCqy
  65. let _html = `
  66. <details data-view-component="true" class="details-overlay details-reset position-relative mr-2 github-folder-download">
  67. <summary role="button" data-view-component="true">
  68. <span class="btn d-none d-md-flex flex-items-center">
  69. Download folder
  70. <span class="dropdown-caret ml-1"></span>
  71. </span>
  72. <span class="btn d-inline-block d-md-none">
  73. <svg aria-label="More options" role="img" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-kebab-horizontal">
  74. <path d="M8 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zM1.5 9a1.5 1.5 0 100-3 1.5 1.5 0 000 3zm13 0a1.5 1.5 0 100-3 1.5 1.5 0 000 3z"></path>
  75. </svg>
  76. </span>
  77. </summary>
  78. <div class="dropdown-menu dropdown-menu-sw" style="top:32px;width:220px;">
  79. <ul class="list-style-none">
  80. <li class="Box-row Box-row--hover-gray p-3 mt-0">
  81. <a class="d-flex flex-items-center color-text-primary text-bold no-underline" rel="noopener" target="_blank" href="https://download-directory.github.io?url=${window.location.href}">
  82. With download - directory
  83. </a >
  84. </li >
  85. <li class="Box-row Box-row--hover-gray p-3 mt-0">
  86. <a class="d-flex flex-items-center color-text-primary text-bold no-underline" rel="noopener" target="_blank" href="https://downgit.github.io/#/home?url=${window.location.href}">
  87. With DownGit
  88. </a>
  89. </li>
  90. </ul >
  91. </div >
  92. </detials>`
  93. html.insertAdjacentHTML("beforebegin", _html)
  94. }
  95. }
  96. function removeAllInjectedElem() {
  97. document.querySelectorAll(".github-folder-download").forEach(elem => elem.remove())
  98. }
  99. function detectFoldUnfold() {
  100. if (document.body.clientWidth <= 1200 && !isFold) {
  101. console.log("收起" + document.body.clientWidth)
  102. isFold = true
  103. } else if (document.body.clientWidth > 1200 && isFold) {
  104. console.log("展开" + document.body.clientWidth)
  105. isFold = false
  106. }
  107. }
  108. function reinject() {
  109. if (document.querySelector(".octicon.octicon-copy")) {//复制路径的元素
  110. // 仅当处于文件夹内时注入按钮
  111. removeAllInjectedElem()
  112. injectDownloadFolderBtn()
  113. }
  114. }
  115. function main() {
  116. detectFoldUnfold()
  117. reinject()
  118. }
  119. (function () {
  120. 'use strict'
  121. /**
  122. * 在浏览器窗口大小改变时自动重新定位设置菜单
  123. */
  124. window.onresize = function () {
  125. // 监听窗口大小改变
  126. main()
  127. }
  128. let oldPushState = history.pushState
  129. history.pushState = function pushState() {
  130. let ret = oldPushState.apply(this, arguments)
  131. window.dispatchEvent(new Event('pushstate'))
  132. window.dispatchEvent(new Event('locationchange'))
  133. return ret
  134. }
  135. let oldReplaceState = history.replaceState
  136. history.replaceState = function replaceState() {
  137. let ret = oldReplaceState.apply(this, arguments)
  138. window.dispatchEvent(new Event('replacestate'))
  139. window.dispatchEvent(new Event('locationchange'))
  140. return ret
  141. }
  142. window.addEventListener('popstate', () => {
  143. window.dispatchEvent(new Event('locationchange'))
  144. })
  145. document.addEventListener('pjax:success', function () {
  146. // 由于 GitHub 使用 pjax 而不是页面跳转的方式在仓库内导航,因此将 main 函数绑定到 pjax 监听器上
  147. window.dispatchEvent(new Event('locationchange'))
  148. })
  149. window.addEventListener('locationchange', function () {
  150. console.log('locationchange!')
  151. main()
  152. })
  153. main()
  154. })()