1 package com.ranfa.main;
3 import java.awt.BorderLayout;
4 import java.awt.CardLayout;
5 import java.awt.EventQueue;
7 import java.io.IOException;
8 import java.nio.file.Files;
9 import java.nio.file.Paths;
10 import java.util.ArrayList;
11 import java.util.Random;
12 import java.util.concurrent.CompletableFuture;
13 import java.util.concurrent.ExecutorService;
14 import java.util.concurrent.Executors;
15 import java.util.function.BiConsumer;
17 import javax.swing.DefaultComboBoxModel;
18 import javax.swing.JButton;
19 import javax.swing.JCheckBox;
20 import javax.swing.JComboBox;
21 import javax.swing.JFrame;
22 import javax.swing.JLabel;
23 import javax.swing.JOptionPane;
24 import javax.swing.JPanel;
25 import javax.swing.JScrollPane;
26 import javax.swing.JSpinner;
27 import javax.swing.JTabbedPane;
28 import javax.swing.JTextArea;
29 import javax.swing.border.EmptyBorder;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
34 import com.jgoodies.forms.layout.ColumnSpec;
35 import com.jgoodies.forms.layout.FormLayout;
36 import com.jgoodies.forms.layout.FormSpecs;
37 import com.jgoodies.forms.layout.RowSpec;
38 import com.ranfa.lib.CheckVersion;
39 import com.ranfa.lib.Easter;
40 import com.ranfa.lib.EstimateAlbumTypeCycle;
41 import com.ranfa.lib.ManualUpdateThreadImpl;
42 import com.ranfa.lib.Scraping;
43 import com.ranfa.lib.SettingJSONProperty;
44 import com.ranfa.lib.Settings;
45 import com.ranfa.lib.Song;
46 import com.ranfa.lib.TwitterIntegration;
47 import com.ranfa.lib.Version;
49 @Version(major = 3, minor = 1, patch = 0)
50 public class DelesteRandomSelector extends JFrame {
52 private static ArrayList<Song> selectedSongsList = new ArrayList<>();
54 private JPanel contentPane;
55 private SettingJSONProperty property = new SettingJSONProperty();
56 private String[] integratorArray;
57 private boolean integratorBool = false;
58 private CompletableFuture<Void> softwareUpdateFuture = null;
59 private CompletableFuture<Void> albumTypeEstimateFuture = null;
60 private String albumType = Messages.MSGAlbumTypeBeingCalculated.toString();
61 private Logger logger = LoggerFactory.getLogger(DelesteRandomSelector.class);
62 private ManualUpdateThreadImpl impl;
63 private Thread manualUpdateThread;
64 private Easter easter;
65 private JPanel panelMain;
66 private JPanel panelNorthMain;
67 private JLabel labelTitle;
68 private JLabel labelVersion;
69 private JPanel panelWestMain;
70 private JLabel labelDifficulty;
71 private JComboBox comboDifficultySelect;
72 private JComboBox comboAttribute;
73 private JLabel labelLevel;
74 private JSpinner spinnerLevel;
75 private JCheckBox checkLessLv;
76 private JCheckBox checkMoreLv;
77 private JLabel labelLvCaution;
78 private JPanel panelEastMain;
79 private JButton btnImport;
80 private JButton btnConfig;
81 private JButton btnStart;
82 private JButton btnManualUpdate;
83 private JButton btnTwitterIntegration;
84 private JButton btnExit;
85 private JPanel panelCenterMain;
86 private JScrollPane scrollPane;
87 private JTextArea textArea;
88 private JTabbedPane tabbedPane;
89 private JPanel panelTool;
90 private JPanel panelNorthTool;
91 private JLabel labelSubToolTitle;
92 private JLabel labelVersionTool;
93 private JPanel panelCenterTool;
94 private JLabel lblNewLabel;
97 * Launch the application.
99 public static void main(String[] args) {
100 EventQueue.invokeLater(() -> {
102 DelesteRandomSelector frame = new DelesteRandomSelector();
103 frame.setVisible(true);
104 } catch (Exception e) {
113 * this.getClass() + ":[LEVEL]: " +
119 public DelesteRandomSelector() {
120 this.contentPane = new JPanel();
121 boolean isFirst = !Scraping.databaseExists();
123 JOptionPane.showMessageDialog(this, Messages.MSGDatabaseNotExist.toString());
124 if(!Scraping.writeToJson(Scraping.getWholeData())) {
125 JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
126 throw new NullPointerException("FATAL: cannot continue!");
129 ExecutorService es = Executors.newWorkStealingPool();
130 CompletableFuture<ArrayList<Song>> getFromJsonFuture = CompletableFuture.supplyAsync(() -> Scraping.getFromJson(), es);
131 CompletableFuture<ArrayList<Song>> getWholeDataFuture = CompletableFuture.supplyAsync(() -> Scraping.getWholeData(), es);
132 if(!Settings.fileExists() && !Settings.writeDownJSON()) {
133 JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
134 throw new NullPointerException("FATAL: cannot continue!");
136 this.logger.debug("Loading settings...");
137 this.property.setCheckLibraryUpdates(Settings.needToCheckLibraryUpdates());
138 this.property.setCheckVersion(Settings.needToCheckVersion());
139 this.property.setWindowWidth(Settings.getWindowWidth());
140 this.property.setWindowHeight(Settings.getWindowHeight());
141 this.property.setSongLimit(Settings.getSongsLimit());
142 this.property.setSaveScoreLog(Settings.saveScoreLog());
143 this.logger.debug("Load settings done.");
144 this.logger.debug("Version check: {}", this.property.isCheckVersion());
145 this.logger.debug("Library update check: {}", this.property.isCheckLibraryUpdates());
146 this.logger.debug("Window Width: {}", this.property.getWindowWidth());
147 this.logger.debug("Window Height: {}", this.property.getWindowHeight());
148 this.logger.debug("Song Limit: {}", this.property.getSongLimit());
149 this.logger.debug("SaveScoreLog: {}", this.property.isSaveScoreLog());
150 EstimateAlbumTypeCycle.Initialization();
151 if(Files.exists(Paths.get("generated/albumCycle.json"))) {
152 this.albumType = EstimateAlbumTypeCycle.getCurrentCycle();
154 if(this.property.isCheckVersion()) {
155 this.softwareUpdateFuture = CompletableFuture.runAsync(() -> CheckVersion.needToBeUpdated(), es);
157 BiConsumer<ArrayList<Song>, ArrayList<Song>> updateConsumer = (list1, list2) -> {
158 this.logger.info("Checking database updates...");
159 if(list1.size() > list2.size()) {
160 long time = System.currentTimeMillis();
161 this.logger.info("{} Update detected.", (list1.size() - list2.size()));
162 Scraping.writeToJson(list1);
163 this.logger.info("Update completed in {} ms", (System.currentTimeMillis() - time));
164 this.logger.info("Updated database size: {}", list1.size());
166 this.logger.info("database is up-to-date.");
169 Runnable setEnabled = () -> {
171 Thread.sleep(3 * 1000L);
172 } catch (InterruptedException e1) {
173 this.logger.error("Thread has been interrupted during waiting cooldown.", e1);
175 this.btnImport.setEnabled(true);
176 this.btnImport.setText(Messages.MSGNarrowingDownSongs.toString());
178 getWholeDataFuture.thenAcceptAsync(list -> this.logger.info("Scraping data size:" + list.size()), es);
179 getFromJsonFuture.thenAcceptAsync(list -> this.logger.info("Currently database size:" + list.size()), es);
180 if(this.property.isCheckLibraryUpdates()) {
181 CompletableFuture<Void> updatedFuture = getWholeDataFuture.thenAcceptBothAsync(getFromJsonFuture, updateConsumer, es);
182 updatedFuture.thenRunAsync(setEnabled, es);
184 this.easter = new Easter();
185 this.setTitle(this.easter.getTodaysBirth());
186 this.logger.debug("Version: {}", CheckVersion.getVersion());
187 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
188 // this.setBounds(100, 100, this.property.getWindowWidth(), this.property.getWindowHeight());
189 this.setBounds(100, 100, 960, 540);
190 this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
191 this.setContentPane(this.contentPane);
192 contentPane.setLayout(new CardLayout(0, 0));
194 panelMain = new JPanel();
195 panelMain.setLayout(new BorderLayout(0, 0));
197 panelNorthMain = new JPanel();
198 panelMain.add(panelNorthMain, BorderLayout.NORTH);
199 panelNorthMain.setLayout(new FormLayout(new ColumnSpec[] {
200 ColumnSpec.decode("829px"),
201 FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
202 ColumnSpec.decode("center:94px"),},
204 RowSpec.decode("20px"),}));
206 labelTitle = new JLabel(Messages.MSGTitle.toString());
207 labelTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 16));
208 panelNorthMain.add(labelTitle, "1, 1, center, top");
210 labelVersion = new JLabel(CheckVersion.getVersion());
211 labelVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
212 panelNorthMain.add(labelVersion, "3, 1, center, center");
214 panelWestMain = new JPanel();
215 panelMain.add(panelWestMain, BorderLayout.WEST);
216 panelWestMain.setLayout(new FormLayout(new ColumnSpec[] {
217 FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
218 ColumnSpec.decode("120px"),},
220 FormSpecs.LINE_GAP_ROWSPEC,
221 RowSpec.decode("25px"),
222 FormSpecs.RELATED_GAP_ROWSPEC,
223 FormSpecs.DEFAULT_ROWSPEC,
224 FormSpecs.RELATED_GAP_ROWSPEC,
225 FormSpecs.DEFAULT_ROWSPEC,
226 FormSpecs.RELATED_GAP_ROWSPEC,
227 FormSpecs.DEFAULT_ROWSPEC,
228 FormSpecs.RELATED_GAP_ROWSPEC,
229 FormSpecs.DEFAULT_ROWSPEC,
230 FormSpecs.RELATED_GAP_ROWSPEC,
231 FormSpecs.DEFAULT_ROWSPEC,
232 FormSpecs.RELATED_GAP_ROWSPEC,
233 FormSpecs.DEFAULT_ROWSPEC,
234 FormSpecs.RELATED_GAP_ROWSPEC,
235 RowSpec.decode("max(41dlu;default)"),}));
237 labelDifficulty = new JLabel(Messages.MSGSelectDifficulty.toString());
238 labelDifficulty.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
239 panelWestMain.add(labelDifficulty, "2, 2, center, center");
241 comboDifficultySelect = new JComboBox();
242 comboDifficultySelect.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "DEBUT", "REGULAR", "PRO", "MASTER", "MASTER+", "ⓁMASTER+", "LIGHT", "TRICK", "PIANO", "FORTE", "WITCH"}));
243 comboDifficultySelect.setFont(new Font("Dialog", Font.BOLD, 12));
244 panelWestMain.add(comboDifficultySelect, "2, 4, fill, fill");
246 comboAttribute = new JComboBox();
247 comboAttribute.setModel(new DefaultComboBoxModel(new String[] {Messages.MSGNonSelected.toString(), "全タイプ", "キュート", "クール", "パッション"}));
248 comboAttribute.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
249 panelWestMain.add(comboAttribute, "2, 6, fill, top");
251 labelLevel = new JLabel(Messages.MSGSongLevel.toString());
252 labelLevel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
253 panelWestMain.add(labelLevel, "2, 8, center, center");
255 spinnerLevel = new JSpinner();
256 panelWestMain.add(spinnerLevel, "2, 10, fill, center");
258 checkLessLv = new JCheckBox(Messages.MSGBelowSpecificLevel.toString());
259 checkLessLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
260 panelWestMain.add(checkLessLv, "2, 12, left, top");
262 checkMoreLv = new JCheckBox(Messages.MSGOverSpecificLevel.toString());
263 checkMoreLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
264 panelWestMain.add(checkMoreLv, "2, 14, left, top");
266 labelLvCaution = new JLabel(Messages.MSGLevelCheckboxInfo.toString());
267 labelLvCaution.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
268 panelWestMain.add(labelLvCaution, "2, 16, left, center");
270 panelEastMain = new JPanel();
271 panelMain.add(panelEastMain, BorderLayout.EAST);
272 panelEastMain.setLayout(new FormLayout(new ColumnSpec[] {
273 FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
274 ColumnSpec.decode("100px"),},
276 FormSpecs.LINE_GAP_ROWSPEC,
277 RowSpec.decode("77px"),
278 FormSpecs.RELATED_GAP_ROWSPEC,
279 FormSpecs.DEFAULT_ROWSPEC,
280 FormSpecs.RELATED_GAP_ROWSPEC,
281 FormSpecs.DEFAULT_ROWSPEC,
282 FormSpecs.RELATED_GAP_ROWSPEC,
283 FormSpecs.DEFAULT_ROWSPEC,
284 FormSpecs.RELATED_GAP_ROWSPEC,
285 RowSpec.decode("max(36dlu;default)"),
286 FormSpecs.RELATED_GAP_ROWSPEC,
287 FormSpecs.DEFAULT_ROWSPEC,}));
289 btnImport = new JButton(Messages.MSGUpdatingDatabase.toString());
290 btnImport.addActionListener(e -> {
292 if(!impl.getFlag()) {
293 JOptionPane.showMessageDialog(null, Messages.MSGManualUpdateNotCompleteYet.toString());
296 ArrayList<Song> fromJson = Scraping.getFromJson();
297 ArrayList<Song> specificlevelList = Scraping.getSpecificLevelSongs(fromJson, (Integer)DelesteRandomSelector.this.spinnerLevel.getValue(), DelesteRandomSelector.this.checkLessLv.isSelected(), DelesteRandomSelector.this.checkMoreLv.isSelected());
298 ArrayList<Song> specificDifficultyList = Scraping.getSpecificDifficultySongs(specificlevelList, DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().toString());
299 ArrayList<Song> specificAttributeList = Scraping.getSpecificAttributeSongs(specificDifficultyList, DelesteRandomSelector.this.comboAttribute.getSelectedItem().toString());
300 ArrayList<Song> specificTypeList = Scraping.getSpecificAlbumTypeSongs(specificAttributeList, EstimateAlbumTypeCycle.getCurrentCycle());
301 if(!selectedSongsList.isEmpty()) {
302 selectedSongsList.clear();
304 selectedSongsList.addAll((DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS)) ? specificTypeList : specificAttributeList);
305 DelesteRandomSelector.this.logger.info("Songs are selected.We are Ready to go.");
306 JOptionPane.showMessageDialog(null, Messages.MSGCompleteNarrowDown.toString());
308 btnImport.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
309 btnImport.setEnabled(false);
310 panelEastMain.add(btnImport, "2, 2, fill, fill");
312 btnConfig = new JButton(Messages.MSGConfigurations.toString());
313 btnConfig.addActionListener(e -> {
314 ProcessBuilder builder = new ProcessBuilder("java", "-jar", "Configurations.jar");
317 } catch (IOException e1) {
318 logger.error("Cannot start external jar file. maybe are you running this with mac or linux?", e);
321 panelEastMain.add(btnConfig, "2, 6, fill, fill");
323 btnStart = new JButton(Messages.MSGCalcStart.toString());
324 btnStart.addActionListener(e -> {
325 Random random = new Random(System.currentTimeMillis());
326 String paneString = "";
327 DelesteRandomSelector.this.integratorArray = new String[DelesteRandomSelector.this.property.getSongLimit()];
328 for(int i = 0; i < DelesteRandomSelector.this.property.getSongLimit(); i++) {
329 int randomInt = random.nextInt(selectedSongsList.size());
330 String typeString = DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || DelesteRandomSelector.this.comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS) ? EstimateAlbumTypeCycle.getCurrentCycle() : "";
331 paneString = paneString + (i + 1) + Messages.MSGNumberOfSongs.toString() + " " + selectedSongsList.get(randomInt).getAttribute() + " [" + selectedSongsList.get(randomInt).getDifficulty() + "]「" + selectedSongsList.get(randomInt).getName() + "」!(Lv:" + selectedSongsList.get(randomInt).getLevel() + " " + typeString + ")\n\n";
332 DelesteRandomSelector.this.integratorArray[i] = selectedSongsList.get(randomInt).getName() + "(Lv" + selectedSongsList.get(randomInt).getLevel() + ")\n";
334 paneString = paneString + Messages.MSGThisPhrase.toString() + DelesteRandomSelector.this.property.getSongLimit() + Messages.MSGPlayPhrase.toString();
335 DelesteRandomSelector.this.textArea.setText(paneString);
336 DelesteRandomSelector.this.integratorBool = true;
337 DelesteRandomSelector.this.logger.info("show up completed.");
339 btnStart.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
340 panelEastMain.add(btnStart, "2, 4, fill, fill");
342 btnManualUpdate = new JButton(Messages.MSGManualUpdate.toString());
343 btnManualUpdate.addActionListener(e -> {
344 impl = new ManualUpdateThreadImpl();
347 panelEastMain.add(btnManualUpdate, "2, 8, fill, fill");
349 btnTwitterIntegration = new JButton(Messages.MSGTwitterIntegration.toString());
350 btnTwitterIntegration.addActionListener(e -> {
351 boolean authorizationStatus = TwitterIntegration.authorization();
352 String updatedStatus = Messages.MSGUsingThisAppPhrase.toString();
353 int lengthLimit = updatedStatus.length();
354 boolean isBroken = false;
355 if(!DelesteRandomSelector.this.integratorBool) {
356 JOptionPane.showMessageDialog(null, Messages.MSGNotPlayYet.toString());
359 for (String element : DelesteRandomSelector.this.integratorArray) {
360 updatedStatus = updatedStatus + element;
361 lengthLimit += element.length();
362 if(lengthLimit > 69) {
368 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOtherwisePhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
370 updatedStatus = updatedStatus + Messages.MSGTwitterPlayOnlyPhrase.toString() + "\n#DelesteRandomSelector #デレステ ";
372 DelesteRandomSelector.this.logger.info("status message constructed.");
373 lengthLimit = updatedStatus.length();
374 if(authorizationStatus) {
375 int option = JOptionPane.showConfirmDialog(null, Messages.MSGTwitterIntegrationConfirm.toString() + updatedStatus + Messages.MSGStringLength.toString() + lengthLimit);
376 DelesteRandomSelector.this.logger.info("user seletced: " + option);
378 case JOptionPane.OK_OPTION:
379 TwitterIntegration.PostTwitter(updatedStatus);
380 DelesteRandomSelector.this.logger.info("Success to update the status.");
381 JOptionPane.showMessageDialog(null, Messages.MSGCompletePost.toString());
383 case JOptionPane.NO_OPTION:
384 DelesteRandomSelector.this.logger.info("There is no will to post.");
386 case JOptionPane.CANCEL_OPTION:
387 DelesteRandomSelector.this.logger.info("The Operation was canceled by user.");
393 DelesteRandomSelector.this.logger.info("seems to reject the permission.it should need try again.");
396 btnTwitterIntegration.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 11));
397 panelEastMain.add(btnTwitterIntegration, "2, 10, fill, fill");
399 btnExit = new JButton(Messages.MSGTerminate.toString());
400 btnExit.addActionListener(e -> {
401 if(DelesteRandomSelector.this.softwareUpdateFuture.isDone() || DelesteRandomSelector.this.albumTypeEstimateFuture.isDone() || !this.impl.getFlag()) {
402 DelesteRandomSelector.this.logger.info("Requested Exit by Button.");
403 logger.info("Shut down thread pool.");
407 JOptionPane.showMessageDialog(null, Messages.MSGInternalYpdateNotDoneYet.toString());
410 btnExit.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
411 panelEastMain.add(btnExit, "2, 12, fill, fill");
413 panelCenterMain = new JPanel();
414 panelMain.add(panelCenterMain, BorderLayout.CENTER);
415 panelCenterMain.setLayout(new BorderLayout(0, 0));
417 scrollPane = new JScrollPane();
418 panelCenterMain.add(scrollPane);
420 textArea = new JTextArea();
421 textArea.setText(Messages.MSGNarrowDownProcedure.toString() + property.getSongLimit() + Messages.MSGCurrentAlbumType.toString() + albumType);
422 textArea.setEditable(false);
423 scrollPane.setViewportView(textArea);
425 tabbedPane = new JTabbedPane(JTabbedPane.TOP);
426 tabbedPane.addTab("Main", null, panelMain, null);
427 contentPane.add(tabbedPane, "name_307238585319500");
429 panelTool = new JPanel();
430 tabbedPane.addTab("SubTools", null, panelTool, null);
431 panelTool.setLayout(new BorderLayout(0, 0));
433 panelNorthTool = new JPanel();
434 panelTool.add(panelNorthTool, BorderLayout.NORTH);
435 panelNorthTool.setLayout(new FormLayout(new ColumnSpec[] {
436 ColumnSpec.decode("center:max(524dlu;default)"),
437 FormSpecs.RELATED_GAP_COLSPEC,
438 ColumnSpec.decode("max(30dlu;default)"),},
440 RowSpec.decode("max(16dlu;default)"),}));
442 labelSubToolTitle = new JLabel("補助ツール");
443 labelSubToolTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.PLAIN, 16));
444 panelNorthTool.add(labelSubToolTitle, "1, 1");
446 labelVersionTool = new JLabel(CheckVersion.getVersion());
447 labelVersionTool.setFont(new Font("SansSerif", Font.BOLD, 12));
448 panelNorthTool.add(labelVersionTool, "3, 1");
450 panelCenterTool = new JPanel();
451 panelTool.add(panelCenterTool, BorderLayout.CENTER);
452 panelCenterTool.setLayout(new FormLayout(new ColumnSpec[] {
453 FormSpecs.RELATED_GAP_COLSPEC,
454 ColumnSpec.decode("max(166dlu;default)"),},
456 FormSpecs.RELATED_GAP_ROWSPEC,
457 FormSpecs.DEFAULT_ROWSPEC,}));
459 lblNewLabel = new JLabel("New label");
460 panelCenterTool.add(lblNewLabel, "2, 2, center, default");
461 if(isFirst || !this.property.isCheckLibraryUpdates()) {