diff options
Diffstat (limited to 'src/main/java/zajc/gogarchiver/Arguments.java')
-rw-r--r-- | src/main/java/zajc/gogarchiver/Arguments.java | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/main/java/zajc/gogarchiver/Arguments.java b/src/main/java/zajc/gogarchiver/Arguments.java new file mode 100644 index 0000000..cd24ffa --- /dev/null +++ b/src/main/java/zajc/gogarchiver/Arguments.java | |||
@@ -0,0 +1,206 @@ | |||
1 | //SPDX-License-Identifier: GPL-3.0 | ||
2 | /* | ||
3 | * gogarchiver-ng, an archival tool for GOG.com | ||
4 | * Copyright (C) 2024 Marko Zajc | ||
5 | * | ||
6 | * This program is free software: you can redistribute it and/or modify it under the | ||
7 | * terms of the GNU General Public License as published by the Free Software | ||
8 | * Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY | ||
11 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
12 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with this | ||
15 | * program. If not, see <https://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | package zajc.gogarchiver; | ||
18 | |||
19 | import static java.lang.Runtime.getRuntime; | ||
20 | import static java.util.Collections.unmodifiableSet; | ||
21 | import static java.util.stream.Collectors.toUnmodifiableSet; | ||
22 | import static picocli.CommandLine.Help.Ansi.AUTO; | ||
23 | import static picocli.CommandLine.Help.Visibility.ALWAYS; | ||
24 | import static zajc.gogarchiver.api.GameDownload.Type.*; | ||
25 | |||
26 | import java.io.IOException; | ||
27 | import java.nio.file.*; | ||
28 | import java.util.*; | ||
29 | import java.util.function.Predicate; | ||
30 | |||
31 | import javax.annotation.Nonnull; | ||
32 | |||
33 | import org.eu.zajc.ef.supplier.except.all.AESupplier; | ||
34 | |||
35 | import picocli.CommandLine.*; | ||
36 | import picocli.CommandLine.Help.Ansi; | ||
37 | import zajc.gogarchiver.api.*; | ||
38 | import zajc.gogarchiver.api.GameDownload.Platform; | ||
39 | import zajc.gogarchiver.exception.NotLoggedInException; | ||
40 | import zajc.gogarchiver.util.LazyValue; | ||
41 | |||
42 | public class Arguments { | ||
43 | |||
44 | private final LazyValue<User> user = new LazyValue<>(); | ||
45 | |||
46 | @ArgGroup(exclusive = true, multiplicity = "1") private Token token; | ||
47 | |||
48 | private static class Token { | ||
49 | |||
50 | @Option(names = { "-k", "--token" }, description = "GOG token, which can be extracted from the gog-al cookie", | ||
51 | paramLabel = "TOKEN") private String tokenString; | ||
52 | @Option(names = { "-K", "--token-file" }, description = "read GOG token from a file", | ||
53 | paramLabel = "PATH") private Path tokenFile; | ||
54 | |||
55 | @Nonnull | ||
56 | @SuppressWarnings("null") | ||
57 | public String getTokenString() throws IOException { | ||
58 | var token = this.tokenString; | ||
59 | if (token == null) | ||
60 | token = Files.readString(this.tokenFile); | ||
61 | return token.strip(); | ||
62 | } | ||
63 | |||
64 | } | ||
65 | |||
66 | @Option(names = { "-o", "--output" }, required = true, description = "directory to write downloaded games to", | ||
67 | paramLabel = "PATH") private Path output; | ||
68 | @Option(names = { "-t", "--threads" }, description = "number of download threads", paramLabel = "THREADS", | ||
69 | showDefaultValue = ALWAYS) private int threads = getRuntime().availableProcessors(); | ||
70 | @Option(names = { "-q", "--quiet" }, description = "disable progress bars") private boolean quiet = false; | ||
71 | @Option(names = { "-c", "--color" }, description = "control output color. Supported are auto, on, off", | ||
72 | paramLabel = "MODE") private Ansi color = AUTO; | ||
73 | |||
74 | @ArgGroup(validate = false, heading = "%nFilter options%n") private Filters filters = new Filters(); | ||
75 | |||
76 | private static class Filters { | ||
77 | |||
78 | @Option(names = { "--no-installers" }, description = "download installers", negatable = true, | ||
79 | showDefaultValue = ALWAYS) private boolean installers = true; | ||
80 | @Option(names = { "--no-patches" }, description = "download version patches", negatable = true, | ||
81 | showDefaultValue = ALWAYS) private boolean patches = true; | ||
82 | @Option(names = { "--no-dlcs" }, description = "download available DLCs", negatable = true, | ||
83 | showDefaultValue = ALWAYS) private boolean dlcs = true; | ||
84 | |||
85 | @ArgGroup(exclusive = true) private GameIds gameIds = new GameIds(); | ||
86 | |||
87 | private static class GameIds { | ||
88 | |||
89 | @Option(names = { "-i", "--include-game" }, description = """ | ||
90 | only the listed game IDs will be downloaded. Game IDs can be obtained from https://www.gogdb.org/""", | ||
91 | paramLabel = "ID", split = ",") private Set<String> included; | ||
92 | @Option(names = { "-e", "--exclude-game" }, description = """ | ||
93 | all games owned by the account except those listed will be downloaded""", paramLabel = "ID", | ||
94 | split = ",") private Set<String> excluded; | ||
95 | |||
96 | @Nonnull | ||
97 | @SuppressWarnings("null") | ||
98 | public Set<String> getGameIds(@Nonnull User user) { | ||
99 | if (this.included != null) | ||
100 | return unmodifiableSet(this.included); | ||
101 | |||
102 | var library = user.getLibraryIds(); | ||
103 | |||
104 | if (this.excluded == null) | ||
105 | return library; | ||
106 | else | ||
107 | return library.stream().filter(Predicate.not(this.excluded::contains)).collect(toUnmodifiableSet()); | ||
108 | } | ||
109 | |||
110 | } | ||
111 | |||
112 | @ArgGroup(exclusive = true) private Platforms platforms = new Platforms(); | ||
113 | |||
114 | private static class Platforms { | ||
115 | |||
116 | @Option(names = { "--include-platform" }, description = """ | ||
117 | platforms to download for. Supported are linux, windows, mac""", paramLabel = "PLATFORM", | ||
118 | split = ",") private EnumSet<Platform> included; | ||
119 | @Option(names = { "--exclude-platform" }, description = """ | ||
120 | platforms to not download for""", paramLabel = "PLATFORM", | ||
121 | split = ",") private EnumSet<Platform> excluded; | ||
122 | |||
123 | @Nonnull | ||
124 | @SuppressWarnings("null") | ||
125 | public Set<Platform> getPlatforms() { | ||
126 | if (this.included != null) | ||
127 | return unmodifiableSet(this.included); | ||
128 | else if (this.excluded != null) | ||
129 | return unmodifiableSet(this.excluded); | ||
130 | else | ||
131 | return EnumSet.allOf(Platform.class); | ||
132 | } | ||
133 | |||
134 | } | ||
135 | |||
136 | } | ||
137 | |||
138 | @ArgGroup(validate = false, heading = "%nAdvanced options%n") private AdvancedOptions advanced = | ||
139 | new AdvancedOptions(); | ||
140 | |||
141 | private static class AdvancedOptions { | ||
142 | |||
143 | @Option(names = { "-v", "--verbose" }, description = "display verbose log messages") private boolean verbose = | ||
144 | false; | ||
145 | |||
146 | @Option(names = { "--unknown-types" }, description = "download unknown download types", negatable = true, | ||
147 | showDefaultValue = ALWAYS) private boolean unknown = false; | ||
148 | |||
149 | } | ||
150 | |||
151 | @Nonnull | ||
152 | @SuppressWarnings({ "unused", "null" }) | ||
153 | public User getUser() throws IOException, NotLoggedInException { | ||
154 | return this.user.get((AESupplier<User>) () -> new User(this.token.getTokenString())); | ||
155 | } | ||
156 | |||
157 | @Nonnull | ||
158 | public Set<String> getGameIds() throws IOException, NotLoggedInException { | ||
159 | return this.filters.gameIds.getGameIds(getUser()); | ||
160 | } | ||
161 | |||
162 | @Nonnull | ||
163 | @SuppressWarnings("null") | ||
164 | public Ansi getColorMode() { | ||
165 | return this.color; | ||
166 | } | ||
167 | |||
168 | public int getThreads() { | ||
169 | return this.threads; | ||
170 | } | ||
171 | |||
172 | public Path getOutputPath() { | ||
173 | return this.output; | ||
174 | } | ||
175 | |||
176 | public Set<Platform> getPlatforms() { | ||
177 | return this.filters.platforms.getPlatforms(); | ||
178 | } | ||
179 | |||
180 | public boolean downloadDlcs() { | ||
181 | return this.filters.dlcs; | ||
182 | } | ||
183 | |||
184 | public Set<GameDownload.Type> getTypes() { | ||
185 | var types = EnumSet.noneOf(GameDownload.Type.class); | ||
186 | if (this.filters.installers) | ||
187 | types.add(INSTALLER); | ||
188 | |||
189 | if (this.filters.patches) | ||
190 | types.add(PATCH); | ||
191 | |||
192 | if (this.advanced.unknown) | ||
193 | types.add(UNKNOWN); | ||
194 | |||
195 | return types; | ||
196 | } | ||
197 | |||
198 | public boolean isVerbose() { | ||
199 | return this.advanced.verbose; | ||
200 | } | ||
201 | |||
202 | public boolean isQuiet() { | ||
203 | return this.quiet; | ||
204 | } | ||
205 | |||
206 | } | ||