OSDN Git Service

chore: increment version to v2.0.3
[delesterandomselector/DelesteRandomSelector.git] / src / com / ranfa / main / DelesteRandomSelector.java
1 package com.ranfa.main;
2
3 import java.awt.BorderLayout;
4 import java.awt.EventQueue;
5 import java.awt.Font;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
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;
16
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.JTextArea;
28 import javax.swing.border.EmptyBorder;
29
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.jgoodies.forms.layout.ColumnSpec;
34 import com.jgoodies.forms.layout.FormLayout;
35 import com.jgoodies.forms.layout.FormSpecs;
36 import com.jgoodies.forms.layout.RowSpec;
37 import com.ranfa.lib.CheckVersion;
38 import com.ranfa.lib.EstimateAlbumTypeCycle;
39 import com.ranfa.lib.Scraping;
40 import com.ranfa.lib.SettingJSONProperty;
41 import com.ranfa.lib.Settings;
42 import com.ranfa.lib.Song;
43 import com.ranfa.lib.TwitterIntegration;
44 import com.ranfa.lib.Version;
45
46 @Version(major = 2, minor = 0, patch = 3)
47 public class DelesteRandomSelector extends JFrame {
48
49         private static ArrayList<Song> selectedSongsList = new ArrayList<Song>();
50
51         private JPanel contentPane;
52         private JPanel panelNorth;
53         private JPanel panelWest;
54         private JLabel labelVersion;
55         private JLabel labelTitle;
56         private JLabel labelDifficulty;
57         private JLabel labelLevel;
58         private JSpinner spinnerLevel;
59         private JCheckBox checkMoreLv;
60         private JCheckBox checkLessLv;
61         private JPanel panelEast;
62         private JPanel panelCentre;
63         private JButton btnImport;
64         private JButton btnStart;
65         private JButton btnExit;
66         private JComboBox comboDifficultySelect;
67         private JLabel labelLvCaution;
68         private JComboBox comboAttribute;
69         private SettingJSONProperty property = new SettingJSONProperty();
70         private JButton btnTwitterIntegration;
71         private String[] integratorArray;
72         private boolean integratorBool = false;
73         private JTextArea textArea;
74         private JScrollPane scrollPane;
75         private CompletableFuture<Void> softwareUpdateFuture = null;
76         private CompletableFuture<Void> albumTypeEstimateFuture = null;
77         private String albumType = "計算中";
78         private Logger logger = LoggerFactory.getLogger(DelesteRandomSelector.class);
79
80         /**
81          * Launch the application.
82          */
83         public static void main(String[] args) {
84                 EventQueue.invokeLater(new Runnable() {
85                         @Override
86                         public void run() {
87                                 try {
88                                         DelesteRandomSelector frame = new DelesteRandomSelector();
89                                         frame.setVisible(true);
90                                 } catch (Exception e) {
91                                         e.printStackTrace();
92                                 }
93                         }
94                 });
95         }
96
97         /**
98          * log file prefix:
99          *  this.getClass() + ":[LEVEL]: " +
100          */
101
102         /**
103          * Create the frame.
104          */
105         public DelesteRandomSelector() {
106                 boolean isFirst = !Scraping.databaseExists();
107                 if(isFirst) {
108                         JOptionPane.showMessageDialog(this, "楽曲データベースが見つかりませんでした。自動的に作成されます…\n注意:初回起動ではなく、かつ、Jarファイルと同じ階層に\"database.json\"というファイルが存在するにも関わらず\nこのポップアップが出た場合、開発者までご一報ください。\nGithub URL: https://github.com/hizumiaoba/DelesteRandomSelector/issues");
109                         if(!Scraping.writeToJson(Scraping.getWholeData())) {
110                                 JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
111                                 throw new NullPointerException("FATAL: cannot continue!");
112                         }
113                 }
114                 ExecutorService es = Executors.newWorkStealingPool();
115                 CompletableFuture<ArrayList<Song>> getFromJsonFuture = CompletableFuture.supplyAsync(() -> Scraping.getFromJson(), es);
116                 CompletableFuture<ArrayList<Song>> getWholeDataFuture = CompletableFuture.supplyAsync(() -> Scraping.getWholeData(), es);
117                 if(!Settings.fileExists() && !Settings.writeDownJSON()) {
118                         JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
119                         throw new NullPointerException("FATAL: cannot continue!");
120                 }
121                 logger.debug("Loading settings...");
122                 property.setCheckLibraryUpdates(Settings.needToCheckLibraryUpdates());
123                 property.setCheckVersion(Settings.needToCheckVersion());
124                 property.setWindowWidth(Settings.getWindowWidth());
125                 property.setWindowHeight(Settings.getWindowHeight());
126                 property.setSongLimit(Settings.getSongsLimit());
127                 property.setSaveScoreLog(Settings.saveScoreLog());
128                 logger.debug("Load settings done.");
129                 logger.debug("Version check: " + property.isCheckVersion());
130                 logger.debug("Library update check: " + property.isCheckLibraryUpdates());
131                 logger.debug("Window Width: " + property.getWindowWidth());
132                 logger.debug("Window Height: " + property.getWindowHeight());
133                 logger.debug("Song Limit: " + property.getSongLimit());
134                 logger.debug("SaveScoreLog: " + property.isSaveScoreLog());
135                 EstimateAlbumTypeCycle.Initialization();
136                 if(Files.exists(Paths.get("generated/albumCycle.json"))) {
137                         albumType = EstimateAlbumTypeCycle.getCurrentCycle();
138                 }
139                 if(property.isCheckVersion()) {
140                         softwareUpdateFuture = CompletableFuture.runAsync(() -> CheckVersion.needToBeUpdated(), es);
141                 }
142                 BiConsumer<ArrayList<Song>, ArrayList<Song>> updateConsumer = (list1, list2) -> {
143                         logger.info("Checking database updates...");
144                         if(list1.size() > list2.size()) {
145                                 long time = System.currentTimeMillis();
146                                 logger.info((list1.size() - list2.size()) + " Update detected.");
147                                 Scraping.writeToJson(list1);
148                                 logger.info("Update completed in " + (System.currentTimeMillis() - time) + "ms");
149                                 logger.info("Updated database size: " + list1.size());
150                         } else {
151                                 logger.info("database is up-to-date.");
152                         }
153                 };
154                 Runnable setEnabled = () -> {
155                         try {
156                                 Thread.sleep(1000);
157                         } catch (InterruptedException e1) {
158                                 // TODO 自動生成された catch ブロック
159                                 e1.printStackTrace();
160                         }
161                         btnImport.setEnabled(true);
162                         btnImport.setText("<html><body>楽曲<br>絞り込み</body></html>");
163                 };
164                 getWholeDataFuture.thenAcceptAsync(list -> logger.info("Scraping data size:" + list.size()), es);
165                 getFromJsonFuture.thenAcceptAsync(list -> logger.info("Currently database size:" + list.size()), es);
166                 if(property.isCheckLibraryUpdates()) {
167                         CompletableFuture<Void> updatedFuture = getWholeDataFuture.thenAcceptBothAsync(getFromJsonFuture, updateConsumer, es);
168                         updatedFuture.thenRunAsync(setEnabled, es);
169                 }
170                 logger.debug("Version:" + CheckVersion.getVersion());
171                 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
172                 setBounds(100, 100, property.getWindowWidth(), property.getWindowHeight());
173                 // setBounds(100, 100, 640, 360);
174                 contentPane = new JPanel();
175                 contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
176                 setContentPane(contentPane);
177                 contentPane.setLayout(new BorderLayout(0, 0));
178
179                 panelNorth = new JPanel();
180                 contentPane.add(panelNorth, BorderLayout.NORTH);
181                 panelNorth.setLayout(new FormLayout(new ColumnSpec[] {
182                                 ColumnSpec.decode("max(302dlu;default)"),
183                                 FormSpecs.RELATED_GAP_COLSPEC,
184                                 ColumnSpec.decode("40px"),},
185                         new RowSpec[] {
186                                 RowSpec.decode("20px"),}));
187
188                 labelTitle = new JLabel("デレステ課題曲セレクター");
189                 labelTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 16));
190                 panelNorth.add(labelTitle, "1, 1, center, top");
191
192                 labelVersion = new JLabel(CheckVersion.getVersion());
193                 labelVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
194                 panelNorth.add(labelVersion, "3, 1, right, top");
195
196                 panelWest = new JPanel();
197                 contentPane.add(panelWest, BorderLayout.WEST);
198                 panelWest.setLayout(new FormLayout(new ColumnSpec[] {
199                                 FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
200                                 ColumnSpec.decode("112px:grow"),},
201                         new RowSpec[] {
202                                 FormSpecs.LINE_GAP_ROWSPEC,
203                                 RowSpec.decode("19px"),
204                                 FormSpecs.RELATED_GAP_ROWSPEC,
205                                 RowSpec.decode("max(12dlu;default)"),
206                                 FormSpecs.RELATED_GAP_ROWSPEC,
207                                 RowSpec.decode("max(12dlu;default)"),
208                                 FormSpecs.RELATED_GAP_ROWSPEC,
209                                 RowSpec.decode("12dlu"),
210                                 FormSpecs.RELATED_GAP_ROWSPEC,
211                                 RowSpec.decode("max(12dlu;default)"),
212                                 FormSpecs.RELATED_GAP_ROWSPEC,
213                                 RowSpec.decode("max(12dlu;default)"),
214                                 FormSpecs.RELATED_GAP_ROWSPEC,
215                                 RowSpec.decode("max(12dlu;default)"),
216                                 FormSpecs.RELATED_GAP_ROWSPEC,
217                                 RowSpec.decode("max(52dlu;default)"),}));
218
219                 labelDifficulty = new JLabel("難易度選択");
220                 labelDifficulty.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
221                 panelWest.add(labelDifficulty, "2, 2, center, default");
222
223                 comboDifficultySelect = new JComboBox();
224                 comboDifficultySelect.setFont(new Font("Dialog", Font.BOLD, 12));
225                 comboDifficultySelect.setModel(new DefaultComboBoxModel(new String[] {"指定なし", "DEBUT", "REGULAR", "PRO", "MASTER", "MASTER+", "ⓁMASTER+", "LIGHT", "TRICK", "PIANO", "FORTE", "WITCH"}));
226                 panelWest.add(comboDifficultySelect, "2, 4, fill, default");
227
228                                 comboAttribute = new JComboBox();
229                                 comboAttribute.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
230                                 comboAttribute.setModel(new DefaultComboBoxModel(new String[] {"指定なし", "全タイプ", "キュート", "クール", "パッション"}));
231                                 panelWest.add(comboAttribute, "2, 6, fill, default");
232
233                                 labelLevel = new JLabel("楽曲Lv");
234                                 labelLevel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
235                                 panelWest.add(labelLevel, "2, 8, center, default");
236
237                                 spinnerLevel = new JSpinner();
238                                 panelWest.add(spinnerLevel, "2, 10");
239
240                                 checkLessLv = new JCheckBox("指定Lv以下");
241                                 checkLessLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
242                                 panelWest.add(checkLessLv, "2, 12");
243
244                                 checkMoreLv = new JCheckBox("指定Lv以上");
245                                 checkMoreLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
246                                 panelWest.add(checkMoreLv, "2, 14");
247
248                                 labelLvCaution = new JLabel("<html><body>※以下以上両方にチェックをつけることで指定レベルのみ絞り込むことができます</body></html>");
249                                 labelLvCaution.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
250                                 panelWest.add(labelLvCaution, "2, 16, fill, fill");
251
252                 panelEast = new JPanel();
253                 contentPane.add(panelEast, BorderLayout.EAST);
254                 panelEast.setLayout(new FormLayout(new ColumnSpec[] {
255                                 ColumnSpec.decode("98px"),},
256                         new RowSpec[] {
257                                 RowSpec.decode("26px"),
258                                 FormSpecs.RELATED_GAP_ROWSPEC,
259                                 RowSpec.decode("max(36dlu;default)"),
260                                 FormSpecs.RELATED_GAP_ROWSPEC,
261                                 FormSpecs.DEFAULT_ROWSPEC,
262                                 FormSpecs.RELATED_GAP_ROWSPEC,
263                                 RowSpec.decode("max(30dlu;default)"),
264                                 FormSpecs.RELATED_GAP_ROWSPEC,
265                                 RowSpec.decode("max(15dlu;default)"),
266                                 FormSpecs.RELATED_GAP_ROWSPEC,
267                                 RowSpec.decode("max(11dlu;default)"),
268                                 FormSpecs.RELATED_GAP_ROWSPEC,
269                                 FormSpecs.DEFAULT_ROWSPEC,
270                                 FormSpecs.RELATED_GAP_ROWSPEC,
271                                 FormSpecs.DEFAULT_ROWSPEC,
272                                 FormSpecs.RELATED_GAP_ROWSPEC,
273                                 FormSpecs.DEFAULT_ROWSPEC,}));
274
275                 btnImport = new JButton("<html><body>データベース<br>更新中…</body></html>");
276                 btnImport.setEnabled(false);
277                 btnImport.addActionListener(new ActionListener() {
278                         @Override
279                         public void actionPerformed(ActionEvent e) {
280                                 ArrayList<Song> fromJson = Scraping.getFromJson();
281                                         ArrayList<Song> specificlevelList = Scraping.getSpecificLevelSongs(fromJson, (Integer)spinnerLevel.getValue(), checkLessLv.isSelected(), checkMoreLv.isSelected());
282                                         ArrayList<Song> specificDifficultyList = Scraping.getSpecificDifficultySongs(specificlevelList, comboDifficultySelect.getSelectedItem().toString());
283                                         ArrayList<Song> specificAttributeList = Scraping.getSpecificAttributeSongs(specificDifficultyList, comboAttribute.getSelectedItem().toString());
284                                         ArrayList<Song> specificTypeList = Scraping.getSpecificAlbumTypeSongs(specificAttributeList, EstimateAlbumTypeCycle.getCurrentCycle());
285                                         if(!selectedSongsList.isEmpty())
286                                         selectedSongsList.clear();
287                                 selectedSongsList.addAll((comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS)) ? specificTypeList : specificAttributeList);
288                                 logger.info("Songs are selected.We are Ready to go.");
289                                 JOptionPane.showMessageDialog(null, "絞り込み完了!「開始」をクリックすることで選曲できます!");
290                         }
291                 });
292                 btnImport.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
293                 panelEast.add(btnImport, "1, 3, fill, fill");
294
295                 btnStart = new JButton("開始!");
296                 btnStart.addActionListener(new ActionListener() {
297                         @Override
298                         public void actionPerformed(ActionEvent e) {
299                                 Random random = new Random(System.currentTimeMillis());
300                                 String paneString = "";
301                                 integratorArray = new String[property.getSongLimit()];
302                                 for(int i = 0; i < property.getSongLimit(); i++) {
303                                         int randomInt = random.nextInt(selectedSongsList.size());
304                                         String typeString = comboDifficultySelect.getSelectedItem().equals(Scraping.MASTERPLUS) || comboDifficultySelect.getSelectedItem().equals(Scraping.LEGACYMASTERPLUS) ? EstimateAlbumTypeCycle.getCurrentCycle() : "";
305                                         paneString = paneString + (i + 1) + "曲目: " + selectedSongsList.get(randomInt).getAttribute() + " [" + selectedSongsList.get(randomInt).getDifficulty() + "]「" + selectedSongsList.get(randomInt).getName() + "」!(Lv:" + selectedSongsList.get(randomInt).getLevel() + " " + typeString + ")\n\n";
306                                         integratorArray[i] = selectedSongsList.get(randomInt).getName() + "(Lv" + selectedSongsList.get(randomInt).getLevel() + ")\n";
307                                 }
308                                 paneString = paneString + "この" + property.getSongLimit() + "曲をプレイしましょう!!!";
309                                 textArea.setText(paneString);
310                                 integratorBool = true;
311                                 logger.info("show up completed.");
312                         }
313                 });
314                 btnStart.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
315                 panelEast.add(btnStart, "1, 7, fill, fill");
316
317                                 btnTwitterIntegration = new JButton("Twitter連携");
318                                 btnTwitterIntegration.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 11));
319                                 btnTwitterIntegration.addActionListener(new ActionListener() {
320                                         @Override
321                                         public void actionPerformed(ActionEvent e) {
322                                                 boolean authorizationStatus = TwitterIntegration.authorization();
323                                                 String updatedStatus = "デレステ課題曲セレクターで\n";
324                                                 int lengthLimit = updatedStatus.length();
325                                                 boolean isBroken = false;
326                                                 if(!integratorBool) {
327                                                         JOptionPane.showMessageDialog(null, "ちひろ「まだプレイを始めていないみたいですね」");
328                                                         return;
329                                                 }
330                                                 for(int i = 0; i < integratorArray.length; i++) {
331                                                         updatedStatus = updatedStatus + integratorArray[i];
332                                                         lengthLimit += integratorArray[i].length();
333                                                         if(lengthLimit > 69) {
334                                                                 isBroken = true;
335                                                                 break;
336                                                         }
337                                                 }
338                                                 if(isBroken) {
339                                                         updatedStatus = updatedStatus + "…その他数曲\nをプレイしました!\n#DelesteRandomSelector #デレステ ";
340                                                 } else {
341                                                         updatedStatus = updatedStatus + "をプレイしました!\n#DelesteRandomSelector #デレステ ";
342                                                 }
343                                                 logger.info("status message constructed.");
344                                                 lengthLimit = updatedStatus.length();
345                                                 if(authorizationStatus) {
346                                                         int option = JOptionPane.showConfirmDialog(null, "Twitterへ以下の内容を投稿します。よろしいですか?\n\n" + updatedStatus + "\n\n文字数:" + lengthLimit);
347                                                         logger.info("user seletced: " + option);
348                                                         switch(option) {
349                                                                 case JOptionPane.OK_OPTION:
350                                                                         TwitterIntegration.PostTwitter(updatedStatus);
351                                                                         logger.info("Success to update the status.");
352                                                                         JOptionPane.showMessageDialog(null, "投稿が完了しました。");
353                                                                         break;
354                                                                 case JOptionPane.NO_OPTION:
355                                                                         logger.info("There is no will to post.");
356                                                                         break;
357                                                                 case JOptionPane.CANCEL_OPTION:
358                                                                         logger.info("The Operation was canceled by user.");
359                                                                         break;
360                                                                 default:
361                                                                         break;
362                                                         }
363                                                 } else {
364                                                         logger.info("seems to reject the permission.it should need try again.");
365                                                 }
366                                         }
367                                 });
368                                 panelEast.add(btnTwitterIntegration, "1, 11");
369
370                                                                 btnExit = new JButton("終了");
371                                                                 btnExit.addActionListener(new ActionListener() {
372                                                                         @Override
373                                                                         public void actionPerformed(ActionEvent e) {
374                                                                                 if(softwareUpdateFuture.isDone() || albumTypeEstimateFuture.isDone()) {
375                                                                                         logger.info("Requested Exit by Button");
376                                                                                         System.exit(0);
377                                                                                 } else {
378                                                                                         JOptionPane.showMessageDialog(null, "内部更新処理が完了していません。少し待ってからやり直してください。");
379                                                                                 }
380                                                                         }
381                                                                 });
382                                                                 btnExit.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
383                                                                 panelEast.add(btnExit, "1, 13");
384
385                 panelCentre = new JPanel();
386                 contentPane.add(panelCentre, BorderLayout.CENTER);
387                 panelCentre.setLayout(new BorderLayout(0, 0));
388
389                 textArea = new JTextArea();
390                 textArea.setText("楽曲選択の手順\r\n1.難易度、属性、レベルを選択する\r\n2.「楽曲取り込み」ボタンを押す!\r\n3.「開始」ボタンを押す!\r\n4.選択された楽曲がここに表示されます!\r\n現在設定されている楽曲選択の最大数:" + property.getSongLimit() + "\n現在のMASTER+アルバム周期(推定):" + albumType);
391                 textArea.setEditable(false);
392
393                 scrollPane = new JScrollPane(textArea);
394                 panelCentre.add(scrollPane, BorderLayout.CENTER);
395                 if(isFirst || !property.isCheckLibraryUpdates()) {
396                         setEnabled.run();
397                 }
398         }
399
400 }