baidu-netdisk-rename

Renaming tool for web-based version of baidu netdisk. It supports batch renaming. 百度网盘的重命名小工具,支持批量重命名。

  1. // ==UserScript==
  2. // @name baidu-netdisk-rename
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.6
  5. // @description Renaming tool for web-based version of baidu netdisk. It supports batch renaming. 百度网盘的重命名小工具,支持批量重命名。
  6. // @author neotan
  7. // @match https://pan.baidu.com/disk/*
  8. // @grant GM_addStyle
  9. // @grant GM_getResourceText
  10. // @resource purecss https://cdn.jsdelivr.net/npm/purecss@1.0.1/build/pure-min.min.css
  11. // @resource responsiveCss https://cdn.jsdelivr.net/npm/purecss@1.0.1/build/grids-responsive-min.css
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. ;(async function () {
  16. 'use strict'
  17.  
  18. // ------------------- Utilities START ------------------- //
  19. function getMeta() {
  20. var filemanagerUrl
  21. var taskqueryUrl
  22.  
  23. try {
  24. var scriptTag = $('script').filter((i, ctt) => {
  25. return !ctt.src && ctt.text.includes('"bdstoken":"')
  26. })[0]
  27. var bdstoken = scriptTag.text.match(/(?<=bdstoken"\s*:\s*")([A-Za-z0-9]*)(?=")/).pop().trim()
  28. if (bdstoken) {
  29. filemanagerUrl = `https://pan.baidu.com/api/filemanager?opera=rename&async=2&onnest=fail&channel=chunlei&web=1&app_id=250528&bdstoken=${bdstoken}&clienttype=0`
  30. taskqueryUrl = `https://pan.baidu.com/share/taskquery?taskid=1052678625270016&channel=chunlei&web=1&app_id=250528&bdstoken=${bdstoken}&clienttype=0`
  31. }
  32. } catch (e) {
  33. console.error(e)
  34. }
  35.  
  36. return {
  37. filemanagerUrl,
  38. taskqueryUrl,
  39. }
  40. }
  41.  
  42. function getFileNames() {
  43. var nodes = document.querySelectorAll('.file-name .text a')
  44. return [...nodes].map(n => n.textContent)
  45. }
  46.  
  47. function escapeRegExp(str) {
  48. return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
  49. }
  50.  
  51. function createFileName(oldName, searchStr, replaceStr, applyToAll, caseSenstive, useRegexp = true) {
  52. var g = applyToAll ? 'g' : ''
  53. var i = caseSenstive ? '' : 'i'
  54. var rex = new RegExp(escapeRegExp(searchStr), g + i)
  55.  
  56. return oldName.replace(rex, replaceStr)
  57. }
  58.  
  59. function getCWD() {
  60. var addr = window.location.href
  61. var urlParams = new URLSearchParams(addr.substring(addr.indexOf('?') + 1))
  62. var cwd = urlParams.get('path')
  63. if (!cwd) {
  64. throw new Error('Can\'t get current working directory.')
  65. }
  66. return cwd
  67. }
  68.  
  69. function getBatchActions(cwd, batchText, applyToAll = true, caseSenstive = false, separator) {
  70. if (batchText && separator) {
  71. return batchText
  72. .split('\n')
  73. .map(line => {
  74. line = line.trim()
  75. var namingPair = line.split(separator)
  76. if (namingPair && namingPair.length === 2) {
  77. return getAction(cwd, namingPair[0].trim(), namingPair[0].trim(), namingPair[1].trim(), applyToAll, caseSenstive)
  78. }
  79. })
  80. .filter(action => action)
  81. }
  82. }
  83.  
  84. function getAction(cwd, fileName, searchStr, replaceStr, applyToAll = true, caseSenstive = false) {
  85. var path = cwd + '/' + fileName
  86. var newname = createFileName(fileName, searchStr, replaceStr, applyToAll, caseSenstive)
  87.  
  88. return fileName !== newname ? {path, newname} : ''
  89. }
  90.  
  91. function getFormData(actions) {
  92. var formData = new FormData()
  93. formData.append('filelist', JSON.stringify(actions))
  94.  
  95. return formData
  96. }
  97.  
  98. function showMsg(msg) {
  99. $('.msg').html(msg).show('slow').delay(10000).hide(500)
  100. }
  101.  
  102. function postData(url, formData) {
  103. fetch(url, {
  104. method: 'POST',
  105. body: formData,
  106. })
  107. .then(res => res.json())
  108. .catch(err => console.error('Error:', err))
  109. .then(res => console.log('Response:', res))
  110. }
  111.  
  112. function toBatchMode() {
  113. $('.single-mode').map(function () {
  114. $(this).slideUp(() => {
  115. $('.batch-mode').map(function () {
  116. $(this).slideDown()
  117. })
  118. })
  119. })
  120.  
  121. }
  122.  
  123. function toSingleMode() {
  124. $('.batch-mode').map(function () {
  125. $(this).slideUp(() => {
  126. $('.single-mode').map(function () {
  127. $(this).slideDown()
  128. })
  129. })
  130. })
  131. }
  132.  
  133. // ------------------- Utilities END ------------------- //
  134.  
  135. // ------------------- Main Functions declaration START ------------------- //
  136. var msg = ''
  137. var isBatchMode = $('.batch-switcher').prop('checked', true)
  138. var customCss = `
  139. .pure-g {
  140. padding: 5px;
  141. display: flex;
  142. align-items: center;
  143. background: #f1f1f1;
  144. }
  145. .netdisk-rename{
  146. display: flex;
  147. }
  148. .rename-form {
  149. width: 100%;
  150. display: none;
  151. }
  152. .rename-form > label {
  153. white-space: nowrap;
  154. }
  155. .rename-btn-wrapper > label:not(:first-child) {
  156. margin-left: 10px;
  157. }
  158. .rename-form__input-text {
  159. width: 80%;
  160. }
  161. .rename-btn-wrapper > label:not(:last-child) {
  162. margin-right: 10px;
  163. }
  164. .msg{
  165. background: #b1e279;
  166. padding: 8px 10px;
  167. display: none;
  168. }
  169. .toggle-btn{
  170. font-size: 10px;
  171. position: absolute;
  172. top: 0;
  173. left: 0;
  174. z-index: 2147483647;
  175. width: 26px;
  176. transition: all .2s;
  177. }
  178. .rename-btn{
  179. width: 100%;
  180. }
  181. .rename-btn-wrapper{
  182. display: flex;
  183. }
  184. .author-label{
  185. font-size: 1.3rem;
  186. }
  187. .batch-mode{
  188. display: none;
  189. }
  190. .enlarge {
  191. width: 100px;
  192. height: 30px;
  193. font-size: 12px;
  194. }
  195. `
  196. var domHtml = `
  197. <div class="netdisk-rename">
  198. <button class="pure-button pure-button-primary toggle-btn" title="Toggle Netdisk renaming panel">R</button>
  199. <form class="pure-g pure-form rename-form">
  200. <div class="rename-btn-wrapper">
  201. <label class="pure-u-1 pure-button">Case Senstive? <input type="checkbox" name="caseSenstive" checked></label>
  202. <label class="pure-u-1 pure-button">Apply to all? <input type="checkbox" name="applyToAll" checked></label>
  203. <label class="pure-u-1 pure-button">Batch <input type="checkbox" class="batch-switcher" name="isBatchMode"></label>
  204. <button class="pure-button pure-button-primary rename-btn" type="submit">Rename</button>
  205. <a class="pure-link author-label" href="https://greasyfork.org/en/scripts/398489-baidu-netdisk-rename">&#9784;</a>
  206. </div>
  207. <div class="single-mode">
  208. <label class="pure-u-8-24">Replace: <input class="rename-form__input-text" type="text" name="searchStr"/></label>
  209. <label class="pure-u-8-24">with: <input class="rename-form__input-text" type="text" name="replaceStr"/></label>
  210. <label class="pure-u-7-24">Extension: <input class="rename-form__input-text" type="text" name="extention" size=10 value=".mp4" placeholder="all files"/></label>
  211. </div>
  212. <div class="batch-mode">
  213. <label class="pure-u-8-24">Separator: <input class="rename-form__input-text" type="text" name="separator" value="###"/></label>
  214. <label class="pure-u-1">
  215. <textarea class="pure-u-1" name="batchText" rows="4">
  216. oldName1 ### newName1
  217. oldName2 ### newName2
  218. </textarea>
  219. </label>
  220. </div>
  221. <div class="pure-u-1 msg">${msg}</div>
  222. </form>
  223. </div>
  224. `
  225.  
  226. function main() {
  227. GM_addStyle(GM_getResourceText('purecss'))
  228. GM_addStyle(GM_getResourceText('responsiveCss'))
  229. GM_addStyle(customCss)
  230. $('#layoutMain').prepend($(domHtml))
  231.  
  232. // initiate listeners
  233. $('.toggle-btn').hover(function () {
  234. $(this).addClass('enlarge').text('Rename Panel')
  235. }, function () {
  236. $(this).removeClass('enlarge').text('R')
  237. })
  238. $('.toggle-btn').click(() => $('.rename-form').slideToggle('fast'))
  239. $('.rename-form').submit(function (event) {
  240. event.preventDefault()
  241. var urlParams = new URLSearchParams($(this).serialize())
  242. var searchStr = urlParams.get('searchStr')
  243. var replaceStr = urlParams.get('replaceStr')
  244. var extention = urlParams.get('extention')
  245. var applyToAll = urlParams.get('applyToAll')
  246. var caseSenstive = urlParams.get('caseSenstive')
  247.  
  248. var isBatchMode = urlParams.get('isBatchMode')
  249. var batchText = urlParams.get('batchText')
  250. var separator = urlParams.get('separator')
  251.  
  252. var fileNames = getFileNames().filter(name => name.endsWith(extention))
  253. var cwd = getCWD()
  254.  
  255. var actions = []
  256. if (isBatchMode) {
  257. actions = getBatchActions(cwd, batchText, applyToAll = true, caseSenstive = false, separator)
  258. } else {
  259. actions = fileNames.map(fileName => getAction(cwd, fileName, searchStr, replaceStr, applyToAll, caseSenstive)).filter(action => action)
  260. }
  261.  
  262. var formData = getFormData(actions)
  263. var {filemanagerUrl, taskqueryUrl} = getMeta()
  264.  
  265. if (actions.length > 0 && filemanagerUrl && taskqueryUrl) {
  266. postData(filemanagerUrl, formData)
  267. postData(taskqueryUrl, formData)
  268. showMsg(`Tried renaming ${actions.length} files, please <a onclick="location.reload()" style="cursor:pointer;">Refresh</a> for result.`)
  269. } else {
  270. showMsg('Nothing matched!')
  271. }
  272. })
  273.  
  274. $('.batch-switcher').change(function () {
  275. if (this.checked) {
  276. toBatchMode()
  277. } else {
  278. toSingleMode()
  279. }
  280. })
  281. console.log('baidu-netdisk-rename initiated!')
  282. }
  283.  
  284. // ------------------- Main Functions declaration END ------------------- //
  285.  
  286. // ------------------- Main Functions execution START ------------------- //
  287. main()
  288. })()