Greasy Fork is available in English.

Github Copy Raw File URL and Download File

Add buttons at the end of each file line to copy the raw file URL and download the file

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

  1. // ==UserScript==
  2. // @name Github Copy Raw File URL and Download File
  3. // @name:zh-CN Github 复制原始文件 URL 与下载文件
  4. // @name:zh-TW Github 複製原始檔案 URL 與下載檔案
  5. // @name:vi Github Sao chép URL tệp gốc và tải xuống tệp
  6. // @name:ko Github 원본 파일 URL 복사 및 파일 다운로드
  7. // @name:ja Github 原始ファイル URL をコピーし、ファイルをダウンロードする
  8. // @name:en Github Copy Raw File URL and Download File
  9. // @name:de Github Rohdatei-URL kopieren und Datei herunterladen
  10. // @description Add buttons at the end of each file line to copy the raw file URL and download the file
  11. // @description:zh-CN 在每个文件行的末尾添加按钮,以复制原始文件 URL 和下载文件
  12. // @description:zh-TW 在每個檔案行的末尾添加按鈕,以複製原始檔案 URL 和下載檔案
  13. // @description:vi Thêm nút vào cuối mỗi dòng tệp để sao chép URL tệp gốc và tải xuống tệp
  14. // @description:ko 각 파일 행 끝에 원본 파일 URL 복사 및 파일 다운로드 버튼 추가
  15. // @description:ja 各ファイル行の末尾に、原始ファイルURLをコピーし、ファイルをダウンロードするボタンを追加
  16. // @description:en Add buttons at the end of each file line to copy the raw file URL and download the file
  17. // @description:de Fügen Sie Schaltflächen am Ende jeder Dateizeile hinzu, um die Rohdatei-URL zu kopieren und die Datei herunterzuladen
  18. // @namespace https://github.com/ChinaGodMan/UserScripts
  19. // @version 2.2.0.11
  20. // @author Kamikaze (https://github.com/Kamiikaze) ,人民的勤务员 <toniaiwanowskiskr47@gmail.com>
  21. // @match https://github.com/*
  22. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.com
  23. // @run-at document-ready
  24. // @license MIT
  25. // @supportURL https://github.com/ChinaGodMan/UserScripts/issues
  26. // @homepageURL https://github.com/ChinaGodMan/UserScripts
  27. // ==/UserScript==
  28.  
  29.  
  30. // Need an Interval to detect path changes on github tree one-pager
  31. // Define the number of seconds
  32. const scanInterval = 2
  33.  
  34.  
  35. const waitForFilelist = setInterval(() => {
  36. let fileListContainer = document.querySelector("div.Box > div.js-details-container.Details div") || document.querySelector("table")
  37. let fileList = []
  38. let isTable = false
  39.  
  40. if (fileListContainer.tBodies) {
  41. fileList = fileListContainer.tBodies[0].children
  42. isTable = true
  43. } else {
  44. fileList = fileListContainer.children
  45. }
  46.  
  47. if (fileList < 1) return
  48.  
  49. appendButtons(fileList, isTable)
  50.  
  51. }, scanInterval * 1000)
  52.  
  53. function appendButtons(fileList, isTable = false) {
  54. let fileUrl = ""
  55. let rawFileUrl = ""
  56. for (let i = 0; i < fileList.length; i++) {
  57. let file = fileList[i]
  58.  
  59. if (file.classList.contains("cp-btn-rdy")) continue
  60.  
  61. file.classList.add("cp-btn-rdy")
  62.  
  63. if (!isTable) {
  64. if (
  65. file.classList.contains("sr-only") ||
  66. file.childElementCount !== 4
  67. ) continue
  68.  
  69. fileUrl = file.querySelector('div:nth-child(2) .js-navigation-open')
  70. .href
  71. } else {
  72. if (i === 0) continue
  73.  
  74. if (
  75. file.classList.contains("sr-only")
  76. ) continue
  77.  
  78.  
  79. fileUrl = file.querySelector("a")
  80. .href
  81. file = file.querySelector("td:nth-child(4) > div")
  82. }
  83. //alert(fileUrl)
  84. // Dont add button if its a folder
  85. if (!fileUrl.includes("/blob/")) continue
  86.  
  87. rawFileUrl = fileUrl.replace('/blob/', '/raw/')
  88. file.style = "display: flex; justify-content: flex-end;"
  89. file.append(creatyCopyButton(rawFileUrl))
  90. file.append(creatyDownButton(rawFileUrl))
  91. }
  92. };
  93.  
  94. function creatyCopyButton(copyText) {
  95. const copy2clipboard = `
  96. <clipboard-copy aria-label="Copy" value="test value" data-view-component="true" class="" tabindex="0" role="button" title="Copy raw file url">
  97. <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-copy">
  98. <path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z"></path><path fill-rule="evenodd" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z"></path>
  99. </svg>
  100. </clipboard-copy>`
  101.  
  102. const copyButton = document.createElement('div')
  103. copyButton.setAttribute('role', 'gridcell')
  104. copyButton.style = "margin-left: 10px; display: inline;"
  105. copyButton.innerHTML = copy2clipboard
  106. copyButton.children[0].value = copyText
  107. copyButton.children[0].style = "cursor: pointer;"
  108.  
  109. return copyButton
  110. }
  111. function creatyDownButton(copyText) {
  112. const copy2clipboard = `
  113. <clipboard-copy aria-label="Download" value="test value" data-view-component="true" class="" tabindex="0" role="button" title="Download raw file url">
  114. <svg aria-hidden="true" height="16" viewBox="0 0 16 16" version="1.1" width="16" data-view-component="true" class="octicon octicon-download">
  115. <path fill-rule="evenodd" d="M1.75 14.25A1.75 1.75 0 013.5 12.5h9a1.75 1.75 0 011.75 1.75v1.5a.75.75 0 01-.75.75H2.5a.75.75 0 01-.75-.75v-1.5zM10.75 9.25a.25.25 0 01.25.25v2.5a.25.25 0 01-.25.25H5.25a.25.25 0 01-.25-.25v-2.5a.25.25 0 01.25-.25h5.5zM8 1.75a.25.25 0 01.25.25v7.5a.25.25 0 01-.25.25H6.75a.25.25 0 01-.25-.25v-7.5a.25.25 0 01.25-.25h1.5zM10.25 5.25l1.5 1.5a.25.25 0 01.35 0l3-3a.25.25 0 00-.35-.35L11 5.25 9.25 3.5a.25.25 0 00-.35.35z"></path>
  116. </svg>
  117. </clipboard-copy>
  118. `
  119.  
  120. const copyButton = document.createElement('div')
  121. copyButton.setAttribute('role', 'gridcell')
  122. copyButton.style = "margin-left: 10px; display: inline;"
  123. copyButton.innerHTML = copy2clipboard
  124. copyButton.children[0].value = copyText
  125. copyButton.children[0].style = "cursor: pointer;"
  126. copyButton.addEventListener('click', () => {
  127. // window.location.href = copyText;
  128. downloadFile(copyText, getFilenameFromUrl(copyText))
  129. })
  130. return copyButton
  131. }
  132. function downloadFile(url, filename) {
  133. var xhr = new XMLHttpRequest()
  134. xhr.open('GET', url, true)
  135. xhr.responseType = 'blob'
  136. xhr.onload = function () {
  137. if (xhr.status === 200) {
  138. var blob = xhr.response
  139. var objectUrl = window.URL.createObjectURL(blob)
  140. var a = document.createElement('a')
  141. a.href = objectUrl
  142. a.download = filename // 设置下载文件名
  143. document.body.appendChild(a)
  144. a.click()
  145. window.URL.revokeObjectURL(objectUrl) // 清理 object URL
  146. document.body.removeChild(a) // 清理 DOM
  147. }
  148. }
  149. xhr.send()
  150. }
  151. function getFilenameFromUrl(url) {
  152. if (typeof url !== 'string' || url.trim() === '') {
  153. logMessage('getFilenameFromUrl', 'URL无效,默认文件名download', false)
  154. return 'download' // 返回一个默认的文件名
  155. }
  156. var lastSlashIndex = url.lastIndexOf('/')
  157. if (lastSlashIndex === -1 || lastSlashIndex === url.length - 1) {
  158. logMessage('getFilenameFromUrl', 'URL格式无效缺少文件名,默认文件名download', false)
  159. return 'download' // 返回一个默认的文件名
  160. }
  161. var filenameWithExtension = url.substring(lastSlashIndex + 1)
  162. var decodedFilename = decodeURIComponent(filenameWithExtension)
  163. decodedFilename = decodedFilename.replace(/%20/g, '_') // 替换所有的 %20 为下划线
  164. return decodedFilename
  165. }