1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00
jellyfin-web/src/components/playback/skipsegment.ts

171 lines
5.5 KiB
TypeScript
Raw Normal View History

2024-10-12 15:43:40 +03:00
import { PlaybackManager } from './playbackmanager';
2024-10-15 15:20:39 +03:00
import { TICKS_PER_MILLISECOND, TICKS_PER_SECOND } from 'constants/time';
2024-10-24 12:34:52 +03:00
import type { MediaSegmentDto } from '@jellyfin/sdk/lib/generated-client/models/media-segment-dto';
2024-10-12 15:43:40 +03:00
import { PlaybackSubscriber } from 'apps/stable/features/playback/utils/playbackSubscriber';
import { isInSegment } from 'apps/stable/features/playback/utils/mediaSegments';
import Events, { type Event } from '../../utils/events';
import { EventType } from 'types/eventType';
import './skipbutton.scss';
import dom from 'scripts/dom';
import globalize from 'lib/globalize';
interface ShowOptions {
animate?: boolean;
keep?: boolean;
}
class SkipSegment extends PlaybackSubscriber {
private skipElement: HTMLButtonElement | undefined;
private currentSegment: MediaSegmentDto | null | undefined;
private hideTimeout: ReturnType<typeof setTimeout> | null | undefined;
constructor(playbackManager: PlaybackManager) {
super(playbackManager);
this.onOsdChanged = this.onOsdChanged.bind(this);
}
onHideComplete() {
if (this.skipElement) {
this.skipElement.classList.add('hide');
}
}
createSkipElement() {
if (!this.skipElement && this.currentSegment) {
const elem = document.createElement('button');
elem.classList.add('skip-button');
elem.classList.add('hide');
elem.classList.add('skip-button-hidden');
elem.addEventListener('click', () => {
2024-10-15 15:20:39 +03:00
const time = this.playbackManager.currentTime() * TICKS_PER_MILLISECOND;
if (this.currentSegment?.EndTicks) {
if (time < this.currentSegment.EndTicks - TICKS_PER_SECOND) {
this.playbackManager.seek(this.currentSegment.EndTicks);
} else {
this.hideSkipButton();
}
2024-10-12 15:43:40 +03:00
}
});
document.body.appendChild(elem);
this.skipElement = elem;
}
}
setButtonText() {
if (this.skipElement && this.currentSegment) {
2024-10-19 20:08:27 +03:00
this.skipElement.innerHTML = globalize.translate('MediaSegmentSkipPrompt', globalize.translate(`MediaSegmentType.${this.currentSegment.Type}`));
2024-10-12 15:43:40 +03:00
this.skipElement.innerHTML += '<span class="material-icons skip_next" aria-hidden="true"></span>';
}
}
showSkipButton(options: ShowOptions) {
const elem = this.skipElement;
if (elem) {
this.clearHideTimeout();
dom.removeEventListener(elem, dom.whichTransitionEvent(), this.onHideComplete, {
once: true
});
elem.classList.remove('hide');
if (!options.animate) {
elem.classList.add('no-transition');
} else {
elem.classList.remove('no-transition');
}
void elem.offsetWidth;
requestAnimationFrame(() => {
elem.classList.remove('skip-button-hidden');
if (!options.keep) {
2024-10-15 15:10:13 +03:00
this.hideTimeout = setTimeout(this.hideSkipButton.bind(this), 8000);
2024-10-12 15:43:40 +03:00
}
});
}
}
hideSkipButton() {
const elem = this.skipElement;
if (elem) {
elem.classList.remove('no-transition');
void elem.offsetWidth;
requestAnimationFrame(() => {
elem.classList.add('skip-button-hidden');
dom.addEventListener(elem, dom.whichTransitionEvent(), this.onHideComplete, {
once: true
});
});
}
}
clearHideTimeout() {
if (this.hideTimeout) {
clearTimeout(this.hideTimeout);
this.hideTimeout = null;
}
}
2024-10-15 12:52:05 +03:00
onOsdChanged(_e: Event, isOpen: boolean) {
if (this.currentSegment) {
if (isOpen) {
this.showSkipButton({
animate: false,
keep: true
});
} else if (!this.hideTimeout) {
this.hideSkipButton();
}
}
}
2024-10-19 20:08:27 +03:00
onPromptSkip(e: Event, segment: MediaSegmentDto) {
if (this.player && segment.EndTicks != null
&& segment.EndTicks >= this.playbackManager.currentItem(this.player).RunTimeTicks
&& this.playbackManager.getNextItem()
) {
// Don't display button when UpNextDialog is expected.
return;
}
2024-10-12 15:43:40 +03:00
if (!this.currentSegment) {
this.currentSegment = segment;
this.createSkipElement();
this.setButtonText();
this.showSkipButton({ animate: true });
}
}
onPlayerTimeUpdate() {
if (this.currentSegment) {
const time = this.playbackManager.currentTime(this.player) * TICKS_PER_MILLISECOND;
if (!isInSegment(this.currentSegment, time)) {
this.currentSegment = null;
this.hideSkipButton();
}
}
}
2024-10-15 12:52:05 +03:00
onPlayerChange(): void {
if (this.playbackManager.getCurrentPlayer()) {
Events.off(document, EventType.SHOW_VIDEO_OSD, this.onOsdChanged);
Events.on(document, EventType.SHOW_VIDEO_OSD, this.onOsdChanged);
}
}
2024-10-12 15:43:40 +03:00
onPlaybackStop() {
this.currentSegment = null;
this.hideSkipButton();
Events.off(document, EventType.SHOW_VIDEO_OSD, this.onOsdChanged);
}
}
export const bindSkipSegment = (playbackManager: PlaybackManager) => new SkipSegment(playbackManager);