mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #6196 from viown/prompt-to-skip
Add 'ask to skip' to media segments
This commit is contained in:
commit
fa1934a124
10 changed files with 277 additions and 25 deletions
|
@ -3,5 +3,6 @@
|
|||
*/
|
||||
export enum MediaSegmentAction {
|
||||
None = 'None',
|
||||
AskToSkip = 'AskToSkip',
|
||||
Skip = 'Skip'
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ export enum PlayerEvent {
|
|||
PlaylistItemAdd = 'playlistitemadd',
|
||||
PlaylistItemMove = 'playlistitemmove',
|
||||
PlaylistItemRemove = 'playlistitemremove',
|
||||
PromptSkip = 'promptskip',
|
||||
RepeatModeChange = 'repeatmodechange',
|
||||
ShuffleModeChange = 'shufflequeuemodechange',
|
||||
Stopped = 'stopped',
|
||||
|
|
|
@ -37,6 +37,38 @@ class MediaSegmentManager extends PlaybackSubscriber {
|
|||
}
|
||||
}
|
||||
|
||||
skipSegment(mediaSegment: MediaSegmentDto) {
|
||||
// Ignore segment if playback progress has passed the segment's start time
|
||||
if (mediaSegment.StartTicks !== undefined && this.lastTime > mediaSegment.StartTicks) {
|
||||
console.info('[MediaSegmentManager] ignoring skipping segment that has been seeked back into', mediaSegment);
|
||||
this.isLastSegmentIgnored = true;
|
||||
} else if (mediaSegment.EndTicks) {
|
||||
// If there is an end time, seek to it
|
||||
// Do not skip if duration < 1s to avoid slow stream changes
|
||||
if (mediaSegment.StartTicks && mediaSegment.EndTicks - mediaSegment.StartTicks < TICKS_PER_SECOND) {
|
||||
console.info('[MediaSegmentManager] ignoring skipping segment with duration <1s', mediaSegment);
|
||||
this.isLastSegmentIgnored = true;
|
||||
return;
|
||||
}
|
||||
console.debug('[MediaSegmentManager] skipping to %s ms', mediaSegment.EndTicks / TICKS_PER_MILLISECOND);
|
||||
this.playbackManager.seek(mediaSegment.EndTicks, this.player);
|
||||
} else {
|
||||
// If there is no end time, skip to the next track
|
||||
console.debug('[MediaSegmentManager] skipping to next item in queue');
|
||||
this.playbackManager.nextTrack(this.player);
|
||||
}
|
||||
}
|
||||
|
||||
promptToSkip(mediaSegment: MediaSegmentDto) {
|
||||
if (mediaSegment.StartTicks && mediaSegment.EndTicks
|
||||
&& mediaSegment.EndTicks - mediaSegment.StartTicks < TICKS_PER_SECOND * 3) {
|
||||
console.info('[MediaSegmentManager] ignoring segment prompt with duration <3s', mediaSegment);
|
||||
this.isLastSegmentIgnored = true;
|
||||
return;
|
||||
}
|
||||
this.playbackManager.promptToSkip(mediaSegment);
|
||||
}
|
||||
|
||||
private performAction(mediaSegment: MediaSegmentDto) {
|
||||
if (!this.mediaSegmentTypeActions || !mediaSegment.Type || !this.mediaSegmentTypeActions[mediaSegment.Type]) {
|
||||
console.error('[MediaSegmentManager] segment type missing from action map', mediaSegment, this.mediaSegmentTypeActions);
|
||||
|
@ -45,27 +77,9 @@ class MediaSegmentManager extends PlaybackSubscriber {
|
|||
|
||||
const action = this.mediaSegmentTypeActions[mediaSegment.Type];
|
||||
if (action === MediaSegmentAction.Skip) {
|
||||
// Ignore segment if playback progress has passed the segment's start time
|
||||
if (mediaSegment.StartTicks !== undefined && this.lastTime > mediaSegment.StartTicks) {
|
||||
console.info('[MediaSegmentManager] ignoring skipping segment that has been seeked back into', mediaSegment);
|
||||
this.isLastSegmentIgnored = true;
|
||||
return;
|
||||
} else if (mediaSegment.EndTicks) {
|
||||
// If there is an end time, seek to it
|
||||
// Do not skip if duration < 1s to avoid slow stream changes
|
||||
if (mediaSegment.StartTicks && mediaSegment.EndTicks - mediaSegment.StartTicks < TICKS_PER_SECOND) {
|
||||
console.info('[MediaSegmentManager] ignoring skipping segment with duration <1s', mediaSegment);
|
||||
this.isLastSegmentIgnored = true;
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('[MediaSegmentManager] skipping to %s ms', mediaSegment.EndTicks / TICKS_PER_MILLISECOND);
|
||||
this.playbackManager.seek(mediaSegment.EndTicks, this.player);
|
||||
} else {
|
||||
// If there is no end time, skip to the next track
|
||||
console.debug('[MediaSegmentManager] skipping to next item in queue');
|
||||
this.playbackManager.nextTrack(this.player);
|
||||
}
|
||||
this.skipSegment(mediaSegment);
|
||||
} else if (action === MediaSegmentAction.AskToSkip) {
|
||||
this.promptToSkip(mediaSegment);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ const isBeforeSegment = (segment: MediaSegmentDto, time: number, direction: numb
|
|||
);
|
||||
};
|
||||
|
||||
const isInSegment = (segment: MediaSegmentDto, time: number) => (
|
||||
export const isInSegment = (segment: MediaSegmentDto, time: number) => (
|
||||
typeof segment.StartTicks !== 'undefined'
|
||||
&& segment.StartTicks <= time
|
||||
&& (typeof segment.EndTicks === 'undefined' || segment.EndTicks > time)
|
||||
|
|
|
@ -11,6 +11,7 @@ import Events, { type Event } from 'utils/events';
|
|||
import { PlaybackManagerEvent } from '../constants/playbackManagerEvent';
|
||||
import { PlayerEvent } from '../constants/playerEvent';
|
||||
import type { ManagedPlayerStopInfo, MovedItem, PlayerError, PlayerErrorCode, PlayerStopInfo, RemovedItems } from '../types/callbacks';
|
||||
import type { MediaSegmentDto } from '@jellyfin/sdk/lib/generated-client/models/media-segment-dto';
|
||||
|
||||
export interface PlaybackSubscriber {
|
||||
onPlaybackCancelled?(e: Event): void
|
||||
|
@ -18,6 +19,7 @@ export interface PlaybackSubscriber {
|
|||
onPlaybackStart?(e: Event, player: Plugin, state: PlayerState): void
|
||||
onPlaybackStop?(e: Event, info: PlaybackStopInfo): void
|
||||
onPlayerChange?(e: Event, player: Plugin, target: PlayTarget, previousPlayer: Plugin): void
|
||||
onPromptSkip?(e: Event, mediaSegment: MediaSegmentDto): void
|
||||
onPlayerError?(e: Event, error: PlayerError): void
|
||||
onPlayerFullscreenChange?(e: Event): void
|
||||
onPlayerItemStarted?(e: Event, item?: BaseItemDto, mediaSource?: MediaSourceInfo): void
|
||||
|
@ -62,6 +64,7 @@ export abstract class PlaybackSubscriber {
|
|||
[PlayerEvent.PlaylistItemAdd]: this.onPlayerPlaylistItemAdd?.bind(this),
|
||||
[PlayerEvent.PlaylistItemMove]: this.onPlayerPlaylistItemMove?.bind(this),
|
||||
[PlayerEvent.PlaylistItemRemove]: this.onPlayerPlaylistItemRemove?.bind(this),
|
||||
[PlayerEvent.PromptSkip]: this.onPromptSkip?.bind(this),
|
||||
[PlayerEvent.RepeatModeChange]: this.onPlayerRepeatModeChange?.bind(this),
|
||||
[PlayerEvent.ShuffleModeChange]: this.onPlayerShuffleModeChange?.bind(this),
|
||||
[PlayerEvent.Stopped]: this.onPlayerStopped?.bind(this),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue