├── .gitattributes ├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── dist ├── 秒传连接提取.meta.js └── 秒传连接提取.user.js ├── doc ├── README.md ├── 关于一键秒传.md ├── 关于脚本安装.md ├── 度盘接口错误码.txt ├── 度盘防和谐相关.md ├── 支持秒传格式.md └── 秒传生成相关.md ├── homePage.md ├── package-lock.json ├── package.json ├── src ├── app.tsx ├── baidu │ ├── common │ │ ├── const.tsx │ │ ├── generatebdlinkTask.tsx │ │ └── rapiduploadTask.tsx │ ├── legacyPage │ │ └── loader.tsx │ ├── loader.tsx │ ├── newPage │ │ └── loader.tsx │ ├── sharePage │ │ └── loader.tsx │ └── syncPage │ │ └── loader.tsx ├── common │ ├── ajax.tsx │ ├── const.tsx │ ├── duParser.tsx │ ├── injectStyle.tsx │ ├── swalBase.tsx │ ├── swalConfig.tsx │ └── utils.tsx ├── components │ └── updateInfo.html ├── css │ ├── app.css │ └── app.scss └── types │ ├── css.d.ts │ ├── html.d.ts │ ├── scss.d.ts │ └── types.d.ts ├── tsconfig.json └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | custom: https://afdian.net/@mengzonefire -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .history 2 | .vscode 3 | .history 4 | node_modules 5 | dist/types 6 | sample 7 | test -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rapid-upload-userscript 2 | 3 | > 秒传链接提取脚本, 使用typescript + webpack重构 [主页](https://greasyfork.org/zh-CN/scripts/424574-%E7%A7%92%E4%BC%A0%E9%93%BE%E6%8E%A5%E6%8F%90%E5%8F%96) 4 | 5 | > 用于提取和生成百度网盘秒传链接, 详见 [脚本指南](https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/) [*备用地址*](https://xtsat.github.io/rapid-upload-userscript-doc/) 6 | 7 | > 秒传链接是一种通过模拟网盘自带秒传功能实现的文件分享方式(非官方), 其优点是可以永久保证分享有效性(在官方不限制秒传功能前提下), 且秒传链接不包含任何账号信息. 使用秒传链接转存文件并没有任何加速下载的效果. 8 | 9 | ## Usage 10 | 11 | 安装脚本可参考 [安装教程](https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/install-userscript/) [*备用地址*](https://xtsat.github.io/rapid-upload-userscript-doc/install-userscript/) 12 | 13 | 注意:此分支为dev分支, 正式版可用时请不要使用此分支的dist 14 | 15 | ## Build Setup 16 | 17 | node: 16.17.0 18 | 19 | ``` bash 20 | # install dependencies 21 | npm install 22 | 23 | # build 24 | npm run build 25 | ``` 26 | -------------------------------------------------------------------------------- /dist/秒传连接提取.meta.js: -------------------------------------------------------------------------------- 1 | // ==UserScript== 2 | // @name 秒传链接提取 3 | // @version 2.7.8 4 | // @author mengzonefire 5 | // @description 用于提取和生成百度网盘秒传链接 6 | // @homepage https://greasyfork.org/zh-CN/scripts/424574 7 | // @supportURL https://github.com/mengzonefire/rapid-upload-userscript/issues 8 | // @match *://pan.baidu.com/disk/home* 9 | // @match *://pan.baidu.com/disk/main* 10 | // @match *://pan.baidu.com/disk/synchronization* 11 | // @match *://pan.baidu.com/s/* 12 | // @match *://yun.baidu.com/disk/home* 13 | // @match *://yun.baidu.com/disk/main* 14 | // @match *://yun.baidu.com/disk/synchronization* 15 | // @match *://yun.baidu.com/s/* 16 | // @match *://wangpan.baidu.com/disk/home* 17 | // @match *://wangpan.baidu.com/disk/main* 18 | // @match *://wangpan.baidu.com/disk/synchronization* 19 | // @match *://wangpan.baidu.com/s/* 20 | // @name:en rapidupload-userscript 21 | // @license GPLv3 22 | // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABBUlEQVR4AZTTJRBUURTH4TtDwXuPdPrgbhHXiksf3CPucRNScHd3d3d3uO9bKeu7b79+fun8Q17CNHyMMUqaiPE4fEyYVjjGNKnNwQ4lpgV8lManEfwfosLHEGPU1N3ZnAv4qlT+NiQ56uPWSjKBrztUSnIaB66sY1vgxgxoMXB5NbsCB9rxcB5fN2M5/16nCFxeS6YTezpzsB1Pu/C2O7/78/99eYBYHXh+gqdHObGIK4GHgevjVIt1AgAnhvE4cGe8euoHbizgYuD2RGgx8O0RpwIPRmsmJDGqcrANd3pLo/qVr03hUlcpfSwf0/vD3JwkPdPK5/zhkOz+/f1FIDv/RcnOAEjywH/DhgADAAAAAElFTkSuQmCC 23 | // @namespace moe.cangku.mengzonefire 24 | // @homepageURL https://greasyfork.org/zh-CN/scripts/424574 25 | // @contributionURL https://afdian.net/@mengzonefire 26 | // @description:en input bdlink to get files or get bdlink for Baidu™ WebDisk. 27 | // @compatible firefox Violentmonkey 28 | // @compatible firefox Tampermonkey 29 | // @compatible chrome Violentmonkey 30 | // @compatible chrome Tampermonkey 31 | // @compatible edge Violentmonkey 32 | // @compatible edge Tampermonkey 33 | // @grant GM_setValue 34 | // @grant GM_getValue 35 | // @grant GM_deleteValue 36 | // @grant GM_setClipboard 37 | // @grant GM_addStyle 38 | // @grant GM_xmlhttpRequest 39 | // @grant GM_registerMenuCommand 40 | // @grant unsafeWindow 41 | // @run-at document-body 42 | // @connect baidu.com 43 | // @connect baidupcs.com 44 | // @connect cdn.jsdelivr.net 45 | // @connect * 46 | // @downloadURL https://greasyfork.org/scripts/424574/code/%E7%A7%92%E4%BC%A0%E9%93%BE%E6%8E%A5%E6%8F%90%E5%8F%96.user.js 47 | // @updateURL https://greasyfork.org/scripts/424574/code/%E7%A7%92%E4%BC%A0%E9%93%BE%E6%8E%A5%E6%8F%90%E5%8F%96.user.js 48 | // @antifeature referral-link 23.4.5: 加了一个百度官方的网盘会员推广 (从那里开通可使作者获得佣金), 觉得碍眼可以点 "不再显示" 永久隐藏 49 | // ==/UserScript== 50 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # rapid-upload-userscript-doc 2 | 3 | 此目录存放项目相关文档的markdown版本备档 4 | 5 | 目录下的所有文档均遵循 [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.zh) 协议 6 | 7 | - 文档开发已迁移到 [秒传文档v2](https://github.com/XTsat/rapid-upload-userscript-doc), 此目录下的markdown版本不会再继续更新, 故可能会存在过时内容 8 | 9 | 浏览用文档页: [载点1](https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/) [载点2](https://xtsat.github.io/rapid-upload-userscript-doc/) 10 | -------------------------------------------------------------------------------- /doc/关于一键秒传.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: "/about-bdlink" 3 | title: "一键秒传相关" 4 | --- 5 | 6 | 为了使秒传能像传统分享链接一样 (例如[https://pan.baidu.com/s/xxxxx](https://pan.baidu.com/s/xxxxx)), 实现单次点击即可跳转到网盘页面转存 7 | 8 | 秒传脚本自带了转存和生成 "**一键秒传**" 的功能: 9 | 10 | 1. 使用版本≥2.3.0的秒传脚本 ([脚本发布页](https://greasyfork.org/zh-CN/scripts/424574)), 点击生成秒传, 完成后点击 "**复制一键秒传**" 11 | 12 | ![](https://pic.rmb.bdstatic.com/bjh/bc4ce0e00904a2481577adb4249ef5a9.png) 13 | 14 | 2. 得到类似[https://pan.baidu.com/#bdlink=xxxxx](https://pan.baidu.com/#bdlink=ZDVhYWJlZmMzMjkwZjdhM2MwOTkxMjIyOGIxMzZkMGMjODIxYTlmMGQyN2ZjZDE5YzgwNDc0ZDIxNDBlZDJkODUjNjQ2NzY1OSMvdGVzdC5leGU=)的一串url链接, 即可像使用普通链接一样, 跳转到网盘页面直接转存 (使用该链接**同样需要**安装最新版秒传脚本) 15 | 16 | *使用已安装脚本的浏览器, 点击链接, 跳转到网盘页面, 自动弹出转存窗口并填充秒传链接: 17 | 18 | ![](https://pic.rmb.bdstatic.com/bjh/d90372a4c6192aaf186d9b544d220251.png) 19 | 20 | -------------------------------------------------------------------------------- /doc/关于脚本安装.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: "/install-userscript" 3 | title: "秒传脚本安装教程" 4 | --- 5 | 6 | 此文档提供 Win/安卓/MacOS 平台下的完整安装流程 7 | 8 | \*其他平台和**无法安装脚本**的用户可尝试使用 [秒传网页版](https://rapidacg.gmgard.moe/) 9 | 10 | \*教程仅为参考, 实际安装方案并不唯一 11 | 12 | 22.6.3 更新: 尽可能去除提供的软件下载链接, 改为对应官方发布地址 13 | 14 | --- 15 | 16 | ## Windows端 17 | 18 | ### 安装浏览器 19 | 20 | 安装下方**任意一个**浏览器, 该浏览器在下文称为 **A浏览器**: 21 | 22 | * [Edge](https://www.microsoft.com/zh-cn/edge) 23 | 24 | * [FireFox](https://www.mozilla.org/zh-CN/firefox/new/) 25 | 26 | * [Chrome](https://www.google.cn/chrome/) 27 | 28 | ### 安装 Tampermonkey 油猴插件 29 | 30 | 使用 **A浏览器** 访问下方的商店页面, 并安装插件 31 | 32 | * **Edge** -> [微软商店](https://microsoftedge.microsoft.com/addons/detail/tampermonkey/iikmkjmpaadaobahmlepeloendndfphd) 33 | 34 | * **FireFox** -> [火狐商店](https://addons.mozilla.org/zh-CN/firefox/addon/tampermonkey/) 35 | 36 | * **Chrome** -> [谷歌商店](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) (**可能无法访问**) 37 | 38 | ### 安装脚本 39 | 40 | - 使用 **A浏览器** 访问 [脚本页](https://greasyfork.org/zh-CN/scripts/424574) 点击 "安装此脚本"([图例1](https://pic.rmb.bdstatic.com/bjh/a6f3f140754b8e8bdeaae39992749d1e.png)) (若弹出**下载或代码页**, 请检查上一步是否正确完成), 正确的安装界面如图例所示: [图例2](https://pic.rmb.bdstatic.com/bjh/9d3d54e9dbcdb5ce9db25a9d8ee12dfe.jpeg) 41 | 42 | ### 使用脚本 43 | 44 | - 使用 **A浏览器** 访问 [百度网盘](https://pan.baidu.com/) 即可看到秒传按钮: [新版界面图例](https://pic.rmb.bdstatic.com/bjh/f0cd38fd5bf474a1ca73afe5ac767ebf.png) [旧版界面图例](https://pic.rmb.bdstatic.com/bjh/1cb5384f4b7cd3fc5a07b42ef45bfe93.png) 45 | 46 | --- 47 | 48 | ## 安卓端 49 | 50 | ### 安装浏览器 51 | 52 | 安装Kiwi浏览器: 53 | 54 | * [谷歌商店](https://play.google.com/store/apps/details?id=com.kiwibrowser.browser) (**可能无法访问**) 55 | 56 | * 本地安装(旧版本): [蓝奏云](https://wwe.lanzoui.com/ilaSts35jwh) 57 | 58 | ### 安装 Tampermonkey 油猴插件 59 | 60 | * 在线安装: [谷歌商店](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) (**可能无法访问**) 61 | 62 | * 本地安装(旧版本): 63 | 1. 下载提供的油猴插件 crx 安装包(版本 4.13): [蓝奏云](https://wwe.lanzoui.com/iWtyfs3541g) 64 | 2. 打开 Kiwi 浏览器, 点击右上角 ┇ 按钮 [(图示 1)](https://pic.rmb.bdstatic.com/bjh/3cae4fb32add8b72e8b560e8f015c941.jpeg) , 点击 **扩展程序** 选项 [(图示 2)](https://pic.rmb.bdstatic.com/bjh/0d2710ac7721100eba72b34d519204ac.jpeg) 65 | 3. 打开右上角的 **开发者模式**, 点击 **Load(+)** 按钮, 选择第一步下载的 crx 文件 ( [图示 3](https://pic.rmb.bdstatic.com/bjh/a0d1c2edd2c8dd7bdf7da1c110768262.jpeg) ), 打开扩展页内的开关启用插件 ( [图示 4](https://pic.rmb.bdstatic.com/bjh/a27dc6a338dc75b77571a34a2204d69b.jpeg) ), 若弹出权限提示点确定 ( [图示 5](https://pic.rmb.bdstatic.com/bjh/9ea9dacc5eafb7b0b44b8a9faf9b5215.jpeg) ) 66 | 67 | ### 安装脚本 68 | 69 | - 使用 Kiwi 浏览器 访问 [脚本页](https://greasyfork.org/zh-CN/scripts/424574) 点击 "安装此脚本"([图例1](https://pic.rmb.bdstatic.com/bjh/a6f3f140754b8e8bdeaae39992749d1e.png)) (若弹出**下载或代码页**, 请检查上一步是否正确完成), 正确的安装界面如图例所示: [图例2](https://pic.rmb.bdstatic.com/bjh/9d3d54e9dbcdb5ce9db25a9d8ee12dfe.jpeg) 70 | 71 | ### 使用脚本 72 | 73 | - 使用 Kiwi 访问 [百度网盘](https://pan.baidu.com/), 并勾选 "右上角 ┇ 按钮 -> **桌面版网站**" 选项, 即可看到秒传按钮: [新版界面图例](https://pic.rmb.bdstatic.com/bjh/f0cd38fd5bf474a1ca73afe5ac767ebf.png) [旧版界面图例](https://pic.rmb.bdstatic.com/bjh/1cb5384f4b7cd3fc5a07b42ef45bfe93.png) 74 | 75 | --- 76 | 77 | ## MacOS端 78 | 79 | ### 安装浏览器 80 | 81 | 安装 [chrome浏览器](https://www.google.cn/chrome/) (脚本目前不兼容safari) 82 | 83 | ### 安装 Tampermonkey 油猴插件 84 | 85 | 使用 **chrome浏览器** 访问 [谷歌商店](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo) (**可能无法访问**), 并安装插件 86 | 87 | ### 安装脚本 88 | 89 | - 使用 **chrome浏览器** 访问 [脚本页](https://greasyfork.org/zh-CN/scripts/424574) 点击 "安装此脚本"([图例1](https://pic.rmb.bdstatic.com/bjh/a6f3f140754b8e8bdeaae39992749d1e.png)) (若弹出**下载或代码页**, 请检查上一步是否正确完成), 正确的安装界面如图例所示: [图例2](https://pic.rmb.bdstatic.com/bjh/9d3d54e9dbcdb5ce9db25a9d8ee12dfe.jpeg) 90 | 91 | ### 使用脚本 92 | 93 | - 使用 **chrome浏览器** 访问 [百度网盘](https://pan.baidu.com/) 即可看到秒传按钮: [新版界面图例](https://pic.rmb.bdstatic.com/bjh/f0cd38fd5bf474a1ca73afe5ac767ebf.png) [旧版界面图例](https://pic.rmb.bdstatic.com/bjh/1cb5384f4b7cd3fc5a07b42ef45bfe93.png) -------------------------------------------------------------------------------- /doc/度盘接口错误码.txt: -------------------------------------------------------------------------------- 1 | 文件数据API错误码 2 | 3 | HTTP状态码 错误码 错误信息 备注 4 | 200 0 no error 没有错误 5 | 400 3 Unsupported open api 不支持此接口 6 | 403 4 No permission to do this operation 没有权限执行此操作 7 | 403 5 Unauthorized client IP address IP未授权 8 | 503 31001 db query error 数据库查询错误 9 | 503 31002 db connect error 数据库连接错误 10 | 503 31003 db result set is empty 数据库返回空结果 11 | 503 31021 network error 网络错误 12 | 503 31022 can not access server 暂时无法连接服务器 13 | 400 31023 param error 输入参数错误 14 | 400 31024 app id is empty app id为空 15 | 503 31025 bcs error 后端存储错误 16 | 403 31041 bduss is invalid 用户的cookie不是合法的百度cookie 17 | 403 31042 user is not login 用户未登陆 18 | 403 31043 user is not active 用户未激活 19 | 403 31044 user is not authorized 用户未授权 20 | 403 31045 user not exists 用户不存在 21 | 403 31046 user already exists 用户已经存在 22 | 400 31061 file already exists 文件已经存在 23 | 400 31062 file name is invalid 文件名非法 24 | 400 31063 file parent path does not exist 文件父目录不存在 25 | 403 31064 file is not authorized 无权访问此文件 26 | 400 31065 directory is full 目录已满 27 | 403 31066 file does not exist 文件不存在 28 | 503 31067 file deal failed 文件处理出错 29 | 503 31068 file create failed 文件创建失败 30 | 503 31069 file copy failed 文件拷贝失败 31 | 503 31070 file delete failed 文件删除失败 32 | 503 31071 get file meta failed 不能读取文件元信息 33 | 503 31072 file move failed 文件移动失败 34 | 503 31073 file rename failed 文件重命名失败 35 | 503 31081 superfile create failed superfile创建失败 36 | 503 31082 superfile block list is empty superfile 块列表为空 37 | 503 31083 superfile update failed superfile 更新失败 38 | 503 31101 tag internal error tag系统内部错误 39 | 503 31102 tag param error tag参数错误 40 | 503 31103 tag database error tag系统错误 41 | 403 31110 access denied to set quota 未授权设置此目录配额 42 | 400 31111 quota only sopport 2 level directories 配额管理只支持两级目录 43 | 400 31112 exceed quota 超出配额 44 | 403 31113 the quota is bigger than one of its parent directorys 配额不能超出目录祖先的配额 45 | 403 31114 the quota is smaller than one of its sub directorys 配额不能比子目录配额小 46 | 503 31141 thumbnail failed, internal error 请求缩略图服务失败 47 | 401 110 Access token invalid or no longer valid Access Token不正确或者已经过期 48 | 400 31201 signature error 签名错误 49 | 400 31203 acl put error 设置acl失败 50 | 400 31204 acl query error 请求acl验证失败 51 | 400 31205 acl get error 获取acl失败 52 | 404 31079 File md5 not found, you should use upload API to upload the whole file. 未找到文件MD5,请使用上传API上传整个文件。 53 | 404 31202 object not exists 文件不存在 54 | 404 31206 acl get error acl不存在 55 | 400 31207 bucket already exists bucket已存在 56 | 400 31208 bad request 用户请求错误 57 | 500 31209 baidubs internal error 服务器错误 58 | 501 31210 not implement 服务器不支持 59 | 403 31211 access denied 禁止访问 60 | 503 31212 service unavailable 服务不可用 61 | 503 31213 service unavailable 重试出错 62 | 503 31214 put object data error 上传文件data失败 63 | 503 31215 put object meta error 上传文件meta失败 64 | 503 31216 get object data error 下载文件data失败 65 | 503 31217 get object meta error 下载文件meta失败 66 | 403 31218 storage exceed limit 容量超出限额 67 | 403 31219 request exceed limit 请求数超出限额 68 | 403 31220 transfer exceed limit 流量超出限额 69 | 500 31298 the value of KEY[VALUE] in pcs response headers is invalid 服务器返回值KEY非法 70 | 500 31299 no KEY in pcs response headers 服务器返回值KEY不存在 71 | 72 | BNDSDK_ERROR(-1), 73 | 3. BNDSDK_SUCCESS(0), 74 | 4. UNKNOWN_ERROR(1), 75 | 5. TASK_ERR_TIMEOUT(19), 76 | 6. TASK_ERR_DISK_SPACE(20), 77 | 7. TASK_ERR_FILE(21), 78 | 8. TASK_ERR_CHECKSUM(22), 79 | 9. TASK_ERR_SOURCE_FAIL(23), 80 | 10. TASK_ERR_RENAME_FAIL(24), 81 | 11. TASK_ERR_FILESYSTEM_INCAPABLE(25), 82 | 12. TASK_ERR_ALREADY_EXIST(26), 83 | 13. TASK_ERR_PCS_FAIL(27), 84 | 14. TASK_ERR_PCS_BDUSS_INVALID(28), 85 | 15. TASK_ERR_PCS_USER_UNLOGIN(29), 86 | 16. TASK_ERR_PCS_USER_UNAUTHORIZED(30), 87 | 17. TASK_ERR_PCS_USER_UNEXIST(31), 88 | 18. TASK_ERR_PCS_REQUEST_LINK_EXPIRED(32), 89 | 19. TASK_ERR_PCS_FILE_NOT_EXIST(33), 90 | 20. TASK_ERR_PCS_FILE_NOT_MATCH(34), 91 | 21. TASK_ERR_PCS_FILE_ILLEGAL(35), 92 | 22. TASK_ERR_PCS_FILE_INCOMPLETE(36), 93 | 23. TASK_ERR_PCS_AUTHORIZED_ERR(37), 94 | 24. TASK_ERR_OLD_FS_ADD_FILE_FAILED(38), 95 | 25. TASK_ERR_DLINK_ERROR(39), 96 | 26. TASK_ERR_FILE_METAS_CHANGED(40), 97 | 27. TASK_ERR_FS_ADD_FILE_FAILED(41), 98 | 28. TASK_ERR_M3U8_FAILED(42), 99 | 29. TASK_ERR_M3U8_RW_FAILED(43), 100 | 30. TASK_ERR_M3U8_PARSE_FAILED(44), 101 | 31. TASK_ERR_ADD_CHECKSUM_FAILED(45), 102 | 32. TASK_ERR_DLINK_REFRESH_ERROR(46), 103 | 33. TASK_ERR_OPEN_FAILED(47), 104 | 34. TASK_ERR_M3U8_SLICE_CHANGED(48), 105 | 35. TASK_ERR_TS_URL_FAIL(49), 106 | 36. TASK_ERR_PCS_HIT_ANTI_HOTLINKING(50), 107 | 37. TASK_ERR_PCS_HOTLINKING_FORBIDDEN(51), 108 | 38. TASK_EER_PCS_HIT_ANTI_RAND_ERROR(52), 109 | 39. TASK_ERR_STREAMING_NOT_INTEGRITY(53), 110 | 40. TASK_ERR_STREAMING_CONVERT_FAILED(54), 111 | 41. TASK_ERR_STREAMING_DURATION_TOO_LONG(55), 112 | 42. TASK_ERR_STREAMING_TS_CLEAN_UP(56), 113 | 43. TASK_ERR_STREAMING_VIDEO_NOT_SUPPORT(57), 114 | 44. TASK_ERR_STREAMING_CODE_RATE_NOT_SUPPORT(58), 115 | 45. TASK_ERR_STREAMING_FILE_NOT_VIDEO(59), 116 | 46. TASK_ERR_STREAMING_OTHER_ERROR(60), 117 | 47. TASK_ERR_PCS_OPERATE_NOT_ALLOWED(61), 118 | 48. TASK_ERR_PCS_PARAM_ERROR(62), 119 | 49. TASK_ERR_PCS_FORMAT_NOT_SUPPORT(63), 120 | 50. TASK_ERR_PCS_SIGN_ERROR(64), 121 | 51. TASK_ERR_STREAMING_API_PARAM_ERROR(65), 122 | 52. TASK_ERR_STREAMING_API_SAFEBOX_STOKEN_INVALID(66), 123 | 53. TASK_ERR_STREAMING_API_ADVERTISMENT(67), 124 | 54. TASK_ERR_STREAMING_PLAY_NO_AUTHORITY(68), 125 | 55. TASK_ERR_STREAMING_SERVER_INTERNAL_ERROR(69), 126 | 56. TASK_ERR_STREAMING_NO_FSID(70), 127 | 57. TASK_ERR_STREAMING_FILE_NOT_EXIST(71), 128 | 58. TASK_ERR_STREAMING_USER_NO_PERMISSION(72), 129 | 59. TASK_ERR_STREAMING_PCS_RETURN_406(73), 130 | 60. TASK_ERR_STREAMING_MBOX_GROUP_NOT_EXIST(74), 131 | 61. TASK_ERR_STREAMING_MBOX_USER_NOT_IN_GROUP(75), 132 | 62. TASK_ERR_STREAMING_MBOX_SHARE_NOT_EXIST(76), 133 | 63. TASK_ERR_STREAMING_MBOX_SHARE_USER_NO_PERMISSION(77), 134 | 64. TASK_ERR_STREAMING_PCS_FREQUENCY_ERROR(78), 135 | 65. TASK_ERR_STREAMING_QUERY_TIMEOUT(79), 136 | 66. TASK_ERR_STREAMING_QUERY_ERROR_DATA(80), 137 | 67. TASK_EER_PCS_HIT_CONCURRENT_TOO_MANY(81), 138 | 68. TASK_EER_GATEWAY_PASSPORT_ERROR(82), 139 | 69. TASK_EER_GATEWAY_RAND_PARAM_ERROR(83), 140 | 70. TASK_EER_SHARE_FILE_NO_DLINK_INFO(84), 141 | 71. PEER_MSG_TIMEOUT(85), 142 | 72. EXCEED_MAX_REQUEST_INTERVAL(86), 143 | 73. NORMAL_PEER_HANDSHAKE_TIMEOUT(87), 144 | 74. QUERY_APAAS_META_DLINK_FAILED(88), 145 | 75. TASK_ERR_TOO_MANY_TASKS(89), 146 | 76. SERVER_PROXY_QUERY_ERROR(90), 147 | 77. SERVER_PROXY_QUERY_ERROR_TIMEOUT(91), 148 | 78. SERVER_PROXY_QUERY_ERROR_DATA(92), 149 | 79. SERVER_PROXY_QUERY_BDUSS_ERROR(93), 150 | 80. SERVER_PROXY_QUERY_PARAM_ERROR(94), 151 | 81. SERVER_ACTIVE_CLOSE(138), 152 | 82. DELAY_SERVER_ACTIVE_CLOSE(139), 153 | 83. PEER_REQUEST_TIMEOUT(140), 154 | 84. READ_FILE_PIECE_DATA_ERROR(141), 155 | 85. FILE_NOT_EXIST(142), 156 | 86. PUNCH_REQUEST_TIMEOUT(143), 157 | 87. CHOKE_PEER(144), 158 | 88. LOG_UPLOAD_FAIL(145), 159 | 89. HTTP_STATUS_ERROR(146), 160 | 90. BLOCK_CHECKSUM_ERROR(147), 161 | 91. HANDSHEAKE_FGID_ERROR(148), 162 | 92. PCS_ERROR(149), 163 | 93. TOO_MUCH_LINK(150), 164 | 94. DECRYPT_FAILED(151), 165 | 95. HTTP_PEER_REQUEST_TIMEOUT(152), 166 | 96. ZERO_SPEED(153), 167 | 97. FILE_PADDING(154), 168 | 98. TASK_ALLOC_BLOCK_MEMORY_FAIL(155), 169 | 99. HTTP_CHOKE_PEER(156), 170 | 100. LOCATEDOWNLOAD_TIMEOUT(157), 171 | 101. HTTP_ACTIVE_CLOSE(158), 172 | 102. READ_FILE_PARAM_ERROR(159), 173 | 103. DATA_MISSING(160), 174 | 104. P2P_DECODE_ERROR(161), 175 | 105. TASK_ERR_DLINK_REFRESH_ERROR_EMPTY(162), 176 | 106. TASK_ERR_DLINK_REFRESH_ERROR_API(163), 177 | 107. TASK_DB_CHECKSUM_EMPTY(164), 178 | 108. PROCESS_COMMUNICATE_ERROR_ON_CREATE_TASK(165), 179 | 109. TASK_ERR_GET_DISK_SPARE_SIZE(166), 180 | 110. FF_TIMEOUT(200), 181 | 111. HTTP_NOT_FOUND(201), 182 | 112. RECV_HTTPS_URL(202), 183 | 113. SQL_FATAL_UNKNOWN(300), 184 | 114. SQL_RECORD_EXIST(301), 185 | 115. SQL_FATAL_LOCAL_PATH_EXIST(302), 186 | 116. SQL_FATAL_RECORD_NOT_EXIST(304), 187 | 117. SQL_FATAL_MORE_THAN_ONE_RECORDS(305), 188 | 118. SQL_FATAL_RECORD_NOT_MATCH(306), 189 | 119. SQL_FATAL_NO_COLUMN(307), 190 | 120. HTTP_DNS_REQUEST_TIMEOUT(401), 191 | 121. CREATE_DIR_ERROR(501), 192 | 122. DOWNLOAD_DATA_TIMEOUT(2001), 193 | 123. QUERY_DETECT_URL_TIMEOUT(2002), 194 | 124. QUERY_NO_URLS(2003), 195 | 125. NO_USABLE_URLS(2004), 196 | 126. PARSE_FIELD_ERROR(1000), 197 | 127. PARSE_INT_VALUE_ERROR(1001), 198 | 128. TASK_NOT_EXIST(1002), 199 | 129. TIMEOUT_ERROR(1003), 200 | 130. BNDSDK_NOTINIT(1004), 201 | 131. BNDSDK_LOADFAIL(1005), 202 | 132. BNDSDK_BADID(1006), 203 | 133. UNRESOLVED_ERROR(1007); -------------------------------------------------------------------------------- /doc/度盘防和谐相关.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: "/file-protect" 3 | title: "度盘防和谐相关" 4 | --- 5 | 6 | - 本文档不定时更新, 最后更新时间: **21.11.25** 7 | 8 | # 前言 9 | 10 | 由于旧版脚本 1.6.7 版本中的 修复下载 功能 已在 21 年 4 月上旬失效(官方封杀), 目前已经没有任何硬性的反和谐\*手段, 只能通过以往总结的一些软性手段实现防和谐. 11 | 12 | \* **和谐** 定义为 文件无法下载, 下载提示 **包含违规... / 下载失败1252017** 13 | 14 | 此文档用于记录已知的度盘和谐机制及解决方法, 可尽量分享给有需要的人. 15 | 16 | --- 17 | 18 | # 已知和谐机制&对策 19 | 20 | ## 在线解压导致的文件和谐: 21 | 22 | ### 机制: 23 | 24 | 已知在使用度盘的 "在线解压" 功能时, 会记录压缩包中的文件, 若包含已和谐的媒体文件(视频/图片等), 就会和谐压缩包文件. 25 | 26 | \* 此机制已验证, 验证过程见下方 **双压防和谐的对照验证** 27 | 28 | \* 通过此机制和谐的文件(仅限压缩文件), 使用网盘 **在线解压** 功能提取压缩包内的所有文件, 将至少有 1 个文件是和谐文件. 29 | 30 | ### 对策: 31 | 32 | 通过 "双层压缩"(详见下章) 规避 33 | 34 | --- 35 | 36 | ## 敏感账号分享导致的文件和谐 37 | 38 | #### 机制: 39 | 40 | 文件分享者的账号在达到一定的分享量&举报量后, 可能被标记为敏感账号, 敏感账号使用分享链分享的文件, 在达到一定的访问量(转存&下载, 数值大致为 50-100 范围)之后, 文件自动被和谐, 但使用秒传分享不受此机制影响(秒传不涉及传统的分享过程). 41 | 42 | \*此机制未经过实际验证, 仅为分析大量现象后得出的结论, 也无法明确判断账号是否为敏感 43 | 44 | ### 对策: 45 | 46 | 不使用分享链接的方式分享文件, 但无法排除&防止其他人使用分享链接分享该文件 47 | 48 | \*被此机制和谐的压缩文件, 可尝试通过 "在线解压" 提取压缩包内的文件, 大概率可以完整提取所有文件且均未和谐. 49 | 50 | --- 51 | 52 | ## 手动举报导致的文件和谐 53 | 54 | ### 机制: 55 | 56 | 使用分享链接分享文件后, 通过分享链接页面的举报按钮举报, 可能导致文件被和谐 57 | 58 | \*此机制未经过实际验证, 考虑到度盘的文件数量, 很难认为官方通过人工审查举报的文件, 猜测是举报到一定次数(一个账号只能举报同文件一次), 自动和谐文件 59 | 60 | ### 对策: 61 | 62 | 不使用分享链接的方式分享文件, 但无法排除&防止其他人使用分享链接分享该文件 63 | 64 | \*简单的道理: 不开分享链接就没有举报按钮 65 | 66 | \*被此机制和谐的压缩文件, 可尝试通过 "在线解压" 提取压缩包内的文件, 大概率可以完整提取所有文件且均未和谐. 67 | 68 | --- 69 | 70 | # 双层压缩 71 | 72 | 使用任意压缩格式将原压缩包再压缩一次, 经过测试发现可以有效防和谐, 双层压缩的压缩包在线解压后只有内层压缩包会被和谐, 而外层压缩不会被和谐(验证过程见下文). 73 | 74 | PS: 提供一个一键批量双层压缩的工具 (使用秒传转存): 75 | 76 | ```plain 77 | f2c3e6a533c9fc4e78293d082bbd5274#9804e9c75762a21f971ad8e9bc5ed576#15352276#auto_double_zip 批量双层压缩工具 v1.0.1.zip 78 | ``` 79 | 80 | \*工具源码: [项目主页](https://github.com/mengzonefire/auto_double_zip) 81 | 82 | 双压防和谐的对照验证过程: 83 | 84 | 1 组: 直接上传已和谐的视频文件 -> 文件和谐(无法下载) 85 | 86 | 2 组: 将视频文件压缩为 无加密zip -> 上传 -> 分享 -> 在线解压 -> 压缩包被和谐(无法下载) 87 | 88 | 3 组: 将 2 组的 zip 文件再压缩一次(无加密zip) -> 上传 -> 分享 -> 在线解压 -> 解压出来的内层 zip 被和谐, 但原压缩包未和谐. 89 | 90 | \*测试时间 2021.6.7, 使用度盘 PC 客户端测试 91 | 92 | 综上可知双层压缩(任意压缩格式, 甚至无加密zip) 可有效防止在线解压导致的文件和谐, 猜测原理为在线解压只扫描压缩包内的媒体文件而不扫描其他文件(例如压缩文件). 93 | 94 | 但手动举报导致的和谐目前还是无解. 95 | 96 | 97 | -------------------------------------------------------------------------------- /doc/支持秒传格式.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: "/format-support" 3 | date: "2021-11-09" 4 | title: "支持秒传格式" 5 | --- 6 | 7 | - 梦姬标准/标准码: 8 | 9 | ```plain 10 | 格式: [md5]#[md5s(可省略)]#[文件大小(byte)]#[文件名] (md5和md5s是字母数字组成的32个字符) 11 | 示例: 12 | D5AABEFC3290F7A3C09912228B136D0C#821A9F0D27FCD19C80474D2140ED2D85#6467659#test.exe 13 | 或 14 | d5aabefc3290f7a3c09912228b136d0c#821a9f0d27fcd19c80474d2140ed2d85#6467659#test.exe 15 | 或 16 | d5aabefc3290f7a3c09912228b136d0c#6467659#test.exe 17 | ``` 18 | 19 | - PanDL 格式: 20 | 21 | ```plain 22 | bdpan://dGVzdC5leGV8NjQ2NzY1OXxENUFBQkVGQzMyOTBGN0EzQzA5OTEyMjI4QjEzNkQwQ3w4MjFBOUYwRDI3RkNEMTlDODA0NzREMjE0MEVEMkQ4NQ== 23 | ``` 24 | 25 | - PCS-GO 格式: 26 | 27 | ```plain 28 | BaiduPCS-Go rapidupload -length=6467659 -md5=D5AABEFC3290F7A3C09912228B136D0C -slicemd5=821A9F0D27FCD19C80474D2140ED2D85 "/test.exe" 29 | ``` 30 | 31 | - 游侠格式(BDLINK......): 32 | 33 | ```plain 34 | BDLINKQkRGUwAHAAAA0/AgXQEAAABvU6INa3SryWsF1pGpw7ALjjjB7lz4B3zYkhccg7C38ToAAABXAG8AcgBsAGQALgBXAGEAcgAuAFoALgAyADAAMQAzAC4AVQBuAHIAYQB0AGUAZAAuAEMAdQB0 35 | ``` 36 | 37 | - 一键秒传链接(https://pan.baidu.com/#bdlink=......): 38 | 39 | \* 秒传脚本≥2.3.5 秒传网页版≥0.9 支持输入(输入转存窗口后会自动转换为上述的其他格式) 40 | 41 | ```plain 42 | https://pan.baidu.com/#bdlink=ZDVhYWJlZmMzMjkwZjdhM2MwOTkxMjIyOGIxMzZkMGMjODIxYTlmMGQyN2ZjZDE5YzgwNDc0ZDIxNDBlZDJkODUjNjQ2NzY1OSMvdGVzdC5leGU= 43 | ``` -------------------------------------------------------------------------------- /doc/秒传生成相关.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: "/generate-bdcode" 3 | title: "秒传链接生成教程" 4 | --- 5 | 6 | 秒传脚本自带 **生成秒传链接** 的功能, 此文档用于帮助用户解决相关问题. 7 | 8 | - 本文档不定时更新, 最后更新时间: **22.6.30** 9 | 10 | --- 11 | 12 | ## 常见错误码及解决方法 13 | 14 | ### 认证失败(#-6) 15 | 16 | 1. 若使用的浏览器为safari, 请改用mac版chrome(可参考 [脚本主页](https://greasyfork.org/zh-CN/scripts/424574) 提供的安装教程), 脚本目前**不兼容**safari 17 | 2. 若使用的浏览器为firefox(火狐), 且使用的油猴插件为Tampermonkey, 请尝试更换为 [Violentmonkey](https://addons.mozilla.org/zh-CN/firefox/addon/violentmonkey/)(暴力猴)再安装脚本 18 | 3. 尝试 刷新页面 或 重新登录度盘账号, 若无法解决请前往 [反馈页](https://greasyfork.org/zh-CN/scripts/424574/feedback) 反馈: 1.浏览器版本 2.油猴插件版本 3.出现问题时按F12->打开控制台(console)->截图 19 | 20 | ### 请求失败(#514) 21 | 22 | 1. 若生成时弹出**跨域提示**, 请选择允许: [图例](https://pic.rmb.bdstatic.com/bjh/763ff5014cca49237cb3ede92b5b7ac5.png) 23 | 2. 若生成时使用了网络代理工具, 请关闭代理工具再尝试生成 24 | 3. 尝试更新油猴插件到最新版本: [微软商店](https://microsoftedge.microsoft.com/addons/detail/tampermonkey/iikmkjmpaadaobahmlepeloendndfphd) [火狐商店](https://addons.mozilla.org/zh-CN/firefox/addon/tampermonkey/) [谷歌商店](https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo)(**可能无法访问**) 25 | 26 | --- 27 | 28 | ### 接口限制访问(#403) 29 | 30 | 一般是账号问题, 可能是生成秒传过于频繁等各种原因导致的, 一般等待 24小时 即可解除, 也可尝试 更换账号 或 使用本地生成工具 [蓝奏云](https://wwe.lanzoui.com/b01u0yqvi) 密码:2233 31 | 32 | \* 百度接口不稳定也可能出现该问题, 可以手动重试几次 33 | 34 | --- 35 | 36 | ### 服务器错误(#502/#503) 37 | 38 | 一般是百度服务器暂时问题, 可使用本地生成工具 [蓝奏云](https://wwe.lanzoui.com/b01u0yqvi) 密码:2233 或 1-24小时 之后再试, 若依旧出现请前往 [反馈页](https://greasyfork.org/zh-CN/scripts/424574/feedback) 反馈 39 | 40 | --- 41 | 42 | ### 服务器错误(#500) 43 | 44 | 使用的账号被限制, 无法生成 3.9-4G 以上的文件 45 | 46 | 可使用本地生成工具 [蓝奏云](https://wwe.lanzoui.com/b01u0yqvi) 密码:2233 生成秒传, 或 更换账号/开通svip 即可解决 47 | 48 | --- 49 | 50 | ### md5 获取失败(#996) 51 | 52 | 1. 更新脚本到最新版本, 再尝试生成, 更新地址: [脚本页](https://greasyfork.org/zh-CN/scripts/424574) 53 | 2. IDM 拦截下载导致 "md5 获取失败", 解决方法: [图例 1](https://pic.rmb.bdstatic.com/bjh/df3eb220a36cd4d4de8995b6040511fd.png) , [图例 2](https://pic.rmb.bdstatic.com/bjh/d7959c6b10a1207fcbf53ee30666e929.png) 54 | 3. 迅雷 拦截下载导致 "md5 获取失败", 解决方法: 迅雷设置 -> [图例](https://pic.rmb.bdstatic.com/bjh/188178d196b485f54cd0959d81a0afbf.png) , 被其他下载工具拦截时同理 55 | 4. (推荐) 通过 本地生成工具 [蓝奏云](https://wwe.lanzoui.com/b01u0yqvi) 密码:2233 生成秒传, 并手动转存测试秒传有效性 (注意将转存成功的文件覆盖到原文件以防止删除转存文件后秒传失效) 56 | 57 | --- 58 | 59 | ### 秒传未生效(#404/#31190) 60 | 61 | #### 秒传转存者 62 | 63 | 1. 更新脚本到最新版本, 再尝试转存, 更新地址: [脚本页](https://greasyfork.org/zh-CN/scripts/424574) 64 | 2. 见下方 **秒传分享者** -> 2. & 5. 65 | 3. 将下方 **秒传分享者** 部分反馈给分享者 66 | 67 | #### 秒传分享者 68 | 69 | 1. (**重要**) 使用低于2.0.11版本的脚本生成秒传, 有小概率会生成错误秒传, 导致转存失败, 若出现该情况请 **更新脚本** 并 **重新生成** 70 | 2. 秒传可能延迟生效, 可等待一段时间(1-24 小时左右)再重试, 若不想等待或等待后依旧无效, 可尝试重传(4.) 71 | 3. 删除首次秒传转存的网盘文件可能导致秒传无效, 此时恢复删除的文件即可使秒传重新生效, 强烈建议使用脚本提供的 **测试秒传** 功能, 即可预防此情况. 72 | 4. 使用 度盘网页端 / 度盘客户端 重传文件, 再尝试转存 73 | 5. (**重要**) 标准码格式的秒传链接可以简化, 例如: 74 | ```plain 75 | D5AABEFC3290F7A3C09912228B136D0C#821A9F0D27FCD19C80474D2140ED2D85#6467659#test.exe 76 | ``` 77 | 可以简化为 (删除第二段md5, 可以正常转存): 78 | ```plain 79 | D5AABEFC3290F7A3C09912228B136D0C#6467659#test.exe 80 | ``` 81 | 但不能简化为 (删除第一段md5, 会导致上述报错, 无法转存): 82 | ```plain 83 | 821A9F0D27FCD19C80474D2140ED2D85#6467659#test.exe 84 | ``` 85 | --- 86 | 87 | ### 文件和谐 88 | 89 | 生成秒传提示如下弹窗, 或下载文件时提示 **包含违规... / 下载失败1252017**, 即文件被和谐, 不允许下载 (压缩包文件, 可尝试网盘的 **在线解压(云解压)** 功能获取部分可下载的文件) 90 | 91 | 文件被和谐 1: 92 | 93 | ![图例1](https://pic.rmb.bdstatic.com/bjh/ca690a39f6668dcaa38b0a01ddf78e20.png) 94 | ![图例2](https://pic.rmb.bdstatic.com/bjh/95b6be9e217d7270fb34076cc0fa6695.png) 95 | 96 | 文件被和谐 2: 97 | 98 | ![图例3](https://pic.rmb.bdstatic.com/bjh/3c182fdbccab1eec22ebc9ee91a40573.png) 99 | 100 | #### 预防方法 101 | 102 | 1. 使用 **双层压缩**, 可规避在线解压导致的和谐, 详见 **文件压缩方法** 章节 103 | 2. **不使用** "分享链接" 分享文件, 可一定程度上规避举报导致的和谐(不开分享链接就没有举报按钮), 但不排除其他人使用秒传转存文件后再开分享链接. 104 | 105 | 关于文件和谐的详细说明文档: [防和谐相关](/rapid-upload-userscript-doc/file-protect) 106 | 107 | --- 108 | 109 | ## 文件压缩方法 110 | 111 | 原压缩方法: 固实压缩+加密文件名 已无法防止在线解压, 也无法再防和谐, 目前有效方法请参考 **双层压缩**: 112 | 113 | ### 双层压缩 114 | 115 | 使用任意压缩格式将原压缩包再压缩一次, 经过测试验证可效防和谐, 双层压缩的压缩包在线解压后只有内层压缩包会被和谐, 而外层压缩包**不会被和谐**(验证过程见下文). 116 | 117 | \* 文件 "**被和谐**" 仅定义为**无法下载**, ≠ 无法分享 118 | 119 | PS: 提供一个一键批量双层压缩的工具 (使用秒传转存): 120 | 121 | ```plain 122 | f2c3e6a533c9fc4e78293d082bbd5274#9804e9c75762a21f971ad8e9bc5ed576#15352276#auto_double_zip 批量双层压缩工具 v1.0.1.zip 123 | ``` 124 | 125 | \*工具源码: [项目主页](https://github.com/mengzonefire/auto_double_zip) 126 | 127 | 双压防和谐的对照验证过程: 128 | 129 | 1 组: 直接上传已和谐的视频文件 -> 文件和谐(无法下载) 130 | 131 | 2 组: 将视频文件压缩为 无加密zip -> 上传 -> 分享 -> 在线解压 -> 压缩包被和谐(无法下载) 132 | 133 | 3 组: 将 2 组的 zip 文件再压缩一次(无加密zip) -> 上传 -> 分享 -> 在线解压 -> 解压出来的内层 zip 被和谐, 但原压缩包未和谐. 134 | 135 | \*测试时间 2021.6.7, 使用度盘 PC 客户端测试 136 | 137 | 综上可知双层压缩(任意压缩格式, 甚至无加密zip) 可有效防止在线解压导致的文件和谐, 但手动举报导致的和谐目前还是无解. 138 | 139 | --- -------------------------------------------------------------------------------- /homePage.md: -------------------------------------------------------------------------------- 1 | 若喜欢该脚本可前往 [爱发电](https://afdian.net/@mengzonefire) 支持作者 2 | 3 | ## 近期通知 4 | 5 | - 23.4.27: 23.4.25发布的 2.7.3, 2.7.4 这两个版本会生成错误的秒传, 错误秒传在文件上传者账号正常转存, 但在其他的账号会报错 秒传未生效#404 6 | - 出现此问题请更新 2.7.5 以上版本重新生成秒传 7 | - 关闭极速生成生成的完整版秒传则不受上述影响, 例如: d5aabefc3290f7a3c09912228b136d0c#821a9f0d27fcd19c80474d2140ed2d85#6467659#test.exe 8 | 9 | - 23.4.25: 转存秒传提示 #404更新2.7.4版本 (更新完**刷新一下度盘页面生效**, 若无效请**删除脚本重新安装**) 10 | 11 | - 23.3.24: 提供一个简易的分享链生成秒传的后端: [GitHub](https://github.com/mengzonefire/shareLink2bdLink) 12 | 13 | - 23.2.12: 完成了新脚本 [秒传链接提取Ultra](https://greasyfork.org/zh-CN/scripts/459862): 无需访问度盘主页, 直接转存页面上的秒传链接 14 | 15 | - 22.12.24: 从10.24开始, 疑似度盘服务端更新后未同步数据, 导致 使用旧PCS接口([PCS-GO](https://github.com/qjfoidnh/BaiduPCS-Go)等第三方客户端)上传的文件秒传全部失效(新旧文件均失效), 至今仍未恢复, 使用 官方客户端 和 官方网页端 上传的文件则不受影响 16 | - 如何恢复失效的秒传: 使用 官方客户端 / 官方网页端 重传文件即可 17 | 18 | - 21.10.16: 已将完整的秒传转存功能移植到 **秒传网页版工具**: [载点1](https://rapidacg.gmgard.moe/)(可能不是最新版) [载点2](https://mengzonefire.github.io/baidupan-rapidupload) [载点3](https://mengzonefire.code.misakanet.cn/baidupan-rapidupload) 19 | - 网页版无需安装插件, 点开即用, 支持所有平台, 推荐无法安装插件的用户使用, 工具源码托管在 [GitHub](https://github.com/mengzonefire/baidupan-rapidupload), 欢迎搭建分流 20 | 21 | ## 相关教程 22 | 23 | - 安装教程: [载点1](https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/document/Install/About) [载点2](https://xtsat.github.io/rapid-upload-userscript-doc/document/Install/About): 适用于 不能正常使用 不会安装 此脚本的用户 [Win/安卓/IOS/MAC] 24 | 25 | - 错误码文档: [载点1](https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/document/FAQ/错误代码) [载点2](https://xtsat.github.io/rapid-upload-userscript-doc/document/FAQ/错误代码): 适用于解决秒传 生成&分享 过程中遇到问题, 例如 秒传未生效 / md5获取失败 / 文件和谐 26 | 27 | ## 运行页面 28 | 29 | 脚本在如下页面运行: 30 | - 度盘新版主页: https://pan.baidu.com/disk/main 31 | - 度盘旧版主页: https://pan.baidu.com/disk/home?stayAtHome=true 32 | - 度盘同步空间页: https://pan.baidu.com/disk/synchronization# 33 | - 度盘文件分享页: https://pan.baidu.com/s/... 34 | 35 | ## 常见问题 36 | 37 | 1. 大部分国产浏览器有双内核, 使用时注意切换到 **chrome内核**, **ie内核** 下油猴插件是不运行的(会导致看不到秒传按钮) 38 | - 以 360浏览器 为例: [图例](https://p.sda1.dev/9/31e5d03209b255297cef46c6a591de18/Snipaste_2023-01-24_13-08-08.png) 39 | 40 | 2. 安装时请使用最新版本的油猴插件, 脚本不兼容版本低于4.9的油猴插件, 尽量参考上方提供的 **安装教程** 41 | 42 | 3. 若使用脚本时 秒传按钮 或 转存窗口 不显示、页面卡死无法操作 等, 尝试关闭广告拦截插件和同时运行的其他插件脚本 43 | - (**排查冲突**) 若无效再根据 **5.** 反馈 44 | 45 | 4. 下载转存的文件显示 "下载失败1252017" 等同**包含违规...**, 即文件已被和谐, 不允许下载 46 | 47 | 5. 若遇到其他问题, 请前往 [反馈页](https://greasyfork.org/zh-CN/scripts/424574/feedback) 反馈: 1.浏览器版本 2.油猴插件版本 3.出现问题时按F12->打开控制台(console)->截图 48 | 49 | ## 脚本说明 50 | 51 | - 秒传链接是一种通过模拟网盘自带秒传功能实现的文件分享方式(**非官方**), 其优点是可以**永久**保证分享有效性(在官方不限制秒传功能前提下), 且链接内不包含账号信息, 注意, 使用秒传链接分享文件**并没有**任何加速下载的效果, 且**无法取消分享** 52 | 53 | - 参考了初版秒传脚本 [仓库用度盘投稿助手](https://greasyfork.org/zh-CN/scripts/3285) 进行开发, 脚本源码托管在 [GitHub](https://github.com/mengzonefire/rapid-upload-userscript) 54 | 55 | - 支持批量提取(**换行分隔**), 支持 url 传参(**一键秒传**), 格式:`https://pan.baidu.com/#bdlink=[参数]`, [参数]为 base64 加密过的任意格式链接 (支持批量), 访问该链接后脚本会自动弹出秒传窗口, 并将[参数]base64解密, 添加到秒传输入框内 56 | 57 | - 支持新版度盘页面, 支持生成秒传, 网盘页面内选中 文件/文件夹后 即可看到秒传生成按钮 58 | 59 | ![](https://pic.rmb.bdstatic.com/bjh/f0cd38fd5bf474a1ca73afe5ac767ebf.png) 60 | 61 | ![](https://pic.rmb.bdstatic.com/bjh/1cb5384f4b7cd3fc5a07b42ef45bfe93.png) 62 | 63 | - 支持输入文件路径生成秒传, 在秒传输入框中输入gen即可进入生成页面 64 | 65 | - 支持设置主题样式, 在秒传输入框中输入set即可进入设置页面 66 | 67 | ## 常见秒传格式 68 | 69 |
70 | 点击展开 71 | 72 |
  • 梦姬标准/标准码: D5AABEFC3290F7A3C09912228B136D0C#821A9F0D27FCD19C80474D2140ED2D85#6467659#test.exe

  • PanDL格式: bdpan://dGVzdC5leGV8NjQ2NzY1OXxENUFBQkVGQzMyOTBGN0EzQzA5OTEyMjI4QjEzNkQwQ3w4MjFBOUYwRDI3RkNEMTlDODA0NzREMjE0MEVEMkQ4NQ==

  • PCS-GO格式: BaiduPCS-Go rapidupload -length=6467659 -md5=D5AABEFC3290F7A3C09912228B136D0C -slicemd5=821A9F0D27FCD19C80474D2140ED2D85 "/test.exe"

  • 游侠格式(BDLINK......): BDLINKQkRGUwAHAAAA0/AgXQEAAABvU6INa3SryWsF1pGpw7ALjjjB7lz4B3zYkhccg7C38ToAAABXAG8AcgBsAGQALgBXAGEAcgAuAFoALgAyADAAMQAzAC4AVQBuAHIAYQB0AGUAZAAuAEMAdQB0

73 | 74 |
75 | 76 | ## 待更新 77 | 78 | 1. ~~[给页面中的秒传添加一键秒传超链接](https://greasyfork.org/zh-CN/scripts/424574/discussions/127485)~~ (已完成, 见 [秒传链接提取Ultra](https://greasyfork.org/zh-CN/scripts/459862)) 79 | 80 |
81 | 已完成 [点击展开] 82 |
  1. 不少人反馈依赖加载失败, 找找更好的cdn替换unpkg(打算放弃使用cdn并内置所有依赖)(已完成)

  2. 尝试通过混合模式生成解决 “极速生成” 功能 生成部分md5错误的秒传的问题 (已完成)

  3. 尝试解决秒传转存v2接口在批量连续转存文件时出现转存结果错误的问题 (秒传正确但转存显示秒传未生效, 单独转存该文件又能正常转存) (已完成)

    • PS: “极速生成” 得到的简化版秒传只能通过v2接口转存
  4. 支持 新版度盘页面 下的 "生成秒传" 功能 (完成)
  5. 支持 阿里云盘 的秒传提取&生成 (废弃, 阿里官方限制了秒传接口)
  6. 支持 新版度盘页面 (完成)
  7. 修复设置为非默认主题时, 窗口内会出现警告标识的问题 (完成, 实际为主题包不适配旧版 sweetalert2)
  8. cdn.jsdelivr.net抽风有点严重, 尝试添加替代cdn (完成)
  9. 转存完成后的提示框添加转存成功列表(使用折叠框隐藏)(完成)
83 |
84 | 85 | ## 秒传链接的获取方式 86 | 87 | 1. 使用秒传脚本自带的生成功能, 选中文件/文件夹, 再点击 "生成秒传" 88 | 89 | 2. 网页版秒传生成工具: [载点1](https://rapidacg.gmgard.moe/gen.html) [载点2](https://mengzonefire.github.io/baidupan-rapidupload/gen.html) [载点3](https://mengzonefire.code.misakanet.cn/baidupan-rapidupload/gen.html) 90 | 91 | 3. 本地秒传生成工具: [蓝奏云](https://wwe.lanzoui.com/b01u0yqvi) 密码:2233 92 | 93 | \*需要任意账号的网盘中存有至少一份文件才能保证秒传链接的有效性 -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapidupload-userscript", 3 | "version": "2.7.8", 4 | "description": "用于提取和生成百度网盘秒传链接", 5 | "main": "app.tsx", 6 | "scripts": { 7 | "build": "webpack --config webpack.config.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/mengzonefire/rapid-upload-userscript.git" 12 | }, 13 | "author": "mengzonefire", 14 | "license": "GPLv3", 15 | "bugs": { 16 | "url": "https://github.com/mengzonefire/rapid-upload-userscript/issues" 17 | }, 18 | "homepage": "https://greasyfork.org/zh-CN/scripts/424574", 19 | "dependencies": { 20 | "js-base64": "^3.7.2", 21 | "spark-md5": "^3.0.2", 22 | "sweetalert2": "^11.7.1" 23 | }, 24 | "devDependencies": { 25 | "@types/jquery": "^3.5.6", 26 | "@types/spark-md5": "^3.0.2", 27 | "@types/tampermonkey": "^4.0.2", 28 | "css-loader": "^6.7.1", 29 | "mini-css-extract-plugin": "^2.6.0", 30 | "node-sass": "^7.0.3", 31 | "sass": "^1.49.9", 32 | "sass-loader": "^12.6.0", 33 | "text-loader": "^0.0.1", 34 | "ts-loader": "^9.2.5", 35 | "typescript": "^4.3.5", 36 | "webpack": "^5.76.0", 37 | "webpack-cli": "^4.8.0", 38 | "webpack-node-externals": "^3.0.0", 39 | "webpack-userscript": "^2.5.8" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/app.tsx: -------------------------------------------------------------------------------- 1 | import { injectStyle } from "./common/injectStyle"; 2 | import { Base64 } from "js-base64"; 3 | /** 4 | * @description: 主函数入口 5 | */ 6 | function app(): void { 7 | Base64.extendString(); 8 | injectStyle(); 9 | } 10 | 11 | // 广告拦截插件会导致脚本报错跳出, 网页卡死, 故加入异常处理 12 | try { 13 | app(); 14 | } catch (error) { 15 | console.log(error); 16 | } 17 | -------------------------------------------------------------------------------- /src/baidu/common/const.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-10-20 10:36:43 4 | * @LastEditTime: 2023-05-04 12:43:06 5 | * @LastEditors: mengzonefire 6 | * @Description: 存放各种全局常量对象 7 | */ 8 | 9 | import { doc, doc2, linkStyle } from "@/common/const"; 10 | import Swalbase from "@/common/swalBase"; 11 | import GeneratebdlinkTask from "./generatebdlinkTask"; 12 | import RapiduploadTask from "./rapiduploadTask"; 13 | 14 | const host = location.host; 15 | export const listLimit = 10000; 16 | export const syncPathPrefix = "/_pcs_.workspace"; 17 | export const retryMax_apiV2 = 4; // v2转存接口的最大重试次数 18 | export const create_url = `https://${host}/api/create`; 19 | export const precreate_url = `https://${host}/api/precreate`; 20 | export const list_url = `https://${host}/rest/2.0/xpan/multimedia?method=listall&order=name&limit=${listLimit}&path=`; 21 | export const meta_url = `https://pcs.baidu.com/rest/2.0/pcs/file?app_id=778750&method=meta&path=`; 22 | export const meta_url2 = `https://${host}/api/filemetas?dlink=1&fsids=`; 23 | export const tpl_url = `https://${host}/share/tplconfig?fields=sign,timestamp&channel=chunlei&web=1&app_id=250528&clienttype=0`; 24 | export const sharedownload_url = `https://${host}/api/sharedownload?channel=chunlei&clienttype=12&web=1&app_id=250528`; 25 | export const sharelist_url = `https://${host}/share/list?showempty=0&num=${listLimit}&channel=chunlei&web=1&app_id=250528&clienttype=0`; 26 | export const syncdownload_url = `https://${host}/api/download`; 27 | export const testPath = "/apps/生成秒传测试文件.mengzonefire"; 28 | export const pcs_url = 29 | "https://pcs.baidu.com/rest/2.0/pcs/file?app_id=778750&method=download"; 30 | export const illegalPathPattern = /[\\":*?<>|]/g; // 匹配路径中的非法字符 31 | export var getBdstoken: () => string; // 获取bdstoken的实现 32 | export function setGetBdstoken(func: () => string) { 33 | getBdstoken = func; 34 | } 35 | export var refreshList: () => void; // 刷新文件列表的实现 36 | export function setRefreshList(func: () => void) { 37 | refreshList = func; 38 | } 39 | export var getSelectedFileList: () => any; // 获取选中的文件列表的实现 40 | export function setGetSelectedFileList(func: () => any) { 41 | getSelectedFileList = func; 42 | } 43 | export const swalInstance = new Swalbase( 44 | new RapiduploadTask(), 45 | new GeneratebdlinkTask() 46 | ); 47 | 48 | export function baiduErrno(errno: number) { 49 | switch (errno) { 50 | case 31045: 51 | case -6: 52 | return `认证失败(请看文档:载点1 载点2)`; 53 | case -7: 54 | return `转存路径含有非法字符(请看文档:载点1 载点2)`; 55 | case -8: 56 | return "路径下存在同名文件"; 57 | case -9: 58 | return "验证已过期, 请刷新页面"; 59 | case 400: 60 | return `请求错误(请看文档:载点1 载点2)`; 61 | case 9019: 62 | case 403: 63 | return `接口限制访问(请看文档:载点1 载点2)`; 64 | case 404: 65 | return `秒传未生效(请看文档:载点1 载点2)`; 66 | case 114: 67 | return `转存失败-v2接口(请看文档:载点1 载点2)`; 68 | case 514: 69 | return `请求失败(请看文档:载点1 载点2)`; 70 | case 1919: 71 | return `文件已被和谐(请看文档:载点1 载点2)`; 72 | case 996: 73 | return `md5获取失败(请看文档:载点1 载点2)`; 74 | case 2: 75 | return `转存失败-v1接口(请看文档:载点1 载点2)`; 76 | case -10: 77 | return "网盘容量已满"; 78 | case 500: 79 | case 502: 80 | case 503: 81 | return `服务器错误(请看文档:载点1 载点2)`; 82 | case 31066: 83 | case 909: 84 | return "路径不存在/云端文件已损坏"; 85 | case 900: 86 | return "路径为文件夹, 不支持生成秒传"; 87 | case 31039: 88 | return `服务器错误(请看文档:载点1 载点2)`; 89 | case 110: 90 | return "请先登录百度账号"; 91 | case 9013: 92 | return "账号被限制, 尝试 更换账号 或 等待一段时间再重试"; 93 | default: 94 | return `未知错误(请看文档:载点1 载点2)`; 95 | } 96 | } // 自定义百度api返回errno的报错 97 | -------------------------------------------------------------------------------- /src/baidu/common/generatebdlinkTask.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-25 01:31:01 4 | * @LastEditTime: 2023-05-15 16:50:55 5 | * @LastEditors: mengzonefire 6 | * @Description: 百度网盘 秒传生成任务实现 7 | */ 8 | 9 | import ajax from "@/common/ajax"; 10 | import { homePage } from "@/common/const"; 11 | import { 12 | convertData, 13 | decryptMd5, 14 | getExtra, 15 | getLogid, 16 | getSurl, 17 | showAlert, 18 | } from "@/common/utils"; 19 | import { UA } from "@/common/const"; 20 | import { 21 | list_url, 22 | meta_url, 23 | meta_url2, 24 | pcs_url, 25 | tpl_url, 26 | sharedownload_url, 27 | sharelist_url, 28 | getBdstoken, 29 | listLimit, 30 | } from "./const"; 31 | // import { createFileV2 } from "./rapiduploadTask"; 32 | import SparkMD5 from "spark-md5"; 33 | import { createFileV2 } from "./rapiduploadTask"; 34 | 35 | // 普通生成: 36 | export default class GeneratebdlinkTask { 37 | isSharePage: boolean; // 分享页标记 38 | isGenView: boolean; // 生成页(秒传框输入gen)标记 39 | isFast: boolean; // 极速生成功能开关标记 40 | recursive: boolean; // 递归生成标记 41 | savePath: string; 42 | dirList: Array; 43 | selectList: Array; 44 | fileInfoList: Array; 45 | logid: string; 46 | surl: string; 47 | bdstoken: string; 48 | onFinish: (fileInfoList: Array) => void; 49 | onProcess: (i: number, fileInfoList: Array) => void; 50 | onProgress: (e: any, text?: string) => void; 51 | onHasDir: () => void; 52 | onHasNoDir: () => void; 53 | 54 | reset(): void { 55 | this.isGenView = false; 56 | this.isSharePage = false; 57 | this.isFast = 58 | GM_getValue("fast-generate") === undefined 59 | ? true 60 | : GM_getValue("fast-generate"); 61 | this.recursive = false; 62 | this.savePath = ""; 63 | this.bdstoken = getBdstoken(); // 此处bdstoken不可删除, 会在下方createFileV2方法调用 64 | this.dirList = []; 65 | this.selectList = []; 66 | this.fileInfoList = []; 67 | this.onFinish = () => {}; 68 | this.onProcess = () => {}; 69 | this.onProgress = () => {}; 70 | this.onHasDir = () => {}; 71 | this.onHasNoDir = () => {}; 72 | } 73 | 74 | /** 75 | * @description: 执行新任务的初始化步骤 扫描选择的文件列表 76 | */ 77 | start(): void { 78 | if (this.isSharePage) { 79 | this.logid = getLogid(); 80 | this.surl = getSurl(); 81 | if (!this.surl) { 82 | showAlert( 83 | `surl获取失败: ${location.href}, 请前往脚本页反馈:\n${homePage}` 84 | ); 85 | return; 86 | } 87 | this.parseShareFileList(); 88 | this.onHasNoDir(); 89 | } else { 90 | this.parseMainFileList(); 91 | if (this.dirList.length) this.onHasDir(); 92 | else this.onHasNoDir(); 93 | } 94 | } 95 | 96 | scanShareFile(i: number, page: number = 1): void { 97 | if (i >= this.dirList.length) { 98 | this.generateBdlink(0); 99 | return; 100 | } 101 | this.onProgress(false, `正在获取文件列表, 第${i + 1}个`); 102 | ajax( 103 | { 104 | url: `${sharelist_url}&dir=${encodeURIComponent( 105 | this.dirList[i] 106 | )}&logid=${this.logid}&shareid=${unsafeWindow.yunData.shareid}&uk=${ 107 | unsafeWindow.yunData.share_uk 108 | }&page=${page}`, 109 | method: "GET", 110 | responseType: "json", 111 | }, 112 | (data) => { 113 | data = data.response; 114 | if (!data.errno) { 115 | if (!data.list.length) this.scanShareFile(i + 1); 116 | // 返回列表为空, 即此文件夹文件全部扫描完成 117 | else { 118 | this.parseShareFileList(data.list); 119 | this.scanShareFile(i, page + 1); // 下一页 120 | } 121 | } else { 122 | this.fileInfoList.push({ 123 | path: this.dirList[i], 124 | isdir: 1, 125 | errno: data.errno, 126 | }); // list接口访问失败, 添加失败信息 127 | this.scanShareFile(i + 1); 128 | } 129 | }, 130 | (statusCode) => { 131 | this.fileInfoList.push({ 132 | path: this.dirList[i], 133 | isdir: 1, 134 | errno: statusCode, 135 | }); 136 | this.scanShareFile(i + 1); 137 | } 138 | ); 139 | } 140 | 141 | /** 142 | * @description: 选择的列表包含文件夹, 获取文件夹下的子文件 143 | * @param {number} i 条目index 144 | * @param {number} start 列表接口检索起点(即翻页参数) 145 | */ 146 | scanFile(i: number, start: number = 0): void { 147 | if (i >= this.dirList.length) { 148 | this.generateBdlink(0); 149 | return; 150 | } 151 | ajax( 152 | { 153 | url: `${list_url}${encodeURIComponent(this.dirList[i])}&recursion=${ 154 | this.recursive ? 1 : 0 155 | }&start=${start}`, 156 | method: "GET", 157 | responseType: "json", 158 | }, // list接口自带递归参数recursion 159 | (data) => { 160 | data = data.response; 161 | if (!data.errno) { 162 | if (!data.list.length) 163 | this.scanFile(i + 1); // 返回列表为空, 即此文件夹文件全部扫描完成 164 | else { 165 | data.list.forEach((item: any) => { 166 | item.isdir || 167 | this.fileInfoList.push({ 168 | path: item.path, 169 | size: item.size, 170 | fs_id: item.fs_id, 171 | md5: this.isFast ? decryptMd5(item.md5.toLowerCase()) : "", 172 | md5s: "", 173 | }); // 筛选文件(isdir=0) 174 | }); 175 | this.scanFile(i, start + listLimit); // 从下一个起点继续检索列表 176 | } 177 | } else { 178 | this.fileInfoList.push({ 179 | path: this.dirList[i], 180 | isdir: 1, 181 | errno: data.errno, 182 | }); // list接口访问失败, 添加失败信息 183 | this.scanFile(i + 1); 184 | } 185 | }, 186 | (statusCode) => { 187 | this.fileInfoList.push({ 188 | path: this.dirList[i], 189 | isdir: 1, 190 | errno: statusCode, 191 | }); 192 | this.scanFile(i + 1); 193 | } 194 | ); 195 | } 196 | 197 | /** 198 | * @description: 顺序执行生成任务 199 | * @param {number} i 200 | */ 201 | generateBdlink(i: number): void { 202 | // 保存任务进度数据, 分享页生成不保存 203 | if (!this.isSharePage) 204 | GM_setValue("unfinish", { 205 | file_info_list: this.fileInfoList, 206 | file_id: i, 207 | }); 208 | // 生成完成 209 | if (i >= this.fileInfoList.length) { 210 | if (this.isFast) this.checkMd5(0); // 已开启 "极速生成", 执行md5检查 211 | else this.onFinish(this.fileInfoList); 212 | return; 213 | } 214 | // 未开启 "极速生成", 刷新弹窗内的任务进度 215 | if (!this.isFast) this.onProcess(i, this.fileInfoList); 216 | let file = this.fileInfoList[i]; 217 | // 跳过扫描失败的目录路径 218 | if (file.errno && file.isdir) { 219 | this.generateBdlink(i + 1); 220 | return; 221 | } 222 | // 已开启 "极速生成" 且已获取到md5, 跳过普通生成步骤 223 | if (this.isFast && file.md5) this.generateBdlink(i + 1); 224 | // 普通生成步骤 225 | else this.isSharePage ? this.getShareDlink(i) : this.getDlink(i); 226 | } 227 | 228 | /** 229 | * @description: 获取文件信息: size, md5(可能错误), fs_id 230 | * @param {number} i 231 | */ 232 | getFileInfo(i: number): void { 233 | let file = this.fileInfoList[i]; 234 | ajax( 235 | { 236 | url: meta_url + encodeURIComponent(file.path), 237 | responseType: "json", 238 | method: "GET", 239 | }, 240 | (data) => { 241 | data = data.response; 242 | if (!data.error_code) { 243 | if (data.list[0].isdir) { 244 | console.log(1111); 245 | file.isdir = 1; 246 | file.errno = 900; 247 | this.generateBdlink(i + 1); 248 | return; 249 | } 250 | file.size = data.list[0].size; 251 | file.fs_id = data.list[0].fs_id; 252 | // 已开启极速生成, 直接取meta内的md5 253 | file.md5 = this.isFast 254 | ? decryptMd5(data.list[0].md5.toLowerCase()) 255 | : ""; 256 | file.md5s = ""; 257 | this.getDlink(i); 258 | } else { 259 | file.errno = data.error_code; 260 | this.generateBdlink(i + 1); 261 | } 262 | }, 263 | (statusCode) => { 264 | file.errno = statusCode === 404 ? 909 : statusCode; 265 | this.generateBdlink(i + 1); 266 | } 267 | ); 268 | } 269 | 270 | /** 271 | * @description: 获取分享页的文件dlink(下载直链) 272 | * @param {number} i 273 | */ 274 | getShareDlink(i: number): void { 275 | let sign: string, 276 | timestamp: number, 277 | file = this.fileInfoList[i], 278 | onFailed = (errno: number) => { 279 | file.errno = errno; 280 | this.checkMd5(i + 1); 281 | // md5为空只在分享单个文件时出现, 故无需考虑获取多文件md5(跳转generateBdlink), 直接跳转checkMd5即可 282 | }; 283 | function getTplconfig(file: FileInfo): void { 284 | ajax( 285 | { 286 | url: `${tpl_url}&surl=${this.surl}&logid=${this.logid}`, 287 | responseType: "json", 288 | method: "GET", 289 | }, 290 | (data) => { 291 | data = data.response; 292 | // 请求正常 293 | if (!data.errno) { 294 | sign = data.data.sign; 295 | timestamp = data.data.timestamp; 296 | getDlink.call(this, file); 297 | return; 298 | } 299 | // 请求报错 300 | onFailed(data.errno); 301 | }, 302 | onFailed 303 | ); 304 | } 305 | function getDlink(file: FileInfo): void { 306 | ajax( 307 | { 308 | url: `${sharedownload_url}&sign=${sign}×tamp=${timestamp}`, 309 | responseType: "json", 310 | method: "POST", 311 | data: convertData({ 312 | extra: getExtra(), 313 | logid: this.logid, 314 | fid_list: JSON.stringify([file.fs_id]), 315 | primaryid: unsafeWindow.yunData.shareid, 316 | uk: unsafeWindow.yunData.share_uk, 317 | product: "share", 318 | encrypt: 0, 319 | }), 320 | }, 321 | (data) => { 322 | data = data.response; 323 | // 请求正常 324 | if (!data.errno) { 325 | this.downloadFileData(i, data.list[0].dlink); 326 | return; 327 | } 328 | // 请求报错 329 | onFailed(data.errno); 330 | }, 331 | onFailed 332 | ); 333 | } 334 | getTplconfig.call(this, file); 335 | } 336 | 337 | /** 338 | * @description: 获取文件dlink(下载直链) 339 | * @param {number} i 340 | */ 341 | getDlink(i: number): void { 342 | let file = this.fileInfoList[i]; 343 | 344 | // 使用生成页时仅有path没有fs_id, 跳转到获取fs_id 345 | if (!file.fs_id) { 346 | this.getFileInfo(i); 347 | return; 348 | } 349 | ajax( 350 | { 351 | url: meta_url2 + JSON.stringify([String(file.fs_id)]), 352 | responseType: "json", 353 | method: "GET", 354 | headers: { "User-Agent": UA }, 355 | }, 356 | (data) => { 357 | data = data.response; 358 | // 请求正常 359 | if (!data.errno) { 360 | this.downloadFileData(i, data.info[0].dlink); 361 | return; 362 | } 363 | // 请求报错 364 | file.errno = data.errno; 365 | this.isFast ? this.checkMd5(i + 1) : this.generateBdlink(i + 1); 366 | }, 367 | (statusCode) => { 368 | file.errno = statusCode; 369 | this.isFast ? this.checkMd5(i + 1) : this.generateBdlink(i + 1); 370 | } 371 | ); 372 | } 373 | 374 | /** 375 | * @description: 调用下载直链 376 | * @param {number} i 377 | * @param {string} dlink 378 | */ 379 | downloadFileData(i: number, dlink: string): void { 380 | let dlSize: number, 381 | file = this.fileInfoList[i]; 382 | if (this.isFast) 383 | dlSize = 1; // "极速下载" 不需要生成slice-md5, 故无需下载文件数据 384 | else dlSize = file.size < 262144 ? 1 : 262143; //slice-md5: 文件前256KiB的md5, size<256KiB则直接取md5即可, 无需下载文件数据 385 | ajax( 386 | { 387 | url: dlink, 388 | method: "GET", 389 | responseType: "arraybuffer", 390 | headers: { 391 | Range: `bytes=0-${dlSize}`, 392 | "User-Agent": UA, 393 | }, 394 | onprogress: this.isFast ? () => {} : this.onProgress, 395 | }, 396 | (data) => { 397 | if (!this.isFast) this.onProgress({ loaded: 100, total: 100 }); // 100% 398 | this.parseDownloadData(i, data); 399 | }, 400 | (statusCode) => { 401 | if (statusCode === 404) file.errno = 909; 402 | else file.errno = statusCode; 403 | this.isFast ? this.checkMd5(i + 1) : this.generateBdlink(i + 1); 404 | } 405 | ); 406 | } 407 | 408 | /** 409 | * @description: 解析直链请求返回的数据 410 | * @param {number} i 411 | * @param {any} data 412 | */ 413 | parseDownloadData(i: number, data: any): void { 414 | let file = this.fileInfoList[i]; 415 | console.log(`dl_url: ${data.finalUrl}`); // debug 416 | // 下载直链重定向到此域名, 判定为文件和谐 417 | if (data.finalUrl.includes("issuecdn.baidupcs.com")) { 418 | file.errno = 1919; 419 | this.isFast ? this.checkMd5(i + 1) : this.generateBdlink(i + 1); 420 | return; 421 | } 422 | // 从下载接口获取md5, 此步骤可确保获取到正确md5 423 | let fileMd5 = data.responseHeaders.match(/content-md5: ([\da-f]{32})/i); 424 | if (fileMd5) file.md5 = fileMd5[1].toLowerCase(); 425 | else if (file.size <= 3900000000 && !file.retry_996 && !this.isSharePage) { 426 | // 默认下载接口未拿到md5, 尝试使用旧下载接口, 旧接口请求文件size大于3.9G会返回403 427 | // 分享页的生成任务不要调用旧接口 428 | file.retry_996 = true; 429 | this.downloadFileData( 430 | i, 431 | pcs_url + `&path=${encodeURIComponent(file.path)}` 432 | ); 433 | return; 434 | } else { 435 | // 两个下载接口均未拿到md5, 失败跳出 436 | file.errno = 996; 437 | this.isFast ? this.checkMd5(i + 1) : this.generateBdlink(i + 1); 438 | return; 439 | } 440 | // 获取md5s, "极速生成" 跳过此步 441 | if (!this.isFast) { 442 | if (file.size < 262144) file.md5s = file.md5; // 此时md5s=md5 443 | else { 444 | // 计算md5s 445 | let spark = new SparkMD5.ArrayBuffer(); 446 | spark.append(data.response); 447 | let sliceMd5 = spark.end(); 448 | file.md5s = sliceMd5; 449 | } 450 | let interval = this.fileInfoList.length > 1 ? 2000 : 1000; 451 | setTimeout(() => { 452 | this.generateBdlink(i + 1); 453 | }, interval); 454 | } else this.checkMd5(i + 1); 455 | } 456 | 457 | /** 458 | * @description: "极速生成" 可能得到错误md5, 故执行验证步骤, 若验证不通过则执行普通生成 459 | * @param {number} i 460 | */ 461 | checkMd5(i: number): void { 462 | if (i >= this.fileInfoList.length) { 463 | this.onFinish(this.fileInfoList); 464 | return; 465 | } 466 | let file = this.fileInfoList[i]; 467 | // 跳过扫描失败的目录路径 468 | if (file.errno && file.isdir) { 469 | this.checkMd5(i + 1); 470 | return; 471 | } 472 | this.onProcess(i, this.fileInfoList); 473 | this.onProgress(false, "极速生成中..."); 474 | // this.isSharePage ? this.getShareDlink(i) : this.getDlink(i); 475 | // 23.4.27: 错误md5在文件上传者账号使用此接口正常转存, 在其他账号则报错#404(#31190), 导致生成秒传完全无法验证, 故弃用meta内的md5 476 | // 23.5.4: 发现错误md5只要改成大写, 在上传者账号就能正常返回#31190, 而正确md5则大小写都能正常转存, 故重新启用此验证过程 477 | // 主要是因为频繁请求直链接口获取正确md5会导致#9019错误(即账号被限制), 对大批量生成秒传有很大影响, 极速生成功能使用此验证则可以节约请求以避免此问题 478 | // 23.5.15: 错误md5问题的原理: 通过网页端上传大文件(分片上传)发现, list接口的错误md5仅在上传完成后24h内有效, 且多次上传相同的文件时, 得到的错误md5也相同 479 | // 故猜测此错误md5实际对应block_list(分片md5列表), 用于在服务端计算出文件完整md5前临时代替使用 480 | createFileV2.call( 481 | this, 482 | file, 483 | (data: any) => { 484 | data = data.response; 485 | // errno=-10即网盘容量已满, 由于31190(秒传无效)的优先级高于-10, 所以验证md5时此错误可视为验证成功 486 | if ([0, -10].includes(data.errno)) this.checkMd5(i + 1); // md5验证成功 487 | else if (31190 === data.errno) { 488 | // md5验证失败, 执行普通生成, 仅在此处保存任务进度, 生成页不保存进度 489 | if (!this.isSharePage) 490 | GM_setValue("unfinish", { 491 | file_info_list: this.fileInfoList, 492 | file_id: i, 493 | isCheckMd5: true, 494 | }); 495 | this.isSharePage ? this.getShareDlink(i) : this.getDlink(i); 496 | } else { 497 | // 接口访问失败 498 | file.errno = data.errno; 499 | this.checkMd5(i + 1); 500 | } 501 | }, 502 | (statusCode: number) => { 503 | file.errno = statusCode; 504 | this.checkMd5(i + 1); 505 | }, 506 | 0, 507 | true 508 | ); 509 | } 510 | 511 | /** 512 | * @description: 用于解析度盘主页的文件列表数据 513 | */ 514 | parseMainFileList() { 515 | for (let item of this.selectList) { 516 | if (item.isdir) this.dirList.push(item.path); 517 | else 518 | this.fileInfoList.push({ 519 | path: item.path, 520 | size: item.size, 521 | fs_id: item.fs_id, 522 | // 已开启极速生成, 直接取meta内的md5 523 | md5: this.isFast ? decryptMd5(item.md5.toLowerCase()) : "", 524 | md5s: "", 525 | }); 526 | } 527 | } 528 | 529 | /** 530 | * @description: 用于解析分享页的文件列表数据 531 | */ 532 | parseShareFileList(list = this.selectList) { 533 | for (let item of list) { 534 | let path: string; 535 | if ("app_id" in item) 536 | path = item.isdir ? item.path : item.server_filename; 537 | else path = item.path; 538 | if ("/" !== path.charAt(0)) path = "/" + path; // 补齐路径开头的斜杠 539 | if (item.isdir) this.dirList.push(path); 540 | else 541 | this.fileInfoList.push({ 542 | path: path, 543 | size: item.size, 544 | fs_id: item.fs_id, 545 | md5: item.md5 && decryptMd5(item.md5.toLowerCase()), 546 | md5s: "", 547 | }); 548 | } 549 | } 550 | } 551 | -------------------------------------------------------------------------------- /src/baidu/common/rapiduploadTask.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-25 01:30:29 4 | * @LastEditTime: 2023-05-04 18:09:10 5 | * @LastEditors: mengzonefire 6 | * @Description: 百度网盘 秒传转存任务实现 7 | */ 8 | 9 | import ajax from "@/common/ajax"; 10 | import { convertData, suffixChange } from "@/common/utils"; 11 | import { 12 | retryMax_apiV2, 13 | create_url, 14 | getBdstoken, 15 | illegalPathPattern, 16 | testPath, 17 | } from "./const"; 18 | export default class RapiduploadTask { 19 | savePath: string; 20 | isDefaultPath: boolean; 21 | fileInfoList: Array; 22 | bdstoken: string; 23 | onFinish: (fileInfoList: Array) => void; 24 | onProcess: (i: number, fileInfoList: Array) => void; 25 | 26 | reset(): void { 27 | this.bdstoken = getBdstoken(); 28 | console.log(`bdstoken状态: ${this.bdstoken ? "获取成功" : "获取失败"}`); // debug 29 | this.fileInfoList = []; 30 | this.savePath = ""; 31 | this.isDefaultPath = false; 32 | this.onFinish = () => {}; 33 | this.onProcess = () => {}; 34 | } 35 | 36 | start(): void { 37 | this.saveFileV2(0); 38 | } 39 | 40 | /** 41 | * @description: 转存秒传 接口2 42 | * @param {number} i 43 | */ 44 | saveFileV2(i: number): void { 45 | if (i >= this.fileInfoList.length) { 46 | this.onFinish(this.fileInfoList); 47 | return; 48 | } 49 | this.onProcess(i, this.fileInfoList); 50 | let file = this.fileInfoList[i]; 51 | // 文件名为空 52 | if (file.path === "/") { 53 | file.errno = -7; 54 | this.saveFileV2(i + 1); 55 | return; 56 | } 57 | let onFailed = (statusCode: number) => { 58 | file.errno = statusCode; 59 | this.saveFileV2(i + 1); 60 | }; 61 | createFileV2.call( 62 | this, 63 | file, 64 | (data: any) => { 65 | data = data.response; 66 | file.errno = 2 === data.errno ? 114 : data.errno; 67 | file.errno = 31190 === file.errno ? 404 : file.errno; 68 | this.saveFileV2(i + 1); 69 | }, 70 | onFailed 71 | ); 72 | // precreateFileV2.call( 73 | // this, 74 | // file, 75 | // (data: any) => { 76 | // data = data.response; 77 | // if (0 === data.errno) { 78 | // if (0 === data.block_list.length) { 79 | // this.createFileV2( 80 | // file, 81 | // (data) => { 82 | // data = data.response; 83 | // file.errno = 2 === data.errno ? 114 : data.errno; 84 | // file.errno = 31190 === file.errno ? 404 : file.errno; 85 | // this.saveFileV2(i + 1); 86 | // }, 87 | // onFailed 88 | // ); 89 | // } else { 90 | // file.errno = 404; 91 | // this.saveFileV2(i + 1); 92 | // } 93 | // } else { 94 | // file.errno = data.errno; 95 | // this.saveFileV2(i + 1); 96 | // } 97 | // }, 98 | // onFailed 99 | // ); 100 | } 101 | } 102 | 103 | // 此接口测试结果如下: 错误md5->返回"errno": 31190, 正确md5+错误size->返回"errno": 2 104 | // 此外, 即使md5和size均正确, 连续请求时依旧有小概率返回"errno": 2, 故建议加入retry策略 105 | export function createFileV2( 106 | file: FileInfo, 107 | onResponsed: (data: any) => void, 108 | onFailed: (statusCode: number) => void, 109 | retry: number = 0, 110 | isGen: boolean = false 111 | ): void { 112 | ajax( 113 | { 114 | url: `${create_url}${this.bdstoken ? "&bdstoken=" + this.bdstoken : ""}`, // bdstoken参数不能放在data里, 否则无效 115 | method: "POST", 116 | responseType: "json", 117 | data: convertData({ 118 | block_list: JSON.stringify([ 119 | isGen ? file.md5.toUpperCase() : file.md5.toLowerCase(), 120 | ]), 121 | path: isGen 122 | ? testPath 123 | : this.savePath + file.path.replace(illegalPathPattern, "_"), 124 | size: file.size, 125 | isdir: 0, 126 | rtype: isGen ? 3 : 0, // rtype=3覆盖文件, rtype=0则返回报错, 不覆盖文件, 默认为rtype=1 (自动重命名, 1和2是两种不同的重命名策略) 127 | is_revision: isGen ? 1 : 0, // is_revision=0时, rtype=3会不生效 (会依旧返回重名报错), is_revision=1时则等同rtype=3效果 128 | }), 129 | }, 130 | (data) => { 131 | // console.log(data.response); // debug 132 | if (31039 === data.response.errno && 31039 != file.errno && !isGen) { 133 | file.errno = 31039; 134 | file.path = suffixChange(file.path); 135 | createFileV2.call(this, file, onResponsed, onFailed, retry, isGen); 136 | } else if (2 === data.response.errno && retry < retryMax_apiV2) { 137 | // console.log(`转存接口错误, 重试${retry + 1}次: ${file.path}`); // debug 138 | createFileV2.call(this, file, onResponsed, onFailed, ++retry, isGen); 139 | } else onResponsed(data); 140 | }, 141 | onFailed 142 | ); 143 | } 144 | 145 | // 此接口测试结果如下: 错误md5->返回block_list: [0], 正确md5+正确/错误size->返回block_list: [] 146 | // 23.4.24测试发现此接口也不稳定, 有效md5也有20-30%概率返回block_list: [0], 建议加入retry策略 147 | // 23.4.25测试发现此接口反复横跳, 今天又全部返回block_list: [0], 垃圾, 我直接弃用 148 | // export function precreateFileV2( 149 | // file: FileInfo, 150 | // onResponsed: (data: any) => void, 151 | // onFailed: (statusCode: number) => void, 152 | // retry: number = 0 153 | // ): void { 154 | // ajax( 155 | // { 156 | // url: `${precreate_url}${this.bdstoken && "&bdstoken=" + this.bdstoken}`, // bdstoken参数不能放在data里, 否则无效 157 | // method: "POST", 158 | // responseType: "json", 159 | // data: convertData({ 160 | // block_list: JSON.stringify([file.md5.toLowerCase()]), 161 | // path: this.savePath + file.path.replace(illegalPathPattern, "_"), 162 | // size: file.size, 163 | // isdir: 0, 164 | // autoinit: 1, 165 | // }), 166 | // }, 167 | // (data) => { 168 | // let _data = data.response; 169 | // if (0 === _data.errno) { 170 | // if (0 != _data.block_list.length && retry < retryMax_apiV2) 171 | // precreateFileV2.call(this, file, onResponsed, onFailed, ++retry); 172 | // else onResponsed(data); 173 | // } else onResponsed(data); 174 | // }, 175 | // onFailed 176 | // ); 177 | // } 178 | -------------------------------------------------------------------------------- /src/baidu/legacyPage/loader.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-10-20 10:36:43 4 | * @LastEditTime: 2022-12-24 10:57:23 5 | * @LastEditors: mengzonefire 6 | * @Description: 旧版度盘界面loader入口: https://pan.baidu.com/disk/home?stayAtHome=true 7 | */ 8 | 9 | import { TAG, version } from "@/common/const"; 10 | import { 11 | setGetBdstoken, 12 | setGetSelectedFileList, 13 | setRefreshList, 14 | swalInstance, 15 | } from "../common/const"; 16 | import { getSelectedFileListLegacy } from "@/common/utils"; 17 | 18 | const htmlTagLegacy = "div.tcuLAu"; // 旧版界面秒传按钮的html父对象 19 | const htmlBtnRapidLegacy = // 旧版界面秒传按钮的html元素 20 | '秒传链接'; 21 | const htmlBtnGenLegacy = // 旧版界面秒传生成按钮的html元素 22 | '生成秒传'; 23 | 24 | export default function installLegacy() { 25 | console.info("%s version: %s DOM方式安装", TAG, version); 26 | setRefreshList(() => { 27 | // 旧版界面, 调用原生方法刷新文件列表, 无需重新加载页面 28 | unsafeWindow 29 | .require("system-core:system/baseService/message/message.js") 30 | .trigger("system-refresh"); 31 | }); 32 | setGetSelectedFileList(getSelectedFileListLegacy); 33 | setGetBdstoken(() => unsafeWindow.locals.get("bdstoken")); 34 | addBtn(); // DOM添加秒传按钮 35 | addGenBtn(); // DOM添加生成按钮 36 | $(document).on("click", "#bdlink_btn", () => { 37 | swalInstance.inputView(); 38 | }); // 绑定秒传按钮事件 39 | $(document).on("click", "#gen_bdlink_btn", () => { 40 | swalInstance.generatebdlinkTask.reset(); 41 | swalInstance.checkUnfinish(); 42 | }); // 绑定生成按钮事件 43 | } 44 | 45 | function getSystemContext() { 46 | return unsafeWindow.require("system-core:context/context.js") 47 | .instanceForSystem; 48 | } 49 | 50 | function addGenBtn() { 51 | let listTools = getSystemContext().Broker.getButtonBroker("listTools"); 52 | if (listTools && listTools.$box) 53 | $(listTools.$box).children("div").after(htmlBtnGenLegacy); 54 | else setTimeout(addGenBtn, 300); 55 | } 56 | 57 | function addBtn() { 58 | if ($(htmlTagLegacy).length) $(htmlTagLegacy).append(htmlBtnRapidLegacy); 59 | else setTimeout(addBtn, 100); 60 | } 61 | -------------------------------------------------------------------------------- /src/baidu/loader.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-10-20 10:36:43 4 | * @LastEditTime: 2023-04-05 07:30:42 5 | * @LastEditors: mengzonefire 6 | * @Description: 主函数入口 7 | */ 8 | 9 | import { 10 | locUrl, 11 | baiduNewPage, 12 | baiduSyncPage, 13 | baiduSharePage, 14 | updateInfoVer, 15 | donateVer, 16 | feedbackVer, 17 | TAG, 18 | version, 19 | referralVer, 20 | } from "@/common/const"; 21 | import { parseQueryLink } from "@/common/duParser"; 22 | import installNew from "./newPage/loader"; 23 | import installLegacy from "./legacyPage/loader"; 24 | import { swalInstance } from "./common/const"; 25 | import installSync from "./syncPage/loader"; 26 | import installShare from "./sharePage/loader"; 27 | 28 | export function loaderBaidu(): void { 29 | let load = () => { 30 | if (locUrl.includes(baiduNewPage)) installNew(); 31 | else if (locUrl.includes(baiduSharePage)) installShare(); 32 | else if (locUrl.includes(baiduSyncPage)) installSync(); 33 | else installLegacy(); 34 | 35 | // 进入页面后的弹窗任务 36 | let bdlink = parseQueryLink(locUrl); // 解析url中的秒传链接 37 | if (bdlink) { 38 | // 解析到秒传链接, 弹出转存窗口 39 | swalInstance.inputView(bdlink); 40 | } else if (!GM_getValue(`${updateInfoVer}_no_first`)) 41 | // 检查是否首次运行, 若是则弹出更新信息窗口 42 | swalInstance.updateInfo(() => { 43 | GM_setValue(`${updateInfoVer}_no_first`, true); 44 | }); 45 | 46 | // 预先绑定好按钮事件 47 | $(document).on("click", "#mzf_kill_donate", function () { 48 | GM_setValue(`${donateVer}_kill_donate`, true); 49 | $("#mzf_donate").remove(); 50 | }); // 赞助提示 "不再显示" 按钮 51 | $(document).on("click", "#mzf_kill_feedback", function () { 52 | GM_setValue(`${feedbackVer}_kill_feedback`, true); 53 | $("#mzf_feedback").remove(); 54 | }); // 反馈提示 "不再显示" 按钮 55 | $(document).on("click", "#mzf_kill_referral", function () { 56 | GM_setValue(`${referralVer}_kill_referral`, true); 57 | $("#mzf_referral").remove(); 58 | }); // 网盘会员推广 "不再显示" 按钮 59 | $(document).on("click", "#copy_fail_list", (btn) => { 60 | let listText = ""; 61 | for (let item of swalInstance.parseResult.failList) 62 | listText += item.path + "\n"; 63 | GM_setClipboard(listText); 64 | btn.target.innerText = "复制成功"; 65 | }); // 失败文件列表复制 66 | $(document).on("click", "#copy_success_list", (btn) => { 67 | let listText = ""; 68 | for (let item of swalInstance.parseResult.successList) 69 | listText += item.path + "\n"; 70 | GM_setClipboard(listText); 71 | btn.target.innerText = "复制成功"; 72 | }); // 成功文件列表复制 73 | $(document).on("click", "#copy_fail_branch_list", (btn) => { 74 | let ele = $(btn.target); 75 | GM_setClipboard( 76 | ele 77 | .parents("details.mzf_details_branch") 78 | .next()[0] 79 | .innerText.replace(/\n\n/g, "\n") 80 | ); 81 | btn.target.innerText = "复制成功"; 82 | }); // 失败文件分支列表复制 83 | 84 | try { 85 | // 添加油猴插件菜单按钮 86 | GM_registerMenuCommand("🕮 版本信息", () => { 87 | swalInstance.updateInfo(() => {}); 88 | }); 89 | GM_registerMenuCommand("⚙ 工具设置", () => { 90 | swalInstance.settingView(); 91 | }); 92 | GM_registerMenuCommand("⚡生成秒传(输入文件路径)", () => { 93 | swalInstance.genView(); 94 | }); 95 | } catch (_) { 96 | console.info( 97 | "%s version: %s 插件菜单添加失败, 使用的插件不支持GM_registerMenuCommand", 98 | TAG, 99 | version 100 | ); 101 | } 102 | }; 103 | 104 | // 绑定入口函数到dom事件 105 | if (["interactive", "complete"].includes(document.readyState)) load(); 106 | else window.addEventListener("DOMContentLoaded", load); 107 | } 108 | -------------------------------------------------------------------------------- /src/baidu/newPage/loader.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-10-20 10:36:43 4 | * @LastEditTime: 2023-02-14 03:53:02 5 | * @LastEditors: mengzonefire 6 | * @Description: 新版度盘界面loader入口: https://pan.baidu.com/disk/main 7 | */ 8 | 9 | import { TAG, version } from "@/common/const"; 10 | import { 11 | setGetBdstoken, 12 | setGetSelectedFileList, 13 | setRefreshList, 14 | swalInstance, 15 | } from "../common/const"; 16 | import { getSelectedFileListNew } from "@/common/utils"; 17 | 18 | const htmlTagNew = "div.nd-file-list-toolbar__actions"; // 新版界面秒传按钮的html父对象 19 | const htmlTagNew2 = "div.wp-s-agile-tool-bar__header"; // 22.5.24: 新版界面新增的一个父对象 20 | const htmlBtnRapidNew = // 新版界面秒传按钮的html元素 21 | ''; 22 | const htmlBtnGenNew = // 新版界面秒传生成按钮的html元素 23 | ''; 24 | 25 | export default function installNew() { 26 | console.info("%s version: %s DOM方式安装", TAG, version); 27 | swalInstance.swalGlobalArgs = { 28 | heightAuto: false, 29 | scrollbarPadding: false, 30 | }; // 添加swal参数以防止新版界面下的body样式突变 31 | setRefreshList(() => { 32 | document 33 | .querySelector(".nd-main-list, .nd-new-main-list") 34 | .__vue__.reloadList(); 35 | }); 36 | setGetSelectedFileList(getSelectedFileListNew); 37 | setGetBdstoken( 38 | () => 39 | document.querySelector(".nd-main-list, .nd-new-main-list").__vue__.yunData 40 | .bdstoken 41 | ); 42 | $(document).on("click", "#bdlink_btn", () => { 43 | swalInstance.inputView(); 44 | }); // 绑定转存秒传按钮事件 45 | $(document).on("click", "#gen_bdlink_btn", () => { 46 | swalInstance.generatebdlinkTask.reset(); 47 | swalInstance.checkUnfinish(); 48 | }); // 绑定生成秒传按钮事件 49 | addBtn(); 50 | } 51 | 52 | function addBtn() { 53 | // 轮询添加按钮, 防止新版页面重复init时, 将按钮覆盖 54 | let target = $(htmlTagNew); 55 | if (!target.length) target = $(htmlTagNew2); 56 | if (target.length && !$("#bdlink_btn").length) 57 | target.append(htmlBtnRapidNew, htmlBtnGenNew); 58 | setTimeout(addBtn, 500); 59 | } 60 | -------------------------------------------------------------------------------- /src/baidu/sharePage/loader.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-12-12 10:57:58 4 | * @LastEditTime: 2022-12-24 10:57:15 5 | * @LastEditors: mengzonefire 6 | * @Description: 文件分享页loader入口: https://pan.baidu.com/s/xxx 7 | */ 8 | 9 | import { TAG, version } from "@/common/const"; 10 | import { setGetBdstoken, swalInstance } from "../common/const"; 11 | 12 | const htmlBtnGenShare = // 分享页的秒传生成按钮html元素 13 | ' 生成秒传 '; 14 | const htmlTagSahre = "[node-type=qrCode]"; 15 | 16 | export default function installShare() { 17 | console.info("%s version: %s DOM方式安装", TAG, version); 18 | setGetBdstoken(() => unsafeWindow.locals.get("bdstoken")); 19 | addBtn(); 20 | $(document).on("click", "#gen_bdlink_btn_sharePage", () => { 21 | swalInstance.generatebdlinkTask.reset(); 22 | swalInstance.generatebdlinkTask.isSharePage = true; 23 | swalInstance.generatebdlinkTask.isFast = true; // 强制使用极速生成 24 | swalInstance.genFileWork(false, false); 25 | }); // 绑定生成按钮事件 26 | } 27 | 28 | function addBtn() { 29 | if ($(htmlTagSahre).length) $(htmlTagSahre).before(htmlBtnGenShare); 30 | else setTimeout(addBtn, 100); 31 | } 32 | -------------------------------------------------------------------------------- /src/baidu/syncPage/loader.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2022-12-12 10:58:59 4 | * @LastEditTime: 2022-12-24 10:57:12 5 | * @LastEditors: mengzonefire 6 | * @Description: 同步空间loader入口: https://pan.baidu.com/disk/synchronization# 7 | */ 8 | 9 | import { TAG, version } from "@/common/const"; 10 | import { 11 | setGetBdstoken, 12 | setGetSelectedFileList, 13 | setRefreshList, 14 | swalInstance, 15 | } from "../common/const"; 16 | import { getSelectedFileListNew } from "@/common/utils"; 17 | 18 | const htmlTagNew = "div.nd-btn-group > span"; 19 | const htmlBtnRapidNew = 20 | ''; 21 | // const htmlBtnGenNew = 22 | // ''; 23 | 24 | export default function installSync() { 25 | console.info("%s version: %s DOM方式安装", TAG, version); 26 | swalInstance.swalGlobalArgs = { 27 | heightAuto: false, 28 | scrollbarPadding: false, 29 | }; 30 | setRefreshList(() => { 31 | document 32 | .querySelector(".nd-main-list, .nd-new-main-list") 33 | .__vue__.reloadList(); 34 | }); 35 | setGetSelectedFileList(getSelectedFileListNew); 36 | setGetBdstoken( 37 | () => 38 | document.querySelector(".nd-main-list, .nd-new-main-list").__vue__.yunData 39 | .bdstoken 40 | ); 41 | $(document).on("click", "#bdlink_btn", () => { 42 | swalInstance.inputView(); 43 | }); // 绑定转存秒传按钮事件 44 | $(document).on("click", "#gen_bdlink_btn", () => { 45 | swalInstance.generatebdlinkTask.reset(); 46 | swalInstance.checkUnfinish(); 47 | }); // 绑定生成秒传按钮事件 48 | addBtn(); 49 | } 50 | 51 | function addBtn() { 52 | // 轮询添加按钮, 防止新版页面重复init时, 将按钮覆盖 53 | let target = $(htmlTagNew); 54 | if (target.length && !$("#bdlink_btn").length) target.append(htmlBtnRapidNew); 55 | // target.append(htmlBtnRapidNew, htmlBtnGenNew); 56 | // 同步页中的文件使用另一种的接口获取dlink, 故暂不添加生成功能 57 | setTimeout(addBtn, 500); 58 | } 59 | -------------------------------------------------------------------------------- /src/common/ajax.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-27 14:48:24 4 | * @LastEditTime: 2023-02-14 04:10:09 5 | * @LastEditors: mengzonefire 6 | * @Description: 自封装JQ ajax方法 7 | */ 8 | 9 | import { ajaxError, TAG, version } from "./const"; 10 | 11 | export default function ajax( 12 | config: any, 13 | callback: (response: any) => void, 14 | failback: (statusCode: number) => void 15 | ) { 16 | GM_xmlhttpRequest({ 17 | ...config, 18 | onload: (r: any) => { 19 | // console.log(r); // debug 20 | if (Math.floor(r.status / 100) === 2) { 21 | console.info( 22 | "%s version: %s 接口返回: %s", 23 | TAG, 24 | version, 25 | JSON.stringify(r.response) 26 | ); // user debug 27 | callback(r); 28 | } else failback(r.status); 29 | }, 30 | onerror: () => { 31 | failback(ajaxError); 32 | }, 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /src/common/const.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-07-23 17:41:28 4 | * @LastEditTime: 2023-05-15 16:53:31 5 | * @LastEditors: mengzonefire 6 | * @Description: 存放各种全局常量对象 7 | */ 8 | 9 | export const version = "2.7.8"; // 当前版本号 10 | export const updateDate = "23.5.15"; // 更新弹窗显示的日期 11 | export const updateInfoVer = "2.7.5"; // 更新弹窗的版本, 没必要提示的非功能性更新就不弹窗了 12 | export const swalCssVer = "1.7.4"; // 由于其他主题的Css代码会缓存到本地, 故更新主题包版本(url)时, 需要同时更新该字段以刷新缓存 13 | export const donateVer = "2.6.4"; // 用于检测可关闭的赞助提示的版本号 14 | export const feedbackVer = "2.6.4"; // 用于检测可关闭的反馈提示的版本号 15 | export const referralVer = "2.6.4"; // 用于检测可关闭的推广提示的版本号 16 | export const locUrl: string = location.href; 17 | export const baiduNewPage = "baidu.com/disk/main"; // 匹配新版度盘界面 18 | export const baiduSyncPage = "baidu.com/disk/synchronization"; // 匹配同步空间 19 | export const baiduSharePage = "baidu.com/s/"; // 匹配分享页 20 | export const TAG = "[秒传链接提取 by mengzonefire]"; 21 | export const homePage = "https://greasyfork.org/zh-CN/scripts/424574"; 22 | export const donatePage = "https://afdian.net/@mengzonefire"; 23 | export const referralPage = "https://snsyun.baidu.com/sl/eQlxlz8"; 24 | export const ajaxError = 514; // 自定义ajax请求失败时的错误码(不能与http statusCode冲突) 25 | export const bdlinkPrefix = "https://pan.baidu.com/#bdlink="; // 一键秒传链接的前缀 26 | export const commandList = ["set", "gen", "info"]; // 转存输入框内支持输入的命令 27 | export const UA = "netdisk;"; // 自定义User-Agent 28 | export const extCssUrl = { 29 | Default: "", 30 | Dark: "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-dark@5/dark.min.css", 31 | "WordPress Admin": 32 | "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-wordpress-admin@5/wordpress-admin.min.css", 33 | "Material UI": 34 | "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-material-ui@5/material-ui.min.css", 35 | Bulma: 36 | "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bulma@5/bulma.min.css", 37 | "Bootstrap 4": 38 | "https://cdn.jsdelivr.net/npm/@sweetalert2/theme-bootstrap-4/bootstrap-4.min.css", 39 | }; // 各主题包对应的url 40 | export const appError = { 41 | SwalCssInvalid: `样式包数据错误, 自动使用内置样式 (请点确定)`, 42 | SwalCssErrReq: `样式包加载失败, 自动使用内置样式 (请点确定), 错误代码: `, 43 | ClipboardPremissionErr: 44 | '使用 "监听剪贴板" 功能需要允许剪贴板权限!\n该功能只支持Chrome系/Edge/Opera浏览器, 不支持Firefox, 同时注意使用https访问页面 (http访问会导致浏览器直接禁止剪贴板权限)', 45 | }; // 主程序异常 46 | export const appWarning = { 47 | fastGenerateWarn: 48 | '使用 "极速生成" 功能请注意:\n优点:\n1. 极大幅度提高秒传生成速度\n2. 有效避免 "md5获取失败(#996)" "接口限制访问(#403)"\n缺点:\n1. 生成和谐文件秒传时大概率正常生成 (非极速生成则会报错#1919)\n2. 生成的秒传格式为简化版, 只保证最新版的 秒传脚本 和 秒传网页版 支持转存\n\n* 若开启后出现问题请根据设置页内的 "说明文档" 进行反馈', 49 | }; // 主程序各功能警告/提醒 50 | export const enum genTryflag { 51 | useDlink1 = 0, 52 | useDlink2 = 1, 53 | } // 秒传生成 标识参数 54 | const docPrefix = 55 | "https://mengzonefire.code.misakanet.cn/rapid-upload-userscript-doc/document"; 56 | const docPrefix2 = 57 | "https://xtsat.github.io/rapid-upload-userscript-doc/document"; 58 | export const doc = { 59 | shareDoc: `${docPrefix}/FAQ/错误代码`, 60 | linkTypeDoc: `${docPrefix}/Info/秒传格式`, 61 | bdlinkDoc: `${docPrefix}/秒传链接生成/一键秒传`, 62 | fastGenDoc: `${docPrefix}/秒传链接生成/极速生成`, 63 | }; // 文档载点1 64 | export const doc2 = { 65 | shareDoc: `${docPrefix2}/FAQ/错误代码`, 66 | linkTypeDoc: `${docPrefix2}/Info/秒传格式`, 67 | bdlinkDoc: `${docPrefix2}/秒传链接生成/一键秒传`, 68 | fastGenDoc: `${docPrefix2}/秒传链接生成/极速生成`, 69 | }; // 文档载点2 70 | export const linkStyle = 71 | 'class="mzf_link" rel="noopener noreferrer" target="_blank"'; 72 | export const btnStyle = 73 | 'class="mzf_btn" rel="noopener noreferrer" target="_blank"'; 74 | export const bdlinkPattern = /#bdlink=([\da-zA-Z+/=]+)/; // b64可能出现的字符: 大小写字母a-zA-Z, 数字0-9, +, /, = (=用于末尾补位) 75 | export const htmlDocument = `

秒传无效,防和谐等 可参考秒传文档载点1载点2

`; 76 | export const htmlDonate = `

若喜欢该脚本, 可前往 赞助页 支持作者不再显示

`; 77 | export const htmlFeedback = `

若有任何疑问, 可前往 脚本主页 反馈不再显示

`; 78 | export const htmlReferral = `

(百度官方推广) 优惠开通网盘会员不再显示

`; 79 | export const htmlAboutBdlink = `什么是一键秒传?: 文档载点1 文档载点2`; 80 | export const copyFailList = 81 | '复制列表'; 82 | export const copyFailBranchList = 83 | '复制列表'; 84 | export const copySuccessList = 85 | '复制列表'; 86 | -------------------------------------------------------------------------------- /src/common/duParser.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-26 12:01:28 4 | * @LastEditTime: 2022-08-29 10:21:05 5 | * @LastEditors: mengzonefire 6 | * @Description: 各种解析器 7 | */ 8 | 9 | import { bdlinkPattern } from "@/common/const"; 10 | import { decryptMd5 } from "./utils"; 11 | 12 | /** 13 | * @description: 从url中解析秒传链接 14 | */ 15 | export function parseQueryLink(url: string): string { 16 | let bdlinkB64 = url.match(bdlinkPattern); 17 | return bdlinkB64 ? bdlinkB64[1].fromBase64() : ""; 18 | } 19 | 20 | /** 21 | * @description: 秒传链接解析器 22 | */ 23 | export function DuParser() {} 24 | 25 | DuParser.parse = function generalDuCodeParse(szUrl: string) { 26 | let r: any; 27 | if (szUrl.indexOf("bdpan") === 0) { 28 | r = DuParser.parseDu_v1(szUrl); 29 | r.ver = "PanDL"; 30 | } else if (szUrl.indexOf("BaiduPCS-Go") === 0) { 31 | r = DuParser.parseDu_v2(szUrl); 32 | r.ver = "PCS-Go"; 33 | } else if (szUrl.indexOf("BDLINK") === 0) { 34 | r = DuParser.parseDu_v3(szUrl); 35 | r.ver = "游侠 v1"; 36 | } else { 37 | r = DuParser.parseDu_v4(szUrl); 38 | r.ver = "梦姬标准"; 39 | } 40 | return r; 41 | }; 42 | 43 | DuParser.parseDu_v1 = function parseDu_v1(szUrl: string) { 44 | return szUrl 45 | .replace(/\s*bdpan:\/\//g, " ") 46 | .trim() 47 | .split(" ") 48 | .map(function (z) { 49 | return z 50 | .trim() 51 | .fromBase64() 52 | .match(/([\s\S]+)\|([\d]{1,20})\|([\da-f]{32})\|([\da-f]{32})/i); 53 | }) 54 | .filter(function (z) { 55 | return z; 56 | }) 57 | .map(function (info: Array) { 58 | return { 59 | md5: info[3], 60 | md5s: info[4], 61 | size: info[2], 62 | path: info[1], 63 | }; 64 | }); 65 | }; 66 | 67 | DuParser.parseDu_v2 = function parseDu_v2(szUrl: string) { 68 | return szUrl 69 | .split("\n") 70 | .map(function (z) { 71 | // unsigned long long: 0~18446744073709551615 72 | return z 73 | .trim() 74 | .match( 75 | /-length=([\d]{1,20}) -md5=([\da-f]{32}) -slicemd5=([\da-f]{32})[\s\S]+"([\s\S]+)"/i 76 | ); 77 | }) 78 | .filter(function (z) { 79 | return z; 80 | }) 81 | .map(function (info) { 82 | return { 83 | md5: info[2], 84 | md5s: info[3], 85 | size: info[1], 86 | path: info[4], 87 | }; 88 | }); 89 | }; 90 | 91 | DuParser.parseDu_v3 = function parseDu_v3(szUrl: string) { 92 | var raw = atob(szUrl.slice(6).replace(/\s/g, "")); 93 | if (raw.slice(0, 5) !== "BDFS\x00") { 94 | return null; 95 | } 96 | var buf = new SimpleBuffer(raw); 97 | var ptr = 9; 98 | var arrFiles = []; 99 | var fileInfo: { 100 | size?: any; 101 | md5?: any; 102 | md5s?: any; 103 | nameSize?: any; 104 | path?: any; 105 | }, 106 | nameSize: number; 107 | var total = buf.readUInt(5); 108 | var i: number; 109 | 110 | for (i = 0; i < total; i++) { 111 | // 大小 (8 bytes) 112 | // MD5 + MD5S (0x20) 113 | // nameSize (4 bytes) 114 | // Name (unicode) 115 | fileInfo = {}; 116 | fileInfo.size = buf.readULong(ptr + 0); 117 | fileInfo.md5 = buf.readHex(ptr + 8, 0x10); 118 | fileInfo.md5s = buf.readHex(ptr + 0x18, 0x10); 119 | nameSize = buf.readUInt(ptr + 0x28) << 1; 120 | fileInfo.nameSize = nameSize; 121 | ptr += 0x2c; 122 | fileInfo.path = buf.readUnicode(ptr, nameSize); 123 | arrFiles.push(fileInfo); 124 | ptr += nameSize; 125 | } 126 | 127 | return arrFiles; 128 | }; 129 | 130 | DuParser.parseDu_v4 = function parseDu_v3(szUrl: string) { 131 | return szUrl 132 | .split("\n") 133 | .map(function (z) { 134 | return z 135 | .trim() 136 | .match( 137 | /^([\da-f]{9}[\da-z][\da-f]{22})#(?:([\da-f]{32})#)?([\d]{1,20})#([\s\S]+)/i 138 | ); // 22.8.29新增支持第10位为g-z的加密md5, 输入后自动解密转存 139 | }) 140 | .filter(function (z) { 141 | return z; 142 | }) 143 | .map(function (info) { 144 | return { 145 | // 标准码 / 短版标准码(无md5s) 146 | md5: decryptMd5(info[1].toLowerCase()), 147 | md5s: info[2] || "", 148 | size: info[3], 149 | path: info[4], 150 | }; 151 | }); 152 | }; 153 | 154 | /** 155 | * 一个简单的类似于 NodeJS Buffer 的实现. 156 | * 用于解析游侠度娘提取码。 157 | * @param {SimpleBuffer} 158 | */ 159 | 160 | function SimpleBuffer(str: string) { 161 | this.fromString(str); 162 | } 163 | 164 | SimpleBuffer.toStdHex = function toStdHex(n: { 165 | toString: (arg0: number) => string; 166 | }) { 167 | return ("0" + n.toString(16)).slice(-2); 168 | }; 169 | 170 | SimpleBuffer.prototype.fromString = function fromString(str: string) { 171 | var len = str.length; 172 | this.buf = new Uint8Array(len); 173 | 174 | for (var i = 0; i < len; i++) { 175 | this.buf[i] = str.charCodeAt(i); 176 | } 177 | }; 178 | 179 | SimpleBuffer.prototype.readUnicode = function readUnicode( 180 | index: any, 181 | size: number 182 | ) { 183 | if (size & 1) { 184 | size++; 185 | } 186 | 187 | var bufText = Array.prototype.slice 188 | .call(this.buf, index, index + size) 189 | .map(SimpleBuffer.toStdHex); 190 | var buf = [""]; 191 | 192 | for (var i = 0; i < size; i += 2) { 193 | buf.push(bufText[i + 1] + bufText[i]); 194 | } 195 | 196 | return JSON.parse('"' + buf.join("\\u") + '"'); 197 | }; 198 | 199 | SimpleBuffer.prototype.readNumber = function readNumber( 200 | index: number, 201 | size: any 202 | ) { 203 | var ret = 0; 204 | 205 | for (var i = index + size; i > index; ) { 206 | ret = this.buf[--i] + ret * 256; 207 | } 208 | 209 | return ret; 210 | }; 211 | 212 | SimpleBuffer.prototype.readUInt = function readUInt(index: any) { 213 | return this.readNumber(index, 4); 214 | }; 215 | 216 | SimpleBuffer.prototype.readULong = function readULong(index: any) { 217 | return this.readNumber(index, 8); 218 | }; 219 | 220 | SimpleBuffer.prototype.readHex = function readHex(index: any, size: any) { 221 | return Array.prototype.slice 222 | .call(this.buf, index, index + size) 223 | .map(SimpleBuffer.toStdHex) 224 | .join(""); 225 | }; 226 | -------------------------------------------------------------------------------- /src/common/injectStyle.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-07-23 17:32:18 4 | * @LastEditTime: 2023-04-19 21:51:03 5 | * @LastEditors: mengzonefire 6 | * @Description: 样式注入模块 7 | */ 8 | import appCss from "@/css/app.css"; 9 | import appSCss from "@/css/app.scss"; 10 | import { showAlert } from "./utils"; 11 | import { extCssUrl, appError, swalCssVer } from "./const"; 12 | import { loaderBaidu } from "../baidu/loader"; 13 | import ajax from "./ajax"; 14 | 15 | /** 16 | * @description: 注入脚本样式 17 | */ 18 | export function injectStyle(): void { 19 | // 注入自定义样式 20 | GM_addStyle(appCss); 21 | GM_addStyle(appSCss); 22 | let swalThemes: string = GM_getValue("swalThemes") || "Default"; // sweetAlert的主题(css), 默认为Default 23 | if ("Default" != swalThemes) { 24 | let ThemesCss: string = GM_getValue(`${swalCssVer}${swalThemes}`); // 从缓存获取非默认主题的css代码 25 | if (ThemesCss) GM_addStyle(ThemesCss); 26 | else { 27 | getThemesCss(swalThemes); // 未找到缓存, fallback到下载css代码 28 | return; 29 | } 30 | } 31 | loaderBaidu(); 32 | } 33 | 34 | /** 35 | * @description: 下载并注入对应主题的css样式代码, 会将css代码缓存本地 36 | * @param {string} swalThemes 主题包名 37 | */ 38 | function getThemesCss(swalThemes: string): void { 39 | ajax( 40 | { 41 | url: extCssUrl[swalThemes], 42 | method: "GET", 43 | }, 44 | (data) => { 45 | let ThemesCss = data.responseText; 46 | if (ThemesCss.length < 100) { 47 | showAlert( 48 | appError.SwalCssInvalid + 49 | `\n错误数据:${swalThemes} InvalidCss:\n${ThemesCss}` 50 | ); 51 | GM_setValue("swalThemes", "Default"); 52 | loaderBaidu(); 53 | return; 54 | } // 返回data数据长度过小, 判定为无效样式代码 55 | GM_setValue(`${swalCssVer}${swalThemes}`, ThemesCss); // 缓存css代码 56 | GM_addStyle(ThemesCss); // 注入css 57 | loaderBaidu(); 58 | }, 59 | 60 | (statusCode) => { 61 | showAlert(appError.SwalCssErrReq + `#${statusCode}`); 62 | GM_setValue("swalThemes", "Default"); 63 | loaderBaidu(); 64 | } 65 | ); 66 | } 67 | -------------------------------------------------------------------------------- /src/common/swalBase.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-25 08:34:46 4 | * @LastEditTime: 2023-04-11 14:10:57 5 | * @LastEditors: mengzonefire 6 | * @Description: 定义全套的前台弹窗逻辑, 在Swal的回调函数内调用***Task类内定义的任务代码 7 | */ 8 | 9 | import { 10 | appError, 11 | appWarning, 12 | baiduSyncPage, 13 | bdlinkPrefix, 14 | commandList, 15 | doc, 16 | htmlAboutBdlink, 17 | htmlReferral, 18 | linkStyle, 19 | locUrl, 20 | referralVer, 21 | } from "./const"; 22 | import { 23 | refreshList, 24 | getSelectedFileList, 25 | illegalPathPattern, 26 | syncPathPrefix, 27 | } from "@/baidu/common/const"; 28 | import GeneratebdlinkTask from "@/baidu/common/generatebdlinkTask"; 29 | import RapiduploadTask from "@/baidu/common/rapiduploadTask"; 30 | import { 31 | donateVer, 32 | feedbackVer, 33 | htmlDocument, 34 | htmlDonate, 35 | htmlFeedback, 36 | } from "./const"; 37 | import { DuParser, parseQueryLink } from "./duParser"; 38 | import { SwalConfig } from "./swalConfig"; 39 | import { 40 | parsefileInfo, 41 | parseClipboard, 42 | showAlert, 43 | getShareFileList, 44 | } from "./utils"; 45 | import Swal from "sweetalert2"; 46 | 47 | export default class Swalbase { 48 | parseResult: any; // 存储 转存/生成 任务的结果信息 49 | swalGlobalArgs: any; // 全局swal参数配置对象 50 | constructor( 51 | readonly rapiduploadTask: RapiduploadTask, 52 | readonly generatebdlinkTask: GeneratebdlinkTask 53 | ) {} 54 | 55 | // 合并swal参数 56 | mergeArg(...inputArgs: any) { 57 | let output = {}; 58 | let swalCfgArgs: any = { 59 | // 禁用backdrop动画, 阻止多次弹窗时的屏闪 60 | showClass: { backdrop: "swal2-noanimation" }, 61 | hideClass: { backdrop: "swal2-noanimation" }, 62 | }; 63 | $.extend(output, this.swalGlobalArgs, swalCfgArgs, ...inputArgs); 64 | return output; 65 | } 66 | 67 | // 点击 "秒传链接" 后显示的弹窗 68 | async inputView(inputValue: string = "") { 69 | if (GM_getValue("listen-clipboard") && !inputValue) 70 | // 标志位true 且 inputValue为空(非一键秒传进入时) 从剪贴板读取有效的秒传链接 71 | inputValue = await parseClipboard(); 72 | let pathValue: string = GM_getValue("last_dir") || ""; // 从GM存储读取上次输入的转存路径 73 | let preConfirm = () => { 74 | // 手动读取Multiple inputs内的数据, 由于未设置input参数, 原生Validator不生效, 自行添加Validator逻辑 75 | inputValue = $("#mzf-rapid-input")[0].value; 76 | pathValue = $("#mzf-path-input")[0] 77 | .value.trim() 78 | .replace(/(\s+)?\/(\s+)?/g, "/"); // 修正不合规的路径(空白开头/结尾) 79 | if (!inputValue) { 80 | Swal.showValidationMessage("秒传不能为空"); 81 | return false; 82 | } 83 | if (commandList.includes(inputValue.trim())) { 84 | // 输入支持的命令, 跳出检查 85 | inputValue = inputValue.trim(); 86 | return; 87 | } 88 | if (!DuParser.parse(inputValue).length) { 89 | Swal.showValidationMessage( 90 | `

未识别到正确的链接 查看支持格式

` 91 | ); 92 | return false; 93 | } 94 | if (pathValue.match(illegalPathPattern)) { 95 | Swal.showValidationMessage( 96 | '保存路径不能含有字符\\":*?<>|, 示例:/GTA5/' 97 | ); 98 | return false; 99 | } 100 | }; 101 | let willOpen = () => { 102 | $("#swal2-html-container") 103 | .css("font-size", "1rem") 104 | .css("display", "grid") 105 | .css("margin", "0"); 106 | $("#mzf-rapid-input")[0].value = inputValue; 107 | $("#mzf-path-input")[0].value = pathValue; 108 | $("#mzf-rapid-input").on("input", function (event) { 109 | let result = parseQueryLink(event.target.value); 110 | if (DuParser.parse(result).length) event.target.value = result; 111 | }); // 绑定输入框事件, 输入一键秒传后尝试转换为普通秒传 112 | }; 113 | Swal.fire( 114 | this.mergeArg(SwalConfig.inputView, { 115 | preConfirm: preConfirm, 116 | willOpen: willOpen, 117 | }) 118 | ).then((result: any) => { 119 | if (result.isConfirmed) { 120 | if (inputValue === "set") this.settingView(); 121 | else if (inputValue === "gen") this.genView(); 122 | else if (inputValue === "info") this.updateInfo(() => {}); 123 | else { 124 | this.rapiduploadTask.reset(); 125 | this.rapiduploadTask.fileInfoList = DuParser.parse(inputValue); 126 | GM_setValue("last_dir", pathValue); 127 | if (!pathValue) { 128 | // 路径留空 129 | this.rapiduploadTask.isDefaultPath = true; 130 | let nowPath = location.href.match(/path=(.+?)(?:&|$)/); 131 | if (nowPath) pathValue = decodeURIComponent(nowPath[1]); 132 | else pathValue = "/"; 133 | } 134 | if (pathValue.charAt(0) !== "/") pathValue = "/" + pathValue; // 补齐路径前缀斜杠 135 | if (pathValue.charAt(pathValue.length - 1) !== "/") pathValue += "/"; // 补全路径结尾的斜杠 136 | if ( 137 | locUrl.includes(baiduSyncPage) && 138 | !pathValue.includes(syncPathPrefix) 139 | ) 140 | pathValue = syncPathPrefix + pathValue; // 补全同步页路径前缀 141 | console.log(`秒传文件保存到: ${pathValue}`); // debug 142 | this.rapiduploadTask.savePath = pathValue; 143 | this.processView(false); 144 | } 145 | } 146 | }); 147 | } 148 | 149 | // 转存/生成过程中的弹窗 150 | processView(isGen: boolean) { 151 | let swalArg = { 152 | title: isGen ? "秒传生成中" : "文件转存中", 153 | html: isGen 154 | ? "

正在生成第 0

正在获取文件列表...

" 155 | : "正在转存第 0 个", 156 | willOpen: () => { 157 | Swal.showLoading(); 158 | isGen || this.saveFileWork(); 159 | }, 160 | }; 161 | Swal.fire(this.mergeArg(SwalConfig.processView, swalArg)); 162 | } 163 | 164 | // 转存/生成秒传完成的弹窗 165 | finishView(isGen: boolean) { 166 | let action = isGen ? "生成" : "转存"; 167 | let fileInfoList = isGen 168 | ? this.generatebdlinkTask.fileInfoList 169 | : this.rapiduploadTask.fileInfoList; 170 | let parseResult = parsefileInfo(fileInfoList); 171 | this.parseResult = parseResult; 172 | let checkboxArg = { 173 | input: "checkbox", 174 | inputValue: GM_getValue("with_path"), 175 | inputPlaceholder: "导出文件夹目录结构", 176 | }; // 全部失败不显示此checkbox, 22.5.22: 全部失败也显示 177 | let html = 178 | (isGen ? htmlDocument : "") + // 生成模式下添加文档入口 179 | (parseResult.htmlInfo && isGen ? "
" : "") + 180 | parseResult.htmlInfo; // 添加失败列表, 生成模式下添加顶部空行分隔 181 | let htmlFooter = ""; 182 | if (!GM_getValue(`${donateVer}_kill_donate`)) htmlFooter += htmlDonate; // 添加赞助入口提示 183 | if (!GM_getValue(`${feedbackVer}_kill_feedback`)) 184 | htmlFooter += htmlFeedback; // 添加反馈入口提示 185 | if (!GM_getValue(`${referralVer}_kill_referral`)) 186 | htmlFooter += htmlReferral; // 添加网盘推广入口提示 187 | if (htmlFooter) htmlFooter = "
" + htmlFooter; // 添加底部空行分隔 188 | let swalArg = { 189 | title: `${action}完毕 共${fileInfoList.length}个, 失败${parseResult.failList.length}个!`, 190 | confirmButtonText: isGen ? "复制秒传代码" : "确认", 191 | showDenyButton: isGen, 192 | denyButtonText: "复制一键秒传", 193 | denyButtonColor: "#ecae3c", 194 | reverseButtons: true, 195 | html: html + htmlFooter, 196 | ...(isGen && checkboxArg), 197 | willOpen: () => { 198 | if (isGen) 199 | GM_setValue("unClose", true); // 生成模式设置结果窗口未关闭的标记 200 | else this.addOpenDirBtn(); // 转存模式时添加 "打开目录" 按钮 201 | }, 202 | // 秒传生成的 "复制一键秒传" 按钮回调 203 | preDeny: () => { 204 | let with_path = $("#swal2-checkbox")[0].checked; 205 | GM_setValue("with_path", with_path); 206 | if (!with_path) 207 | GM_setClipboard( 208 | bdlinkPrefix + parseResult.bdcode.replace(/\/.+\//g, "").toBase64() 209 | ); 210 | // 去除目录结构, 并转换为一键秒传 211 | else GM_setClipboard(bdlinkPrefix + parseResult.bdcode.toBase64()); // 转换为一键秒传 212 | Swal.getDenyButton().innerText = "复制成功,点击右上关闭"; 213 | let footer = Swal.getFooter(); 214 | footer.innerHTML = htmlAboutBdlink; 215 | footer.style.display = "flex"; 216 | return false; 217 | }, 218 | preConfirm: () => { 219 | if (isGen) { 220 | // 生成模式, "复制秒传代码"按钮 221 | let with_path = $("#swal2-checkbox")[0].checked; 222 | GM_setValue("with_path", with_path); 223 | if (!with_path) 224 | GM_setClipboard( 225 | parseResult.bdcode.replace(/(#\/.+\/)|(#\/)/g, "#") 226 | ); 227 | // 去除秒传链接中的目录结构(仅保留文件名) 228 | else { 229 | let pathType = 230 | GM_getValue("pathType") === undefined 231 | ? "relative" 232 | : GM_getValue("pathType"); 233 | if ("absolute" === pathType) GM_setClipboard(parseResult.bdcode); 234 | // 保留完整的文件路径(绝对路径) 235 | else if ("relative" === pathType) { 236 | // 去除前置的路径以及路径开头的'/', 将绝对路径转换为相对路径 (默认执行) 237 | let localPathPrefix = ""; 238 | let nowPath = location.href.match(/path=(.+?)(?:&|$)/); 239 | if (nowPath) localPathPrefix = decodeURIComponent(nowPath[1]); 240 | GM_setClipboard( 241 | parseResult.bdcode.replace( 242 | new RegExp(`(#${localPathPrefix}/)|(#/)`, "g"), 243 | "#" 244 | ) 245 | ); 246 | } 247 | } 248 | Swal.getConfirmButton().innerText = "复制成功,点击右上关闭"; 249 | return false; 250 | } else { 251 | // 转存模式, "确定" 按钮 252 | refreshList(); // 调用刷新文件列表的方法 253 | return undefined; 254 | } 255 | }, 256 | }; 257 | Swal.fire(this.mergeArg(SwalConfig.finishView, swalArg)).then( 258 | (result: any) => { 259 | if (result.isDismissed || result.dismiss === Swal.DismissReason.close) { 260 | GM_deleteValue("unfinish"); // 点击了右上角的关闭按钮, 清除任务进度数据 261 | GM_setValue("unClose", false); 262 | } 263 | } 264 | ); 265 | } 266 | 267 | // 生成文件夹秒传, 是否递归生成提示 268 | checkRecursive() { 269 | Swal.fire(this.mergeArg(SwalConfig.checkRecursive)).then((result: any) => { 270 | if (result.isConfirmed) { 271 | this.generatebdlinkTask.recursive = true; 272 | } else if (result.dismiss === Swal.DismissReason.cancel) 273 | this.generatebdlinkTask.recursive = false; 274 | else return; 275 | this.processView(true); 276 | this.generatebdlinkTask.scanFile(0); 277 | }); 278 | } 279 | 280 | // 设置页 281 | settingView() { 282 | let willOpen = () => { 283 | $("#swal2-html-container") 284 | .css("font-size", "1rem") 285 | .css("display", "grid") 286 | .css("margin", "0"); 287 | $("#mzf-theme")[0].value = GM_getValue("swalThemes") || "Default"; 288 | $("#mzf-pathType")[0].value = GM_getValue("pathType") || "relative"; 289 | $("#mzf-listen-clipboard")[0].checked = Boolean( 290 | GM_getValue("listen-clipboard") 291 | ); 292 | $("#mzf-fast-generate")[0].checked = Boolean( 293 | GM_getValue("fast-generate") === undefined 294 | ? true 295 | : GM_getValue("fast-generate") 296 | ); 297 | }; 298 | let preConfirm = async () => { 299 | // 设置主题 300 | GM_setValue("swalThemes", $("#mzf-theme")[0].value); 301 | // 设置生成秒传导出路径(相对/绝对) 302 | GM_setValue("pathType", $("#mzf-pathType")[0].value); 303 | 304 | // 设置监听剪贴板 305 | if ($("#mzf-listen-clipboard")[0].checked) { 306 | try { 307 | await navigator.clipboard.readText(); 308 | GM_setValue( 309 | "listen-clipboard", 310 | $("#mzf-listen-clipboard")[0].checked 311 | ); 312 | } catch (error) { 313 | showAlert(appError.ClipboardPremissionErr); 314 | return; 315 | } // 验证剪贴板权限, 若报错则跳出不设置该项 316 | } 317 | 318 | // 设置极速生成, 若开启则弹出文本提醒 319 | if ($("#mzf-fast-generate")[0].checked) 320 | showAlert(appWarning.fastGenerateWarn); 321 | GM_setValue("fast-generate", $("#mzf-fast-generate")[0].checked); 322 | }; 323 | Swal.fire( 324 | this.mergeArg(SwalConfig.settingView, { 325 | willOpen: willOpen, 326 | preConfirm: preConfirm, 327 | }) 328 | ).then((result: any) => { 329 | if (result.isConfirmed) 330 | Swal.fire(this.mergeArg(SwalConfig.settingWarning)); 331 | }); 332 | } 333 | 334 | // 生成页 (输入路径列表进行秒传生成) 335 | genView() { 336 | Swal.fire(this.mergeArg(SwalConfig.genView)).then((result: any) => { 337 | if (result.isConfirmed) { 338 | this.generatebdlinkTask.reset(); 339 | result.value.split("\n").forEach((filePath: string) => { 340 | if (filePath.charAt(0) !== "/") filePath = "/" + filePath; // 补齐路径前缀斜杠 341 | if ( 342 | locUrl.includes(baiduSyncPage) && 343 | !filePath.includes(syncPathPrefix) 344 | ) 345 | filePath = syncPathPrefix + filePath; // 补全同步页路径前缀 346 | this.generatebdlinkTask.fileInfoList.push({ 347 | path: filePath, 348 | }); 349 | }); 350 | this.processView(true); // 显示进度弹窗 351 | this.genFileWork(false, true); // 跳过获取选择文件列表和扫描文件夹的步骤 352 | this.generatebdlinkTask.generateBdlink(0); // 开始生成任务 353 | } 354 | }); 355 | } 356 | 357 | // 生成秒传未完成任务提示 358 | genUnfinish(onConfirm: () => void, onCancel: () => void) { 359 | Swal.fire( 360 | this.mergeArg( 361 | GM_getValue("unClose") 362 | ? SwalConfig.genUnfinish2 363 | : SwalConfig.genUnfinish 364 | ) 365 | ).then((result: any) => { 366 | if (result.isConfirmed) onConfirm(); 367 | else if (result.dismiss === Swal.DismissReason.cancel) onCancel(); 368 | }); 369 | } 370 | 371 | // 生成秒传, 未选择任何文件的提示 372 | selectNoFileWarning() { 373 | Swal.fire(this.mergeArg(SwalConfig.selectNoFileWarning)); 374 | } 375 | 376 | // 更新信息页 377 | updateInfo(onConfirm: () => void) { 378 | Swal.fire(this.mergeArg(SwalConfig.updateInfo)).then((result: any) => { 379 | if (result.isConfirmed) onConfirm(); 380 | }); 381 | } 382 | 383 | // 以下的方法都是任务操作逻辑, 不是弹窗逻辑 384 | saveFileWork() { 385 | this.rapiduploadTask.onFinish = () => this.finishView(false); 386 | this.rapiduploadTask.onProcess = (i, fileInfoList) => { 387 | Swal.getHtmlContainer().querySelector("file_num").textContent = `${ 388 | i + 1 389 | } / ${fileInfoList.length}`; 390 | }; 391 | this.rapiduploadTask.start(); // 开始转存任务 392 | } 393 | 394 | genFileWork(isUnfinish: boolean, isGenView: boolean) { 395 | if (this.generatebdlinkTask.isSharePage) 396 | this.generatebdlinkTask.selectList = getShareFileList(); 397 | else if (!isGenView) 398 | this.generatebdlinkTask.selectList = getSelectedFileList(); 399 | 400 | if ( 401 | // 未选择文件 + 无未完成的生成任务 + 不在生成页 -> 弹出未选择生成文件的警告弹出 402 | !this.generatebdlinkTask.selectList.length && 403 | !isGenView && 404 | !isUnfinish 405 | ) { 406 | this.selectNoFileWarning(); 407 | return; 408 | } 409 | this.generatebdlinkTask.onProcess = (i, fileInfoList) => { 410 | Swal.getHtmlContainer().querySelector("file_num").textContent = `${ 411 | i + 1 412 | } / ${fileInfoList.length}`; 413 | Swal.getHtmlContainer().querySelector("gen_prog").textContent = "0%"; 414 | }; 415 | this.generatebdlinkTask.onProgress = (e: any, text: string = "") => { 416 | if (text) { 417 | // 显示自定义文本 418 | Swal.getHtmlContainer().querySelector("gen_prog").textContent = text; 419 | return; 420 | } 421 | if (!e || typeof e.total !== "number") return; // 参数数据不正确 跳过 422 | Swal.getHtmlContainer().querySelector("gen_prog").textContent = `${( 423 | (e.loaded / e.total) * 424 | 100 425 | ).toFixed()}%`; 426 | }; 427 | 428 | if (this.generatebdlinkTask.isSharePage) { 429 | this.generatebdlinkTask.onHasNoDir = () => { 430 | this.processView(true); 431 | this.generatebdlinkTask.scanShareFile(0); 432 | }; 433 | } else { 434 | this.generatebdlinkTask.onHasNoDir = () => { 435 | this.processView(true); 436 | this.generatebdlinkTask.generateBdlink(0); 437 | }; 438 | this.generatebdlinkTask.onHasDir = () => this.checkRecursive(); 439 | } 440 | this.generatebdlinkTask.onFinish = () => this.finishView(true); 441 | if (!isUnfinish && !isGenView) this.generatebdlinkTask.start(); // 执行新任务初始化 442 | } 443 | 444 | checkUnfinish() { 445 | if (GM_getValue("unfinish")) { 446 | this.genUnfinish( 447 | () => { 448 | this.processView(true); 449 | this.genFileWork(true, false); 450 | let unfinishInfo: any = GM_getValue("unfinish"); 451 | this.generatebdlinkTask.fileInfoList = unfinishInfo.file_info_list; 452 | unfinishInfo.isCheckMd5 453 | ? this.generatebdlinkTask.checkMd5(unfinishInfo.file_id) 454 | : this.generatebdlinkTask.generateBdlink(unfinishInfo.file_id); 455 | }, // 确认继续未完成任务 456 | () => { 457 | GM_deleteValue("unfinish"); 458 | this.genFileWork(false, false); 459 | } // 不继续未完成任务, 清除数据, 开启新任务 460 | ); 461 | } else { 462 | this.genFileWork(false, false); 463 | } // 没有未完成任务, 直接开启新任务 464 | } 465 | 466 | // 添加 "打开目录" 按钮 467 | addOpenDirBtn() { 468 | if (this.rapiduploadTask.isDefaultPath) return; // 转存路径留空, 跳出 469 | let _dir = (this.rapiduploadTask.savePath || "").replace(/\/$/, ""); // 去除路径结尾的"/" 470 | if (_dir.charAt(0) !== "/") _dir = "/" + _dir; // 补齐路径开头的"/" 471 | let cBtn = Swal.getConfirmButton(); 472 | let btn: HTMLElement = cBtn.cloneNode() as HTMLElement; 473 | btn.textContent = "打开目录"; 474 | btn.style.backgroundColor = "#ecae3c"; 475 | let nowPath = location.href.match(/(path=(.+?))(?:&|$)/); 476 | btn.onclick = () => { 477 | if (nowPath) { 478 | location.href = location.href.replace( 479 | // 仅替换path参数, 不修改其他参数 480 | nowPath[1], 481 | `path=${encodeURIComponent(_dir)}` 482 | ); 483 | } else { 484 | let connectChar = location.href.includes("?") ? "&" : "?"; // 确定参数的连接符 485 | location.href += `${connectChar}path=${encodeURIComponent(_dir)}`; 486 | } // 没有找到path参数, 直接添加 487 | Swal.close(); 488 | }; 489 | if ((nowPath ? nowPath[2] : "%2F") != encodeURIComponent(_dir)) 490 | // 当前已在转存目录时不添加按钮 491 | cBtn.before(btn); 492 | } 493 | } 494 | -------------------------------------------------------------------------------- /src/common/swalConfig.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-26 12:16:57 4 | * @LastEditTime: 2023-02-18 21:27:36 5 | * @LastEditors: mengzonefire 6 | * @Description: 存放各Swal弹窗的固定参数配置 7 | */ 8 | 9 | import updateInfo from "@/components/updateInfo.html"; 10 | import { doc, doc2, linkStyle, updateDate, version } from "@/common/const"; 11 | 12 | export const SwalConfig = { 13 | inputView: { 14 | title: "请输入秒传&保存路径", 15 | showCancelButton: true, 16 | html: ` 17 | `, 18 | confirmButtonText: "确定", 19 | cancelButtonText: "取消", 20 | customClass: { htmlContainer: "mzf_html_container" }, 21 | }, 22 | 23 | processView: { 24 | showCloseButton: true, 25 | showConfirmButton: false, 26 | allowOutsideClick: false, 27 | }, 28 | 29 | finishView: { 30 | showCloseButton: true, 31 | allowOutsideClick: false, 32 | }, 33 | 34 | genUnfinish: { 35 | title: "检测到上次未完成的秒传任务", 36 | text: "是否继续该任务?", 37 | showCancelButton: true, 38 | allowOutsideClick: false, 39 | confirmButtonText: "是", 40 | cancelButtonText: "否", 41 | }, 42 | 43 | genUnfinish2: { 44 | title: "检测到上次未正常退出的秒传任务", 45 | text: "是否恢复该任务?", 46 | showCancelButton: true, 47 | allowOutsideClick: false, 48 | confirmButtonText: "是", 49 | cancelButtonText: "否", 50 | }, 51 | 52 | genView: { 53 | title: "请输入需要生成的文件路径", 54 | input: "textarea", 55 | showCancelButton: true, 56 | showCloseButton: true, 57 | inputPlaceholder: "[支持批量(换行分隔)]", 58 | confirmButtonText: "确定", 59 | cancelButtonText: "取消", 60 | inputValidator: (value: string) => { 61 | if (!value) { 62 | return "文件路径不能为空"; 63 | } 64 | }, 65 | }, 66 | 67 | updateInfo: { 68 | title: `秒传链接提取 v${version} (${updateDate})`, 69 | showCloseButton: true, 70 | allowOutsideClick: false, 71 | confirmButtonText: "知道了", 72 | html: updateInfo, 73 | }, 74 | 75 | checkRecursive: { 76 | icon: "info", 77 | title: "包含文件夹, 是否递归生成?", 78 | text: "若选是, 将同时生成各级子文件夹下的文件", 79 | allowOutsideClick: false, 80 | focusCancel: true, 81 | showCancelButton: true, 82 | reverseButtons: true, 83 | showCloseButton: true, 84 | confirmButtonText: "是", 85 | cancelButtonText: "否", 86 | }, 87 | 88 | settingView: { 89 | title: "秒传链接提取 设置页", 90 | showCloseButton: true, 91 | showCancelButton: true, 92 | confirmButtonText: "确定", 93 | cancelButtonText: "取消", 94 | allowOutsideClick: false, 95 | html: ` `, 96 | }, 97 | 98 | settingWarning: { 99 | title: "设置成功 刷新页面生效", 100 | showCloseButton: true, 101 | allowOutsideClick: false, 102 | confirmButtonText: "知道了", 103 | }, 104 | 105 | selectNoFileWarning: { 106 | title: "请勾选要生成秒传的文件/文件夹", 107 | icon: "error", 108 | showCloseButton: true, 109 | confirmButtonText: "知道了", 110 | }, 111 | }; 112 | -------------------------------------------------------------------------------- /src/common/utils.tsx: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: mengzonefire 3 | * @Date: 2021-08-22 04:01:11 4 | * @LastEditTime: 2023-03-10 19:47:20 5 | * @LastEditors: mengzonefire 6 | * @Description: 存放工具函数 7 | */ 8 | 9 | import { baiduErrno, syncPathPrefix } from "@/baidu/common/const"; 10 | import { 11 | appError, 12 | copyFailBranchList, 13 | copyFailList, 14 | copySuccessList, 15 | TAG, 16 | } from "./const"; 17 | import { DuParser } from "./duParser"; 18 | 19 | /** 20 | * @description: 弹出一个文本提示框 21 | * @param {string} text 22 | */ 23 | export function showAlert(text: string): void { 24 | alert(`${TAG}:\n${text}`); 25 | } 26 | 27 | /** 28 | * @description: 解析文件信息, 返回转存结果列表html, 秒传链接, 失败文件个数, 成功的文件信息列表, 失败的文件信息列表 29 | * @param {Array} fileInfoList 文件信息数据列表 30 | */ 31 | export function parsefileInfo(fileInfoList: Array) { 32 | let bdcode = ""; 33 | let successInfo = ""; 34 | let failedInfo = ""; 35 | let successList = []; 36 | let failList = []; 37 | let failCodeDic = {}; 38 | fileInfoList.forEach((item) => { 39 | item.path = item.path.replace(syncPathPrefix, ""); // 移除同步页前缀 40 | // 成功文件 41 | if (0 === item.errno || undefined === item.errno) { 42 | successInfo += `

${item.path}

`; 43 | bdcode += `${item.md5}${item.md5s && "#" + item.md5s}#${item.size}#${ 44 | item.path 45 | }\n`; 46 | successList.push(item); 47 | } 48 | // 失败文件 49 | else { 50 | failList.push(item); 51 | if (String(item.errno) in failCodeDic) 52 | failCodeDic[String(item.errno)].push(item); 53 | else failCodeDic[String(item.errno)] = [item]; 54 | } 55 | }); 56 | for (let failCode in failCodeDic) { 57 | let failBranchInfo = ""; 58 | let failBranchList = failCodeDic[failCode]; 59 | failBranchList.forEach((item: any) => { 60 | failBranchInfo += `

${item.path}

`; 61 | }); 62 | failedInfo += `
${baiduErrno( 63 | Number(failCode) 64 | )}(#${Number( 65 | failCode 66 | )}):${copyFailBranchList}
${failBranchInfo}
`; 67 | } 68 | if (failedInfo) 69 | failedInfo = `
失败文件列表(点这里看失败原因):${copyFailList}
${failedInfo}
`; 70 | if (successInfo) 71 | successInfo = `
成功文件列表(点击展开):${copySuccessList}
${successInfo}
`; 72 | bdcode = bdcode.trim(); 73 | return { 74 | htmlInfo: 75 | successInfo && failedInfo 76 | ? successInfo + "


" + failedInfo 77 | : successInfo + failedInfo, 78 | bdcode: bdcode, 79 | successList: successList, 80 | failList: failList, 81 | }; 82 | } 83 | 84 | /** 85 | * @description: 获取分享页的文件列表 86 | */ 87 | export function getShareFileList() { 88 | const bdListInstance = unsafeWindow.require("system-core:context/context.js") 89 | .instanceForSystem.list; 90 | let selectList = bdListInstance.getSelected(); 91 | if (!selectList.length) selectList = bdListInstance.getCurrentList(); 92 | return selectList; 93 | } 94 | 95 | /** 96 | * @description: 获取选择的文件列表(旧版界面) 97 | */ 98 | export function getSelectedFileListLegacy() { 99 | return unsafeWindow 100 | .require("system-core:context/context.js") 101 | .instanceForSystem.list.getSelected(); 102 | } 103 | 104 | /** 105 | * @description: 获取选择的文件列表(新版界面) 106 | * 我从这里抄的, 谢谢你: https://greasyfork.org/zh-CN/scripts/436446 107 | */ 108 | export function getSelectedFileListNew() { 109 | return document.querySelector(".nd-main-list, .nd-new-main-list").__vue__ 110 | .selectedList; 111 | } 112 | 113 | /** 114 | * @description: 将data键值对转换为query字符串 115 | * @param {any} data 116 | * @return {string} query 117 | */ 118 | export function convertData(data: any): string { 119 | let query = ""; 120 | for (let key in data) query += `&${key}=${encodeURIComponent(data[key])}`; 121 | return query; 122 | } 123 | 124 | /** 125 | * @description: 从剪贴板获取字符串数据 126 | * @return {string} bdlink 127 | */ 128 | export async function parseClipboard(): Promise { 129 | try { 130 | let bdlink = await navigator.clipboard.readText(); 131 | if (!DuParser.parse(bdlink).length) return ""; 132 | return bdlink; 133 | } catch (error) { 134 | showAlert(appError.ClipboardPremissionErr); 135 | return ""; 136 | } 137 | } 138 | 139 | /** 140 | * @description: 解密已加密的md5 141 | * @param {string} md5 (加密) 142 | * @return {string} md5 (解密) 143 | */ 144 | export function decryptMd5(md5: string): string { 145 | if ( 146 | !( 147 | (parseInt(md5[9]) >= 0 && parseInt(md5[9]) <= 9) || 148 | (md5[9] >= "a" && md5[9] <= "f") 149 | ) 150 | ) 151 | return decrypt(md5); 152 | else return md5; 153 | 154 | function decrypt(encryptMd5: string): string { 155 | let key = (encryptMd5[9].charCodeAt(0) - "g".charCodeAt(0)).toString(16); 156 | let key2 = encryptMd5.slice(0, 9) + key + encryptMd5.slice(10); 157 | let key3 = ""; 158 | for (let a = 0; a < key2.length; a++) 159 | key3 += (parseInt(key2[a], 16) ^ (15 & a)).toString(16); 160 | let md5 = 161 | key3.slice(8, 16) + 162 | key3.slice(0, 8) + 163 | key3.slice(24, 32) + 164 | key3.slice(16, 24); 165 | return md5; 166 | } 167 | } 168 | 169 | /** 170 | * @description: 用于解决#31039报错 171 | * @param {string} path 原文件路径 172 | * @return {string} 修改文件后缀的路径 173 | */ 174 | export function suffixChange(path: string): string { 175 | let suffix = path.substring(path.lastIndexOf(".") + 1); // 获取后缀 176 | return path.substring(0, path.length - suffix.length) + reverseStr(suffix); 177 | } 178 | 179 | /** 180 | * @description: 逆转字符串大小写 181 | * @param {string} str 输入字符串 182 | * @return {string} 处理后的字符串 183 | */ 184 | function reverseStr(str: string): string { 185 | let newStr = ""; 186 | for (let i = 0; i < str.length; i++) { 187 | let reverseChar: string; 188 | if (str.charAt(i) >= "a") reverseChar = str.charAt(i).toUpperCase(); 189 | else if (str.charAt(i) >= "A") reverseChar = str.charAt(i).toLowerCase(); 190 | else reverseChar = str.charAt(i); 191 | newStr += reverseChar; 192 | } 193 | return newStr; 194 | } 195 | 196 | // 下方四个function用于分享页生成秒传 197 | // 依旧是从这里抄的: https://greasyfork.org/zh-CN/scripts/436446 198 | function getCookie(name: string) { 199 | let arr = document.cookie.replace(/\s/g, "").split(";"); 200 | for (let i = 0, l = arr.length; i < l; i++) { 201 | let tempArr = arr[i].split("="); 202 | if (tempArr[0] === name) { 203 | return decodeURIComponent(tempArr[1]); 204 | } 205 | } 206 | return ""; 207 | } 208 | 209 | export function getLogid() { 210 | let ut = unsafeWindow.require("system-core:context/context.js") 211 | .instanceForSystem.tools.baseService; 212 | return ut.base64Encode(getCookie("BAIDUID")); 213 | } 214 | 215 | export function getSurl() { 216 | let reg = /(s\/|surl=)([a-zA-Z0-9_-]+)/; 217 | if (reg.test(location.href)) { 218 | return location.href.match(reg)[2]; 219 | } 220 | return ""; 221 | } 222 | 223 | export function getExtra() { 224 | let seKey = decodeURIComponent(getCookie("BDCLND")); 225 | return "{" + '"sekey":"' + seKey + '"' + "}"; 226 | } 227 | -------------------------------------------------------------------------------- /src/components/updateInfo.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

更新日志:

4 |

修复生成错误秒传的问题: 23.4.25发布的 2.7.3, 2.7.4 这两个版本会生成错误的秒传, 错误秒传在文件上传者账号正常转存, 但在其他的账号会报错 秒传未生效#404, 出现此问题注意使用当前版本重新生成秒传

5 |
6 | 39 |
40 |
-------------------------------------------------------------------------------- /src/css/app.css: -------------------------------------------------------------------------------- 1 | /*自定义单选框样式*/ 2 | .mzf_check { 3 | display: inline-block; 4 | background-color: white; 5 | border-radius: 5px; 6 | border: 1px solid #d3d3d3; 7 | width: 20px; 8 | height: 20px; 9 | text-align: center; 10 | vertical-align: middle; 11 | line-height: 20px; 12 | margin-left: 10px; 13 | } 14 | .mzf_check_ori:checked + .mzf_check { 15 | background-color: #eee; 16 | } 17 | .mzf_check_ori:checked + .mzf_check::after { 18 | content: "✓"; 19 | } 20 | .mzf_check_ori { 21 | display: none; 22 | } 23 | 24 | /*新版度盘页面的按钮样式(直接拷贝)*/ 25 | .mzf_new_btn { 26 | -webkit-text-size-adjust: 100%; 27 | -webkit-font-smoothing: antialiased; 28 | -webkit-tap-highlight-color: transparent; 29 | vertical-align: middle; 30 | font: inherit; 31 | overflow: visible; 32 | text-transform: none; 33 | font-family: SFUIText, PingFangSC-Regular, Helvetica Neue, Helvetica, Arial, 34 | sans-serif; 35 | display: inline-block; 36 | line-height: 1; 37 | white-space: nowrap; 38 | cursor: pointer; 39 | background: #fff; 40 | text-align: center; 41 | box-sizing: border-box; 42 | outline: 0; 43 | margin: 0; 44 | transition: 0.1s; 45 | color: #fff; 46 | background-color: #06a7ff; 47 | font-weight: 700; 48 | padding: 8px 24px; 49 | height: 32px; 50 | font-size: 14px; 51 | border-radius: 16px; 52 | border: none; 53 | margin-left: 8px; 54 | } 55 | -------------------------------------------------------------------------------- /src/css/app.scss: -------------------------------------------------------------------------------- 1 | /*按钮样式*/ 2 | .mzf_btn { 3 | text-align: center; 4 | font-size: 0.85em; 5 | color: #09aaff; 6 | border: 2px solid #c3eaff; 7 | border-radius: 4px; 8 | margin-left: 5px; 9 | padding: 10px; 10 | padding-top: 5px; 11 | padding-bottom: 5px; 12 | cursor: pointer; 13 | } 14 | 15 | /*按钮样式2*/ 16 | .mzf_btn2 { 17 | text-align: center; 18 | color: #09aaff; 19 | margin-left: 5px; 20 | cursor: pointer; 21 | } 22 | 23 | /*超链接样式*/ 24 | .mzf_link { 25 | font-family: inherit; 26 | color: #09aaff; 27 | text-decoration: none; 28 | vertical-align: baseline; 29 | } 30 | 31 | /*行样式*/ 32 | .mzf_text { 33 | font-feature-settings: "lnum"; 34 | -webkit-font-smoothing: antialiased; 35 | font-family: inherit; 36 | color: #545454; 37 | font-weight: 400; 38 | word-break: break-word; 39 | -webkit-tap-highlight-color: transparent; 40 | margin: 0; 41 | padding: 0; 42 | width: 100%; 43 | height: 34px; 44 | display: block; 45 | line-height: 34px; 46 | text-align: center; 47 | white-space: nowrap; 48 | } 49 | 50 | /*折叠框箭头样式*/ 51 | .mzf_arrow { 52 | margin-right: 5px; 53 | transform: rotate(180deg); 54 | transition: transform 0.2s; 55 | fill: none; 56 | stroke: gray; 57 | } 58 | 59 | /*折叠框*/ 60 | .mzf_details { 61 | cursor: pointer; 62 | } 63 | 64 | .mzf_details summary { 65 | white-space: nowrap; 66 | } 67 | 68 | /*折叠框内容*/ 69 | .mzf_content { 70 | max-height: 0; 71 | margin: 0; 72 | transition: max-height 0.5s; 73 | overflow: hidden; 74 | } 75 | 76 | /*折叠框动画*/ 77 | .mzf_details[open] { 78 | > summary > svg { 79 | transform: rotate(0deg); 80 | } 81 | + .mzf_content { 82 | max-height: 100%; 83 | } 84 | } 85 | 86 | /*html容器样式*/ 87 | .mzf_html_container { 88 | grid-template-columns: minmax(0, 100%); 89 | align-self: center; 90 | justify-self: center; 91 | width: 32em; 92 | max-width: 100%; 93 | } 94 | 95 | .mzf_updateInfo { 96 | border: 1px #000000; 97 | width: 100%; 98 | margin: 0 auto; 99 | } 100 | 101 | .mzf_updateInfo span { 102 | vertical-align: baseline; 103 | } 104 | -------------------------------------------------------------------------------- /src/types/css.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.css" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /src/types/html.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.html" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /src/types/scss.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.scss" { 2 | const content: string; 3 | export default content; 4 | } 5 | -------------------------------------------------------------------------------- /src/types/types.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | declare global { 3 | interface FileInfo { 4 | path: string; // 文件路径 5 | isdir?: number; // 是否为目录 6 | errno?: number; // =0成功, !=0为失败 7 | size?: number; // 文件大小, 若为目录则=0 8 | md5?: string; // md5 9 | md5s?: string; // 前256KiB md5 10 | fs_id?: string; // 云端文件id 11 | retry_996?: boolean; // 用于判断是否使用备用生成接口 12 | } 13 | interface String { 14 | fromBase64: any; 15 | toBase64: any; 16 | } 17 | interface Element { 18 | __vue__: any; 19 | } 20 | interface HTMLElement { 21 | value: string; 22 | checked: boolean; 23 | } 24 | interface Window { 25 | require: any; 26 | locals: any; 27 | yunData: any; 28 | } 29 | // var __non_webpack_require__: any; 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/", // 打包到的目录 5 | "noImplicitAny": false, 6 | "noUnusedLocals": true, 7 | "noUnusedParameters": true, 8 | "module": "ES2015", 9 | "moduleResolution": "Node", 10 | "target": "es5", // 转化成的目标语言 设为es5以支持更多浏览器 11 | "baseUrl": ".", 12 | "paths": { "@/*": ["src/*"] }, 13 | "types": ["node", "tampermonkey", "jquery"], // 引入的全局类型声明 14 | "typeRoots": ["./node_modules/@types"], 15 | "lib": ["dom", "es2015"], 16 | "jsx": "react", 17 | "allowJs": false, 18 | "allowSyntheticDefaultImports": true 19 | }, 20 | "include": ["src/**/*.tsx", "src/**/*.ts"], // 要打包的文件 21 | "exclude": ["node_modules", "*.test.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 2 | const WebpackUserscript = require("webpack-userscript"); 3 | const TerserPlugin = require("terser-webpack-plugin"); 4 | const path = require("path"); 5 | // const nodeExternals = require("webpack-node-externals"); 6 | const requireFunc = 7 | typeof __webpack_require__ === "function" ? __non_webpack_require__ : require; // 忽略源码中的require功能 8 | module.exports = { 9 | mode: "production", 10 | entry: path.resolve(__dirname, "src", "app.tsx"), 11 | externalsPresets: { node: true }, 12 | // externals: [nodeExternals()], 13 | resolve: { 14 | extensions: [".js", ".ts", ".tsx", ".json"], 15 | alias: { 16 | "@": path.resolve(__dirname, "src/"), 17 | }, 18 | }, 19 | output: { 20 | filename: "秒传连接提取.user.js", 21 | path: path.resolve(__dirname, "dist"), 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.html$/, 27 | use: [ 28 | { 29 | loader: "text-loader", 30 | }, 31 | ], 32 | exclude: /node_modules/, 33 | }, 34 | { 35 | test: /\.tsx?$/, 36 | use: [ 37 | { 38 | loader: "ts-loader", 39 | options: { 40 | configFile: path.resolve(__dirname, "./tsconfig.json"), 41 | }, 42 | }, 43 | ], 44 | exclude: /node_modules/, 45 | }, 46 | { 47 | test: /\.s[ac]ss$/i, 48 | use: [ 49 | { 50 | loader: "text-loader", 51 | }, 52 | "sass-loader", 53 | ], 54 | exclude: /node_modules/, 55 | }, 56 | { 57 | test: /\.css$/, 58 | use: [ 59 | { 60 | loader: "text-loader", 61 | }, 62 | ], 63 | exclude: /node_modules/, 64 | }, 65 | ], 66 | }, 67 | plugins: [ 68 | new MiniCssExtractPlugin(), 69 | // 生成userscript header信息 70 | new WebpackUserscript({ 71 | headers: { 72 | name: "秒传链接提取", 73 | "name:en": `[name]`, 74 | version: `[version]`, 75 | author: `[author]`, 76 | license: `GPLv3`, 77 | icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABBUlEQVR4AZTTJRBUURTH4TtDwXuPdPrgbhHXiksf3CPucRNScHd3d3d3uO9bKeu7b79+fun8Q17CNHyMMUqaiPE4fEyYVjjGNKnNwQ4lpgV8lManEfwfosLHEGPU1N3ZnAv4qlT+NiQ56uPWSjKBrztUSnIaB66sY1vgxgxoMXB5NbsCB9rxcB5fN2M5/16nCFxeS6YTezpzsB1Pu/C2O7/78/99eYBYHXh+gqdHObGIK4GHgevjVIt1AgAnhvE4cGe8euoHbizgYuD2RGgx8O0RpwIPRmsmJDGqcrANd3pLo/qVr03hUlcpfSwf0/vD3JwkPdPK5/zhkOz+/f1FIDv/RcnOAEjywH/DhgADAAAAAElFTkSuQmCC", 78 | namespace: "moe.cangku.mengzonefire", 79 | supportURL: `https://github.com/mengzonefire/rapid-upload-userscript/issues`, 80 | homepageURL: `[homepage]`, 81 | contributionURL: "https://afdian.net/@mengzonefire", 82 | description: `[description]`, 83 | "description:en": 84 | "input bdlink to get files or get bdlink for Baidu™ WebDisk.", 85 | compatible: [ 86 | "firefox Violentmonkey", 87 | "firefox Tampermonkey", 88 | "chrome Violentmonkey", 89 | "chrome Tampermonkey", 90 | "edge Violentmonkey", 91 | "edge Tampermonkey", 92 | ], 93 | match: [ 94 | "*://pan.baidu.com/disk/home*", 95 | "*://pan.baidu.com/disk/main*", 96 | "*://pan.baidu.com/disk/synchronization*", 97 | "*://pan.baidu.com/s/*", 98 | "*://yun.baidu.com/disk/home*", 99 | "*://yun.baidu.com/disk/main*", 100 | "*://yun.baidu.com/disk/synchronization*", 101 | "*://yun.baidu.com/s/*", 102 | "*://wangpan.baidu.com/disk/home*", 103 | "*://wangpan.baidu.com/disk/main*", 104 | "*://wangpan.baidu.com/disk/synchronization*", 105 | "*://wangpan.baidu.com/s/*", 106 | ], 107 | grant: [ 108 | "GM_setValue", 109 | "GM_getValue", 110 | "GM_deleteValue", 111 | "GM_setClipboard", 112 | "GM_addStyle", 113 | "GM_xmlhttpRequest", 114 | "GM_registerMenuCommand", 115 | "unsafeWindow", 116 | ], 117 | "run-at": "document-body", 118 | connect: ["baidu.com", "baidupcs.com", "cdn.jsdelivr.net", "*"], 119 | downloadURL: 120 | "https://greasyfork.org/scripts/424574/code/%E7%A7%92%E4%BC%A0%E9%93%BE%E6%8E%A5%E6%8F%90%E5%8F%96.user.js", 121 | updateURL: 122 | "https://greasyfork.org/scripts/424574/code/%E7%A7%92%E4%BC%A0%E9%93%BE%E6%8E%A5%E6%8F%90%E5%8F%96.user.js", 123 | antifeature: 124 | 'referral-link 23.4.5: 加了一个百度官方的网盘会员推广 (从那里开通可使作者获得佣金), 觉得碍眼可以点 "不再显示" 永久隐藏', 125 | }, 126 | pretty: true, 127 | }), 128 | ], 129 | optimization: { 130 | minimize: false, 131 | // 完全禁用压缩(会导致下面的配置项全部失效), 防止在greasyfork上被举报为加密/最小化代码 132 | minimizer: [ 133 | new TerserPlugin({ 134 | parallel: true, 135 | extractComments: false, 136 | terserOptions: { 137 | // 以下四项为禁用代码压缩 + 不压缩标识符 138 | mangle: false, 139 | compress: false, 140 | keep_fnames: true, 141 | keep_classnames: true, 142 | format: { 143 | // 输出格式化, 防止在greasyfork上被举报为最小化代码 144 | beautify: true, 145 | // 删除注释 146 | comments: false, 147 | }, 148 | }, 149 | }), 150 | ], 151 | }, 152 | }; 153 | --------------------------------------------------------------------------------