Skip to content

Commit d59e6a7

Browse files
authored
Merge pull request #40 from MrTimscampi/backports
Backport apiclient changes
2 parents 5ef711d + dac5f57 commit d59e6a7

File tree

1 file changed

+77
-25
lines changed

1 file changed

+77
-25
lines changed

src/apiClient.js

Lines changed: 77 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import events from './events';
22
import appStorage from './appStorage';
33

4+
/** Report rate limits in ms for different events */
5+
const reportRateLimits = {
6+
timeupdate: 10000,
7+
volumechange: 3000
8+
};
9+
410
function redetectBitrate(instance) {
511
stopBitrateDetection(instance);
612

@@ -104,6 +110,10 @@ function getFetchPromise(request) {
104110
return fetchWithTimeout(request.url, fetchRequest, request.timeout);
105111
}
106112

113+
function cancelReportPlaybackProgressPromise(instance) {
114+
if (typeof instance.reportPlaybackProgressCancel === 'function') instance.reportPlaybackProgressCancel();
115+
}
116+
107117
/**
108118
* Creates a new api client instance
109119
* @param {String} serverAddress
@@ -2962,6 +2972,7 @@ class ApiClient {
29622972
this.lastPlaybackProgressReportTicks = null;
29632973
stopBitrateDetection(this);
29642974

2975+
cancelReportPlaybackProgressPromise(this);
29652976
const url = this.getUrl('Sessions/Playing');
29662977

29672978
return this.ajax({
@@ -2982,39 +2993,79 @@ class ApiClient {
29822993
throw new Error('null options');
29832994
}
29842995

2996+
const eventName = options.EventName || 'timeupdate';
2997+
let reportRateLimitTime = reportRateLimits[eventName] || 0;
2998+
2999+
const now = new Date().getTime();
3000+
const msSinceLastReport = now - (this.lastPlaybackProgressReport || 0);
29853001
const newPositionTicks = options.PositionTicks;
29863002

2987-
if ((options.EventName || 'timeupdate') === 'timeupdate') {
2988-
const now = new Date().getTime();
2989-
const msSinceLastReport = now - (this.lastPlaybackProgressReport || 0);
3003+
if (msSinceLastReport < reportRateLimitTime && eventName === 'timeupdate' && newPositionTicks) {
3004+
const expectedReportTicks = 1e4 * msSinceLastReport + (this.lastPlaybackProgressReportTicks || 0);
3005+
if (Math.abs(newPositionTicks - expectedReportTicks) >= 5e7) reportRateLimitTime = 0;
3006+
}
29903007

2991-
if (msSinceLastReport <= 10000) {
2992-
if (!newPositionTicks) {
2993-
return Promise.resolve();
2994-
}
3008+
if (
3009+
reportRateLimitTime <
3010+
(this.reportPlaybackProgressTimeout !== undefined ? this.reportPlaybackProgressTimeout : 1e6)
3011+
) {
3012+
cancelReportPlaybackProgressPromise(this);
3013+
}
29953014

2996-
const expectedReportTicks = msSinceLastReport * 10000 + (this.lastPlaybackProgressReportTicks || 0);
3015+
this.lastPlaybackProgressOptions = options;
29973016

2998-
if (Math.abs((newPositionTicks || 0) - expectedReportTicks) < 5000 * 10000) {
2999-
return Promise.resolve();
3000-
}
3001-
}
3017+
/* eslint-disable-next-line @typescript-eslint/no-misused-promises */
3018+
if (this.reportPlaybackProgressPromise) return Promise.resolve();
30023019

3003-
this.lastPlaybackProgressReport = now;
3004-
} else {
3005-
// allow the next timeupdate
3006-
this.lastPlaybackProgressReport = 0;
3007-
}
3020+
let instance = this;
3021+
let promise;
3022+
let cancelled = false;
30083023

3009-
this.lastPlaybackProgressReportTicks = newPositionTicks;
3010-
const url = this.getUrl('Sessions/Playing/Progress');
3024+
let resetPromise = function () {
3025+
if (instance.reportPlaybackProgressPromise !== promise) return;
30113026

3012-
return this.ajax({
3013-
type: 'POST',
3014-
data: JSON.stringify(options),
3015-
contentType: 'application/json',
3016-
url
3017-
});
3027+
delete instance.lastPlaybackProgressOptions;
3028+
delete instance.reportPlaybackProgressTimeout;
3029+
delete instance.reportPlaybackProgressPromise;
3030+
delete instance.reportPlaybackProgressCancel;
3031+
};
3032+
3033+
let sendReport = function (lastOptions) {
3034+
resetPromise();
3035+
3036+
if (!lastOptions) throw new Error('null options');
3037+
3038+
instance.lastPlaybackProgressReport = new Date().getTime();
3039+
instance.lastPlaybackProgressReportTicks = lastOptions.PositionTicks;
3040+
3041+
const url = instance.getUrl('Sessions/Playing/Progress');
3042+
return instance.ajax({
3043+
type: 'POST',
3044+
data: JSON.stringify(lastOptions),
3045+
contentType: 'application/json',
3046+
url: url
3047+
});
3048+
};
3049+
3050+
let delay = Math.max(0, reportRateLimitTime - msSinceLastReport);
3051+
3052+
promise = new Promise((resolve, reject) => setTimeout(resolve, delay))
3053+
.then(() => {
3054+
if (cancelled) return Promise.resolve();
3055+
return sendReport(instance.lastPlaybackProgressOptions);
3056+
})
3057+
.finally(() => {
3058+
resetPromise();
3059+
});
3060+
3061+
this.reportPlaybackProgressTimeout = reportRateLimitTime;
3062+
this.reportPlaybackProgressPromise = promise;
3063+
this.reportPlaybackProgressCancel = function () {
3064+
cancelled = true;
3065+
resetPromise();
3066+
};
3067+
3068+
return promise;
30183069
}
30193070

30203071
reportOfflineActions(actions) {
@@ -3102,6 +3153,7 @@ class ApiClient {
31023153
this.lastPlaybackProgressReportTicks = null;
31033154
redetectBitrate(this);
31043155

3156+
cancelReportPlaybackProgressPromise(this);
31053157
const url = this.getUrl('Sessions/Playing/Stopped');
31063158

31073159
return this.ajax({

0 commit comments

Comments
 (0)