OSDN Git Service

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