Skip to content

Commit b063d6e

Browse files
committed
Pull Request Wil-B#8: Prevented foobar crash when exiting during AllMusic fetching
2 parents 4ca106b + e05c964 commit b063d6e

File tree

2 files changed

+134
-97
lines changed

2 files changed

+134
-97
lines changed

scripts/allmusic.js

Lines changed: 133 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,101 @@
11
'use strict';
22

3-
function onStateChange(resolve, reject, func = null) { // credit regorxxx
4-
if (this !== null) { // this is xmlhttp bound
5-
if (this.Status === 200) {
6-
if (func) {return func(this.ResponseText, this);}
7-
else {return resolve(this.ResponseText);}
8-
} else {
9-
if (!func) {return reject(this.ResponseText);}
10-
}
11-
} else if (!func) {return reject({status: 408, responseText: this.ResponseText})}; // 408 Request Timeout
12-
return null;
13-
}
3+
class RequestAllmusic {
4+
constructor() {
5+
this.request = null;
6+
this.timer = null;
7+
this.checkResponse = null;
8+
}
149

15-
// May be used to async run a func for the response or as promise
16-
function send({method = 'GET', URL, body = void(0), func = null, requestHeader = [/*[header, type]*/], bypassCache = false, timeout = 5000}) { // credit regorxxx
17-
return new Promise(async (resolve, reject) => {
18-
const xmlhttp = new ActiveXObject('WinHttp.WinHttpRequest.5.1');
19-
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#bypassing_the_cache
20-
// Add ('&' + new Date().getTime()) to URLS to avoid caching
21-
xmlhttp.Open(
22-
method,
23-
URL + (bypassCache
24-
? (/\?/.test(URL) ? '&' : '?') + new Date().getTime()
25-
: ''),
26-
true
27-
);
28-
requestHeader.forEach((pair) => {
29-
if (!pair[0] || !pair[1]) {console.log('HTTP Headers missing: ' + pair); return;}
30-
xmlhttp.SetRequestHeader(...pair);
31-
});
32-
if (bypassCache) {
33-
xmlhttp.SetRequestHeader('Cache-Control', 'private');
34-
xmlhttp.SetRequestHeader('Pragma', 'no-cache');
35-
xmlhttp.SetRequestHeader('cache', 'no-store');
36-
xmlhttp.SetRequestHeader('If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT');
10+
abortRequest() {
11+
if (!this.request) return;
12+
clearTimeout(this.timer);
13+
clearInterval(this.checkResponse);
14+
this.request.Abort();
15+
this.request = null;
16+
this.timer = null;
17+
this.checkResponse = null;
18+
}
19+
20+
onStateChange(resolve, reject, func = null) { // credit regorxxx
21+
if (this.request !== null) {
22+
if (this.request.Status === 200) {
23+
return func ? func(this.request.ResponseText, this.request) : resolve(this.request.ResponseText);
24+
} else if (!func) {
25+
return reject(this.request.ResponseText);
26+
}
27+
} else if (!func) {
28+
return reject({ status: 408, responseText: 'Request Timeout' });
3729
}
38-
xmlhttp.SetTimeouts(timeout, timeout, timeout, timeout);
39-
xmlhttp.Send(method === 'POST' ? body : void(0));
40-
// Add a timer for timeout
41-
const timer = setTimeout(() => {
42-
try {
43-
xmlhttp.WaitForResponse(-1);
44-
onStateChange.call(xmlhttp, resolve, reject, func);
45-
} catch (e) {
46-
let status = 400;
47-
if (e.message.indexOf('0x80072ee7') !== -1) {status = 400;} // No network
48-
else if (e.message.indexOf('0x80072ee2') !== -1) {status = 408;} // No response
49-
else if (e.message.indexOf('0x8000000a') !== -1) {status = 408;} // Not finished response
50-
xmlhttp.Abort(); return reject({status, responseText: e.message});
30+
return null;
31+
}
32+
33+
send({ method = 'GET', URL, body = void (0), func = null, requestHeader = [], bypassCache = false, timeout = 5000 }) { // credit regorxxx
34+
this.abortRequest();
35+
36+
return new Promise((resolve, reject) => {
37+
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#bypassing_the_cache
38+
// Add ('&' + new Date().getTime()) to URLS to avoid caching
39+
const fullUrl = URL + (bypassCache ? (/\?/.test(URL) ? '&' : '?') + new Date().getTime() : '');
40+
this.request = new ActiveXObject('WinHttp.WinHttpRequest.5.1');
41+
this.request.Open(method, fullUrl, true);
42+
43+
requestHeader.forEach(pair => {
44+
if (!pair[0] || !pair[1]) {
45+
console.log(`HTTP Headers missing: ${pair}`);
46+
return;
47+
}
48+
this.request.SetRequestHeader(...pair);
49+
});
50+
51+
if (bypassCache) {
52+
this.request.SetRequestHeader('Cache-Control', 'private');
53+
this.request.SetRequestHeader('Pragma', 'no-cache');
54+
this.request.SetRequestHeader('Cache', 'no-store');
55+
this.request.SetRequestHeader('If-Modified-Since', 'Sat, 1 Jan 2000 00:00:00 GMT');
5156
}
52-
}, timeout);
53-
// Check for response periodically to not block the UI
54-
const checkResponse = setInterval(() => {
55-
try {xmlhttp.Status && xmlhttp.ResponseText} catch(e) {return;}
56-
clearTimeout(timer);
57-
clearInterval(checkResponse);
58-
onStateChange.call(xmlhttp, resolve, reject, func);
59-
}, 30);
60-
});
57+
58+
this.request.SetTimeouts(timeout, timeout, timeout, timeout);
59+
this.request.Send(method === 'POST' ? body : void (0));
60+
61+
this.timer = setTimeout(() => {
62+
clearInterval(this.checkResponse);
63+
try {
64+
this.request.WaitForResponse(-1);
65+
this.onStateChange(resolve, reject, func);
66+
} catch (e) {
67+
let status = 400;
68+
if (e.message.indexOf('0x80072ee7') !== -1) {
69+
status = 400;
70+
} else if (e.message.indexOf('0x80072ee2') !== -1) {
71+
status = 408;
72+
} else if (e.message.indexOf('0x8000000a') !== -1) {
73+
status = 408;
74+
}
75+
this.abortRequest();
76+
reject({ status, responseText: e.message });
77+
}
78+
}, timeout);
79+
80+
this.checkResponse = setInterval(() => {
81+
let response;
82+
try {
83+
response = this.request.Status && this.request.ResponseText;
84+
} catch (e) {}
85+
if (!response) return;
86+
this.onStateChange(resolve, reject, func);
87+
}, 30);
88+
});
89+
}
6190
}
6291

92+
/**
93+
* The instance of `RequestAllmusic` class for biography AllMusic request operations.
94+
* @typedef {RequestAllmusic}
95+
* @global
96+
*/
97+
const allMusicReq = new RequestAllmusic();
98+
6399
class DldAllmusicBio {
64100
init(URL, referer, p_title, p_artist, p_fo_bio, p_pth_bio, p_force) {
65101
this.active = '';
@@ -79,17 +115,17 @@ class DldAllmusicBio {
79115

80116
this.search(!this.title ? 'artist' : 'id', URL, referer);
81117
}
82-
118+
83119
search(item, URL, referer) {
84120
let i = 0;
85121
let list = [];
86122
switch (item) {
87123
case 'id':
88-
send({
89-
method: 'GET',
124+
allMusicReq.send({
125+
method: 'GET',
90126
bypassCache: this.force,
91127
requestHeader: [
92-
['referer', referer],
128+
['referer', referer],
93129
['user-agent', this.userAgent]
94130
],
95131
URL: URL
@@ -118,13 +154,13 @@ class DldAllmusicBio {
118154
if (!$.file(this.pth_bio)) $.trace('allmusic biography: ' + this.artist + ': not found', true);
119155
});
120156
break;
121-
157+
122158
case 'artist':
123-
send({
124-
method: 'GET',
159+
allMusicReq.send({
160+
method: 'GET',
125161
bypassCache: this.force,
126162
requestHeader: [
127-
['referer', referer],
163+
['referer', referer],
128164
['user-agent', this.userAgent]
129165
],
130166
URL: URL
@@ -163,13 +199,13 @@ class DldAllmusicBio {
163199
if (!$.file(this.pth_bio)) $.trace('allmusic biography: ' + this.artist + ': not found', true);
164200
});
165201
break;
166-
202+
167203
case 'biography':
168-
send({
169-
method: 'GET',
204+
allMusicReq.send({
205+
method: 'GET',
170206
bypassCache: this.force,
171207
requestHeader: [
172-
['referer', referer],
208+
['referer', referer],
173209
['user-agent', this.userAgent]
174210
],
175211
URL: URL
@@ -185,11 +221,11 @@ class DldAllmusicBio {
185221
break;
186222

187223
case 'artistPage':
188-
send({
189-
method: 'GET',
224+
allMusicReq.send({
225+
method: 'GET',
190226
bypassCache: this.force,
191227
requestHeader: [
192-
['referer', referer],
228+
['referer', referer],
193229
['user-agent', this.userAgent]
194230
],
195231
URL: URL
@@ -250,11 +286,11 @@ class DldAllmusicRev {
250286
let list = [];
251287
switch (item) {
252288
case 'id':
253-
send({
254-
method: 'GET',
289+
allMusicReq.send({
290+
method: 'GET',
255291
bypassCache: this.force,
256292
requestHeader: [
257-
['referer', referer],
293+
['referer', referer],
258294
['user-agent', this.userAgent]
259295
],
260296
URL: URL
@@ -300,13 +336,13 @@ class DldAllmusicRev {
300336
$.trace('allmusic review: ' + this.album + ' / ' + this.albumArtist + ': not found', true);
301337
});
302338
break;
303-
339+
304340
case 'review':
305-
send({
306-
method: 'GET',
341+
allMusicReq.send({
342+
method: 'GET',
307343
bypassCache: this.force,
308344
requestHeader: [
309-
['referer', referer],
345+
['referer', referer],
310346
['user-agent', this.userAgent]
311347
],
312348
URL: URL
@@ -334,11 +370,11 @@ class DldAllmusicRev {
334370
break;
335371

336372
case 'moodsThemes':
337-
send({
338-
method: 'GET',
373+
allMusicReq.send({
374+
method: 'GET',
339375
bypassCache: this.force,
340376
requestHeader: [
341-
['referer', referer],
377+
['referer', referer],
342378
['user-agent', this.userAgent]
343379
],
344380
URL: URL
@@ -376,11 +412,11 @@ class DldAllmusicRev {
376412
break;
377413

378414
case 'titlePage':
379-
send({
380-
method: 'GET',
415+
allMusicReq.send({
416+
method: 'GET',
381417
bypassCache: this.force,
382418
requestHeader: [
383-
['referer', referer],
419+
['referer', referer],
384420
['user-agent', this.userAgent]
385421
],
386422
URL: URL
@@ -431,26 +467,26 @@ class DldAllmusicRev {
431467
this.saveTrackReview();
432468
}
433469
doc.close();
434-
470+
435471
if (this.dn_type.includes('+biography')) {
436472
if (this.artistLink) {
437473
return this.search('biography', this.artistLink + '/biographyAjax', this.artistLink);
438-
}
474+
}
439475
}
440476
},
441477
(error) => {
442478
if (this.dn_type.includes('+biography')) {
443479
if (this.artistLink) {
444480
return this.search('biography', this.artistLink + '/biographyAjax', this.artistLink);
445-
}
481+
}
446482
}
447483
$.trace('allmusic review / biography: ' + this.album + ' / ' + this.albumArtist + ': not found' + ' Status error: ' + JSON.stringify(error), true)
448484
}
449485
).catch((error) => {
450486
if (this.dn_type.includes('+biography')) {
451487
if (this.artistLink) {
452488
return this.search('biography', this.artistLink + '/biographyAjax', this.artistLink);
453-
}
489+
}
454490
}
455491
server.updateNotFound('Bio ' + cfg.partialMatch + ' ' + this.pth_rev);
456492
server.updateNotFound('Rev ' + cfg.partialMatch + ' ' + this.pth_rev + (this.dn_type != 'track' ? '' : ' ' + this.album + ' ' + this.albumArtist));
@@ -459,29 +495,29 @@ class DldAllmusicRev {
459495
break;
460496

461497
case 'biography':
462-
send({
463-
method: 'GET',
498+
allMusicReq.send({
499+
method: 'GET',
464500
bypassCache: this.force,
465501
requestHeader: [
466-
['referer', referer],
502+
['referer', referer],
467503
['user-agent', this.userAgent]
468504
],
469505
URL: URL
470506
}).then(
471507
(response) => {
472508
parse.amBio(this, response);
473509
if (this.artistLink) this.search('artistPage', this.artistLink, 'https://allmusic.com');
474-
},
510+
},
475511
(error) => {}
476512
).catch((error) => {});
477513
break;
478514

479515
case 'artistPage':
480-
send({
481-
method: 'GET',
516+
allMusicReq.send({
517+
method: 'GET',
482518
bypassCache: this.force,
483519
requestHeader: [
484-
['referer', referer],
520+
['referer', referer],
485521
['user-agent', this.userAgent]
486522
],
487523
URL: URL
@@ -513,7 +549,7 @@ class DldAllmusicRev {
513549
} else {
514550
server.updateNotFound('Rev ' + cfg.partialMatch + ' ' + this.pth_rev);
515551
$.trace('allmusic this.review: ' + this.album + ' / ' + this.albumArtist + ': not found', true);
516-
}
552+
}
517553
}
518554
saveTrackReview() {
519555
const text = $.jsonParse(this.pth_rev, {}, 'file');
@@ -569,11 +605,11 @@ class Parse {
569605

570606
that.biographyGenre = that.biographyGenre.length ? 'Genre: ' + that.biographyGenre.join('\u200b, ') : '';
571607
that.groupMembers = that.groupMembers.length ? 'Group Members: ' + that.groupMembers.join('\u200b, ') : '';
572-
608+
573609
this.saveBiography(that, artist, album, title, fo_bio, pth_bio, pth_rev);
574610
doc.close();
575611
}
576-
612+
577613
amBio(that, responseText) {
578614
doc.open();
579615
const div = doc.createElement('div');

scripts/callbacks.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ function on_script_unload() {
534534
window.NotifyOthers(`bio_scriptUnload${ppt.serverName}`, 0);
535535
timer.clear(timer.img);
536536
}
537+
allMusicReq.abortRequest();
537538
but.on_script_unload();
538539
txt.deactivateTooltip();
539540
}

0 commit comments

Comments
 (0)