├── LICENSE ├── README.md ├── clock_in.js ├── eval_script.js ├── eval_script ├── qx.txt ├── qx_script.txt ├── sg.sgmodule └── sg_script.sgmodule ├── jd_price.js ├── jd_price_lite.js ├── loon_sub.conf ├── nf_rating.js ├── nf_rating_season.js ├── qx_sub.txt ├── sg_sub.sgmodule ├── tb_pre.js ├── tb_price.js ├── tb_price_lite.js ├── tool.js ├── wb_ad.js └── wb_launch.js /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 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Surge 2 | 3 | Netflix ratings(IMDb、douban) 4 | ```properties 5 | [Script] 6 | nf_rating.js = type=http-request,pattern=^https?:\/\/ios(-.*)?\.prod\.ftl\.netflix\.com\/iosui\/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 7 | nf_rating.js = type=http-response,requires-body=1,pattern=^https?:\/\/ios(-.*)?\.prod\.ftl\.netflix\.com\/iosui\/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 8 | [MITM] 9 | hostname = ios-*.prod.ftl.netflix.com,ios.prod.ftl.netflix.com 10 | ``` 11 | 12 | Wb 13 | ```properties 14 | [Script] 15 | http-response ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js 16 | http-response ^https?://m?api\.weibo\.c(n|om)/2/(messageflow/notice|search/(container_timeline|finder)|statuses/(container_timeline_hot|container_timeline_unread|container_timeline|unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info|remind/unread_count) requires-body=1,max-size=-1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js 17 | [MITM] 18 | hostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com 19 | ``` 20 | 21 | ~~Display jd historical price~~ 22 | ```properties 23 | [Script] 24 | http-response ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js 25 | [MITM] 26 | hostname = api.m.jd.com 27 | ``` 28 | 29 | ~~Display taobao historical price~~ 30 | ```properties 31 | [Script] 32 | http-response ^http://.+/amdc/mobileDispatch requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 33 | http-response ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 34 | [MITM] 35 | hostname = trade-acs.m.taobao.com 36 | ``` 37 | 38 | # Quan-X 39 | 40 | Netflix ratings(IMDb、douban) 41 | ```properties 42 | [rewrite_local] 43 | ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-request-header https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 44 | ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 45 | [mitm] 46 | hostname = ios-*.prod.ftl.netflix.com,ios.prod.ftl.netflix.com 47 | ``` 48 | 49 | Wb 50 | ```properties 51 | [rewrite_local] 52 | ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js 53 | ^https?://m?api\.weibo\.c(n|om)/2/(messageflow/notice|search/(container_timeline|finder)|statuses/(container_timeline_hot|container_timeline_unread|container_timeline|unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info|remind/unread_count) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js 54 | [mitm] 55 | hostname = api.weibo.cn, mapi.weibo.com, *.uve.weibo.com 56 | ``` 57 | 58 | ~~Display jd historical price~~ 59 | ```properties 60 | [rewrite_local] 61 | ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js 62 | [mitm] 63 | hostname = api.m.jd.com 64 | ``` 65 | 66 | ~~Display taobao historical price~~ 67 | ```properties 68 | [rewrite_local] 69 | ^http://.+/amdc/mobileDispatch url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 70 | ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 71 | [mitm] 72 | hostname = trade-acs.m.taobao.com 73 | ``` 74 | -------------------------------------------------------------------------------- /clock_in.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | 每日打卡提醒(corn "0 9,18 * * 1-5" 周一到周五,早九晚六)+ 每日壹句(有道词典)+ 跳转钉钉打卡页面 4 | */ 5 | 6 | const $tool = new Tool() 7 | $tool.get('https://dict.youdao.com/infoline/style/cardList?mode=publish&client=mobile&style=daily&size=2', function (error, response, data) { 8 | let obj = JSON.parse(data); 9 | let date = new Date(); 10 | let isAM = date.getHours() < 12 ? true : false; 11 | let title = 'Clock' + (isAM ? ' in' : ' out') + (isAM ? ' ☀️' : ' 🌙'); 12 | let subtitle = ''; 13 | let scheme = 'dingtalk://dingtalkclient/page/link?url=https://attend.dingtalk.com/attend/index.html'; 14 | let content = ""; 15 | let option = {"open-url" : scheme}; 16 | if (!error) { 17 | if (obj && obj.length > 1) { 18 | let yi = obj[1]; 19 | content = yi.title + '\n' + yi.summary; 20 | option["media-url"] = yi.image[0]; 21 | } 22 | } 23 | $tool.notify(title, subtitle, content, option); 24 | $done(); 25 | }) 26 | 27 | function Tool() { 28 | _node = (() => { 29 | if (typeof require == "function") { 30 | const request = require('request') 31 | return ({ request }) 32 | } else { 33 | return (null) 34 | } 35 | })() 36 | _isLoon = typeof $loon !== "undefined"; 37 | _isSurge = typeof $httpClient != "undefined" && !_isLoon; 38 | _isQuanX = typeof $task != "undefined" 39 | this.isSurge = _isSurge 40 | this.isQuanX = _isQuanX 41 | this.isResponse = typeof $response != "undefined" 42 | this.notify = (title, subtitle, message, option) => { 43 | if (_isQuanX) $notify(title, subtitle, message, option) 44 | if (_isSurge) $notification.post(title, subtitle, message, {"url":option["open-url"]}) 45 | if (_isLoon) $notification.post(title, subtitle, message, option["open-url"]) 46 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 47 | } 48 | this.write = (value, key) => { 49 | if (_isQuanX) return $prefs.setValueForKey(value, key) 50 | if (_isSurge) return $persistentStore.write(value, key) 51 | } 52 | this.read = (key) => { 53 | if (_isQuanX) return $prefs.valueForKey(key) 54 | if (_isSurge) return $persistentStore.read(key) 55 | } 56 | this.get = (options, callback) => { 57 | if (_isQuanX) { 58 | if (typeof options == "string") options = { url: options } 59 | options["method"] = "GET" 60 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 61 | } 62 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 63 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 64 | } 65 | this.post = (options, callback) => { 66 | if (_isQuanX) { 67 | if (typeof options == "string") options = { url: options } 68 | options["method"] = "POST" 69 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 70 | } 71 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 72 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 73 | } 74 | _status = (response) => { 75 | if (response) { 76 | if (response.status) { 77 | response["statusCode"] = response.status 78 | } else if (response.statusCode) { 79 | response["status"] = response.statusCode 80 | } 81 | } 82 | return response 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /eval_script/qx.txt: -------------------------------------------------------------------------------- 1 | hostname = api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios.prod.ftl.netflix.com,bea.sportq.com,api.meiyan.com,api.gao1gps.cn,avoscloud.com,app.flashdown365.com,m.samh.xndm.tech,mob2015.kekenet.com,vipapi.jxedt.com,api.interpreter.caiyunai.com,pocketlists.com,book.haitunwallet.com,mubu.com,app.xunjiepdf.com,miaow.yiyongcad.com,api.lennou.com,api.gkocr.com,vira.llsapp.com,commerce-.*api.faceu.mobi,commerce-api.faceu.mobi,pan.baidu.com,api.revenuecat.com,api.rr.tv,editorapi.115.com,api.lakecoloring.com,ctrl.playcvn.com,dict.eudic.net,m.client.10010.com,api.wakamoment.ga,*.bh3.com,api.diyidan.net,api.flexibits.com,api.jiaonizuocai.com,api.sololearn.com,tncj.hortorgames.com,bkcd.b-cdn.net,souhu.mett.me,ayk.tmdidi.com,m.pearkin.com,www.baidu.com2.club,claritywallpaper.com,bookapi.ihuman.com,rest.zhibo.tv,note.youdao.com,billing.peakcloud.org,api.ithome.com,www.xmind.cn,*.arten.cn,api.weiqire.com,api.shimo.im,pay.wecut.com,*.videostarapp.com,app.api.versa-ai.com,*.bjxkhc.com,api.591master.com,jdytv.cn,user.shywck.com,*.xunjie*.com,api.psy-1.com,snailsleep.net,mp.weixin.qq.com,api.bilibili.com,app.bilibili.com,*.zhihu.com,aweme*.snssdk.com,*.kuwo.cn,vip1.kuwo.cn,*.xiaoxiao*.com,api*.tiktokv.com,*.musical.ly,*.amemv.com,p.du.163.com,getuserinfo.321mh.com,getuserinfo-globalapi.zymk.cn,ios.fuliapps.com,vsco.co,api.vnision.com,*.my10api.com,sp.kaola.com,r.inews.qq.com,apple.fuliapps.com,newdrugs.dxy.cn,app101.avictown.cc,api.hlo.xyz,api.ijo.xyz,www.luqijianggushi.com,account.wps.*,u.kanghuayun.com,api.gyrosco.pe,api1.dobenge.cn,api.mvmtv.com,mitaoapp.yeduapp.com,origin-prod-phoenix.jibjab.com,www.3ivf.com,pay.guoing.com,api.termius.com,api.bjxkhc.com,viva.v21xy.com,biz.caiyunapp.com,api.gotokeep.com,ap*.intsig.net,mp.bybutter.com,api.vuevideo.net,api.picsart.c*,api.meiease.c*,splice.oracle.*.com,api.gamer.com.tw,ios.xiangjiaoapps.com,apple.xiangjiaoapps.com,*.lagoapps.com,*.xiangxiangapps.com,avatar-nct.nixcdn.com,spclient.wg.spotify.com,oa.zalo.me,api.unfold.app,viva-asia1.vvbrd.com,graph.nhaccuatui.com,api.memrise.com,api.sync.me,pool.elsanow.io,lambda.us-east-1.amazonaws.com,api.mondlylanguages.com,api.busuu.com,owa.videoshowiosglobalserver.com:0,accounts.elevateapp.net,purchases.ws.pho.to,api-intl.mr.meitu.com,bmall.camera360.com,api.tv.zing.vn,api.calm.com,www.calm.com,api.global.mp3.zing.vn,apimboom2.globaldelight.net,photos.adobe.io,license.pdfexpert.com,subs.platforms.team,apic.musixmatch.com,api.getmimo.com,engbright.com,api.lingokids.com,www.peacefulsoundsapp.com,duolingo-leaderboards-prod.duolingo.com,mobile-api.adguard.com,api.blinkist.com,api-kinemaster-assetstore.*,api.pushover.net,api.overhq.com,receipt-validator.herewetest.com,lcs-mobile-cops.adobe.io,education.github.com,backend.getdrafts.com,ssl-api.itranslateapp.com,sk.ulysses.app,dayone.me,license.enpass.io,*.grammarly.com,api.keepkeep.com,planner5d.com,secure.istreamer.com,www.api.monkeyuni.net,api.textnow.me 2 | 3 | ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body eval_script.js 4 | 5 | ^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/photos/pic_recommend_status|video/tiny_stream_video_list) url script-response-body eval_script.js 6 | 7 | ^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad url script-response-body eval_script.js 8 | 9 | ^https://api.zhihu.com/moments/recommend url script-response-body eval_script.js 10 | 11 | ^https://api.zhihu.com/topstory/recommend url script-response-body eval_script.js 12 | 13 | https://api.zhihu.com/v4/questions url script-response-body eval_script.js 14 | 15 | ^https://api.zhihu.com/people/ url script-response-body eval_script.js 16 | 17 | ^https://api.zhihu.com/market/header url script-response-body eval_script.js 18 | 19 | https://app.bilibili.com/x/v2/space\?access_key url script-response-body eval_script.js 20 | 21 | https://app.bilibili.com/x/resource/show/tab\?access_key url script-response-body eval_script.js 22 | 23 | https://app.bilibili.com/x/v2/feed/index\?access_key url script-response-body eval_script.js 24 | 25 | https://app.bilibili.com/x/v2/view\?access_key url script-response-body eval_script.js 26 | 27 | https://api.bilibili.com/x/v2/reply/main\?access_key url script-response-body eval_script.js 28 | 29 | https://api.live.bilibili.com/xlive/app-room/v1/index/getInfoByRoom\?access_key url script-response-body eval_script.js 30 | 31 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/aweme\/post\/ url script-response-body eval_script.js 32 | 33 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/feed\/ url script-response-body eval_script.js 34 | 35 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/follow\/feed\/ url script-response-body eval_script.js 36 | 37 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/nearby\/feed\/ url script-response-body eval_script.js 38 | 39 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/search\/item\/ url script-response-body eval_script.js 40 | 41 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/general\/search\/single\/ url script-response-body eval_script.js 42 | 43 | ^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/hot\/search\/video\/list\/ url script-response-body eval_script.js 44 | 45 | ^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/user\/vip|vip\/spi/mservice) url script-response-body eval_script.js 46 | 47 | https:\/\/.*\/getGlobalData url script-response-body eval_script.js 48 | 49 | ^http(s)://api.bjxkhc.com/index.php/app/ios/(vod/show|(user|vod|topic|type)/index) url script-response-body eval_script.js 50 | 51 | ^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json url script-response-body eval_script.js 52 | 53 | ^https?:\/\/getuserinfo\.321mh\.com\/app_api\/v5\/getuserinfo\/ url script-response-body eval_script.js 54 | 55 | ^https://getuserinfo-globalapi.zymk.cn/app_api/v5/(getuserinfo|coin_account|getuserinfo_ticket|getcomicinfo)/ url script-response-body eval_script.js 56 | 57 | https:\/\/ap(p|i)\.bilibili\.com\/((pgc\/player\/api\/playurl)|(x\/v2\/account\/myinfo\?)|(x\/v2\/account/mine\?)) url script-response-body eval_script.js 58 | 59 | ^https?:\/\/vsco\.co\/api\/subscriptions\/2.1\/user-subscriptions\/ url script-response-body eval_script.js 60 | 61 | ^https?:\/\/api\.vnision\.com\/v1\/(users\/|banners) url script-response-body eval_script.js 62 | 63 | ^https?:\/\/.+\.(my10api|(.*91.*))\.(com|tips|app|xyz)(:\d{2,5})?\/api.php$ url script-response-body eval_script.js 64 | 65 | ^https://sp\.kaola\.com/api/openad$ url script-response-body eval_script.js 66 | 67 | ^https://r\.inews\.qq.com\/get(QQNewsUnreadList|RecommendList) url script-response-body eval_script.js 68 | 69 | ^https?:\/\/.*\.(lago|fuli|xiang(jiao|xiang))apps\.com\/(ucp\/index|getGlobalData|.+\/reqplay\/) url script-response-body eval_script.js 70 | 71 | ^https?:\/\/(i|newdrugs)\.dxy\.cn\/(snsapi\/username\/|app\/user\/(pro\/stat\?|init\?timestamp=)) url script-response-body eval_script.js 72 | 73 | ^https?:\/\/(.+)\.(\w{2,3})(:?\d*)\/(api\/public\/\?service=Live\.checkLive$|public\/\/\?service=Live\.roomCharge$|lg\/video\/loadVideoFees\.do$) url script-response-body eval_script.js 74 | 75 | ^https:\/\/www\.luqijianggushi\.com\/api\/v2\/user\/get url script-response-body eval_script.js 76 | 77 | ^https://account.wps.*/api/users/ url script-response-body eval_script.js 78 | 79 | ^https:\/\/api\.gyrosco\.pe\/v1\/account\/$ url script-response-body eval_script.js 80 | 81 | ^https:\/\/api1\.dobenge\.cn\/api\/user\/getuserinfo url script-response-body eval_script.js 82 | 83 | ^https:\/\/api\.mvmtv\.com\/index\.php.*(c=user.*a=info|a=addr.*vid=.*) url script-response-body eval_script.js 84 | 85 | ^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user url script-response-body eval_script.js 86 | 87 | https:\/\/api\.termius\.com\/api\/v3\/bulk\/account\/ url script-response-body eval_script.js 88 | 89 | ^https:\/\/viva\.v21xy\.com\/api\/rest\/u\/vip url script-response-body eval_script.js 90 | 91 | ^https:\/\/biz\.caiyunapp\.com\/v2\/user\?app_name\=weather url script-response-body eval_script.js 92 | 93 | ^https:\/\/api\.gotokeep\.com\/(.+\/subject|.+\/dynamic) url script-response-body eval_script.js 94 | 95 | ^https:\/\/(api|api-cs)\.intsig\.net\/purchase\/cs\/query_property\? url script-response-body eval_script.js 96 | 97 | ^https:\/\/api\.vuevideo\.net\/api\/v1\/(users\/.+\/profile|subtitle\/prepare) url script-response-body eval_script.js 98 | 99 | ^https?:\/\/mp\.bybutter\.com\/mood\/(official-templates|privileges) url script-response-body eval_script.js 100 | 101 | ^https:\/\/api\.(picsart|meiease)\.c(n|om)\/users\/show\/me\.json url script-response-body eval_script.js 102 | 103 | ^https:\/\/splice\.oracle\.\w+\.com\/devices\/me url script-response-body eval_script.js 104 | 105 | https:\/\/pan\.baidu\.com\/rest\/2\.0\/membership\/user url script-response-body eval_script.js 106 | 107 | ^https?://.*\.snssdk\.com/bds/(feed/stream|comment/cell_reply|cell/cell_comment|cell/detail|ward/list|user/favorite|user/cell_coment|user/cell_userfeed|user/publish_list) url script-response-body eval_script.js 108 | 109 | ^https:\/\/viva-asia1\.vvbrd\.com\/api\/rest\/u\/vip* url script-response-body eval_script.js 110 | 111 | ^https:\/\/api\.unfold\.app\/v1\/ios\/receipts$ url script-response-body eval_script.js 112 | 113 | ^https:\/\/graph\.nhaccuatui\.com\/.*\/users\/info* url script-response-body eval_script.js 114 | 115 | ^https:\/\/api\.memrise\.com\/.+\/(me\/$|dashboard\/$|leaderboards\/following\/) url script-response-body eval_script.js 116 | 117 | ^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user$ url script-response-body eval_script.js 118 | 119 | ^https:\/\/buy\.itunes\.apple\.com\/verifyReceipt$ url script-response-body eval_script.js 120 | 121 | ^https:\/\/api\.sync\.me\/api\/purchases\/(report_purchases|get_purchases) url script-response-body eval_script.js 122 | 123 | ^https:\/\/pool\.elsanow\.io\/user\/api\/v1\/purchase$ url script-response-body eval_script.js 124 | 125 | ^https:\/\/lambda\.us-east-1\.amazonaws\.com/.*/functions\/prod-4-syncPurchases\/invocations$ url script-response-body eval_script.js 126 | 127 | ^https:\/\/api\.mondlylanguages\.com\/v1\/ios\/user\/sync$ url script-response-body eval_script.js 128 | 129 | ^https:\/\/api\.busuu\.com\/users\/me* url script-response-body eval_script.js 130 | 131 | ^https:\/\/owa\.videoshowiosglobalserver\.com\/.*\/iosPayClient url script-response-body eval_script.js 132 | 133 | ^https:\/\/accounts\.elevateapp\.net\/api\/users\?user%5Bauthentication_token* url script-response-body eval_script.js 134 | 135 | ^https:\/\/api-intl\.mr\.meitu\.com/.*/subs_offer_elg$ url script-response-body eval_script.js 136 | 137 | ^https:\/\/bmall\.camera360\.com\/api\/(iap\/check-receipt$|mix\/getinfo$) url script-response-body eval_script.js 138 | 139 | ^https?:\/\/api\.tv\.zing\.vn\/.*/user* url script-response-body eval_script.js 140 | 141 | ^https:\/\/api\.calm\.com\/me$ url script-response-body eval_script.js 142 | 143 | ^https:\/\/photos\.adobe\.io\/v2\/accounts* url script-response-body eval_script.js 144 | 145 | ^https:\/\/license\.pdfexpert\.com\/api\/1\.0\/pdfexpert6\/subscription\/(refresh$|check$) url script-response-body eval_script.js 146 | 147 | ^https:\/\/subs\.platforms\.team\/.+\/apple\/verify$ url script-response-body eval_script.js 148 | 149 | ^https:\/\/apic\.musixmatch\.com\/ws\/.*\/config\.get url script-response-body eval_script.js 150 | 151 | ^https:\/\/api\.getmimo\.com\/v1\/subscriptions$ url script-response-body eval_script.js 152 | 153 | ^https:\/\/api\.revenuecat\.com\/.+\/(receipts$|subscribers\/[a-zA-Z0-9_-]*$) url script-response-body eval_script.js 154 | 155 | ^https:\/\/api\.lingokids\.com\/v1\/renovate_session$ url script-response-body eval_script.js 156 | 157 | ^https:\/\/www\.peacefulsoundsapp\.com\/api\/v1\/init$ url script-response-body eval_script.js 158 | 159 | ^https:\/\/duolingo-leaderboards-prod\.duolingo\.com\/leaderboards* url script-response-body eval_script.js 160 | 161 | ^https:\/\/commerce-i18n-api\.faceu\.mobi\/commerce\/v1\/subscription\/user_info$ url script-response-body eval_script.js 162 | 163 | ^https:\/\/api\.global\.mp3\.zing\.vn\/1\.0\/getUserInfo\?data=* url script-response-body eval_script.js 164 | 165 | ^https:\/\/api\.blinkist\.com\/v4\/(me$|me.json$|me\/access$) url script-response-body eval_script.js 166 | 167 | ^https:\/\/api\.sololearn\.com\/(Profile\/GetProfile$|authenticateDevice$) url script-response-body eval_script.js 168 | 169 | ^https:\/\/api-kinemaster-assetstore\.(nexstreaming|kinemasters)\.com\/.*\/product\/verifyReceipt$ url script-response-body eval_script.js 170 | 171 | ^https:\/\/api\.pushover\.net\/1\/messages\.json* url script-response-body eval_script.js 172 | 173 | ^https:\/\/api\.overhq\.com\/(user\/token\/refresh$|subscription\/verifyReceipt$) url script-response-body eval_script.js 174 | 175 | ^https:\/\/receipt-validator\.herewetest\.com\/apple\/verifyTransaction$ url script-response-body eval_script.js 176 | 177 | ^https:\/\/license\.pdfexpert\.com\/api\/.*\/documents\/subscription\/(refresh$|check$) url script-response-body eval_script.js 178 | 179 | ^https:\/\/education\.github\.com\/api\/user$ url script-response-body eval_script.js 180 | 181 | ^https:\/\/backend\.getdrafts\.com\/api\/.*\/verification* url script-response-body eval_script.js 182 | 183 | ^https:\/\/lcs-mobile-cops\.adobe\.io\/mobile_profile url script-response-body eval_script.js 184 | 185 | ^https:\/\/ssl-api\.itranslateapp\.com\/.*\/subscriptions\/.*\/ios$ url script-response-body eval_script.js 186 | 187 | ^https:\/\/sk\.ulysses\.app\/api\/v1\/itunes_receipt_verify$ url script-response-body eval_script.js 188 | 189 | ^https:\/\/dayone\.me\/api\/(users|v2\/users\/account-status)$ url script-response-body eval_script.js 190 | 191 | ^https:\/\/api-production\.endel\.io\/.*\/user$ url script-response-body eval_script.js 192 | 193 | ^https:\/\/api\.shred\.app\/verifyReceipt$ url script-response-body eval_script.js 194 | 195 | ^https:\/\/subscription\.grammarly\.com\/api\/v1$ url script-response-body eval_script.js 196 | 197 | ^https:\/\/planner5d\.com\/api\/sets url script-response-body eval_script.js 198 | 199 | ^https:\/\/secure\.istreamer\.com\/backend$ url script-response-body eval_script.js 200 | 201 | ^https:\/\/www\.api\.monkeyuni\.net\/api\/.+\/mobile\/account\/load-update url script-response-body eval_script.js 202 | 203 | ^https:\/\/api\.textnow\.me\/api2.0\/users\/.* url script-response-body eval_script.js 204 | 205 | ^https:\/\/vipapi\.jxedt\.com\/vip\/check url script-response-body eval_script.js 206 | 207 | ^https:\/\/api\.interpreter\.caiyunai\.com\/v1\/user url script-response-body eval_script.js 208 | 209 | ^https:\/\/buy\.itunes\.apple\.com\/verifyReceipt url script-response-body eval_script.js 210 | 211 | ^https:\/\/pocketlists\.com\/api\/v1\/pocketlists.me.get url script-response-body eval_script.js 212 | 213 | https:\/\/book\.haitunwallet\.com\/app\/vip\/status url script-response-body eval_script.js 214 | 215 | https:\/\/mubu\.com\/api\/app\/user\/info url script-response-body eval_script.js 216 | 217 | ^https:\/\/app\.xunjiepdf\.com\/api\/v4\/virtualactregister url script-response-body eval_script.js 218 | 219 | http:\/\/miaow\.yiyongcad\.com\/api\/v4\/memprofile url script-response-body eval_script.js 220 | 221 | https:\/\/api\.lennou\.com\/user\/info url script-response-body eval_script.js 222 | 223 | ^https:\/\/api\.gkocr\.com\/api\/userlogin1.php url script-response-body eval_script.js 224 | 225 | ^https?:\/\/vira\.llsapp\.com\/api\/v2\/readings\/(accessible|limitation) url script-response-body eval_script.js 226 | 227 | ^https:\/\/api\.rr\.tv(\/user\/privilege\/list|\/ad\/getAll|\/rrtv-video\/v4plus\/season\/detail) url script-response-body eval_script.js 228 | 229 | ^https?:\/\/pan\.baidu\.com\/s\/ url script-response-body eval_script.js 230 | 231 | ^https:\/\/api\.revenuecat\.com\/v1\/(receipts|\d{1,})$ url script-response-body eval_script.js 232 | 233 | https://(commerce-.*api|pay).(faceu|wecut).(com|mobi)/(commerce|apple)/(iosAppVerifyReceipt.php|v1/subscription/user_info) url script-response-body eval_script.js 234 | 235 | ^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/theme) url script-response-body eval_script.js 236 | 237 | ^http:\/\/115\.com\/lx.*$ url script-response-body eval_script.js 238 | 239 | ^https:\/\/api\.lakecoloring\.com\/v1\/receipt url script-response-body eval_script.js 240 | 241 | ^http://ctrl.playcvn.com/app/(init|ads) url script-response-body eval_script.js 242 | 243 | ^https:\/\/dict\.eudic\.net\/jingting\/GetThisChapterTaskStatus? url script-response-body eval_script.js 244 | 245 | ^https?://m.client.10010.com/uniAdmsInterface/getHomePageAd url script-response-body eval_script.js 246 | 247 | ^https:\/\/api\.wakamoment\.ga\/init\?platform\=ios url script-response-body eval_script.js 248 | 249 | ^https:\/\/api\.diyidan\.net\/v0\.3\/(user\/personal_homepage|vip_user\/info|tv_series\/index\?appChanne) url script-response-body eval_script.js 250 | 251 | ^https:\/\/api\.flexibits\.com\/v1\/(auth|account)\/(device|details|appstore-receipt)\/$ url script-response-body eval_script.js 252 | 253 | https?:\/\/api\.jiaonizuocai\.com url script-response-body eval_script.js 254 | 255 | https:\/\/api\.sololearn\.com\/(authenticateDevice|challenge\/GetContestFeed|Profile\/GetProfile)$ url script-response-body eval_script.js 256 | 257 | ^https://tncj.hortorgames.com/chicken/fight/(answer|findQuiz) url script-response-body eval_script.js 258 | 259 | ^https:\/\/(www\.baidu.com2\.club|ayk\.tmdidi\.com|m\.pearkin\.com|souhu\.mett\.me|bkcd\.b-cdn\.net)\/(api\/movie\/WatchMovie|api\/Account\/CheckVip|api\/account\/IndexDetail) url script-response-body eval_script.js 260 | 261 | ^https:\/\/claritywallpaper\.com\/clarity\/api\/(userInfo|special\/queryByCatalogAll) url script-response-body eval_script.js 262 | 263 | https:\/\/bookapi\.ihuman\.com\/(v1\/get\_user\_info|v1\/get\_purchase\_list) url script-response-body eval_script.js 264 | 265 | http:\/\/rest\.zhibo\.tv\/room\/get\-room\-info\-v430 url script-response-body eval_script.js 266 | 267 | https://note.youdao.com/yws/(mapi/payment|api/self) url script-response-body eval_script.js 268 | 269 | ^https:\/\/billing\.peakcloud\.org\/billing\/2\/user\/me? url script-response-body eval_script.js 270 | 271 | ^https?:\/\/api\.ithome\.com\/json\/slide\/index url script-response-body eval_script.js 272 | 273 | ^https?:\/\/api\.ithome\.com\/json\/(newslist|listpage)\/news url script-response-body eval_script.js 274 | 275 | https:\/\/www\.xmind\.cn\/\_res\/devices url script-response-body eval_script.js 276 | 277 | ^http?:\/\/.*\.arten.cn/login/login url script-response-body eval_script.js 278 | 279 | ^https://api.weiqire.com/api3/(visitor/|user/unlockCharpter) url script-response-body eval_script.js 280 | 281 | https://api.shimo.im/users/ url script-response-body eval_script.js 282 | 283 | ^https?:\/\/.*\.videostarapp\.com\/scripts\/subsNew\.php url script-response-body eval_script.js 284 | 285 | https:\/\/api\.revenuecat\.com\/v1\/(subscribers|receipts) url script-response-body eval_script.js 286 | 287 | https://app.api.versa-ai.com/pay/order/iap/check url script-response-body eval_script.js 288 | 289 | ^https\:\/\/hjapi\.bjxkhc\.com\/v2d2\/users\/.*\/member url script-response-body eval_script.js 290 | 291 | http:\/\/api\.591master\.com\:8081\/(1.0|3.6.8)\/ui(forum|common)\/(downloadwallpaper|getuser) url script-response-body eval_script.js 292 | 293 | ^http\:\/\/jdytv\.cn\/login\/login\/veifys url script-response-body eval_script.js 294 | 295 | http://user.shywck.com/user/userinfo url script-response-body eval_script.js 296 | 297 | ^https?:\/\/.*\.xunjie.*\.com\/api\/v\d\/* url script-response-body eval_script.js 298 | 299 | ^https:\/\/api\.psy-1\.com\/cosleep\/user\/info url script-response-body eval_script.js 300 | 301 | ^https:\/\/snailsleep\.net\/snail\/v1\/profile\/get url script-response-body eval_script.js 302 | 303 | ^https:\/\/mob2015\.kekenet\.com\/keke\/mobile\/index\.php url script-response-body eval_script.js 304 | 305 | ^https:\/\/m\.samh\.xndm\.tech\/userapi\/info\/v1\/getuserinfo url script-response-body eval_script.js 306 | 307 | ^http\:\/\/app\.flashdown365\.com\/ios\/login url script-response-body eval_script.js 308 | 309 | ^https:\/\/avoscloud\.com\/1\.1\/users\/ url script-response-body eval_script.js 310 | 311 | ^https\:\/\/api\.gao1gps\.cn\/v1\/user\/info url script-response-body eval_script.js 312 | 313 | ^https:\/\/api\.meiyan\.com\/iap\/verify\.json url script-response-body eval_script.js 314 | 315 | ^https:\/\/bea\.sportq\.com\/SFitWeb\/sfit\/getUserBaseInfo url script-response-body eval_script.js 316 | 317 | ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig) url script-response-body eval_script.js 318 | 319 | ^http://.+/amdc/mobileDispatch url script-request-body eval_script.js 320 | 321 | ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail url script-response-body eval_script.js 322 | 323 | ^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-request-header eval_script.js 324 | 325 | ^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-response-body eval_script.js 326 | 327 | ^https?://ios\.prod\.ftl\.netflix\.com/iosui/warmer/.+type=show-ath url script-response-body eval_script.js -------------------------------------------------------------------------------- /eval_script/qx_script.txt: -------------------------------------------------------------------------------- 1 | hostname = api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios.prod.ftl.netflix.com 2 | 3 | ^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-request-header eval_script.js 4 | 5 | ^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-response-body eval_script.js 6 | 7 | ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig) url script-response-body eval_script.js 8 | 9 | ^http://.+/amdc/mobileDispatch url script-request-body eval_script.js 10 | 11 | ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail url script-response-body eval_script.js 12 | 13 | ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body eval_script.js 14 | 15 | ^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/photos/pic_recommend_status|video/tiny_stream_video_list) url script-response-body eval_script.js -------------------------------------------------------------------------------- /eval_script/sg.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=eval_script.js module 2 | 3 | [MITM] 4 | hostname = %INSERT% api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios.prod.ftl.netflix.com,bea.sportq.com,api.meiyan.com,api.gao1gps.cn,avoscloud.com,app.flashdown365.com,m.samh.xndm.tech,mob2015.kekenet.com,vipapi.jxedt.com,api.interpreter.caiyunai.com,pocketlists.com,book.haitunwallet.com,mubu.com,app.xunjiepdf.com,miaow.yiyongcad.com,api.lennou.com,api.gkocr.com,vira.llsapp.com,commerce-.*api.faceu.mobi,commerce-api.faceu.mobi,pan.baidu.com,api.revenuecat.com,api.rr.tv,editorapi.115.com,api.lakecoloring.com,ctrl.playcvn.com,dict.eudic.net,m.client.10010.com,api.wakamoment.ga,*.bh3.com,api.diyidan.net,api.flexibits.com,api.jiaonizuocai.com,api.sololearn.com,tncj.hortorgames.com,bkcd.b-cdn.net,souhu.mett.me,ayk.tmdidi.com,m.pearkin.com,www.baidu.com2.club,claritywallpaper.com,bookapi.ihuman.com,rest.zhibo.tv,note.youdao.com,billing.peakcloud.org,api.ithome.com,www.xmind.cn,*.arten.cn,api.weiqire.com,api.shimo.im,pay.wecut.com,*.videostarapp.com,app.api.versa-ai.com,*.bjxkhc.com,api.591master.com,jdytv.cn,user.shywck.com,*.xunjie*.com,api.psy-1.com,snailsleep.net,mp.weixin.qq.com,api.bilibili.com,app.bilibili.com,*.zhihu.com,aweme*.snssdk.com,*.kuwo.cn,vip1.kuwo.cn,*.xiaoxiao*.com,api*.tiktokv.com,*.musical.ly,*.amemv.com,p.du.163.com,getuserinfo.321mh.com,getuserinfo-globalapi.zymk.cn,ios.fuliapps.com,vsco.co,api.vnision.com,*.my10api.com,sp.kaola.com,r.inews.qq.com,apple.fuliapps.com,newdrugs.dxy.cn,app101.avictown.cc,api.hlo.xyz,api.ijo.xyz,www.luqijianggushi.com,account.wps.*,u.kanghuayun.com,api.gyrosco.pe,api1.dobenge.cn,api.mvmtv.com,mitaoapp.yeduapp.com,origin-prod-phoenix.jibjab.com,www.3ivf.com,pay.guoing.com,api.termius.com,api.bjxkhc.com,viva.v21xy.com,biz.caiyunapp.com,api.gotokeep.com,ap*.intsig.net,mp.bybutter.com,api.vuevideo.net,api.picsart.c*,api.meiease.c*,splice.oracle.*.com,api.gamer.com.tw,ios.xiangjiaoapps.com,apple.xiangjiaoapps.com,*.lagoapps.com,*.xiangxiangapps.com,avatar-nct.nixcdn.com,spclient.wg.spotify.com,oa.zalo.me,api.unfold.app,viva-asia1.vvbrd.com,graph.nhaccuatui.com,api.memrise.com,api.sync.me,pool.elsanow.io,lambda.us-east-1.amazonaws.com,api.mondlylanguages.com,api.busuu.com,owa.videoshowiosglobalserver.com:0,accounts.elevateapp.net,purchases.ws.pho.to,api-intl.mr.meitu.com,bmall.camera360.com,api.tv.zing.vn,api.calm.com,www.calm.com,api.global.mp3.zing.vn,apimboom2.globaldelight.net,photos.adobe.io,license.pdfexpert.com,subs.platforms.team,apic.musixmatch.com,api.getmimo.com,engbright.com,api.lingokids.com,www.peacefulsoundsapp.com,duolingo-leaderboards-prod.duolingo.com,mobile-api.adguard.com,api.blinkist.com,api-kinemaster-assetstore.*,api.pushover.net,api.overhq.com,receipt-validator.herewetest.com,lcs-mobile-cops.adobe.io,education.github.com,backend.getdrafts.com,ssl-api.itranslateapp.com,sk.ulysses.app,dayone.me,license.enpass.io,*.grammarly.com,api.keepkeep.com,planner5d.com,secure.istreamer.com,www.api.monkeyuni.net,api.textnow.me 5 | 6 | [Script] 7 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua),script-path=eval_script.js 8 | 9 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/photos/pic_recommend_status|video/tiny_stream_video_list),script-path=eval_script.js 10 | 11 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/mp\.weixin\.qq\.com\/mp\/getappmsgad,script-path=eval_script.js 12 | 13 | eval_script.js = type=http-response,requires-body=1,pattern=^https://api.zhihu.com/moments/recommend,script-path=eval_script.js 14 | 15 | eval_script.js = type=http-response,requires-body=1,pattern=^https://api.zhihu.com/topstory/recommend,script-path=eval_script.js 16 | 17 | eval_script.js = type=http-response,requires-body=1,pattern=https://api.zhihu.com/v4/questions,script-path=eval_script.js 18 | 19 | eval_script.js = type=http-response,requires-body=1,pattern=^https://api.zhihu.com/people/,script-path=eval_script.js 20 | 21 | eval_script.js = type=http-response,requires-body=1,pattern=^https://api.zhihu.com/market/header,script-path=eval_script.js 22 | 23 | eval_script.js = type=http-response,requires-body=1,pattern=https://app.bilibili.com/x/v2/space\?access_key,script-path=eval_script.js 24 | 25 | eval_script.js = type=http-response,requires-body=1,pattern=https://app.bilibili.com/x/resource/show/tab\?access_key,script-path=eval_script.js 26 | 27 | eval_script.js = type=http-response,requires-body=1,pattern=https://app.bilibili.com/x/v2/feed/index\?access_key,script-path=eval_script.js 28 | 29 | eval_script.js = type=http-response,requires-body=1,pattern=https://app.bilibili.com/x/v2/view\?access_key,script-path=eval_script.js 30 | 31 | eval_script.js = type=http-response,requires-body=1,pattern=https://api.bilibili.com/x/v2/reply/main\?access_key,script-path=eval_script.js 32 | 33 | eval_script.js = type=http-response,requires-body=1,pattern=https://api.live.bilibili.com/xlive/app-room/v1/index/getInfoByRoom\?access_key,script-path=eval_script.js 34 | 35 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/aweme\/post\/,script-path=eval_script.js 36 | 37 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/feed\/,script-path=eval_script.js 38 | 39 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/follow\/feed\/,script-path=eval_script.js 40 | 41 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/nearby\/feed\/,script-path=eval_script.js 42 | 43 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/search\/item\/,script-path=eval_script.js 44 | 45 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/general\/search\/single\/,script-path=eval_script.js 46 | 47 | eval_script.js = type=http-response,requires-body=1,pattern=^https?+:\/\/[\w-]++\.amemv\.com\/aweme\/v\d\/hot\/search\/video\/list\/,script-path=eval_script.js 48 | 49 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/user\/vip|vip\/spi/mservice),script-path=eval_script.js 50 | 51 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/.*\/getGlobalData,script-path=eval_script.js 52 | 53 | eval_script.js = type=http-response,requires-body=1,pattern=^http(s)://api.bjxkhc.com/index.php/app/ios/(vod/show|(user|vod|topic|type)/index),script-path=eval_script.js 54 | 55 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/p\.du\.163\.com\/gain\/readtime\/info\.json,script-path=eval_script.js 56 | 57 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/getuserinfo\.321mh\.com\/app_api\/v5\/getuserinfo\/,script-path=eval_script.js 58 | 59 | eval_script.js = type=http-response,requires-body=1,pattern=^https://getuserinfo-globalapi.zymk.cn/app_api/v5/(getuserinfo|coin_account|getuserinfo_ticket|getcomicinfo)/,script-path=eval_script.js 60 | 61 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/ap(p|i)\.bilibili\.com\/((pgc\/player\/api\/playurl)|(x\/v2\/account\/myinfo\?)|(x\/v2\/account/mine\?)),script-path=eval_script.js 62 | 63 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/vsco\.co\/api\/subscriptions\/2.1\/user-subscriptions\/,script-path=eval_script.js 64 | 65 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/api\.vnision\.com\/v1\/(users\/|banners),script-path=eval_script.js 66 | 67 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/.+\.(my10api|(.*91.*))\.(com|tips|app|xyz)(:\d{2,5})?\/api.php$,script-path=eval_script.js 68 | 69 | eval_script.js = type=http-response,requires-body=1,pattern=^https://sp\.kaola\.com/api/openad$,script-path=eval_script.js 70 | 71 | eval_script.js = type=http-response,requires-body=1,pattern=^https://r\.inews\.qq.com\/get(QQNewsUnreadList|RecommendList),script-path=eval_script.js 72 | 73 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/.*\.(lago|fuli|xiang(jiao|xiang))apps\.com\/(ucp\/index|getGlobalData|.+\/reqplay\/),script-path=eval_script.js 74 | 75 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/(i|newdrugs)\.dxy\.cn\/(snsapi\/username\/|app\/user\/(pro\/stat\?|init\?timestamp=)),script-path=eval_script.js 76 | 77 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/(.+)\.(\w{2,3})(:?\d*)\/(api\/public\/\?service=Live\.checkLive$|public\/\/\?service=Live\.roomCharge$|lg\/video\/loadVideoFees\.do$),script-path=eval_script.js 78 | 79 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/www\.luqijianggushi\.com\/api\/v2\/user\/get,script-path=eval_script.js 80 | 81 | eval_script.js = type=http-response,requires-body=1,pattern=^https://account.wps.*/api/users/,script-path=eval_script.js 82 | 83 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.gyrosco\.pe\/v1\/account\/$,script-path=eval_script.js 84 | 85 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api1\.dobenge\.cn\/api\/user\/getuserinfo,script-path=eval_script.js 86 | 87 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.mvmtv\.com\/index\.php.*(c=user.*a=info|a=addr.*vid=.*),script-path=eval_script.js 88 | 89 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user,script-path=eval_script.js 90 | 91 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/api\.termius\.com\/api\/v3\/bulk\/account\/,script-path=eval_script.js 92 | 93 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/viva\.v21xy\.com\/api\/rest\/u\/vip,script-path=eval_script.js 94 | 95 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/biz\.caiyunapp\.com\/v2\/user\?app_name\=weather,script-path=eval_script.js 96 | 97 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.gotokeep\.com\/(.+\/subject|.+\/dynamic),script-path=eval_script.js 98 | 99 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/(api|api-cs)\.intsig\.net\/purchase\/cs\/query_property\?,script-path=eval_script.js 100 | 101 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.vuevideo\.net\/api\/v1\/(users\/.+\/profile|subtitle\/prepare),script-path=eval_script.js 102 | 103 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/mp\.bybutter\.com\/mood\/(official-templates|privileges),script-path=eval_script.js 104 | 105 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.(picsart|meiease)\.c(n|om)\/users\/show\/me\.json,script-path=eval_script.js 106 | 107 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/splice\.oracle\.\w+\.com\/devices\/me,script-path=eval_script.js 108 | 109 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/pan\.baidu\.com\/rest\/2\.0\/membership\/user,script-path=eval_script.js 110 | 111 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://.*\.snssdk\.com/bds/(feed/stream|comment/cell_reply|cell/cell_comment|cell/detail|ward/list|user/favorite|user/cell_coment|user/cell_userfeed|user/publish_list),script-path=eval_script.js 112 | 113 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/viva-asia1\.vvbrd\.com\/api\/rest\/u\/vip*,script-path=eval_script.js 114 | 115 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.unfold\.app\/v1\/ios\/receipts$,script-path=eval_script.js 116 | 117 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/graph\.nhaccuatui\.com\/.*\/users\/info*,script-path=eval_script.js 118 | 119 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.memrise\.com\/.+\/(me\/$|dashboard\/$|leaderboards\/following\/),script-path=eval_script.js 120 | 121 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/origin-prod-phoenix\.jibjab\.com\/v1\/user$,script-path=eval_script.js 122 | 123 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/buy\.itunes\.apple\.com\/verifyReceipt$,script-path=eval_script.js 124 | 125 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.sync\.me\/api\/purchases\/(report_purchases|get_purchases),script-path=eval_script.js 126 | 127 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/pool\.elsanow\.io\/user\/api\/v1\/purchase$,script-path=eval_script.js 128 | 129 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/lambda\.us-east-1\.amazonaws\.com/.*/functions\/prod-4-syncPurchases\/invocations$,script-path=eval_script.js 130 | 131 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.mondlylanguages\.com\/v1\/ios\/user\/sync$,script-path=eval_script.js 132 | 133 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.busuu\.com\/users\/me*,script-path=eval_script.js 134 | 135 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/owa\.videoshowiosglobalserver\.com\/.*\/iosPayClient,script-path=eval_script.js 136 | 137 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/accounts\.elevateapp\.net\/api\/users\?user%5Bauthentication_token*,script-path=eval_script.js 138 | 139 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api-intl\.mr\.meitu\.com/.*/subs_offer_elg$,script-path=eval_script.js 140 | 141 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/bmall\.camera360\.com\/api\/(iap\/check-receipt$|mix\/getinfo$),script-path=eval_script.js 142 | 143 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/api\.tv\.zing\.vn\/.*/user*,script-path=eval_script.js 144 | 145 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.calm\.com\/me$,script-path=eval_script.js 146 | 147 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/photos\.adobe\.io\/v2\/accounts*,script-path=eval_script.js 148 | 149 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/license\.pdfexpert\.com\/api\/1\.0\/pdfexpert6\/subscription\/(refresh$|check$),script-path=eval_script.js 150 | 151 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/subs\.platforms\.team\/.+\/apple\/verify$,script-path=eval_script.js 152 | 153 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/apic\.musixmatch\.com\/ws\/.*\/config\.get,script-path=eval_script.js 154 | 155 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.getmimo\.com\/v1\/subscriptions$,script-path=eval_script.js 156 | 157 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.revenuecat\.com\/.+\/(receipts$|subscribers\/[a-zA-Z0-9_-]*$),script-path=eval_script.js 158 | 159 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.lingokids\.com\/v1\/renovate_session$,script-path=eval_script.js 160 | 161 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/www\.peacefulsoundsapp\.com\/api\/v1\/init$,script-path=eval_script.js 162 | 163 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/duolingo-leaderboards-prod\.duolingo\.com\/leaderboards*,script-path=eval_script.js 164 | 165 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/commerce-i18n-api\.faceu\.mobi\/commerce\/v1\/subscription\/user_info$,script-path=eval_script.js 166 | 167 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.global\.mp3\.zing\.vn\/1\.0\/getUserInfo\?data=*,script-path=eval_script.js 168 | 169 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.blinkist\.com\/v4\/(me$|me.json$|me\/access$),script-path=eval_script.js 170 | 171 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.sololearn\.com\/(Profile\/GetProfile$|authenticateDevice$),script-path=eval_script.js 172 | 173 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api-kinemaster-assetstore\.(nexstreaming|kinemasters)\.com\/.*\/product\/verifyReceipt$,script-path=eval_script.js 174 | 175 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.pushover\.net\/1\/messages\.json*,script-path=eval_script.js 176 | 177 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.overhq\.com\/(user\/token\/refresh$|subscription\/verifyReceipt$),script-path=eval_script.js 178 | 179 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/receipt-validator\.herewetest\.com\/apple\/verifyTransaction$,script-path=eval_script.js 180 | 181 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/license\.pdfexpert\.com\/api\/.*\/documents\/subscription\/(refresh$|check$),script-path=eval_script.js 182 | 183 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/education\.github\.com\/api\/user$,script-path=eval_script.js 184 | 185 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/backend\.getdrafts\.com\/api\/.*\/verification*,script-path=eval_script.js 186 | 187 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/lcs-mobile-cops\.adobe\.io\/mobile_profile,script-path=eval_script.js 188 | 189 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/ssl-api\.itranslateapp\.com\/.*\/subscriptions\/.*\/ios$,script-path=eval_script.js 190 | 191 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/sk\.ulysses\.app\/api\/v1\/itunes_receipt_verify$,script-path=eval_script.js 192 | 193 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/dayone\.me\/api\/(users|v2\/users\/account-status)$,script-path=eval_script.js 194 | 195 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api-production\.endel\.io\/.*\/user$,script-path=eval_script.js 196 | 197 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.shred\.app\/verifyReceipt$,script-path=eval_script.js 198 | 199 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/subscription\.grammarly\.com\/api\/v1$,script-path=eval_script.js 200 | 201 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/planner5d\.com\/api\/sets,script-path=eval_script.js 202 | 203 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/secure\.istreamer\.com\/backend$,script-path=eval_script.js 204 | 205 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/www\.api\.monkeyuni\.net\/api\/.+\/mobile\/account\/load-update,script-path=eval_script.js 206 | 207 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.textnow\.me\/api2.0\/users\/.*,script-path=eval_script.js 208 | 209 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/vipapi\.jxedt\.com\/vip\/check,script-path=eval_script.js 210 | 211 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.interpreter\.caiyunai\.com\/v1\/user,script-path=eval_script.js 212 | 213 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/buy\.itunes\.apple\.com\/verifyReceipt,script-path=eval_script.js 214 | 215 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/pocketlists\.com\/api\/v1\/pocketlists.me.get,script-path=eval_script.js 216 | 217 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/book\.haitunwallet\.com\/app\/vip\/status,script-path=eval_script.js 218 | 219 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/mubu\.com\/api\/app\/user\/info,script-path=eval_script.js 220 | 221 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/app\.xunjiepdf\.com\/api\/v4\/virtualactregister,script-path=eval_script.js 222 | 223 | eval_script.js = type=http-response,requires-body=1,pattern=http:\/\/miaow\.yiyongcad\.com\/api\/v4\/memprofile,script-path=eval_script.js 224 | 225 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/api\.lennou\.com\/user\/info,script-path=eval_script.js 226 | 227 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.gkocr\.com\/api\/userlogin1.php,script-path=eval_script.js 228 | 229 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/vira\.llsapp\.com\/api\/v2\/readings\/(accessible|limitation),script-path=eval_script.js 230 | 231 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.rr\.tv(\/user\/privilege\/list|\/ad\/getAll|\/rrtv-video\/v4plus\/season\/detail),script-path=eval_script.js 232 | 233 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/pan\.baidu\.com\/s\/,script-path=eval_script.js 234 | 235 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.revenuecat\.com\/v1\/(receipts|\d{1,})$,script-path=eval_script.js 236 | 237 | eval_script.js = type=http-response,requires-body=1,pattern=https://(commerce-.*api|pay).(faceu|wecut).(com|mobi)/(commerce|apple)/(iosAppVerifyReceipt.php|v1/subscription/user_info),script-path=eval_script.js 238 | 239 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/vip1\.kuwo\.cn\/(vip\/v2\/theme),script-path=eval_script.js 240 | 241 | eval_script.js = type=http-response,requires-body=1,pattern=^http:\/\/115\.com\/lx.*$,script-path=eval_script.js 242 | 243 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.lakecoloring\.com\/v1\/receipt,script-path=eval_script.js 244 | 245 | eval_script.js = type=http-response,requires-body=1,pattern=^http://ctrl.playcvn.com/app/(init|ads),script-path=eval_script.js 246 | 247 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/dict\.eudic\.net\/jingting\/GetThisChapterTaskStatus?,script-path=eval_script.js 248 | 249 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://m.client.10010.com/uniAdmsInterface/getHomePageAd,script-path=eval_script.js 250 | 251 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.wakamoment\.ga\/init\?platform\=ios,script-path=eval_script.js 252 | 253 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.diyidan\.net\/v0\.3\/(user\/personal_homepage|vip_user\/info|tv_series\/index\?appChanne),script-path=eval_script.js 254 | 255 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.flexibits\.com\/v1\/(auth|account)\/(device|details|appstore-receipt)\/$,script-path=eval_script.js 256 | 257 | eval_script.js = type=http-response,requires-body=1,pattern=https?:\/\/api\.jiaonizuocai\.com,script-path=eval_script.js 258 | 259 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/api\.sololearn\.com\/(authenticateDevice|challenge\/GetContestFeed|Profile\/GetProfile)$,script-path=eval_script.js 260 | 261 | eval_script.js = type=http-response,requires-body=1,pattern=^https://tncj.hortorgames.com/chicken/fight/(answer|findQuiz),script-path=eval_script.js 262 | 263 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/(www\.baidu.com2\.club|ayk\.tmdidi\.com|m\.pearkin\.com|souhu\.mett\.me|bkcd\.b-cdn\.net)\/(api\/movie\/WatchMovie|api\/Account\/CheckVip|api\/account\/IndexDetail),script-path=eval_script.js 264 | 265 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/claritywallpaper\.com\/clarity\/api\/(userInfo|special\/queryByCatalogAll),script-path=eval_script.js 266 | 267 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/bookapi\.ihuman\.com\/(v1\/get\_user\_info|v1\/get\_purchase\_list),script-path=eval_script.js 268 | 269 | eval_script.js = type=http-response,requires-body=1,pattern=http:\/\/rest\.zhibo\.tv\/room\/get\-room\-info\-v430,script-path=eval_script.js 270 | 271 | eval_script.js = type=http-response,requires-body=1,pattern=https://note.youdao.com/yws/(mapi/payment|api/self),script-path=eval_script.js 272 | 273 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/billing\.peakcloud\.org\/billing\/2\/user\/me?,script-path=eval_script.js 274 | 275 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/api\.ithome\.com\/json\/slide\/index,script-path=eval_script.js 276 | 277 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/api\.ithome\.com\/json\/(newslist|listpage)\/news,script-path=eval_script.js 278 | 279 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/www\.xmind\.cn\/\_res\/devices,script-path=eval_script.js 280 | 281 | eval_script.js = type=http-response,requires-body=1,pattern=^http?:\/\/.*\.arten.cn/login/login,script-path=eval_script.js 282 | 283 | eval_script.js = type=http-response,requires-body=1,pattern=^https://api.weiqire.com/api3/(visitor/|user/unlockCharpter),script-path=eval_script.js 284 | 285 | eval_script.js = type=http-response,requires-body=1,pattern=https://api.shimo.im/users/,script-path=eval_script.js 286 | 287 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/.*\.videostarapp\.com\/scripts\/subsNew\.php,script-path=eval_script.js 288 | 289 | eval_script.js = type=http-response,requires-body=1,pattern=https:\/\/api\.revenuecat\.com\/v1\/(subscribers|receipts),script-path=eval_script.js 290 | 291 | eval_script.js = type=http-response,requires-body=1,pattern=https://app.api.versa-ai.com/pay/order/iap/check,script-path=eval_script.js 292 | 293 | eval_script.js = type=http-response,requires-body=1,pattern=^https\:\/\/hjapi\.bjxkhc\.com\/v2d2\/users\/.*\/member,script-path=eval_script.js 294 | 295 | eval_script.js = type=http-response,requires-body=1,pattern=http:\/\/api\.591master\.com\:8081\/(1.0|3.6.8)\/ui(forum|common)\/(downloadwallpaper|getuser),script-path=eval_script.js 296 | 297 | eval_script.js = type=http-response,requires-body=1,pattern=^http\:\/\/jdytv\.cn\/login\/login\/veifys,script-path=eval_script.js 298 | 299 | eval_script.js = type=http-response,requires-body=1,pattern=http://user.shywck.com/user/userinfo,script-path=eval_script.js 300 | 301 | eval_script.js = type=http-response,requires-body=1,pattern=^https?:\/\/.*\.xunjie.*\.com\/api\/v\d\/*,script-path=eval_script.js 302 | 303 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.psy-1\.com\/cosleep\/user\/info,script-path=eval_script.js 304 | 305 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/snailsleep\.net\/snail\/v1\/profile\/get,script-path=eval_script.js 306 | 307 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/mob2015\.kekenet\.com\/keke\/mobile\/index\.php,script-path=eval_script.js 308 | 309 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/m\.samh\.xndm\.tech\/userapi\/info\/v1\/getuserinfo,script-path=eval_script.js 310 | 311 | eval_script.js = type=http-response,requires-body=1,pattern=^http\:\/\/app\.flashdown365\.com\/ios\/login,script-path=eval_script.js 312 | 313 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/avoscloud\.com\/1\.1\/users\/,script-path=eval_script.js 314 | 315 | eval_script.js = type=http-response,requires-body=1,pattern=^https\:\/\/api\.gao1gps\.cn\/v1\/user\/info,script-path=eval_script.js 316 | 317 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/api\.meiyan\.com\/iap\/verify\.json,script-path=eval_script.js 318 | 319 | eval_script.js = type=http-response,requires-body=1,pattern=^https:\/\/bea\.sportq\.com\/SFitWeb\/sfit\/getUserBaseInfo,script-path=eval_script.js 320 | 321 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig),script-path=eval_script.js 322 | 323 | eval_script.js = type=http-request,requires-body=1,pattern=^http://.+/amdc/mobileDispatch,script-path=eval_script.js 324 | 325 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail,script-path=eval_script.js 326 | 327 | eval_script.js = type=http-request,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=eval_script.js 328 | 329 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=eval_script.js 330 | 331 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/warmer/.+type=show-ath,script-path=eval_script.js -------------------------------------------------------------------------------- /eval_script/sg_script.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=eval_script.js module 2 | 3 | [MITM] 4 | hostname = %INSERT% api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios.prod.ftl.netflix.com 5 | 6 | [Script] 7 | eval_script.js = type=http-request,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=eval_script.js 8 | 9 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=eval_script.js 10 | 11 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig),script-path=eval_script.js 12 | 13 | eval_script.js = type=http-request,requires-body=1,pattern=^http://.+/amdc/mobileDispatch,script-path=eval_script.js 14 | 15 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail,script-path=eval_script.js 16 | 17 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua),script-path=eval_script.js 18 | 19 | eval_script.js = type=http-response,requires-body=1,pattern=^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/photos/pic_recommend_status|video/tiny_stream_video_list),script-path=eval_script.js -------------------------------------------------------------------------------- /jd_price.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const path1 = "serverConfig"; 6 | const path2 = "wareBusiness"; 7 | const path3 = "basicConfig"; 8 | const url = $request.url; 9 | const body = $response.body; 10 | const $tool = tool(); 11 | 12 | if (url.indexOf(path1) != -1) { 13 | let obj = JSON.parse(body); 14 | delete obj.serverConfig.httpdns; 15 | delete obj.serverConfig.dnsvip; 16 | delete obj.serverConfig.dnsvip_v6; 17 | $done({ body: JSON.stringify(obj) }); 18 | } 19 | 20 | if (url.indexOf(path3) != -1) { 21 | let obj = JSON.parse(body); 22 | let JDHttpToolKit = obj.data.JDHttpToolKit; 23 | if (JDHttpToolKit) { 24 | delete obj.data.JDHttpToolKit.httpdns; 25 | delete obj.data.JDHttpToolKit.dnsvipV6; 26 | } 27 | $done({ body: JSON.stringify(obj) }); 28 | } 29 | 30 | if (url.indexOf(path2) != -1) { 31 | let obj = JSON.parse(body); 32 | const floors = obj.floors; 33 | const commodity_info = floors[floors.length - 1]; 34 | const shareUrl = commodity_info.data.property.shareUrl; 35 | let msg = ""; 36 | request_history_price(shareUrl) 37 | .then((data) => { 38 | if (data.errno == -1) throw new Error("Whoops!"); 39 | msg = priceSummary(data.data); 40 | }) 41 | .catch((error) => (msg = "暂无价格信息")) 42 | .finally(() => { 43 | const lowerword = adword_obj(); 44 | lowerword.data.ad.textColor = "#fe0000"; 45 | let bestIndex = 0; 46 | for (let index = 0; index < floors.length; index++) { 47 | const element = floors[index]; 48 | if (element.mId == lowerword.mId) { 49 | bestIndex = index + 1; 50 | break; 51 | } else { 52 | if (element.sortId > lowerword.sortId) { 53 | bestIndex = index; 54 | break; 55 | } 56 | } 57 | } 58 | lowerword.data.ad.adword = msg; 59 | floors.insert(bestIndex, lowerword); 60 | $done({ body: JSON.stringify(obj) }); 61 | }); 62 | } 63 | 64 | function priceSummary(data) { 65 | let summary = `🌨 当前: ${data.CurrentPrice}${getSpace(8)}最低: ${data.LowestPrice} (${data.LowestDate})`; 66 | const list = historySummary(data.PricesHistory); 67 | list.forEach((item, index) => { 68 | summary += `\n${item.Name}${getSpace(8)}${item.Price}${getSpace(8)}${item.Date}${getSpace(8)}${item.Difference}`; 69 | }); 70 | return summary; 71 | } 72 | 73 | function historySummary(list) { 74 | let currentPrice, lowest30, lowest90, lowest180, lowest360, price11, price618; 75 | list = list.reverse().slice(0, 360); 76 | list.forEach((item, index) => { 77 | const date = item.Date; 78 | let price = item.Price; 79 | if (index == 0) { 80 | currentPrice = price; 81 | price618 = { 82 | Name: "六一八价格", 83 | Price: "-", 84 | Date: "-", 85 | Difference: "-", 86 | price: "-", 87 | }; 88 | price11 = { 89 | Name: "双十一价格", 90 | Price: "-", 91 | Date: "-", 92 | Difference: "-", 93 | price: "-", 94 | }; 95 | lowest30 = { 96 | Name: "三十天最低", 97 | Price: `¥${String(price)}`, 98 | Date: date, 99 | Difference: difference(currentPrice, price), 100 | price, 101 | }; 102 | lowest90 = { 103 | Name: "九十天最低", 104 | Price: `¥${String(price)}`, 105 | Date: date, 106 | Difference: difference(currentPrice, price), 107 | price, 108 | }; 109 | lowest180 = { 110 | Name: "一百八最低", 111 | Price: `¥${String(price)}`, 112 | Date: date, 113 | Difference: difference(currentPrice, price), 114 | price, 115 | }; 116 | lowest360 = { 117 | Name: "三百六最低", 118 | Price: `¥${String(price)}`, 119 | Date: date, 120 | Difference: difference(currentPrice, price), 121 | price, 122 | }; 123 | } 124 | if (date.indexOf("06-18") != -1) { 125 | price618.price = price; 126 | price618.Price = `¥${String(price)}`; 127 | price618.Date = date; 128 | price618.Difference = difference(currentPrice, price); 129 | } 130 | if (date.indexOf("11-11") != -1) { 131 | price11.price = price; 132 | price11.Price = `¥${String(price)}`; 133 | price11.Date = date; 134 | price11.Difference = difference(currentPrice, price); 135 | } 136 | if (index < 30 && price < lowest30.price) { 137 | lowest30.price = price; 138 | lowest30.Price = `¥${String(price)}`; 139 | lowest30.Date = date; 140 | lowest30.Difference = difference(currentPrice, price); 141 | } 142 | if (index < 90 && price < lowest90.price) { 143 | lowest90.price = price; 144 | lowest90.Price = `¥${String(price)}`; 145 | lowest90.Date = date; 146 | lowest90.Difference = difference(currentPrice, price); 147 | } 148 | if (index < 180 && price < lowest180.price) { 149 | lowest180.price = price; 150 | lowest180.Price = `¥${String(price)}`; 151 | lowest180.Date = date; 152 | lowest180.Difference = difference(currentPrice, price); 153 | } 154 | if (index < 360 && price < lowest360.price) { 155 | lowest360.price = price; 156 | lowest360.Price = `¥${String(price)}`; 157 | lowest360.Date = date; 158 | lowest360.Difference = difference(currentPrice, price); 159 | } 160 | }); 161 | return [lowest30, lowest90, lowest180, lowest360, price618, price11]; 162 | } 163 | 164 | async function request_history_price(share_url) { 165 | const options = { 166 | headers: { 167 | "Content-Type": "application/json; charset=utf-8", 168 | }, 169 | }; 170 | 171 | const priceTrend = new Promise(function (resolve, reject) { 172 | options.url = "https://price.icharle.com/?product_id=" + share_url; 173 | $tool.get(options, function (error, response, data) { 174 | if (!error) { 175 | resolve(JSON.parse(data)); 176 | } else { 177 | reject(error); 178 | } 179 | }); 180 | }); 181 | const priceTrendData = await priceTrend; 182 | return priceTrendData; 183 | } 184 | 185 | function getExactTime(time) { 186 | var date = new Date(time * 1000); 187 | var year = date.getFullYear() + "-"; 188 | var month = 189 | (date.getMonth() + 1 < 10 190 | ? "0" + (date.getMonth() + 1) 191 | : date.getMonth() + 1) + "-"; 192 | var dates = date.getDate(); 193 | return year + month + dates; 194 | } 195 | 196 | function difference(currentPrice, price) { 197 | let difference = sub(currentPrice, price); 198 | if (difference == 0) { 199 | return "-"; 200 | } else { 201 | return `${difference > 0 ? "↑" : "↓"}${String(Math.abs(difference))}`; 202 | } 203 | } 204 | 205 | function sub(arg1, arg2) { 206 | return add(arg1, -Number(arg2), arguments[2]); 207 | } 208 | 209 | function add(arg1, arg2) { 210 | (arg1 = arg1.toString()), (arg2 = arg2.toString()); 211 | var arg1Arr = arg1.split("."), 212 | arg2Arr = arg2.split("."), 213 | d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", 214 | d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 215 | var maxLen = Math.max(d1.length, d2.length); 216 | var m = Math.pow(10, maxLen); 217 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 218 | var d = arguments[2]; 219 | return typeof d === "number" ? Number(result.toFixed(d)) : result; 220 | } 221 | 222 | function getSpace(length) { 223 | let blank = ""; 224 | for (let index = 0; index < length; index++) { 225 | blank += " "; 226 | } 227 | return blank; 228 | } 229 | 230 | function adword_obj() { 231 | return { 232 | bId: "eCustom_flo_199", 233 | cf: { 234 | bgc: "#ffffff", 235 | spl: "empty", 236 | }, 237 | data: { 238 | ad: { 239 | adword: "", 240 | textColor: "#8C8C8C", 241 | color: "#f23030", 242 | newALContent: true, 243 | hasFold: true, 244 | class: "com.jd.app.server.warecoresoa.domain.AdWordInfo.AdWordInfo", 245 | adLinkContent: "", 246 | adLink: "", 247 | }, 248 | }, 249 | mId: "bpAdword", 250 | refId: "eAdword_0000000028", 251 | sortId: 13, 252 | }; 253 | } 254 | 255 | function tool() { 256 | const isSurge = typeof $httpClient != "undefined"; 257 | const isQuanX = typeof $task != "undefined"; 258 | const isResponse = typeof $response != "undefined"; 259 | const node = (() => { 260 | if (typeof require == "function") { 261 | const request = require("request"); 262 | return { request }; 263 | } else { 264 | return null; 265 | } 266 | })(); 267 | const notify = (title, subtitle, message) => { 268 | if (isQuanX) $notify(title, subtitle, message); 269 | if (isSurge) $notification.post(title, subtitle, message); 270 | if (node) console.log(JSON.stringify({ title, subtitle, message })); 271 | }; 272 | const write = (value, key) => { 273 | if (isQuanX) return $prefs.setValueForKey(value, key); 274 | if (isSurge) return $persistentStore.write(value, key); 275 | }; 276 | const read = (key) => { 277 | if (isQuanX) return $prefs.valueForKey(key); 278 | if (isSurge) return $persistentStore.read(key); 279 | }; 280 | const adapterStatus = (response) => { 281 | if (response) { 282 | if (response.status) { 283 | response["statusCode"] = response.status; 284 | } else if (response.statusCode) { 285 | response["status"] = response.statusCode; 286 | } 287 | } 288 | return response; 289 | }; 290 | const get = (options, callback) => { 291 | if (isQuanX) { 292 | if (typeof options == "string") options = { url: options }; 293 | options["method"] = "GET"; 294 | $task.fetch(options).then( 295 | (response) => { 296 | callback(null, adapterStatus(response), response.body); 297 | }, 298 | (reason) => callback(reason.error, null, null) 299 | ); 300 | } 301 | if (isSurge) 302 | $httpClient.get(options, (error, response, body) => { 303 | callback(error, adapterStatus(response), body); 304 | }); 305 | if (node) { 306 | node.request(options, (error, response, body) => { 307 | callback(error, adapterStatus(response), body); 308 | }); 309 | } 310 | }; 311 | const post = (options, callback) => { 312 | if (isQuanX) { 313 | if (typeof options == "string") options = { url: options }; 314 | options["method"] = "POST"; 315 | $task.fetch(options).then( 316 | (response) => { 317 | callback(null, adapterStatus(response), response.body); 318 | }, 319 | (reason) => callback(reason.error, null, null) 320 | ); 321 | } 322 | if (isSurge) { 323 | $httpClient.post(options, (error, response, body) => { 324 | callback(error, adapterStatus(response), body); 325 | }); 326 | } 327 | if (node) { 328 | node.request.post(options, (error, response, body) => { 329 | callback(error, adapterStatus(response), body); 330 | }); 331 | } 332 | }; 333 | return { isQuanX, isSurge, isResponse, notify, write, read, get, post }; 334 | } 335 | 336 | Array.prototype.insert = function (index, item) { 337 | this.splice(index, 0, item); 338 | }; 339 | 340 | Date.prototype.format = function (fmt) { 341 | var o = { 342 | "y+": this.getFullYear(), 343 | "M+": this.getMonth() + 1, 344 | "d+": this.getDate(), 345 | "h+": this.getHours(), 346 | "m+": this.getMinutes(), 347 | "s+": this.getSeconds(), 348 | "q+": Math.floor((this.getMonth() + 3) / 3), 349 | "S+": this.getMilliseconds(), 350 | }; 351 | for (var k in o) { 352 | if (new RegExp("(" + k + ")").test(fmt)) { 353 | if (k == "y+") { 354 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 355 | } else if (k == "S+") { 356 | var lens = RegExp.$1.length; 357 | lens = lens == 1 ? 3 : lens; 358 | fmt = fmt.replace( 359 | RegExp.$1, 360 | ("00" + o[k]).substr(("" + o[k]).length - 1, lens) 361 | ); 362 | } else { 363 | fmt = fmt.replace( 364 | RegExp.$1, 365 | RegExp.$1.length == 1 366 | ? o[k] 367 | : ("00" + o[k]).substr(("" + o[k]).length) 368 | ); 369 | } 370 | } 371 | } 372 | return fmt; 373 | }; 374 | -------------------------------------------------------------------------------- /jd_price_lite.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | ^https?://api\.m\.jd\.com/(client\.action|api)\?functionId=(wareBusiness|serverConfig|basicConfig|lite_wareBusiness|pingou_item) 4 | */ 5 | 6 | const path1 = "serverConfig"; 7 | const path2 = "wareBusiness"; 8 | const path2h = "wareBusiness.style"; 9 | const path3 = "basicConfig"; 10 | const path4 = "pingou_item"; 11 | const consolelog = false; 12 | const url = $request.url; 13 | const body = $response.body; 14 | const $tool = tool(); 15 | 16 | if (url.indexOf(path1) != -1) { 17 | let obj = JSON.parse(body); 18 | delete obj.serverConfig.httpdns; 19 | delete obj.serverConfig.dnsvip; 20 | delete obj.serverConfig.dnsvip_v6; 21 | $done({ body: JSON.stringify(obj) }); 22 | } 23 | 24 | if (url.indexOf(path3) != -1) { 25 | let obj = JSON.parse(body); 26 | let JDHttpToolKit = obj.data.JDHttpToolKit; 27 | let jCommandConfig = obj.data.jCommandConfig; 28 | if (JDHttpToolKit) { 29 | delete obj.data.JDHttpToolKit.httpdns; 30 | delete obj.data.JDHttpToolKit.dnsvipV6; 31 | } 32 | if (jCommandConfig) { 33 | delete obj.data.jCommandConfig.httpdnsConfig; 34 | } 35 | $done({ body: JSON.stringify(obj) }); 36 | } 37 | 38 | if (url.indexOf(path2) != -1 || url.indexOf(path4) != -1) { 39 | if (!$tool.isQuanX) { 40 | $done({ body }); 41 | } 42 | let obj = JSON.parse(body); 43 | const floors = obj.floors; 44 | const commodity_info = floors[floors.length - 1]; 45 | const others = obj.others; 46 | const domain = obj.domain; 47 | const shareUrl = 48 | url.indexOf(path4) != -1 49 | ? domain.h5Url 50 | : url.indexOf(path2h) != -1 51 | ? others.property.shareUrl 52 | : commodity_info.data.property.shareUrl; 53 | request_history_price(shareUrl, function (data) { 54 | if (data) { 55 | if (data.ok == 1 && data.single) { 56 | const lower = lowerMsgs(data.single) 57 | const detail = priceSummary(data) 58 | const tip = data.PriceRemark.Tip 59 | $tool.notify("", "", `${lower}\n${tip}${detail}`) 60 | } 61 | if (data.ok == 0 && data.msg.length > 0) { 62 | $tool.notify("", "", `⚠️ ${data.msg}`) 63 | } 64 | } 65 | $done({ body }); 66 | }) 67 | } 68 | 69 | function lowerMsgs(data) { 70 | const lower = data.lowerPriceyh 71 | const lowerDate = dateFormat(data.lowerDateyh) 72 | const lowerMsg = "🍵 历史最低到手价:¥" + String(lower) + ` (${lowerDate}) ` 73 | return lowerMsg 74 | } 75 | 76 | 77 | function priceSummary(data) { 78 | let summary = "" 79 | let listPriceDetail = data.PriceRemark.ListPriceDetail.slice(0,4) 80 | let list = listPriceDetail.concat(historySummary(data.single)) 81 | list.forEach((item, index) => { 82 | if (item.Name == "双11价格") { 83 | item.Name = "双十一价格" 84 | } else if (item.Name == "618价格") { 85 | item.Name = "六一八价格" 86 | } 87 | let price = String(parseInt(item.Price.substr(1))); 88 | summary += `\n${item.Name} ${isNaN(price) ? "-" : "¥" + price} ${item.Date} ${item.Difference}` 89 | }) 90 | return summary 91 | } 92 | 93 | function historySummary(single) { 94 | const rexMatch = /\[.*?\]/g; 95 | const rexExec = /\[(.*),(.*),"(.*)".*\]/; 96 | let currentPrice, lowest30, lowest90, lowest180, lowest360 97 | let list = single.jiagequshiyh.match(rexMatch); 98 | list = list.reverse().slice(0, 360); 99 | list.forEach((item, index) => { 100 | if (item.length > 0) { 101 | const result = rexExec.exec(item); 102 | const dateUTC = new Date(eval(result[1])); 103 | const date = dateUTC.format("yyyy-MM-dd"); 104 | let price = parseFloat(result[2]); 105 | if (index == 0) { 106 | currentPrice = price 107 | lowest30 = { Name: "三十天最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 108 | lowest90 = { Name: "九十天最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 109 | lowest180 = { Name: "一百八最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 110 | lowest360 = { Name: "三百六最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 111 | } 112 | if (index < 30 && price < lowest30.price) { 113 | lowest30.price = price 114 | lowest30.Price = `¥${String(price)}` 115 | lowest30.Date = date 116 | lowest30.Difference = difference(currentPrice, price) 117 | } 118 | if (index < 90 && price < lowest90.price) { 119 | lowest90.price = price 120 | lowest90.Price = `¥${String(price)}` 121 | lowest90.Date = date 122 | lowest90.Difference = difference(currentPrice, price) 123 | } 124 | if (index < 180 && price < lowest180.price) { 125 | lowest180.price = price 126 | lowest180.Price = `¥${String(price)}` 127 | lowest180.Date = date 128 | lowest180.Difference = difference(currentPrice, price) 129 | } 130 | if (index < 360 && price < lowest360.price) { 131 | lowest360.price = price 132 | lowest360.Price = `¥${String(price)}` 133 | lowest360.Date = date 134 | lowest360.Difference = difference(currentPrice, price) 135 | } 136 | } 137 | }); 138 | return [lowest30, lowest90, lowest180]; 139 | } 140 | 141 | function difference(currentPrice, price) { 142 | let difference = sub(currentPrice, price) 143 | if (difference == 0) { 144 | return "-" 145 | } else { 146 | return `${difference > 0 ? "↑" : "↓"}${String(difference)}` 147 | } 148 | } 149 | 150 | function sub(arg1, arg2) { 151 | return add(arg1, -Number(arg2), arguments[2]); 152 | } 153 | 154 | function add(arg1, arg2) { 155 | arg1 = arg1.toString(), arg2 = arg2.toString(); 156 | var arg1Arr = arg1.split("."), arg2Arr = arg2.split("."), d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 157 | var maxLen = Math.max(d1.length, d2.length); 158 | var m = Math.pow(10, maxLen); 159 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 160 | var d = arguments[2]; 161 | return typeof d === "number" ? Number((result).toFixed(d)) : result; 162 | } 163 | 164 | function request_history_price(share_url, callback) { 165 | const options = { 166 | url: "https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx", 167 | headers: { 168 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 169 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios" 170 | }, 171 | body: "methodName=getHistoryTrend&p_url=" + encodeURIComponent(share_url) 172 | } 173 | $tool.post(options, function (error, response, data) { 174 | if (!error) { 175 | callback(JSON.parse(data)); 176 | if (consolelog) console.log("Data:\n" + data); 177 | } else { 178 | callback(null, null); 179 | if (consolelog) console.log("Error:\n" + error); 180 | } 181 | }) 182 | } 183 | 184 | function dateFormat(cellval) { 185 | const date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10)); 186 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 187 | const currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 188 | return date.getFullYear() + "-" + month + "-" + currentDate; 189 | } 190 | 191 | function tool() { 192 | const isSurge = typeof $httpClient != "undefined" 193 | const isQuanX = typeof $task != "undefined" 194 | const node = (() => { 195 | if (typeof require == "function") { 196 | const request = require('request') 197 | return ({ request }) 198 | } else { 199 | return (null) 200 | } 201 | })() 202 | const notify = (title, subtitle, message) => { 203 | if (isQuanX) $notify(title, subtitle, message) 204 | if (isSurge) $notification.post(title, subtitle, message) 205 | if (node) console.log(JSON.stringify({ title, subtitle, message })); 206 | } 207 | const setCache = (value, key) => { 208 | if (isQuanX) return $prefs.setValueForKey(value, key) 209 | if (isSurge) return $persistentStore.write(value, key) 210 | } 211 | const getCache = (key) => { 212 | if (isQuanX) return $prefs.valueForKey(key) 213 | if (isSurge) return $persistentStore.read(key) 214 | } 215 | const adapterStatus = (response) => { 216 | if (response.status) { 217 | response["statusCode"] = response.status 218 | } else if (response.statusCode) { 219 | response["status"] = response.statusCode 220 | } 221 | return response 222 | } 223 | const get = (options, callback) => { 224 | if (isQuanX) { 225 | if (typeof options == "string") options = { url: options } 226 | options["method"] = "GET" 227 | $task.fetch(options).then(response => { 228 | callback(null, adapterStatus(response), response.body) 229 | }, reason => callback(reason.error, null, null)) 230 | } 231 | if (isSurge) $httpClient.get(options, (error, response, body) => { 232 | callback(error, adapterStatus(response), body) 233 | }) 234 | if (node) { 235 | node.request(options, (error, response, body) => { 236 | callback(error, adapterStatus(response), body) 237 | }) 238 | } 239 | } 240 | const post = (options, callback) => { 241 | if (isQuanX) { 242 | if (typeof options == "string") options = { url: options } 243 | options["method"] = "POST" 244 | $task.fetch(options).then(response => { 245 | callback(null, adapterStatus(response), response.body) 246 | }, reason => callback(reason.error, null, null)) 247 | } 248 | if (isSurge) { 249 | $httpClient.post(options, (error, response, body) => { 250 | callback(error, adapterStatus(response), body) 251 | }) 252 | } 253 | if (node) { 254 | node.request.post(options, (error, response, body) => { 255 | callback(error, adapterStatus(response), body) 256 | }) 257 | } 258 | } 259 | return { isQuanX, isSurge, notify, setCache, getCache, get, post } 260 | } 261 | 262 | Array.prototype.insert = function (index, item) { 263 | this.splice(index, 0, item); 264 | }; 265 | 266 | Date.prototype.format = function (fmt) { 267 | var o = { 268 | "y+": this.getFullYear(), 269 | "M+": this.getMonth() + 1, 270 | "d+": this.getDate(), 271 | "h+": this.getHours(), 272 | "m+": this.getMinutes(), 273 | "s+": this.getSeconds(), 274 | "q+": Math.floor((this.getMonth() + 3) / 3), 275 | "S+": this.getMilliseconds() 276 | }; 277 | for (var k in o) { 278 | if (new RegExp("(" + k + ")").test(fmt)) { 279 | if (k == "y+") { 280 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 281 | } 282 | else if (k == "S+") { 283 | var lens = RegExp.$1.length; 284 | lens = lens == 1 ? 3 : lens; 285 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 286 | } 287 | else { 288 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 289 | } 290 | } 291 | } 292 | return fmt; 293 | } -------------------------------------------------------------------------------- /loon_sub.conf: -------------------------------------------------------------------------------- 1 | http-request ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js, tag=奈飞评分1 2 | http-response ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js, tag=奈飞评分2 3 | http-response ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/warmer/.+type=show-ath requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating_season.js, tag=单集评分 4 | http-response ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js, tag=微博去广告 5 | http-response ^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info) requires-body=1,max-size=-1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js, , tag=微博去广告 6 | http-response ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js,tag=京东比价 7 | http-response ^http://.+/amdc/mobileDispatch requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js,tag=淘宝比价1(内置版) 8 | http-response ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js, tag=淘宝比价2(内置版) 9 | http-response ^http://.+/amdc/mobileDispatch requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price_lite.js,tag=淘宝比价1 Lite(通知版) 10 | http-response ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail requires-body=1,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price_lite.js, tag=淘宝比价2 Lite(通知版) 11 | 12 | hostname = api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios-*.prod.ftl.netflix.com,ios.prod.ftl.netflix.com 13 | -------------------------------------------------------------------------------- /nf_rating.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const $tool = new Tool() 6 | const consoleLog = false; 7 | const imdbApikeyCacheKey = "ImdbApikeyCacheKey"; 8 | const netflixTitleCacheKey = "NetflixTitleCacheKey"; 9 | 10 | if (!$tool.isResponse) { 11 | let url = $request.url; 12 | const urlDecode = decodeURIComponent(url); 13 | const videos = urlDecode.match(/"videos","(\d+)"/); 14 | const videoID = videos[1]; 15 | const map = getTitleMap(); 16 | const title = map[videoID]; 17 | const isEnglish = url.match(/languages=en/) ? true : false; 18 | if (!title && !isEnglish) { 19 | const currentSummary = urlDecode.match(/\["videos","(\d+)","current","summary"\]/); 20 | if (currentSummary) { 21 | url = url.replace("&path=" + encodeURIComponent(currentSummary[0]), ""); 22 | } 23 | url = url.replace(/&languages=(.*?)&/, "&languages=en-US&"); 24 | } 25 | url += "&path=" + encodeURIComponent(`[${videos[0]},"details"]`); 26 | $done({ url }); 27 | } else { 28 | var IMDbApikeys = IMDbApikeys(); 29 | var IMDbApikey = $tool.read(imdbApikeyCacheKey); 30 | if (!IMDbApikey) updateIMDbApikey(); 31 | let obj = JSON.parse($response.body); 32 | if (consoleLog) console.log("Netflix Original Body:\n" + $response.body); 33 | if (typeof (obj.paths[0][1]) == "string") { 34 | const videoID = obj.paths[0][1]; 35 | const video = obj.value.videos[videoID]; 36 | const map = getTitleMap(); 37 | let title = map[videoID]; 38 | if (!title) { 39 | title = video.summary.title; 40 | setTitleMap(videoID, title, map); 41 | } 42 | let year = null; 43 | let type = video.summary.type; 44 | if (type == "show") { 45 | type = "series"; 46 | } 47 | if (video.details) { 48 | if (type == "movie") { 49 | year = video.details.releaseYear; 50 | } 51 | delete video.details; 52 | } 53 | const requestRatings = async () => { 54 | const IMDb = await requestIMDbRating(title, year, type); 55 | const Douban = await requestDoubanRating(IMDb.id); 56 | const IMDbrating = IMDb.msg.rating; 57 | const tomatoes = IMDb.msg.tomatoes; 58 | const country = IMDb.msg.country; 59 | const awards = IMDb.msg.awards; 60 | const doubanRating = Douban.rating; 61 | const message = `${awards.length > 0 ? awards + "\n": ""}${country}\n${IMDbrating}\n${doubanRating}${tomatoes.length > 0 ? "\n" + tomatoes + "\n" : "\n"}`; 62 | return message; 63 | } 64 | let msg = ""; 65 | requestRatings() 66 | .then(message => msg = message) 67 | .catch(error => msg = error + "\n") 68 | .finally(() => { 69 | let summary = obj.value.videos[videoID].summary; 70 | summary["supplementalMessage"] = `${msg}${summary && summary.supplementalMessage ? "\n" + summary.supplementalMessage : ""}`; 71 | msg_obj = {"tagline":summary.supplementalMessage, "classification":"REGULAR"} 72 | if (summary["supplementalMessages"]) { 73 | summary["supplementalMessages"].push(msg_obj) 74 | }else { 75 | summary["supplementalMessages"] = [msg_obj] 76 | } 77 | if (consoleLog) console.log("Netflix Modified Body:\n" + JSON.stringify(obj)); 78 | $done({ body: JSON.stringify(obj) }); 79 | }); 80 | } else { 81 | $done({}); 82 | } 83 | } 84 | 85 | function getTitleMap() { 86 | const map = $tool.read(netflixTitleCacheKey); 87 | return map ? JSON.parse(map) : {}; 88 | } 89 | 90 | function setTitleMap(id, title, map) { 91 | map[id] = title; 92 | $tool.write(JSON.stringify(map), netflixTitleCacheKey); 93 | } 94 | 95 | function requestDoubanRating(imdbId) { 96 | return new Promise(function (resolve, reject) { 97 | const url = `https://www.douban.com/search?cat=1002&q=${imdbId}`; 98 | if (consoleLog) console.log("Netflix Douban Rating URL:\n" + url); 99 | $tool.get(url, function (error, response, data) { 100 | if (!error) { 101 | if (consoleLog) console.log("Netflix Douban Rating Data:\n" + data); 102 | if (response.status == 200) { 103 | const rating = get_douban_rating_message(data); 104 | resolve({ rating }); 105 | } else { 106 | resolve({ rating: "Douban: " + errorTip().noData }); 107 | } 108 | } else { 109 | if (consoleLog) console.log("Netflix Douban Rating Error:\n" + error); 110 | resolve({ rating: "Douban: " + errorTip().error }); 111 | } 112 | }); 113 | }); 114 | } 115 | 116 | function requestIMDbRating(title, year, type) { 117 | return new Promise(function (resolve, reject) { 118 | let url = "https://www.omdbapi.com/?t=" + encodeURI(title) + "&apikey=" + IMDbApikey; 119 | if (year) url += "&y=" + year; 120 | if (type) url += "&type=" + type; 121 | if (consoleLog) console.log("Netflix IMDb Rating URL:\n" + url); 122 | $tool.get(url, function (error, response, data) { 123 | if (!error) { 124 | if (consoleLog) console.log("Netflix IMDb Rating Data:\n" + data); 125 | if (response.status == 200) { 126 | const obj = JSON.parse(data); 127 | if (obj.Response != "False") { 128 | const id = obj.imdbID; 129 | const msg = get_IMDb_message(obj); 130 | resolve({ id, msg }); 131 | } else { 132 | reject(errorTip().noData); 133 | } 134 | } else if (response.status == 401) { 135 | if (IMDbApikeys.length > 1) { 136 | updateIMDbApikey(); 137 | requestIMDbRating(title, year, type); 138 | } else { 139 | reject(errorTip().noData); 140 | } 141 | } else { 142 | reject(errorTip().noData); 143 | } 144 | } else { 145 | if (consoleLog) console.log("Netflix IMDb Rating Error:\n" + error); 146 | reject(errorTip().error); 147 | } 148 | }); 149 | }); 150 | } 151 | 152 | function updateIMDbApikey() { 153 | if (IMDbApikey) IMDbApikeys.splice(IMDbApikeys.indexOf(IMDbApikey), 1); 154 | const index = Math.floor(Math.random() * IMDbApikeys.length); 155 | IMDbApikey = IMDbApikeys[index]; 156 | $tool.write(IMDbApikey, imdbApikeyCacheKey); 157 | } 158 | 159 | function get_IMDb_message(data) { 160 | let rating_message = "IMDb: ⭐️ N/A"; 161 | let tomatoes_message = ""; 162 | let country_message = ""; 163 | let ratings = data.Ratings; 164 | let awards_message = ""; 165 | if (data.Awards && data.Awards != "N/A") { 166 | awards_message = "🏆 " + data.Awards; 167 | } 168 | if (ratings.length > 0) { 169 | const imdb_source = ratings[0]["Source"]; 170 | if (imdb_source == "Internet Movie Database") { 171 | const imdb_votes = data.imdbVotes; 172 | const imdb_rating = ratings[0]["Value"]; 173 | rating_message = "IMDb: ⭐️ " + imdb_rating + " " + imdb_votes; 174 | if (data.Type == "movie") { 175 | if (ratings.length > 1) { 176 | const source = ratings[1]["Source"]; 177 | if (source == "Rotten Tomatoes") { 178 | const tomatoes = ratings[1]["Value"]; 179 | tomatoes_message = "Tomatoes: 🍅 " + tomatoes; 180 | } 181 | } 182 | } 183 | } 184 | } 185 | country_message = get_country_message(data.Country); 186 | return { rating: rating_message, tomatoes: tomatoes_message, country: country_message, awards: awards_message } 187 | } 188 | 189 | function get_douban_rating_message(data) { 190 | const s = data.replace(/\n| |&#\d{2}/g, '') 191 | .match(/\[(\u7535\u5f71|\u7535\u89c6\u5267)\].+?subject-cast\">.+?<\/span>/g); 192 | const average = s ? s[0].split(/">(\d\.\d) { 203 | emoji_country += countryEmoji(item) + " " + item + ", "; 204 | }); 205 | return emoji_country.slice(0, -2); 206 | } 207 | 208 | function errorTip() { 209 | return { noData: "⭐️ N/A", error: "❌ N/A" } 210 | } 211 | 212 | function IMDbApikeys() { 213 | const apikeys = [ 214 | "f75e0253", "d8bb2d6b", 215 | "ae64ce8d", "7218d678", 216 | "b2650e38", "8c4a29ab", 217 | "9bd135c2", "953dbabe", 218 | "1a66ef12", "3e7ea721", 219 | "457fc4ff", "d2131426", 220 | "9cc1a9b7", "e53c2c11", 221 | "f6dfce0e", "b9db622f", 222 | "e6bde2b9", "d324dbab", 223 | "d7904fa3", "aeaf88b9", 224 | "4e89234e",]; 225 | return apikeys; 226 | } 227 | 228 | function countryEmoji(name) { 229 | const emojiMap = { 230 | "Chequered": "🏁", 231 | "Triangular": "🚩", 232 | "Crossed": "🎌", 233 | "Black": "🏴", 234 | "White": "🏳", 235 | "Rainbow": "🏳️‍🌈", 236 | "Pirate": "🏴‍☠️", 237 | "Ascension Island": "🇦🇨", 238 | "Andorra": "🇦🇩", 239 | "United Arab Emirates": "🇦🇪", 240 | "Afghanistan": "🇦🇫", 241 | "Antigua & Barbuda": "🇦🇬", 242 | "Anguilla": "🇦🇮", 243 | "Albania": "🇦🇱", 244 | "Armenia": "🇦🇲", 245 | "Angola": "🇦🇴", 246 | "Antarctica": "🇦🇶", 247 | "Argentina": "🇦🇷", 248 | "American Samoa": "🇦🇸", 249 | "Austria": "🇦🇹", 250 | "Australia": "🇦🇺", 251 | "Aruba": "🇦🇼", 252 | "Åland Islands": "🇦🇽", 253 | "Azerbaijan": "🇦🇿", 254 | "Bosnia & Herzegovina": "🇧🇦", 255 | "Barbados": "🇧🇧", 256 | "Bangladesh": "🇧🇩", 257 | "Belgium": "🇧🇪", 258 | "Burkina Faso": "🇧🇫", 259 | "Bulgaria": "🇧🇬", 260 | "Bahrain": "🇧🇭", 261 | "Burundi": "🇧🇮", 262 | "Benin": "🇧🇯", 263 | "St. Barthélemy": "🇧🇱", 264 | "Bermuda": "🇧🇲", 265 | "Brunei": "🇧🇳", 266 | "Bolivia": "🇧🇴", 267 | "Caribbean Netherlands": "🇧🇶", 268 | "Brazil": "🇧🇷", 269 | "Bahamas": "🇧🇸", 270 | "Bhutan": "🇧🇹", 271 | "Bouvet Island": "🇧🇻", 272 | "Botswana": "🇧🇼", 273 | "Belarus": "🇧🇾", 274 | "Belize": "🇧🇿", 275 | "Canada": "🇨🇦", 276 | "Cocos (Keeling) Islands": "🇨🇨", 277 | "Congo - Kinshasa": "🇨🇩", 278 | "Congo": "🇨🇩", 279 | "Central African Republic": "🇨🇫", 280 | "Congo - Brazzaville": "🇨🇬", 281 | "Switzerland": "🇨🇭", 282 | "Côte d’Ivoire": "🇨🇮", 283 | "Cook Islands": "🇨🇰", 284 | "Chile": "🇨🇱", 285 | "Cameroon": "🇨🇲", 286 | "China": "🇨🇳", 287 | "Colombia": "🇨🇴", 288 | "Clipperton Island": "🇨🇵", 289 | "Costa Rica": "🇨🇷", 290 | "Cuba": "🇨🇺", 291 | "Cape Verde": "🇨🇻", 292 | "Curaçao": "🇨🇼", 293 | "Christmas Island": "🇨🇽", 294 | "Cyprus": "🇨🇾", 295 | "Czechia": "🇨🇿", 296 | "Czech Republic": "🇨🇿", 297 | "Germany": "🇩🇪", 298 | "Diego Garcia": "🇩🇬", 299 | "Djibouti": "🇩🇯", 300 | "Denmark": "🇩🇰", 301 | "Dominica": "🇩🇲", 302 | "Dominican Republic": "🇩🇴", 303 | "Algeria": "🇩🇿", 304 | "Ceuta & Melilla": "🇪🇦", 305 | "Ecuador": "🇪🇨", 306 | "Estonia": "🇪🇪", 307 | "Egypt": "🇪🇬", 308 | "Western Sahara": "🇪🇭", 309 | "Eritrea": "🇪🇷", 310 | "Spain": "🇪🇸", 311 | "Ethiopia": "🇪🇹", 312 | "European Union": "🇪🇺", 313 | "Finland": "🇫🇮", 314 | "Fiji": "🇫🇯", 315 | "Falkland Islands": "🇫🇰", 316 | "Micronesia": "🇫🇲", 317 | "Faroe Islands": "🇫🇴", 318 | "France": "🇫🇷", 319 | "Gabon": "🇬🇦", 320 | "United Kingdom": "🇬🇧", 321 | "UK": "🇬🇧", 322 | "Grenada": "🇬🇩", 323 | "Georgia": "🇬🇪", 324 | "French Guiana": "🇬🇫", 325 | "Guernsey": "🇬🇬", 326 | "Ghana": "🇬🇭", 327 | "Gibraltar": "🇬🇮", 328 | "Greenland": "🇬🇱", 329 | "Gambia": "🇬🇲", 330 | "Guinea": "🇬🇳", 331 | "Guadeloupe": "🇬🇵", 332 | "Equatorial Guinea": "🇬🇶", 333 | "Greece": "🇬🇷", 334 | "South Georgia & South Sandwich Is lands": "🇬🇸", 335 | "Guatemala": "🇬🇹", 336 | "Guam": "🇬🇺", 337 | "Guinea-Bissau": "🇬🇼", 338 | "Guyana": "🇬🇾", 339 | "Hong Kong SAR China": "🇭🇰", 340 | "Hong Kong": "🇭🇰", 341 | "Heard & McDonald Islands": "🇭🇲", 342 | "Honduras": "🇭🇳", 343 | "Croatia": "🇭🇷", 344 | "Haiti": "🇭🇹", 345 | "Hungary": "🇭🇺", 346 | "Canary Islands": "🇮🇨", 347 | "Indonesia": "🇮🇩", 348 | "Ireland": "🇮🇪", 349 | "Israel": "🇮🇱", 350 | "Isle of Man": "🇮🇲", 351 | "India": "🇮🇳", 352 | "British Indian Ocean Territory": "🇮🇴", 353 | "Iraq": "🇮🇶", 354 | "Iran": "🇮🇷", 355 | "Iceland": "🇮🇸", 356 | "Italy": "🇮🇹", 357 | "Jersey": "🇯🇪", 358 | "Jamaica": "🇯🇲", 359 | "Jordan": "🇯🇴", 360 | "Japan": "🇯🇵", 361 | "Kenya": "🇰🇪", 362 | "Kyrgyzstan": "🇰🇬", 363 | "Cambodia": "🇰🇭", 364 | "Kiribati": "🇰🇮", 365 | "Comoros": "🇰🇲", 366 | "St. Kitts & Nevis": "🇰🇳", 367 | "North Korea": "🇰🇵", 368 | "South Korea": "🇰🇷", 369 | "Kuwait": "🇰🇼", 370 | "Cayman Islands": "🇰🇾", 371 | "Kazakhstan": "🇰🇿", 372 | "Laos": "🇱🇦", 373 | "Lebanon": "🇱🇧", 374 | "St. Lucia": "🇱🇨", 375 | "Liechtenstein": "🇱🇮", 376 | "Sri Lanka": "🇱🇰", 377 | "Liberia": "🇱🇷", 378 | "Lesotho": "🇱🇸", 379 | "Lithuania": "🇱🇹", 380 | "Luxembourg": "🇱🇺", 381 | "Latvia": "🇱🇻", 382 | "Libya": "🇱🇾", 383 | "Morocco": "🇲🇦", 384 | "Monaco": "🇲🇨", 385 | "Moldova": "🇲🇩", 386 | "Montenegro": "🇲🇪", 387 | "St. Martin": "🇲🇫", 388 | "Madagascar": "🇲🇬", 389 | "Marshall Islands": "🇲🇭", 390 | "North Macedonia": "🇲🇰", 391 | "Mali": "🇲🇱", 392 | "Myanmar (Burma)": "🇲🇲", 393 | "Mongolia": "🇲🇳", 394 | "Macau Sar China": "🇲🇴", 395 | "Northern Mariana Islands": "🇲🇵", 396 | "Martinique": "🇲🇶", 397 | "Mauritania": "🇲🇷", 398 | "Montserrat": "🇲🇸", 399 | "Malta": "🇲🇹", 400 | "Mauritius": "🇲🇺", 401 | "Maldives": "🇲🇻", 402 | "Malawi": "🇲🇼", 403 | "Mexico": "🇲🇽", 404 | "Malaysia": "🇲🇾", 405 | "Mozambique": "🇲🇿", 406 | "Namibia": "🇳🇦", 407 | "New Caledonia": "🇳🇨", 408 | "Niger": "🇳🇪", 409 | "Norfolk Island": "🇳🇫", 410 | "Nigeria": "🇳🇬", 411 | "Nicaragua": "🇳🇮", 412 | "Netherlands": "🇳🇱", 413 | "Norway": "🇳🇴", 414 | "Nepal": "🇳🇵", 415 | "Nauru": "🇳🇷", 416 | "Niue": "🇳🇺", 417 | "New Zealand": "🇳🇿", 418 | "Oman": "🇴🇲", 419 | "Panama": "🇵🇦", 420 | "Peru": "🇵🇪", 421 | "French Polynesia": "🇵🇫", 422 | "Papua New Guinea": "🇵🇬", 423 | "Philippines": "🇵🇭", 424 | "Pakistan": "🇵🇰", 425 | "Poland": "🇵🇱", 426 | "St. Pierre & Miquelon": "🇵🇲", 427 | "Pitcairn Islands": "🇵🇳", 428 | "Puerto Rico": "🇵🇷", 429 | "Palestinian Territories": "🇵🇸", 430 | "Portugal": "🇵🇹", 431 | "Palau": "🇵🇼", 432 | "Paraguay": "🇵🇾", 433 | "Qatar": "🇶🇦", 434 | "Réunion": "🇷🇪", 435 | "Romania": "🇷🇴", 436 | "Serbia": "🇷🇸", 437 | "Russia": "🇷🇺", 438 | "Rwanda": "🇷🇼", 439 | "Saudi Arabia": "🇸🇦", 440 | "Solomon Islands": "🇸🇧", 441 | "Seychelles": "🇸🇨", 442 | "Sudan": "🇸🇩", 443 | "Sweden": "🇸🇪", 444 | "Singapore": "🇸🇬", 445 | "St. Helena": "🇸🇭", 446 | "Slovenia": "🇸🇮", 447 | "Svalbard & Jan Mayen": "🇸🇯", 448 | "Slovakia": "🇸🇰", 449 | "Sierra Leone": "🇸🇱", 450 | "San Marino": "🇸🇲", 451 | "Senegal": "🇸🇳", 452 | "Somalia": "🇸🇴", 453 | "Suriname": "🇸🇷", 454 | "South Sudan": "🇸🇸", 455 | "São Tomé & Príncipe": "🇸🇹", 456 | "El Salvador": "🇸🇻", 457 | "Sint Maarten": "🇸🇽", 458 | "Syria": "🇸🇾", 459 | "Swaziland": "🇸🇿", 460 | "Tristan Da Cunha": "🇹🇦", 461 | "Turks & Caicos Islands": "🇹🇨", 462 | "Chad": "🇹🇩", 463 | "French Southern Territories": "🇹🇫", 464 | "Togo": "🇹🇬", 465 | "Thailand": "🇹🇭", 466 | "Tajikistan": "🇹🇯", 467 | "Tokelau": "🇹🇰", 468 | "Timor-Leste": "🇹🇱", 469 | "Turkmenistan": "🇹🇲", 470 | "Tunisia": "🇹🇳", 471 | "Tonga": "🇹🇴", 472 | "Turkey": "🇹🇷", 473 | "Trinidad & Tobago": "🇹🇹", 474 | "Tuvalu": "🇹🇻", 475 | "Taiwan": "🇨🇳", 476 | "Tanzania": "🇹🇿", 477 | "Ukraine": "🇺🇦", 478 | "Uganda": "🇺🇬", 479 | "U.S. Outlying Islands": "🇺🇲", 480 | "United Nations": "🇺🇳", 481 | "United States": "🇺🇸", 482 | "USA": "🇺🇸", 483 | "Uruguay": "🇺🇾", 484 | "Uzbekistan": "🇺🇿", 485 | "Vatican City": "🇻🇦", 486 | "St. Vincent & Grenadines": "🇻🇨", 487 | "Venezuela": "🇻🇪", 488 | "British Virgin Islands": "🇻🇬", 489 | "U.S. Virgin Islands": "🇻🇮", 490 | "Vietnam": "🇻🇳", 491 | "Vanuatu": "🇻🇺", 492 | "Wallis & Futuna": "🇼🇫", 493 | "Samoa": "🇼🇸", 494 | "Kosovo": "🇽🇰", 495 | "Yemen": "🇾🇪", 496 | "Mayotte": "🇾🇹", 497 | "South Africa": "🇿🇦", 498 | "Zambia": "🇿🇲", 499 | "Zimbabwe": "🇿🇼", 500 | "England": "🏴󠁧󠁢󠁥󠁮󠁧󠁿", 501 | "Scotland": "🏴󠁧󠁢󠁳󠁣󠁴󠁿", 502 | "Wales": "🏴󠁧󠁢󠁷󠁬󠁳󠁿", 503 | } 504 | return emojiMap[name] ? emojiMap[name] : emojiMap["Chequered"]; 505 | } 506 | 507 | function Tool() { 508 | _node = (() => { 509 | if (typeof require == "function") { 510 | const request = require('request') 511 | return ({ request }) 512 | } else { 513 | return (null) 514 | } 515 | })() 516 | _isSurge = typeof $httpClient != "undefined" 517 | _isQuanX = typeof $task != "undefined" 518 | this.isSurge = _isSurge 519 | this.isQuanX = _isQuanX 520 | this.isResponse = typeof $response != "undefined" 521 | this.notify = (title, subtitle, message) => { 522 | if (_isQuanX) $notify(title, subtitle, message) 523 | if (_isSurge) $notification.post(title, subtitle, message) 524 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 525 | } 526 | this.write = (value, key) => { 527 | if (_isQuanX) return $prefs.setValueForKey(value, key) 528 | if (_isSurge) return $persistentStore.write(value, key) 529 | } 530 | this.read = (key) => { 531 | if (_isQuanX) return $prefs.valueForKey(key) 532 | if (_isSurge) return $persistentStore.read(key) 533 | } 534 | this.get = (options, callback) => { 535 | if (_isQuanX) { 536 | if (typeof options == "string") options = { url: options } 537 | options["method"] = "GET" 538 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 539 | } 540 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 541 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 542 | } 543 | this.post = (options, callback) => { 544 | if (_isQuanX) { 545 | if (typeof options == "string") options = { url: options } 546 | options["method"] = "POST" 547 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 548 | } 549 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 550 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 551 | } 552 | _status = (response) => { 553 | if (response) { 554 | if (response.status) { 555 | response["statusCode"] = response.status 556 | } else if (response.statusCode) { 557 | response["status"] = response.statusCode 558 | } 559 | } 560 | return response 561 | } 562 | } 563 | -------------------------------------------------------------------------------- /nf_rating_season.js: -------------------------------------------------------------------------------- 1 | /** 2 | * nf_rating_season.js = type=http-response,pattern=^https?://ios\.prod\.ftl\.netflix\.com/iosui/warmer/.+type=show-ath,requires-body=1,max-size=0,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating_season.js 3 | */ 4 | 5 | const $tool = new Tool() 6 | const url = $request.url 7 | const body = $response.body 8 | const imdbApikeyCacheKey = "ImdbApikeyCacheKey" 9 | const netflixTitleCacheKey = "NetflixTitleCacheKey" 10 | const map = $tool.read(netflixTitleCacheKey) 11 | const id = url.match(/id=(\d+)/)[1] 12 | const title = map ? JSON.parse(map)[id] : null 13 | const obj = JSON.parse(body) 14 | 15 | if (title && obj.shows[id].seasons) { 16 | const key = $tool.read(imdbApikeyCacheKey) 17 | const seasons = obj.shows[id].seasons.map(item => item.season) 18 | const promises = [] 19 | for (let index = 0; index < seasons.length; index++) { 20 | const url = `https://www.omdbapi.com/?t=${title}&apikey=${key}&type=series&Season=${seasons[index]}` 21 | promises.push(requestSeasonRating(encodeURI(url))) 22 | } 23 | Promise.all(promises).then((values) => { 24 | // console.log(values) 25 | for (let index = 0; index < values.length; index++) { 26 | const imdb = values[index] 27 | if (imdb) { 28 | const imdbSeasonNumber = imdb.Season 29 | const imdbEpisodes = imdb.Episodes 30 | const entities = obj.entities 31 | for (let [key, value] of Object.entries(entities)) { 32 | // console.log(`${key}: ${value}`); 33 | const seasonNumber = value.summary.seasonNumber 34 | const episodeNumber = value.summary.episodeNumber 35 | let title = value.summary.title 36 | if (parseInt(imdbSeasonNumber) == seasonNumber) { 37 | const imdbEpisode = imdbEpisodes.find(element => parseInt(element.Episode) == episodeNumber) 38 | title = `${title}${imdbEpisode && imdbEpisode.imdbRating ? ` ⭐️ ${imdbEpisode.imdbRating}` : " ⭐️ N/A"}` 39 | value.summary.title = title 40 | //console.log(title); 41 | } 42 | } 43 | } 44 | } 45 | // console.log(JSON.stringify(obj)) 46 | $tool.done({ body: JSON.stringify(obj) }) 47 | }) 48 | } else { 49 | $tool.done({}) 50 | } 51 | 52 | function requestSeasonRating(url) { 53 | return new Promise((resolve) => { 54 | $tool.get(url, (error, response, body) => { 55 | if (!error) { 56 | const code = response.statusCode 57 | if (code == 200) { 58 | const obj = JSON.parse(body) 59 | if (obj.Response != "False") { 60 | //console.log(`successfully: ${url}`) 61 | resolve(obj) 62 | } else { 63 | //console.log(`failed: ${obj.Error} -> ${url}`) 64 | resolve(null) 65 | } 66 | } else { 67 | //console.log(`failed: ${response.statusCode} -> ${url}`) 68 | resolve(null) 69 | } 70 | } else { 71 | //console.log(`faile: ${error}`) 72 | resolve(null) 73 | } 74 | }) 75 | }) 76 | } 77 | 78 | function Tool() { 79 | _node = (() => { 80 | if (typeof require == "function") { 81 | const request = require('request') 82 | return ({ request }) 83 | } else { 84 | return (null) 85 | } 86 | })() 87 | _isSurge = typeof $httpClient != "undefined" 88 | _isQuanX = typeof $task != "undefined" 89 | _isTask = typeof $request == "undefined" 90 | _isResponse = typeof $response != "undefined" 91 | _isRequestBody = typeof $request != "undefined" && typeof $request.body != "undefined" 92 | this.isSurge = _isSurge 93 | this.isQuanX = _isQuanX 94 | this.isTask = _isTask 95 | this.isResponse = _isResponse 96 | this.isRequestBody = _isRequestBody 97 | this.method = (() => { 98 | if (!_isTask && (_isSurge || _isQuanX)) { 99 | return $request.method 100 | } 101 | })() 102 | this.scriptType = (() => { 103 | if (_isResponse) { 104 | return "response" 105 | } else { 106 | return "request" 107 | } 108 | })() 109 | this.done = (obj) => { 110 | if (_isQuanX) $done(obj) 111 | if (_isSurge) $done(obj) 112 | if (_node) console.log("script done."); 113 | } 114 | this.notify = (title, subtitle, message) => { 115 | if (_isQuanX) $notify(title, subtitle, message) 116 | if (_isSurge) $notification.post(title, subtitle, message) 117 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 118 | } 119 | this.write = (value, key) => { 120 | if (_isQuanX) return $prefs.setValueForKey(value, key) 121 | if (_isSurge) return $persistentStore.write(value, key) 122 | if (_node) console.log(`write success: ${key}`); 123 | } 124 | this.read = (key) => { 125 | if (_isQuanX) return $prefs.valueForKey(key) 126 | if (_isSurge) return $persistentStore.read(key) 127 | if (_node) console.log(`read success: ${key}`); 128 | } 129 | this.get = (options, callback) => { 130 | if (_isQuanX) { 131 | if (typeof options == "string") options = { url: options } 132 | options["method"] = "GET" 133 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 134 | } 135 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 136 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 137 | } 138 | this.put = (options, callback) => { 139 | if (_isQuanX) $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 140 | if (_isSurge) $httpClient.put(options, (error, response, body) => { callback(error, _status(response), body) }) 141 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 142 | } 143 | this.post = (options, callback) => { 144 | if (_isQuanX) { 145 | if (typeof options == "string") options = { url: options } 146 | options["method"] = "POST" 147 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 148 | } 149 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 150 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 151 | } 152 | _status = (response) => { 153 | if (response) { 154 | if (response.status) { 155 | response["statusCode"] = response.status 156 | } else if (response.statusCode) { 157 | response["status"] = response.statusCode 158 | } 159 | } 160 | return response 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /qx_sub.txt: -------------------------------------------------------------------------------- 1 | hostname = api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios-*.prod.ftl.netflix.com,ios.prod.ftl.netflix.com 2 | 3 | ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-request-header https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 4 | ^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 5 | ^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js 6 | ^http://.+/amdc/mobileDispatch url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 7 | ^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 8 | ^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js 9 | ^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info|remind/unread_count) url script-response-body https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js 10 | -------------------------------------------------------------------------------- /sg_sub.sgmodule: -------------------------------------------------------------------------------- 1 | #!name=eval_script.js module 2 | 3 | [MITM] 4 | hostname = %INSERT% api.weibo.cn,mapi.weibo.com,*.uve.weibo.com,trade-acs.m.taobao.com,api.m.jd.com,ios-*.prod.ftl.netflix.com,ios.prod.ftl.netflix.com 5 | 6 | [Script] 7 | nf_rating.js = type=http-request,pattern=^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 8 | nf_rating.js = type=http-response,requires-body=1,pattern=^https?://ios(-.*)?\.prod\.ftl\.netflix\.com/iosui/user/.+path=%5B%22videos%22%2C%\d+%22%2C%22summary%22%5D,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/nf_rating.js 9 | jd_price.js = type=http-response,requires-body=1,pattern=^https?://api\.m\.jd\.com/client\.action\?functionId=(wareBusiness|serverConfig|basicConfig),script-path=https://raw.githubusercontent.com/yichahucha/surge/master/jd_price.js 10 | tb_price.js = type=http-response,requires-body=1,pattern=^http://.+/amdc/mobileDispatch,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 11 | tb_price.js = type=http-response,requires-body=1,pattern=^https?://trade-acs\.m\.taobao\.com/gw/mtop\.taobao\.detail\.getdetail,script-path=https://raw.githubusercontent.com/yichahucha/surge/master/tb_price.js 12 | wb_launch.js = type=http-response,requires-body=1,pattern=^https?://(sdk|wb)app\.uve\.weibo\.com(/interface/sdk/sdkad.php|/wbapplua/wbpullad.lua),script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_launch.js 13 | wb_ad.js = type=http-response,requires-body=1,max-size=-1,pattern=^https?://m?api\.weibo\.c(n|om)/2/(statuses/(unread|extend|positives/get|(friends|video)(/|_)(mix)?timeline)|stories/(video_stream|home_list)|(groups|fangle)/timeline|profile/statuses|comments/build_comments|photo/recommend_list|service/picfeed|searchall|cardlist|page|!/(photos/pic_recommend_status|live/media_homelist)|video/tiny_stream_video_list|photo/info|remind/unread_count),script-path=https://raw.githubusercontent.com/yichahucha/surge/master/wb_ad.js 14 | -------------------------------------------------------------------------------- /tb_pre.js: -------------------------------------------------------------------------------- 1 | let headers = $request.headers 2 | let body = $request.body 3 | if (headers["User-Agent"].indexOf("%E6%89%8B%E6%9C%BA%E6%B7%98%E5%AE%9D") != -1) { 4 | let json = Qs2Json(body) 5 | let domain = json.domain.split(" ") 6 | let i = domain.length; 7 | while (i--) { 8 | const block = "trade-acs.m.taobao.com" 9 | const element = domain[i]; 10 | if (element == block) { 11 | domain.splice(i, 1); 12 | } 13 | } 14 | json.domain = domain.join(" ") 15 | body = Json2Qs(json) 16 | } 17 | $done({ 18 | body 19 | }) 20 | 21 | function Qs2Json(url) { 22 | var search = url.substring(url.lastIndexOf("?") + 1); 23 | var obj = {}; 24 | var reg = /([^?&=]+)=([^?&=]*)/g; 25 | search.replace(reg, function(rs, $1, $2) { 26 | var name = decodeURIComponent($1); 27 | var val = decodeURIComponent($2); 28 | val = String(val); 29 | obj[name] = val; 30 | return rs; 31 | }); 32 | return obj; 33 | } 34 | 35 | function Json2Qs(json) { 36 | var temp = []; 37 | for (var k in json) { 38 | temp.push(k + "=" + json[k]); 39 | } 40 | return temp.join("&"); 41 | } -------------------------------------------------------------------------------- /tb_price.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const $tool = new Tool() 6 | const path1 = "/amdc/mobileDispatch" 7 | const path2 = "/gw/mtop.taobao.detail.getdetail" 8 | const consoleLog = false 9 | const url = $request.url 10 | 11 | if (url.indexOf(path1) != -1) { 12 | if ($tool.isResponse) { 13 | const $base64 = new Base64() 14 | let body = $response.body 15 | let obj = JSON.parse($base64.decode(body)) 16 | let dns = obj.dns 17 | if (dns && dns.length > 0) { 18 | let i = dns.length; 19 | while (i--) { 20 | const element = dns[i]; 21 | let host = "trade-acs.m.taobao.com" 22 | if (element.host == host) { 23 | element.ips = [] 24 | if (consoleLog) console.log(JSON.stringify(element)) 25 | } 26 | } 27 | } 28 | body = $base64.encode(JSON.stringify(obj)) 29 | $done({ body }) 30 | } else { 31 | let headers = $request.headers 32 | let body = $request.body 33 | if (headers["User-Agent"].indexOf("%E6%89%8B%E6%9C%BA%E6%B7%98%E5%AE%9D") != -1) { 34 | let json = Qs2Json(body) 35 | let domain = json.domain.split(" ") 36 | let i = domain.length; 37 | while (i--) { 38 | const block = "trade-acs.m.taobao.com" 39 | const element = domain[i]; 40 | if (element == block) { 41 | domain.splice(i, 1); 42 | } 43 | } 44 | json.domain = domain.join(" ") 45 | body = Json2Qs(json) 46 | } 47 | $done({ body }) 48 | } 49 | } 50 | 51 | if (url.indexOf(path2) != -1) { 52 | const body = $response.body 53 | let obj = JSON.parse(body) 54 | let item = obj.data.item 55 | let shareUrl = `https://item.taobao.com/item.htm?id=${item.itemId}` 56 | let msg 57 | request_history_price(shareUrl) 58 | .then(data => { 59 | if (data.errno == -1) throw new Error('Whoops!') 60 | msg = data 61 | }) 62 | .catch(error => msg = "暂无价格信息") 63 | .finally(() => { 64 | if (obj.data.apiStack) { 65 | let apiStack = obj.data.apiStack[0] 66 | let value = JSON.parse(apiStack.value) 67 | let tradeConsumerProtection = null 68 | let consumerProtection = null 69 | let trade = null 70 | let vertical = null 71 | if (value.global) { 72 | tradeConsumerProtection = value.global.data.tradeConsumerProtection 73 | consumerProtection = value.global.data.consumerProtection 74 | trade = value.global.data.trade 75 | vertical = value.global.data.vertical 76 | } else { 77 | tradeConsumerProtection = value.tradeConsumerProtection 78 | consumerProtection = value.consumerProtection 79 | trade = value.trade 80 | vertical = value.vertical 81 | } 82 | if (trade && trade.useWap == "true") { 83 | sendNotify(msg) 84 | } else { 85 | if (vertical && vertical.hasOwnProperty("tmallhkDirectSale")) { 86 | sendNotify(msg) 87 | } else if (tradeConsumerProtection) { 88 | tradeConsumerProtection = setTradeConsumerProtection(msg, tradeConsumerProtection) 89 | } else { 90 | consumerProtection = setConsumerProtection(msg, consumerProtection) 91 | } 92 | apiStack.value = JSON.stringify(value) 93 | } 94 | } else { 95 | sendNotify(msg) 96 | } 97 | $done({ body: JSON.stringify(obj) }) 98 | }) 99 | } 100 | 101 | function sendNotify(data) { 102 | if (data.data.PricesHistory == null) { 103 | $tool.notify("", "", `暂无历史价格`) 104 | } else { 105 | const detail = priceSummary(data.data) 106 | $tool.notify("", "", `${detail}`) 107 | } 108 | } 109 | 110 | function setConsumerProtection(data, consumerProtection) { 111 | let basicService = consumerProtection.serviceProtection.basicService 112 | let items = consumerProtection.items 113 | if (data.data.PricesHistory == null) { 114 | let item = customItem("暂无历史价格", []) 115 | basicService.services.unshift(item) 116 | items.unshift(item) 117 | } else { 118 | const summary = priceSummary(data.data)[1] 119 | const item = customItem("🌨 历史价格详情", [`${summary}`]) 120 | basicService.services.unshift(item) 121 | items.unshift(item) 122 | } 123 | return consumerProtection 124 | } 125 | 126 | function setTradeConsumerProtection(data, tradeConsumerProtection) { 127 | let service = tradeConsumerProtection.tradeConsumerService.service 128 | if (data.data.PricesHistory == null) { 129 | service.items.unshift(customItem("暂无历史价格", "")) 130 | } else { 131 | const tbitems = priceSummary(data.data)[0] 132 | let nonService = tradeConsumerProtection.tradeConsumerService.nonService 133 | service.items = service.items.concat(nonService.items) 134 | nonService.title = "🌨 历史价格详情" 135 | nonService.items = tbitems 136 | } 137 | return tradeConsumerProtection 138 | } 139 | 140 | function priceSummary(data) { 141 | let summary = `当前: ${data.CurrentPrice}${getSpace(8)}最低: ${data.LowestPrice} (${data.LowestDate})` 142 | let tbitems = [customItem(summary)] 143 | const list = historySummary(data.PricesHistory) 144 | list.forEach((item, index) => { 145 | summary += `\n${item.Name}${getSpace(4)}${item.Price}${getSpace(4)}${item.Date}${getSpace(4)}${item.Difference}` 146 | let summaryItem = `${item.Name}${getSpace(3)}${item.Price}${getSpace(3)}${item.Date}${getSpace(3)}${item.Difference}` 147 | tbitems.push(customItem(summaryItem)) 148 | }); 149 | return [tbitems, summary] 150 | } 151 | 152 | function historySummary(list) { 153 | let currentPrice, lowest30, lowest90, lowest180, lowest360, price11, price618; 154 | list = list.reverse().slice(0, 360); 155 | list.forEach((item, index) => { 156 | const date = item.Date; 157 | let price = item.Price; 158 | if (index == 0) { 159 | currentPrice = price; 160 | price618 = { 161 | Name: "六一八价格", 162 | Price: "-", 163 | Date: "-", 164 | Difference: "-", 165 | price: "-", 166 | }; 167 | price11 = { 168 | Name: "双十一价格", 169 | Price: "-", 170 | Date: "-", 171 | Difference: "-", 172 | price: "-", 173 | }; 174 | lowest30 = { 175 | Name: "三十天最低", 176 | Price: `¥${String(price)}`, 177 | Date: date, 178 | Difference: difference(currentPrice, price), 179 | price, 180 | }; 181 | lowest90 = { 182 | Name: "九十天最低", 183 | Price: `¥${String(price)}`, 184 | Date: date, 185 | Difference: difference(currentPrice, price), 186 | price, 187 | }; 188 | lowest180 = { 189 | Name: "一百八最低", 190 | Price: `¥${String(price)}`, 191 | Date: date, 192 | Difference: difference(currentPrice, price), 193 | price, 194 | }; 195 | lowest360 = { 196 | Name: "三百六最低", 197 | Price: `¥${String(price)}`, 198 | Date: date, 199 | Difference: difference(currentPrice, price), 200 | price, 201 | }; 202 | } 203 | if (date.indexOf("06-18") != -1) { 204 | price618.price = price; 205 | price618.Price = `¥${String(price)}`; 206 | price618.Date = date; 207 | price618.Difference = difference(currentPrice, price); 208 | } 209 | if (date.indexOf("11-11") != -1) { 210 | price11.price = price; 211 | price11.Price = `¥${String(price)}`; 212 | price11.Date = date; 213 | price11.Difference = difference(currentPrice, price); 214 | } 215 | if (index < 30 && price < lowest30.price) { 216 | lowest30.price = price; 217 | lowest30.Price = `¥${String(price)}`; 218 | lowest30.Date = date; 219 | lowest30.Difference = difference(currentPrice, price); 220 | } 221 | if (index < 90 && price < lowest90.price) { 222 | lowest90.price = price; 223 | lowest90.Price = `¥${String(price)}`; 224 | lowest90.Date = date; 225 | lowest90.Difference = difference(currentPrice, price); 226 | } 227 | if (index < 180 && price < lowest180.price) { 228 | lowest180.price = price; 229 | lowest180.Price = `¥${String(price)}`; 230 | lowest180.Date = date; 231 | lowest180.Difference = difference(currentPrice, price); 232 | } 233 | if (index < 360 && price < lowest360.price) { 234 | lowest360.price = price; 235 | lowest360.Price = `¥${String(price)}`; 236 | lowest360.Date = date; 237 | lowest360.Difference = difference(currentPrice, price); 238 | } 239 | }); 240 | return [lowest30, lowest90, lowest180, lowest360, price618, price11]; 241 | } 242 | 243 | async function request_history_price(share_url) { 244 | const options = { 245 | headers: { 246 | "Content-Type": "application/json; charset=utf-8", 247 | }, 248 | }; 249 | 250 | const priceTrend = new Promise(function (resolve, reject) { 251 | options.url = "https://price.icharle.com/?product_id=" + share_url; 252 | $tool.get(options, function (error, response, data) { 253 | if (!error) { 254 | resolve(JSON.parse(data)); 255 | } else { 256 | reject(error); 257 | } 258 | }); 259 | }); 260 | const priceTrendData = await priceTrend; 261 | return priceTrendData; 262 | } 263 | 264 | function getExactTime(time) { 265 | var date = new Date(time * 1000); 266 | var year = date.getFullYear() + "-"; 267 | var month = 268 | (date.getMonth() + 1 < 10 269 | ? "0" + (date.getMonth() + 1) 270 | : date.getMonth() + 1) + "-"; 271 | var dates = date.getDate(); 272 | return year + month + dates; 273 | } 274 | 275 | function difference(currentPrice, price) { 276 | let difference = sub(currentPrice, price) 277 | if (difference == 0) { 278 | return "-" 279 | } else { 280 | return `${difference > 0 ? "↑" : "↓"}${String(Math.abs(difference))}` 281 | } 282 | } 283 | 284 | function sub(arg1, arg2) { 285 | return add(arg1, -Number(arg2), arguments[2]); 286 | } 287 | 288 | function add(arg1, arg2) { 289 | arg1 = arg1.toString(), arg2 = arg2.toString(); 290 | var arg1Arr = arg1.split("."), arg2Arr = arg2.split("."), d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 291 | var maxLen = Math.max(d1.length, d2.length); 292 | var m = Math.pow(10, maxLen); 293 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 294 | var d = arguments[2]; 295 | return typeof d === "number" ? Number((result).toFixed(d)) : result; 296 | } 297 | 298 | function getSpace(length) { 299 | let blank = ""; 300 | for (let index = 0; index < length; index++) { 301 | blank += " "; 302 | } 303 | return blank; 304 | } 305 | 306 | function customItem(title, desc) { 307 | return { 308 | icon: "https://s2.ax1x.com/2020/02/16/3STeIJ.png", 309 | title: title, 310 | name: title, 311 | desc: desc 312 | } 313 | } 314 | 315 | function Qs2Json(url) { 316 | var search = url.substring(url.lastIndexOf("?") + 1); 317 | var obj = {}; 318 | var reg = /([^?&=]+)=([^?&=]*)/g; 319 | search.replace(reg, function (rs, $1, $2) { 320 | var name = decodeURIComponent($1); 321 | var val = decodeURIComponent($2); 322 | val = String(val); 323 | obj[name] = val; 324 | return rs; 325 | }); 326 | return obj; 327 | } 328 | 329 | function Json2Qs(json) { 330 | var temp = []; 331 | for (var k in json) { 332 | temp.push(k + "=" + json[k]); 333 | } 334 | return temp.join("&"); 335 | } 336 | 337 | Array.prototype.insert = function (index, item) { 338 | this.splice(index, 0, item); 339 | }; 340 | 341 | Date.prototype.format = function (fmt) { 342 | var o = { 343 | "y+": this.getFullYear(), 344 | "M+": this.getMonth() + 1, 345 | "d+": this.getDate(), 346 | "h+": this.getHours(), 347 | "m+": this.getMinutes(), 348 | "s+": this.getSeconds(), 349 | "q+": Math.floor((this.getMonth() + 3) / 3), 350 | "S+": this.getMilliseconds() 351 | }; 352 | for (var k in o) { 353 | if (new RegExp("(" + k + ")").test(fmt)) { 354 | if (k == "y+") { 355 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 356 | } 357 | else if (k == "S+") { 358 | var lens = RegExp.$1.length; 359 | lens = lens == 1 ? 3 : lens; 360 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 361 | } 362 | else { 363 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 364 | } 365 | } 366 | } 367 | return fmt; 368 | } 369 | 370 | function Tool() { 371 | _node = (() => { 372 | if (typeof require == "function") { 373 | const request = require('request') 374 | return ({ request }) 375 | } else { 376 | return (null) 377 | } 378 | })() 379 | _isSurge = typeof $httpClient != "undefined" 380 | _isQuanX = typeof $task != "undefined" 381 | this.isSurge = _isSurge 382 | this.isQuanX = _isQuanX 383 | this.isResponse = typeof $response != "undefined" 384 | this.notify = (title, subtitle, message) => { 385 | if (_isQuanX) $notify(title, subtitle, message) 386 | if (_isSurge) $notification.post(title, subtitle, message) 387 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 388 | } 389 | this.write = (value, key) => { 390 | if (_isQuanX) return $prefs.setValueForKey(value, key) 391 | if (_isSurge) return $persistentStore.write(value, key) 392 | } 393 | this.read = (key) => { 394 | if (_isQuanX) return $prefs.valueForKey(key) 395 | if (_isSurge) return $persistentStore.read(key) 396 | } 397 | this.get = (options, callback) => { 398 | if (_isQuanX) { 399 | if (typeof options == "string") options = { url: options } 400 | options["method"] = "GET" 401 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 402 | } 403 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 404 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 405 | } 406 | this.post = (options, callback) => { 407 | if (_isQuanX) { 408 | if (typeof options == "string") options = { url: options } 409 | options["method"] = "POST" 410 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 411 | } 412 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 413 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 414 | } 415 | _status = (response) => { 416 | if (response) { 417 | if (response.status) { 418 | response["statusCode"] = response.status 419 | } else if (response.statusCode) { 420 | response["status"] = response.statusCode 421 | } 422 | } 423 | return response 424 | } 425 | } 426 | 427 | function Base64() { 428 | // private property 429 | _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 430 | // public method for encoding 431 | this.encode = function (input) { 432 | var output = ""; 433 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 434 | var i = 0; 435 | input = _utf8_encode(input); 436 | while (i < input.length) { 437 | chr1 = input.charCodeAt(i++); 438 | chr2 = input.charCodeAt(i++); 439 | chr3 = input.charCodeAt(i++); 440 | enc1 = chr1 >> 2; 441 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 442 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 443 | enc4 = chr3 & 63; 444 | if (isNaN(chr2)) { 445 | enc3 = enc4 = 64; 446 | } else if (isNaN(chr3)) { 447 | enc4 = 64; 448 | } 449 | output = output + 450 | _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + 451 | _keyStr.charAt(enc3) + _keyStr.charAt(enc4); 452 | } 453 | return output; 454 | } 455 | // public method for decoding 456 | this.decode = function (input) { 457 | var output = ""; 458 | var chr1, chr2, chr3; 459 | var enc1, enc2, enc3, enc4; 460 | var i = 0; 461 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 462 | while (i < input.length) { 463 | enc1 = _keyStr.indexOf(input.charAt(i++)); 464 | enc2 = _keyStr.indexOf(input.charAt(i++)); 465 | enc3 = _keyStr.indexOf(input.charAt(i++)); 466 | enc4 = _keyStr.indexOf(input.charAt(i++)); 467 | chr1 = (enc1 << 2) | (enc2 >> 4); 468 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 469 | chr3 = ((enc3 & 3) << 6) | enc4; 470 | output = output + String.fromCharCode(chr1); 471 | if (enc3 != 64) { 472 | output = output + String.fromCharCode(chr2); 473 | } 474 | if (enc4 != 64) { 475 | output = output + String.fromCharCode(chr3); 476 | } 477 | } 478 | output = _utf8_decode(output); 479 | return output; 480 | } 481 | // private method for UTF-8 encoding 482 | _utf8_encode = function (string) { 483 | string = string.replace(/\r\n/g, "\n"); 484 | var utftext = ""; 485 | for (var n = 0; n < string.length; n++) { 486 | var c = string.charCodeAt(n); 487 | if (c < 128) { 488 | utftext += String.fromCharCode(c); 489 | } else if ((c > 127) && (c < 2048)) { 490 | utftext += String.fromCharCode((c >> 6) | 192); 491 | utftext += String.fromCharCode((c & 63) | 128); 492 | } else { 493 | utftext += String.fromCharCode((c >> 12) | 224); 494 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 495 | utftext += String.fromCharCode((c & 63) | 128); 496 | } 497 | 498 | } 499 | return utftext; 500 | } 501 | // private method for UTF-8 decoding 502 | _utf8_decode = function (utftext) { 503 | var string = ""; 504 | var i = 0; 505 | var c = c1 = c2 = 0; 506 | while (i < utftext.length) { 507 | c = utftext.charCodeAt(i); 508 | if (c < 128) { 509 | string += String.fromCharCode(c); 510 | i++; 511 | } else if ((c > 191) && (c < 224)) { 512 | c2 = utftext.charCodeAt(i + 1); 513 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 514 | i += 2; 515 | } else { 516 | c2 = utftext.charCodeAt(i + 1); 517 | c3 = utftext.charCodeAt(i + 2); 518 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); 519 | i += 3; 520 | } 521 | } 522 | return string; 523 | } 524 | } 525 | -------------------------------------------------------------------------------- /tb_price_lite.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const $tool = new Tool() 6 | const consoleLog = false 7 | const url = $request.url 8 | const path1 = "/amdc/mobileDispatch" 9 | const path2 = "/gw/mtop.taobao.detail.getdetail" 10 | 11 | if (url.indexOf(path1) != -1) { 12 | if ($tool.isResponse) { 13 | const $base64 = new Base64() 14 | let body = $response.body 15 | let obj = JSON.parse($base64.decode(body)) 16 | let dns = obj.dns 17 | if (dns && dns.length > 0) { 18 | let i = dns.length; 19 | while (i--) { 20 | const element = dns[i]; 21 | let host = "trade-acs.m.taobao.com" 22 | if (element.host == host) { 23 | element.ips = [] 24 | if (consoleLog) console.log(JSON.stringify(element)) 25 | } 26 | } 27 | } 28 | body = $base64.encode(JSON.stringify(obj)) 29 | $done({ body }) 30 | } else { 31 | let headers = $request.headers 32 | let body = $request.body 33 | if (headers["User-Agent"].indexOf("%E6%89%8B%E6%9C%BA%E6%B7%98%E5%AE%9D") != -1) { 34 | let json = Qs2Json(body) 35 | let domain = json.domain.split(" ") 36 | let i = domain.length; 37 | while (i--) { 38 | const block = "trade-acs.m.taobao.com" 39 | const element = domain[i]; 40 | if (element == block) { 41 | domain.splice(i, 1); 42 | } 43 | } 44 | json.domain = domain.join(" ") 45 | body = Json2Qs(json) 46 | } 47 | $done({ body }) 48 | } 49 | } 50 | 51 | if (url.indexOf(path2) != -1) { 52 | const body = $response.body 53 | $done({ body }) 54 | const obj = JSON.parse(body) 55 | let item = obj.data.item 56 | let shareUrl = `https://item.taobao.com/item.htm?id=${item.itemId}` 57 | requestPrice(shareUrl, function (data) { 58 | if (data) { 59 | if (data.ok == 1 && data.single) { 60 | const lower = lowerMsgs(data.single) 61 | const detail = priceSummary(data) 62 | const tip = data.PriceRemark.Tip 63 | $tool.notify("", "", `${lower}\n${tip}${detail}`) 64 | } 65 | if (data.ok == 0 && data.msg.length > 0) { 66 | $tool.notify("", "", `⚠️ ${data.msg}`) 67 | } 68 | } 69 | }) 70 | } 71 | 72 | function lowerMsgs(data) { 73 | const lower = data.lowerPriceyh 74 | const lowerDate = dateFormat(data.lowerDateyh) 75 | const lowerMsg = "🍵 历史最低到手价:¥" + String(lower) + ` (${lowerDate}) ` 76 | return lowerMsg 77 | } 78 | 79 | function priceSummary(data) { 80 | let summary = "" 81 | let listPriceDetail = data.PriceRemark.ListPriceDetail.slice(0,4) 82 | let list = listPriceDetail.concat(historySummary(data.single)) 83 | list.forEach((item, index) => { 84 | if (item.Name == "双11价格") { 85 | item.Name = "双十一价格" 86 | } else if (item.Name == "618价格") { 87 | item.Name = "六一八价格" 88 | } 89 | let price = String(parseInt(item.Price.substr(1))); 90 | summary += `\n${item.Name} ${isNaN(price) ? "-" : "¥" + price} ${item.Date} ${item.Difference}` 91 | }) 92 | return summary 93 | } 94 | 95 | function historySummary(single) { 96 | const rexMatch = /\[.*?\]/g; 97 | const rexExec = /\[(.*),(.*),"(.*)".*\]/; 98 | let currentPrice, lowest30, lowest90, lowest180, lowest360 99 | let list = single.jiagequshiyh.match(rexMatch); 100 | list = list.reverse().slice(0, 360); 101 | list.forEach((item, index) => { 102 | if (item.length > 0) { 103 | const result = rexExec.exec(item); 104 | const dateUTC = new Date(eval(result[1])); 105 | const date = dateUTC.format("yyyy-MM-dd"); 106 | let price = parseFloat(result[2]); 107 | if (index == 0) { 108 | currentPrice = price 109 | lowest30 = { Name: "三十天最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 110 | lowest90 = { Name: "九十天最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 111 | lowest180 = { Name: "一百八最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 112 | lowest360 = { Name: "三百六最低", Price: `¥${String(price)}`, Date: date, Difference: difference(currentPrice, price), price } 113 | } 114 | if (index < 30 && price < lowest30.price) { 115 | lowest30.price = price 116 | lowest30.Price = `¥${String(price)}` 117 | lowest30.Date = date 118 | lowest30.Difference = difference(currentPrice, price) 119 | } 120 | if (index < 90 && price < lowest90.price) { 121 | lowest90.price = price 122 | lowest90.Price = `¥${String(price)}` 123 | lowest90.Date = date 124 | lowest90.Difference = difference(currentPrice, price) 125 | } 126 | if (index < 180 && price < lowest180.price) { 127 | lowest180.price = price 128 | lowest180.Price = `¥${String(price)}` 129 | lowest180.Date = date 130 | lowest180.Difference = difference(currentPrice, price) 131 | } 132 | if (index < 360 && price < lowest360.price) { 133 | lowest360.price = price 134 | lowest360.Price = `¥${String(price)}` 135 | lowest360.Date = date 136 | lowest360.Difference = difference(currentPrice, price) 137 | } 138 | } 139 | }); 140 | return [lowest30, lowest90, lowest180]; 141 | } 142 | 143 | function difference(currentPrice, price) { 144 | let difference = sub(currentPrice, price) 145 | if (difference == 0) { 146 | return "-" 147 | } else { 148 | return `${difference > 0 ? "↑" : "↓"}${String(difference)}` 149 | } 150 | } 151 | 152 | function sub(arg1, arg2) { 153 | return add(arg1, -Number(arg2), arguments[2]); 154 | } 155 | 156 | function add(arg1, arg2) { 157 | arg1 = arg1.toString(), arg2 = arg2.toString(); 158 | var arg1Arr = arg1.split("."), arg2Arr = arg2.split("."), d1 = arg1Arr.length == 2 ? arg1Arr[1] : "", d2 = arg2Arr.length == 2 ? arg2Arr[1] : ""; 159 | var maxLen = Math.max(d1.length, d2.length); 160 | var m = Math.pow(10, maxLen); 161 | var result = Number(((arg1 * m + arg2 * m) / m).toFixed(maxLen)); 162 | var d = arguments[2]; 163 | return typeof d === "number" ? Number((result).toFixed(d)) : result; 164 | } 165 | 166 | function requestPrice(share_url, callback) { 167 | const options = { 168 | url: "https://apapia-history.manmanbuy.com/ChromeWidgetServices/WidgetServices.ashx", 169 | headers: { 170 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 171 | "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_1_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - mmbWebBrowse - ios" 172 | }, 173 | body: "methodName=getHistoryTrend&p_url=" + encodeURIComponent(share_url) 174 | } 175 | $tool.post(options, function (error, response, data) { 176 | if (!error) { 177 | callback(JSON.parse(data)); 178 | if (consoleLog) console.log("Data:\n" + data); 179 | } else { 180 | callback(null, null); 181 | if (consoleLog) console.log("Error:\n" + error); 182 | } 183 | }) 184 | } 185 | 186 | function dateFormat(cellval) { 187 | const date = new Date(parseInt(cellval.replace("/Date(", "").replace(")/", ""), 10)); 188 | const month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1; 189 | const currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate(); 190 | return date.getFullYear() + "-" + month + "-" + currentDate; 191 | } 192 | 193 | function Qs2Json(url) { 194 | var search = url.substring(url.lastIndexOf("?") + 1); 195 | var obj = {}; 196 | var reg = /([^?&=]+)=([^?&=]*)/g; 197 | search.replace(reg, function (rs, $1, $2) { 198 | var name = decodeURIComponent($1); 199 | var val = decodeURIComponent($2); 200 | val = String(val); 201 | obj[name] = val; 202 | return rs; 203 | }); 204 | return obj; 205 | } 206 | 207 | function Json2Qs(json) { 208 | var temp = []; 209 | for (var k in json) { 210 | temp.push(k + "=" + json[k]); 211 | } 212 | return temp.join("&"); 213 | } 214 | 215 | Array.prototype.insert = function (index, item) { 216 | this.splice(index, 0, item); 217 | }; 218 | 219 | Date.prototype.format = function (fmt) { 220 | var o = { 221 | "y+": this.getFullYear(), 222 | "M+": this.getMonth() + 1, 223 | "d+": this.getDate(), 224 | "h+": this.getHours(), 225 | "m+": this.getMinutes(), 226 | "s+": this.getSeconds(), 227 | "q+": Math.floor((this.getMonth() + 3) / 3), 228 | "S+": this.getMilliseconds() 229 | }; 230 | for (var k in o) { 231 | if (new RegExp("(" + k + ")").test(fmt)) { 232 | if (k == "y+") { 233 | fmt = fmt.replace(RegExp.$1, ("" + o[k]).substr(4 - RegExp.$1.length)); 234 | } 235 | else if (k == "S+") { 236 | var lens = RegExp.$1.length; 237 | lens = lens == 1 ? 3 : lens; 238 | fmt = fmt.replace(RegExp.$1, ("00" + o[k]).substr(("" + o[k]).length - 1, lens)); 239 | } 240 | else { 241 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 242 | } 243 | } 244 | } 245 | return fmt; 246 | } 247 | 248 | function Tool() { 249 | _node = (() => { 250 | if (typeof require == "function") { 251 | const request = require('request') 252 | return ({ request }) 253 | } else { 254 | return (null) 255 | } 256 | })() 257 | _isSurge = typeof $httpClient != "undefined" 258 | _isQuanX = typeof $task != "undefined" 259 | this.isSurge = _isSurge 260 | this.isQuanX = _isQuanX 261 | this.isResponse = typeof $response != "undefined" 262 | this.notify = (title, subtitle, message) => { 263 | if (_isQuanX) $notify(title, subtitle, message) 264 | if (_isSurge) $notification.post(title, subtitle, message) 265 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 266 | } 267 | this.write = (value, key) => { 268 | if (_isQuanX) return $prefs.setValueForKey(value, key) 269 | if (_isSurge) return $persistentStore.write(value, key) 270 | } 271 | this.read = (key) => { 272 | if (_isQuanX) return $prefs.valueForKey(key) 273 | if (_isSurge) return $persistentStore.read(key) 274 | } 275 | this.get = (options, callback) => { 276 | if (_isQuanX) { 277 | if (typeof options == "string") options = { url: options } 278 | options["method"] = "GET" 279 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 280 | } 281 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 282 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 283 | } 284 | this.post = (options, callback) => { 285 | if (_isQuanX) { 286 | if (typeof options == "string") options = { url: options } 287 | options["method"] = "POST" 288 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 289 | } 290 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 291 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 292 | } 293 | _status = (response) => { 294 | if (response) { 295 | if (response.status) { 296 | response["statusCode"] = response.status 297 | } else if (response.statusCode) { 298 | response["status"] = response.statusCode 299 | } 300 | } 301 | return response 302 | } 303 | } 304 | 305 | function Base64() { 306 | // private property 307 | _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; 308 | // public method for encoding 309 | this.encode = function (input) { 310 | var output = ""; 311 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4; 312 | var i = 0; 313 | input = _utf8_encode(input); 314 | while (i < input.length) { 315 | chr1 = input.charCodeAt(i++); 316 | chr2 = input.charCodeAt(i++); 317 | chr3 = input.charCodeAt(i++); 318 | enc1 = chr1 >> 2; 319 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 320 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 321 | enc4 = chr3 & 63; 322 | if (isNaN(chr2)) { 323 | enc3 = enc4 = 64; 324 | } else if (isNaN(chr3)) { 325 | enc4 = 64; 326 | } 327 | output = output + 328 | _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + 329 | _keyStr.charAt(enc3) + _keyStr.charAt(enc4); 330 | } 331 | return output; 332 | } 333 | // public method for decoding 334 | this.decode = function (input) { 335 | var output = ""; 336 | var chr1, chr2, chr3; 337 | var enc1, enc2, enc3, enc4; 338 | var i = 0; 339 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); 340 | while (i < input.length) { 341 | enc1 = _keyStr.indexOf(input.charAt(i++)); 342 | enc2 = _keyStr.indexOf(input.charAt(i++)); 343 | enc3 = _keyStr.indexOf(input.charAt(i++)); 344 | enc4 = _keyStr.indexOf(input.charAt(i++)); 345 | chr1 = (enc1 << 2) | (enc2 >> 4); 346 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); 347 | chr3 = ((enc3 & 3) << 6) | enc4; 348 | output = output + String.fromCharCode(chr1); 349 | if (enc3 != 64) { 350 | output = output + String.fromCharCode(chr2); 351 | } 352 | if (enc4 != 64) { 353 | output = output + String.fromCharCode(chr3); 354 | } 355 | } 356 | output = _utf8_decode(output); 357 | return output; 358 | } 359 | // private method for UTF-8 encoding 360 | _utf8_encode = function (string) { 361 | string = string.replace(/\r\n/g, "\n"); 362 | var utftext = ""; 363 | for (var n = 0; n < string.length; n++) { 364 | var c = string.charCodeAt(n); 365 | if (c < 128) { 366 | utftext += String.fromCharCode(c); 367 | } else if ((c > 127) && (c < 2048)) { 368 | utftext += String.fromCharCode((c >> 6) | 192); 369 | utftext += String.fromCharCode((c & 63) | 128); 370 | } else { 371 | utftext += String.fromCharCode((c >> 12) | 224); 372 | utftext += String.fromCharCode(((c >> 6) & 63) | 128); 373 | utftext += String.fromCharCode((c & 63) | 128); 374 | } 375 | 376 | } 377 | return utftext; 378 | } 379 | // private method for UTF-8 decoding 380 | _utf8_decode = function (utftext) { 381 | var string = ""; 382 | var i = 0; 383 | var c = c1 = c2 = 0; 384 | while (i < utftext.length) { 385 | c = utftext.charCodeAt(i); 386 | if (c < 128) { 387 | string += String.fromCharCode(c); 388 | i++; 389 | } else if ((c > 191) && (c < 224)) { 390 | c2 = utftext.charCodeAt(i + 1); 391 | string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); 392 | i += 2; 393 | } else { 394 | c2 = utftext.charCodeAt(i + 1); 395 | c3 = utftext.charCodeAt(i + 2); 396 | string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); 397 | i += 3; 398 | } 399 | } 400 | return string; 401 | } 402 | } 403 | -------------------------------------------------------------------------------- /tool.js: -------------------------------------------------------------------------------- 1 | // 统一 Surge、QuanX、Node 相关脚本 API, 方便开发、调试 2 | // 包括 Node(request 模块)、Surge($httpClient,$notification,$persistentStore 模块)、QuanX($task,$notify,$prefs 模块) 3 | 4 | const $tool = new Tool() 5 | // notify 6 | $tool.notify("title", "subtitle", "message") 7 | // cache 8 | $tool.write("value", "key") 9 | $tool.read("key") 10 | // get 11 | $tool.get("http://www.baidu.com", function (error, response, body) { 12 | // response.status response.statusCode response.headers 13 | if (!error) { 14 | if (response.statusCode == 200) { 15 | console.log(body) 16 | } 17 | } else { 18 | console.log(error) 19 | } 20 | }) 21 | // post 22 | const request = { 23 | url: "https://www.baidu.com", 24 | body: "" 25 | //... 26 | } 27 | $tool.post(request, function (error, response, body) { 28 | // response.status response.statusCode response.headers 29 | if (!error) { 30 | if (response.statusCode == 200) { 31 | console.log(body) 32 | } 33 | } else { 34 | console.log(error) 35 | } 36 | }) 37 | 38 | function Tool() { 39 | _node = (() => { 40 | if (typeof require == "function") { 41 | const request = require('request') 42 | return ({ request }) 43 | } else { 44 | return (null) 45 | } 46 | })() 47 | _isSurge = typeof $httpClient != "undefined" 48 | _isQuanX = typeof $task != "undefined" 49 | this.isSurge = _isSurge 50 | this.isQuanX = _isQuanX 51 | this.isResponse = typeof $response != "undefined" 52 | this.notify = (title, subtitle, message) => { 53 | if (_isQuanX) $notify(title, subtitle, message) 54 | if (_isSurge) $notification.post(title, subtitle, message) 55 | if (_node) console.log(JSON.stringify({ title, subtitle, message })); 56 | } 57 | this.write = (value, key) => { 58 | if (_isQuanX) return $prefs.setValueForKey(value, key) 59 | if (_isSurge) return $persistentStore.write(value, key) 60 | } 61 | this.read = (key) => { 62 | if (_isQuanX) return $prefs.valueForKey(key) 63 | if (_isSurge) return $persistentStore.read(key) 64 | } 65 | this.get = (options, callback) => { 66 | if (_isQuanX) { 67 | if (typeof options == "string") options = { url: options } 68 | options["method"] = "GET" 69 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 70 | } 71 | if (_isSurge) $httpClient.get(options, (error, response, body) => { callback(error, _status(response), body) }) 72 | if (_node) _node.request(options, (error, response, body) => { callback(error, _status(response), body) }) 73 | } 74 | this.post = (options, callback) => { 75 | if (_isQuanX) { 76 | if (typeof options == "string") options = { url: options } 77 | options["method"] = "POST" 78 | $task.fetch(options).then(response => { callback(null, _status(response), response.body) }, reason => callback(reason.error, null, null)) 79 | } 80 | if (_isSurge) $httpClient.post(options, (error, response, body) => { callback(error, _status(response), body) }) 81 | if (_node) _node.request.post(options, (error, response, body) => { callback(error, _status(response), body) }) 82 | } 83 | _status = (response) => { 84 | if (response) { 85 | if (response.status) { 86 | response["statusCode"] = response.status 87 | } else if (response.statusCode) { 88 | response["status"] = response.statusCode 89 | } 90 | } 91 | return response 92 | } 93 | } 94 | 95 | function tool() { 96 | const isSurge = typeof $httpClient != "undefined" 97 | const isQuanX = typeof $task != "undefined" 98 | const isResponse = typeof $response != "undefined" 99 | const node = (() => { 100 | if (typeof require == "function") { 101 | const request = require('request') 102 | return ({ request }) 103 | } else { 104 | return (null) 105 | } 106 | })() 107 | const notify = (title, subtitle, message) => { 108 | if (isQuanX) $notify(title, subtitle, message) 109 | if (isSurge) $notification.post(title, subtitle, message) 110 | if (node) console.log(JSON.stringify({ title, subtitle, message })); 111 | } 112 | const write = (value, key) => { 113 | if (isQuanX) return $prefs.setValueForKey(value, key) 114 | if (isSurge) return $persistentStore.write(value, key) 115 | } 116 | const read = (key) => { 117 | if (isQuanX) return $prefs.valueForKey(key) 118 | if (isSurge) return $persistentStore.read(key) 119 | } 120 | const adapterStatus = (response) => { 121 | if (response) { 122 | if (response.status) { 123 | response["statusCode"] = response.status 124 | } else if (response.statusCode) { 125 | response["status"] = response.statusCode 126 | } 127 | } 128 | return response 129 | } 130 | const get = (options, callback) => { 131 | if (isQuanX) { 132 | if (typeof options == "string") options = { url: options } 133 | options["method"] = "GET" 134 | $task.fetch(options).then(response => { 135 | callback(null, adapterStatus(response), response.body) 136 | }, reason => callback(reason.error, null, null)) 137 | } 138 | if (isSurge) $httpClient.get(options, (error, response, body) => { 139 | callback(error, adapterStatus(response), body) 140 | }) 141 | if (node) { 142 | node.request(options, (error, response, body) => { 143 | callback(error, adapterStatus(response), body) 144 | }) 145 | } 146 | } 147 | const post = (options, callback) => { 148 | if (isQuanX) { 149 | if (typeof options == "string") options = { url: options } 150 | options["method"] = "POST" 151 | $task.fetch(options).then(response => { 152 | callback(null, adapterStatus(response), response.body) 153 | }, reason => callback(reason.error, null, null)) 154 | } 155 | if (isSurge) { 156 | $httpClient.post(options, (error, response, body) => { 157 | callback(error, adapterStatus(response), body) 158 | }) 159 | } 160 | if (node) { 161 | node.request.post(options, (error, response, body) => { 162 | callback(error, adapterStatus(response), body) 163 | }) 164 | } 165 | } 166 | return { isQuanX, isSurge, isResponse, notify, write, read, get, post } 167 | } -------------------------------------------------------------------------------- /wb_ad.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const path1 = "/groups/timeline"; 6 | const path2 = "/statuses/unread"; 7 | const path3 = "/statuses/extend"; 8 | const path4 = "/comments/build_comments"; 9 | const path5 = "/photo/recommend_list"; 10 | const path6 = "/stories/video_stream"; 11 | const path7 = "/statuses/positives/get"; 12 | const path8 = "/stories/home_list"; 13 | const path9 = "/profile/statuses"; 14 | const path10 = "/statuses/friends/timeline"; 15 | const path11 = "/service/picfeed"; 16 | const path12 = "/fangle/timeline"; 17 | const path13 = "/searchall"; 18 | const path14 = "/cardlist"; 19 | const path15 = "/statuses/video_timeline"; 20 | const path16 = "/page"; 21 | const path17 = "/statuses/friends_timeline"; 22 | const path18 = "/!/photos/pic_recommend_status"; 23 | const path19 = "/statuses/video_mixtimeline"; 24 | const path20 = "/video/tiny_stream_video_list"; 25 | const path21 = "/photo/info"; 26 | const path22 = "/live/media_homelist"; 27 | const path23 = "/remind/unread_count"; 28 | const path24 = "/search/container_timeline" 29 | const path25 = "/messageflow/notice" 30 | const path26 = "/statuses/container_timeline_hot" 31 | const path27 = "/search/finder" 32 | const path28 = "/statuses/container_timeline_unread" 33 | const path29 = "/statuses/container_timeline" 34 | const path30 = "/profile/container_timeline" 35 | 36 | const url = $request.url; 37 | let body = $response.body; 38 | 39 | if ( 40 | url.indexOf(path1) != -1 || 41 | url.indexOf(path2) != -1 || 42 | url.indexOf(path10) != -1 || 43 | url.indexOf(path15) != -1 || 44 | url.indexOf(path17) != -1 || 45 | url.indexOf(path20) != -1 46 | ) { 47 | let obj = JSON.parse(body); 48 | if (obj.statuses) obj.statuses = filter_timeline_statuses(obj.statuses); 49 | if (obj.advertises) obj.advertises = []; 50 | if (obj.ad) obj.ad = []; 51 | if (obj.num) obj.num = obj.original_num; 52 | if (obj.trends) obj.trends = []; 53 | body = JSON.stringify(obj); 54 | } else if (url.indexOf(path3) != -1) { 55 | let obj = JSON.parse(body); 56 | if (obj.trend) delete obj.trend; 57 | body = JSON.stringify(obj); 58 | } else if (url.indexOf(path4) != -1) { 59 | let obj = JSON.parse(body); 60 | obj.recommend_max_id = 0; 61 | if (obj.status) { 62 | if (obj.top_hot_structs) { 63 | obj.max_id = obj.top_hot_structs.call_back_struct.max_id; 64 | delete obj.top_hot_structs; 65 | } 66 | if (obj.datas) obj.datas = filter_comments(obj.datas); 67 | } else { 68 | obj.datas = []; 69 | } 70 | body = JSON.stringify(obj); 71 | } else if (url.indexOf(path5) != -1 || url.indexOf(path18) != -1) { 72 | let obj = JSON.parse(body); 73 | obj.data = {}; 74 | body = JSON.stringify(obj); 75 | } else if (url.indexOf(path6) != -1) { 76 | let obj = JSON.parse(body); 77 | let segments = obj.segments; 78 | if (segments && segments.length > 0) { 79 | let i = segments.length; 80 | while (i--) { 81 | const element = segments[i]; 82 | let is_ad = element.is_ad; 83 | if (is_ad && is_ad == true) segments.splice(i, 1); 84 | } 85 | } 86 | body = JSON.stringify(obj); 87 | } else if (url.indexOf(path7) != -1) { 88 | let obj = JSON.parse(body); 89 | obj.datas = []; 90 | body = JSON.stringify(obj); 91 | } else if (url.indexOf(path8) != -1) { 92 | let obj = JSON.parse(body); 93 | obj.story_list = []; 94 | body = JSON.stringify(obj); 95 | } else if (url.indexOf(path11) != -1 || url.indexOf(path22) != -1) { 96 | let obj = JSON.parse(body); 97 | obj.data = []; 98 | body = JSON.stringify(obj); 99 | } else if ( 100 | url.indexOf(path9) != -1 || 101 | url.indexOf(path12) != -1 || 102 | url.indexOf(path13) != -1 || 103 | url.indexOf(path14) != -1 || 104 | url.indexOf(path16) != -1 105 | ) { 106 | let obj = JSON.parse(body); 107 | if (obj.cards) obj.cards = filter_timeline_cards(obj.cards); 108 | body = JSON.stringify(obj); 109 | } else if (url.indexOf(path19) != -1) { 110 | let obj = JSON.parse(body); 111 | delete obj.expandable_view; 112 | if (obj.hasOwnProperty("expandable_views")) delete obj.expandable_views; 113 | body = JSON.stringify(obj); 114 | } else if (url.indexOf(path21) != -1) { 115 | if (body.indexOf("ad_params") != -1) { 116 | body = JSON.stringify({}); 117 | } 118 | } else if (url.indexOf(path23) != -1) { 119 | let obj = JSON.parse(body); 120 | obj.video = {}; 121 | body = JSON.stringify(obj); 122 | } else if (url.indexOf(path24) != -1) { 123 | let obj = JSON.parse(body); 124 | filter_items_feed(obj) 125 | body = JSON.stringify(obj); 126 | } else if (url.indexOf(path25) != -1) { 127 | let obj = JSON.parse(body); 128 | filter_messageflow_notice(obj) 129 | body = JSON.stringify(obj); 130 | } else if ( url.indexOf(path30) != -1 || url.indexOf(path26) != -1 || url.indexOf(path28) != -1 || url.indexOf(path29) != -1) { 131 | let obj = JSON.parse(body); 132 | filter_items_feed(obj) 133 | body = JSON.stringify(obj); 134 | } else if (url.indexOf(path27) != -1) { 135 | let obj = JSON.parse(body); 136 | filter_search_finder(obj) 137 | body = JSON.stringify(obj); 138 | } 139 | 140 | $done({ body }); 141 | 142 | function filter_search_finder(data) { 143 | channels = data["channelInfo"]["channels"] 144 | for (let index = 0; index < channels.length; index++) { 145 | const element = channels[index]; 146 | if (element["en_name"] == "Discover") { 147 | filter_finder_items(element["payload"]) 148 | } 149 | } 150 | } 151 | 152 | function filter_finder_items(data) { 153 | items = data["items"] 154 | for (let index = items.length-1; index >= 0; index--) { 155 | const item = items[index]; 156 | if (item["category"] == "card") { 157 | type = item["data"]["card_type"] 158 | if (type == 118) { 159 | items.splice(index,1) 160 | } 161 | }else if (item["category"] == "feed") { 162 | type = item["data"]["mblogtype"] 163 | if (type == 1) { 164 | items.splice(index,1) 165 | } 166 | } 167 | } 168 | } 169 | 170 | function filter_messageflow_notice(data) { 171 | items = data["messages"] 172 | for (let index = items.length-1; index >= 0; index--) { 173 | const item = items[index]; 174 | if (item["isrecommend"] == true) { 175 | items.splice(index,1) 176 | } 177 | } 178 | } 179 | 180 | function filter_items_feed(data) { 181 | items = data["items"] 182 | for (let index = items.length-1; index >= 0; index--) { 183 | const item = items[index]; 184 | if (item["category"] == "feed") { 185 | type = item["data"]["mblogtype"] 186 | if (type == 1) { 187 | items.splice(index,1) 188 | } 189 | } 190 | } 191 | } 192 | 193 | function filter_timeline_statuses(statuses) { 194 | if (statuses && statuses.length > 0) { 195 | let i = statuses.length; 196 | while (i--) { 197 | let element = statuses[i]; 198 | if ( 199 | is_timeline_likerecommend(element.title) || 200 | is_timeline_ad(element) || 201 | is_stream_video_ad(element) 202 | ) { 203 | statuses.splice(i, 1); 204 | } 205 | } 206 | } 207 | return statuses; 208 | } 209 | 210 | function filter_comments(datas) { 211 | if (datas && datas.length > 0) { 212 | let i = datas.length; 213 | while (i--) { 214 | const element = datas[i]; 215 | const type = element.type; 216 | if (type == 5 || type == 1 || type == 6) datas.splice(i, 1); 217 | } 218 | } 219 | return datas; 220 | } 221 | 222 | function filter_timeline_cards(cards) { 223 | if (cards && cards.length > 0) { 224 | let j = cards.length; 225 | while (j--) { 226 | let item = cards[j]; 227 | let card_group = item.card_group; 228 | if (card_group && card_group.length > 0) { 229 | if (item.itemid && item.itemid == "hotword") { 230 | filter_top_search(card_group); 231 | } else { 232 | let i = card_group.length; 233 | while (i--) { 234 | let card_group_item = card_group[i]; 235 | let card_type = card_group_item.card_type; 236 | if (card_type) { 237 | if (card_type == 9) { 238 | if (is_timeline_ad(card_group_item.mblog)) 239 | card_group.splice(i, 1); 240 | } else if (card_type == 118 || card_type == 89) { 241 | card_group.splice(i, 1); 242 | } else if (card_type == 42) { 243 | if ( 244 | card_group_item.desc == 245 | "\u53ef\u80fd\u611f\u5174\u8da3\u7684\u4eba" 246 | ) { 247 | cards.splice(j, 1); 248 | break; 249 | } 250 | } else if (card_type == 17) { 251 | filter_top_search(card_group_item.group); 252 | } 253 | } 254 | } 255 | } 256 | } else { 257 | let card_type = item.card_type; 258 | if (card_type && card_type == 9) { 259 | if (is_timeline_ad(item.mblog)) cards.splice(j, 1); 260 | } 261 | } 262 | } 263 | } 264 | return cards; 265 | } 266 | 267 | function filter_top_search(group) { 268 | if (group && group.length > 0) { 269 | let k = group.length; 270 | while (k--) { 271 | let group_item = group[k]; 272 | if (group_item.hasOwnProperty("promotion")) { 273 | group.splice(k, 1); 274 | } 275 | } 276 | } 277 | } 278 | 279 | function is_timeline_ad(mblog) { 280 | if (!mblog) return false; 281 | let promotiontype = 282 | mblog.promotion && mblog.promotion.type && mblog.promotion.type == "ad"; 283 | let mblogtype = mblog.mblogtype && mblog.mblogtype == 1; 284 | return promotiontype || mblogtype ? true : false; 285 | } 286 | 287 | function is_timeline_likerecommend(title) { 288 | return title && title.type && title.type == "likerecommend" ? true : false; 289 | } 290 | 291 | function is_stream_video_ad(item) { 292 | return item.ad_state && item.ad_state == 1; 293 | } 294 | -------------------------------------------------------------------------------- /wb_launch.js: -------------------------------------------------------------------------------- 1 | /* 2 | README:https://github.com/yichahucha/surge/tree/master 3 | */ 4 | 5 | const path1 = "/interface/sdk/sdkad.php"; 6 | const path2 = "/wbapplua/wbpullad.lua"; 7 | 8 | const url = $request.url; 9 | var body = $response.body; 10 | 11 | if (url.indexOf(path1) != -1) { 12 | let re = /\{.*\}/; 13 | body = body.match(re); 14 | var obj = JSON.parse(body); 15 | if (obj.background_delay_display_time) obj.background_delay_display_time = 60*60*24*365; 16 | if (obj.show_push_splash_ad) obj.show_push_splash_ad = false; 17 | if (obj.ads) obj.ads = []; 18 | body = JSON.stringify(obj) + 'OK'; 19 | } 20 | 21 | if (url.indexOf(path2) != -1) { 22 | var obj = JSON.parse(body); 23 | if (obj.cached_ad && obj.cached_ad.ads) obj.cached_ad.ads = []; 24 | body = JSON.stringify(obj); 25 | } 26 | 27 | $done({body}); 28 | --------------------------------------------------------------------------------