Skip to content

Commit

Permalink
Merge branch 'master' into bug/6211-Unintentional-wrap-of-button-labe…
Browse files Browse the repository at this point in the history
…l-for-SaveChanges
  • Loading branch information
tylers-username authored Nov 9, 2024
2 parents 1dcdf97 + d0a1fb2 commit 4bd44e4
Show file tree
Hide file tree
Showing 62 changed files with 1,914 additions and 640 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/__deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
path: dist

- name: Publish to Cloudflare Pages 📃
uses: cloudflare/wrangler-action@9681c2997648301493e78cacbfb790a9f19c833f # v3.9.0
uses: cloudflare/wrangler-action@b2a0191ce60d21388e1a8dcc968b4e9966f938e1 # v3.11.0
id: cf
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/__package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
ref: ${{ inputs.commit || github.sha }}

- name: Setup node environment
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
cache: npm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/__quality_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
show-progress: false

- name: Setup node environment ⚙️
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
cache: npm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}

- name: Setup node environment
uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # v4.0.4
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
with:
node-version: 20
cache: npm
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@ jobs:
secrets: inherit
with:
branch: ${{ github.ref_name }}
comment:
comment: false
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jellyfin-web",
"version": "10.10.0",
"version": "10.11.0",
"description": "Web interface for Jellyfin",
"repository": "https://github.com/jellyfin/jellyfin-web",
"license": "GPL-2.0-or-later",
Expand Down Expand Up @@ -79,7 +79,7 @@
"@fontsource/noto-sans-sc": "5.1.0",
"@fontsource/noto-sans-tc": "5.1.0",
"@jellyfin/libass-wasm": "4.2.3",
"@jellyfin/sdk": "0.0.0-unstable.202410230556",
"@jellyfin/sdk": "0.0.0-unstable.202410250501",
"@mui/icons-material": "5.16.7",
"@mui/material": "5.16.7",
"@mui/x-date-pickers": "7.20.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ const ServerDrawerSection = () => {
<ListItemText inset primary={globalize.translate('Display')} />
</ListItemLink>
<ListItemLink to='/dashboard/libraries/metadata' sx={{ pl: 4 }}>
<ListItemText inset primary={globalize.translate('MetadataManager')} />
<ListItemText inset primary={globalize.translate('LabelMetadata')} />
</ListItemLink>
<ListItemLink to='/dashboard/libraries/nfo' sx={{ pl: 4 }}>
<ListItemText inset primary={globalize.translate('TabNfoSettings')} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import Stack from '@mui/material/Stack/Stack';
import React, { type FC } from 'react';

import MarkdownBox from 'components/MarkdownBox';
import { parseISO8601Date, toLocaleString } from 'scripts/datetime';
import { getDisplayDateTime } from 'scripts/datetime';
import globalize from 'lib/globalize';

import type { PluginDetails } from '../types/PluginDetails';
Expand All @@ -32,7 +32,7 @@ const PluginRevisions: FC<PluginRevisionsProps> = ({
{version.version}
{version.timestamp && (<>
&nbsp;&mdash;&nbsp;
{toLocaleString(parseISO8601Date(version.timestamp))}
{getDisplayDateTime(version.timestamp)}
</>)}
</AccordionSummary>
<AccordionDetails>
Expand Down
15 changes: 15 additions & 0 deletions src/apps/dashboard/features/plugins/constants/categoryLabels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/** A mapping of category names used by the plugin repository to translation keys. */
export const CATEGORY_LABELS = {
Administration: 'HeaderAdmin',
Anime: 'Anime',
Authentication: 'LabelAuthProvider', // Legacy
Books: 'Books',
Channel: 'Channels', // Unused?
General: 'General',
LiveTV: 'LiveTV',
Metadata: 'LabelMetadata', // Legacy
MoviesAndShows: 'MoviesAndShows',
Music: 'TabMusic',
Subtitles: 'Subtitles',
Other: 'Other'
};
7 changes: 5 additions & 2 deletions src/apps/experimental/components/library/PlayAllButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,21 @@ const PlayAllButton: FC<PlayAllButtonProps> = ({ item, items, viewType, hasFilte
SortBy: [libraryViewSettings.SortBy],
SortOrder: [libraryViewSettings.SortOrder]
}
}).catch(err => {
console.error('[PlayAllButton] failed to play', err);
});
} else {
playbackManager.play({
items: items,
items,
autoplay: true,
queryOptions: {
ParentId: item?.Id ?? undefined,
...getFiltersQuery(viewType, libraryViewSettings),
SortBy: [libraryViewSettings.SortBy],
SortOrder: [libraryViewSettings.SortOrder]
}

}).catch(err => {
console.error('[PlayAllButton] failed to play', err);
});
}
}, [hasFilters, item, items, libraryViewSettings, viewType]);
Expand Down
6 changes: 5 additions & 1 deletion src/apps/experimental/components/library/QueueButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ const QueueButton: FC<QueueButtonProps> = ({ item, items, hasFilters }) => {
if (item && !hasFilters) {
playbackManager.queue({
items: [item]
}).catch(err => {
console.error('[QueueButton] failed to add to queue', err);
});
} else {
playbackManager.queue({
items: items
items
}).catch(err => {
console.error('[QueueButton] failed to add to queue', err);
});
}
}, [hasFilters, item, items]);
Expand Down
4 changes: 3 additions & 1 deletion src/apps/experimental/components/library/ShuffleButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ const ShuffleButton: FC<ShuffleButtonProps> = ({ item, items, viewType, hasFilte
playbackManager.shuffle(item);
} else {
playbackManager.play({
items: items,
items,
autoplay: true,
queryOptions: {
ParentId: item?.Id ?? undefined,
...getFiltersQuery(viewType, libraryViewSettings),
SortBy: [ItemSortBy.Random]
}
}).catch(err => {
console.error('[ShuffleButton] failed to play', err);
});
}
}, [hasFilters, item, items, libraryViewSettings, viewType]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function playAllFromHere(opts: PlayAllFromHereOptions) {
}

if (!ids.length) {
return;
return Promise.resolve();
}

if (queue) {
Expand Down Expand Up @@ -168,13 +168,17 @@ const MoreCommandsButton: FC<MoreCommandsButtonProps> = ({
item: item || {},
items: items || [],
serverId: item?.ServerId
}).catch(err => {
console.error('[MoreCommandsButton] failed to play', err);
});
} else if (result.command === 'queueallfromhere') {
playAllFromHere({
item: item || {},
items: items || [],
serverId: item?.ServerId,
queue: true
}).catch(err => {
console.error('[MoreCommandsButton] failed to play', err);
});
} else if (result.deleted) {
if (result?.itemId !== itemId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,17 @@ const PlayOrResumeButton: FC<PlayOrResumeButtonProps> = ({
);
playbackManager.play({
items: [channel]
}).catch(err => {
console.error('[PlayOrResumeButton] failed to play', err);
});
return;
}

playbackManager.play({
items: [item],
...playOptions
}).catch(err => {
console.error('[PlayOrResumeButton] failed to play', err);
});
}, [apiContext, item, playOptions, queryClient]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
*/
export enum MediaSegmentAction {
None = 'None',
AskToSkip = 'AskToSkip',
Skip = 'Skip'
}
1 change: 1 addition & 0 deletions src/apps/stable/features/playback/constants/playerEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export enum PlayerEvent {
PlaylistItemAdd = 'playlistitemadd',
PlaylistItemMove = 'playlistitemmove',
PlaylistItemRemove = 'playlistitemremove',
PromptSkip = 'promptskip',
RepeatModeChange = 'repeatmodechange',
ShuffleModeChange = 'shufflequeuemodechange',
Stopped = 'stopped',
Expand Down
56 changes: 35 additions & 21 deletions src/apps/stable/features/playback/utils/mediaSegmentManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/apps/stable/features/playback/utils/mediaSegmentSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import { UserSettings } from 'scripts/settings/userSettings';
import { MediaSegmentAction } from '../constants/mediaSegmentAction';

const PREFIX = 'segmentTypeAction';
const DEFAULT_ACTIONS: Partial<Record<MediaSegmentType, MediaSegmentAction>> = {
[MediaSegmentType.Intro]: MediaSegmentAction.AskToSkip,
[MediaSegmentType.Outro]: MediaSegmentAction.AskToSkip
};

export const getId = (type: MediaSegmentType) => `${PREFIX}__${type}`;

export function getMediaSegmentAction(userSettings: UserSettings, type: MediaSegmentType): MediaSegmentAction | undefined {
export function getMediaSegmentAction(userSettings: UserSettings, type: MediaSegmentType): MediaSegmentAction {
const action = userSettings.get(getId(type), false);
return action ? action as MediaSegmentAction : undefined;
const defaultAction = DEFAULT_ACTIONS[type] || MediaSegmentAction.None;

return action ? action as MediaSegmentAction : defaultAction;
}
2 changes: 1 addition & 1 deletion src/apps/stable/features/playback/utils/mediaSegments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions src/apps/stable/features/playback/utils/playbackSubscriber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ 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
onPlaybackError?(e: Event, errorType: MediaError): void
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
Expand Down Expand Up @@ -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),
Expand Down
Loading

0 comments on commit 4bd44e4

Please sign in to comment.