mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-18 03:18:19 -07:00
update components
This commit is contained in:
parent
42d4a8cfaa
commit
1d176e480f
@ -14,12 +14,12 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"ignore": [],
|
"ignore": [],
|
||||||
"version": "1.4.409",
|
"version": "1.4.411",
|
||||||
"_release": "1.4.409",
|
"_release": "1.4.411",
|
||||||
"_resolution": {
|
"_resolution": {
|
||||||
"type": "version",
|
"type": "version",
|
||||||
"tag": "1.4.409",
|
"tag": "1.4.411",
|
||||||
"commit": "6a6a35e136f70989be0a63846b02bff62bab6367"
|
"commit": "50fdd44728ec2a1faa1aaf44ccb16df821b8295f"
|
||||||
},
|
},
|
||||||
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
|
"_source": "https://github.com/MediaBrowser/emby-webcomponents.git",
|
||||||
"_target": "^1.2.1",
|
"_target": "^1.2.1",
|
||||||
|
BIN
dashboard-ui/bower_components/emby-webcomponents/htmlaudioplayer/blank.mp3
vendored
Normal file
BIN
dashboard-ui/bower_components/emby-webcomponents/htmlaudioplayer/blank.mp3
vendored
Normal file
Binary file not shown.
367
dashboard-ui/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js
vendored
Normal file
367
dashboard-ui/bower_components/emby-webcomponents/htmlaudioplayer/plugin.js
vendored
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
define(['events', 'browser', 'pluginManager', 'apphost'], function (events, browser, pluginManager, appHost) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
self.name = 'Html Audio Player';
|
||||||
|
self.type = 'mediaplayer';
|
||||||
|
self.id = 'htmlaudioplayer';
|
||||||
|
|
||||||
|
// Let any players created by plugins take priority
|
||||||
|
self.priority = 1;
|
||||||
|
|
||||||
|
var mediaElement;
|
||||||
|
var currentSrc;
|
||||||
|
|
||||||
|
self.canPlayMediaType = function (mediaType) {
|
||||||
|
|
||||||
|
return (mediaType || '').toLowerCase() === 'audio';
|
||||||
|
};
|
||||||
|
|
||||||
|
self.getDeviceProfile = function () {
|
||||||
|
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
|
||||||
|
require(['browserdeviceprofile'], function (profileBuilder) {
|
||||||
|
|
||||||
|
var profile = profileBuilder({
|
||||||
|
supportsCustomSeeking: true
|
||||||
|
});
|
||||||
|
resolve(profile);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
self.currentSrc = function () {
|
||||||
|
return currentSrc;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.play = function (options) {
|
||||||
|
|
||||||
|
var elem = createMediaElement();
|
||||||
|
|
||||||
|
var val = options.url;
|
||||||
|
|
||||||
|
elem.crossOrigin = getCrossOriginValue(options.mediaSource);
|
||||||
|
elem.title = options.title;
|
||||||
|
|
||||||
|
// Opera TV guidelines suggest using source elements, so let's do that if we have a valid mimeType
|
||||||
|
if (options.mimeType && browser.operaTv) {
|
||||||
|
|
||||||
|
// Need to do this or we won't be able to restart a new stream
|
||||||
|
if (elem.currentSrc) {
|
||||||
|
elem.src = '';
|
||||||
|
elem.removeAttribute('src');
|
||||||
|
}
|
||||||
|
|
||||||
|
elem.innerHTML = '<source src="' + val + '" type="' + options.mimeType + '">';
|
||||||
|
} else {
|
||||||
|
elem.src = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSrc = val;
|
||||||
|
|
||||||
|
// Chrome now returns a promise
|
||||||
|
var promise = elem.play();
|
||||||
|
|
||||||
|
if (promise && promise.then) {
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
function getCrossOriginValue(mediaSource) {
|
||||||
|
|
||||||
|
return 'anonymous';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save this for when playback stops, because querying the time at that point might return 0
|
||||||
|
self.currentTime = function (val) {
|
||||||
|
|
||||||
|
if (mediaElement) {
|
||||||
|
if (val != null) {
|
||||||
|
mediaElement.currentTime = val / 1000;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (mediaElement.currentTime || 0) * 1000;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.duration = function (val) {
|
||||||
|
|
||||||
|
if (mediaElement) {
|
||||||
|
return mediaElement.duration * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function supportsFade() {
|
||||||
|
|
||||||
|
if (browser.tv) {
|
||||||
|
// Not working on tizen.
|
||||||
|
// We could possibly enable on other tv's, but all smart tv browsers tend to be pretty primitive
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.stop = function (destroyPlayer, reportEnded) {
|
||||||
|
|
||||||
|
cancelFadeTimeout();
|
||||||
|
|
||||||
|
var elem = mediaElement;
|
||||||
|
var src = currentSrc;
|
||||||
|
|
||||||
|
if (elem && src) {
|
||||||
|
|
||||||
|
if (!destroyPlayer || !supportsFade()) {
|
||||||
|
|
||||||
|
if (!elem.paused) {
|
||||||
|
elem.pause();
|
||||||
|
}
|
||||||
|
elem.src = '';
|
||||||
|
elem.innerHTML = '';
|
||||||
|
elem.removeAttribute("src");
|
||||||
|
onEndedInternal(reportEnded);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
var originalVolume = elem.volume;
|
||||||
|
|
||||||
|
return fade(elem, function () {
|
||||||
|
|
||||||
|
}).then(function () {
|
||||||
|
if (!elem.paused) {
|
||||||
|
elem.pause();
|
||||||
|
}
|
||||||
|
elem.src = '';
|
||||||
|
elem.innerHTML = '';
|
||||||
|
elem.removeAttribute("src");
|
||||||
|
|
||||||
|
elem.volume = originalVolume;
|
||||||
|
onEndedInternal(reportEnded);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
self.destroy = function () {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
var fadeTimeout;
|
||||||
|
|
||||||
|
function fade(elem) {
|
||||||
|
|
||||||
|
var newVolume = Math.max(0, elem.volume - 0.15);
|
||||||
|
console.log('fading volume to ' + newVolume);
|
||||||
|
elem.volume = newVolume;
|
||||||
|
|
||||||
|
if (!elem.volume) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
|
||||||
|
cancelFadeTimeout();
|
||||||
|
|
||||||
|
fadeTimeout = setTimeout(function () {
|
||||||
|
fade(elem).then(resolve, reject);
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelFadeTimeout() {
|
||||||
|
var timeout = fadeTimeout;
|
||||||
|
if (timeout) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
fadeTimeout = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.pause = function () {
|
||||||
|
if (mediaElement) {
|
||||||
|
mediaElement.pause();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a retry after error
|
||||||
|
self.resume = function () {
|
||||||
|
if (mediaElement) {
|
||||||
|
mediaElement.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.unpause = function () {
|
||||||
|
if (mediaElement) {
|
||||||
|
mediaElement.play();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.paused = function () {
|
||||||
|
|
||||||
|
if (mediaElement) {
|
||||||
|
return mediaElement.paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.volume = function (val) {
|
||||||
|
if (mediaElement) {
|
||||||
|
if (val != null) {
|
||||||
|
mediaElement.volume = val / 100;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaElement.volume * 100;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.volumeUp = function () {
|
||||||
|
self.volume(Math.min(self.volume() + 2, 100));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.volumeDown = function () {
|
||||||
|
self.volume(Math.max(self.volume() - 2, 0));
|
||||||
|
};
|
||||||
|
|
||||||
|
self.setMute = function (mute) {
|
||||||
|
|
||||||
|
if (mute) {
|
||||||
|
self.volume(0);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (self.isMuted()) {
|
||||||
|
self.volume(50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.isMuted = function () {
|
||||||
|
return self.volume() === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
function onEnded() {
|
||||||
|
|
||||||
|
onEndedInternal(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndedInternal(triggerEnded) {
|
||||||
|
|
||||||
|
if (triggerEnded) {
|
||||||
|
var stopInfo = {
|
||||||
|
src: currentSrc
|
||||||
|
};
|
||||||
|
|
||||||
|
events.trigger(self, 'stopped', [stopInfo]);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSrc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTimeUpdate() {
|
||||||
|
|
||||||
|
events.trigger(self, 'timeupdate');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVolumeChange() {
|
||||||
|
|
||||||
|
if (!fadeTimeout) {
|
||||||
|
events.trigger(self, 'volumechange');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPlaying() {
|
||||||
|
|
||||||
|
events.trigger(self, 'playing');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPause() {
|
||||||
|
events.trigger(self, 'pause');
|
||||||
|
}
|
||||||
|
|
||||||
|
function onError() {
|
||||||
|
|
||||||
|
var errorCode = this.error ? this.error.code : '';
|
||||||
|
errorCode = (errorCode || '').toString();
|
||||||
|
console.log('Media element error code: ' + errorCode);
|
||||||
|
|
||||||
|
var type;
|
||||||
|
|
||||||
|
switch (errorCode) {
|
||||||
|
case 1:
|
||||||
|
// MEDIA_ERR_ABORTED
|
||||||
|
// This will trigger when changing media while something is playing
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
// MEDIA_ERR_NETWORK
|
||||||
|
type = 'network';
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// MEDIA_ERR_DECODE
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// MEDIA_ERR_SRC_NOT_SUPPORTED
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//events.trigger(self, 'error', [
|
||||||
|
//{
|
||||||
|
// type: type
|
||||||
|
//}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMediaElement() {
|
||||||
|
|
||||||
|
var elem = document.querySelector('.mediaPlayerAudio');
|
||||||
|
|
||||||
|
if (!elem) {
|
||||||
|
elem = document.createElement('audio');
|
||||||
|
elem.classList.add('mediaPlayerAudio');
|
||||||
|
elem.classList.add('hide');
|
||||||
|
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
|
||||||
|
elem.addEventListener('timeupdate', onTimeUpdate);
|
||||||
|
elem.addEventListener('ended', onEnded);
|
||||||
|
elem.addEventListener('volumechange', onVolumeChange);
|
||||||
|
elem.addEventListener('pause', onPause);
|
||||||
|
elem.addEventListener('playing', onPlaying);
|
||||||
|
elem.addEventListener('error', onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaElement = elem;
|
||||||
|
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDocumentClick() {
|
||||||
|
document.removeEventListener('click', onDocumentClick);
|
||||||
|
|
||||||
|
var elem = document.createElement('audio');
|
||||||
|
elem.classList.add('mediaPlayerAudio');
|
||||||
|
elem.classList.add('hide');
|
||||||
|
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
|
||||||
|
elem.src = pluginManager.mapPath(self, 'blank.mp3');
|
||||||
|
elem.play();
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
elem.src = '';
|
||||||
|
elem.removeAttribute("src");
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mobile browsers don't allow autoplay, so this is a nice workaround
|
||||||
|
if (!appHost.supports('htmlaudioautoplay')) {
|
||||||
|
document.addEventListener('click', onDocumentClick);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
@ -33,11 +33,32 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
events.trigger(self, 'playerchange', [newPlayer, newTarget, previousPlayer]);
|
events.trigger(self, 'playerchange', [newPlayer, newTarget, previousPlayer]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.getPlayerInfo = function () {
|
||||||
|
|
||||||
|
var player = currentPlayer;
|
||||||
|
|
||||||
|
if (!player) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var target = currentTargetInfo || {};
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
name: player.name,
|
||||||
|
isLocalPlayer: player.isLocalPlayer,
|
||||||
|
id: target.id,
|
||||||
|
deviceName: target.deviceName,
|
||||||
|
playableMediaTypes: target.playableMediaTypes,
|
||||||
|
supportedCommands: target.supportedCommands
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
self.setActivePlayer = function (player, targetInfo) {
|
self.setActivePlayer = function (player, targetInfo) {
|
||||||
|
|
||||||
if (typeof (player) === 'string') {
|
if (typeof (player) === 'string') {
|
||||||
player = players.filter(function (p) {
|
player = players.filter(function (p) {
|
||||||
return p.name == player;
|
return p.name === player;
|
||||||
})[0];
|
})[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +81,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
if (typeof (player) === 'string') {
|
if (typeof (player) === 'string') {
|
||||||
player = players.filter(function (p) {
|
player = players.filter(function (p) {
|
||||||
return p.name == player;
|
return p.name === player;
|
||||||
})[0];
|
})[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,7 +89,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
throw new Error('null player');
|
throw new Error('null player');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentPairingId == targetInfo.id) {
|
if (currentPairingId === targetInfo.id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +107,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
triggerPlayerChange(player, targetInfo, previousPlayer);
|
triggerPlayerChange(player, targetInfo, previousPlayer);
|
||||||
}, function () {
|
}, function () {
|
||||||
|
|
||||||
if (currentPairingId == targetInfo.id) {
|
if (currentPairingId === targetInfo.id) {
|
||||||
currentPairingId = null;
|
currentPairingId = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -103,7 +124,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
self.getTargets().then(function (result) {
|
self.getTargets().then(function (result) {
|
||||||
|
|
||||||
var target = result.filter(function (p) {
|
var target = result.filter(function (p) {
|
||||||
return normalizeName(p.name) == name;
|
return normalizeName(p.name) === name;
|
||||||
})[0];
|
})[0];
|
||||||
|
|
||||||
if (target) {
|
if (target) {
|
||||||
@ -125,7 +146,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
self.removeActivePlayer = function (name) {
|
self.removeActivePlayer = function (name) {
|
||||||
|
|
||||||
if (self.getPlayerInfo().name == name) {
|
if (self.getPlayerInfo().name === name) {
|
||||||
self.setDefaultPlayerActive();
|
self.setDefaultPlayerActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +154,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
self.removeActiveTarget = function (id) {
|
self.removeActiveTarget = function (id) {
|
||||||
|
|
||||||
if (self.getPlayerInfo().id == id) {
|
if (self.getPlayerInfo().id === id) {
|
||||||
self.setDefaultPlayerActive();
|
self.setDefaultPlayerActive();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -142,7 +163,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
var playerInfo = self.getPlayerInfo();
|
var playerInfo = self.getPlayerInfo();
|
||||||
|
|
||||||
if (playerInfo.supportedCommands.indexOf('EndSession') != -1) {
|
if (playerInfo.supportedCommands.indexOf('EndSession') !== -1) {
|
||||||
|
|
||||||
require(['dialog'], function (dialog) {
|
require(['dialog'], function (dialog) {
|
||||||
|
|
||||||
@ -166,7 +187,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
switch (id) {
|
switch (id) {
|
||||||
|
|
||||||
case 'yes':
|
case 'yes':
|
||||||
MediaController.getCurrentPlayer().endSession();
|
self.getCurrentPlayer().endSession();
|
||||||
self.setDefaultPlayerActive();
|
self.setDefaultPlayerActive();
|
||||||
break;
|
break;
|
||||||
case 'no':
|
case 'no':
|
||||||
@ -261,7 +282,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
return playlist.slice(0);
|
return playlist.slice(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.currentPlayer = function () {
|
self.getCurrentPlayer = function () {
|
||||||
return currentPlayer;
|
return currentPlayer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -481,7 +502,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (appSettings.get('displaymirror--' + Dashboard.getCurrentUserId()) || '') != '0';
|
return (appSettings.get('displaymirror--' + Dashboard.getCurrentUserId()) || '') !== '0';
|
||||||
};
|
};
|
||||||
|
|
||||||
self.stop = function () {
|
self.stop = function () {
|
||||||
@ -523,14 +544,14 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
self.seek = function (ticks) {
|
self.seek = function (ticks) {
|
||||||
|
|
||||||
var player = self.currentPlayer();
|
var player = currentPlayer;
|
||||||
|
|
||||||
changeStream(player, ticks);
|
changeStream(player, ticks);
|
||||||
};
|
};
|
||||||
|
|
||||||
self.nextChapter = function () {
|
self.nextChapter = function () {
|
||||||
|
|
||||||
var player = self.currentPlayer();
|
var player = currentPlayer;
|
||||||
var item = self.currentItem(player);
|
var item = self.currentItem(player);
|
||||||
|
|
||||||
var ticks = getCurrentTicks(player);
|
var ticks = getCurrentTicks(player);
|
||||||
@ -549,7 +570,8 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.previousChapter = function () {
|
self.previousChapter = function () {
|
||||||
var player = self.currentPlayer();
|
|
||||||
|
var player = currentPlayer;
|
||||||
var item = self.currentItem(player);
|
var item = self.currentItem(player);
|
||||||
|
|
||||||
var ticks = getCurrentTicks(player);
|
var ticks = getCurrentTicks(player);
|
||||||
@ -571,7 +593,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
self.fastForward = function () {
|
self.fastForward = function () {
|
||||||
|
|
||||||
var player = self.currentPlayer();
|
var player = currentPlayer;
|
||||||
|
|
||||||
if (player.fastForward != null) {
|
if (player.fastForward != null) {
|
||||||
player.fastForward(userSettings.skipForwardLength());
|
player.fastForward(userSettings.skipForwardLength());
|
||||||
@ -597,7 +619,7 @@ define(['events', 'datetime', 'appSettings', 'pluginManager', 'userSettings', 'g
|
|||||||
|
|
||||||
self.rewind = function () {
|
self.rewind = function () {
|
||||||
|
|
||||||
var player = self.currentPlayer();
|
var player = currentPlayer;
|
||||||
|
|
||||||
if (player.rewind != null) {
|
if (player.rewind != null) {
|
||||||
player.rewind(userSettings.skipBackLength());
|
player.rewind(userSettings.skipBackLength());
|
||||||
|
Loading…
Reference in New Issue
Block a user