daydreamer-json commited on
Commit
e99018f
·
verified ·
1 Parent(s): 1cb68a5

Test build

Browse files
Files changed (3) hide show
  1. index.html +125 -5
  2. script.js +360 -6
  3. style.css +1 -1
index.html CHANGED
@@ -8,6 +8,7 @@
8
  <!-- JavaScript load -->
9
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
10
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
 
11
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.bundle.min.js"></script>
12
  <!-- CSS load -->
13
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css">
@@ -72,8 +73,7 @@
72
  </div>
73
  </div>
74
  <hr class="my-4">
75
- <h3 class="user-select-none">Track listing test</h3>
76
- <button id="trackListingTestButton" class="btn btn-primary mb-3" type="button"><i class="bi bi-menu-button-wide me-1"></i>List track</button>
77
  <div class="fetchingDataNowLabel user-select-none d-none">
78
  <div class="d-inline-flex align-items-center mb-3">
79
  <div class="spinner-border text-primary me-2" role="status">
@@ -89,8 +89,128 @@
89
  <div class="flex-fill w-100">Track</div>
90
  </button>
91
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  <hr class="my-4">
93
- <h3 class="user-select-none">Fetch data output testing</h3>
 
 
94
  <button id="loadDatabaseTestButton" class="btn btn-primary mb-3" type="button"><i class="bi bi-database-down me-1"></i>Load Database</button>
95
  <div class="fetchingDataNowLabel user-select-none d-none">
96
  <div class="d-inline-flex align-items-center mb-3">
@@ -118,8 +238,8 @@
118
  <hr class="my-4">
119
  <iframe data-aa='2297053' src='//acceptable.a-ads.com/2297053' style='border:0px; padding:0; width:100%; height:100%; overflow:hidden; background-color: transparent;'></iframe>
120
  <footer>
121
- <p><small class="text-body-tertiary user-select-none">This page using: Bootstrap, Axios, CryptoJS, A-ADS, Inter, Fira Code, Noto Sans JP</small></p>
122
- <p><small class="text-body-tertiary user-select-none">(C) 2024 daydreamer-json, and other contributer. All rights reserved.</small></p>
123
  </footer>
124
  </div>
125
  <script src="script.js"></script>
 
8
  <!-- JavaScript load -->
9
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
10
  <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js"></script>
11
+ <script src="https://cdn.jsdelivr.net/npm/moment@2/moment.min.js"></script>
12
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.bundle.min.js"></script>
13
  <!-- CSS load -->
14
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css">
 
73
  </div>
74
  </div>
75
  <hr class="my-4">
76
+ <h3 class="user-select-none">Track List</h3>
 
77
  <div class="fetchingDataNowLabel user-select-none d-none">
78
  <div class="d-inline-flex align-items-center mb-3">
79
  <div class="spinner-border text-primary me-2" role="status">
 
89
  <div class="flex-fill w-100">Track</div>
90
  </button>
91
  </div>
92
+ <div class="modal fade user-select-none" id="trackInfoModal" tabindex="-1">
93
+ <div class="modal-dialog modal-lg modal-fullscreen-md-down modal-dialog-scrollable">
94
+ <div class="modal-content">
95
+ <div class="modal-header">
96
+ <h1 class="modal-title fs-5" id="trackInfoModalLabel"><i class="bi bi-file-earmark-music me-2"></i>Track Info</h1>
97
+ <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
98
+ </div>
99
+ <div class="modal-body">
100
+ <h3>Download</h3>
101
+ <table class="table table-sm table-responsive table-hover table-borderless align-middle">
102
+ <tbody id="trackInfoModal-downloadTable">
103
+ </tbody>
104
+ </table>
105
+ <h3>Metadata</h3>
106
+ <h4>General</h4>
107
+ <table class="table table-sm table-responsive table-hover table-borderless align-middle">
108
+ <tbody>
109
+ <tr>
110
+ <td>Track Title</td>
111
+ <td id="trackInfoModal-metadataTable-trackTitle">---</td>
112
+ </tr>
113
+ <tr>
114
+ <td>Artists</td>
115
+ <td id="trackInfoModal-metadataTable-artists">---</td>
116
+ </tr>
117
+ <tr>
118
+ <td>Lyricist</td>
119
+ <td id="trackInfoModal-metadataTable-lyricist">---</td>
120
+ </tr>
121
+ <tr>
122
+ <td>Composer</td>
123
+ <td id="trackInfoModal-metadataTable-composer">---</td>
124
+ </tr>
125
+ <tr>
126
+ <td>Arranger</td>
127
+ <td id="trackInfoModal-metadataTable-arranger">---</td>
128
+ </tr>
129
+ <tr>
130
+ <td>Track Title (Latin)</td>
131
+ <td id="trackInfoModal-metadataTable-trackTitleLatin">---</td>
132
+ </tr>
133
+ <tr>
134
+ <td>Artists (Latin)</td>
135
+ <td id="trackInfoModal-metadataTable-artistsLatin">---</td>
136
+ </tr>
137
+ <tr>
138
+ <td>Lyricist (Latin)</td>
139
+ <td id="trackInfoModal-metadataTable-lyricistLatin">---</td>
140
+ </tr>
141
+ <tr>
142
+ <td>Composer (Latin)</td>
143
+ <td id="trackInfoModal-metadataTable-composerLatin">---</td>
144
+ </tr>
145
+ <tr>
146
+ <td>Arranger (Latin)</td>
147
+ <td id="trackInfoModal-metadataTable-arrangerLatin">---</td>
148
+ </tr>
149
+ <tr>
150
+ <td>Track Duration (Readable)</td>
151
+ <td id="trackInfoModal-metadataTable-trackDurationReadable">---</td>
152
+ </tr>
153
+ <tr>
154
+ <td>Track Duration (MS)</td>
155
+ <td id="trackInfoModal-metadataTable-trackDurationMsec">---</td>
156
+ </tr>
157
+ <tr>
158
+ <td>Track Duration (Samples)</td>
159
+ <td id="trackInfoModal-metadataTable-trackDurationSamples">---</td>
160
+ </tr>
161
+ </tbody>
162
+ </table>
163
+ <table class="table table-sm table-responsive table-hover table-borderless align-middle">
164
+ <tbody>
165
+ <tr>
166
+ <td>Album Title</td>
167
+ <td id="trackInfoModal-metadataTable-albumTitle">---</td>
168
+ </tr>
169
+ <tr>
170
+ <td>Album Artist</td>
171
+ <td id="trackInfoModal-metadataTable-albumArtist">---</td>
172
+ </tr>
173
+ <tr>
174
+ <td>Album Title (Latin)</td>
175
+ <td id="trackInfoModal-metadataTable-albumTitleLatin">---</td>
176
+ </tr>
177
+ <tr>
178
+ <td>Album Artist (Latin)</td>
179
+ <td id="trackInfoModal-metadataTable-albumArtistLatin">---</td>
180
+ </tr>
181
+ <tr>
182
+ <td>Album Released</td>
183
+ <td id="trackInfoModal-metadataTable-albumReleaseDate">YYYY/MM/DD</td>
184
+ </tr>
185
+ <tr>
186
+ <td>Album Barcode</td>
187
+ <td id="trackInfoModal-metadataTable-albumBarcode">Sample Number</td>
188
+ </tr>
189
+ <tr>
190
+ <td>Album Copyright</td>
191
+ <td id="trackInfoModal-metadataTable-albumCopyright">---</td>
192
+ </tr>
193
+ </tbody>
194
+ </table>
195
+ <h4>External Links</h4>
196
+ <table id="trackInfoModal-externalLinkTableRoot" class="table table-sm table-responsive table-hover table-borderless align-middle">
197
+ <tbody id="trackInfoModal-externalLinkTable">
198
+ </tbody>
199
+ </table>
200
+ <h4>Cover Artwork Images</h4>
201
+ <div id="trackInfoModal-coverArtLinkDiv">
202
+ </div>
203
+ </div>
204
+ <div class="modal-footer">
205
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
206
+ </div>
207
+ </div>
208
+ </div>
209
+ </div>
210
  <hr class="my-4">
211
+ <h3 class="user-select-none">Debug Area</h3>
212
+ <button id="trackListingTestButton" class="btn btn-primary mb-3" type="button"><i class="bi bi-menu-button-wide me-1"></i>List track</button>
213
+ <h4 class="user-select-none">Fetch data output testing</h3>
214
  <button id="loadDatabaseTestButton" class="btn btn-primary mb-3" type="button"><i class="bi bi-database-down me-1"></i>Load Database</button>
215
  <div class="fetchingDataNowLabel user-select-none d-none">
216
  <div class="d-inline-flex align-items-center mb-3">
 
238
  <hr class="my-4">
239
  <iframe data-aa='2297053' src='//acceptable.a-ads.com/2297053' style='border:0px; padding:0; width:100%; height:100%; overflow:hidden; background-color: transparent;'></iframe>
240
  <footer>
241
+ <p class="my-1"><small class="text-body-tertiary user-select-none">This page using: Bootstrap, Axios, CryptoJS, A-ADS, Inter, Fira Code, Noto Sans JP</small></p>
242
+ <p class="my-1"><small class="text-body-tertiary user-select-none">(C) 2024 daydreamer-json, and other contributer. All rights reserved.</small></p>
243
  </footer>
244
  </div>
245
  <script src="script.js"></script>
script.js CHANGED
@@ -42,11 +42,13 @@ window.addEventListener('load', async function(){
42
  await loadRequiredDatabase();
43
  await decryptConfig();
44
  pushToTrackListGroupUi();
 
45
  });
46
 
47
  document.querySelector('#loadDatabaseTestButton').addEventListener('click', async function() {
48
  console.log('loadDatabaseTestButton clicked!');
49
  await loadRequiredDatabase();
 
50
  });
51
 
52
  document.querySelector('#trackListingTestButton').addEventListener('click', () => {
@@ -87,6 +89,7 @@ function pushToTrackListGroupUi () {
87
  let divTrackNodeEl = document.createElement('div');
88
  buttonNodeEl.classList.add('list-group-item', 'list-group-item-action', 'd-flex');
89
  buttonNodeEl.setAttribute('type', 'button');
 
90
  divArtistNodeEl.classList.add('flex-fill', 'w-100');
91
  divAlbumNodeEl.classList.add('flex-fill', 'w-100');
92
  divTrackNodeEl.classList.add('flex-fill', 'w-100');
@@ -100,11 +103,205 @@ function pushToTrackListGroupUi () {
100
  buttonNodeEl.appendChild(divArtistNodeEl);
101
  buttonNodeEl.appendChild(divAlbumNodeEl);
102
  buttonNodeEl.appendChild(divTrackNodeEl);
 
 
 
103
  trackAllListGroup.appendChild(buttonNodeEl);
104
  });
105
  });
106
  }
107
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  // ========== 設定画面のイベントリスナー登録など ==========
109
 
110
  document.querySelector('#settingsApplyButton').addEventListener('click', () => {appSettingsApply()});
@@ -175,8 +372,6 @@ async function loadRequiredDatabase () {
175
  'headers': apiConnectDefaultHeader,
176
  'timeout': internalConfig.network.timeout
177
  });
178
- console.log(apiDataMasterDB);
179
- console.log(apiDataConfig);
180
  if (apiDataMasterDB) {
181
  document.querySelector('#databaseTestInfoCodeEl').innerHTML = `OK (Time: ${Math.ceil(apiDataMasterDB.apiConnectionTime)} ms)`;
182
  document.querySelector('#databaseTestOutputCodeEl').innerHTML = JSON.stringify(apiDataMasterDB.response, '', ' ');
@@ -188,6 +383,157 @@ async function loadRequiredDatabase () {
188
  });
189
  }
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  // ========== MasterDB/Configの暗号化を解く ==========
192
 
193
  async function decryptConfig () {
@@ -213,8 +559,7 @@ function loadAppSettingsFromLocalStorage () {
213
  if (localStorage.hasOwnProperty(appSettingsStorageName)) {
214
  appSettingsSaveData = JSON.parse(CryptoJS.enc.Base64.parse(localStorage.getItem(appSettingsStorageName)).toString(CryptoJS.enc.Utf8));
215
  console.warn(`LocalStorage key detected`);
216
- console.log(`Loaded appSettings:`);
217
- console.log(appSettingsSaveData);
218
  } else {
219
  appSettingsSaveData = appSettingsSaveDataDefault;
220
  console.warn(`LocalStorage key not found\nUsing default settings`);
@@ -233,6 +578,15 @@ function checkAppSettingsExistsOnStorage () {
233
  function writeAppSettingsToLocalStorage () {
234
  // CryptoJS.enc.Utf8.parseを使うことでCryptoJS内部形式を強制
235
  localStorage.setItem(appSettingsStorageName, CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(appSettingsSaveData))));
236
- console.log(`Wrote appSettings:`);
237
- console.log(appSettingsSaveData);
 
 
 
 
 
 
 
 
 
238
  }
 
42
  await loadRequiredDatabase();
43
  await decryptConfig();
44
  pushToTrackListGroupUi();
45
+ loadTrackInfoModal('018d2827-8ae1-7a2d-823e-2557a01e70ca');
46
  });
47
 
48
  document.querySelector('#loadDatabaseTestButton').addEventListener('click', async function() {
49
  console.log('loadDatabaseTestButton clicked!');
50
  await loadRequiredDatabase();
51
+ await decryptConfig();
52
  });
53
 
54
  document.querySelector('#trackListingTestButton').addEventListener('click', () => {
 
89
  let divTrackNodeEl = document.createElement('div');
90
  buttonNodeEl.classList.add('list-group-item', 'list-group-item-action', 'd-flex');
91
  buttonNodeEl.setAttribute('type', 'button');
92
+ buttonNodeEl.setAttribute('data-track-uuid', trackObject.uuid);
93
  divArtistNodeEl.classList.add('flex-fill', 'w-100');
94
  divAlbumNodeEl.classList.add('flex-fill', 'w-100');
95
  divTrackNodeEl.classList.add('flex-fill', 'w-100');
 
103
  buttonNodeEl.appendChild(divArtistNodeEl);
104
  buttonNodeEl.appendChild(divAlbumNodeEl);
105
  buttonNodeEl.appendChild(divTrackNodeEl);
106
+ buttonNodeEl.addEventListener('click', () => {
107
+ loadTrackInfoModal(trackObject.uuid);
108
+ });
109
  trackAllListGroup.appendChild(buttonNodeEl);
110
  });
111
  });
112
  }
113
 
114
+ // ========== trackInfoModalの処理 ==========
115
+
116
+ function loadTrackInfoModal (trackUuid) {
117
+ const albumParsedObject = getParsedAlbumObjectFromAlbumUuid(getAlbumUuidFromTrackUuid(trackUuid));
118
+ const trackParsedObject = albumParsedObject.tracks.find((obj) => obj.uuid === trackUuid);
119
+ document.getElementById('trackInfoModal-metadataTable-trackTitle').innerHTML = trackParsedObject.title;
120
+ if (trackParsedObject.titleLatin === null) {
121
+ document.getElementById('trackInfoModal-metadataTable-trackTitleLatin').parentNode.classList.add('d-none');
122
+ } else {
123
+ document.getElementById('trackInfoModal-metadataTable-trackTitleLatin').parentNode.classList.remove('d-none');
124
+ document.getElementById('trackInfoModal-metadataTable-trackTitleLatin').innerHTML = trackParsedObject.titleLatin;
125
+ }
126
+ document.getElementById('trackInfoModal-metadataTable-artists').innerHTML = trackParsedObject.artist.map((obj) => obj.name).join(', ');
127
+ if (trackParsedObject.artist.some((obj) => obj.nameLatin === null)) {
128
+ document.getElementById('trackInfoModal-metadataTable-artistsLatin').parentNode.classList.add('d-none');
129
+ } else {
130
+ document.getElementById('trackInfoModal-metadataTable-artistsLatin').parentNode.classList.remove('d-none');
131
+ document.getElementById('trackInfoModal-metadataTable-artistsLatin').innerHTML = trackParsedObject.artist.map((obj) => obj.nameLatin).join(', ');
132
+ }
133
+ if (trackParsedObject.lyricist === null) {
134
+ document.getElementById('trackInfoModal-metadataTable-lyricist').parentNode.classList.add('d-none');
135
+ document.getElementById('trackInfoModal-metadataTable-lyricistLatin').parentNode.classList.add('d-none');
136
+ } else {
137
+ document.getElementById('trackInfoModal-metadataTable-lyricist').parentNode.classList.remove('d-none');
138
+ document.getElementById('trackInfoModal-metadataTable-lyricist').innerHTML = trackParsedObject.lyricist.map((obj) => obj.name).join(', ');
139
+ if (trackParsedObject.lyricist.some((obj) => obj.nameLatin === null)) {
140
+ document.getElementById('trackInfoModal-metadataTable-lyricistLatin').parentNode.classList.add('d-none');
141
+ } else {
142
+ document.getElementById('trackInfoModal-metadataTable-lyricistLatin').parentNode.classList.remove('d-none');
143
+ document.getElementById('trackInfoModal-metadataTable-lyricistLatin').innerHTML = trackParsedObject.lyricist.map((obj) => obj.nameLatin).join(', ');
144
+ }
145
+ }
146
+ if (trackParsedObject.composer === null) {
147
+ document.getElementById('trackInfoModal-metadataTable-composer').parentNode.classList.add('d-none');
148
+ document.getElementById('trackInfoModal-metadataTable-composerLatin').parentNode.classList.add('d-none');
149
+ } else {
150
+ document.getElementById('trackInfoModal-metadataTable-composer').parentNode.classList.remove('d-none');
151
+ document.getElementById('trackInfoModal-metadataTable-composer').innerHTML = trackParsedObject.composer.map((obj) => obj.name).join(', ');
152
+ if (trackParsedObject.composer.some((obj) => obj.nameLatin === null)) {
153
+ document.getElementById('trackInfoModal-metadataTable-composerLatin').parentNode.classList.add('d-none');
154
+ } else {
155
+ document.getElementById('trackInfoModal-metadataTable-composerLatin').parentNode.classList.remove('d-none');
156
+ document.getElementById('trackInfoModal-metadataTable-composerLatin').innerHTML = trackParsedObject.composer.map((obj) => obj.nameLatin).join(', ');
157
+ }
158
+ }
159
+ if (trackParsedObject.arranger === null) {
160
+ document.getElementById('trackInfoModal-metadataTable-arranger').parentNode.classList.add('d-none');
161
+ document.getElementById('trackInfoModal-metadataTable-arrangerLatin').parentNode.classList.add('d-none');
162
+ } else {
163
+ document.getElementById('trackInfoModal-metadataTable-arranger').parentNode.classList.remove('d-none');
164
+ document.getElementById('trackInfoModal-metadataTable-arranger').innerHTML = trackParsedObject.arranger.map((obj) => obj.name).join(', ');
165
+ if (trackParsedObject.arranger.some((obj) => obj.nameLatin === null)) {
166
+ document.getElementById('trackInfoModal-metadataTable-arrangerLatin').parentNode.classList.add('d-none');
167
+ } else {
168
+ document.getElementById('trackInfoModal-metadataTable-arrangerLatin').parentNode.classList.remove('d-none');
169
+ document.getElementById('trackInfoModal-metadataTable-arrangerLatin').innerHTML = trackParsedObject.arranger.map((obj) => obj.nameLatin).join(', ');
170
+ }
171
+ }
172
+ document.getElementById('trackInfoModal-metadataTable-trackDurationReadable').innerHTML = msecToReadableTime(trackParsedObject.durationMsecs);
173
+ document.getElementById('trackInfoModal-metadataTable-trackDurationMsec').innerHTML = `${trackParsedObject.durationMsecs} ms`;
174
+ document.getElementById('trackInfoModal-metadataTable-trackDurationSamples').innerHTML = `${trackParsedObject.durationSamples} samples`;
175
+ document.getElementById('trackInfoModal-metadataTable-albumTitle').innerHTML = albumParsedObject.title;
176
+ if (albumParsedObject.titleLatin === null) {
177
+ document.getElementById('trackInfoModal-metadataTable-albumTitleLatin').parentNode.classList.add('d-none');
178
+ } else {
179
+ document.getElementById('trackInfoModal-metadataTable-albumTitleLatin').parentNode.classList.remove('d-none');
180
+ document.getElementById('trackInfoModal-metadataTable-albumTitleLatin').innerHTML = albumParsedObject.titleLatin;
181
+ }
182
+ document.getElementById('trackInfoModal-metadataTable-albumArtist').innerHTML = albumParsedObject.artist.map((obj) => obj.name).join(', ');
183
+ if (albumParsedObject.artist.some((obj) => obj.nameLatin === null)) {
184
+ document.getElementById('trackInfoModal-metadataTable-albumArtistLatin').parentNode.classList.add('d-none');
185
+ } else {
186
+ document.getElementById('trackInfoModal-metadataTable-albumArtistLatin').parentNode.classList.remove('d-none');
187
+ document.getElementById('trackInfoModal-metadataTable-albumArtistLatin').innerHTML = albumParsedObject.artist.map((obj) => obj.nameLatin).join(', ');
188
+ }
189
+ document.getElementById('trackInfoModal-metadataTable-albumReleaseDate').innerHTML = moment(albumParsedObject.releaseDate).format('YYYY/MM/DD');
190
+ document.getElementById('trackInfoModal-metadataTable-albumBarcode').innerHTML = albumParsedObject.barCode;
191
+ document.getElementById('trackInfoModal-metadataTable-albumCopyright').innerHTML = albumParsedObject.copyright;
192
+ while(document.getElementById('trackInfoModal-externalLinkTable').firstChild) {
193
+ document.getElementById('trackInfoModal-externalLinkTable').removeChild(document.getElementById('trackInfoModal-externalLinkTable').firstChild);
194
+ }
195
+ while(document.getElementById('trackInfoModal-coverArtLinkDiv').firstChild) {
196
+ document.getElementById('trackInfoModal-coverArtLinkDiv').removeChild(document.getElementById('trackInfoModal-coverArtLinkDiv').firstChild);
197
+ }
198
+ while(document.getElementById('trackInfoModal-downloadTable').firstChild) {
199
+ document.getElementById('trackInfoModal-downloadTable').removeChild(document.getElementById('trackInfoModal-downloadTable').firstChild);
200
+ }
201
+ if (albumParsedObject.link.itunes !== null || albumParsedObject.link.spotify !== null) {
202
+ let temp_extLinkAlbumTrEl = document.createElement('tr');
203
+ let temp_extLinkAlbumTdKeyEl = document.createElement('td');
204
+ let temp_extLinkAlbumTdValueEl = document.createElement('td');
205
+ let temp_extLinkAlbumA1El = document.createElement('a');
206
+ let temp_extLinkAlbumA2El = document.createElement('a');
207
+ temp_extLinkAlbumTdKeyEl.innerHTML = 'Album Link';
208
+ if (albumParsedObject.link.itunes !== null) {
209
+ temp_extLinkAlbumA1El.classList.add('btn','btn-outline-primary','btn-sm','me-1');
210
+ temp_extLinkAlbumA1El.setAttribute('href', `https://music.apple.com/album/${albumParsedObject.link.itunes}`);
211
+ temp_extLinkAlbumA1El.setAttribute('role', 'button');
212
+ temp_extLinkAlbumA1El.setAttribute('target', '_blank');
213
+ temp_extLinkAlbumA1El.setAttribute('rel', 'noopener noreferrer');
214
+ temp_extLinkAlbumA1El.innerHTML = 'Apple Music';
215
+ temp_extLinkAlbumTdValueEl.appendChild(temp_extLinkAlbumA1El);
216
+ }
217
+ if (albumParsedObject.link.spotify !== null) {
218
+ temp_extLinkAlbumA2El.classList.add('btn','btn-outline-primary','btn-sm','me-1');
219
+ temp_extLinkAlbumA2El.setAttribute('href', `https://open.spotify.com/album/${albumParsedObject.link.spotify}`);
220
+ temp_extLinkAlbumA2El.setAttribute('role', 'button');
221
+ temp_extLinkAlbumA2El.setAttribute('target', '_blank');
222
+ temp_extLinkAlbumA2El.setAttribute('rel', 'noopener noreferrer');
223
+ temp_extLinkAlbumA2El.innerHTML = 'Spotify';
224
+ temp_extLinkAlbumTdValueEl.appendChild(temp_extLinkAlbumA2El);
225
+ }
226
+ temp_extLinkAlbumTrEl.appendChild(temp_extLinkAlbumTdKeyEl);
227
+ temp_extLinkAlbumTrEl.appendChild(temp_extLinkAlbumTdValueEl);
228
+ document.getElementById('trackInfoModal-externalLinkTable').appendChild(temp_extLinkAlbumTrEl);
229
+ }
230
+ albumParsedObject.coverArts.forEach((obj1) => {
231
+ obj1.format.forEach((obj2) => {
232
+ let temp_coverArtAEl = document.createElement('a');
233
+ temp_coverArtAEl.classList.add('btn','btn-primary','btn-sm','me-1','mb-1');
234
+ temp_coverArtAEl.setAttribute('href', `${apiDataConfig.response.config.decrypted.rawMediaUrlBase64}/media/${albumParsedObject.uuid}/${obj1.fileName}.${obj2.extension}`);
235
+ temp_coverArtAEl.setAttribute('role', 'button');
236
+ temp_coverArtAEl.setAttribute('target', '_blank');
237
+ temp_coverArtAEl.setAttribute('rel', 'noopener noreferrer');
238
+ temp_coverArtAEl.innerHTML = `${obj2.name} ${obj1.height}px`;
239
+ document.getElementById('trackInfoModal-coverArtLinkDiv').appendChild(temp_coverArtAEl);
240
+ });
241
+ });
242
+ let temp_codecListImported = new Array();
243
+ if (albumParsedObject.isAllTrackSameCodecs === false) {temp_codecListImported = trackParsedObject.codecs} else {temp_codecListImported = albumParsedObject.codecs}
244
+ temp_codecListImported.forEach((obj) => {
245
+ let temp_dlTrEl = document.createElement('tr');
246
+ let temp_dlTdCodecEl = document.createElement('td');
247
+ let temp_dlTdInfoEl = document.createElement('td');
248
+ let temp_dlTdBtnEl = document.createElement('td');
249
+ let temp_dlButtonGroupEl = document.createElement('div');
250
+ let temp_dlButtonEl = document.createElement('button');
251
+ let temp_dlButtonExtEl = document.createElement('a');
252
+ let temp_dlButtonIconEl = document.createElement('i');
253
+ let temp_dlButtonExtIconEl = document.createElement('i');
254
+ let temp_codecBitrateTemporal = null;
255
+ temp_dlTdCodecEl.innerHTML = obj.nameBasic;
256
+ temp_dlTdCodecEl.setAttribute('data-bs-toggle', 'tooltip');
257
+ temp_dlTdCodecEl.setAttribute('data-bs-title', obj.nameLong);
258
+ if ((obj.bitRateAvg !== null && obj.bitRateMax !== null) || (obj.bitRateAvg !== null && obj.bitRateMax === null)) {
259
+ temp_codecBitrateTemporal = obj.bitRateAvg;
260
+ } else {
261
+ temp_codecBitrateTemporal = obj.bitRateMax;
262
+ }
263
+ if (obj.bitDepth === null) {
264
+ temp_dlTdInfoEl.innerHTML = `${obj.sampleRate / 1000}kHz ${obj.channelCount}ch ${temp_codecBitrateTemporal / 1000}kbps`;
265
+ } else {
266
+ temp_dlTdInfoEl.innerHTML = `${obj.bitDepth}bit ${obj.sampleRate / 1000}kHz ${obj.channelCount}ch ${temp_codecBitrateTemporal / 1000}kbps`;
267
+ }
268
+ if (obj.isOriginal === true) {
269
+ temp_dlButtonEl.classList.add('btn', 'btn-primary');
270
+ temp_dlButtonExtEl.classList.add('btn', 'btn-primary', 'text-center');
271
+ } else {
272
+ temp_dlButtonEl.classList.add('btn', 'btn-secondary');
273
+ temp_dlButtonExtEl.classList.add('btn', 'btn-secondary', 'text-center');
274
+ }
275
+ temp_dlButtonEl.setAttribute('type', 'button');
276
+ temp_dlButtonEl.addEventListener('click', async () => {
277
+ await downloadAudioDataToBlob (trackParsedObject.uuid, obj.uuid)
278
+ })
279
+ temp_dlButtonExtEl.setAttribute('href', `${apiDataConfig.response.config.decrypted.rawMediaUrlBase64}/media/${albumParsedObject.uuid}/${obj.path}/${trackParsedObject.uuid}.${obj.extension}`);
280
+ temp_dlButtonExtEl.setAttribute('role', 'button');
281
+ temp_dlButtonExtEl.setAttribute('target', '_blank');
282
+ temp_dlButtonExtEl.setAttribute('rel', 'noopener noreferrer');
283
+ temp_dlButtonGroupEl.setAttribute('role', 'group');
284
+ temp_dlButtonGroupEl.classList.add('btn-group');
285
+ temp_dlButtonIconEl.classList.add('bi', 'bi-download');
286
+ temp_dlButtonExtIconEl.classList.add('bi', 'bi-box-arrow-up-right');
287
+ temp_dlTdBtnEl.classList.add('text-end');
288
+ temp_dlButtonEl.appendChild(temp_dlButtonIconEl);
289
+ temp_dlButtonExtEl.appendChild(temp_dlButtonExtIconEl);
290
+ temp_dlButtonGroupEl.appendChild(temp_dlButtonEl);
291
+ temp_dlButtonGroupEl.appendChild(temp_dlButtonExtEl);
292
+ temp_dlTdBtnEl.appendChild(temp_dlButtonGroupEl);
293
+ temp_dlTrEl.appendChild(temp_dlTdCodecEl);
294
+ temp_dlTrEl.appendChild(temp_dlTdInfoEl);
295
+ temp_dlTrEl.appendChild(temp_dlTdBtnEl);
296
+ document.getElementById('trackInfoModal-downloadTable').appendChild(temp_dlTrEl);
297
+ });
298
+ const bootstrapTooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
299
+ const bootstrapTooltipList = [...bootstrapTooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
300
+ console.log(trackParsedObject);
301
+ const trackInfoModal = new bootstrap.Modal(document.getElementById('trackInfoModal'));
302
+ trackInfoModal.show();
303
+ }
304
+
305
  // ========== 設定画面のイベントリスナー登録など ==========
306
 
307
  document.querySelector('#settingsApplyButton').addEventListener('click', () => {appSettingsApply()});
 
372
  'headers': apiConnectDefaultHeader,
373
  'timeout': internalConfig.network.timeout
374
  });
 
 
375
  if (apiDataMasterDB) {
376
  document.querySelector('#databaseTestInfoCodeEl').innerHTML = `OK (Time: ${Math.ceil(apiDataMasterDB.apiConnectionTime)} ms)`;
377
  document.querySelector('#databaseTestOutputCodeEl').innerHTML = JSON.stringify(apiDataMasterDB.response, '', ' ');
 
383
  });
384
  }
385
 
386
+ // ========== データベース内部検索などの処理 ==========
387
+
388
+ function getAlbumUuidFromTrackUuid (trackUuid) {
389
+ let albumUuid = null;
390
+ apiDataMasterDB.response.data.albums.forEach((albumObject) => {
391
+ if (albumObject.tracks.some((trackObject) => trackObject.uuid === trackUuid)) {
392
+ albumUuid = albumObject.uuid;
393
+ }
394
+ });
395
+ return albumUuid;
396
+ }
397
+
398
+ function getDbObjectFromUuid (uuid, type) {
399
+ switch (type) {
400
+ case 'album':
401
+ if (apiDataMasterDB.response.data.albums.some((albumObject) => albumObject.uuid === uuid)) {
402
+ return apiDataMasterDB.response.data.albums.filter((albumObject) => albumObject.uuid === uuid)[0];
403
+ } else {
404
+ return null;
405
+ }
406
+ case 'track':
407
+ apiDataMasterDB.response.data.albums.forEach((albumObject) => {
408
+ if (albumObject.tracks.some((trackObject) => trackObject.uuid === uuid)) {
409
+ return albumObject.tracks.filter((trackObject) => trackObject.uuid === uuid)[0];
410
+ }
411
+ });
412
+ return null;
413
+ case 'artist':
414
+ if (apiDataMasterDB.response.data.artists.some((artistObject) => artistObject.uuid === uuid)) {
415
+ return apiDataMasterDB.response.data.artists.filter((artistObject) => artistObject.uuid === uuid)[0];
416
+ } else {
417
+ return null;
418
+ }
419
+ case 'codec':
420
+ if (apiDataMasterDB.response.data.codecs.some((codecObject) => codecObject.uuid === uuid)) {
421
+ return apiDataMasterDB.response.data.codecs.filter((codecObject) => codecObject.uuid === uuid)[0];
422
+ } else {
423
+ return null;
424
+ }
425
+ default:
426
+ throw new Error ('unexpected type');
427
+ }
428
+ }
429
+
430
+ function getParsedAlbumObjectFromAlbumUuid (uuid) {
431
+ const rawAlbumObject = getDbObjectFromUuid(uuid, 'album');
432
+ let outputObject = JSON.parse(JSON.stringify(rawAlbumObject));
433
+ outputObject.artist = new Array();
434
+ rawAlbumObject.artist.forEach((artistUuidStr) => {
435
+ outputObject.artist.push(getDbObjectFromUuid(artistUuidStr, 'artist'));
436
+ });
437
+ if (rawAlbumObject.isAllTrackSameCodecs === true) {
438
+ outputObject.codecs = new Array();
439
+ rawAlbumObject.codecs.forEach((codecObj) => {
440
+ let temp_searchedCodecObj = new Object();
441
+ temp_searchedCodecObj = getDbObjectFromUuid(codecObj.uuid, 'codec');
442
+ temp_searchedCodecObj.isOriginal = codecObj.isOriginal;
443
+ temp_searchedCodecObj.path = codecObj.path;
444
+ outputObject.codecs.push(temp_searchedCodecObj);
445
+ });
446
+ }
447
+ if (rawAlbumObject.isCoverArtsUseDefault === true) {
448
+ outputObject.coverArts = apiDataMasterDB.response.data.coverArtDefaults;
449
+ }
450
+ outputObject.tracks = new Array();
451
+ rawAlbumObject.tracks.forEach((rawTrackObj) => {
452
+ let temp_outputTrackObj = new Object();
453
+ temp_outputTrackObj = JSON.parse(JSON.stringify(rawTrackObj));
454
+ temp_outputTrackObj.artist = new Array();
455
+ rawTrackObj.artist.forEach((artistUuidStr) => {
456
+ temp_outputTrackObj.artist.push(getDbObjectFromUuid(artistUuidStr, 'artist'));
457
+ });
458
+ if (rawTrackObj.lyricist !== null) {
459
+ temp_outputTrackObj.lyricist = new Array();
460
+ rawTrackObj.lyricist.forEach((artistUuidStr) => {
461
+ temp_outputTrackObj.lyricist.push(getDbObjectFromUuid(artistUuidStr, 'artist'));
462
+ });
463
+ }
464
+ if (rawTrackObj.composer !== null) {
465
+ temp_outputTrackObj.composer = new Array();
466
+ rawTrackObj.composer.forEach((artistUuidStr) => {
467
+ temp_outputTrackObj.composer.push(getDbObjectFromUuid(artistUuidStr, 'artist'));
468
+ });
469
+ }
470
+ if (rawTrackObj.arranger !== null) {
471
+ temp_outputTrackObj.arranger = new Array();
472
+ rawTrackObj.arranger.forEach((artistUuidStr) => {
473
+ temp_outputTrackObj.arranger.push(getDbObjectFromUuid(artistUuidStr, 'artist'));
474
+ });
475
+ }
476
+ if (rawAlbumObject.isAllTrackSameCodecs === false || rawTrackObj.codecs !== null) {
477
+ temp_outputTrackObj.codecs = new Array();
478
+ rawTrackObj.codecs.forEach((codecObj) => {
479
+ let temp_searchedCodecObj2 = new Object();
480
+ temp_searchedCodecObj2 = getDbObjectFromUuid(codecObj.uuid, 'codec');
481
+ temp_searchedCodecObj2.isOriginal = codecObj.isOriginal;
482
+ temp_searchedCodecObj2.path = codecObj.path;
483
+ temp_outputTrackObj.codecs.push(temp_searchedCodecObj2);
484
+ });
485
+ temp_outputTrackObj.durationMsecs = (rawTrackObj.durationSamples / temp_outputTrackObj.codecs.filter((t) => t.isOriginal === true)[0].sampleRate) * 1000;
486
+ } else {
487
+ temp_outputTrackObj.durationMsecs = (rawTrackObj.durationSamples / outputObject.codecs.filter((t) => t.isOriginal === true)[0].sampleRate) * 1000;
488
+ }
489
+ outputObject.tracks.push(temp_outputTrackObj);
490
+ });
491
+ let temp_albumTotalDurationSamples = 0;
492
+ let temp_albumTotalDurationMsecs = 0;
493
+ for (let i = 0; i < rawAlbumObject.tracks.length; i++) {
494
+ temp_albumTotalDurationSamples += outputObject.tracks[i].durationSamples;
495
+ temp_albumTotalDurationMsecs += outputObject.tracks[i].durationMsecs;
496
+ }
497
+ outputObject.durationSamples = temp_albumTotalDurationSamples;
498
+ outputObject.durationMsecs = temp_albumTotalDurationMsecs;
499
+ return outputObject;
500
+ }
501
+
502
+ // ========== ファイルをDLしてBlob化、ブラウザに開かせる ==========
503
+
504
+ async function downloadAudioDataToBlob (trackUuid, codecUuid) {
505
+ const albumParsedObject = getParsedAlbumObjectFromAlbumUuid(getAlbumUuidFromTrackUuid(trackUuid));
506
+ const trackParsedObject = albumParsedObject.tracks.find((obj) => obj.uuid === trackUuid);
507
+ let codecParsedObject = null;
508
+ if (albumParsedObject.isAllTrackSameCodecs === false) {
509
+ codecParsedObject = trackParsedObject.codecs.find((obj) => obj.uuid === codecUuid);
510
+ } else {
511
+ codecParsedObject = albumParsedObject.codecs.find((obj) => obj.uuid === codecUuid);
512
+ }
513
+ const axiosRes = await apiConnect ({
514
+ 'method': 'get',
515
+ 'url': `${apiDataConfig.response.config.decrypted.rawMediaUrlBase64}/media/${albumParsedObject.uuid}/${codecParsedObject.path}/${trackParsedObject.uuid}.${codecParsedObject.extension}`,
516
+ 'headers': apiConnectDefaultHeader,
517
+ 'timeout': internalConfig.network.timeout,
518
+ 'responseType': 'blob'
519
+ });
520
+ console.log(`File downloaded to Blob\nDownload time: ${axiosRes.apiConnectionTime} ms`);
521
+ const blobUrl = window.URL.createObjectURL(response.data);
522
+ const link = document.createElement('a');
523
+ let saveFileName = null;
524
+ if (trackParsedObject.titleFileName !== null) {
525
+ saveFileName = `${trackParsedObject.disc}_${('00' + trackParsedObject.index).slice(-2)}_${trackParsedObject.titleFileName}.${codecParsedObject.extension}`;
526
+ } else {
527
+ saveFileName = `${trackParsedObject.disc}_${('00' + trackParsedObject.index).slice(-2)}_${trackParsedObject.title}.${codecParsedObject.extension}`;
528
+ }
529
+ link.href = blobUrl;
530
+ link.setAttribute('download', saveFileName);
531
+ link.classList.add('d-none');
532
+ document.body.appendChild(link);
533
+ link.click();
534
+ document.body.removeChild(link);
535
+ }
536
+
537
  // ========== MasterDB/Configの暗号化を解く ==========
538
 
539
  async function decryptConfig () {
 
559
  if (localStorage.hasOwnProperty(appSettingsStorageName)) {
560
  appSettingsSaveData = JSON.parse(CryptoJS.enc.Base64.parse(localStorage.getItem(appSettingsStorageName)).toString(CryptoJS.enc.Utf8));
561
  console.warn(`LocalStorage key detected`);
562
+ console.log(`Loaded appSettings:\n${JSON.stringify(appSettingsSaveData)}`);
 
563
  } else {
564
  appSettingsSaveData = appSettingsSaveDataDefault;
565
  console.warn(`LocalStorage key not found\nUsing default settings`);
 
578
  function writeAppSettingsToLocalStorage () {
579
  // CryptoJS.enc.Utf8.parseを使うことでCryptoJS内部形式を強制
580
  localStorage.setItem(appSettingsStorageName, CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(JSON.stringify(appSettingsSaveData))));
581
+ console.log(`Wrote appSettings:\n${JSON.stringify(appSettingsSaveData)}`);
582
+ }
583
+
584
+ // ========== その他使い回す汎用関数など ==========
585
+
586
+ function msecToReadableTime (msec) {
587
+ let msecCeiled = Math.ceil(msec);
588
+ let sec = msec / 1000;
589
+ let min = ('00' + Math.floor(sec / 60)).slice(-2);
590
+ let secPart = ('00' + Math.floor(sec % 60)).slice(-2);
591
+ return `${min}:${secPart}.${('000' + msecCeiled % 1000).slice(-3)}`;
592
  }
style.css CHANGED
@@ -1,4 +1,4 @@
1
- body {
2
  font-family: 'Inter', 'Noto Sans JP', system-ui, sans-serif
3
  }
4
  pre, code {
 
1
+ body, .tooltip {
2
  font-family: 'Inter', 'Noto Sans JP', system-ui, sans-serif
3
  }
4
  pre, code {