mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #1100 from dmitrylyzo/playback_delayed_update-3
Add scheduled playback progress report
This commit is contained in:
commit
45bf7db7ae
2 changed files with 99 additions and 38 deletions
|
@ -1,6 +1,9 @@
|
||||||
define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) {
|
define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
/** Delay time in ms for reportPlayback logging */
|
||||||
|
const reportPlaybackLogDelay = 1e3;
|
||||||
|
|
||||||
function enableLocalPlaylistManagement(player) {
|
function enableLocalPlaylistManagement(player) {
|
||||||
|
|
||||||
if (player.getPlaylist) {
|
if (player.getPlaylist) {
|
||||||
|
@ -38,6 +41,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||||
events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]);
|
events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Last invoked method */
|
||||||
|
let reportPlaybackLastMethod;
|
||||||
|
|
||||||
|
/** Last invoke time of method */
|
||||||
|
let reportPlaybackLastTime;
|
||||||
|
|
||||||
function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) {
|
function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) {
|
||||||
|
|
||||||
if (!serverId) {
|
if (!serverId) {
|
||||||
|
@ -57,7 +66,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||||
addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId);
|
addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.debug(method + '-' + JSON.stringify(info));
|
const now = (new Date).getTime();
|
||||||
|
|
||||||
|
if (method !== reportPlaybackLastMethod || now - (reportPlaybackLastTime || 0) >= reportPlaybackLogDelay) {
|
||||||
|
console.debug(method + '-' + JSON.stringify(info));
|
||||||
|
reportPlaybackLastMethod = method;
|
||||||
|
reportPlaybackLastTime = now;
|
||||||
|
}
|
||||||
|
|
||||||
var apiClient = connectionManager.getApiClient(serverId);
|
var apiClient = connectionManager.getApiClient(serverId);
|
||||||
apiClient[method](info);
|
apiClient[method](info);
|
||||||
}
|
}
|
||||||
|
@ -3280,7 +3296,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||||
|
|
||||||
function onPlaybackVolumeChange(e) {
|
function onPlaybackVolumeChange(e) {
|
||||||
var player = this;
|
var player = this;
|
||||||
sendProgressUpdateDelayed(player, 'volumechange');
|
sendProgressUpdate(player, 'volumechange');
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRepeatModeChange(e) {
|
function onRepeatModeChange(e) {
|
||||||
|
@ -3375,16 +3391,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||||
|
|
||||||
pluginManager.ofType('mediaplayer').map(initMediaPlayer);
|
pluginManager.ofType('mediaplayer').map(initMediaPlayer);
|
||||||
|
|
||||||
/** Delay timer for sendProgressUpdate */
|
|
||||||
var sendProgressUpdateTimer;
|
|
||||||
|
|
||||||
/** Delay time in ms for sendProgressUpdate */
|
|
||||||
var sendProgressUpdateDelay = 700;
|
|
||||||
|
|
||||||
function sendProgressUpdate(player, progressEventName, reportPlaylist) {
|
function sendProgressUpdate(player, progressEventName, reportPlaylist) {
|
||||||
clearTimeout(sendProgressUpdateTimer);
|
|
||||||
sendProgressUpdateTimer = null;
|
|
||||||
|
|
||||||
if (!player) {
|
if (!player) {
|
||||||
throw new Error('player cannot be null');
|
throw new Error('player cannot be null');
|
||||||
}
|
}
|
||||||
|
@ -3409,14 +3416,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sendProgressUpdateDelayed(player, progressEventName, reportPlaylist) {
|
|
||||||
if (!sendProgressUpdateTimer) {
|
|
||||||
sendProgressUpdateTimer = setTimeout(function () {
|
|
||||||
sendProgressUpdate(player, progressEventName, reportPlaylist);
|
|
||||||
}, sendProgressUpdateDelay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLiveStreamMediaInfo(player, streamInfo, mediaSource, liveStreamId, serverId) {
|
function getLiveStreamMediaInfo(player, streamInfo, mediaSource, liveStreamId, serverId) {
|
||||||
|
|
||||||
console.debug('getLiveStreamMediaInfo');
|
console.debug('getLiveStreamMediaInfo');
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
define(["events", "appStorage"], function(events, appStorage) {
|
define(["events", "appStorage"], function(events, appStorage) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
/** Report rate limits in ms for different events */
|
||||||
|
const reportRateLimits = {
|
||||||
|
"timeupdate": 10000,
|
||||||
|
"volumechange": 3000
|
||||||
|
};
|
||||||
|
|
||||||
function redetectBitrate(instance) {
|
function redetectBitrate(instance) {
|
||||||
stopBitrateDetection(instance), instance.accessToken() && !1 !== instance.enableAutomaticBitrateDetection && setTimeout(redetectBitrateInternal.bind(instance), 6e3)
|
stopBitrateDetection(instance), instance.accessToken() && !1 !== instance.enableAutomaticBitrateDetection && setTimeout(redetectBitrateInternal.bind(instance), 6e3)
|
||||||
}
|
}
|
||||||
|
@ -231,6 +237,11 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cancelReportPlaybackProgressPromise(instance) {
|
||||||
|
if (typeof instance.reportPlaybackProgressCancel === "function") instance.reportPlaybackProgressCancel();
|
||||||
|
}
|
||||||
|
|
||||||
ApiClient.prototype.appName = function() {
|
ApiClient.prototype.appName = function() {
|
||||||
return this._appName
|
return this._appName
|
||||||
}, ApiClient.prototype.setRequestHeaders = function(headers) {
|
}, ApiClient.prototype.setRequestHeaders = function(headers) {
|
||||||
|
@ -1417,6 +1428,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||||
}, ApiClient.prototype.reportPlaybackStart = function(options) {
|
}, ApiClient.prototype.reportPlaybackStart = function(options) {
|
||||||
if (!options) throw new Error("null options");
|
if (!options) throw new Error("null options");
|
||||||
this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, stopBitrateDetection(this);
|
this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, stopBitrateDetection(this);
|
||||||
|
cancelReportPlaybackProgressPromise(this);
|
||||||
var url = this.getUrl("Sessions/Playing");
|
var url = this.getUrl("Sessions/Playing");
|
||||||
return this.ajax({
|
return this.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
@ -1426,25 +1438,74 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||||
})
|
})
|
||||||
}, ApiClient.prototype.reportPlaybackProgress = function(options) {
|
}, ApiClient.prototype.reportPlaybackProgress = function(options) {
|
||||||
if (!options) throw new Error("null options");
|
if (!options) throw new Error("null options");
|
||||||
var newPositionTicks = options.PositionTicks;
|
|
||||||
if ("timeupdate" === (options.EventName || "timeupdate")) {
|
const eventName = options.EventName || "timeupdate";
|
||||||
var now = (new Date).getTime(),
|
let reportRateLimitTime = reportRateLimits[eventName] || 0;
|
||||||
msSinceLastReport = now - (this.lastPlaybackProgressReport || 0);
|
|
||||||
if (msSinceLastReport <= 1e4) {
|
const now = (new Date).getTime();
|
||||||
if (!newPositionTicks) return Promise.resolve();
|
const msSinceLastReport = now - (this.lastPlaybackProgressReport || 0);
|
||||||
var expectedReportTicks = 1e4 * msSinceLastReport + (this.lastPlaybackProgressReportTicks || 0);
|
const newPositionTicks = options.PositionTicks;
|
||||||
if (Math.abs((newPositionTicks || 0) - expectedReportTicks) < 5e7) return Promise.resolve()
|
|
||||||
}
|
if (msSinceLastReport < reportRateLimitTime && eventName === "timeupdate" && newPositionTicks) {
|
||||||
this.lastPlaybackProgressReport = now
|
const expectedReportTicks = 1e4 * msSinceLastReport + (this.lastPlaybackProgressReportTicks || 0);
|
||||||
} else this.lastPlaybackProgressReport = 0;
|
if (Math.abs(newPositionTicks - expectedReportTicks) >= 5e7) reportRateLimitTime = 0;
|
||||||
this.lastPlaybackProgressReportTicks = newPositionTicks;
|
}
|
||||||
var url = this.getUrl("Sessions/Playing/Progress");
|
|
||||||
return this.ajax({
|
if (reportRateLimitTime < (this.reportPlaybackProgressTimeout !== undefined ? this.reportPlaybackProgressTimeout : 1e6)) {
|
||||||
type: "POST",
|
cancelReportPlaybackProgressPromise(this);
|
||||||
data: JSON.stringify(options),
|
}
|
||||||
contentType: "application/json",
|
|
||||||
url: url
|
this.lastPlaybackProgressOptions = options;
|
||||||
})
|
|
||||||
|
if (this.reportPlaybackProgressPromise) return Promise.resolve();
|
||||||
|
|
||||||
|
let instance = this;
|
||||||
|
let promise;
|
||||||
|
let cancelled = false;
|
||||||
|
|
||||||
|
let resetPromise = function () {
|
||||||
|
if (instance.reportPlaybackProgressPromise !== promise) return;
|
||||||
|
|
||||||
|
delete instance.lastPlaybackProgressOptions;
|
||||||
|
delete instance.reportPlaybackProgressTimeout;
|
||||||
|
delete instance.reportPlaybackProgressPromise;
|
||||||
|
delete instance.reportPlaybackProgressCancel;
|
||||||
|
};
|
||||||
|
|
||||||
|
let sendReport = function (lastOptions) {
|
||||||
|
resetPromise();
|
||||||
|
|
||||||
|
if (!lastOptions) throw new Error("null options");
|
||||||
|
|
||||||
|
instance.lastPlaybackProgressReport = (new Date).getTime();
|
||||||
|
instance.lastPlaybackProgressReportTicks = lastOptions.PositionTicks;
|
||||||
|
|
||||||
|
const url = instance.getUrl("Sessions/Playing/Progress");
|
||||||
|
return instance.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: JSON.stringify(lastOptions),
|
||||||
|
contentType: "application/json",
|
||||||
|
url: url
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let delay = Math.max(0, reportRateLimitTime - msSinceLastReport);
|
||||||
|
|
||||||
|
promise = new Promise((resolve, reject) => setTimeout(resolve, delay)).then(() => {
|
||||||
|
if (cancelled) return Promise.resolve();
|
||||||
|
return sendReport(instance.lastPlaybackProgressOptions);
|
||||||
|
}).finally(() => {
|
||||||
|
resetPromise();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.reportPlaybackProgressTimeout = reportRateLimitTime;
|
||||||
|
this.reportPlaybackProgressPromise = promise;
|
||||||
|
this.reportPlaybackProgressCancel = function () {
|
||||||
|
cancelled = true;
|
||||||
|
resetPromise();
|
||||||
|
};
|
||||||
|
|
||||||
|
return promise;
|
||||||
}, ApiClient.prototype.reportOfflineActions = function(actions) {
|
}, ApiClient.prototype.reportOfflineActions = function(actions) {
|
||||||
if (!actions) throw new Error("null actions");
|
if (!actions) throw new Error("null actions");
|
||||||
var url = this.getUrl("Sync/OfflineActions");
|
var url = this.getUrl("Sync/OfflineActions");
|
||||||
|
@ -1489,6 +1550,7 @@ define(["events", "appStorage"], function(events, appStorage) {
|
||||||
}, ApiClient.prototype.reportPlaybackStopped = function(options) {
|
}, ApiClient.prototype.reportPlaybackStopped = function(options) {
|
||||||
if (!options) throw new Error("null options");
|
if (!options) throw new Error("null options");
|
||||||
this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, redetectBitrate(this);
|
this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, redetectBitrate(this);
|
||||||
|
cancelReportPlaybackProgressPromise(this);
|
||||||
var url = this.getUrl("Sessions/Playing/Stopped");
|
var url = this.getUrl("Sessions/Playing/Stopped");
|
||||||
return this.ajax({
|
return this.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue