123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- let fadeTimeout;
- function fade(instance, elem, startingVolume) {
- instance._isFadingOut = true;
- // Need to record the starting volume on each pass rather than querying elem.volume
- // This is due to iOS safari not allowing volume changes and always returning the system volume value
- const newVolume = Math.max(0, startingVolume - 15);
- console.debug('fading volume to ' + newVolume);
- api.player.setVolume(newVolume);
- if (newVolume <= 0) {
- instance._isFadingOut = false;
- return Promise.resolve();
- }
- return new Promise(function (resolve, reject) {
- cancelFadeTimeout();
- fadeTimeout = setTimeout(function () {
- fade(instance, null, newVolume).then(resolve, reject);
- }, 100);
- });
- }
- function cancelFadeTimeout() {
- const timeout = fadeTimeout;
- if (timeout) {
- clearTimeout(timeout);
- fadeTimeout = null;
- }
- }
- class mpvAudioPlayer {
- constructor({ events, appHost, appSettings }) {
- const self = this;
- self.events = events;
- self.appHost = appHost;
- self.appSettings = appSettings;
- self.name = 'MPV Audio Player';
- self.type = 'mediaplayer';
- self.id = 'mpvaudioplayer';
- self.syncPlayWrapAs = 'htmlaudioplayer';
- self.useServerPlaybackInfoForAudio = true;
- self._duration = undefined;
- self._currentTime = undefined;
- self._paused = false;
- self._volume = this.getSavedVolume() * 100;
- self._playRate = 1;
- self._hasConnection = false;
- self.play = (options) => {
- self._started = false;
- self._timeUpdated = false;
- self._currentTime = null;
- self._duration = undefined;
- const player = window.api.player;
- if (!self._hasConnection) {
- self._hasConnection = true;
- player.playing.connect(onPlaying);
- player.positionUpdate.connect(onTimeUpdate);
- player.finished.connect(onEnded);
- player.updateDuration.connect(onDuration);
- player.error.connect(onError);
- player.paused.connect(onPause);
- window.api.taskbar.pauseClicked.connect(onPauseClicked);
- }
- return setCurrentSrc(options);
- };
- function setCurrentSrc(options) {
- return new Promise((resolve) => {
- const val = options.url;
- self._currentSrc = val;
- console.debug('playing url: ' + val);
- // Convert to seconds
- const ms = (options.playerStartPositionTicks || 0) / 10000;
- self._currentPlayOptions = options;
- window.api.player.load(val,
- { startMilliseconds: ms, autoplay: true },
- {type: 'music', headers: {'User-Agent': 'JellyfinMediaPlayer'}, media: {}},
- '#1',
- '',
- resolve);
- });
- }
- self.onEndedInternal = () => {
- const stopInfo = {
- src: self._currentSrc
- };
- self.events.trigger(self, 'stopped', [stopInfo]);
- window.api.taskbar.setControlsVisible(false);
- self._currentTime = null;
- self._currentSrc = null;
- self._currentPlayOptions = null;
- };
- self.stop = (destroyPlayer) => {
- cancelFadeTimeout();
- const src = self._currentSrc;
- if (src) {
- const originalVolume = self._volume;
- return fade(self, null, self._volume).then(function () {
- self.pause();
- self.setVolume(originalVolume, false);
- self.onEndedInternal();
- if (destroyPlayer) {
- self.destroy();
- }
- });
- }
- return Promise.resolve();
- };
- self.destroy = () => {
- window.api.player.stop();
- const player = window.api.player;
- self._hasConnection = false;
- player.playing.disconnect(onPlaying);
- player.positionUpdate.disconnect(onTimeUpdate);
- player.finished.disconnect(onEnded);
- self._duration = undefined;
- player.updateDuration.disconnect(onDuration);
- player.error.disconnect(onError);
- player.paused.disconnect(onPause);
- window.api.taskbar.pauseClicked.disconnect(onPauseClicked);
- };
- function onDuration(duration) {
- self._duration = duration;
- }
- function onEnded() {
- self.onEndedInternal();
- }
- function onTimeUpdate(time) {
- // Don't trigger events after user stop
- if (!self._isFadingOut) {
- self._currentTime = time;
- self.events.trigger(self, 'timeupdate');
- window.api.taskbar.setProgress(time * 100 / self._duration);
- }
- }
- function onPlaying() {
- if (!self._started) {
- self._started = true;
- window.api.taskbar.setControlsVisible(true);
- }
- self.setPlaybackRate(1);
- self.setMute(false);
- if (self._paused) {
- self._paused = false;
- self.events.trigger(self, 'unpause');
- window.api.taskbar.setPaused(false);
- }
- self.events.trigger(self, 'playing');
- }
- function onPause() {
- self._paused = true;
- self.events.trigger(self, 'pause');
- window.api.taskbar.setPaused(true);
- }
- function onError(error) {
- console.error(`media element error: ${error}`);
- self.events.trigger(self, 'error', [
- {
- type: 'mediadecodeerror'
- }
- ]);
- }
- function onPauseClicked() {
- self.paused() ? self.unpause() : self.pause();
- }
- }
- getSavedVolume() {
- return this.appSettings.get('volume') || 1;
- }
- currentSrc() {
- return this._currentSrc;
- }
- canPlayMediaType(mediaType) {
- return (mediaType || '').toLowerCase() === 'audio';
- }
- getDeviceProfile(item, options) {
- if (this.appHost.getDeviceProfile) {
- return this.appHost.getDeviceProfile(item, options);
- }
- return {};
- }
- currentTime(val) {
- if (val != null) {
- window.api.player.seekTo(val);
- return;
- }
- return this._currentTime;
- }
- currentTimeAsync() {
- return new Promise((resolve) => {
- window.api.player.getPosition(resolve);
- });
- }
- duration() {
- if (this._duration) {
- return this._duration;
- }
- return null;
- }
- seekable() {
- return Boolean(this._duration);
- }
- getBufferedRanges() {
- return [];
- }
- pause() {
- window.api.player.pause();
- }
- // This is a retry after error
- resume() {
- this._paused = false;
- window.api.player.play();
- }
- unpause() {
- window.api.player.play();
- }
- paused() {
- return this._paused;
- }
- setPlaybackRate(value) {
- this._playRate = value;
- window.api.player.setPlaybackRate(value * 1000);
- }
- getPlaybackRate() {
- return this._playRate;
- }
- getSupportedPlaybackRates() {
- return [{
- name: '0.5x',
- id: 0.5
- }, {
- name: '0.75x',
- id: 0.75
- }, {
- name: '1x',
- id: 1.0
- }, {
- name: '1.25x',
- id: 1.25
- }, {
- name: '1.5x',
- id: 1.5
- }, {
- name: '1.75x',
- id: 1.75
- }, {
- name: '2x',
- id: 2.0
- }];
- }
- saveVolume(value) {
- if (value) {
- this.appSettings.set('volume', value);
- }
- }
- setVolume(val, save = true) {
- this._volume = val;
- if (save) {
- this.saveVolume((val || 100) / 100);
- this.events.trigger(this, 'volumechange');
- }
- window.api.player.setVolume(val);
- }
- getVolume() {
- return this._volume;
- }
- volumeUp() {
- this.setVolume(Math.min(this.getVolume() + 2, 100));
- }
- volumeDown() {
- this.setVolume(Math.max(this.getVolume() - 2, 0));
- }
- setMute(mute) {
- this._muted = mute;
- window.api.player.setMuted(mute);
- }
- isMuted() {
- return this._muted;
- }
- supports(feature) {
- if (!supportedFeatures) {
- supportedFeatures = getSupportedFeatures();
- }
- return supportedFeatures.indexOf(feature) !== -1;
- }
- }
- let supportedFeatures;
- function getSupportedFeatures() {
- return ['PlaybackRate'];
- }
- window._mpvAudioPlayer = mpvAudioPlayer;
|