├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
├── screenshots
├── screenshot1.png
├── screenshot2.png
├── screenshot3.png
└── screenshot4.png
└── src
└── main
├── java
└── com
│ └── github
│ └── franckyi
│ └── cmpdl
│ ├── CMPDL.java
│ ├── api
│ ├── CMPDLConverterFactory.java
│ ├── IBean.java
│ ├── IEnum.java
│ ├── TwitchAppAPI.java
│ └── response
│ │ ├── Addon.java
│ │ ├── AddonFile.java
│ │ ├── Attachment.java
│ │ ├── Author.java
│ │ ├── Category.java
│ │ ├── CategorySection.java
│ │ └── ReleaseType.java
│ ├── controller
│ ├── CleanTask.java
│ ├── DestinationPaneController.java
│ ├── FilePaneController.java
│ ├── IContentController.java
│ ├── MainWindowController.java
│ ├── ModpackPaneController.java
│ └── ProgressPaneController.java
│ ├── core
│ ├── ContentControllerView.java
│ └── ControllerView.java
│ ├── model
│ └── ModpackManifest.java
│ ├── task
│ ├── TaskBase.java
│ ├── api
│ │ ├── CallTask.java
│ │ └── GetProjectIdTask.java
│ └── mpimport
│ │ ├── CopyOverridesTask.java
│ │ ├── DownloadFileTask.java
│ │ ├── DownloadModsTask.java
│ │ ├── ReadManifestTask.java
│ │ └── UnzipFileTask.java
│ └── view
│ └── AddonFileMinimalView.java
└── resources
└── fxml
├── DestinationPane.fxml
├── FilePane.fxml
├── MainWindow.fxml
├── ModpackPane.fxml
└── ProgressPane.fxml
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | insert_final_newline = true
7 | indent_style = space
8 | indent_size = 4
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Java template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.ear
19 | *.zip
20 | *.tar.gz
21 | *.rar
22 |
23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
24 | hs_err_pid*
25 |
26 | .idea/
27 | target/*
28 | *.iml
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Franckyi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CMPDL (Curse Modpack Downloader)
2 | ### A lightweight alternative to Twitch App for downloading Minecraft modpacks.
3 |
4 | ---
5 | ## [Downloads](https://github.com/Franckyi/CMPDL/releases)
6 | CMPDL is a Java application created by Franckyi, based on [Vazkii's project](https://github.com/Vazkii/CMPDL). It allows you to download your favorite modpacks from websites like [CurseForge](https://minecraft.curseforge.com/modpacks) or [Feed the Beast](https://www.feed-the-beast.com/modpacks). For users who don't like the Twitch App and still want to enjoy Minecraft modpacks, this app is made for you !
7 |
8 | This project is under the [MIT License](LICENSE).
9 |
10 | ### As this project is based on the JavaFX framework, Linux and MacOS system users must install OpenJFX or Oracle's JRE to start the application.
11 |
12 | What changed between Vazkii's version and my version ?
13 |
14 | - A revamped user interface
15 | - Support for [www.curseforge.com](http://www.curseforge.com) website
16 | - The user can choose the destination path
17 |
18 | ## How to use ?
19 |
20 | - Follow the steps from step 1 to step 3.
21 | - Press "Start" and wait until it finishes.
22 | - Forge won't be installed. The recommended Forge version to install will be shown in the log. You can also install a newer version, but if it breaks, go back to the recommended version.
23 |
24 | ## Screenshots
25 | 
26 | 
27 | 
28 | 
29 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.github.franckyi
8 | cmpdl
9 | 2.3.0
10 |
11 | 1.8
12 | 1.8
13 |
14 |
15 |
16 | org.json
17 | json
18 | 20180813
19 |
20 |
21 | com.squareup.retrofit2
22 | retrofit
23 | 2.6.0
24 |
25 |
26 | org.jsoup
27 | jsoup
28 | 1.12.1
29 |
30 |
31 |
32 |
33 |
34 | maven-assembly-plugin
35 |
36 |
37 |
38 | com.github.franckyi.cmpdl.CMPDL
39 |
40 |
41 |
42 | jar-with-dependencies
43 |
44 |
45 |
46 |
47 | make-assembly
48 | package
49 |
50 | single
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/screenshots/screenshot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skyecodes/CMPDL/d7e2adaa1c01648a63f1235ae52c1fd7f16f94ba/screenshots/screenshot1.png
--------------------------------------------------------------------------------
/screenshots/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skyecodes/CMPDL/d7e2adaa1c01648a63f1235ae52c1fd7f16f94ba/screenshots/screenshot2.png
--------------------------------------------------------------------------------
/screenshots/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skyecodes/CMPDL/d7e2adaa1c01648a63f1235ae52c1fd7f16f94ba/screenshots/screenshot3.png
--------------------------------------------------------------------------------
/screenshots/screenshot4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/skyecodes/CMPDL/d7e2adaa1c01648a63f1235ae52c1fd7f16f94ba/screenshots/screenshot4.png
--------------------------------------------------------------------------------
/src/main/java/com/github/franckyi/cmpdl/CMPDL.java:
--------------------------------------------------------------------------------
1 | package com.github.franckyi.cmpdl;
2 |
3 | import com.github.franckyi.cmpdl.api.CMPDLConverterFactory;
4 | import com.github.franckyi.cmpdl.api.TwitchAppAPI;
5 | import com.github.franckyi.cmpdl.controller.*;
6 | import com.github.franckyi.cmpdl.core.ContentControllerView;
7 | import com.github.franckyi.cmpdl.core.ControllerView;
8 | import javafx.application.Application;
9 | import javafx.application.Platform;
10 | import javafx.scene.Scene;
11 | import javafx.scene.control.Alert;
12 | import javafx.scene.control.ButtonType;
13 | import javafx.stage.Stage;
14 | import retrofit2.Retrofit;
15 |
16 | import java.awt.*;
17 | import java.io.IOException;
18 | import java.net.URI;
19 | import java.net.URISyntaxException;
20 | import java.util.concurrent.ExecutorService;
21 | import java.util.concurrent.Executors;
22 |
23 | public class CMPDL extends Application {
24 |
25 | public static final String NAME = "CMPDL";
26 | public static final String VERSION = "2.3.0";
27 | public static final String AUTHOR = "Franckyi";
28 | public static final String TITLE = String.format("%s v%s by %s", NAME, VERSION, AUTHOR);
29 |
30 | public static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool();
31 |
32 | public static Stage stage;
33 | public static TwitchAppAPI api;
34 |
35 | public static ControllerView mainWindow;
36 | public static ContentControllerView modpackPane;
37 | public static ContentControllerView filePane;
38 | public static ContentControllerView destinationPane;
39 | public static ContentControllerView progressPane;
40 |
41 | public static ContentControllerView> currentContent;
42 |
43 | public static void main(String[] args) {
44 | api = new Retrofit.Builder()
45 | .baseUrl("https://addons-ecs.forgesvc.net/api/v2/")
46 | .addConverterFactory(CMPDLConverterFactory.create())
47 | .build()
48 | .create(TwitchAppAPI.class);
49 | launch(args);
50 | }
51 |
52 | @Override
53 | public void start(Stage primaryStage) throws Exception {
54 | stage = primaryStage;
55 | modpackPane = new ContentControllerView<>("fxml/ModpackPane.fxml");
56 | filePane = new ContentControllerView<>("fxml/FilePane.fxml");
57 | destinationPane = new ContentControllerView<>("fxml/DestinationPane.fxml");
58 | progressPane = new ContentControllerView<>("fxml/ProgressPane.fxml");
59 | mainWindow = new ControllerView<>("fxml/MainWindow.fxml");
60 | stage.setScene(new Scene(mainWindow.getView()));
61 | stage.setTitle(TITLE);
62 | stage.setOnCloseRequest(e -> currentContent.getController().handleClose());
63 | stage.show();
64 | }
65 |
66 | @Override
67 | public void stop() {
68 | EXECUTOR_SERVICE.shutdown();
69 | }
70 |
71 | public static TwitchAppAPI getAPI() {
72 | return api;
73 | }
74 |
75 | public static void openBrowser(String url) {
76 | if (Desktop.isDesktopSupported()) {
77 | EXECUTOR_SERVICE.execute(() -> {
78 | try {
79 | Desktop.getDesktop().browse(new URI(url));
80 | } catch (IOException | URISyntaxException e) {
81 | Platform.runLater(() -> new Alert(Alert.AlertType.ERROR, "Can't open URL", ButtonType.OK).show());
82 | e.printStackTrace();
83 | }
84 | });
85 | } else {
86 | new Alert(Alert.AlertType.ERROR, "Desktop not supported", ButtonType.OK).show();
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/com/github/franckyi/cmpdl/api/CMPDLConverterFactory.java:
--------------------------------------------------------------------------------
1 | package com.github.franckyi.cmpdl.api;
2 |
3 | import okhttp3.MediaType;
4 | import okhttp3.RequestBody;
5 | import okhttp3.ResponseBody;
6 | import okio.BufferedSink;
7 | import org.json.JSONArray;
8 | import org.json.JSONObject;
9 | import retrofit2.Converter;
10 | import retrofit2.Retrofit;
11 |
12 | import java.io.IOException;
13 | import java.lang.annotation.Annotation;
14 | import java.lang.reflect.ParameterizedType;
15 | import java.lang.reflect.Type;
16 | import java.time.Instant;
17 | import java.util.ArrayList;
18 | import java.util.List;
19 |
20 | public class CMPDLConverterFactory extends Converter.Factory {
21 |
22 | private CMPDLConverterFactory() {
23 | }
24 |
25 | public static CMPDLConverterFactory create() {
26 | return new CMPDLConverterFactory();
27 | }
28 |
29 | @Override
30 | public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
31 | return value -> {
32 | try {
33 | if (type instanceof Class) {
34 | Class> clazz = (Class>) type;
35 | if (clazz == Instant.class) {
36 | return Instant.parse(value.string());
37 | } else if (IBean.class.isAssignableFrom(clazz)) {
38 | return ((IBean) clazz.newInstance()).fromJson(new JSONObject(value.string()));
39 | }
40 | } else if (type instanceof ParameterizedType) {
41 | ParameterizedType type0 = (ParameterizedType) type;
42 | if (List.class.isAssignableFrom((Class>) type0.getRawType())) {
43 | return toList(type0, new JSONArray(value.string()));
44 | }
45 | }
46 | } catch (Exception e) {
47 | e.printStackTrace();
48 | }
49 | return null;
50 | };
51 | }
52 |
53 | @Override
54 | public Converter, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
55 | return value -> {
56 | try {
57 | if (value instanceof List) {
58 | return new JSONBody(fromList(((ParameterizedType) type), (List) value));
59 | } else if (value instanceof IBean) {
60 | return new JSONBody(((IBean) value).toJson());
61 | }
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | return null;
66 | };
67 | }
68 |
69 | public static List toList(ParameterizedType type, JSONArray array) throws Exception {
70 | Class> type0 = (Class>) getParameterUpperBound(0, type);
71 | List