115.user.js 103 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641
  1. // ==UserScript==
  2. // @name 115转存助手ui优化版
  3. // @name:zh 115转存助手ui优化版
  4. // @description 2021.12.20更新,115转存助手ui优化版 v3.2.1 (143.2021.1220.1)(based on Fake115Upload 1.4.3 @T3rry)
  5. // @author Never4Ever
  6. // @namespace Fake115Upload@Never4Ever
  7. // @version 143.2021.1220.1
  8. // @match https://115.com/*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_log
  11. // @grant GM_setValue
  12. // @grant GM_getValue
  13. // @grant GM_setClipboard
  14. // @grant unsafeWindow
  15. // @grant GM_registerMenuCommand
  16. // @grant GM_addStyle
  17. // @connect proapi.115.com
  18. // @connect webapi.115.com
  19. // @connect 115.com
  20. // @require https://greasyfork.org/scripts/398240-gm-config-zh-cn/code/GM_config_zh-CN.js
  21. // @require https://cdn.bootcss.com/jsSHA/2.3.1/sha1.js
  22. // @require https://unpkg.zhimg.com/[email protected]/underscore-min.js
  23. // @require https://unpkg.zhimg.com/[email protected]
  24. // @require https://unpkg.zhimg.com/[email protected]/dist/forge.min.js
  25. // @require https://unpkg.zhimg.com/[email protected]/dist/umd/emoutils.min.js
  26. // ==/UserScript==
  27. /*********************************************
  28. 请从以下获取最新版,或者遇到问题去此反馈,感谢
  29. https://gist.github.com/Nerver4Ever/953447c9ecd330ffc0861d4cbb839369
  30. **********************************************/
  31. (function () {
  32. 'use strict';
  33. const TIPS = {
  34. CurrentVersion: "143.2021.1220.1",
  35. LastUpdateDate: "2021.12.20",
  36. VersionTips: "115转存助手ui优化版 V3.2.1",
  37. UpdateUrl: "https://gist.github.com/Nerver4Ever/953447c9ecd330ffc0861d4cbb839369",
  38. Sha1FileInputDetails: "",
  39. };
  40. const WORKSETTINGS = {
  41. WorkingItemsNumber: 4, //同时执行任务数
  42. SleepLittleTime: 500, //短暂休眠,毫秒,暂时在转存中使用
  43. SleepMoreTime: 1000, //长时休眠,毫秒,暂时在提取中使用
  44. SleepMuchMoreTime: 8000, //超长休眠,暂时未使用
  45. ANumber: 27, //随机数,暂时未使用
  46. };
  47. GM_addStyle(`
  48. .my115Info{
  49. color:red
  50. }
  51. .btnInGrid{
  52. height:20px;
  53. width:20px;
  54. margin-left:-22px;
  55. margin-top:36px;
  56. border:0px;
  57. border-color:transparent;
  58. background-color:transparent;
  59. }
  60. .btnInGrid i{
  61. margin:3px -3px
  62. }
  63. li:hover .btnInGrid{
  64. background-color:#2777F8 !important
  65. }
  66. /* Style The Dropdown Button */
  67. .my115Dropbtn {
  68. background-color: #2777F8;
  69. color: white;
  70. font-size: 16px;
  71. border: none;
  72. cursor: pointer;
  73. }
  74. /* The container <div> - needed to position the dropdown content */
  75. .my115Dropdown {
  76. position: relative;
  77. display: inline-block;
  78. }
  79. /* Dropdown Content (Hidden by Default) */
  80. .my115Dropdown-content {
  81. display: none;
  82. position: absolute;
  83. background-color: #f9f9f9;
  84. min-width: 230px;
  85. box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
  86. z-index: 1;
  87. margin-top: 32px;
  88. }
  89. /* Links inside the dropdown */
  90. .my115Dropdown-content a {
  91. color: black;
  92. padding: 12px 16px;
  93. text-decoration: none;
  94. display: block;
  95. cursor: pointer;
  96. margin:4px;
  97. }
  98. /* Change color of dropdown links on hover */
  99. .my115Dropdown-content a:hover{
  100. background-color: #2777F8;
  101. color:white;
  102. }
  103. /* Show the dropdown menu on hover */
  104. .my115Dropdown:hover .my115Dropdown-content {
  105. display: block;
  106. }
  107. /* Change the background color of the dropdown button when the dropdown content is shown */
  108. .my115Dropdown:hover .my115Dropbtn {
  109. background-color: #3e8e41;
  110. }
  111. `);
  112. function config() {
  113. var windowCss = '#Cfg4ne .nav-tabs {margin: 20 2} #Cfg4ne .config_var textarea{width: 310px; height: 50px;} #Cfg4ne .inline {padding-bottom:0px;} #Cfg4ne .config_header a:hover {color:#1e90ff;} #Cfg4ne .config_var {margin-left: 6%;margin-right: 6%;} #Cfg4ne input[type="checkbox"] {margin: 3px 3px 3px 0px;} #Cfg4ne input[type="text"] {width: 60px;} #Cfg4ne {background-color: lightgray;} #Cfg4ne .reset_holder {float: left; position: relative; bottom: -1em;} #Cfg4ne .saveclose_buttons {margin: .7em;} #Cfg4ne .section_desc {font-size: 10pt;}';
  114. GM_registerMenuCommand('设置', opencfg);
  115. function opencfg() {
  116. GM_config.open();
  117. };
  118. GM_config.init({
  119. id: 'Cfg4ne',
  120. title: GM_config.create('a', {
  121. href: TIPS.UpdateUrl,
  122. target: '_blank',
  123. className: 'setTitle',
  124. textContent: `${TIPS.VersionTips}设置`,
  125. title: `作者:Never4Ever 版本:${TIPS.CurrentVersion}点击访问主页`
  126. }),
  127. isTabs: true,
  128. skin: 'tab',
  129. css: windowCss,
  130. frameStyle: {
  131. height: '420px',
  132. width: '570px',
  133. zIndex: '2147483648',
  134. },
  135. fields: {
  136. createRootFolderDefaultValue: {
  137. section: ['', '转存助手一些功能设置,发包参数暂未开放,敬请期待!'],
  138. label: '“sha1转存时,强制在保存处新建根目录”这项默认选中',
  139. labelPos: 'right',
  140. type: 'checkbox',
  141. default: true,
  142. },
  143. createChildFolderVisible: {
  144. label: '显示“sha1转存时,不创建任何子目录”选项;不显示则强制创建子目录',
  145. labelPos: 'right',
  146. type: 'checkbox',
  147. default: false,
  148. },
  149. advancedRename: {
  150. label: '在目录的悬浮工具条处显示“去除分隔符”选项',
  151. labelPos: 'right',
  152. type: 'checkbox',
  153. default: false,
  154. },
  155. autoUseSeparator: {
  156. label: '自动给文件名添加分隔符进行上传,以防文件名违规',
  157. labelPos: 'right',
  158. type: 'checkbox',
  159. default: true,
  160. },
  161. autoUseSeparatorToRename: {
  162. label: '上传结束,自动给文件名去除分隔符,还原原文件名',
  163. labelPos: 'right',
  164. type: 'checkbox',
  165. default: true,
  166. },
  167. separator: {
  168. label: '分隔符方案(推荐非常用汉字;如果分隔符失效,请自行修改):',
  169. type: 'text',
  170. default: '變'
  171. },
  172. uploadNumber: {
  173. //section: ['时间参数设置', '注意:参数设置过快,会引起115服务器无响应,为稳定运行参数未启用!'],
  174. //label: '转存同时工作任务数:',
  175. labelPos: 'left',
  176. type: 'hidden',
  177. default: '4',
  178. },
  179. uploadSleepTime: {
  180. //label: '转存间隔时间(毫秒):',
  181. labelPos: 'left',
  182. type: 'hidden',
  183. default: '500',
  184. },
  185. downloadNumber: {
  186. //label: '提取同时工作任务数:',
  187. labelPos: 'left',
  188. type: 'hidden',
  189. default: '4',
  190. },
  191. downloadSleepTime: {
  192. //label: '提取间隔时间(毫秒):',
  193. labelPos: 'left',
  194. type: 'hidden',
  195. default: '1300',
  196. },
  197. createFolderSleepTime: {
  198. //label: '目录创建间隔时间(毫秒):',
  199. labelPos: 'left',
  200. type: 'hidden',
  201. default: '300',
  202. },
  203. checkUpdate: {
  204. //section: ['帮助&更新&反馈', '常见错误以及对本脚本进行更新检查与bug反馈'],
  205. label: '前往github主页',
  206. labelPos: 'right',
  207. type: 'button',
  208. click: function () {
  209. window.open(TIPS.UpdateUrl, "_blank");
  210. }
  211. },
  212. },
  213. events: {
  214. save: function () {
  215. GM_config.close();
  216. location.reload();
  217. }
  218. },
  219. });
  220. };
  221. config();
  222. var currentConfig = {
  223. createRootFolderDefaultValue: 'createRootFolderDefaultValue',
  224. createChildFolderVisible: 'createChildFolderVisible',
  225. advancedRename: 'advancedRename',
  226. autoUseSeparator: 'autoUseSeparator',
  227. autoUseSeparatorToRename: 'autoUseSeparatorToRename',
  228. separator: 'separator',
  229. uploadNumber: 'uploadNumber',
  230. uploadSleepTime: 'uploadSleepTime',
  231. downloadNumber: 'downloadNumber',
  232. downloadSleepTime: 'downloadSleepTime',
  233. createFolderSleepTime: 'createFolderSleepTime',
  234. }
  235. var offlineTaskButton = `
  236. <div class="my115Dropdown" id="my115Dropdown">
  237. <div class="my115Dropbtn">
  238. <a href="javascript:;" class="button btn-line btn-upload" menu="offline_task"><i class="icon-operate ifo-linktask"></i><span>链接与sha1转存任务</span><em style="display:none;" class="num-dot"></em></a>
  239. </div>
  240. <div class="my115Dropdown-content" style="display:none;">
  241. <a id="my115ContinuedDownload"> 继续【提取】或者【转存】</a>
  242. </div>
  243. </div>
  244. `;
  245. console.log($("#my115Dropdown").length);
  246. if (!$("#my115Dropdown").length > 0) {
  247. $(".left-tvf").eq(0).append(offlineTaskButton);
  248. $("#my115ContinuedDownload").click(e => {
  249. postSha1Messgae(createMessage(MessageType.BEGIN4CONTINUETASK, ""));
  250. });
  251. }
  252. window.cookie = document.cookie
  253. //todo:waitForKeyElements
  254. waitForKeyElements("div.file-opr", AddShareSHA1Btn);
  255. waitForKeyElements("div.dialog-bottom", AddDownloadSha1Btn);
  256. waitForKeyElements("div.lstc-search", AddShareButtonForSearchItem);
  257. waitForKeyElements(`#js_cantain_box .list-thumb li[rel="item"]`, AddCeateSha1ButtonInGrid)
  258. waitForKeyElements('div#js_top_header_file_path_box', CreateSha1ButtonForSelectedItems);
  259. //隐藏截图中的uid
  260. waitForKeyElements('div[class^="fp-"]', HandleUidDiv);
  261. function HandleUidDiv(node){
  262. node.hide();
  263. console.log("set uiddiv");
  264. }
  265. //#region 20201230新的提取api相关
  266. var pub_key = '-----BEGIN PUBLIC KEY-----\
  267. MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDR3rWmeYnRClwLBB0Rq0dlm8Mr\
  268. PmWpL5I23SzCFAoNpJX6Dn74dfb6y02YH15eO6XmeBHdc7ekEFJUIi+swganTokR\
  269. IVRRr/z16/3oh7ya22dcAqg191y+d6YDr4IGg/Q5587UKJMj35yQVXaeFXmLlFPo\
  270. kFiz4uPxhrB7BGqZbQIDAQAB\
  271. -----END PUBLIC KEY-----'
  272. var private_key = '-----BEGIN RSA PRIVATE KEY-----\
  273. MIICXAIBAAKBgQCMgUJLwWb0kYdW6feyLvqgNHmwgeYYlocst8UckQ1+waTOKHFC\
  274. TVyRSb1eCKJZWaGa08mB5lEu/asruNo/HjFcKUvRF6n7nYzo5jO0li4IfGKdxso6\
  275. FJIUtAke8rA2PLOubH7nAjd/BV7TzZP2w0IlanZVS76n8gNDe75l8tonQQIDAQAB\
  276. AoGANwTasA2Awl5GT/t4WhbZX2iNClgjgRdYwWMI1aHbVfqADZZ6m0rt55qng63/\
  277. 3NsjVByAuNQ2kB8XKxzMoZCyJNvnd78YuW3Zowqs6HgDUHk6T5CmRad0fvaVYi6t\
  278. viOkxtiPIuh4QrQ7NUhsLRtbH6d9s1KLCRDKhO23pGr9vtECQQDpjKYssF+kq9iy\
  279. A9WvXRjbY9+ca27YfarD9WVzWS2rFg8MsCbvCo9ebXcmju44QhCghQFIVXuebQ7Q\
  280. pydvqF0lAkEAmgLnib1XonYOxjVJM2jqy5zEGe6vzg8aSwKCYec14iiJKmEYcP4z\
  281. DSRms43hnQsp8M2ynjnsYCjyiegg+AZ87QJANuwwmAnSNDOFfjeQpPDLy6wtBeft\
  282. 5VOIORUYiovKRZWmbGFwhn6BQL+VaafrNaezqUweBRi1PYiAF2l3yLZbUQJAf/nN\
  283. 4Hz/pzYmzLlWnGugP5WCtnHKkJWoKZBqO2RfOBCq+hY4sxvn3BHVbXqGcXLnZPvo\
  284. YuaK7tTXxZSoYLEzeQJBAL8Mt3AkF1Gci5HOug6jT4s4Z+qDDrUXo9BlTwSWP90v\
  285. wlHF+mkTJpKd5Wacef0vV+xumqNorvLpIXWKwxNaoHM=\
  286. -----END RSA PRIVATE KEY-----'
  287. const priv = forge.pki.privateKeyFromPem(private_key);
  288. const pub = forge.pki.publicKeyFromPem(pub_key);
  289. const g_key_l = [0x42, 0xda, 0x13, 0xba, 0x78, 0x76, 0x8d, 0x37, 0xe8, 0xee, 0x04, 0x91]
  290. const g_key_s = [0x29, 0x23, 0x21, 0x5e]
  291. const g_kts = [0xf0, 0xe5, 0x69, 0xae, 0xbf, 0xdc, 0xbf, 0x5a, 0x1a, 0x45, 0xe8, 0xbe, 0x7d, 0xa6, 0x73, 0x88, 0xde, 0x8f, 0xe7, 0xc4, 0x45, 0xda, 0x86, 0x94, 0x9b, 0x69, 0x92, 0x0b, 0x6a, 0xb8, 0xf1, 0x7a, 0x38, 0x06, 0x3c, 0x95, 0x26, 0x6d, 0x2c, 0x56, 0x00, 0x70, 0x56, 0x9c, 0x36, 0x38, 0x62, 0x76, 0x2f, 0x9b, 0x5f, 0x0f, 0xf2, 0xfe, 0xfd, 0x2d, 0x70, 0x9c, 0x86, 0x44, 0x8f, 0x3d, 0x14, 0x27, 0x71, 0x93, 0x8a, 0xe4, 0x0e, 0xc1, 0x48, 0xae, 0xdc, 0x34, 0x7f, 0xcf, 0xfe, 0xb2, 0x7f, 0xf6, 0x55, 0x9a, 0x46, 0xc8, 0xeb, 0x37, 0x77, 0xa4, 0xe0, 0x6b, 0x72, 0x93, 0x7e, 0x51, 0xcb, 0xf1, 0x37, 0xef, 0xad, 0x2a, 0xde, 0xee, 0xf9, 0xc9, 0x39, 0x6b, 0x32, 0xa1, 0xba, 0x35, 0xb1, 0xb8, 0xbe, 0xda, 0x78, 0x73, 0xf8, 0x20, 0xd5, 0x27, 0x04, 0x5a, 0x6f, 0xfd, 0x5e, 0x72, 0x39, 0xcf, 0x3b, 0x9c, 0x2b, 0x57, 0x5c, 0xf9, 0x7c, 0x4b, 0x7b, 0xd2, 0x12, 0x66, 0xcc, 0x77, 0x09, 0xa6]
  292. var m115_l_rnd_key = genRandom(16)
  293. var m115_s_rnd_key = []
  294. var key_s = []
  295. var key_l = []
  296. function intToByte(i) {
  297. var b = i & 0xFF;
  298. var c = 0;
  299. if (b >= 256) {
  300. c = b % 256;
  301. c = -1 * (256 - c);
  302. } else {
  303. c = b;
  304. }
  305. return c
  306. }
  307. function stringToArray(s) {
  308. var map = Array.prototype.map
  309. var array = map.call(s, function (x) {
  310. return x.charCodeAt(0);
  311. })
  312. return array
  313. }
  314. function arrayTostring(array) {
  315. var result = "";
  316. for (var i = 0; i < array.length; ++i) {
  317. result += (String.fromCharCode(array[i]));
  318. }
  319. return result;
  320. }
  321. function m115_init() {
  322. key_s = []
  323. key_l = []
  324. }
  325. function m115_setkey(randkey, sk_len) {
  326. var length = sk_len * (sk_len - 1)
  327. var index = 0
  328. var xorkey = ''
  329. if (randkey) {
  330. for (var i = 0; i < sk_len; i++) {
  331. var x = intToByte((randkey[i]) + (g_kts[index]))
  332. xorkey += String.fromCharCode(g_kts[length] ^ x)
  333. length -= sk_len
  334. index += sk_len
  335. }
  336. if (sk_len == 4) {
  337. key_s = stringToArray(xorkey)
  338. } else if (sk_len == 12) {
  339. key_l = stringToArray(xorkey)
  340. }
  341. }
  342. }
  343. function xor115_enc(src, key) {
  344. var lkey = key.length
  345. var secret = []
  346. var num = 0
  347. var pad = (src.length) % 4
  348. if (pad > 0) {
  349. for (var i = 0; i < pad; i++) {
  350. secret.push((src[i]) ^ key[i])
  351. }
  352. src = src.slice(pad)
  353. }
  354. for (var j = 0; j < src.length; j++) {
  355. if (num >= lkey) {
  356. num = num % lkey
  357. }
  358. secret.push((src[j] ^ key[num]))
  359. num += 1
  360. }
  361. return secret
  362. }
  363. function genRandom(len) {
  364. var keys = []
  365. var chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz23456789';
  366. var maxPos = chars.length;
  367. for (var i = 0; i < len; i++) {
  368. keys.push(chars.charAt(Math.floor(Math.random() * maxPos)).charCodeAt(0));
  369. }
  370. return keys;
  371. }
  372. function m115_encode(plaintext) {
  373. //console.log('m115_encode:')
  374. m115_init()
  375. key_l = g_key_l
  376. m115_setkey(m115_l_rnd_key, 4)
  377. var tmp = xor115_enc(stringToArray(plaintext), key_s).reverse()
  378. var xortext = xor115_enc(tmp, key_l)
  379. var text = arrayTostring(m115_l_rnd_key) + arrayTostring(xortext)
  380. var ciphertext = pub.encrypt(text)
  381. ciphertext = encodeURIComponent(forge.util.encode64(ciphertext))
  382. return ciphertext
  383. }
  384. function m115_decode(ciphertext) {
  385. //console.log('m115_decode:')
  386. var bciphertext = forge.util.decode64(ciphertext)
  387. var block = bciphertext.length / (128)
  388. var plaintext = ''
  389. var index = 0
  390. for (var i = 1; i <= block; ++i) {
  391. plaintext += priv.decrypt(bciphertext.slice(index, i * 128))
  392. index += 128
  393. }
  394. m115_s_rnd_key = stringToArray(plaintext.slice(0, 16))
  395. plaintext = plaintext.slice(16);
  396. m115_setkey(m115_l_rnd_key, 4)
  397. m115_setkey(m115_s_rnd_key, 12)
  398. var tmp = xor115_enc(stringToArray(plaintext), key_l).reverse()
  399. plaintext = xor115_enc(tmp, key_s)
  400. return arrayTostring(plaintext)
  401. }
  402. function PostData(dict) {
  403. var k, tmp, v;
  404. tmp = [];
  405. for (k in dict) {
  406. v = dict[k];
  407. tmp.push(k + "=" + v);
  408. }
  409. return tmp.join('&');
  410. };
  411. function UrlData(dict) {
  412. var k, tmp, v;
  413. tmp = [];
  414. for (k in dict) {
  415. v = dict[k];
  416. tmp.push((encodeURIComponent(k)) + "=" + (encodeURIComponent(v)));
  417. }
  418. return tmp.join('&');
  419. };
  420. function GetSig(userid, fileid, target, userkey) {
  421. var sha1, tmp;
  422. sha1 = new jsSHA('SHA-1', 'TEXT');
  423. sha1.update("" + userid + fileid + fileid + target + "0");
  424. tmp = sha1.getHash('HEX');
  425. sha1 = new jsSHA('SHA-1', 'TEXT');
  426. sha1.update("" + userkey + tmp + "000000");
  427. return sha1.getHash('HEX', {
  428. outputUpper: true
  429. });
  430. }
  431. function download(filename, content, contentType) {
  432. if (!contentType) contentType = 'application/octet-stream';
  433. var a = document.createElement('a');
  434. var blob = new Blob([content], {
  435. 'type': contentType
  436. });
  437. a.href = window.URL.createObjectURL(blob);
  438. a.download = filename;
  439. a.click();
  440. }
  441. function RenewCookie() {
  442. var arryCookie = window.cookie.split(';');
  443. arryCookie.forEach(function (kv) {
  444. document.cookie = kv + ";expires=Thu, 01 Jan 2100 00:00:00 UTC;;domain=.115.com"
  445. })
  446. }
  447. function DeleteCookie(resp) {
  448. try {
  449. var reg = /set-cookie: .+;/g;
  450. var setcookie = reg.exec(resp)[0].split(';');
  451. var filecookie = setcookie[0].slice(11) + "; expires=Thu, 01 Jan 1970 00:00:00 UTC;" + setcookie[3] + ";domain=.115.com";
  452. document.cookie = filecookie;
  453. RenewCookie()
  454. return filecookie;
  455. } catch (err) {
  456. return null;
  457. }
  458. }
  459. //#endregion
  460. function hereDoc(f) {
  461. return f.toString().replace(/^[^\/]+\/\*!?\s?/, '').replace(/\*\/[^\/]+$/, '');
  462. }
  463. const TaskType = {
  464. DOWNLOAD: 'Download', //提取
  465. UPLOAD: 'Upload', //转存
  466. };
  467. const MessageType = {
  468. BEGIN: 0,
  469. PROCESSING: 1,
  470. END: 2,
  471. ERROR: 3,
  472. CLOSE: 4,
  473. CANCEL: 5,
  474. BEGIN4UPLOAD: 6,
  475. END4UPLOAD: 7,
  476. NOTIFYINFO: 8,
  477. BEGIN4CONTINUETASK: 9,
  478. SHOWCANCEl: 10,
  479. HIDECANCEL: 11,
  480. };
  481. function createMessage(messageType, msg, id) {
  482. return {
  483. messageType: messageType,
  484. msg: msg,
  485. targetID: id
  486. }
  487. }
  488. String.prototype.format = function () {
  489. if (arguments.length == 0) {
  490. return this;
  491. }
  492. for (var s = this, i = 0; i < arguments.length; i++) {
  493. s = s.replace(new RegExp("\\{" + i + "\\}", "g"), arguments[i]);
  494. }
  495. return s;
  496. };
  497. var getTamplateLines = function () {
  498. /*
  499. <div >
  500. <div class="itemContent" style="color: red;text-align: left;margin: 10px 0;">
  501. </div>
  502. <hr />
  503. <div style="height:140px;overflow-x: hidden;overflow-y: auto;">
  504. <ul class="errorList" style="font-size: small;text-align: left;font-style: italic; "></ul>
  505. </div>
  506. </div>
  507. */
  508. };
  509. //post from iframe
  510. function postSha1Messgae(message) {
  511. var postData = {
  512. eventID: "115sha1",
  513. data: message
  514. };
  515. var text = JSON.stringify(postData);
  516. window.parent.postMessage(text, "https://115.com/");
  517. }
  518. function setTaskCancel() {
  519. GM_setValue("setTaskCancel", true)
  520. }
  521. function resetTaskCancelFlag() {
  522. GM_setValue("setTaskCancel", false)
  523. }
  524. function getTaskCancelFlag() {
  525. return GM_getValue("setTaskCancel");
  526. }
  527. const footerString=`<p><span style="color:#2777F8">[${TIPS.CurrentVersion}]</span>: 操作时,<span class="my115Info">确保本页面置顶</span>,防止脚本休眠!!
  528. <br><span class="my115Info">无</span>115会员,<span class="my115Info">提取速度</span>受限,<span class="my115Info">转存文件大小</span>不超过5GB!!</p>`;
  529. //解决提取时的alert不能全屏的问题
  530. if (window.top === window.self) {
  531. $(function () {
  532. var $itemContent = null;
  533. var $errorList = null;
  534. var getTamplate = hereDoc(getTamplateLines);
  535. $(window).on("message", function (e) {
  536. var dataInfo = JSON.parse(e.originalEvent.data);
  537. if (dataInfo.eventID != "115sha1" || e.originalEvent.origin != "https://115.com") return;
  538. var message = dataInfo.data;
  539. //ui:
  540. if (message.messageType == MessageType.BEGIN) {
  541. Swal.fire({
  542. title: '正在操作中...',
  543. html: getTamplate,
  544. allowOutsideClick: false,
  545. allowEscapeKey: false,
  546. confirmButtonText: `完成`,
  547. showCancelButton: true,
  548. cancelButtonText: `取消操作`,
  549. footer: footerString,
  550. willOpen: function () {
  551. Swal.getCancelButton().style.display = "none";
  552. Swal.showLoading(Swal.getConfirmButton());
  553. var $swalContent1 = $(Swal.getHtmlContainer());
  554. $errorList = $swalContent1.find(".errorList");
  555. $itemContent = $swalContent1.find(".itemContent");
  556. }
  557. }).then((result) => {
  558. if (result.dismiss === Swal.DismissReason.cancel) {
  559. setTaskCancel();
  560. console.log("Download Cancel Task");
  561. Swal.fire({
  562. title: '已取消,等待进行中的任务结束...',
  563. html: getTamplate,
  564. allowOutsideClick: false,
  565. allowEscapeKey: false,
  566. confirmButtonText: `完成`,
  567. footer: footerString,
  568. willOpen: function () {
  569. Swal.showLoading(Swal.getConfirmButton());
  570. var $swalContent1 = $(Swal.getHtmlContainer());
  571. let html = $errorList.eq[0];
  572. $errorList = $swalContent1.find(".errorList");
  573. $errorList.append(html);
  574. $itemContent = $swalContent1.find(".itemContent");
  575. }
  576. })
  577. }
  578. });
  579. } else if (message.messageType == MessageType.PROCESSING) {
  580. $itemContent.html(message.msg);
  581. } else if (message.messageType == MessageType.ERROR) {
  582. $errorList.append('<li><div display: flex;"><p>' + message.msg + '</p><p style="font-style: italic;"><\p><\div><\li><li><hr/></li>');
  583. } else if (message.messageType == MessageType.END) {
  584. $itemContent.html(message.msg);
  585. Swal.getTitle().textContent = "操作完成!";
  586. Swal.getCancelButton().style.display = "none";
  587. Swal.getFooter().style.display = "none";
  588. Swal.hideLoading();
  589. } else if (message.messageType == MessageType.CLOSE) {
  590. Swal.close();
  591. } else if (message.messageType == MessageType.BEGIN4UPLOAD) {
  592. Swal.fire({
  593. title: '正在操作中...',
  594. html: getTamplate,
  595. allowOutsideClick: false,
  596. allowEscapeKey: false,
  597. confirmButtonText: `完成`,
  598. denyButtonText: `打开目录`,
  599. showCancelButton: true,
  600. cancelButtonText: "取消操作",
  601. footer: footerString,
  602. willOpen: function () {
  603. Swal.getCancelButton().style.display = "none";
  604. Swal.getDenyButton().style.display = "none";
  605. Swal.showLoading(Swal.getConfirmButton());
  606. var $swalContent1 = $(Swal.getHtmlContainer());
  607. $errorList = $swalContent1.find(".errorList");
  608. $itemContent = $swalContent1.find(".itemContent");
  609. }
  610. }).then(result => {
  611. if (result.dismiss === Swal.DismissReason.cancel) {
  612. setTaskCancel();
  613. console.log("Upload Cancel Task");
  614. console.log(window.parent.document.myData)
  615. Swal.fire({
  616. title: '已取消,等待进行中的任务完成...',
  617. html: getTamplate,
  618. allowOutsideClick: false,
  619. allowEscapeKey: false,
  620. confirmButtonText: `完成`,
  621. denyButtonText: `打开目录`,
  622. showCancelButton: false,
  623. cancelButtonText: "取消操作",
  624. willOpen: function () {
  625. Swal.getDenyButton().style.display = "none";
  626. Swal.showLoading(Swal.getConfirmButton());
  627. var $swalContent1 = $(Swal.getHtmlContainer());
  628. $errorList = $swalContent1.find(".errorList");
  629. $itemContent = $swalContent1.find(".itemContent");
  630. }
  631. });
  632. }
  633. });
  634. } else if (message.messageType == MessageType.END4UPLOAD) {
  635. $itemContent.html(message.msg);
  636. Swal.getTitle().textContent = "操作完成!";
  637. Swal.getCancelButton().style.display = "none";
  638. Swal.getDenyButton().style.display = "block";
  639. Swal.getDenyButton().addEventListener('click', e => {
  640. console.log("DenyButton click");
  641. console.log(message);
  642. window.location.href = "https://115.com/?cid=" + message.targetID + "&offset=0&tab=&mode=wangpan";
  643. });
  644. Swal.getFooter().style.display = "none";
  645. Swal.hideLoading();
  646. } else if (message.messageType == MessageType.BEGIN4CONTINUETASK) {
  647. let taskFile = '';
  648. Swal.fire({
  649. title: '导入任务文件,继续任务',
  650. html: `<div style="text-align: left;">
  651. 选择任务文件(.7task):<input id="continuedTaskFile" type="file" accept=".7task" ></input>
  652. <div style="font-size:14px;color:red;margin:10px;text-align: left;">*在没有移动相关的文件以及文件夹,包括目标的所有目录层级,导入任务可继续</div>
  653. </div>`,
  654. focusConfirm: false,
  655. confirmButtonText: `开始继续任务`,
  656. }).then(t => {
  657. if (t.isConfirmed && taskFile) {
  658. ContinuedTask(taskFile);
  659. }
  660. })
  661. document.getElementById('continuedTaskFile').addEventListener('change', e => {
  662. taskFile = e.target.files[0];
  663. })
  664. } else if (message.messageType == MessageType.SHOWCANCEl) {
  665. if (Swal.getCancelButton()) {
  666. //Swal.getCancelButton().style.display = "block";
  667. }
  668. } else if (message.messageType == MessageType.HIDECANCEL) {
  669. if (Swal.getCancelButton()) {
  670. Swal.getCancelButton().style.display = "none";
  671. }
  672. }
  673. })
  674. });
  675. }
  676. function delay(ms) {
  677. if (ms == 0) {
  678. ms = 1000 * (Math.floor(Math.random() * (11 - 4)) + 4);
  679. }
  680. return new Promise(resolve => setTimeout(resolve, ms))
  681. }
  682. //#region 115 api
  683. //get UploadInfo
  684. //return {state:false,user_id:0,userkey:'0',error:''}
  685. async function getUploadInfo() {
  686. const r = await $.ajax({
  687. url: 'https://proapi.115.com/app/uploadinfo',
  688. dataType: 'json',
  689. xhrFields: {
  690. withCredentials: true
  691. }
  692. });
  693. return r;
  694. }
  695. //add a folder
  696. //return {state: false, error: "该目录名称已存在。", errno: 20004, errtype: "war"}
  697. //return {state: true, error: "", errno: "", aid: 1, cid: "2020455078010511975", …}
  698. async function addFolder(pid, folderName) {
  699. const postData = PostData({
  700. pid: pid,
  701. cname: encodeURIComponent(folderName)
  702. });
  703. const r = await $.ajax({
  704. type: 'POST',
  705. url: 'https://webapi.115.com/files/add',
  706. headers: {
  707. 'Content-Type': 'application/x-www-form-urlencoded',
  708. //'Origin': 'https://115.com'
  709. },
  710. xhrFields: {
  711. withCredentials: true
  712. },
  713. dataType: 'json',
  714. data: postData
  715. });
  716. return r;
  717. }
  718. //return {data: Array(30), count: 53, data_source: "DB", sys_count: 0, offset: 0, page_size:115, …}
  719. //return Array type:
  720. // [folder]:{cid: "", aid: "1", pid: "", n: "", m: 0, …}
  721. // [file]: {fid: "", uid: 1447812, aid: 1, cid: "", n: "",pc:"",sha:"",s:0,t:"" …}
  722. async function getDirectChildItemsByOffset(cid, offset) {
  723. var tUrl = 'https://webapi.115.com/files?aid=1&cid=' + cid + '&o=file_name&asc=1&offset=' + offset + '&show_dir=1&limit=1150&code=&scid=&snap=0&natsort=1&record_open_time=1&source=&format=json&fc_mix=&type=&star=&is_share=&suffix=&custom_order=';
  724. // var tUrl = "https://aps.115.com/natsort/files.php?aid=1&cid=" + cid + "&o=file_name&asc=1&offset=" + offset + "&show_dir=1&limit=1150&code=&scid=&snap=0&natsort=1&record_open_time=1&source=&format=json&fc_mix=0&type=&star=&is_share=&suffix=&custom_order=";
  725. const result = await $.ajax({
  726. type: 'GET',
  727. url: tUrl,
  728. dataType: "json",
  729. xhrFields: {
  730. withCredentials: true
  731. }
  732. });
  733. return result;
  734. }
  735. //直接子项目少于1200
  736. async function getDirectChildItemsByOffsetlt1200(cid, offset) {
  737. //var tUrl = 'https://webapi.115.com/files?aid=1&cid='+cid+'&o=file_name&asc=1&offset='+offset+'&show_dir=1&limit=1150&code=&scid=&snap=0&natsort=1&record_open_time=1&source=&format=json&fc_mix=&type=&star=&is_share=&suffix=&custom_order=';
  738. var tUrl = "https://aps.115.com/natsort/files.php?aid=1&cid=" + cid + "&o=file_name&asc=1&offset=" + offset + "&show_dir=1&limit=1150&code=&scid=&snap=0&natsort=1&record_open_time=1&source=&format=json&fc_mix=0&type=&star=&is_share=&suffix=&custom_order=";
  739. const result = await $.ajax({
  740. type: 'GET',
  741. url: tUrl,
  742. dataType: "json",
  743. xhrFields: {
  744. withCredentials: true
  745. }
  746. });
  747. return result;
  748. }
  749. //return AllDirect items :{id:"",parentID:cid,isFolder:false,name:"",size:0,pc:"",sha:"",paths[] };
  750. async function getAllDirectItems(cid, folderProcessCallback) {
  751. var items = new Array();
  752. var index = 0;
  753. var flag = true;
  754. var pageIndex = 1;
  755. var first = true;
  756. var isLT1200 = false;
  757. while (flag) {
  758. if (getTaskCancelFlag()) break;
  759. folderProcessCallback(pageIndex);
  760. var result = null;
  761. //1200数量,不同的api;这么写减少发包
  762. if (first) {
  763. result = await getDirectChildItemsByOffset(cid, index);
  764. console.log("first >1200 :{0},{1}".format(result.state, result.count));
  765. if (!result.state) {
  766. result = await getDirectChildItemsByOffsetlt1200(cid, index);
  767. console.log("first <1200 :{0},{1}".format(result.state, result.count));
  768. isLT1200 = true;
  769. }
  770. first = false;
  771. } else {
  772. if (isLT1200) result = await getDirectChildItemsByOffsetlt1200(cid, index);
  773. else result = await getDirectChildItemsByOffset(cid, index);
  774. }
  775. var totalCount = parseInt(result.count);
  776. if (totalCount >= 1) {
  777. result.data.forEach(function (item) {
  778. var pItem = {
  779. id: "",
  780. parentID: cid,
  781. isFolder: false,
  782. name: "",
  783. size: "",
  784. pickCode: "",
  785. sha1: "",
  786. paths: new Array(),
  787. preid: "",
  788. needToRemoved: false
  789. };
  790. if (item.fid) //文件 fid,cid
  791. {
  792. pItem.isFolder = false;
  793. pItem.id = item.fid;
  794. pItem.name = item.n;
  795. pItem.pickCode = item.pc;
  796. pItem.sha1 = item.sha;
  797. pItem.size = item.s;
  798. } else //目录 cid,pid
  799. {
  800. pItem.isFolder = true;
  801. pItem.id = item.cid;
  802. pItem.name = item.n;
  803. pItem.pickCode = item.pc;
  804. }
  805. var itemIndex = items.findIndex(q => q.name == pItem.name && q.pickCode == pItem.pickCode && q.sha1 == pItem.sha1 && (_.isEqual(q.paths, pItem.paths)));
  806. if (itemIndex == -1) items.push(pItem);
  807. else {
  808. //可能存在同一个目录下,两个文件一模一样,
  809. //相同文件处理:不然循环条件退不出
  810. //fix:pickcode不一样,先保存着吧
  811. pItem.needToRemoved = true;
  812. items.push(pItem)
  813. }
  814. })
  815. }
  816. console.log("_______________totalCount " + totalCount);
  817. console.log(items.length)
  818. //当获取到比pagesize小时,获取结束,1200时有个坑。。。
  819. if (totalCount <= items.length) {
  820. break;
  821. } else {
  822. await delay(500);
  823. index = items.length;
  824. pageIndex = pageIndex + 1;
  825. }
  826. }
  827. console.log("cid: {0}, count: {1}".format(cid, items.length));
  828. var noNullItems = items.filter(q => !q.needToRemoved);
  829. console.log("cid: {0}, 除去完全重复count: {1}".format(cid, noNullItems.length));
  830. return noNullItems;
  831. }
  832. //return {file_name:"",pick_code:"",sha1:"",count:"",size:"",folder_count:"",paths:[]}
  833. //return paths:[]层级目录
  834. async function getFolderInfo(cid) {
  835. var pUrl = "https://webapi.115.com/category/get?aid=1&cid=" + cid;
  836. const result = await $.ajax({
  837. type: 'GET',
  838. url: pUrl,
  839. dataType: "json",
  840. xhrFields: {
  841. withCredentials: true
  842. }
  843. });
  844. console.log(result);
  845. var pItem = {
  846. fileCount: parseInt(result.count),
  847. folderCount: parseInt(result.folder_count),
  848. id: cid,
  849. parentID: "",
  850. isFolder: true,
  851. name: result.file_name,
  852. size: result.size,
  853. pickCode: result.pick_code,
  854. sha1: "",
  855. paths: result.paths,
  856. preid: ""
  857. };
  858. return pItem;
  859. }
  860. // get fileArray:{id:"",parentID:cid,isFolder:false,name:"",size:0,pc:"",sha:"",paths[] };
  861. async function getAllFiles(cid, fileArray, topCid, folderProcessCallback) {
  862. var thisFolder = await getFolderInfo(cid);
  863. folderProcessCallback(thisFolder.name, 0);
  864. //空目录,跳过遍历
  865. if (getTaskCancelFlag()) return;
  866. if (thisFolder.fileCount == 0) return;
  867. folderProcessCallback(thisFolder.name)
  868. var directItems = await getAllDirectItems(thisFolder.id, pageIndex => {
  869. folderProcessCallback(thisFolder.name, pageIndex);
  870. });
  871. //空目录,跳过遍历
  872. if (directItems.length == 0) return;
  873. var files = directItems.filter(t => !t.isFolder);
  874. files.forEach(f => {
  875. var index = thisFolder.paths.findIndex(q => q.file_id.toString() == topCid);
  876. var paths = new Array();
  877. if (index != -1) {
  878. paths = thisFolder.paths.slice(index).map(q => q.file_name);
  879. }
  880. paths.push(thisFolder.name);
  881. f.paths = paths.slice(1);
  882. fileArray.push(f);
  883. });
  884. var folders = directItems.filter(t => t.isFolder);
  885. for (var folder of folders) {
  886. if (getTaskCancelFlag()) break;
  887. await getAllFiles(folder.id, fileArray, topCid, folderProcessCallback);
  888. await delay(200);
  889. }
  890. }
  891. //批量重命名 fileArray [{id:id,name:ddd}]
  892. //{"state":true,"error":"","errno":0,"data":{"2187365717527997108":"14214.mp4"}}
  893. async function renameFiles(fileArray) {
  894. console.log("renameFiles fileArray");
  895. console.log(fileArray);
  896. let datas = fileArray.map((value, index, array) => {
  897. let dataKey = `files_new_name[${value.id}]`;
  898. let dataValue = value.name;
  899. return `${encodeURIComponent(dataKey)}=${encodeURIComponent(dataValue)}`;
  900. }).join("&");
  901. let renameUrl = "https://webapi.115.com/files/batch_rename";
  902. const result = await $.ajax({
  903. type: 'POST',
  904. url: renameUrl,
  905. headers: {
  906. 'Content-Type': 'application/x-www-form-urlencoded',
  907. //'Origin': 'https://115.com'
  908. },
  909. dataType: "json",
  910. xhrFields: {
  911. withCredentials: true
  912. },
  913. data: datas
  914. });
  915. return result;
  916. }
  917. //获取生成sha1需要preid
  918. //return: {state:,error:,fileItem:}
  919. function getFileItemPreid(fileItem) {
  920. console.log('getFileItemPreid')
  921. console.log(fileItem);
  922. const f = fileItem;
  923. let fileSize = parseInt(fileItem.size);
  924. if (fileSize == 0) {
  925. return new Promise((resolve, reject) => {
  926. const errorMsg = "{0} 文件大小为0,已经跳过!".format(f.filename);
  927. console.error("errorMsg");
  928. resolve({
  929. state: false,
  930. error: "文件大小为0,已经跳过!",
  931. fileItem: fileItem
  932. });
  933. });
  934. }
  935. const r = new Promise((resolve, reject) => {
  936. GM_xmlhttpRequest({
  937. method: "POST",
  938. url: 'https://proapi.115.com/app/chrome/downurl',
  939. headers: {
  940. 'Content-Type': 'application/x-www-form-urlencoded',
  941. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 115Browser/23.9.3.6'
  942. },
  943. responseType: 'json',
  944. data: PostData({
  945. data: m115_encode('{"pickcode":"' + fileItem.pickCode + '"}')
  946. }),
  947. onload: function (r) {
  948. if (r.status == 200) {
  949. var download_info = r.response;
  950. if (download_info.state && download_info.data) {
  951. try {
  952. var json = m115_decode(download_info.data);
  953. //console.log(json)
  954. var url = JSON.parse(json)[fileItem.id]['url']['url'];
  955. //todo:不能下载的文件处理
  956. if (!url.startsWith("http://cdnfhnfdfs.115.com") && url.startsWith('http:///')) {
  957. console.error(`error url:${url}`);
  958. url = url.replace("http:///", "http://cdnfhnfdfs.115.com/")
  959. }
  960. console.log(url);
  961. var resp = r.responseHeaders
  962. var setCookie = DeleteCookie(resp)
  963. var fileCookie = null;
  964. if (setCookie) {
  965. fileCookie = setCookie;
  966. }
  967. GM_xmlhttpRequest({
  968. method: "GET",
  969. url: url,
  970. timeout: 12000,
  971. headers: {
  972. "Range": "bytes=0-131072",
  973. "Cookie": fileCookie,
  974. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36 115Browser/23.9.3.6'
  975. },
  976. responseType: 'arraybuffer',
  977. onload: function (response) {
  978. if (response.status === 206) {
  979. var pre_buff = response.response;
  980. var data = new Uint8Array(pre_buff);
  981. var sha1 = new jsSHA('SHA-1', 'ARRAYBUFFER');
  982. sha1.update(data.slice(0, 128 * 1024));
  983. var preid = sha1.getHash('HEX', {
  984. outputUpper: true
  985. });
  986. fileItem.preid = preid;
  987. resolve({
  988. state: true,
  989. error: "",
  990. fileItem: fileItem
  991. });
  992. } else if (response.status === 403) {
  993. console.error("Forbidden, 已经用40个0代替");
  994. fileItem.preid = "0000000000000000000000000000000000000000";
  995. resolve({
  996. state: true,
  997. error: "",
  998. fileItem: fileItem
  999. });
  1000. }
  1001. },
  1002. ontimeout: function (res) {
  1003. console.error("下载超时,可能文件无法下载或者网络问题");
  1004. console.log(res);
  1005. resolve({
  1006. state: false,
  1007. error: "下载超时,可能文件无法下载或者网络问题",
  1008. fileItem: fileItem
  1009. });
  1010. }
  1011. });
  1012. } catch (error) {
  1013. console.error(error);
  1014. resolve({
  1015. state: false,
  1016. error: "在提取中发生错误...",
  1017. fileItem: fileItem
  1018. });
  1019. }
  1020. } else {
  1021. console.log(download_info);
  1022. resolve({
  1023. state: false,
  1024. error: download_info.msg,
  1025. fileItem: fileItem
  1026. });
  1027. }
  1028. } else {
  1029. console.error(response.response);
  1030. resolve({
  1031. state: false,
  1032. error: "在提取中发生错误...",
  1033. fileItem: fileItem
  1034. });
  1035. }
  1036. }
  1037. });
  1038. });
  1039. return r;
  1040. }
  1041. //格式化sha1 链接
  1042. //return type: {state:succeed,msg:""}
  1043. // false:msg->出错信息
  1044. //true: msg->sha1链接
  1045. function convertToSha1Link(fileItem, isSimpleFormat) {
  1046. var succeed = false;
  1047. var msg = "格式生成失败!";
  1048. if (fileItem.name && fileItem.size && fileItem.sha1 && fileItem.preid) {
  1049. var sha1Link = "115://" + fileItem.name + "|" + fileItem.size + "|" + fileItem.sha1 + "|" + fileItem.preid;
  1050. if (!isSimpleFormat) {
  1051. if (fileItem.paths.length > 0) {
  1052. //console.log(fileItem.paths);
  1053. var paths = fileItem.paths.join('|');
  1054. msg = sha1Link + '|' + paths;
  1055. } else {
  1056. msg = sha1Link;
  1057. }
  1058. } else {
  1059. msg = sha1Link;
  1060. }
  1061. succeed = true;
  1062. }
  1063. return {
  1064. state: succeed,
  1065. msg: msg
  1066. };
  1067. }
  1068. // 从sha1link 转换为 FileItem
  1069. //return type:{state:succeed,fileItem:{}}
  1070. //true: fileItem, false:null
  1071. function convertFromSha1Link(sha1Link) {
  1072. var succeed = false;
  1073. var item = {};
  1074. if (sha1Link) {
  1075. if (sha1Link.startsWith("115://")) {
  1076. sha1Link = sha1Link.substring(6);
  1077. }
  1078. var infos = sha1Link.split('|');
  1079. if (infos.length >= 4) {
  1080. item.id = "";
  1081. item.pickCode = "";
  1082. item.name = infos[0];
  1083. item.size = infos[1];
  1084. item.sha1 = infos[2];
  1085. item.preid = infos[3];
  1086. item.parentID = "";
  1087. item.paths = new Array();
  1088. if (infos.length > 4) {
  1089. if (infos.length == 5 && infos[4].includes('#')) {
  1090. //兼容 #字符分割
  1091. item.paths = infos[4].split('#');
  1092. } else {
  1093. item.paths = infos.slice(4);
  1094. }
  1095. }
  1096. item.extension = "";
  1097. item.formatedName = "";
  1098. succeed = true;
  1099. }
  1100. }
  1101. return {
  1102. state: succeed,
  1103. fileItem: item
  1104. };
  1105. }
  1106. function createUploadFile(urlData, postData) {
  1107. return new Promise((resolve, reject) => {
  1108. GM_xmlhttpRequest({
  1109. method: 'POST',
  1110. url: 'http://uplb.115.com/3.0/initupload.php?' + urlData,
  1111. data: postData,
  1112. responseType: 'json',
  1113. headers: {
  1114. 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
  1115. //'Origin': 'https://115.com'
  1116. },
  1117. onload: function (response) {
  1118. let data = {
  1119. state: false,
  1120. error: "",
  1121. pickCode: ""
  1122. };
  1123. if (response.status === 200 && response.response.status === 2) {
  1124. data.state = true;
  1125. data.pickCode = response.response.pickcode;
  1126. } else {
  1127. console.error(response);
  1128. let error = "或许sha1链接不匹配(?)";
  1129. if (response.status === 405) {
  1130. error = "频繁请求,被115限制 ([!]立即停止,尝试停止操作半小时或者重新登录):" + response.statusText;
  1131. } else if (response.response && response.response.message) error = response.response.message;
  1132. else if (response.response && response.response.statusmsg) error = "可能参数不正确(?):" + response.response.statusmsg;
  1133. data.error = error;
  1134. }
  1135. resolve(data);
  1136. }
  1137. })
  1138. });
  1139. }
  1140. //return:{state:false,error:"",fileItem:};
  1141. function uploadFile(targetFolder, fileItem, uploadInfo) {
  1142. let fCid = `U_1_${targetFolder}`;
  1143. let appVersion = "25.2.0";
  1144. let urlData = UrlData({
  1145. isp: 0,
  1146. appid: 0,
  1147. appversion: appVersion,
  1148. format: 'json',
  1149. sig: GetSig(uploadInfo.user_id, fileItem.sha1, fCid, uploadInfo.userkey)
  1150. });
  1151. let postData = PostData({
  1152. preid: fileItem.preid,
  1153. fileid: fileItem.sha1,
  1154. quickid: fileItem.sha1,
  1155. app_ver: appVersion,
  1156. filename: encodeURIComponent(fileItem.formatedName),
  1157. filesize: fileItem.size,
  1158. exif: '',
  1159. target: fCid,
  1160. userid: uploadInfo.user_id
  1161. });
  1162. const r = createUploadFile(urlData, postData);
  1163. const x = r.then(t => {
  1164. return new Promise((resole, reject) => {
  1165. fileItem.state = t.state;
  1166. fileItem.pickCode = t.pickCode;
  1167. resole({
  1168. state: t.state,
  1169. error: t.error,
  1170. fileItem: fileItem
  1171. });
  1172. })
  1173. });
  1174. return x;
  1175. }
  1176. function setListView() {
  1177. GM_xmlhttpRequest({
  1178. method: "POST",
  1179. url: 'https://115.com/?ct=user_setting&ac=set',
  1180. headers: {
  1181. 'Content-Type': 'application/x-www-form-urlencoded'
  1182. },
  1183. data: PostData({
  1184. setting: '{"view_file":"list"}'
  1185. }),
  1186. responseType: 'json',
  1187. onload: function (response) {
  1188. if (response.status === 200) {}
  1189. }
  1190. });
  1191. }
  1192. //#endregion
  1193. async function updateParentID(cid, cname, thisLevel, maxLevel, items, sleepTime, createFolderCallback) {
  1194. if (thisLevel == maxLevel) return;
  1195. let files = new Array();
  1196. if (thisLevel == 0) {
  1197. files = items;
  1198. } else {
  1199. files = items.filter(f => f.paths[thisLevel - 1] == cname);
  1200. }
  1201. let childFiles = files.filter(q => q.paths.length == thisLevel);
  1202. let childFolderNames = files.map(q => q.paths[thisLevel]).filter(q => q).filter((x, i, a) => a.indexOf(x) == i)
  1203. console.log(`childFiles :${childFiles.length}`)
  1204. //upload file:
  1205. for (let file of childFiles) {
  1206. file.parentID = cid;
  1207. //console.log(file.parentID);
  1208. }
  1209. //create folder:
  1210. for (let folderName of childFolderNames) {
  1211. let r = await addFolder(cid, folderName);
  1212. createFolderCallback && createFolderCallback({
  1213. state: r.state,
  1214. folderName: folderName,
  1215. error: r.error
  1216. });
  1217. console.log(r);
  1218. if (r.state) {
  1219. await updateParentID(r.cid, folderName, thisLevel + 1, maxLevel, files, createFolderCallback);
  1220. } else { //ui 目录创建失败 todo:
  1221. console.error(`目录 ${folderName} 创建失败`);
  1222. }
  1223. await delay(sleepTime);
  1224. }
  1225. }
  1226. function internelFormat(folder, files, folderParents) {
  1227. var paths = folderParents.slice(0);
  1228. paths.push(folder.dir_name);
  1229. for (var file of folder.files) {
  1230. var link = file + '|' + paths.slice(1).join('|');
  1231. files.push(link);
  1232. }
  1233. for (var childFolder of folder.dirs) {
  1234. internelFormat(childFolder, files, paths)
  1235. }
  1236. }
  1237. //{state:true,error:"",text:""}
  1238. function formatJsonToCommon(text) {
  1239. try {
  1240. var root = JSON.parse(text);
  1241. console.log(root);
  1242. var files = new Array();
  1243. var paths = new Array();
  1244. internelFormat(root, files, paths);
  1245. return {
  1246. state: true,
  1247. error: "",
  1248. text: files.join('\r\n'),
  1249. rootFolder: root.dir_name
  1250. };
  1251. } catch (error) {
  1252. return {
  1253. state: false,
  1254. error: error,
  1255. text: ""
  1256. };
  1257. }
  1258. }
  1259. //解析inline text sha1 links,并根据配置设置分隔符;返回FileArray
  1260. function parseSha1LinksToFileArray(text, nameSeparator, errorCallback) {
  1261. let textLines = text.split(/\r?\n/);
  1262. let files = new Array();
  1263. for (let line of textLines) {
  1264. let fLine = line.trim();
  1265. if (!fLine) continue;
  1266. let r = convertFromSha1Link(fLine);
  1267. if (r.state) {
  1268. let nameStrings = r.fileItem.name.split(".");
  1269. let extension = nameStrings.pop();
  1270. r.fileItem.extension = extension;
  1271. //根据配置重新设置文件名
  1272. if (nameSeparator) {
  1273. //使用emoutils.js库来分割,带有emoji的文件名
  1274. let fileName = emojiUtils.toArray(nameStrings.join('.')).map(c => c + nameSeparator).join("").slice(0, -1);
  1275. r.fileItem.formatedName = fileName + "." + extension;
  1276. } else {
  1277. r.fileItem.formatedName = r.fileItem.name;
  1278. }
  1279. files.push(r.fileItem);
  1280. } else {
  1281. errorCallback && errorCallback(`${fLine} 格式错误?`);
  1282. }
  1283. }
  1284. return files;
  1285. }
  1286. //在targetCid下创建目录,成功则返回新目录cid,否则返回原cid;返回’-1‘,target已经被移除或者删除
  1287. async function createRootFolder(targetCid, folderName, retryTimes, sleepTime, processCallback) {
  1288. let cid = targetCid;
  1289. let newFolderName = folderName;
  1290. if (folderName == "") {
  1291. newFolderName = `auto_create@${new Date().getTime()}`;
  1292. }
  1293. for (let i = 0; i < retryTimes; i++) {
  1294. if (i != 0) {
  1295. newFolderName = `${folderName==""?"auto_create":folderName}@${new Date().getTime()}`;
  1296. }
  1297. processCallback && processCallback(`正在自动创建根目录${newFolderName}...`);
  1298. let tr = await addFolder(targetCid, newFolderName);
  1299. if (tr.state) {
  1300. cid = tr.cid;
  1301. processCallback && processCallback(`自动创建根目录${newFolderName}成功!`);
  1302. break;
  1303. } else {
  1304. processCallback && processCallback(`自动创建根目录${newFolderName}失败!原因:${tr.error},将自动尝试新的名字...`);
  1305. if (tr.error.includes('云端目录不存在') || tr.error.includes('文件不存在或已删除')) {
  1306. cid = '-1'; //父目录不存在时的提示
  1307. break;
  1308. }
  1309. await delay(sleepTime);
  1310. }
  1311. }
  1312. //todo:父目录不存在时的提示
  1313. return {cid:cid,folderName:newFolderName};
  1314. }
  1315. async function processUpload(allFiles, workingNumber, sleepTime, resultCallback) {
  1316. let fileArray=allFiles.filter(q=>!q.state);
  1317. let index = 1;
  1318. let fileLength = allFiles.length;
  1319. let completed = fileLength-fileArray.length;
  1320. let promisArray = new Array();
  1321. let uploadInfo = await getUploadInfo();
  1322. let msg;
  1323. for (let file of fileArray) {
  1324. if (getTaskCancelFlag()) {
  1325. console.log("转存取消");
  1326. //postSha1Messgae(createMessage(MessageType.PROCESSING, "已取消,正在等待进行中的任务结束..."));
  1327. break;
  1328. }
  1329. console.log(file);
  1330. let r = uploadFile(file.parentID, file, uploadInfo).then(t => {
  1331. completed = completed + 1;
  1332. if (t.state) {
  1333. msg = `<div align="right"><b>${completed}</b> | <b>${fileLength}</b></div><hr>【 <b>${t.fileItem.name}</b> 】上传成功.`;
  1334. } else {
  1335. let uploadError = `【 <b>${t.fileItem.name}</b> 】上传失败!!! ${t.error}`;
  1336. resultCallback && resultCallback({
  1337. state: false,
  1338. msg: uploadError
  1339. });
  1340. msg = `<div align="right"><b>${completed}</b> | <b>${fileLength}</b></div><hr>${uploadError}`;
  1341. }
  1342. resultCallback && resultCallback({
  1343. state: true,
  1344. msg: msg
  1345. });
  1346. });
  1347. promisArray.push(r);
  1348. if (index % workingNumber == 0) {
  1349. await delay(sleepTime);
  1350. }
  1351. if (index % 120 == 0) {
  1352. await Promise.all(promisArray);
  1353. let seconds = 3;
  1354. for (let i = 0; i < seconds; i++) {
  1355. resultCallback && resultCallback({
  1356. state: true,
  1357. msg: `防止115服务器限制,暂停发包。<br><br>${seconds - i}秒后继续....`
  1358. });
  1359. await delay(1000);
  1360. }
  1361. promisArray = new Array();
  1362. }
  1363. index = index + 1;
  1364. }
  1365. await delay(500);
  1366. await Promise.all(promisArray);
  1367. return fileArray;
  1368. }
  1369. async function processRename(targetFolderCid, separator, sleepTime, resultCallback) {
  1370. let onlineFiles = new Array();
  1371. await getAllFiles(targetFolderCid, onlineFiles, targetFolderCid, (fname, pIndex) => {
  1372. if (pIndex > 1) {
  1373. resultCallback && resultCallback({
  1374. state: true,
  1375. msg: `正在获取 【${fname}】 下第 ${pIndex} 页的内容...`
  1376. });
  1377. } else {
  1378. resultCallback && resultCallback({
  1379. state: true,
  1380. msg: `正在获取 【${fname}】 下的内容...`
  1381. });
  1382. }
  1383. });
  1384. let selectedFiles = onlineFiles.filter(f => f.name.search(separator) != -1).map(f => {
  1385. let fo = {
  1386. id: f.id,
  1387. name: f.name.split(separator).join("")
  1388. };
  1389. return fo;
  1390. });
  1391. let i, j, temporary, chunk = 500;
  1392. for (i = 0, j = selectedFiles.length; i < j; i += chunk) {
  1393. temporary = selectedFiles.slice(i, i + chunk);
  1394. resultCallback && resultCallback({
  1395. state: true,
  1396. msg: `正在重命名第${i + 1}到${i + temporary.length}个文件...`
  1397. });
  1398. let renameResult = await renameFiles(temporary);
  1399. if (renameResult.state === true) {
  1400. resultCallback && resultCallback({
  1401. state: true,
  1402. msg: `重命名第${i + 1}到${i + temporary.length}个文件成功!`
  1403. });
  1404. } else {
  1405. resultCallback && resultCallback({
  1406. state: false,
  1407. msg: renameResult.error
  1408. });
  1409. resultCallback && resultCallback({
  1410. state: true,
  1411. msg: `重命名第${i + 1}到${i + 1 + temporary.length}个文件中有失败!!!`
  1412. });
  1413. }
  1414. await delay(sleepTime * 2);
  1415. }
  1416. }
  1417. //通过sha1链接转存文件
  1418. //uploadSetting:{targetCid,text,rootFolder:{needToCreate:true,folderName:""},itemNameSeparator:{needToSeparate:true,separator:""}}
  1419. async function UploadFilesBySha1Links(config,continuedTaskSetting=null) {
  1420. let uploadConfig=continuedTaskSetting==null?config:continuedTaskSetting.uploadConfig;
  1421. let folderSleepTime = uploadConfig.folderSetting.sleepTime;
  1422. let nameSeparator = "";
  1423. let newTargetCid ='-1';
  1424. let files;
  1425. window.parent.window.myTaskFiles;
  1426. let fileName='';
  1427. if(continuedTaskSetting==null){
  1428. let formatedText = uploadConfig.text;
  1429. if (!formatedText) return;
  1430. postSha1Messgae(createMessage(MessageType.BEGIN4UPLOAD, "正在解析sha1链接..."));
  1431. //解析json,转为inline text;并且从json中获取root folder name
  1432. if (formatedText.startsWith('{') && formatedText.endsWith('}')) {
  1433. let r = formatJsonToCommon(formatedText);
  1434. if (r.state) {
  1435. uploadConfig.folderSetting.rootFolder.folderName = r.rootFolder;
  1436. formatedText = r.text;
  1437. } else {
  1438. console.error("json 解析失败");
  1439. postSha1Messgae(createMessage(MessageType.END4UPLOAD, "json解析失败!是不是格式不匹配!"));
  1440. return;
  1441. //json 解析失败,提示,,
  1442. }
  1443. }
  1444. //解析inline text sha1 links,并根据配置设置分隔符
  1445. if (uploadConfig.itemNameSeparator.needToSeparate && uploadConfig.itemNameSeparator.separator) {
  1446. nameSeparator = uploadConfig.itemNameSeparator.separator;
  1447. }
  1448. files = parseSha1LinksToFileArray(formatedText, nameSeparator, errorMsg => {
  1449. postSha1Messgae(createMessage(MessageType.ERROR, errorMsg));
  1450. });
  1451. postSha1Messgae(createMessage(MessageType.PROCESSING, `获取到链接个数:${files.length}`));
  1452. await delay(500);
  1453. //根目录设置
  1454. //根据配置重新设置targetCid
  1455. newTargetCid = uploadConfig.targetCid;
  1456. if (uploadConfig.folderSetting.rootFolder.needToCreate === true) {
  1457. let rootFolderName = uploadConfig.folderSetting.rootFolder.folderName;
  1458. let root= await createRootFolder(newTargetCid, rootFolderName, 11, folderSleepTime * 2, msg => {
  1459. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1460. });
  1461. fileName=root.folderName;
  1462. newTargetCid=root.cid;
  1463. await delay(500);
  1464. }
  1465. console.log(`newTargetCid: ${newTargetCid}`);
  1466. if (newTargetCid == "-1") {
  1467. console.log("选择的保存处文件夹已经被删除或者移动");
  1468. postSha1Messgae(createMessage(MessageType.END, "自动创建根目录出错: <br/>选择的保存处文件夹,已经被删除或者移动,请重新选择保存位置!"));
  1469. return;
  1470. }
  1471. //子目录设置
  1472. files.forEach(f => {
  1473. f.parentID = newTargetCid;
  1474. });
  1475. if (uploadConfig.folderSetting.notCreateAnyChildFolder === false) //可以创建目录
  1476. {
  1477. console.log("需要创建子目录");
  1478. //根据配置设置每个文件的parent id
  1479. //最大的层次
  1480. let maxLevel = Math.max.apply(Math, files.map(e => e.length));
  1481. let level = 0;
  1482. //cid更新
  1483. postSha1Messgae(createMessage(MessageType.PROCESSING, `正在配置子目录的生成...`));
  1484. await updateParentID(newTargetCid, '',
  1485. level, maxLevel, files, folderSleepTime, t => {
  1486. let st = t.state ? "成功." : "失败!!! " + t.error;
  1487. let msg = `创建子目录 <b>${t.folderName}</b> ${st}`;
  1488. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1489. if (!t.state) postSha1Messgae(createMessage(MessageType.ERROR, msg));
  1490. });
  1491. }
  1492. }
  1493. else{
  1494. newTargetCid=continuedTaskSetting.targetCid;
  1495. files=continuedTaskSetting.data;
  1496. fileName=continuedTaskSetting.fileName;
  1497. }
  1498. window.parent.document.myData=files;
  1499. postSha1Messgae(createMessage(MessageType.SHOWCANCEl));
  1500. console.log(files.length);
  1501. //文件上传
  1502. await processUpload(files, uploadConfig.upload.workingNumber, uploadConfig.upload.sleepTime, result => {
  1503. if (result.state === true) {
  1504. postSha1Messgae(createMessage(MessageType.PROCESSING, result.msg));
  1505. } else {
  1506. postSha1Messgae(createMessage(MessageType.ERROR, result.msg));
  1507. }
  1508. });
  1509. let isTaskCanceled = getTaskCancelFlag();
  1510. postSha1Messgae(createMessage(MessageType.HIDECANCEL));
  1511. //根据配置,重命名文件
  1512. if (newTargetCid != uploadConfig.targetCid &&
  1513. uploadConfig.itemNameSeparator.needToSeparate &&
  1514. uploadConfig.itemNameSeparator.needToRemoveSeparator &&
  1515. uploadConfig.itemNameSeparator.separator &&
  1516. !isTaskCanceled) {
  1517. postSha1Messgae(createMessage(MessageType.PROCESSING, "开始获取文件,并自动重命名..."));
  1518. await delay(folderSleepTime);
  1519. await processRename(newTargetCid, uploadConfig.itemNameSeparator.separator, folderSleepTime, result => {
  1520. if (result.state === true) {
  1521. postSha1Messgae(createMessage(MessageType.PROCESSING, result.msg));
  1522. } else {
  1523. postSha1Messgae(createMessage(MessageType.ERROR, result.msg));
  1524. }
  1525. });
  1526. postSha1Messgae(createMessage(MessageType.PROCESSING, "文件批量去除分隔符(重命名)完成!"));
  1527. await delay(folderSleepTime * 2);
  1528. }
  1529. var fails = files.filter(q => !q.state);
  1530. var failText = fails.map(function (p) {
  1531. var r = convertToSha1Link(p, false);
  1532. return r.msg;
  1533. }).join("\r\n");
  1534. if (failText) GM_setClipboard(failText);
  1535. if (isTaskCanceled) {
  1536. //todo:取消转存
  1537. let file_name = fileName+ "_转存_未完成.7task";
  1538. let data = files.map(f => {
  1539. `let tempFile={
  1540. parentID:f.parentID,
  1541. name:f.name,
  1542. size:f.size,
  1543. sha1:f.sha1,
  1544. preid:f.preid,
  1545. };`
  1546. let tempFile = [
  1547. f.parentID,f.name, f.formatedName, f.size, f.sha1, f.preid, f.state
  1548. ];
  1549. return tempFile;
  1550. });
  1551. uploadConfig.text='';
  1552. let taskJson = {
  1553. taskType: TaskType.UPLOAD,
  1554. targetCid: newTargetCid,
  1555. fileName: fileName,
  1556. data: data,
  1557. uploadConfig:uploadConfig
  1558. };
  1559. let text = JSON.stringify(taskJson)
  1560. download(file_name, text);
  1561. }
  1562. let msg = `完成上传!成功 <b>${(files.length - fails.length)}</b> ,失败或者取消 <b>${fails.length}</b>\
  1563. <br><br>如果有失败,已将失败sha1链接复制到剪贴板!如果转存失败,请检查sha1链接格式或者在 chrome 上尝试转存。\
  1564. 获取最新版,或者遇到问题去此反馈,感谢 !点击-> <a href="${TIPS.UpdateUrl}" target="_blank">${TIPS.VersionTips}</a>`;
  1565. postSha1Messgae(createMessage(MessageType.END4UPLOAD, msg, newTargetCid));
  1566. }
  1567. function GetFileItemByliNode(liNode) {
  1568. var pItem = {
  1569. id: "",
  1570. parentID: "",
  1571. isFolder: false,
  1572. name: "",
  1573. size: 0,
  1574. pickCode: "",
  1575. sha1: "",
  1576. paths: [],
  1577. preid: "",
  1578. selected: false
  1579. };
  1580. var type = liNode.getAttribute("file_type");
  1581. pItem.name = liNode.getAttribute('title');
  1582. pItem.parentID = liNode.getAttribute('p_id');
  1583. var isSelected = liNode.getAttribute('class');
  1584. if (isSelected == "selected") pItem.selected = true;
  1585. if (type == "0") {
  1586. pItem.id = liNode.getAttribute('cate_id');
  1587. pItem.isFolder = true;
  1588. } else {
  1589. pItem.size = liNode.getAttribute('file_size');
  1590. pItem.sha1 = liNode.getAttribute('sha1');
  1591. pItem.pickCode = liNode.getAttribute('pick_code');
  1592. pItem.id = liNode.getAttribute('file_id');
  1593. }
  1594. return pItem;
  1595. }
  1596. const FILESIZE = 128 * 1024;
  1597. async function InnerCreateSha1Links(allFiles, txtName) {
  1598. var msg = "";
  1599. var index = 1;
  1600. var completedIndex = 1;
  1601. var promisArray = new Array();
  1602. for (let file of allFiles) {
  1603. let fileSize = parseInt(file.size);
  1604. file.size = fileSize;
  1605. if (!file.preid && file.size <= FILESIZE) {
  1606. file.preid = file.sha1;
  1607. }
  1608. }
  1609. let files = allFiles.filter(f => !f.preid);
  1610. completedIndex = allFiles.length - files.length;
  1611. var gt1200files = files.length >= 1200;
  1612. console.log(`>=1200: ${gt1200files}`);
  1613. //postSha1Messgae(createMessage(MessageType.PROCESSING, `总计${allFiles.length},已完成${completedIndex}`));
  1614. postSha1Messgae(createMessage(MessageType.SHOWCANCEl))
  1615. for (var file of files) {
  1616. let taskCancelFlag = getTaskCancelFlag();
  1617. console.log(taskCancelFlag);
  1618. if (taskCancelFlag === true) {
  1619. console.log("InnerCreateSha1Links has Canceled");
  1620. break;
  1621. }
  1622. const f = file;
  1623. const r = getFileItemPreid(f).then((t) => {
  1624. if (t.state) {
  1625. msg = '<div align="right"><b>{0}</b> | <b>{1}</b></div><hr>获取【 <b>{2}</b> 】的sha1链接成功'.format(completedIndex, allFiles.length, t.fileItem.name);
  1626. postSha1Messgae(createMessage(MessageType.PROCESSING, msg))
  1627. } else {
  1628. msg = '<div align="right"><b>{0}</b> | <b>{1}</b></div><hr>获取【 <b>{2}</b> 】的sha1链接失败!{3}'.format(completedIndex, allFiles.length, t.fileItem.name, t.error);
  1629. postSha1Messgae(createMessage(MessageType.PROCESSING, msg))
  1630. var filePath = t.fileItem.paths.join(" > ");
  1631. console.log(filePath);
  1632. if (filePath) msg = "{0},原因:{1},路径:{2}".format(t.fileItem.name, t.error, filePath);
  1633. else msg = "{0},原因:{1}".format(t.fileItem.name, t.error);
  1634. postSha1Messgae(createMessage(MessageType.ERROR, msg));
  1635. }
  1636. completedIndex = completedIndex + 1;
  1637. });
  1638. promisArray.push(r);
  1639. //自己改代码吧,怎么弄提取逻辑。。太慢,耗时长;太快,115容易没反应
  1640. if (index % WORKSETTINGS.WorkingItemsNumber == 0) {
  1641. await delay(WORKSETTINGS.SleepMoreTime * 2);
  1642. if (index % (WORKSETTINGS.WorkingItemsNumber * 9) == 0) {
  1643. await Promise.all(promisArray);
  1644. let seconds = 2;
  1645. for (let i = 0; i < seconds; i++) {
  1646. postSha1Messgae(createMessage(MessageType.PROCESSING, `防止115服务器限制,暂停发包中。<br><br>${seconds - i}秒后继续...`));
  1647. await delay(1000);
  1648. }
  1649. promisArray = new Array();
  1650. }
  1651. }
  1652. //
  1653. index = index + 1;
  1654. }
  1655. await Promise.all(promisArray);
  1656. var succeedArray = allFiles.filter(q => q.preid);
  1657. if (succeedArray.length == 1) {
  1658. var result = convertToSha1Link(succeedArray[0], false);
  1659. postSha1Messgae(createMessage(MessageType.CLOSE, ""));
  1660. setTimeout(s => {
  1661. prompt("复制分享链接到剪贴板", s);
  1662. }, 100, result.msg);
  1663. } else {
  1664. if (succeedArray.length > 1) {
  1665. let file_name = txtName + "_sha1.txt";
  1666. let text = "";
  1667. if (getTaskCancelFlag()) {
  1668. file_name = txtName + "_提取_未完成.7task";
  1669. let data = allFiles.map(f => {
  1670. `let tempFile={
  1671. id:f.id,
  1672. parentID:f.parentID,
  1673. name:f.name,
  1674. size:f.size,
  1675. paths:f.paths,
  1676. pickCode:f.pickCode,
  1677. sha1:f.sha1,
  1678. preid:f.preid,
  1679. };`
  1680. let tempFile = [
  1681. f.id, f.parentID, f.name, f.size, f.paths, f.pickCode, f.sha1, f.preid,
  1682. ];
  1683. return tempFile;
  1684. });
  1685. let taskJson = {
  1686. taskType: TaskType.DOWNLOAD,
  1687. fileName: txtName,
  1688. data: data
  1689. };
  1690. text = JSON.stringify(taskJson)
  1691. //todo:取消任务
  1692. } else {
  1693. text = allFiles.filter(q => q.preid).map(function (p) {
  1694. var r = convertToSha1Link(p, false);
  1695. return r.msg;
  1696. }).join("\r\n");
  1697. }
  1698. download(file_name, text);
  1699. }
  1700. msg = `
  1701. 完成【 <b>${txtName}</b> 】提取!<hr><br>
  1702. 总共<b>${allFiles.length}</b> ,取消或者失败 <b>${allFiles.length-succeedArray.length}</b>。<br>
  1703. 取消后,若未移动文件夹,可导入继续提取。<br>
  1704. 点击-> <a href="${TIPS.UpdateUrl}" target="_blank">${TIPS.VersionTips}</a>,获取最新版与反馈!
  1705. `;
  1706. console.log(msg);
  1707. postSha1Messgae(createMessage(MessageType.END, msg));
  1708. }
  1709. }
  1710. async function CreateSha1LinksAll(items, taskName) {
  1711. //ui: 获取文件中...
  1712. var msg = "正在获取文件...";
  1713. postSha1Messgae(createMessage(MessageType.BEGIN, msg));
  1714. var files = new Array();
  1715. for (let item of items) {
  1716. if (getTaskCancelFlag()) break;
  1717. if (!item.isFolder) {
  1718. files.push(item);
  1719. } else {
  1720. msg = `正在获取 ${item.name} 下的内容...`;
  1721. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1722. let children = new Array();
  1723. await getAllFiles(item.id, children, item.id, (fname, pIndex) => {
  1724. if (pIndex > 1) {
  1725. msg = `正在获取 【${fname}】 下第 ${pIndex} 页的内容...`;
  1726. } else {
  1727. msg = `正在获取 【${fname}】 下的内容...`;
  1728. }
  1729. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1730. });
  1731. for (let f of children) {
  1732. f.paths.unshift(item.name);
  1733. files.push(f);
  1734. }
  1735. }
  1736. }
  1737. if (!files || files.length == 0) {
  1738. postSha1Messgae(createMessage(MessageType.END, `未选中任何内容???`));
  1739. return;
  1740. }
  1741. postSha1Messgae(createMessage(MessageType.PROCESSING, `获取到 【<b>${taskName}</b>】 的内容 ${files.length} 项`));
  1742. await delay(100);
  1743. if (getTaskCancelFlag()) {
  1744. postSha1Messgae(createMessage(MessageType.END, "已经取消任务!"));
  1745. } else InnerCreateSha1Links(files, taskName);
  1746. }
  1747. async function CreateSha1Links(item) {
  1748. //ui: 获取文件中...
  1749. var msg = "正在获取文件...";
  1750. postSha1Messgae(createMessage(MessageType.BEGIN, msg));
  1751. var files = new Array();
  1752. if (!item.isFolder) {
  1753. files.push(item);
  1754. } else {
  1755. msg = `正在获取 ${item.name} 下的内容...`;
  1756. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1757. await getAllFiles(item.id, files, item.id, (fname, pIndex) => {
  1758. if (pIndex > 1) {
  1759. msg = "正在获取 【{0}】 下第 {1} 页的内容...".format(fname, pIndex);
  1760. } else {
  1761. msg = "正在获取 【{0}】 下的内容...".format(fname);
  1762. }
  1763. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  1764. });
  1765. if (!files || files.length == 0) {
  1766. postSha1Messgae(createMessage(MessageType.END, "【<b>{0}</b> 】空目录???".format(item.name)));
  1767. return;
  1768. }
  1769. }
  1770. postSha1Messgae(createMessage(MessageType.PROCESSING, "获取到 【<b>{0}</b>】 的内容 {1} 项".format(item.name, files.length)));
  1771. await delay(100);
  1772. if (getTaskCancelFlag()) {
  1773. postSha1Messgae(createMessage(MessageType.END, "已经取消任务!"));
  1774. } else InnerCreateSha1Links(files, item.name);
  1775. }
  1776. const autoCreateRootFolderTips = {
  1777. msg: `sha1转存时,强制在保存处新建根目录`,
  1778. details: `选择时:&#013;&#010;1.新建根目录名来自sha1转存文件名或者json中的根元素。\
  1779. &#013;&#010;2.如果没有,则按编号(1-10)生成。\
  1780. &#013;&#010;如果未选择或者最终无法提取到目录名,则将保存处作为转存根目录`
  1781. };
  1782. const autoCreateRootFolderString =
  1783. `<div class="linktask-quota" style="height: 40px;display: block">\
  1784. <a>${autoCreateRootFolderTips.msg}</a>\
  1785. <div class="help" title=" ${autoCreateRootFolderTips.details}"><a></a></div>\
  1786. <span>&nbsp;&nbsp;</span><div class="option-switch" style="top:10px;left:10px">\
  1787. <input type="checkbox" checked="true" id="neAutoCreateRootfolder" onclick="function f() {return false}">\
  1788. <label for><i>开启</i><s>关闭</s><b>切换</b></label></div>`;
  1789. const notCreateAnyChildFolderTips = {
  1790. msg: `sha1转存时,不创建任何子目录`,
  1791. details: `选中时,不会自动创建任何子目录。此项与根目录不会影响!`
  1792. };
  1793. const notCreateAnyChildFolderString =
  1794. `<div id="neNotCreateAnyChildFolderParent" class="linktask-quota" style="height: 40px;display: block">\
  1795. <a>${notCreateAnyChildFolderTips.msg}</a>\
  1796. <div class="help" title=" ${notCreateAnyChildFolderTips.details}"><a></a></div>\
  1797. <span>&nbsp;&nbsp;</span><div class="option-switch" style="top:10px;left:10px">\
  1798. <input type="checkbox" checked="true" id="neNotCreateAnyChildFolder" onclick="function f() {return false}">\
  1799. <label for><i>开启</i><s>关闭</s><b>切换</b></label></div>`;
  1800. const selectFileTips = {
  1801. msg: `或者导入sha1链接文件(txt/json)`,
  1802. details: `如果不能正确显示选择文件按钮,可能是与其他脚本或者插件冲突!!`
  1803. };
  1804. const selectFileString = `<div class="linktask-quota" style="margin-top: 10px;">\
  1805. <a>${selectFileTips.msg}</a>\
  1806. <div class="help" title="${selectFileTips.details}"><a></a></div>\
  1807. <span>&nbsp;&nbsp;</span><input type="file" id="neSelectFile" accept=".txt,.json" style="display:block;color:#2777F8;visibility: visible;"></input></div>`;
  1808. const otherSettingString = `<div class="linktask-quota" style="margin-top: 10px;">\
  1809. 分隔符可<a id="neSetting1" href="javascript:;" style="color:#2777F8">点此设置</a>。\
  1810. <a style="color:red">效率考虑:只在自动生成根目录成功的情况下,可按配置自动去除分隔符</a>
  1811. </div>`
  1812. const headerString = `<div id="ne115tipsforheader">${TIPS.VersionTips}(${TIPS.LastUpdateDate}),\
  1813. <a style="color:red;" target="_blank" href=${TIPS.UpdateUrl}>更新&反馈点此!</a>\
  1814. <a href="javascript:;" style="color:#2777F8" id="neSetting2">设置点此!</a></div>`;
  1815. const beginUploadBySha1String = `<div class="con" id="downsha1"><a class="button" href="javascript:;">开始sha1转存</a></div>`;
  1816. function AddDownloadSha1Btn(jNode) {
  1817. var file = "";
  1818. var dialog = document.getElementsByClassName("dialog-box dialog-mini offline-box window-current")[0];
  1819. dialog.style.width = "720px";
  1820. if (document.getElementById('ne115tipsforheader') == null) {
  1821. $(headerString).appendTo(".dialog-header[rel$='title_box']");
  1822. $('#neSetting2')[0].addEventListener('click', e => {
  1823. (document.getElementsByClassName('close')[2].click());
  1824. GM_config.open();
  1825. });
  1826. }
  1827. if (document.getElementById('neSelectFile') == null) {
  1828. var div = document.getElementsByClassName('dialog-input input-offline');
  1829. console.log(div);
  1830. var $selectFile = $(selectFileString);
  1831. var $autoCreateRootFolder = $(autoCreateRootFolderString);
  1832. var $notCreateAnyChildFolder = $(notCreateAnyChildFolderString);
  1833. var $otherSetting = $(otherSettingString);
  1834. div[0].style.display = 'grid';
  1835. div[0].appendChild($selectFile[0]);
  1836. div[0].appendChild($autoCreateRootFolder[0]);
  1837. div[0].appendChild($otherSetting[0]);
  1838. div[0].appendChild($notCreateAnyChildFolder[0]);
  1839. //界面选项设置
  1840. //根目录自动创建默认值:
  1841. document.getElementById('neAutoCreateRootfolder').checked = GM_config.get(currentConfig.createRootFolderDefaultValue);
  1842. //是否显示不创建任何目录:
  1843. document.getElementById('neNotCreateAnyChildFolderParent').style.display = GM_config.get(currentConfig.createChildFolderVisible) === true ? 'block' : 'none';
  1844. document.getElementById('neNotCreateAnyChildFolder').checked = false;
  1845. $selectFile[0].addEventListener('change', e => {
  1846. console.log(e.target.files);
  1847. if (e.target.files) {
  1848. file = e.target.files[0];
  1849. } else {
  1850. file = "";
  1851. }
  1852. });
  1853. $('#neSetting1')[0].addEventListener('click', e => {
  1854. (document.getElementsByClassName('close')[2].click());
  1855. GM_config.open();
  1856. });
  1857. } else {
  1858. //界面选项设置
  1859. document.getElementById('neSelectFile').value = "";
  1860. file = "";
  1861. //根目录自动创建默认值:
  1862. document.getElementById('neAutoCreateRootfolder').checked = GM_config.get(currentConfig.createRootFolderDefaultValue);
  1863. //是否显示不创建任何目录:
  1864. document.getElementById('neNotCreateAnyChildFolderParent').style.display = GM_config.get(currentConfig.createChildFolderVisible) === true ? 'block' : 'none';
  1865. document.getElementById('neNotCreateAnyChildFolder').checked = false;
  1866. }
  1867. if (document.getElementById('downsha1') == null) {
  1868. resetTaskCancelFlag();
  1869. var $btn = $(beginUploadBySha1String);
  1870. jNode[0].appendChild($btn[0]);
  1871. $btn[0].addEventListener('click', e => {
  1872. let cid = $("em[rel=offlint_path_text]").attr("cid");
  1873. if (cid == "") {
  1874. //目录不存在,比如把 “云下载” 目录删除
  1875. cid = '0';
  1876. }
  1877. let notCreateAnyChildFolder = document.getElementById('neNotCreateAnyChildFolder').checked;
  1878. let autoCreateRootfolder = document.getElementById('neAutoCreateRootfolder').checked;
  1879. let links = document.getElementById('js_offline_new_add').value;
  1880. let config = {
  1881. targetCid: cid,
  1882. text: "",
  1883. folderSetting: {
  1884. notCreateAnyChildFolder: notCreateAnyChildFolder,
  1885. sleepTime: GM_config.get(currentConfig.createFolderSleepTime),
  1886. rootFolder: {
  1887. needToCreate: autoCreateRootfolder,
  1888. folderName: ""
  1889. },
  1890. },
  1891. itemNameSeparator: {
  1892. needToSeparate: GM_config.get(currentConfig.autoUseSeparator),
  1893. needToRemoveSeparator: GM_config.get(currentConfig.autoUseSeparatorToRename),
  1894. separator: GM_config.get(currentConfig.separator)
  1895. },
  1896. upload: {
  1897. workingNumber: GM_config.get(currentConfig.uploadNumber),
  1898. sleepTime: GM_config.get(currentConfig.uploadSleepTime),
  1899. }
  1900. };
  1901. if (file) {
  1902. console.log(file);
  1903. let reader = new FileReader();
  1904. reader.addEventListener('load', function (t) {
  1905. config.folderSetting.rootFolder.folderName = file.name.split(".").slice(0, -1).join();
  1906. config.text = t.target.result;
  1907. file = "";
  1908. UploadFilesBySha1Links(config);
  1909. });
  1910. reader.readAsText(file);
  1911. (document.getElementsByClassName('close')[2].click());
  1912. } else if (links) {
  1913. // var text = { FileName: "", Content: links };
  1914. config.folderSetting.rootFolder.folderName = "";
  1915. config.text = links;
  1916. UploadFilesBySha1Links(config);
  1917. (document.getElementsByClassName('close')[2].click());
  1918. }
  1919. });
  1920. }
  1921. let save = document.querySelector('.bt-task-safe')
  1922. if (save != null && document.querySelector('#saveTip') == null) {
  1923. save.insertAdjacentHTML('afterend', `<div id="saveTip"><p style="margin-left:20px;margin-top:-20px;">转存也在此处选择位置。<span style="color:red;">此位置可能已经被删除或移动,最好每次都点击确认!</span></p></div>`)
  1924. }
  1925. }
  1926. // function formatCommonToJson(children, root) {
  1927. // let childFiles = children.filter(f => f.Paths.length == 0);
  1928. // root.files = Array();
  1929. // root.dirs = Array();
  1930. // childFiles.forEach(c => root.files.push({ Name: c.Name }));
  1931. // let selectedChildren = children.filter(f => f.Paths.length > 0);
  1932. // let childFolders = selectedChildren.map(q => q.Paths[0]).filter((v, i, a) => a.indexOf(v) === i);
  1933. // childFolders.forEach(f => root.dirs.push({ dir_name: f }));
  1934. // root.dirs.forEach(d => {
  1935. // let newChildren = selectedChildren.filter(f => f.Paths[0] == d.dir_name)
  1936. // .map(c => {
  1937. // let a = { Name: c.Name, Paths: c.Paths.slice(1) };
  1938. // return a;
  1939. // })
  1940. // ConverterAdvanced(newChildren, d);
  1941. // });
  1942. // }
  1943. function AddCeateSha1ButtonInGrid(jNode) {
  1944. let $li = jNode.find('i[class^="file-thumb"]');
  1945. let $button = $('<button class="btnInGrid" title="获取sha1链接"><i class="icon-operate-light ifol-download"></i></button>');
  1946. $button.appendTo($li);
  1947. $button.click(function (e) {
  1948. e.stopPropagation();
  1949. let pItem = GetFileItemByliNode(jNode[0]);
  1950. console.log("生成sha1");
  1951. console.log(pItem);
  1952. //生成sha1
  1953. resetTaskCancelFlag();
  1954. CreateSha1Links(pItem);
  1955. });
  1956. }
  1957. function AddShareSHA1Btn(jNode) {
  1958. var parentNode = jNode[0].parentNode;
  1959. var pItem = GetFileItemByliNode(parentNode);
  1960. //目录,去除分隔符
  1961. if (pItem.isFolder && GM_config.get(currentConfig.advancedRename)) {
  1962. var $btn1 = $('<a><i></i><span>去除分隔符</span></a>');
  1963. $btn1.prependTo(jNode[0]);
  1964. $btn1[0].addEventListener('click', async e => {
  1965. let separator = GM_config.get(currentConfig.separator);
  1966. let sleepTime = GM_config.get(currentConfig.createFolderSleepTime);
  1967. postSha1Messgae(createMessage(MessageType.BEGIN4UPLOAD, ""));
  1968. postSha1Messgae(createMessage(MessageType.PROCESSING, `即将开始重命名 【${pItem.name}】 下所有文件:<br><br>去除分隔符:${separator}`));
  1969. await delay(1000);
  1970. await processRename(pItem.id, separator, sleepTime, result => {
  1971. if (result.state === true) {
  1972. postSha1Messgae(createMessage(MessageType.PROCESSING, result.msg));
  1973. } else {
  1974. postSha1Messgae(createMessage(MessageType.ERROR, result.msg));
  1975. }
  1976. });
  1977. postSha1Messgae(createMessage(MessageType.END4UPLOAD, `对目录 【${pItem.name}】下的文件重命名完成!\
  1978. <br><br>获取最新版,或者遇到问题去此反馈,感谢 !点击->\
  1979. <a href="${TIPS.UpdateUrl}" target="_blank">${TIPS.VersionTips}</a>`, pItem.id));
  1980. })
  1981. }
  1982. var $btn = $('<a ><i></i><div style="background:white"><span>获取SHA1链接</span></div></a>');
  1983. jNode[0].style.top = "1px";
  1984. jNode[0].style.left = "140px";
  1985. $btn.prependTo(jNode[0]);
  1986. $btn[0].addEventListener('click', e => {
  1987. console.log("生成sha1");
  1988. console.log(pItem);
  1989. //生成sha1
  1990. resetTaskCancelFlag();
  1991. CreateSha1Links(pItem);
  1992. })
  1993. //生成json格式
  1994. // if(pItem.isFolder)
  1995. // {
  1996. // var $btn1 = $('<a><i></i><span>获取SHA1(json)</span></a>');
  1997. // $btn1.prependTo(jNode[0]);
  1998. // $btn1[0].addEventListener('click', e => {
  1999. // console.log(pItem);
  2000. // //生成sha1
  2001. // resetTaskCancelFlag();
  2002. // CreateSha1Links(pItem);
  2003. // })
  2004. // }
  2005. }
  2006. async function GetSearchList(isOnlySelected) {
  2007. resetTaskCancelFlag();
  2008. var msg = "正在获取文件...";
  2009. postSha1Messgae(createMessage(MessageType.BEGIN, msg));
  2010. var doc = document.getElementsByClassName('search-iframe')[0];
  2011. if (!doc) doc = document;
  2012. var lis = doc.querySelectorAll('.list-cell.lstc-search > .list-contents > ul > li');
  2013. if (!lis) return;
  2014. console.log(lis);
  2015. var files = new Array();
  2016. for (var li of lis) {
  2017. var fileItem = GetFileItemByliNode(li);
  2018. files.push(fileItem);
  2019. }
  2020. console.log("0: search items{0}".format(files.length));
  2021. if (isOnlySelected) {
  2022. console.log("search items onlySelected")
  2023. files = files.filter(q => q.selected);
  2024. }
  2025. console.log("1: search items{0}".format(files.length));
  2026. console.log(document.URL);
  2027. var url = new URL(document.URL);
  2028. var key = url.searchParams.get("search_value");
  2029. key = key ? key : "搜索结果";
  2030. files = files.filter(q => !q.isFolder);
  2031. msg = "获取到符合搜索的文件数:{0}".format(files.length);
  2032. postSha1Messgae(createMessage(MessageType.PROCESSING, msg));
  2033. await delay(200);
  2034. await InnerCreateSha1Links(files, key)
  2035. }
  2036. function CreateSha1ButtonForSelectedItems(element) {
  2037. if (document.getElementById('my115CreateSha1ForSelected')) return;
  2038. let div = `<div id="my115CreateSha1ForSelected" style="margin-left:20px;cursor:pointer">
  2039. <a hef="javascript=:;" class="button btn-line">
  2040. <i class="icon-operate ifol-download"></i>
  2041. <span>获取选中项的SHA1链接</span>
  2042. </a>
  2043. </div>`
  2044. element[0].insertAdjacentHTML('beforeend', div);
  2045. document.getElementById('my115CreateSha1ForSelected').addEventListener('mousedown', async e => {
  2046. e.stopPropagation();
  2047. let seletedElements=new Array();
  2048. //列表模式下:
  2049. let selectedItemsInList = document.querySelectorAll('.list-contents > ul > li')
  2050. console.log(`列表模式下,选中:${selectedItemsInList.length}`);
  2051. selectedItemsInList.forEach(ele=>seletedElements.push(ele));
  2052. //缩略图模式下:
  2053. selectedItemsInList=document.querySelectorAll('.list-thumb > ul > li')
  2054. console.log(`缩略图模式下,选中:${selectedItemsInList.length}`);
  2055. selectedItemsInList.forEach(ele=>seletedElements.push(ele));
  2056. console.log(`选中:${seletedElements.length}`);
  2057. let items = new Array();
  2058. for (let item of seletedElements) {
  2059. let sItem = GetFileItemByliNode(item);
  2060. if (sItem.selected) items.push(sItem);
  2061. }
  2062. if (items.length == 0) return;
  2063. if (items.length == 1) {
  2064. await CreateSha1Links(items[0])
  2065. } else {
  2066. await CreateSha1LinksAll(items, `${items[0].name}等${items.length}个`)
  2067. }
  2068. })
  2069. }
  2070. function AddShareButtonForSearchItem(node) {
  2071. //每一项
  2072. var lis = node[0].getElementsByTagName('li');
  2073. for (var li of lis) {
  2074. var pItem = GetFileItemByliNode(li);
  2075. var $btn = $('<div class="file-opr" style="left:200px"></div>');
  2076. $btn.appendTo(li);
  2077. }
  2078. //针对当前页面
  2079. $(".left-tvf > a.btn-upload").css("top", "10px");
  2080. if (document.getElementById('btn_selected_sha1') == null) {
  2081. var $btn_selected = $(`<a href="javascript:;" id="btn_selected_sha1" class="button btn-line" style="top:10px">
  2082. <i class="icon-operate ifo-share"></i>
  2083. <span>提取本页选中文件(不包括文件夹)</span>
  2084. <em style="display:none;" class="num-dot"></em>
  2085. </a>`);
  2086. $(".left-tvf").eq(0).append($btn_selected);
  2087. $btn_selected[0].addEventListener('click', e => {
  2088. GetSearchList(true);
  2089. });
  2090. }
  2091. if (document.getElementById('btn_all_sha1') == null) {
  2092. var $btn_all = $(`<a href="javascript:;" id="btn_all_sha1" class="button btn-line" style="top:10px">
  2093. <i class="icon-operate ifo-share"></i>
  2094. <span>提取本页所有文件(不包括文件夹)</span>
  2095. <em style="display:none;" class="num-dot"></em>
  2096. </a>`);
  2097. $(".left-tvf").eq(0).append($btn_all);
  2098. $btn_all[0].addEventListener('click', e => {
  2099. GetSearchList(false);
  2100. });
  2101. }
  2102. }
  2103. function ContinuedTask(taskJsonFileName) {
  2104. console.log("ContinuedTask");
  2105. postSha1Messgae(createMessage(MessageType.BEGIN, "正在继续任务..."));
  2106. resetTaskCancelFlag();
  2107. let reader = new FileReader();
  2108. reader.addEventListener('load', function (t) {
  2109. try {
  2110. postSha1Messgae(createMessage(MessageType.PROCESSING, "正在解析继续任务配置..."));
  2111. let taskJson = JSON.parse(t.target.result);
  2112. console.log(`${taskJson.taskType}, ${taskJson.fileName}, ${taskJson.data.length}`);
  2113. let canContinued = true;
  2114. if (taskJson.data.length > 0) {
  2115. } else {
  2116. canContinued = false;
  2117. }
  2118. if (canContinued) {
  2119. if (taskJson.taskType == TaskType.DOWNLOAD) {
  2120. postSha1Messgae(createMessage(MessageType.PROCESSING, `正在开始对【${taskJson.fileName}】继续提取...请稍等!`));
  2121. `
  2122. 提取:
  2123. let tempFile=[
  2124. f.id,f.parentID,f.name,f.size,f.paths,f.pickCode,f.sha1,f.preid,
  2125. ];
  2126. `
  2127. let allFiles = taskJson.data.map(f => {
  2128. return {
  2129. id: f[0],
  2130. parentID: f[1],
  2131. name: f[2],
  2132. size: f[3],
  2133. paths: f[4],
  2134. pickCode: f[5],
  2135. sha1: f[6],
  2136. preid: f[7],
  2137. }
  2138. });
  2139. InnerCreateSha1Links(allFiles, taskJson.fileName);
  2140. } else if (taskJson.taskType == TaskType.UPLOAD) {
  2141. postSha1Messgae(createMessage(MessageType.BEGIN4UPLOAD, "正在解析sha1链接..."));
  2142. `转化格式
  2143. 转存:
  2144. let tempFile = [
  2145. f.parentID,f.name, f.formatedName, f.size, f.sha1, f.preid,f.state
  2146. ]
  2147. `
  2148. let allFiles = taskJson.data.map(f => {
  2149. return {
  2150. id: '',
  2151. parentID: f[0],
  2152. name: f[1],
  2153. formatedName:f[2],
  2154. size: f[3],
  2155. pickCode: '',
  2156. sha1: f[4],
  2157. preid: f[5],
  2158. state:f[6]
  2159. }
  2160. });
  2161. taskJson.data=allFiles;
  2162. UploadFilesBySha1Links(null,taskJson);
  2163. }
  2164. } else {
  2165. let msg = `
  2166. 获取的继续任务:【 <b>${taskJson.fileName}</b> 】,配置有误!<br>
  2167. 可能不是正确的配置文件, 或者不适用于此版本的配置!
  2168. `;
  2169. postSha1Messgae(createMessage(MessageType.END, msg));
  2170. }
  2171. } catch (error) {
  2172. console.error(error);
  2173. }
  2174. });
  2175. reader.readAsText(taskJsonFileName);
  2176. }
  2177. /*--- waitForKeyElements(): A utility function, for Greasemonkey scripts,
  2178. that detects and handles AJAXed content.
  2179. Usage example:
  2180. waitForKeyElements ("div.comments", commentCallbackFunction);
  2181. //--- Page-specific function to do what we want when the node is found.
  2182. function commentCallbackFunction (jNode) {
  2183. jNode.text ("This comment changed by waitForKeyElements().");
  2184. }
  2185. IMPORTANT: This function requires your script to have loaded jQuery.
  2186. */
  2187. function waitForKeyElements(
  2188. selectorTxt,
  2189. /* Required: The jQuery selector string that
  2190. specifies the desired element(s).
  2191. */
  2192. actionFunction,
  2193. /* Required: The code to run when elements are
  2194. found. It is passed a jNode to the matched
  2195. element.
  2196. */
  2197. bWaitOnce,
  2198. /* Optional: If false, will continue to scan for
  2199. new elements even after the first match is
  2200. found.
  2201. */
  2202. iframeSelector
  2203. /* Optional: If set, identifies the iframe to
  2204. search.
  2205. */
  2206. ) {
  2207. var targetNodes, btargetsFound;
  2208. if (typeof iframeSelector == "undefined")
  2209. targetNodes = $(selectorTxt);
  2210. else
  2211. targetNodes = $(iframeSelector).contents()
  2212. .find(selectorTxt);
  2213. if (targetNodes && targetNodes.length > 0) {
  2214. btargetsFound = true;
  2215. /*--- Found target node(s). Go through each and act if they
  2216. are new.
  2217. */
  2218. targetNodes.each(function () {
  2219. var jThis = $(this);
  2220. var alreadyFound = jThis.data('alreadyFound') || false;
  2221. if (!alreadyFound) {
  2222. //--- Call the payload function.
  2223. var cancelFound = actionFunction(jThis);
  2224. if (cancelFound)
  2225. btargetsFound = false;
  2226. else
  2227. jThis.data('alreadyFound', true);
  2228. }
  2229. });
  2230. } else {
  2231. btargetsFound = false;
  2232. }
  2233. //--- Get the timer-control variable for this selector.
  2234. var controlObj = waitForKeyElements.controlObj || {};
  2235. var controlKey = selectorTxt.replace(/[^\w]/g, "_");
  2236. var timeControl = controlObj[controlKey];
  2237. //--- Now set or clear the timer as appropriate.
  2238. if (btargetsFound && bWaitOnce && timeControl) {
  2239. //--- The only condition where we need to clear the timer.
  2240. clearInterval(timeControl);
  2241. delete controlObj[controlKey];
  2242. } else {
  2243. //--- Set a timer, if needed.
  2244. if (!timeControl) {
  2245. timeControl = setInterval(function () {
  2246. waitForKeyElements(selectorTxt,
  2247. actionFunction,
  2248. bWaitOnce,
  2249. iframeSelector
  2250. );
  2251. },
  2252. 300
  2253. );
  2254. controlObj[controlKey] = timeControl;
  2255. }
  2256. }
  2257. waitForKeyElements.controlObj = controlObj;
  2258. }
  2259. })();