├── .gitignore ├── LICENSE ├── build.gradle.kts ├── readme.md ├── settings.gradle.kts └── src └── main ├── kotlin └── railgunDownloaderV4 │ ├── Application.kt │ └── components │ ├── Bilibili.kt │ ├── DeviantArt.kt │ ├── Facebook.kt │ ├── Hitomi.kt │ ├── Instagram.kt │ ├── MangaDex.kt │ ├── Nhentai.kt │ ├── Tiktok.kt │ ├── Youtube.kt │ ├── bilibiliUI │ ├── BilibiliUI.kt │ ├── LoadComponents.kt │ └── events │ │ └── Download.kt │ ├── devianArtUI │ ├── DevianArtUI.kt │ ├── LoadComponents.kt │ └── events │ │ ├── DevianArtDownload.kt │ │ └── Download.kt │ ├── facebookUI │ ├── FacebookUI.kt │ ├── LoadComponents.kt │ └── events │ │ └── Download.kt │ ├── global │ ├── ButtonUI.kt │ ├── LogResult.kt │ ├── QualityBox.kt │ ├── TextField.kt │ └── events │ │ ├── DownloadVideoProcess.kt │ │ ├── GoHome.kt │ │ └── LoadUI.kt │ ├── hitomiUI │ ├── HitomiUI.kt │ ├── LoadComponents.kt │ └── events │ │ ├── Downloader.kt │ │ └── HitomiDownload.kt │ ├── instagramUI │ ├── InstagramUI.kt │ ├── LoadComponents.kt │ └── events │ │ └── Download.kt │ ├── mangadexUI │ ├── LogResult.kt │ ├── MangaDexButton.kt │ ├── MangaDexTextField.kt │ ├── MangaDexUI.kt │ ├── events │ │ ├── DownloadMangaDex.kt │ │ ├── LoadUI.kt │ │ ├── OpenDir.kt │ │ └── WindowClosing.kt │ └── helper │ │ └── MangaDexAPI.kt │ ├── nhentaiUI │ ├── ChoosePath.kt │ ├── DownloadButton.kt │ ├── FindByCode.kt │ ├── LogResult.kt │ ├── NhentaiUI.kt │ ├── PathField.kt │ ├── URLField.kt │ └── helper │ │ └── NhentaiDownloadHelper.kt │ ├── tiktokUI │ ├── LoadComponents.kt │ ├── TiktokUI.kt │ └── events │ │ └── Download.kt │ ├── ulti │ ├── CheckOS.kt │ ├── ClearEvents.kt │ ├── DirExists.kt │ ├── MatchNumber.kt │ ├── MatchURL.kt │ ├── MessageDialog.kt │ ├── PathDialog.kt │ ├── ProcessCancel.kt │ ├── SetIcon.kt │ └── SetIconButton.kt │ └── youtubeUI │ ├── LoadComponents.kt │ ├── YoutubeUI.kt │ └── events │ └── Download.kt └── resources ├── AppIcon.jpg ├── Bilibili.png ├── Cancel.png ├── DevianArt.png ├── Download.png ├── Facebook.png ├── FolderPath.png ├── Hitomi.png ├── Instagram.png ├── MangaDex.png ├── Nhentai.png ├── Search.png ├── Tiktok.png └── YoutubeIcon.png /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | .kotlin 5 | *.spec 6 | *.lib 7 | dist 8 | *.bin 9 | *.exe 10 | .venv 11 | RailgunDownloaderV4.iml 12 | test 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: build.gradle.kts 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | plugins { 9 | kotlin("jvm") version "2.1.0" 10 | kotlin("plugin.serialization") version "2.1.0" 11 | } 12 | 13 | group = "RailgunDownloaderV4" 14 | version = "4.0.0" 15 | 16 | sourceSets { 17 | main { kotlin.srcDirs("src/main/kotlin") } 18 | test { kotlin.srcDirs("src/test/kotlin") } 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | dependencies { 25 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") 26 | implementation("org.jsoup:jsoup:1.18.3") 27 | implementation("com.squareup.okhttp3:okhttp:4.12.0") 28 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0") 29 | implementation("com.google.code.gson:gson:2.11.0") 30 | implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.15.2") 31 | implementation("org.seleniumhq.selenium:selenium-java:4.27.0") 32 | } 33 | kotlin { 34 | jvmToolchain(17) 35 | } 36 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | * # Railgun Downloader 2 | * **An awesome download tool with a UI that supports cross-platform functionality, including Windows, Linux and macOS (Beta)** 3 | 4 | **Build Requirements & Usage:** 5 | 6 | - Build dependencies: 7 | - `Open-JDK 17` [Download](https://jdk.java.net/) 8 | - `Python >= 3.11` [Download](https://www.python.org/downloads/) 9 | - `Gradle 8.10.2` [Download](https://gradle.org/install/) 10 | - A Java IDE, such as Eclipse or IntelliJ IDEA. 11 | - Basic acknowledge of Java, Kotlin and Python programing language. 12 | 13 | 14 | - Install & Usage: 15 | - Get latest version of Railgun Downloader at Releases page 16 | - Extract the downloaded folder to your desired directory path 17 | 18 | # Supported download from: 19 | | Site | URL | Download type | 20 | |:-------------:|--------------------------------|----------------| 21 | | **Youtube** | **https://youtube.com** | Video/Playlist | 22 | | **Nhentai** | **https://nhentai.net** | Image | 23 | | **Hitomi** | **https://hitomi.la** | Image | 24 | | **Bilibili** | **https://www.bilibili.tv/** | Video | 25 | | **Instagram** | **https://instagram.com** | Video | 26 | | **Facebook** | **https://facebook.com** | Video | 27 | | **MangaDex** | **https://mangadex.org** | Image | 28 | | **TikTok** | **https://www.tiktok.com/** | Video | 29 | | **DevianArt** | **https://www.deviantart.com** | Image | 30 | 31 | * **Video downloader is supported by [YT DLP](https://github.com/yt-dlp/yt-dlp)** 32 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | mavenCentral() 5 | } 6 | plugins { 7 | id("org.jetbrains.kotlin.jvm") version "1.8.10" 8 | } 9 | } 10 | 11 | rootProject.name = "RailgunDownloaderV4" 12 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/Application.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Application.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4 9 | 10 | import railgunDownloaderV4.components.* 11 | import railgunDownloaderV4.components.ulti.SetIcon 12 | import java.awt.Color 13 | import java.awt.Dimension 14 | import javax.swing.JButton 15 | import javax.swing.JFrame 16 | import javax.swing.SwingUtilities 17 | import javax.swing.WindowConstants 18 | 19 | class Application { 20 | val app: JFrame by lazy { JFrame() } 21 | private val youtubeComponent: Youtube by lazy { Youtube(this) } 22 | private val nhentaiComponent: Nhentai by lazy { Nhentai(this) } 23 | private val facebookComponent: Facebook by lazy { Facebook(this) } 24 | private val mangaDexComponent: MangaDex by lazy { MangaDex(this) } 25 | private val hitomiComponent: Hitomi by lazy { Hitomi(this) } 26 | private val bilibiliComponent: Bilibili by lazy { Bilibili(this) } 27 | private val instagramComponent: Instagram by lazy { Instagram(this) } 28 | private val tiktokComponent: Tiktok by lazy { Tiktok(this) } 29 | private val deviantArtComponent: DeviantArt by lazy { DeviantArt(this) } 30 | private val setIcon: SetIcon by lazy { SetIcon() } 31 | 32 | private val youtubeButton: JButton by lazy { JButton() } 33 | private val nhentaiButton: JButton by lazy { JButton() } 34 | private val facebookButton: JButton by lazy { JButton() } 35 | private val mangaDexButton: JButton by lazy { JButton() } 36 | private val hitomiButton: JButton by lazy { JButton() } 37 | private val bilibiliButton: JButton by lazy { JButton() } 38 | private val instagramButton: JButton by lazy { JButton() } 39 | private val tiktokButton: JButton by lazy { JButton() } 40 | private val deviantArtButton: JButton by lazy { JButton() } 41 | 42 | private fun setProperty() { 43 | app.title = "Railgun Downloader V4" 44 | app.iconImage = setIcon.setAppIcon() 45 | app.setSize(600, 600) 46 | app.maximumSize = Dimension(600, 600) 47 | app.layout = null 48 | app.setLocationRelativeTo(null) 49 | app.contentPane.background = Color(21, 21, 21) 50 | app.defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE 51 | app.isResizable = false 52 | app.isVisible = true 53 | } 54 | 55 | companion object { 56 | @JvmStatic 57 | fun main(args: Array) { 58 | SwingUtilities.invokeLater { 59 | val appScene = Application() 60 | appScene.setProperty() 61 | appScene.youtubeComponent.setYoutubeButton(appScene.youtubeButton) 62 | appScene.nhentaiComponent.setNhentaiUIButton(appScene.nhentaiButton) 63 | appScene.facebookComponent.setFacebookButton(appScene.facebookButton) 64 | appScene.mangaDexComponent.setMangaDex(appScene.mangaDexButton) 65 | appScene.hitomiComponent.setHitomiButton(appScene.hitomiButton) 66 | appScene.bilibiliComponent.setBilibili(appScene.bilibiliButton) 67 | appScene.instagramComponent.setInstagram(appScene.instagramButton) 68 | appScene.tiktokComponent.setTiktok(appScene.tiktokButton) 69 | appScene.deviantArtComponent.setDevianArt(appScene.deviantArtButton) 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Bilibili.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Bilibili.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components 10 | 11 | import railgunDownloaderV4.Application 12 | import railgunDownloaderV4.components.bilibiliUI.BilibiliUI 13 | import railgunDownloaderV4.components.global.ButtonUI 14 | import railgunDownloaderV4.components.global.events.LoadUI 15 | import javax.swing.JButton 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | 19 | class Bilibili(private val appScene: Application){ 20 | 21 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 22 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 23 | private val bilibiliUI: BilibiliUI by lazy { BilibiliUI(appScene) } 24 | 25 | fun setBilibili(targetButton: JButton) { 26 | buttonUI.setButtonUI( 27 | appScene.app, targetButton, 28 | Dimension(70, 60), Point(360, 0), 29 | "/Bilibili.png", "Download from Bilibili" 30 | ) 31 | 32 | loadUI.setLoadUI(targetButton, bilibiliUI::setBilibiliUI) 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/DeviantArt.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DevianArt.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.devianArtUI.DevianArtUI 12 | import railgunDownloaderV4.components.global.ButtonUI 13 | import railgunDownloaderV4.components.global.events.LoadUI 14 | import java.awt.Dimension 15 | import java.awt.Point 16 | import javax.swing.JButton 17 | 18 | class DeviantArt (private val appScene: Application){ 19 | 20 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 21 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 22 | private val devianArtUI: DevianArtUI by lazy { DevianArtUI(appScene) } 23 | 24 | fun setDevianArt(buttonTarget: JButton) { 25 | buttonUI.setButtonUI( 26 | appScene.app, buttonTarget, 27 | Dimension(50, 50), Point(0, 50), 28 | "/DevianArt.png", "Download image from DevianArt" 29 | ) 30 | 31 | loadUI.setLoadUI(buttonTarget, devianArtUI::setDevianArtUI) 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Facebook.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Facebook.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.facebookUI.FacebookUI 12 | import railgunDownloaderV4.components.global.ButtonUI 13 | import railgunDownloaderV4.components.global.events.LoadUI 14 | import java.awt.Dimension 15 | import java.awt.Point 16 | import javax.swing.JButton 17 | 18 | class Facebook (private val appScene: Application){ 19 | private val facebookUI: FacebookUI by lazy { FacebookUI(appScene) } 20 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 21 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 22 | 23 | fun setFacebookButton(facebookButton: JButton) { 24 | buttonUI.setButtonUI( 25 | appScene.app, facebookButton, 26 | Dimension(50, 50), Point(135, 0), 27 | "/Facebook.png", "Download video from Facebook" 28 | ) 29 | 30 | loadUI.setLoadUI(facebookButton, facebookUI::showFacebookUI) 31 | appScene.app.add(facebookButton) 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Hitomi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Hitomi.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.ButtonUI 12 | import railgunDownloaderV4.components.global.events.LoadUI 13 | import railgunDownloaderV4.components.hitomiUI.HitomiUI 14 | import java.awt.Dimension 15 | import java.awt.Point 16 | import javax.swing.JButton 17 | 18 | class Hitomi(private val appScene: Application) { 19 | 20 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 21 | private val hitomiUI: HitomiUI by lazy { HitomiUI(appScene) } 22 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 23 | 24 | fun setHitomiButton(hitomiButton: JButton) { 25 | buttonUI.setButtonUI( 26 | appScene.app, hitomiButton, Dimension(50, 50), 27 | Point(290, 10), "/Hitomi.png", 28 | "Download from Hitomi.la" 29 | ) 30 | loadUI.setLoadUI(hitomiButton, hitomiUI::setHitomiUI) 31 | } 32 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Instagram.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Instagram.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.ButtonUI 12 | import railgunDownloaderV4.components.global.events.LoadUI 13 | import railgunDownloaderV4.components.instagramUI.InstagramUI 14 | import railgunDownloaderV4.components.instagramUI.LoadComponents 15 | import java.awt.Dimension 16 | import java.awt.Point 17 | import javax.swing.JButton 18 | 19 | class Instagram (private val appScene: Application){ 20 | 21 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 22 | private val instagramUI: InstagramUI by lazy { InstagramUI(appScene) } 23 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 24 | 25 | fun setInstagram(buttonTarget: JButton) { 26 | buttonUI.setButtonUI( 27 | appScene.app, buttonTarget, 28 | Dimension(50, 50), Point(450, 10), 29 | "/Instagram.png", "Download video from Instagram" 30 | ) 31 | 32 | loadUI.setLoadUI(buttonTarget, instagramUI::setInstagramUI) 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/MangaDex.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MangaDex.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.mangadexUI.MangaDexUI 12 | import railgunDownloaderV4.components.mangadexUI.events.LoadUI 13 | import railgunDownloaderV4.components.ulti.SetIconButton 14 | import java.awt.Dimension 15 | import java.awt.Point 16 | import javax.swing.JButton 17 | 18 | class MangaDex (private val appScene: Application){ 19 | 20 | private val setIconButton: SetIconButton by lazy { SetIconButton() } 21 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 22 | private val mangaDexUI: MangaDexUI by lazy { MangaDexUI(appScene) } 23 | 24 | fun setMangaDex(mangaDexButton: JButton) { 25 | mangaDexButton.apply { 26 | size = Dimension(50, 50) 27 | isFocusPainted = false 28 | isBorderPainted = false 29 | border = null 30 | isContentAreaFilled = false 31 | location = Point(210, 7) 32 | toolTipText = "Download from MangaDex" 33 | } 34 | setIconButton.setIcon( 35 | mangaDexButton, "/MangaDex.png", 36 | 50, 50 37 | ) 38 | loadUI.setLoadUI(mangaDexButton, mangaDexUI::setMangaDexUI) 39 | 40 | appScene.app.add(mangaDexButton) 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Nhentai.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Nhentai.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | import javax.swing.JButton 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.nhentaiUI.NhentaiUI 12 | import java.awt.Image 13 | import java.awt.Toolkit 14 | import javax.swing.ImageIcon 15 | 16 | class Nhentai (private var appScene: Application) { 17 | private val nhentaiComponent: NhentaiUI by lazy { NhentaiUI(appScene) } 18 | 19 | 20 | fun setNhentaiUIButton(nhentaiButton: JButton) { 21 | nhentaiButton.setSize(50, 50) 22 | nhentaiButton.isContentAreaFilled = false 23 | nhentaiButton.border = null 24 | nhentaiButton.setLocation(70, 0) 25 | nhentaiButton.toolTipText = "Download doujinshi from Nhentai.net" 26 | 27 | val buttonIcon: Image = Toolkit 28 | .getDefaultToolkit().getImage( 29 | this::class.java.getResource("/Nhentai.png")) 30 | nhentaiButton.icon = ImageIcon( 31 | buttonIcon.getScaledInstance( 50, 50, Image.SCALE_FAST) 32 | ) 33 | 34 | loadNhentaiUI(nhentaiButton = nhentaiButton) 35 | appScene.app.add(nhentaiButton) 36 | } 37 | 38 | private fun loadNhentaiUI(nhentaiButton: JButton) { 39 | nhentaiButton.addActionListener { _ -> 40 | nhentaiComponent.showNhentaiUI(true) 41 | appScene.app.isVisible = false 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Tiktok.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Tiktok.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components 10 | 11 | import railgunDownloaderV4.Application 12 | import railgunDownloaderV4.components.global.ButtonUI 13 | import railgunDownloaderV4.components.global.events.LoadUI 14 | import railgunDownloaderV4.components.tiktokUI.TiktokUI 15 | import java.awt.Dimension 16 | import java.awt.Point 17 | import javax.swing.JButton 18 | 19 | class Tiktok (private val appScene: Application){ 20 | 21 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 22 | private val loadUI: LoadUI by lazy { LoadUI(appScene) } 23 | private val tiktokUI: TiktokUI by lazy { TiktokUI(appScene) } 24 | 25 | fun setTiktok(buttonTarget: JButton) { 26 | buttonUI.setButtonUI( 27 | appScene.app, buttonTarget, 28 | Dimension(50, 50), Point(520, 10), 29 | "/Tiktok.png", "Download video from Tiktok" 30 | ) 31 | loadUI.setLoadUI(buttonTarget, tiktokUI::setTiktokUI) 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/Youtube.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Youtube.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.ulti.ClearEvents 12 | import railgunDownloaderV4.components.youtubeUI.YoutubeUI 13 | import java.awt.Image 14 | import java.awt.Toolkit 15 | import java.util.* 16 | import javax.swing.ImageIcon 17 | import javax.swing.JButton 18 | 19 | class Youtube(private val appScene: Application) { 20 | private val youtubeUI: YoutubeUI by lazy { YoutubeUI(appScene) } 21 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 22 | 23 | fun setYoutubeButton(youtubeButton: JButton) { 24 | youtubeButton.setSize(50, 50) 25 | youtubeButton.isBorderPainted = false 26 | youtubeButton.border = null 27 | youtubeButton.isContentAreaFilled = false 28 | youtubeButton.isFocusPainted = false 29 | 30 | val buttonIcon = Toolkit.getDefaultToolkit().getImage( 31 | Objects.requireNonNull( 32 | javaClass.getResource("/YoutubeIcon.png") 33 | ) 34 | ) 35 | youtubeButton.icon = ImageIcon( 36 | buttonIcon.getScaledInstance(50, 50, Image.SCALE_FAST) 37 | ) 38 | 39 | youtubeButton.toolTipText = "Download video from Youtube" 40 | 41 | openYoutubeUI(youtubeButton) 42 | appScene.app.add(youtubeButton) 43 | } 44 | 45 | private fun openYoutubeUI(buttonTarget: JButton) { 46 | clearEvents.clearActionListeners(buttonTarget) 47 | 48 | buttonTarget.addActionListener { 49 | youtubeUI.showYoutubeUI(true) 50 | appScene.app.isVisible = false 51 | } 52 | 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/bilibiliUI/BilibiliUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: BilibiliUI.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.bilibiliUI 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.events.GoHome 12 | import railgunDownloaderV4.components.ulti.SetIcon 13 | import java.awt.Color 14 | import javax.swing.JFrame 15 | import java.awt.Dimension 16 | import javax.swing.WindowConstants 17 | 18 | class BilibiliUI (appScene: Application){ 19 | 20 | private val goHome: GoHome by lazy { GoHome(appScene) } 21 | private val setIcon: SetIcon by lazy { SetIcon() } 22 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 23 | 24 | fun setBilibiliUI(visible: Boolean = false) { 25 | val app = JFrame("Download from Bilibili") 26 | app.size = Dimension(600, 600) 27 | app.layout = null 28 | app.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 29 | app.isResizable = false 30 | app.maximumSize = Dimension(600, 600) 31 | app.contentPane.background = Color(21, 21, 21) 32 | app.setLocationRelativeTo(null) 33 | app.iconImage = setIcon.setAppIcon() 34 | app.isVisible = visible 35 | 36 | goHome.setGoHome(app) 37 | loadComponents.setLoadComponents(app) 38 | } 39 | 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/bilibiliUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.bilibiliUI 9 | 10 | import railgunDownloaderV4.components.bilibiliUI.events.Download 11 | import railgunDownloaderV4.components.global.LogResult 12 | import railgunDownloaderV4.components.global.TextField 13 | import railgunDownloaderV4.components.global.ButtonUI 14 | import railgunDownloaderV4.components.global.QualityBox 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JList 21 | import javax.swing.JTextArea 22 | import javax.swing.JTextField 23 | 24 | class LoadComponents { 25 | 26 | private val textField: TextField by lazy { TextField() } 27 | private val logResult: LogResult by lazy { LogResult() } 28 | private val setButtonUI: ButtonUI by lazy { ButtonUI() } 29 | private val pathDialog: PathDialog by lazy { PathDialog() } 30 | private val qualityBox: QualityBox by lazy { QualityBox() } 31 | private val download: Download by lazy { Download(urlField, pathField, resultLog, qualityList) } 32 | 33 | private val urlField: JTextField by lazy { JTextField() } 34 | private val pathField: JTextField by lazy { JTextField() } 35 | private val resultLog: JTextArea by lazy { JTextArea() } 36 | private val qualityList: JList by lazy { JList() } 37 | private val downloadButton: JButton by lazy { JButton() } 38 | private val saveDirButton: JButton by lazy { JButton() } 39 | 40 | fun setLoadComponents(appTarget: JFrame) { 41 | textField.setTextField( 42 | appTarget, urlField, 43 | Dimension(400, 30), Point(100, 450), 44 | true, "Input your Bilibili video URL here" 45 | ) 46 | textField.setTextField( 47 | appTarget, pathField, 48 | Dimension(400, 30), Point(100, 400), 49 | false, "Your save directory path will be displayed here" 50 | ) 51 | logResult.setLogResult( 52 | appTarget, resultLog, 53 | Dimension(400, 300), Point(100, 50), 54 | "Your result log will be displayed here" 55 | ) 56 | setButtonUI.setButtonUI( 57 | appTarget, downloadButton, 58 | Dimension(50, 50), Point(100, 490), 59 | "/Download.png", "Download video from Bilibili" 60 | ) 61 | download.setDownload(downloadButton) 62 | setButtonUI.setButtonUI( 63 | appTarget, saveDirButton, 64 | Dimension(50, 50), Point(160, 490), 65 | "/FolderPath.png", "Choose your save directory path" 66 | ) 67 | pathDialog.setShowDialog( 68 | saveDirButton, "Download from Bilibili", 69 | pathField 70 | ) 71 | 72 | qualityBox.setQualityBox( 73 | appTarget, qualityList, 74 | Point(20, 390), Dimension(70, 150) 75 | ) 76 | } 77 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/bilibiliUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.bilibiliUI.events 10 | 11 | import railgunDownloaderV4.components.global.events.DownloadVideoProcess 12 | import railgunDownloaderV4.components.ulti.ClearEvents 13 | import railgunDownloaderV4.components.ulti.DirExists 14 | import railgunDownloaderV4.components.ulti.MatchURL 15 | import railgunDownloaderV4.components.ulti.MessageDialog 16 | import javax.swing.JButton 17 | import javax.swing.JList 18 | import javax.swing.JTextArea 19 | import javax.swing.JTextField 20 | 21 | class Download ( 22 | private val urlField: JTextField, 23 | private val pathField: JTextField, 24 | private val logArea: JTextArea, 25 | private val qualityList: JList 26 | ){ 27 | 28 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 29 | private val matchURL: MatchURL by lazy { MatchURL() } 30 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 31 | private val dirExists: DirExists by lazy { DirExists() } 32 | private val downloadVideoProcess: DownloadVideoProcess by lazy { DownloadVideoProcess() } 33 | 34 | fun setDownload(buttonTarget: JButton) { 35 | clearEvents.clearActionListeners(buttonTarget) 36 | 37 | buttonTarget.addActionListener { 38 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 39 | messageDialog.showMessageNotification("Please input valid Bilibili URL") 40 | return@addActionListener 41 | } 42 | 43 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 44 | messageDialog.showMessageNotification("Please choose valid save directory") 45 | return@addActionListener 46 | } 47 | 48 | val quality = qualityList.selectedValue 49 | when(quality) { 50 | "Best Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "best") 51 | "Worst Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worst") 52 | "Best Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestvideo") 53 | "Worst Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstvideo") 54 | "Best Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestaudio") 55 | "Worst Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstaudio") 56 | } 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/devianArtUI/DevianArtUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DevianArtUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.devianArtUI 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.events.GoHome 12 | import railgunDownloaderV4.components.ulti.SetIcon 13 | import java.awt.Color 14 | import java.awt.Dimension 15 | import javax.swing.JFrame 16 | 17 | class DevianArtUI (appScene: Application){ 18 | 19 | private val goHome: GoHome by lazy { GoHome(appScene) } 20 | private val setIcon: SetIcon by lazy { SetIcon() } 21 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 22 | 23 | fun setDevianArtUI(visible: Boolean = true) { 24 | val app = JFrame("Download image from DevianArt") 25 | app.size = Dimension(600, 600) 26 | app.isResizable = false 27 | app.maximumSize = Dimension(600, 600) 28 | app.setLocationRelativeTo(null) 29 | app.layout = null 30 | app.iconImage = setIcon.setAppIcon() 31 | app.contentPane.background = Color(21, 21, 21) 32 | app.foreground = Color.WHITE 33 | app.isVisible = visible 34 | 35 | loadComponents.setLoadComponents(app) 36 | goHome.setGoHome(app) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/devianArtUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.devianArtUI 10 | 11 | import railgunDownloaderV4.components.devianArtUI.events.Download 12 | import railgunDownloaderV4.components.global.ButtonUI 13 | import railgunDownloaderV4.components.global.LogResult 14 | import railgunDownloaderV4.components.global.TextField 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JTextArea 21 | import javax.swing.JTextField 22 | 23 | class LoadComponents { 24 | 25 | private val textField: TextField by lazy { TextField() } 26 | private val logResult: LogResult by lazy { LogResult() } 27 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 28 | private val pathDialog: PathDialog by lazy { PathDialog() } 29 | private val download: Download by lazy { Download(urlField, pathField, logArea) } 30 | 31 | private val urlField: JTextField by lazy { JTextField() } 32 | private val pathField: JTextField by lazy { JTextField() } 33 | private val logArea: JTextArea by lazy { JTextArea() } 34 | private val downloadButton: JButton by lazy { JButton() } 35 | private val saveDirButton: JButton by lazy { JButton() } 36 | 37 | fun setLoadComponents(appTarget: JFrame) { 38 | textField.setTextField( 39 | appTarget, urlField, 40 | Dimension(400, 30), Point(100, 450), 41 | true, "Input your DevianArt image URL here" 42 | ) 43 | textField.setTextField( 44 | appTarget, pathField, 45 | Dimension(400, 30), Point(100, 400), 46 | false, "Your save directory path will be displayed here" 47 | ) 48 | logResult.setLogResult( 49 | appTarget, logArea, 50 | Dimension(400, 300), Point(100, 30), 51 | "Your download result will be displayed here" 52 | ) 53 | buttonUI.setButtonUI( 54 | appTarget, downloadButton, 55 | Dimension(50, 50), Point(100, 490), 56 | "/Download.png", "Download image from DevianArt" 57 | ) 58 | download.setDownload(downloadButton) 59 | 60 | buttonUI.setButtonUI( 61 | appTarget, saveDirButton, 62 | Dimension(50, 50), Point(180, 490), 63 | "/FolderPath.png", "Choose save directory path" 64 | ) 65 | pathDialog.setShowDialog( 66 | saveDirButton, "Choose save directory path", 67 | pathField 68 | ) 69 | } 70 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/devianArtUI/events/DevianArtDownload.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DevianArtDownload.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.devianArtUI.events 9 | 10 | import okhttp3.OkHttpClient 11 | import okhttp3.Request 12 | import org.openqa.selenium.By 13 | import org.openqa.selenium.NoSuchElementException 14 | import org.openqa.selenium.TimeoutException 15 | import org.openqa.selenium.WebElement 16 | import org.openqa.selenium.chrome.ChromeDriver 17 | import org.openqa.selenium.chrome.ChromeOptions 18 | import org.openqa.selenium.support.ui.WebDriverWait 19 | import railgunDownloaderV4.components.ulti.MessageDialog 20 | import java.io.File 21 | import java.io.FileOutputStream 22 | import java.net.URI 23 | import java.time.Duration 24 | import javax.swing.JTextArea 25 | import javax.swing.JTextField 26 | import javax.swing.SwingUtilities 27 | import javax.swing.SwingWorker 28 | 29 | class DevianArtDownload ( 30 | private val urlField: JTextField, 31 | private val pathField: JTextField, 32 | private val logArea: JTextArea 33 | ){ 34 | 35 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 36 | 37 | private fun downloadImage(imgURL: String, saveDir: String, imgName: String) { 38 | val client = OkHttpClient() 39 | val requestBuilder = Request.Builder() 40 | .url(imgURL) 41 | .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36") 42 | .header("Referer", imgURL) 43 | .header("Accept", "image/avif,image/webp,image/apng,image/*,*/*;q=0.8") 44 | .header("Accept-Language", "en-US,en;q=0.5") 45 | .build() 46 | val saveDirectory = File("$saveDir/$imgName") 47 | 48 | client.newCall(requestBuilder).execute() 49 | .use { response -> 50 | FileOutputStream(saveDirectory).let { result -> 51 | response.body?.bytes()?.let { result.write(it) } 52 | SwingUtilities.invokeLater { 53 | logArea.append("Successfully download image $imgName") 54 | 55 | } 56 | } 57 | } 58 | } 59 | 60 | private fun devianArtDownload() { 61 | val chromeOptions = ChromeOptions() 62 | chromeOptions.addArguments("--headless") 63 | 64 | val chromeDriver = ChromeDriver(chromeOptions) 65 | WebDriverWait(chromeDriver, Duration.ofSeconds(30)) 66 | SwingUtilities.invokeLater { 67 | logArea.append("Get your DevianArt URL, please wait\n") 68 | } 69 | chromeDriver.get(urlField.text) 70 | 71 | val imageElement: WebElement? 72 | try { imageElement = chromeDriver.findElement(By.cssSelector("img.TZM0T._2NIJr")) } 73 | catch (noSuchElement: NoSuchElementException) { 74 | messageDialog.showMessageNotification("Can't find any image in your DevianArt URL. Please try again") 75 | return 76 | } catch (timeout: TimeoutException) { 77 | messageDialog.showMessageNotification("Connection timeout. Please check your internet connection and try again") 78 | return 79 | } 80 | 81 | val imgBaseName = imageElement.getDomAttribute("src")?.let { URI(it).path.substringAfterLast('/') } 82 | val imgURL = imageElement.getDomAttribute("src") 83 | 84 | downloadImage( 85 | imgURL!!, pathField.text, 86 | imgBaseName!! 87 | ) 88 | } 89 | 90 | fun setDevianArtDownload() { 91 | object : SwingWorker() { 92 | override fun doInBackground() { 93 | devianArtDownload() 94 | } 95 | }.execute() 96 | } 97 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/devianArtUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.devianArtUI.events 9 | 10 | import railgunDownloaderV4.components.ulti.DirExists 11 | import railgunDownloaderV4.components.ulti.MatchURL 12 | import railgunDownloaderV4.components.ulti.MessageDialog 13 | import javax.swing.JButton 14 | import javax.swing.JTextArea 15 | import javax.swing.JTextField 16 | 17 | class Download ( 18 | private val urlField: JTextField, 19 | private val pathField: JTextField, 20 | private val logArea: JTextArea 21 | ){ 22 | 23 | private val matchURL: MatchURL by lazy { MatchURL() } 24 | private val dirExists: DirExists by lazy { DirExists() } 25 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 26 | private val devianArtDownload: DevianArtDownload by lazy { DevianArtDownload(urlField, pathField, logArea) } 27 | 28 | fun setDownload(buttonTarget: JButton) { 29 | buttonTarget.addActionListener { 30 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 31 | messageDialog.showMessageNotification("Please input valid DevianArt URL") 32 | return@addActionListener 33 | } 34 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 35 | messageDialog.showMessageNotification("Please choose valid save directory path") 36 | return@addActionListener 37 | } 38 | 39 | devianArtDownload.setDevianArtDownload() 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/facebookUI/FacebookUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: FacebookUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.facebookUI 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.events.GoHome 12 | import railgunDownloaderV4.components.ulti.SetIcon 13 | import java.awt.Color 14 | import java.awt.Dimension 15 | import javax.swing.* 16 | 17 | class FacebookUI (private val appScene: Application){ 18 | 19 | private val setIcon: SetIcon by lazy { SetIcon() } 20 | private val goHome: GoHome by lazy { GoHome(appScene) } 21 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 22 | 23 | fun showFacebookUI(visible: Boolean = false) { 24 | val app = JFrame() 25 | SwingUtilities.invokeLater { 26 | app.apply { 27 | title = "Download video from Facebook" 28 | size = Dimension(600, 600) 29 | isResizable = false 30 | maximumSize = Dimension(600, 600) 31 | contentPane.background = Color(21, 21, 21) 32 | setLocationRelativeTo(null) 33 | layout = null 34 | iconImage = setIcon.setAppIcon() 35 | isVisible = visible 36 | 37 | loadComponents.setLoadComponents(app) 38 | goHome.setGoHome(app) 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/facebookUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.facebookUI 10 | 11 | import railgunDownloaderV4.components.facebookUI.events.Download 12 | import railgunDownloaderV4.components.global.ButtonUI 13 | import railgunDownloaderV4.components.global.LogResult 14 | import railgunDownloaderV4.components.global.QualityBox 15 | import railgunDownloaderV4.components.global.TextField 16 | import railgunDownloaderV4.components.ulti.PathDialog 17 | import java.awt.Dimension 18 | import java.awt.Point 19 | import javax.swing.JButton 20 | import javax.swing.JFrame 21 | import javax.swing.JList 22 | import javax.swing.JTextArea 23 | import javax.swing.JTextField 24 | 25 | class LoadComponents { 26 | private val qualityBox: QualityBox by lazy { QualityBox() } 27 | private val textField: TextField by lazy { TextField() } 28 | private val logResult: LogResult by lazy { LogResult() } 29 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 30 | private val pathDialog: PathDialog by lazy { PathDialog() } 31 | private val download: Download by lazy { Download(urlField, pathField, logArea, qualityList) } 32 | 33 | private val qualityList: JList by lazy { JList() } 34 | private val urlField: JTextField by lazy { JTextField() } 35 | private val pathField: JTextField by lazy { JTextField() } 36 | private val logArea: JTextArea by lazy { JTextArea() } 37 | private val downloadButton: JButton by lazy { JButton() } 38 | private val savePathButton: JButton by lazy { JButton() } 39 | 40 | fun setLoadComponents(app: JFrame) { 41 | qualityBox.setQualityBox( 42 | app, qualityList, 43 | Point(320, 440), 44 | Dimension(70, 150) 45 | ) 46 | textField.setTextField( 47 | app, urlField, 48 | Dimension(400, 30), Point(100, 400), 49 | true, "Input your Facebook video URL here" 50 | ) 51 | textField.setTextField( 52 | app, pathField, 53 | Dimension(400, 30), Point(100, 350), 54 | false, "Your chosen directory path will be displayed here" 55 | ) 56 | 57 | buttonUI.setButtonUI( 58 | app, downloadButton, 59 | Dimension(50, 50), Point(170, 440), 60 | "/Download.png", "Download video from Facebook" 61 | ) 62 | download.setDownload(downloadButton) 63 | 64 | buttonUI.setButtonUI( 65 | app, savePathButton, 66 | Dimension(50, 50), Point(100, 440), 67 | "/FolderPath.png", "Choose save directory path" 68 | ) 69 | pathDialog.setShowDialog(savePathButton, "Choose save directory", pathField) 70 | 71 | logResult.setLogResult( 72 | app, logArea, 73 | Dimension(400, 300), Point(100, 20), 74 | "Your download result will be displayed here" 75 | ) 76 | } 77 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/facebookUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.facebookUI.events 9 | import railgunDownloaderV4.components.global.events.DownloadVideoProcess 10 | import railgunDownloaderV4.components.ulti.ClearEvents 11 | import railgunDownloaderV4.components.ulti.DirExists 12 | import railgunDownloaderV4.components.ulti.MatchURL 13 | import railgunDownloaderV4.components.ulti.MessageDialog 14 | import javax.swing.JButton 15 | import javax.swing.JTextArea 16 | import javax.swing.JTextField 17 | import javax.swing.JList 18 | 19 | 20 | class Download ( 21 | private val urlField: JTextField, 22 | private val pathField: JTextField, 23 | private val logArea: JTextArea, 24 | private val qualityList: JList 25 | ){ 26 | 27 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 28 | private val matchURL: MatchURL by lazy { MatchURL() } 29 | private val dirExists: DirExists by lazy { DirExists() } 30 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 31 | private val downloadVideoProcess: DownloadVideoProcess by lazy { DownloadVideoProcess() } 32 | 33 | fun setDownload(downloadButton: JButton) { 34 | 35 | clearEvents.clearActionListeners(downloadButton) 36 | 37 | downloadButton.addActionListener { 38 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 39 | messageDialog.showMessageNotification("Invalid URL. Please try again") 40 | return@addActionListener 41 | } 42 | 43 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 44 | messageDialog.showMessageNotification("Invalid directory. Please try again") 45 | return@addActionListener 46 | } 47 | 48 | val quality = qualityList.selectedValue 49 | when(quality) { 50 | "Best Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "best") 51 | "Worst Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worst") 52 | "Best Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestvideo") 53 | "Worst Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstvideo") 54 | "Best Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestaudio") 55 | "Worst Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstaudio") 56 | } 57 | 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/ButtonUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Application.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.global 9 | 10 | import railgunDownloaderV4.components.ulti.SetIconButton 11 | import java.awt.Dimension 12 | import javax.swing.JButton 13 | import javax.swing.JFrame 14 | import java.awt.Point 15 | 16 | class ButtonUI { 17 | 18 | private val setIconButton: SetIconButton by lazy { SetIconButton() } 19 | 20 | fun setButtonUI( 21 | app: JFrame, 22 | button: JButton, 23 | size: Dimension, 24 | location: Point, 25 | iconPath: String, 26 | toolTipText: String 27 | ) { 28 | button.size = size 29 | button.location = location 30 | button.isContentAreaFilled = false 31 | button.border = null 32 | button.isFocusPainted = false 33 | button.isBorderPainted = false 34 | 35 | setIconButton.setIcon( 36 | button, iconPath, 37 | button.width, button.height 38 | ) 39 | button.toolTipText = toolTipText 40 | 41 | app.add(button) 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/LogResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LogResult.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.global 10 | 11 | import java.awt.Color 12 | import java.awt.Dimension 13 | import java.awt.Font 14 | import java.awt.Point 15 | import javax.swing.JFrame 16 | import javax.swing.JScrollPane 17 | import javax.swing.JTextArea 18 | 19 | class LogResult { 20 | fun setLogResult( 21 | app: JFrame, 22 | logArea: JTextArea, 23 | size: Dimension, 24 | location: Point, 25 | toolTipText: String 26 | ) { 27 | logArea.background = Color(69, 69, 69) 28 | logArea.foreground = Color.WHITE 29 | logArea.font = Font("Consolas", Font.PLAIN, 12) 30 | logArea.isEditable = false 31 | logArea.lineWrap = true 32 | logArea.toolTipText = toolTipText 33 | 34 | val scrollPanel = JScrollPane(logArea) 35 | scrollPanel.size = size 36 | scrollPanel.location = location 37 | scrollPanel.border = null 38 | scrollPanel.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED 39 | scrollPanel.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED 40 | 41 | app.add(scrollPanel) 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/QualityBox.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: QualityBox.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.global 10 | 11 | import java.awt.* 12 | import javax.swing.* 13 | 14 | class QualityBox { 15 | fun setQualityBox( 16 | appTarget: JFrame, 17 | qualityBox: JList, 18 | location: Point, 19 | size: Dimension 20 | ) { 21 | val qualityList = arrayOf( 22 | "Best Quality", 23 | "Worst Quality", 24 | "Best Video", 25 | "Worst Video", 26 | "Best Audio", 27 | "Worst Audio" 28 | ) 29 | 30 | qualityBox.setListData(qualityList) 31 | qualityBox.selectionMode = ListSelectionModel.SINGLE_SELECTION 32 | qualityBox.size = size 33 | qualityBox.location = location 34 | qualityBox.background = Color(21, 21, 21) 35 | qualityBox.foreground = Color.WHITE 36 | qualityBox.selectedIndex = 0 37 | qualityBox.font = Font("Consolas", Font.PLAIN, 10) 38 | qualityBox.toolTipText = "Choose your video quality" 39 | 40 | qualityBox.cellRenderer = object : DefaultListCellRenderer() { 41 | override fun getListCellRendererComponent( 42 | list: JList<*>?, 43 | value: Any, 44 | index: Int, 45 | isSelected: Boolean, 46 | cellHasFocus: Boolean 47 | ): Component { 48 | val qualityLabel = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus) as JLabel 49 | 50 | qualityLabel.horizontalAlignment = CENTER 51 | return qualityLabel 52 | } 53 | } 54 | 55 | appTarget.add(qualityBox) 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/TextField.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Application.kt 4 | * This project is licensed under GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.global 9 | 10 | import java.awt.Color 11 | import java.awt.Dimension 12 | import java.awt.Font 13 | import java.awt.Point 14 | import javax.swing.JFrame 15 | import javax.swing.JTextField 16 | 17 | class TextField { 18 | fun setTextField( 19 | app: JFrame, 20 | textField: JTextField, 21 | size: Dimension, 22 | location: Point, 23 | canEditable: Boolean, 24 | toolTipText: String 25 | ) { 26 | textField.size = size 27 | textField.location = location 28 | textField.toolTipText = toolTipText 29 | textField.border = null 30 | textField.isEditable = canEditable 31 | textField.background = Color(69, 69, 69) 32 | textField.foreground = Color.WHITE 33 | textField.font = Font("Consolas", Font.PLAIN, 12) 34 | textField.isVisible = true 35 | 36 | app.add(textField) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/events/DownloadVideoProcess.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DownloadProcess.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.global.events 10 | 11 | import railgunDownloaderV4.components.ulti.CheckOS 12 | import java.io.BufferedReader 13 | import java.io.InputStreamReader 14 | import javax.swing.JTextArea 15 | import javax.swing.SwingUtilities 16 | import kotlin.io.path.Path 17 | import kotlin.io.path.absolutePathString 18 | 19 | class DownloadVideoProcess { 20 | private val checkOS: CheckOS by lazy { CheckOS() } 21 | 22 | fun setDownloadVideoProcess(videoURL: String, saveDir: String, logArea: JTextArea, quality: String) { 23 | var absolutePath = "Unknown" 24 | when(checkOS.sysType()) { 25 | "Linux" -> absolutePath = Path("bin/Helper.lib").absolutePathString() 26 | "Windows" -> absolutePath = Path("bin/Helper.exe").absolutePathString() 27 | } 28 | val processBuilder = ProcessBuilder( 29 | absolutePath, 30 | "-o", 31 | "$saveDir/%(title)s.%(ext)s", 32 | "-f", 33 | quality, 34 | "--yes-playlist", 35 | videoURL 36 | ) 37 | val process = processBuilder.start() 38 | val reader = BufferedReader(InputStreamReader(process.inputStream)) 39 | var content: String? 40 | 41 | val showResultJob = Thread { 42 | while (reader.readLine().also { content = it } != null) { 43 | SwingUtilities.invokeLater { logArea.append("$content\n") } 44 | } 45 | } 46 | showResultJob.start() 47 | } 48 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/events/GoHome.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: GoHome.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.global.events 10 | 11 | import railgunDownloaderV4.Application 12 | import java.awt.event.WindowAdapter 13 | import java.awt.event.WindowEvent 14 | import javax.swing.JFrame 15 | 16 | class GoHome(private val appScene: Application){ 17 | fun setGoHome(targetApp: JFrame) { 18 | targetApp.addWindowListener(object : WindowAdapter(){ 19 | override fun windowClosing(e: WindowEvent?) { 20 | appScene.app.isVisible = true 21 | } 22 | }) 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/global/events/LoadUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.global.events 10 | 11 | import railgunDownloaderV4.Application 12 | import javax.swing.JButton 13 | 14 | class LoadUI (private val appScene: Application){ 15 | fun setLoadUI(targetButton: JButton, action: (Boolean) -> Unit) { 16 | targetButton.addActionListener { 17 | action(true) 18 | appScene.app.isVisible = false 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/hitomiUI/HitomiUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: HitomiUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.hitomiUI 10 | 11 | import railgunDownloaderV4.Application 12 | import railgunDownloaderV4.components.global.events.GoHome 13 | import railgunDownloaderV4.components.ulti.SetIcon 14 | import java.awt.Color 15 | import java.awt.Dimension 16 | import javax.swing.JFrame 17 | import javax.swing.WindowConstants 18 | 19 | class HitomiUI (private val appScene: Application){ 20 | 21 | private val goHome: GoHome by lazy { GoHome(appScene) } 22 | private val setIcon: SetIcon by lazy { SetIcon() } 23 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 24 | 25 | fun setHitomiUI(visible: Boolean) { 26 | val app = JFrame("Download from Hitomi.la") 27 | app.size = Dimension(600, 600) 28 | app.isResizable = false 29 | app.maximumSize = Dimension(600, 600) 30 | app.contentPane.background = Color(21, 21, 21) 31 | app.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 32 | app.setLocationRelativeTo(null) 33 | app.layout = null 34 | app.iconImage = setIcon.setAppIcon() 35 | loadComponents.setLoadComponents(app) 36 | app.isVisible = visible 37 | 38 | goHome.setGoHome(app) 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/hitomiUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.hitomiUI 10 | 11 | import railgunDownloaderV4.components.global.ButtonUI 12 | import railgunDownloaderV4.components.global.LogResult 13 | import railgunDownloaderV4.components.global.TextField 14 | import railgunDownloaderV4.components.hitomiUI.events.HitomiDownload 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JTextArea 21 | import javax.swing.JTextField 22 | 23 | class LoadComponents { 24 | 25 | private val textField: TextField by lazy { TextField() } 26 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 27 | private val pathDialog: PathDialog by lazy { PathDialog() } 28 | private val hitomiDownload: HitomiDownload by lazy { HitomiDownload(urlField, pathField, logArea) } 29 | private val logResult: LogResult by lazy { LogResult() } 30 | 31 | private val urlField: JTextField by lazy { JTextField() } 32 | private val pathField: JTextField by lazy { JTextField() } 33 | private val downloadButton: JButton by lazy { JButton() } 34 | private val saveDirButton: JButton by lazy { JButton() } 35 | private val logArea: JTextArea by lazy { JTextArea() } 36 | 37 | fun setLoadComponents(appTarget: JFrame ){ 38 | textField.setTextField( 39 | appTarget, urlField, Dimension(400, 30), 40 | Point(100, 400), true, 41 | "Input your Hitomi.la doujinshi URL here" 42 | ) 43 | textField.setTextField( 44 | appTarget, pathField, Dimension(400, 30), 45 | Point(100, 350), false, 46 | "Your chose save path directory will be displayed here" 47 | ) 48 | 49 | buttonUI.setButtonUI( 50 | appTarget, downloadButton, Dimension(50, 50), 51 | Point(100, 450), "/Download.png", 52 | "Download doujinshi from Hitomi.la" 53 | ) 54 | hitomiDownload.setHitomiDownload(downloadButton) 55 | 56 | buttonUI.setButtonUI( 57 | appTarget, saveDirButton, Dimension(50, 50), 58 | Point(200, 450), "/FolderPath.png", 59 | "Choose save directory path" 60 | ) 61 | pathDialog.setShowDialog( 62 | saveDirButton, "Choose save directory", 63 | pathField 64 | ) 65 | 66 | logResult.setLogResult( 67 | appTarget, logArea, Dimension(400, 250), 68 | Point(100, 50), "Your download result will be displayed here" 69 | ) 70 | } 71 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/hitomiUI/events/Downloader.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Downloader.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.hitomiUI.events 10 | 11 | import okhttp3.OkHttpClient 12 | import okhttp3.Request 13 | import org.openqa.selenium.By 14 | import org.openqa.selenium.NoSuchElementException 15 | import org.openqa.selenium.WebDriver 16 | import org.openqa.selenium.WebElement 17 | import org.openqa.selenium.chrome.ChromeDriver 18 | import org.openqa.selenium.chrome.ChromeOptions 19 | import org.openqa.selenium.support.ui.WebDriverWait 20 | import railgunDownloaderV4.components.ulti.MessageDialog 21 | import java.io.File 22 | import java.io.FileOutputStream 23 | import java.net.URI 24 | import java.time.Duration 25 | import javax.swing.JTextArea 26 | import javax.swing.JTextField 27 | import javax.swing.SwingUtilities 28 | import javax.swing.SwingWorker 29 | 30 | class Downloader( 31 | private val urlField: JTextField, 32 | private val pathField: JTextField, 33 | private val logResult: JTextArea 34 | ) { 35 | 36 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 37 | 38 | private fun downloadImage(imageURL: String, saveDir: String, imageName: String) { 39 | val client = OkHttpClient() 40 | val request = Request.Builder() 41 | .url(imageURL) 42 | .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36") 43 | .header("Referer", "https://hitomi.la/") 44 | .header("Accept", "image/avif,image/webp,image/apng,image/*,*/*;q=0.8") 45 | .header("Accept-Language", "en-US,en;q=0.5") 46 | .build() 47 | val saveDirectory = File("$saveDir/$imageName") 48 | 49 | client.newCall(request).execute() 50 | .use { response -> 51 | FileOutputStream(saveDirectory).use { output -> 52 | response.body?.bytes()?.let { output.write(it) } 53 | SwingUtilities.invokeLater { logResult.append("Download: $imageName\n") } 54 | } 55 | } 56 | } 57 | 58 | private fun hitomiDownloadProcess() { 59 | SwingUtilities.invokeLater { logResult.append("Starting download doujinshi, please wait\n") } 60 | val option = ChromeOptions() 61 | option.addArguments("--headless") 62 | val webDriver: WebDriver = ChromeDriver(option) 63 | 64 | WebDriverWait(webDriver, Duration.ofSeconds(30)) 65 | webDriver.get(urlField.text) 66 | 67 | val doujinshiName: WebElement? 68 | try { doujinshiName = webDriver.findElement(By.cssSelector("h1#gallery-brand")) } 69 | catch (notFoundException: NoSuchElementException){ 70 | messageDialog.showMessageNotification("Doujinshi not found. Please try again") 71 | SwingUtilities.invokeLater { logResult.append("Download failed with error: DOUJINSHI_NOT_FOUND\n") } 72 | return 73 | } 74 | 75 | val doujinshiImages: List 76 | try { doujinshiImages = webDriver.findElements(By.cssSelector("ul.thumbnail-list img.lazyload")) } 77 | catch (notFoundException: NoSuchElementException) { 78 | messageDialog.showMessageNotification("Can't find any image in doujinshi $doujinshiName") 79 | SwingUtilities.invokeLater { logResult.append("Download image failed with error: IMAGE_NOT_FOUND") } 80 | return 81 | } 82 | 83 | val absoluteDir = File("${pathField.text}/${doujinshiName.text}") 84 | absoluteDir.takeIf { !it.exists() }?.let { 85 | SwingUtilities.invokeLater { logResult.append("Created save doujinshi folder ${doujinshiName.text}\n") } 86 | it.mkdirs() 87 | } ?: run{ 88 | messageDialog.showMessageNotification("Doujinshi ${doujinshiName.text} is exists in your PC") 89 | SwingUtilities.invokeLater { logResult.append("Doujinshi ${doujinshiName.text} is exists in your PC") } 90 | return 91 | } 92 | 93 | doujinshiImages.forEach { image -> 94 | val imageName = image.getDomAttribute("data-src")?.let { URI(it).path.substringAfterLast('/').substring(50) } 95 | imageName?.let { 96 | downloadImage( 97 | image.getDomAttribute("data-src")!!, 98 | absoluteDir.absolutePath, it 99 | ) 100 | } 101 | } 102 | SwingUtilities.invokeLater { logResult.append("Successfully download doujinshi $doujinshiName to:\n$absoluteDir") } 103 | } 104 | 105 | fun setDownloader() { 106 | object : SwingWorker() { 107 | override fun doInBackground() { 108 | hitomiDownloadProcess() 109 | } 110 | }.execute() 111 | } 112 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/hitomiUI/events/HitomiDownload.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: HitomiDownload.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.hitomiUI.events 10 | 11 | import railgunDownloaderV4.components.ulti.ClearEvents 12 | import railgunDownloaderV4.components.ulti.DirExists 13 | import railgunDownloaderV4.components.ulti.MatchURL 14 | import railgunDownloaderV4.components.ulti.MessageDialog 15 | import javax.swing.JButton 16 | import javax.swing.JTextArea 17 | import javax.swing.JTextField 18 | 19 | class HitomiDownload ( 20 | private val urlField: JTextField, 21 | private val pathField: JTextField, 22 | private val resultArea: JTextArea 23 | ){ 24 | 25 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 26 | private val matchURL: MatchURL by lazy { MatchURL() } 27 | private val dirExists: DirExists by lazy { DirExists() } 28 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 29 | private val downloader: Downloader by lazy { Downloader(urlField, pathField, resultArea) } 30 | 31 | fun setHitomiDownload(buttonTarget: JButton) { 32 | clearEvents.clearActionListeners(buttonTarget) 33 | 34 | buttonTarget.addActionListener { 35 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 36 | messageDialog.showMessageNotification("Please input valid Hitomi.la doujinshi URL") 37 | return@addActionListener 38 | } 39 | 40 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 41 | messageDialog.showMessageNotification("Please choose valid save path directory") 42 | return@addActionListener 43 | 44 | } 45 | 46 | downloader.setDownloader() 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/instagramUI/InstagramUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: InstagramUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.instagramUI 10 | 11 | import railgunDownloaderV4.Application 12 | import railgunDownloaderV4.components.global.events.GoHome 13 | import railgunDownloaderV4.components.ulti.SetIcon 14 | import java.awt.Color 15 | import java.awt.Dimension 16 | import javax.swing.JFrame 17 | import javax.swing.WindowConstants 18 | 19 | class InstagramUI(appScene: Application) { 20 | 21 | private val setIcon: SetIcon by lazy { SetIcon() } 22 | private val goHome: GoHome by lazy { GoHome(appScene) } 23 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 24 | 25 | fun setInstagramUI(visible: Boolean = false) { 26 | val app = JFrame("Download from Instagram") 27 | app.size = Dimension(600, 600) 28 | app.isResizable = false 29 | app.iconImage = setIcon.setAppIcon() 30 | app.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 31 | app.setLocationRelativeTo(null) 32 | app.contentPane.background = Color(21, 21, 21) 33 | app.layout = null 34 | app.maximumSize = Dimension(600, 600) 35 | app.isVisible = visible 36 | 37 | loadComponents.setLoadComponent(app) 38 | goHome.setGoHome(app) 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/instagramUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.instagramUI 10 | 11 | import railgunDownloaderV4.components.global.ButtonUI 12 | import railgunDownloaderV4.components.global.LogResult 13 | import railgunDownloaderV4.components.global.TextField 14 | import railgunDownloaderV4.components.instagramUI.events.Download 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JTextArea 21 | import javax.swing.JTextField 22 | 23 | class LoadComponents { 24 | 25 | private val textField: TextField by lazy { TextField() } 26 | private val logResult: LogResult by lazy { LogResult() } 27 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 28 | private val pathDialog: PathDialog by lazy { PathDialog() } 29 | private val download: Download by lazy { Download(urlField, pathField, logArea) } 30 | 31 | private val urlField: JTextField by lazy { JTextField() } 32 | private val pathField: JTextField by lazy { JTextField() } 33 | private val logArea: JTextArea by lazy { JTextArea() } 34 | private val downloadButton: JButton by lazy { JButton() } 35 | private val saveDirButton: JButton by lazy { JButton() } 36 | 37 | fun setLoadComponent(appTarget: JFrame) { 38 | textField.setTextField( 39 | appTarget, urlField, Dimension(400, 30), 40 | Point(100, 450), true, 41 | "Input your Instagram video URL here" 42 | ) 43 | textField.setTextField( 44 | appTarget, pathField, Dimension(400, 30), 45 | Point(100, 400), false, 46 | "Your chosen save directory path will be displayed here" 47 | ) 48 | 49 | logResult.setLogResult( 50 | appTarget, logArea, Dimension(400, 300), 51 | Point(100, 30), 52 | "Your download result will be displayed here" 53 | ) 54 | 55 | buttonUI.setButtonUI( 56 | appTarget, downloadButton, 57 | Dimension(50, 50), Point(100, 490), 58 | "/Download.png", "Download video from Instagram" 59 | ) 60 | download.setDownload(downloadButton) 61 | 62 | buttonUI.setButtonUI( 63 | appTarget, saveDirButton, 64 | Dimension(50, 50), Point(180, 490), 65 | "/FolderPath.png", "Choose save directory path" 66 | ) 67 | pathDialog.setShowDialog( 68 | saveDirButton, "Choose your save directory path", 69 | pathField 70 | ) 71 | } 72 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/instagramUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.instagramUI.events 10 | 11 | import railgunDownloaderV4.components.global.events.DownloadVideoProcess 12 | import railgunDownloaderV4.components.ulti.ClearEvents 13 | import railgunDownloaderV4.components.ulti.DirExists 14 | import railgunDownloaderV4.components.ulti.MatchURL 15 | import railgunDownloaderV4.components.ulti.MessageDialog 16 | import javax.swing.JButton 17 | import javax.swing.JTextArea 18 | import javax.swing.JTextField 19 | 20 | class Download ( 21 | private val urlField: JTextField, 22 | private val pathField: JTextField, 23 | private val logArea: JTextArea 24 | ){ 25 | 26 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 27 | private val dirExists: DirExists by lazy { DirExists() } 28 | private val matchURL: MatchURL by lazy { MatchURL() } 29 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 30 | private val downloadVideoProcess: DownloadVideoProcess by lazy { DownloadVideoProcess() } 31 | 32 | fun setDownload(buttonTarget: JButton) { 33 | clearEvents.clearActionListeners(buttonTarget) 34 | 35 | buttonTarget.addActionListener { 36 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 37 | messageDialog.showMessageNotification("Please input valid Instagram URL") 38 | return@addActionListener 39 | } 40 | 41 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 42 | messageDialog.showMessageNotification("Please choose valid save directory path") 43 | return@addActionListener 44 | } 45 | 46 | downloadVideoProcess.setDownloadVideoProcess( 47 | urlField.text, pathField.text, 48 | logArea, "best" 49 | ) 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/LogResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LogResult.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI 9 | 10 | import java.awt.Color 11 | import java.awt.Dimension 12 | import java.awt.Font 13 | import java.awt.Point 14 | import javax.swing.JFrame 15 | import javax.swing.JScrollPane 16 | import javax.swing.JTextArea 17 | 18 | class LogResult { 19 | fun setLogResult(app: JFrame, logResultArea: JTextArea) { 20 | logResultArea.background = Color(69, 69, 69) 21 | logResultArea.foreground = Color.WHITE 22 | logResultArea.font = Font("Consolas", Font.PLAIN, 12) 23 | logResultArea.toolTipText = "Your download process will be displayed here" 24 | logResultArea.lineWrap = true 25 | 26 | val scrollPanel = JScrollPane(logResultArea) 27 | scrollPanel.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED 28 | scrollPanel.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED 29 | scrollPanel.border = null 30 | scrollPanel.size = Dimension(400, 340) 31 | scrollPanel.location = Point(100, 30) 32 | 33 | app.add(scrollPanel) 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/MangaDexButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MangaDexButton.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI 9 | 10 | import railgunDownloaderV4.components.ulti.SetIconButton 11 | import java.awt.Dimension 12 | import java.awt.Point 13 | import javax.swing.JButton 14 | import javax.swing.JFrame 15 | 16 | class MangaDexButton { 17 | 18 | private val setIconButton: SetIconButton by lazy { SetIconButton() } 19 | 20 | fun setMangaDexButton( 21 | app: JFrame, 22 | buttonTarget: JButton, 23 | size: Dimension, 24 | location: Point, 25 | iconPath: String, 26 | toolTipText: String 27 | ) { 28 | buttonTarget.size = size 29 | buttonTarget.location = location 30 | buttonTarget.isContentAreaFilled = false 31 | buttonTarget.border = null 32 | buttonTarget.isBorderPainted = false 33 | buttonTarget.isFocusPainted = false 34 | buttonTarget.toolTipText = toolTipText 35 | setIconButton.setIcon( 36 | buttonTarget, iconPath, 37 | 50, 50 38 | ) 39 | 40 | app.add(buttonTarget) 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/MangaDexTextField.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MangaDexTextField.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI 9 | 10 | import java.awt.Color 11 | import java.awt.Dimension 12 | import java.awt.Font 13 | import java.awt.Point 14 | import javax.swing.JFrame 15 | import javax.swing.JTextField 16 | 17 | class MangaDexTextField { 18 | fun setTextField( 19 | app: JFrame, 20 | textField: JTextField, 21 | isEditable: Boolean, 22 | location: Point, 23 | size: Dimension, 24 | toolTipText: String 25 | ) { 26 | 27 | textField.size = size 28 | textField.location = location 29 | textField.isEditable = isEditable 30 | textField.toolTipText = toolTipText 31 | textField.background = Color(69, 69, 69) 32 | textField.border = null 33 | textField.font = Font("Consolas", Font.PLAIN, 12) 34 | textField.foreground = Color.WHITE 35 | 36 | app.add(textField) 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/MangaDexUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MangaDexUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.mangadexUI.events.DownloadMangaDex 12 | import railgunDownloaderV4.components.mangadexUI.events.OpenDir 13 | import railgunDownloaderV4.components.mangadexUI.events.WindowClosing 14 | import railgunDownloaderV4.components.ulti.SetIcon 15 | import java.awt.Color 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JTextArea 21 | import javax.swing.JTextField 22 | import javax.swing.SwingUtilities 23 | 24 | class MangaDexUI (appScene: Application){ 25 | 26 | private val windowClosing: WindowClosing by lazy { WindowClosing(appScene) } 27 | private val mangaDexTextField: MangaDexTextField by lazy { MangaDexTextField() } 28 | private val mangaDexButton: MangaDexButton by lazy { MangaDexButton() } 29 | private val setIcon: SetIcon by lazy { SetIcon() } 30 | private val openDir: OpenDir by lazy { OpenDir(this) } 31 | private val downloadMangaDex: DownloadMangaDex by lazy { DownloadMangaDex(mangaDexIDField, mangaDexSaveDir, logResultArea) } 32 | private val setLogResult: LogResult by lazy { LogResult() } 33 | 34 | private val mangaDexIDField: JTextField by lazy { JTextField() } 35 | val mangaDexSaveDir: JTextField by lazy { JTextField() } 36 | private val saveDirButton: JButton by lazy { JButton() } 37 | private val downloadMangaButton: JButton by lazy { JButton() } 38 | private val logResultArea: JTextArea by lazy { JTextArea() } 39 | 40 | fun setMangaDexUI(visible: Boolean = false) { 41 | val app = JFrame() 42 | SwingUtilities.invokeLater { 43 | app.title = "Download from MangaDex" 44 | app.size = Dimension(600, 600) 45 | app.isResizable = false 46 | app.setLocationRelativeTo(null) 47 | app.isResizable = false 48 | app.contentPane.background = Color(21, 21, 21) 49 | app.layout = null 50 | app.maximumSize = Dimension(600, 600) 51 | app.iconImage = setIcon.setAppIcon() 52 | 53 | mangaDexTextField.setTextField( 54 | app, mangaDexIDField, true, 55 | Point(100, 450), Dimension(400, 30), 56 | "Input your MangaDex manga ID" 57 | ) 58 | mangaDexTextField.setTextField( 59 | app, mangaDexSaveDir, false, 60 | Point(100, 400), Dimension(400, 30), 61 | "Your chosen save directory path will be displayed here" 62 | ) 63 | 64 | mangaDexButton.setMangaDexButton( 65 | app, saveDirButton, 66 | Dimension(50, 50), Point(100, 490), 67 | "/FolderPath.png", "Choose save directory" 68 | ) 69 | openDir.setOpenDir(saveDirButton) 70 | 71 | mangaDexButton.setMangaDexButton( 72 | app, downloadMangaButton, 73 | Dimension(50, 50), Point(170, 490), 74 | "/Download.png", "Download manga" 75 | ) 76 | downloadMangaDex.download(downloadMangaButton) 77 | 78 | setLogResult.setLogResult(app, logResultArea) 79 | 80 | app.isVisible = visible 81 | } 82 | 83 | windowClosing.setWindowClosing(app) 84 | } 85 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/events/DownloadMangaDex.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DownloadMangaDex.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI.events 9 | 10 | import railgunDownloaderV4.components.mangadexUI.helper.MangaDexAPI 11 | import railgunDownloaderV4.components.ulti.ClearEvents 12 | import railgunDownloaderV4.components.ulti.DirExists 13 | import railgunDownloaderV4.components.ulti.MessageDialog 14 | import javax.swing.JButton 15 | import javax.swing.JTextArea 16 | import javax.swing.JTextField 17 | 18 | class DownloadMangaDex (private val inputURLField: JTextField, private val saveDirField: JTextField, private val logResult: JTextArea){ 19 | 20 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 21 | private val dirExists: DirExists by lazy { DirExists() } 22 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 23 | private val mangaDexAPI: MangaDexAPI by lazy { MangaDexAPI(logResult) } 24 | 25 | fun download(downloadButton: JButton) { 26 | clearEvents.clearActionListeners(downloadButton) 27 | 28 | downloadButton.addActionListener { 29 | val urlField = inputURLField.text 30 | val saveDirField = saveDirField.text 31 | 32 | urlField.takeIf { it.isNullOrBlank() }?.let { 33 | messageDialog.showMessageNotification("Please input MangaDex ID") 34 | return@addActionListener 35 | } 36 | 37 | dirExists.takeIf { !it.checkDirExists(saveDirField) }?.let { 38 | messageDialog.showMessageNotification("Please choose save directory") 39 | return@addActionListener 40 | } 41 | 42 | logResult.append("Starting fetch MangaID $urlField, please wait...\n") 43 | mangaDexAPI.startDownloadProcess(urlField, saveDirField ) 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/events/LoadUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI.events 9 | 10 | import railgunDownloaderV4.Application 11 | import javax.swing.JButton 12 | 13 | 14 | class LoadUI (private val appScene: Application){ 15 | fun setLoadUI(app: JButton, action: (Boolean) -> Unit) { 16 | app.addActionListener { 17 | action(true) 18 | appScene.app.isVisible = false 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/events/OpenDir.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: OpenDir.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI.events 9 | 10 | import railgunDownloaderV4.components.mangadexUI.MangaDexUI 11 | import railgunDownloaderV4.components.ulti.ClearEvents 12 | import javax.swing.JButton 13 | import javax.swing.JFileChooser 14 | import javax.swing.filechooser.FileSystemView 15 | 16 | class OpenDir (private val mangaDexUI: MangaDexUI){ 17 | 18 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 19 | 20 | fun setOpenDir(openDirButton: JButton) { 21 | clearEvents.clearActionListeners(openDirButton) 22 | openDirButton.addActionListener { 23 | 24 | val chooser = JFileChooser(FileSystemView.getFileSystemView()) 25 | chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY 26 | chooser.dialogTitle = "Download manga from MangaDex" 27 | 28 | chooser.takeIf { it.showOpenDialog(null) == JFileChooser.APPROVE_OPTION }?.let { 29 | mangaDexUI.mangaDexSaveDir.text = it.selectedFile.absolutePath 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/events/WindowClosing.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: WindowClosing.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI.events 9 | 10 | import railgunDownloaderV4.Application 11 | import java.awt.event.WindowAdapter 12 | import java.awt.event.WindowEvent 13 | import javax.swing.JFrame 14 | 15 | class WindowClosing (private val appScene: Application){ 16 | fun setWindowClosing(app: JFrame) { 17 | app.addWindowListener(object : WindowAdapter() { 18 | override fun windowClosing(e: WindowEvent?) { 19 | appScene.app.isVisible = true 20 | } 21 | }) 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/mangadexUI/helper/MangaDexAPI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MangaDexAPI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.mangadexUI.helper 9 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties 10 | import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper 11 | import okhttp3.OkHttpClient 12 | import okhttp3.Request 13 | import com.fasterxml.jackson.module.kotlin.readValue 14 | import railgunDownloaderV4.components.ulti.MessageDialog 15 | import java.io.File 16 | import java.io.FileOutputStream 17 | import java.net.URI 18 | import javax.swing.JTextArea 19 | import javax.swing.SwingUtilities 20 | import javax.swing.SwingWorker 21 | 22 | class MangaDexAPI ( 23 | private val logArea: JTextArea 24 | ){ 25 | 26 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 27 | 28 | @JsonIgnoreProperties(ignoreUnknown = true) 29 | data class Attributes( 30 | val title: Map 31 | ) 32 | 33 | @JsonIgnoreProperties(ignoreUnknown = true) 34 | data class Chapter( 35 | val id: String 36 | ) 37 | @JsonIgnoreProperties(ignoreUnknown = true) 38 | data class ChapterAttributes( 39 | val title: String 40 | ) 41 | @JsonIgnoreProperties(ignoreUnknown = true) 42 | data class ChapterName( 43 | val attributes: ChapterAttributes 44 | ) 45 | 46 | @JsonIgnoreProperties(ignoreUnknown = true) 47 | data class ImageProperty( 48 | val baseUrl: String, 49 | val result: String, 50 | val chapter: Image 51 | ) 52 | 53 | @JsonIgnoreProperties(ignoreUnknown = true) 54 | data class Image( 55 | val hash: String, 56 | val data: List 57 | ) 58 | 59 | @JsonIgnoreProperties(ignoreUnknown = true) 60 | data class Manga( 61 | val attributes: Attributes 62 | ) 63 | 64 | private fun fetchMangaName(mangaID: String): Manga? { 65 | val client = OkHttpClient() 66 | val request = Request.Builder() 67 | .url("https://api.mangadex.org/manga/$mangaID") 68 | .build() 69 | 70 | client.newCall(request) 71 | .execute().use { response -> 72 | if(!response.isSuccessful) { 73 | messageDialog.showMessageNotification("Can't GET response body. Please check your Manga ID and try again") 74 | return null 75 | } 76 | 77 | val mapper = jacksonObjectMapper() 78 | val jsonData = response.body?.string() ?: return null 79 | 80 | val data = mapper.readTree(jsonData).get("data") 81 | return mapper.treeToValue(data, Manga::class.java) 82 | } 83 | } 84 | 85 | private fun fetchChapterName(mangaID: String): List? { 86 | val client = OkHttpClient() 87 | val request = Request.Builder() 88 | .url("https://api.mangadex.org/manga/$mangaID/feed") 89 | .build() 90 | 91 | client.newCall(request).execute() 92 | .use { response -> 93 | if(!response.isSuccessful) { 94 | messageDialog.showMessageNotification("Can't get manga name. Please try again") 95 | return null 96 | } 97 | 98 | val mapper = jacksonObjectMapper() 99 | val jsonData = response.body?.string() ?: return null 100 | 101 | val chapterData = mapper.readTree(jsonData) 102 | .get("data") 103 | 104 | return mapper.treeToValue(chapterData, Array::class.java)?.toList() 105 | } 106 | } 107 | 108 | private fun fetchChapterID(mangaID: String): List? { 109 | val client = OkHttpClient() 110 | val request = Request.Builder() 111 | .url("https://api.mangadex.org/manga/$mangaID/feed") 112 | .build() 113 | 114 | client.newCall(request) 115 | .execute().use { response -> 116 | if(!response.isSuccessful) { 117 | messageDialog.showMessageNotification("Can't fetch chapter ID. Please try again") 118 | return null 119 | } 120 | 121 | val mapper = jacksonObjectMapper() 122 | val jsonData = response.body?.string() ?: return null 123 | 124 | val chapterData = mapper.readTree(jsonData) 125 | .get("data") 126 | 127 | return mapper.treeToValue(chapterData, Array::class.java)?.toList() 128 | } 129 | } 130 | 131 | private fun fetchImageData(chapterID: String): ImageProperty? { 132 | val client = OkHttpClient() 133 | val request = Request.Builder() 134 | .url(chapterID) 135 | .build() 136 | 137 | client.newCall(request).execute().use { response -> 138 | if (!response.isSuccessful) { 139 | messageDialog.showMessageNotification("Can't fetch image data. Please try again") 140 | return null 141 | } 142 | 143 | val mapper = jacksonObjectMapper() 144 | val jsonData = response.body?.string() ?: return null 145 | 146 | return mapper.readValue(jsonData) 147 | } 148 | } 149 | 150 | private fun download(imageURL: String, saveDir: String, imageName: String) { 151 | val client = OkHttpClient() 152 | val request = Request.Builder() 153 | .url(imageURL) 154 | .build() 155 | val savePath = File("$saveDir/$imageName") 156 | 157 | client.newCall(request).execute() 158 | .use { response -> 159 | if(!response.isSuccessful) return 160 | FileOutputStream(savePath).use { output -> 161 | response.body?.bytes()?.let { output.write(it) } 162 | } 163 | } 164 | } 165 | 166 | private fun getBaseName(urlTarget: String): String { 167 | return URI(urlTarget).path.substringAfterLast('/') 168 | } 169 | 170 | private fun downloadProcess(hashValue: String?, imgURL: String, saveDir: String) { 171 | val cleanImgNames = imgURL.replace("[", "").replace("]", "") 172 | 173 | cleanImgNames.split(", ").forEach { img -> 174 | val imageURL = "https://cmdxd98sb0x3yprd.mangadex.network/data/$hashValue/$img" 175 | val baseName = getBaseName(imageURL) 176 | 177 | download( 178 | imageURL, 179 | saveDir, baseName 180 | ) 181 | SwingUtilities.invokeLater{ logArea.append("Download $baseName\n") } 182 | } 183 | SwingUtilities.invokeLater { logArea.append("Successfully all chapters as $saveDir\n") } 184 | } 185 | 186 | fun startDownloadProcess(mangaID: String, downloadDir: String) { 187 | object : SwingWorker() { 188 | override fun doInBackground() { 189 | val mangaName = fetchMangaName(mangaID) 190 | val chapterIDs = fetchChapterID(mangaID)?. 191 | map { "https://api.mangadex.org/at-home/server/${it.id}" } 192 | 193 | val chapterNames = fetchChapterName(mangaID) 194 | ?.map { it.attributes.title } 195 | 196 | val saveDir = File(downloadDir) 197 | mangaName?.let { 198 | SwingUtilities.invokeLater { logArea.append("Found manga: ${it.attributes.title["en"]}\n") } 199 | 200 | saveDir.mkdirs() 201 | } ?: { messageDialog.showMessageNotification("Can't fetch MangaID $mangaID") } 202 | 203 | chapterNames?.forEachIndexed { index, chapterName -> 204 | val chapterDir = File(saveDir, chapterName) 205 | chapterDir.mkdirs() 206 | 207 | val chapterID = chapterIDs?.get(index) ?: return@forEachIndexed 208 | val imageData = fetchImageData(chapterID) 209 | val imageURL = imageData?.chapter?.data 210 | 211 | downloadProcess( 212 | imageData?.chapter?.hash, 213 | imageURL.toString(), 214 | chapterDir.absolutePath 215 | ) 216 | } 217 | } 218 | }.execute() 219 | } 220 | 221 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/ChoosePath.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: ChoosePath.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI 9 | 10 | import railgunDownloaderV4.components.ulti.ClearEvents 11 | import java.awt.Image 12 | import java.awt.Toolkit 13 | import javax.swing.ImageIcon 14 | import javax.swing.JButton 15 | import javax.swing.JFileChooser 16 | import javax.swing.JFrame 17 | import javax.swing.filechooser.FileSystemView 18 | 19 | class ChoosePath (private val nhentaiUI: NhentaiUI) { 20 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 21 | 22 | fun setChoosePath(app: JFrame, choosePathButton: JButton) { 23 | choosePathButton.setSize(50, 50) 24 | choosePathButton.isContentAreaFilled = false 25 | choosePathButton.setLocation(100, 450) 26 | choosePathButton.border = null 27 | 28 | val buttonIcon = Toolkit.getDefaultToolkit() 29 | .getImage(this::class.java.getResource("/FolderPath.png")) 30 | 31 | choosePathButton.icon = ImageIcon( 32 | buttonIcon.getScaledInstance(50, 50, Image.SCALE_FAST) 33 | ) 34 | 35 | openSaveDir(choosePathButton) 36 | app.add(choosePathButton) 37 | } 38 | 39 | private fun openSaveDir(choosePathButton: JButton) { 40 | 41 | clearEvents.clearActionListeners(choosePathButton) 42 | 43 | choosePathButton.addActionListener { _ -> 44 | val chooser = JFileChooser(FileSystemView.getFileSystemView()) 45 | chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY 46 | chooser.dialogTitle = "Save doujinshi" 47 | 48 | chooser.takeIf { it.showOpenDialog(null) == JFileChooser.APPROVE_OPTION }?.selectedFile?.let { 49 | nhentaiUI.pathField.text = it.absolutePath 50 | } 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/DownloadButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DownloadButton.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI 9 | 10 | import railgunDownloaderV4.components.nhentaiUI.helper.NhentaiDownloadHelper 11 | import railgunDownloaderV4.components.ulti.ClearEvents 12 | import railgunDownloaderV4.components.ulti.DirExists 13 | import railgunDownloaderV4.components.ulti.MatchURL 14 | import railgunDownloaderV4.components.ulti.MessageDialog 15 | import java.awt.Image 16 | import java.awt.Toolkit 17 | import javax.swing.ImageIcon 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JTextArea 21 | import javax.swing.JTextField 22 | import javax.swing.SwingUtilities 23 | 24 | class DownloadButton( 25 | private val urlField: JTextField, 26 | private val savePathField: JTextField, 27 | private val logResultArea: JTextArea 28 | ) { 29 | private val matchURL: MatchURL by lazy { MatchURL() } 30 | private val dirExists: DirExists by lazy { DirExists() } 31 | private val downloadHelper: NhentaiDownloadHelper by lazy { NhentaiDownloadHelper(urlField, savePathField, logResultArea) } 32 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 33 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 34 | 35 | fun setDownloadButton(app: JFrame, downloadButton: JButton) { 36 | downloadButton.setSize(50, 50) 37 | downloadButton.isBorderPainted = false 38 | downloadButton.isFocusPainted = false 39 | 40 | val buttonIcon = Toolkit.getDefaultToolkit() 41 | .getImage(this::class.java.getResource("/Download.png")) 42 | 43 | downloadButton.icon = ImageIcon( 44 | buttonIcon.getScaledInstance(50, 50, Image.SCALE_FAST) 45 | ) 46 | downloadButton.isContentAreaFilled = false 47 | downloadButton.setLocation(170, 450) 48 | downloadButton.toolTipText = "Download doujinshi" 49 | 50 | downloadAction(downloadButton) 51 | 52 | app.add(downloadButton) 53 | } 54 | 55 | private fun downloadAction(downloadButton: JButton) { 56 | 57 | clearEvents.clearActionListeners(downloadButton) 58 | 59 | downloadButton.addActionListener { 60 | val inputURL = urlField.text 61 | val savePathDir = savePathField.text 62 | 63 | matchURL.takeIf { !it.matchURL(inputURL) }?.let { 64 | messageDialog.showMessageNotification("Please input valid URL") 65 | return@addActionListener 66 | } 67 | 68 | dirExists.takeIf { !it.checkDirExists(savePathDir) }?.let { 69 | messageDialog.showMessageNotification("Please choose exists save directory path") 70 | return@addActionListener 71 | } 72 | 73 | SwingUtilities.invokeLater { downloadHelper.executeDownload("BY_URL") } 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/FindByCode.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: FindByCode.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI 9 | 10 | import railgunDownloaderV4.components.nhentaiUI.helper.NhentaiDownloadHelper 11 | import railgunDownloaderV4.components.ulti.* 12 | import javax.swing.JButton 13 | import javax.swing.JFrame 14 | import javax.swing.JTextArea 15 | import javax.swing.JTextField 16 | 17 | class FindByCode ( 18 | private val urlInput: JTextField, 19 | private val pathInput: JTextField, 20 | private val logArea: JTextArea 21 | ){ 22 | private val matchNumber: MatchNumber by lazy { MatchNumber() } 23 | private val dirExists: DirExists by lazy { DirExists() } 24 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 25 | private val setIconButton: SetIconButton by lazy { SetIconButton() } 26 | private val nhentaiDownloadHelper: NhentaiDownloadHelper by lazy { NhentaiDownloadHelper(urlInput, pathInput, logArea) } 27 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 28 | 29 | fun setFindByCode(app: JFrame, findByCodeButton: JButton) { 30 | findByCodeButton.setSize(50, 50) 31 | findByCodeButton.setLocation(235, 450) 32 | findByCodeButton.isContentAreaFilled = false 33 | findByCodeButton.border = null 34 | findByCodeButton.isBorderPainted = false 35 | findByCodeButton.isFocusPainted = false 36 | 37 | setIconButton.setIcon( 38 | findByCodeButton, 39 | "/Search.png", 40 | 50, 41 | 50 42 | ) 43 | findByCodeButton.toolTipText = "Download doujinshi by code" 44 | 45 | downloadProcess(findByCodeButton) 46 | app.add(findByCodeButton) 47 | } 48 | 49 | private fun downloadProcess(findByCodeButton: JButton) { 50 | 51 | clearEvents.clearActionListeners(findByCodeButton) 52 | 53 | findByCodeButton.addActionListener { 54 | val doujinshiCode = urlInput.text 55 | val pathField = pathInput.text 56 | 57 | if(!matchNumber.matchNumber(doujinshiCode)) { 58 | messageDialog.showMessageNotification( 59 | "Please input valid code" 60 | ) 61 | return@addActionListener 62 | } 63 | 64 | if(!dirExists.checkDirExists(pathField)) { 65 | messageDialog.showMessageNotification( 66 | "Please choose your path or make sure this directory path is exists" 67 | ) 68 | return@addActionListener 69 | } 70 | 71 | nhentaiDownloadHelper.executeDownload("BY_CODE") 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/LogResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LogResult.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI 9 | 10 | import java.awt.Color 11 | import java.awt.Font 12 | import javax.swing.JFrame 13 | import javax.swing.JScrollPane 14 | import javax.swing.JTextArea 15 | 16 | class LogResult { 17 | fun setLogResult(app: JFrame, logArea: JTextArea) { 18 | logArea.background = Color(69, 69, 69) 19 | logArea.foreground = Color.WHITE 20 | logArea.isEditable = false 21 | logArea.font = Font("Consolas", Font.PLAIN, 12) 22 | logArea.toolTipText = "Your download result will be displayed here" 23 | 24 | val logScrollPane = JScrollPane(logArea) 25 | logScrollPane.setSize(400, 250) 26 | logScrollPane.verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED 27 | logScrollPane.horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED 28 | logScrollPane.border = null 29 | logScrollPane.setLocation(100, 40) 30 | 31 | app.add(logScrollPane) 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/NhentaiUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * NhentaiUI.kt 4 | */ 5 | package railgunDownloaderV4.components.nhentaiUI 6 | 7 | import railgunDownloaderV4.Application 8 | import railgunDownloaderV4.components.ulti.SetIcon 9 | import java.awt.Color 10 | import java.awt.Dimension 11 | import java.awt.event.WindowAdapter 12 | import java.awt.event.WindowEvent 13 | import javax.swing.JButton 14 | import javax.swing.JFrame 15 | import javax.swing.JTextArea 16 | import javax.swing.JTextField 17 | import javax.swing.SwingUtilities 18 | import javax.swing.WindowConstants 19 | 20 | class NhentaiUI (private val appScene: Application){ 21 | private val setIconComponent: SetIcon by lazy { SetIcon() } 22 | private val urlFieldComponent: URLField by lazy { URLField() } 23 | private val pathFieldComponent: PathField by lazy { PathField() } 24 | private val choosePathComponent: ChoosePath by lazy { ChoosePath(this) } 25 | private val downloadButtonComponent: DownloadButton by lazy { DownloadButton(urlField, pathField, logArea) } 26 | private val logResultComponent: LogResult by lazy { LogResult() } 27 | private val findByCodeComponent: FindByCode by lazy { FindByCode(urlField, pathField, logArea) } 28 | 29 | private val urlField: JTextField by lazy { JTextField() } 30 | val pathField: JTextField by lazy { JTextField() } 31 | private val logArea: JTextArea by lazy { JTextArea() } 32 | private val choosePathButton: JButton by lazy { JButton() } 33 | private val downloadButton: JButton by lazy { JButton() } 34 | private val findByCodeButton: JButton by lazy { JButton() } 35 | 36 | fun showNhentaiUI(visible: Boolean = false) { 37 | val nhentaiUI = JFrame() 38 | SwingUtilities.invokeLater { 39 | nhentaiUI.title = "Download from Nhentai.net" 40 | nhentaiUI.setSize(600, 600) 41 | nhentaiUI.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 42 | nhentaiUI.setLocationRelativeTo(null) 43 | nhentaiUI.isResizable = false 44 | nhentaiUI.maximumSize = Dimension(600, 600) 45 | nhentaiUI.contentPane.background = Color(21, 21, 21) 46 | nhentaiUI.iconImage = setIconComponent.setAppIcon() 47 | nhentaiUI.layout = null 48 | nhentaiUI.isVisible = visible 49 | 50 | 51 | findByCodeComponent.setFindByCode(nhentaiUI, findByCodeButton) 52 | urlFieldComponent.setURLField(nhentaiUI, urlField) 53 | pathFieldComponent.setPathField(nhentaiUI, pathField) 54 | choosePathComponent.setChoosePath(nhentaiUI, choosePathButton) 55 | downloadButtonComponent.setDownloadButton(nhentaiUI, downloadButton) 56 | logResultComponent.setLogResult(nhentaiUI, logArea) 57 | } 58 | closingWindow(nhentaiUI = nhentaiUI) 59 | } 60 | 61 | private fun closingWindow(nhentaiUI: JFrame) { 62 | nhentaiUI.addWindowListener(object: WindowAdapter() { 63 | override fun windowClosing(e: WindowEvent?) { 64 | appScene.app.isVisible = true 65 | } 66 | }) 67 | } 68 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/PathField.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * PathField.kt 4 | */ 5 | package railgunDownloaderV4.components.nhentaiUI 6 | 7 | import java.awt.Color 8 | import java.awt.Font 9 | import javax.swing.JFrame 10 | import javax.swing.JTextField 11 | 12 | class PathField { 13 | fun setPathField(app: JFrame, pathField: JTextField) { 14 | pathField.setSize(400, 30) 15 | pathField.border = null 16 | pathField.background = Color(69, 69, 69) 17 | pathField.foreground = Color.WHITE 18 | pathField.setLocation(100, 350) 19 | pathField.font = Font("Consolas", Font.PLAIN, 12) 20 | pathField.isEditable = false 21 | pathField.toolTipText = "Your chosen path is displayed here" 22 | 23 | app.add(pathField) 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/URLField.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: URLField.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI 9 | 10 | import java.awt.Font 11 | import javax.swing.JFrame 12 | import javax.swing.JTextField 13 | import java.awt.Color 14 | import java.awt.Point 15 | 16 | class URLField { 17 | fun setURLField(app: JFrame, urlField: JTextField) { 18 | urlField.setSize(400, 30) 19 | urlField.border = null 20 | urlField.font = Font("Consolas", Font.PLAIN, 12) 21 | urlField.background = Color(69, 69, 69) 22 | urlField.foreground = Color.WHITE 23 | urlField.location = Point(100, 400) 24 | urlField.toolTipText = "Input your doujinshi URL or code" 25 | 26 | app.add(urlField) 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/nhentaiUI/helper/NhentaiDownloadHelper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: NhentaiDownloadHelper.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.nhentaiUI.helper 9 | 10 | import okhttp3.OkHttpClient 11 | import okhttp3.Request 12 | import org.jsoup.Connection.Response 13 | import org.jsoup.HttpStatusException 14 | import org.jsoup.Jsoup 15 | import railgunDownloaderV4.components.ulti.MatchNumber 16 | import railgunDownloaderV4.components.ulti.MessageDialog 17 | import java.io.File 18 | import java.io.FileOutputStream 19 | import java.net.URI 20 | import java.net.http.HttpConnectTimeoutException 21 | import javax.swing.JTextArea 22 | import javax.swing.JTextField 23 | import javax.swing.SwingUtilities 24 | import javax.swing.SwingWorker 25 | 26 | class NhentaiDownloadHelper( 27 | private val targetURL: JTextField, private val saveDir: JTextField, private val resultLog: JTextArea 28 | ) { 29 | 30 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 31 | private val matchNumber: MatchNumber by lazy { MatchNumber() } 32 | 33 | private fun downloadImages(targetUrl: String, saveDir: String, doujinshiDir: String, imageName: String) { 34 | val client = OkHttpClient() 35 | val request = Request.Builder() 36 | .url(targetUrl) 37 | .build() 38 | val filePath = File("$saveDir/$doujinshiDir", imageName) 39 | 40 | client.newCall(request) 41 | .execute().use { response -> 42 | response.takeIf { !it.isSuccessful }?.let { 43 | SwingUtilities.invokeLater { resultLog.append("HTTP request failed. Please check your internet connection and try again\n") } 44 | return 45 | } 46 | 47 | FileOutputStream(filePath).use { output -> 48 | response.body?.bytes()?.let { output.write(it) } 49 | SwingUtilities.invokeLater { resultLog.append("Download $imageName\n") } 50 | } 51 | } 52 | } 53 | 54 | private fun getBaseName(urlTarget: String): String { 55 | return URI(urlTarget).path.substringAfterLast('/') 56 | } 57 | 58 | private fun downloadByDoujinshiURL() { 59 | val webDocument = Jsoup.connect(targetURL.text).get() 60 | val doujinshiCode = webDocument.select("h3#gallery_id") 61 | val imgTags = webDocument.select("div.thumbs img.lazyload") 62 | 63 | val doujinshi = doujinshiCode.text().replace("#", "") 64 | val saveDoujinshiDir = File("${saveDir.text}/$doujinshi") 65 | 66 | matchNumber.takeIf { !it.matchNumber(doujinshi) }?.let { 67 | messageDialog.showMessageNotification("Doujinshi with URL: ${targetURL.text} not found") 68 | return 69 | } 70 | 71 | saveDoujinshiDir.takeIf { !it.exists() }?.apply { 72 | mkdirs() 73 | } ?: run { messageDialog.showMessageNotification("Doujinshi $doujinshi is exists in your PC"); return } 74 | 75 | SwingUtilities.invokeLater { resultLog.append("Send HTTP request to $targetURL, please wait\n") } 76 | imgTags.forEach { image -> 77 | downloadImages( 78 | targetURL.text, saveDir.text, doujinshi, 79 | getBaseName(image.attr("data-src")) 80 | ) 81 | } 82 | messageDialog.showMessageNotification("Successfully download doujinshi $doujinshiCode") 83 | } 84 | 85 | private fun downloadByCode() { 86 | SwingUtilities.invokeLater { resultLog.append("Searching doujinshi code: ${targetURL.text}\n") } 87 | val webResponse: Response? 88 | val doujinshiCodeTarget = "https://nhentai.net/g/${targetURL.text}" 89 | try { 90 | webResponse = Jsoup.connect(doujinshiCodeTarget).execute() 91 | }catch (exception: HttpStatusException) { 92 | messageDialog.showMessageNotification("Doujinshi ${targetURL.text} not found") 93 | return 94 | } catch (exception: HttpConnectTimeoutException) { 95 | messageDialog.showMessageNotification("Connection timeout. Please check your internet connection and try again") 96 | return 97 | } 98 | val webDocument = webResponse.parse() 99 | val doujinshiCode = webDocument.select("h3#gallery_id") 100 | val imgTags = webDocument.select("div.thumbs img.lazyload") 101 | val doujinshi = doujinshiCode.text().replace("#", "") 102 | 103 | val saveDoujinshiDir = File("${saveDir.text}/$doujinshi") 104 | saveDoujinshiDir.takeIf { !it.exists() }?.apply { 105 | mkdirs() 106 | } ?: run { messageDialog.showMessageNotification("Doujinshi $doujinshi is exists in your PC"); return } 107 | 108 | SwingUtilities.invokeLater { resultLog.append("Find doujinshi code $doujinshi, please wait\n") } 109 | imgTags.forEach{image -> 110 | downloadImages( 111 | doujinshiCodeTarget, saveDir.text, doujinshi, 112 | getBaseName(image.attr("data-src")) 113 | ) 114 | } 115 | } 116 | 117 | fun executeDownload(choice: String) { 118 | object : SwingWorker() { 119 | override fun doInBackground() { 120 | when(choice) { 121 | "BY_URL" -> downloadByDoujinshiURL() 122 | "BY_CODE" -> downloadByCode() 123 | } 124 | } 125 | }.execute() 126 | } 127 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/tiktokUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.tiktokUI 9 | 10 | import railgunDownloaderV4.components.global.ButtonUI 11 | import railgunDownloaderV4.components.global.LogResult 12 | import railgunDownloaderV4.components.global.QualityBox 13 | import railgunDownloaderV4.components.global.TextField 14 | import railgunDownloaderV4.components.tiktokUI.events.Download 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import java.awt.Dimension 17 | import java.awt.Point 18 | import javax.swing.JButton 19 | import javax.swing.JFrame 20 | import javax.swing.JList 21 | import javax.swing.JTextArea 22 | import javax.swing.JTextField 23 | 24 | class LoadComponents { 25 | 26 | private val textField: TextField by lazy { TextField() } 27 | private val logResult: LogResult by lazy { LogResult() } 28 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 29 | private val pathDialog: PathDialog by lazy { PathDialog() } 30 | private val download: Download by lazy { Download(urlField, pathField, logArea, qualityList) } 31 | private val qualityBox: QualityBox by lazy { QualityBox() } 32 | 33 | private val urlField: JTextField by lazy { JTextField() } 34 | private val pathField: JTextField by lazy { JTextField() } 35 | private val logArea: JTextArea by lazy { JTextArea() } 36 | private val qualityList: JList by lazy { JList() } 37 | private val downloadButton: JButton by lazy { JButton() } 38 | private val saveDirButton: JButton by lazy { JButton() } 39 | 40 | fun setLoadComponents(appTarget: JFrame) { 41 | textField.setTextField( 42 | appTarget, urlField, Dimension(400, 30), 43 | Point(100, 450), true, 44 | "Input your Tiktok URL here" 45 | ) 46 | textField.setTextField( 47 | appTarget, pathField, Dimension(400, 30), 48 | Point(100, 380), false, 49 | "Your chosen save directory path will be displayed here" 50 | ) 51 | 52 | logResult.setLogResult( 53 | appTarget, logArea, Dimension(400, 300), 54 | Point(100, 30), "Your download result will be displayed here" 55 | ) 56 | 57 | buttonUI.setButtonUI( 58 | appTarget, downloadButton, 59 | Dimension(50, 50), Point(100, 485), 60 | "/Download.png", "Download video from Tiktok" 61 | ) 62 | download.setDownload(downloadButton) 63 | 64 | buttonUI.setButtonUI( 65 | appTarget, saveDirButton, 66 | Dimension(50, 50), Point(170, 485), 67 | "/FolderPath.png", "Choose your save directory path" 68 | ) 69 | pathDialog.setShowDialog( 70 | saveDirButton, "Choose your save directory path", 71 | pathField 72 | ) 73 | 74 | qualityBox.setQualityBox( 75 | appTarget, qualityList, 76 | Point(20, 380), 77 | Dimension(70, 150) 78 | ) 79 | } 80 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/tiktokUI/TiktokUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: TiktokUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.tiktokUI 10 | 11 | import railgunDownloaderV4.Application 12 | import railgunDownloaderV4.components.global.events.GoHome 13 | import railgunDownloaderV4.components.ulti.SetIcon 14 | import java.awt.Color 15 | import javax.swing.JFrame 16 | import java.awt.Dimension 17 | import javax.swing.WindowConstants 18 | 19 | class TiktokUI (appScene: Application){ 20 | 21 | private val goHome: GoHome by lazy { GoHome(appScene) } 22 | private val setIcon: SetIcon by lazy { SetIcon() } 23 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 24 | 25 | fun setTiktokUI(visible: Boolean) { 26 | val app = JFrame("Download video from Tiktok") 27 | app.size = Dimension(600, 600) 28 | app.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 29 | app.isResizable = false 30 | app.maximumSize = Dimension(600, 600) 31 | app.contentPane.background = Color(21, 21, 21) 32 | app.layout = null 33 | app.setLocationRelativeTo(null) 34 | app.iconImage = setIcon.setAppIcon() 35 | app.isVisible = visible 36 | 37 | loadComponents.setLoadComponents(app) 38 | goHome.setGoHome(app) 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/tiktokUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.tiktokUI.events 10 | 11 | import railgunDownloaderV4.components.global.events.DownloadVideoProcess 12 | import railgunDownloaderV4.components.ulti.DirExists 13 | import railgunDownloaderV4.components.ulti.MatchURL 14 | import railgunDownloaderV4.components.ulti.MessageDialog 15 | import javax.swing.JButton 16 | import javax.swing.JList 17 | import javax.swing.JTextArea 18 | import javax.swing.JTextField 19 | 20 | class Download( 21 | private val urlField: JTextField, 22 | private val pathField: JTextField, 23 | private val logArea: JTextArea, 24 | private val qualityList: JList 25 | ) { 26 | 27 | private val matchURL: MatchURL by lazy { MatchURL() } 28 | private val dirExists: DirExists by lazy { DirExists() } 29 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 30 | private val downloadVideoProcess: DownloadVideoProcess by lazy { DownloadVideoProcess() } 31 | 32 | fun setDownload(buttonTarget: JButton) { 33 | buttonTarget.addActionListener { 34 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 35 | messageDialog.showMessageNotification("Please input valid TikTok video URL") 36 | return@addActionListener 37 | } 38 | 39 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 40 | messageDialog.showMessageNotification("Please choose valid save directory path") 41 | return@addActionListener 42 | } 43 | 44 | val quality = qualityList.selectedValue 45 | when(quality) { 46 | "Best Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "best") 47 | "Worst Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worst") 48 | "Best Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestvideo") 49 | "Worst Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstvideo") 50 | "Best Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestaudio") 51 | "Worst Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstaudio") 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/CheckOS.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: CheckOS.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import java.util.* 11 | 12 | class CheckOS { 13 | fun sysType(): String { 14 | val osProperty = System.getProperty("os.name").lowercase(Locale.getDefault()) 15 | 16 | if (osProperty.contains("win")) { 17 | return "Windows" 18 | } else if (osProperty.contains("nix") || osProperty.contains("nux") || osProperty.contains("aix")) { 19 | return "Linux" 20 | } 21 | 22 | return "UnknownOS" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/ClearEvents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: ClearEvents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import javax.swing.JButton 11 | 12 | class ClearEvents { 13 | fun clearActionListeners(buttonTarget: JButton) { 14 | buttonTarget.actionListeners.forEach(buttonTarget::removeActionListener) 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/DirExists.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: DirExists.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import java.io.File 11 | 12 | class DirExists { 13 | fun checkDirExists(dirPath: String): Boolean { 14 | val saveDir = File(dirPath) 15 | 16 | return saveDir.exists() && saveDir.isDirectory 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/MatchNumber.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MatchNumber.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | class MatchNumber { 11 | fun matchNumber(number: String): Boolean { 12 | val numberRegex = Regex("^[0-9]+$") 13 | return numberRegex.matches(number) 14 | } 15 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/MatchURL.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MatchURL.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.ulti 10 | 11 | class MatchURL { 12 | fun matchURL(url: String): Boolean{ 13 | val urlRegex: Regex = """^(https?://)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(/\S*)?$""".toRegex() 14 | 15 | return urlRegex.matches(url.trim().lowercase()) 16 | } 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/MessageDialog.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: MessageDialog.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import javax.swing.JOptionPane 11 | 12 | class MessageDialog { 13 | fun showMessageNotification(message: String) { 14 | JOptionPane.showMessageDialog( 15 | null, 16 | message, 17 | "Notification", 18 | JOptionPane.INFORMATION_MESSAGE 19 | ) 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/PathDialog.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: PathDialog.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import javax.swing.JButton 11 | import javax.swing.JFileChooser 12 | import javax.swing.JTextField 13 | import javax.swing.filechooser.FileSystemView 14 | 15 | class PathDialog { 16 | 17 | private val clearEvents: ClearEvents by lazy { ClearEvents() } 18 | 19 | fun setShowDialog(openPathButton: JButton, dialogTitle: String, pathField: JTextField){ 20 | 21 | clearEvents.clearActionListeners(openPathButton) 22 | 23 | openPathButton.addActionListener { 24 | val chooser = JFileChooser(FileSystemView.getFileSystemView()) 25 | chooser.dialogTitle = dialogTitle 26 | chooser.fileSelectionMode = JFileChooser.DIRECTORIES_ONLY 27 | 28 | chooser.takeIf {it.showOpenDialog(null) == JFileChooser.APPROVE_OPTION}?.selectedFile?.let { 29 | pathField.text = it.absolutePath 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/ProcessCancel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: ProcessCancel.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | class ProcessCancel { 11 | private var checkOS: CheckOS = CheckOS() 12 | 13 | private fun killProcess(vararg command: String) { 14 | ProcessBuilder(*command).start() 15 | } 16 | 17 | fun taskKill(taskName: String) { 18 | val osProperty = checkOS.sysType() 19 | 20 | when(osProperty) { 21 | "Windows" -> println("windows") 22 | "Linux" -> killProcess("pkill", "-n", taskName) 23 | else -> println("Unknown os") 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/SetIcon.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: SetIcon.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import java.awt.Image 11 | import java.awt.Toolkit 12 | import java.util.* 13 | 14 | class SetIcon { 15 | fun setAppIcon(): Image { 16 | return Objects.requireNonNull( 17 | Toolkit.getDefaultToolkit() 18 | .getImage(javaClass.getResource("/AppIcon.jpg")) 19 | ) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/ulti/SetIconButton.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: SetIconButton.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.ulti 9 | 10 | import java.awt.Image 11 | import java.awt.Toolkit 12 | import javax.swing.ImageIcon 13 | import javax.swing.JButton 14 | 15 | class SetIconButton { 16 | fun setIcon(button: JButton, iconPath: String, width: Int, height: Int) { 17 | val buttonIcon = Toolkit.getDefaultToolkit() 18 | .getImage(this::class.java.getResource(iconPath)) 19 | 20 | button.icon = ImageIcon( 21 | buttonIcon.getScaledInstance(width, height, Image.SCALE_FAST) 22 | ) 23 | } 24 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/youtubeUI/LoadComponents.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: LoadComponents.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.youtubeUI 10 | 11 | import railgunDownloaderV4.components.global.ButtonUI 12 | import railgunDownloaderV4.components.global.LogResult 13 | import railgunDownloaderV4.components.global.QualityBox 14 | import railgunDownloaderV4.components.global.TextField 15 | import railgunDownloaderV4.components.ulti.PathDialog 16 | import railgunDownloaderV4.components.youtubeUI.events.Download 17 | import java.awt.Dimension 18 | import java.awt.Point 19 | import javax.swing.JButton 20 | import javax.swing.JFrame 21 | import javax.swing.JList 22 | import javax.swing.JTextArea 23 | import javax.swing.JTextField 24 | 25 | class LoadComponents { 26 | private val textField: TextField by lazy { TextField() } 27 | private val buttonUI: ButtonUI by lazy { ButtonUI() } 28 | private val logResult: LogResult by lazy { LogResult() } 29 | private val qualityBox: QualityBox by lazy { QualityBox() } 30 | private val pathDialog: PathDialog by lazy { PathDialog() } 31 | private val download: Download by lazy { Download(urlField, pathField, logArea, qualityList) } 32 | 33 | private val urlField: JTextField by lazy { JTextField() } 34 | private val pathField: JTextField by lazy { JTextField() } 35 | private val logArea: JTextArea by lazy { JTextArea() } 36 | private val downloadButton: JButton by lazy { JButton() } 37 | private val saveDirButton: JButton by lazy { JButton() } 38 | private val qualityList: JList by lazy { JList() } 39 | 40 | fun setLoadComponents(appTarget: JFrame) { 41 | textField.setTextField( 42 | appTarget, urlField, 43 | Dimension(400, 30), Point(100, 370), 44 | true, "Input your YouTube video/playlist here" 45 | ) 46 | textField.setTextField( 47 | appTarget, pathField, 48 | Dimension(400, 30), Point(100, 300), 49 | false, "Your chosen directory will be displayed here" 50 | ) 51 | logResult.setLogResult( 52 | appTarget, logArea, 53 | Dimension(400, 200), Point(100, 30), 54 | "Your download result will be displayed here" 55 | ) 56 | 57 | qualityBox.setQualityBox( 58 | appTarget, qualityList, 59 | Point(400, 430), Dimension(100, 100) 60 | ) 61 | 62 | buttonUI.setButtonUI( 63 | appTarget, downloadButton, Dimension(50, 50), 64 | Point(175, 420), "/Download.png", "Download YouTube video/playlist" 65 | ) 66 | buttonUI.setButtonUI( 67 | appTarget, saveDirButton, 68 | Dimension(50, 50), Point(100, 420), 69 | "/FolderPath.png", "Choose save directory path" 70 | ) 71 | pathDialog.setShowDialog( 72 | saveDirButton, "Choose save directory", 73 | pathField 74 | ) 75 | 76 | download.setDownload(downloadButton) 77 | } 78 | } -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/youtubeUI/YoutubeUI.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: YoutubeUI.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | package railgunDownloaderV4.components.youtubeUI 9 | 10 | import railgunDownloaderV4.Application 11 | import railgunDownloaderV4.components.global.events.GoHome 12 | import railgunDownloaderV4.components.ulti.SetIcon 13 | import java.awt.Color 14 | import java.awt.Dimension 15 | import javax.swing.* 16 | 17 | class YoutubeUI(val appScene: Application) { 18 | private val setIcon: SetIcon by lazy { SetIcon() } 19 | private val goHome: GoHome by lazy { GoHome(this.appScene) } 20 | private val loadComponents: LoadComponents by lazy { LoadComponents() } 21 | 22 | val urlField: JTextField by lazy { JTextField() } 23 | val pathField: JTextField by lazy { JTextField() } 24 | 25 | fun showYoutubeUI(visible: Boolean) { 26 | val app = JFrame() 27 | app.title = "Download from Youtube" 28 | app.iconImage = setIcon.setAppIcon() 29 | app.size = Dimension(600, 650) 30 | app.defaultCloseOperation = WindowConstants.DISPOSE_ON_CLOSE 31 | app.setLocationRelativeTo(null) 32 | app.layout = null 33 | app.isResizable = false 34 | app.maximumSize = Dimension(600, 650) 35 | app.contentPane.background = Color(21, 21, 21) 36 | app.isVisible = visible 37 | 38 | loadComponents.setLoadComponents(app) 39 | goHome.setGoHome(app) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/kotlin/railgunDownloaderV4/components/youtubeUI/events/Download.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * RAILGUN DOWNLOADER - VERSION 4.0.0 3 | * File: Download.kt 4 | * This project is licensed GPL-3.0 License. 5 | * LICENSE: https://www.gnu.org/licenses/gpl-3.0.html 6 | * Contribution: Reim 7 | */ 8 | 9 | package railgunDownloaderV4.components.youtubeUI.events 10 | 11 | import railgunDownloaderV4.components.global.events.DownloadVideoProcess 12 | import railgunDownloaderV4.components.ulti.DirExists 13 | import railgunDownloaderV4.components.ulti.MatchURL 14 | import railgunDownloaderV4.components.ulti.MessageDialog 15 | import javax.swing.JButton 16 | import javax.swing.JList 17 | import javax.swing.JTextArea 18 | import javax.swing.JTextField 19 | 20 | class Download( 21 | private val urlField: JTextField, 22 | private val pathField: JTextField, 23 | private val logArea: JTextArea, 24 | private val qualityList: JList 25 | ) { 26 | 27 | private val matchURL: MatchURL by lazy { MatchURL() } 28 | private val dirExists: DirExists by lazy { DirExists() } 29 | private val messageDialog: MessageDialog by lazy { MessageDialog() } 30 | private val downloadVideoProcess: DownloadVideoProcess by lazy { DownloadVideoProcess() } 31 | 32 | fun setDownload(buttonTarget: JButton) { 33 | buttonTarget.addActionListener { 34 | matchURL.takeIf { !it.matchURL(urlField.text) }?.let { 35 | messageDialog.showMessageNotification("Please input valid TikTok video URL") 36 | return@addActionListener 37 | } 38 | 39 | dirExists.takeIf { !it.checkDirExists(pathField.text) }?.let { 40 | messageDialog.showMessageNotification("Please choose valid save directory path") 41 | return@addActionListener 42 | } 43 | 44 | val quality = qualityList.selectedValue 45 | when(quality) { 46 | "Best Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "best") 47 | "Worst Quality" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worst") 48 | "Best Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestvideo") 49 | "Worst Video" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstvideo") 50 | "Best Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "bestaudio") 51 | "Worst Audio" -> downloadVideoProcess.setDownloadVideoProcess(urlField.text, pathField.text, logArea, "worstaudio") 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/resources/AppIcon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/AppIcon.jpg -------------------------------------------------------------------------------- /src/main/resources/Bilibili.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Bilibili.png -------------------------------------------------------------------------------- /src/main/resources/Cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Cancel.png -------------------------------------------------------------------------------- /src/main/resources/DevianArt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/DevianArt.png -------------------------------------------------------------------------------- /src/main/resources/Download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Download.png -------------------------------------------------------------------------------- /src/main/resources/Facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Facebook.png -------------------------------------------------------------------------------- /src/main/resources/FolderPath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/FolderPath.png -------------------------------------------------------------------------------- /src/main/resources/Hitomi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Hitomi.png -------------------------------------------------------------------------------- /src/main/resources/Instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Instagram.png -------------------------------------------------------------------------------- /src/main/resources/MangaDex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/MangaDex.png -------------------------------------------------------------------------------- /src/main/resources/Nhentai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Nhentai.png -------------------------------------------------------------------------------- /src/main/resources/Search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Search.png -------------------------------------------------------------------------------- /src/main/resources/Tiktok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/Tiktok.png -------------------------------------------------------------------------------- /src/main/resources/YoutubeIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Reim-developer/RailgunDownloader/3786866eb6a3fd5cb7d000117afcaf9d662107e4/src/main/resources/YoutubeIcon.png --------------------------------------------------------------------------------