1 package com.ranfa.main;
3 import java.awt.BorderLayout;
4 import java.awt.EventQueue;
6 import java.awt.event.ActionEvent;
7 import java.awt.event.ActionListener;
8 import java.io.IOException;
9 import java.nio.file.Files;
10 import java.nio.file.Path;
11 import java.nio.file.Paths;
12 import java.util.ArrayList;
13 import java.util.Random;
14 import java.util.concurrent.CompletableFuture;
15 import java.util.concurrent.ExecutorService;
16 import java.util.concurrent.Executors;
18 import javax.swing.DefaultComboBoxModel;
19 import javax.swing.JButton;
20 import javax.swing.JCheckBox;
21 import javax.swing.JComboBox;
22 import javax.swing.JFrame;
23 import javax.swing.JLabel;
24 import javax.swing.JOptionPane;
25 import javax.swing.JPanel;
26 import javax.swing.JSpinner;
27 import javax.swing.JTextPane;
28 import javax.swing.border.EmptyBorder;
30 import com.jgoodies.forms.layout.ColumnSpec;
31 import com.jgoodies.forms.layout.FormLayout;
32 import com.jgoodies.forms.layout.FormSpecs;
33 import com.jgoodies.forms.layout.RowSpec;
34 import com.ranfa.lib.LimitedLog;
35 import com.ranfa.lib.Scraping;
36 import com.ranfa.lib.SettingJSONProperty;
37 import com.ranfa.lib.Settings;
38 import com.ranfa.lib.Song;
39 import com.ranfa.lib.TwitterIntegration;
40 import com.ranfa.lib.Version;
42 @Version(major = 1, minor = 0, patch = 2)
43 public class DelesteRandomSelector extends JFrame {
45 private static ArrayList<Song> selectedSongsList = new ArrayList<Song>();
47 private JPanel contentPane;
48 private JPanel panelNorth;
49 private JPanel panelWest;
50 private JLabel labelVersion;
51 private JLabel labelTitle;
52 private JLabel labelDifficulty;
53 private JLabel labelLevel;
54 private JSpinner spinnerLevel;
55 private JCheckBox checkMoreLv;
56 private JCheckBox checkLessLv;
57 private JPanel panelEast;
58 private JPanel panelCentre;
59 private JButton btnImport;
60 private JButton btnStart;
61 private JButton btnExit;
62 private JTextPane textPane;
63 private JComboBox comboDifficultySelect;
64 private JLabel labelLvCaution;
65 private JComboBox comboAttribute;
66 private SettingJSONProperty property = new SettingJSONProperty();
67 private JButton btnTwitterIntegration;
68 private String[] integratorArray;
69 private boolean integratorBool = false;
72 * Launch the application.
74 public static void main(String[] args) {
75 EventQueue.invokeLater(new Runnable() {
78 DelesteRandomSelector frame = new DelesteRandomSelector();
79 frame.setVisible(true);
80 } catch (Exception e) {
89 * "[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[LEVEL]: " +
95 public DelesteRandomSelector() {
96 if(!Settings.fileExists() && !Settings.writeDownJSON()) {
97 JOptionPane.showMessageDialog(this, "Exception:NullPointerException\nCannot Keep up! Please re-download this Application!");
98 throw new NullPointerException("FATAL: cannot continue!");
100 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[DEBUG]: " + "Loading Settings...");
101 property.setCheckLibraryUpdates(Settings.needToCheckLibraryUpdates());
102 property.setCheckVersion(Settings.needToCheckVersion());
103 property.setWindowWidth(Settings.getWindowWidth());
104 property.setWindowHeight(Settings.getWindowHeight());
105 property.setSongLimit(Settings.getSongsLimit());
106 property.setSaveScoreLog(Settings.saveScoreLog());
107 property.setOutputDebugSentences(Settings.outputDebugSentences());
108 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[DEBUG]: " + "Loading Settings done."
109 + "\nVersion Check: " + property.isCheckVersion()
110 + "\nLibrary Update Check: " + property.isCheckLibraryUpdates()
111 + "\nWindow Width: " + property.getWindowWidth()
112 + "\nWindow Height: " + property.getWindowHeight()
113 + "\nSong Limit: " + property.getSongLimit()
114 + "\nSaveScoreLog: " + property.isSaveScoreLog()
115 + "\nOutputDebugSentences: " + property.isOutputDebugSentences());
116 if(!Scraping.databaseExists()) {
117 JOptionPane.showMessageDialog(this, "楽曲データベースが見つかりませんでした。自動的に作成されます…\n注意:初回起動ではなく、かつ、Jarファイルと同じ階層に\"database.json\"というファイルが存在するにも関わらず\nこのポップアップが出た場合、開発者までご一報ください。\nGithub URL: https://github.com/hizumiaoba/DelesteRandomSelector/issues");
118 if(!Scraping.writeToJson(Scraping.getWholeData())) {
119 JOptionPane.showMessageDialog(this, "Exception:NullPointerException\\nCannot Keep up! Please re-download this Application!");
120 throw new NullPointerException("FATAL: cannot continue!");
122 } else if(Scraping.getFromJson().size() < Scraping.getWholeData().size()) {
123 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Update detected.Initiate update process...");
124 Path path = Paths.get(Scraping.getDBPath());
127 } catch (IOException e1) {
128 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[FATAL]: " + "Exception while updating library.\n" + e1.getLocalizedMessage());
129 JOptionPane.showMessageDialog(null, "データベースファイルをアップデートできませんでした。ファイルの削除権限があるかどうか確認してください。\n" + e1.getLocalizedMessage());
131 Scraping.writeToJson(Scraping.getWholeData());
132 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Library update completed.");
134 ExecutorService es = Executors.newWorkStealingPool();
135 CompletableFuture<ArrayList<Song>> getFromJsonFuture = CompletableFuture.supplyAsync(() -> Scraping.getFromJson(), es);
136 CompletableFuture<ArrayList<Song>> getWholeDataFuture = CompletableFuture.supplyAsync(() -> Scraping.getWholeData(), es);
137 getWholeDataFuture.thenAcceptAsync(list -> LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: Scraping data size:" + list.size()), es);
138 getFromJsonFuture.thenAcceptAsync(list -> LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: Currently database size:" + list.size()), es);
139 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[DEBUG]: " + "Version:" + getVersion());
140 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
141 setBounds(100, 100, 640, 360);
142 contentPane = new JPanel();
143 contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
144 setContentPane(contentPane);
145 contentPane.setLayout(new BorderLayout(0, 0));
147 panelNorth = new JPanel();
148 contentPane.add(panelNorth, BorderLayout.NORTH);
149 panelNorth.setLayout(new FormLayout(new ColumnSpec[] {
150 ColumnSpec.decode("max(302dlu;default)"),
151 FormSpecs.RELATED_GAP_COLSPEC,
152 ColumnSpec.decode("40px"),},
154 RowSpec.decode("20px"),}));
156 labelTitle = new JLabel("デレステ課題曲セレクター");
157 labelTitle.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 16));
158 panelNorth.add(labelTitle, "1, 1, center, top");
160 labelVersion = new JLabel(getVersion());
161 labelVersion.setFont(new Font("SansSerif", Font.BOLD, 12));
162 panelNorth.add(labelVersion, "3, 1, right, top");
164 panelWest = new JPanel();
165 contentPane.add(panelWest, BorderLayout.WEST);
166 panelWest.setLayout(new FormLayout(new ColumnSpec[] {
167 FormSpecs.LABEL_COMPONENT_GAP_COLSPEC,
168 ColumnSpec.decode("112px:grow"),},
170 FormSpecs.LINE_GAP_ROWSPEC,
171 RowSpec.decode("19px"),
172 FormSpecs.RELATED_GAP_ROWSPEC,
173 RowSpec.decode("max(12dlu;default)"),
174 FormSpecs.RELATED_GAP_ROWSPEC,
175 RowSpec.decode("max(12dlu;default)"),
176 FormSpecs.RELATED_GAP_ROWSPEC,
177 RowSpec.decode("12dlu"),
178 FormSpecs.RELATED_GAP_ROWSPEC,
179 RowSpec.decode("max(12dlu;default)"),
180 FormSpecs.RELATED_GAP_ROWSPEC,
181 RowSpec.decode("max(12dlu;default)"),
182 FormSpecs.RELATED_GAP_ROWSPEC,
183 RowSpec.decode("max(12dlu;default)"),
184 FormSpecs.RELATED_GAP_ROWSPEC,
185 RowSpec.decode("max(52dlu;default)"),}));
187 labelDifficulty = new JLabel("難易度選択");
188 labelDifficulty.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
189 panelWest.add(labelDifficulty, "2, 2, center, default");
191 comboDifficultySelect = new JComboBox();
192 comboDifficultySelect.setFont(new Font("Dialog", Font.BOLD, 12));
193 comboDifficultySelect.setModel(new DefaultComboBoxModel(new String[] {"指定なし", "DEBUT", "REGULAR", "PRO", "MASTER", "MASTER+", "ⓁMASTER+", "LIGHT", "TRICK", "PIANO", "FORTE", "WITCH"}));
194 panelWest.add(comboDifficultySelect, "2, 4, fill, default");
196 comboAttribute = new JComboBox();
197 comboAttribute.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
198 comboAttribute.setModel(new DefaultComboBoxModel(new String[] {"指定なし", "全タイプ", "キュート", "クール", "パッション"}));
199 panelWest.add(comboAttribute, "2, 6, fill, default");
201 labelLevel = new JLabel("楽曲Lv");
202 labelLevel.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
203 panelWest.add(labelLevel, "2, 8, center, default");
205 spinnerLevel = new JSpinner();
206 panelWest.add(spinnerLevel, "2, 10");
208 checkLessLv = new JCheckBox("指定Lv以下");
209 checkLessLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
210 panelWest.add(checkLessLv, "2, 12");
212 checkMoreLv = new JCheckBox("指定Lv以上");
213 checkMoreLv.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
214 panelWest.add(checkMoreLv, "2, 14");
216 labelLvCaution = new JLabel("<html><body>※以下以上両方にチェックをつけることで指定レベルのみ絞り込むことができます</body></html>");
217 labelLvCaution.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
218 panelWest.add(labelLvCaution, "2, 16, fill, fill");
220 panelEast = new JPanel();
221 contentPane.add(panelEast, BorderLayout.EAST);
222 panelEast.setLayout(new FormLayout(new ColumnSpec[] {
223 ColumnSpec.decode("98px"),},
225 RowSpec.decode("26px"),
226 FormSpecs.RELATED_GAP_ROWSPEC,
227 RowSpec.decode("max(36dlu;default)"),
228 FormSpecs.RELATED_GAP_ROWSPEC,
229 FormSpecs.DEFAULT_ROWSPEC,
230 FormSpecs.RELATED_GAP_ROWSPEC,
231 RowSpec.decode("max(30dlu;default)"),
232 FormSpecs.RELATED_GAP_ROWSPEC,
233 RowSpec.decode("max(15dlu;default)"),
234 FormSpecs.RELATED_GAP_ROWSPEC,
235 RowSpec.decode("max(11dlu;default)"),
236 FormSpecs.RELATED_GAP_ROWSPEC,
237 FormSpecs.DEFAULT_ROWSPEC,
238 FormSpecs.RELATED_GAP_ROWSPEC,
239 FormSpecs.DEFAULT_ROWSPEC,
240 FormSpecs.RELATED_GAP_ROWSPEC,
241 FormSpecs.DEFAULT_ROWSPEC,}));
243 btnImport = new JButton("<html><body>楽曲<br>絞り込み</body></html>");
244 btnImport.addActionListener(new ActionListener() {
245 public void actionPerformed(ActionEvent e) {
246 ArrayList<Song> fromJson = Scraping.getFromJson();
247 ArrayList<Song> specificlevelList = Scraping.getSpecificLevelSongs(fromJson, (Integer)spinnerLevel.getValue(), checkLessLv.isSelected(), checkMoreLv.isSelected());
248 ArrayList<Song> specificDifficultyList = Scraping.getSpecificDifficultySongs(specificlevelList, comboDifficultySelect.getSelectedItem().toString());
249 ArrayList<Song> specificAttributeList = Scraping.getSpecificAttributeSongs(specificDifficultyList, comboAttribute.getSelectedItem().toString());
250 if(!selectedSongsList.isEmpty())
251 selectedSongsList.clear();
252 selectedSongsList.addAll(specificAttributeList);
253 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " +"Songs are selected.We are Ready to go.");
254 JOptionPane.showMessageDialog(null, "絞り込み完了!「開始」をクリックすることで選曲できます!");
257 btnImport.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
258 panelEast.add(btnImport, "1, 3, fill, fill");
260 btnStart = new JButton("開始!");
261 btnStart.addActionListener(new ActionListener() {
262 public void actionPerformed(ActionEvent e) {
263 Random random = new Random(System.currentTimeMillis());
264 String[] tmp = new String[property.getSongLimit()];
265 integratorArray = new String[property.getSongLimit()];
266 for(int i = 0; i < property.getSongLimit(); i++) {
267 int randomInt = random.nextInt(selectedSongsList.size());
268 tmp[i] = (i + 1) + "曲目: " + selectedSongsList.get(randomInt).getAttribute() + " [" + selectedSongsList.get(randomInt).getDifficulty() + "]「" + selectedSongsList.get(randomInt).getName() + "」!(Lv:" + selectedSongsList.get(randomInt).getLevel() + ")\n\n";
269 integratorArray[i] = selectedSongsList.get(randomInt).getName() + "(Lv" + selectedSongsList.get(randomInt).getLevel() + ")\n";
271 String paneString = "";
272 for (int i = 0; i < tmp.length; i++) {
273 paneString = paneString + tmp[i];
275 paneString = paneString + "この" + tmp.length + "曲をプレイしましょう!!!";
276 textPane.setText(paneString);
277 integratorBool = true;
278 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "show up completed.");
281 btnStart.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
282 panelEast.add(btnStart, "1, 7, fill, fill");
284 btnTwitterIntegration = new JButton("Twitter連携");
285 btnTwitterIntegration.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 11));
286 btnTwitterIntegration.addActionListener(new ActionListener() {
287 public void actionPerformed(ActionEvent e) {
288 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Twitter Integration requested.Verify permission status.");
289 boolean authorizationStatus = TwitterIntegration.authorization();
290 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Permission Verifying completed.\nStatus: " + authorizationStatus);
291 System.out.print("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Construction status message...");
292 String updatedStatus = "デレステ課題曲セレクターで\n";
293 int lengthLimit = updatedStatus.length();
294 boolean isBroken = false;
295 if(!integratorBool) {
296 JOptionPane.showMessageDialog(null, "ちひろ「まだプレイを始めていないみたいですね」");
297 System.out.println();
300 for(int i = 0; i < integratorArray.length; i++) {
301 updatedStatus = updatedStatus + integratorArray[i];
302 lengthLimit += integratorArray[i].length();
303 if(lengthLimit > 69) {
309 updatedStatus = updatedStatus + "…その他数曲\nをプレイしました!\n#DelesteRandomSelector #デレステ ";
311 updatedStatus = updatedStatus + "をプレイしました!\n#DelesteRandomSelector #デレステ ";
313 System.out.println("completed.\n" + updatedStatus);
314 lengthLimit = updatedStatus.length();
315 if(authorizationStatus) {
316 int option = JOptionPane.showConfirmDialog(null, "Twitterへ以下の内容を投稿します。よろしいですか?\n\n" + updatedStatus + "\n\n文字数:" + lengthLimit);
317 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "User selected " + option);
319 case JOptionPane.OK_OPTION:
320 TwitterIntegration.PostTwitter(updatedStatus);
321 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "Success to update the status.");
322 JOptionPane.showMessageDialog(null, "投稿が完了しました。");
324 case JOptionPane.NO_OPTION:
325 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "There is no will to post.");
327 case JOptionPane.CANCEL_OPTION:
328 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " + "The Operation was canceled by user.");
334 System.out.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[WARN]: " + "seems to reject the permission.it should need try again.");
338 panelEast.add(btnTwitterIntegration, "1, 11");
340 btnExit = new JButton("終了");
341 btnExit.addActionListener(new ActionListener() {
342 public void actionPerformed(ActionEvent e) {
343 LimitedLog.println("[" + Thread.currentThread().toString() + "]:" + this.getClass() + ":[INFO]: " +"Requested Exit by Button");
344 if(getWholeDataFuture.isDone()) {
347 JOptionPane.showMessageDialog(null, "非同期処理が完了していません。少し時間が経ってからやり直してください。");
351 btnExit.setFont(new Font("UD デジタル 教科書体 NP-B", Font.BOLD, 13));
352 panelEast.add(btnExit, "1, 13");
354 panelCentre = new JPanel();
355 contentPane.add(panelCentre, BorderLayout.CENTER);
356 panelCentre.setLayout(new BorderLayout(0, 0));
358 textPane = new JTextPane();
359 textPane.setText("楽曲選択の手順\r\n1.難易度、属性、レベルを選択する\r\n2.「楽曲取り込み」ボタンを押す!\r\n3.「開始」ボタンを押す!\r\n4.選択された楽曲がここに表示されます!\r\n現在設定されている楽曲選択の最大数:" + property.getSongLimit());
360 textPane.setEditable(false);
361 panelCentre.add(textPane);
366 * アノテーションで記載されているバージョンを取得します
368 * @return アノテーションで定義されているバージョン
370 public static String getVersion() {
372 + getMajorVersion() + "."
373 + getMinorVersion() + "."
378 public static int getMajorVersion() {
379 Version version = (Version) DelesteRandomSelector.class.getAnnotation(Version.class);
380 return version.major();
383 public static int getMinorVersion() {
384 Version version = (Version) DelesteRandomSelector.class.getAnnotation(Version.class);
385 return version.minor();
388 public static int getPatchVersion() {
389 Version version = (Version) DelesteRandomSelector.class.getAnnotation(Version.class);
390 return version.patch();