Skip to content

feat: Support default quality and media type in scene player - #7061

Open
leclerc-leo wants to merge 1 commit into
stashapp:developfrom
leclerc-leo:feature/select-default-transcode-quality
Open

feat: Support default quality and media type in scene player#7061
leclerc-leo wants to merge 1 commit into
stashapp:developfrom
leclerc-leo:feature/select-default-transcode-quality

Conversation

@leclerc-leo

@leclerc-leo leclerc-leo commented Jun 19, 2026

Copy link
Copy Markdown

Description

If Direct stream or MKV is selected, since they do not support any resolution, the resolution will have no effect.
If No preference is selected as a stream type, the last stream type that has an available resolution will be selected.
Otherwise, the stream type with it's specific resolution will be selected. For example, MP4 Full HD (1080p).

In this PR, I'm adding (what I think is) a easy way to select a default source in the ScenePlayer.
I've split it in two, with the possibility to choose a preferred: Stream Type and Resolution.
This allows with only a few options to select one of the 26 possible options.

Here's the full table of what source is selected based on the Stream type on top and Resolution on the left.

Direct Stream MKV MP4 WEBM HLS DASH
Original Direct Stream MKV MP4 WEBM HLS DASH
4k (2160p) Direct Stream MKV MP4 4k (2160p) WEBM 4k (2160p) HLS 4k (2160p) DASH 4k (2160p)
full hd (1080p) Direct Stream MKV MP4 full hd (1080p) WEBM full hd (1080p) HLS full hd (1080p) DASH full hd (1080p)
hd (720p) Direct Stream MKV MP4 hd (720p) WEBM hd (720p) HLS hd (720p) DASH hd (720p)
standard (480p) Direct Stream MKV MP4 standard (480p) WEBM standard (480p) HLS standard (480p) DASH standard (480p)
low (240p) Direct Stream MKV MP4 low (240p) WEBM low (240p) HLS low (240p) DASH low (240p)

However, since some source are not always present like MKV or on Safari browser, I've added a "No preference" Stream Type to fallback on the first Stream Type with the selected Resolution.

P.S.
I did think about making the Stream Type an Ordered List of Preference.
However, this complicated the logic a lot. And (In my opinion), It didn't solve much more than what the "No preference" already does.
But since I'm not at all an expect on every exception that can occur, let me know if you think it would be worth the complexity.

Related Issue

Resolves #2523
Resolves #4175

Testing

I've checked that the table I've given on top was correct by testing a few options like:

  • Direct stream and MKV with Original, 1080p which always selected Direct stream / MKV.
  • MP4 / WEBM with Original that selected MP4 / WEBM
  • and a few option with the Resolution and Stream Type
  • MKV on a MP4 scene (so the MKV option isn't available)

I did not test on Safari browser since I do not own one.

Screenshots

image

Checklist

  • I have read and understood the Contributing document.
  • I have read and understood the AI Usage Policy document.
  • I have made corresponding changes to the documentation (if applicable).

AI Usage Disclosure

  • I have used AI tools to assist with this pull request, and I have disclosed the tools and how I used them below.

I have used Claude inside VSCode to make a draft/PoC so I was faster for me to set it up.
Afterward, I just did everything manually and changed every line of code (except some of en-GB.json)

Additional Context

Since the Resoltuion (such as Standard, Full HD, ...) aren't translated in the source selector inside the ScenePlayer, I didn't translate them, but would you prefer to have a translation for them in the settings ?

If any test needs to be added, let me know I'll check how to add them
And Thank You for taking the time to read this 😄

const label = sources[i].label ?? "";
const matchQuality = preferredQuality ? label.endsWith(preferredQuality) : true;
const matchType = preferredType ? label.startsWith(preferredType) : true;
if (matchQuality && matchType) return i;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you select MKV plus a resolution such as 1080p in the settings, opening an MKV scene falls back to Direct stream instead of selecting MKV. The matching logic requires the label to match both the preferred type and quality, but MKV and Direct stream labels do not include resolution suffixes, so MKV can never match when a non-original quality is selected.

Additionally, I may be missing some context here, but parsing SceneStreamEndpoint.label for behavior feels fragile. It might be better to expose structured metadata on SceneStreamEndpoint such as stream type and resolution, and keep label display-only.

}

setSources(sources: ISource[]) {
setSources(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the default stream type/quality while the current scene remains mounted does not reliably update the selected source. ScenePlayer.tsx passes the new preferences to sourceSelector.setSources, but that code only runs past the scene.id === sceneId.current guard during scene initialization, and the new config fields are not part of a separate reselection path. This means that if you change the setting and refresh a scene page, it breaks and will not load the video to play. It can be resolved by leaving the page and reopening the scene.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to note that the issue still exists. Steps to test:

  1. Have a tab playing a scene
  2. on another tab, change the default settings to another type
  3. refresh the first scene tab
  4. Note that it has updated to the new default but the video is black screened and doesnt play

@leclerc-leo
leclerc-leo force-pushed the feature/select-default-transcode-quality branch from 973cb1b to 2035ed3 Compare June 20, 2026 10:57
@leclerc-leo

Copy link
Copy Markdown
Author

Thanks for the feedback.

I probably forgot to re-check MKV and Direct Stream after making some changes, I've re-tested before pushing this change and it now work as I specified in the PR description.

I added a useEffect to solve the issue you talked about with the settings that could change (this seemed for me this easiest and cleanest solution).
However, I'm not 100% sure if it's the best.

In the initial useEffect that call sourceSelector.setSources, I didn't add both settings as a dependence in the useEffect.
In my opinion, even if the setting changes, we should not update the selected option.
Since after the initial loading the user could have selected another option and we would be overwriting it.

Please let me know what you think is best.

preferredType: string | undefined,
preferredResolution: string | undefined
): number {
for (let i = sources.length - 1; i >= 0; i--) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this cycles through the list from the bottom up, it will match with the bottom type if no preference is selected. You can test this by 1) ensure the settings are written to config with No Preference/Original 2) Load a scene 3) Notice that it defaults to Dash instead of Direct Stream

An additional note on this is the fact that when you first load this build, you don't see this issue because it treats the unset "" and set "ORIGINAL" as different values

}

setSources(sources: ISource[]) {
setSources(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wanted to note that the issue still exists. Steps to test:

  1. Have a tab playing a scene
  2. on another tab, change the default settings to another type
  3. refresh the first scene tab
  4. Note that it has updated to the new default but the video is black screened and doesnt play

@leclerc-leo
leclerc-leo force-pushed the feature/select-default-transcode-quality branch 2 times, most recently from bb6f832 to ded6c21 Compare June 22, 2026 00:06
@leclerc-leo

Copy link
Copy Markdown
Author

Thanks again.

I've finally been able to reproduce the issue (I'm using something similar to https://github.com/nerethos/docker-stash, which edit the transcode a bit, I'm now using a more basic docker image)

The fix I applied is to call player.currentTime only when the metadata has loaded.
I've tried to check a bit the code of the player to understand why exactly this happened but I couldn't find anything conclusive.

However, this seems to be due to the setting "FFmpeg hardware encoding" as when it's off, the issue doesn't happen.
If you want me to take more of a look, I'll do a more in-depth check to try to find the exact reason (probably next we, since I dont really have time during the week).

@leclerc-leo
leclerc-leo force-pushed the feature/select-default-transcode-quality branch from ded6c21 to f82ba54 Compare June 29, 2026 18:07
If Direct stream or MKV is selected, since they do not support any quality, the quality will have no effect.
If No preference is selected as a media type, the first media type that has an available quality will be selected.
Otherwise, the media type with its specifc quality will be selected. For example, MP4 Full HD (1080p).
@leclerc-leo
leclerc-leo force-pushed the feature/select-default-transcode-quality branch from f82ba54 to 4ef3432 Compare June 29, 2026 18:53
@leclerc-leo

Copy link
Copy Markdown
Author

Hi 👋
I've checked more in details.

The issue appears in this PR due to offset: !isDirect(src) during sourceSelector.setSources in ScenePlayer.tsx.

Before, when a player was ready, it would trigger player.currentTime with the startPosition.
Which called setCurrentTime in the offsetMiddleware, which first check that offsetStart is not undefined, which it is when using direct stream.

Now, since the offsetStart is not undefined, it will continue and call loadSource which set the seeking to 1 and try to play the media. However, most modern browser have an anti auto-play feature (see https://developer.chrome.com/blog/autoplay).
This trigger an error which result in the player behing suck in seeking = 1.

When the user tries to play the video canPlay is called and since seeking is true, it just return videojs.middleware.TERMINATOR;.

To resolve this issue, I'm catching the failed tech.play to reset seeking back to 0.

If you have any question about this issue (which I know I'm not very good at explaining things) or anything else, please let me know.
Thanks again for everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Ability to change default live transcode method Ability to change default quality when using live transcode

2 participants