Add force transcode option (#2126)

This commit is contained in:
WithoutPants
2021-12-20 11:45:36 +11:00
committed by GitHub
parent f830d9cf13
commit b0cf04865a
7 changed files with 43 additions and 96 deletions

View File

@@ -9,6 +9,8 @@ input GenerateMetadataInput {
markerImagePreviews: Boolean
markerScreenshots: Boolean
transcodes: Boolean
"""Generate transcodes even if not required"""
forceTranscodes: Boolean
phashes: Boolean
interactiveHeatmapsSpeeds: Boolean

View File

@@ -252,9 +252,11 @@ func (j *GenerateJob) queueSceneJobs(scene *models.Scene, queue chan<- Task, tot
}
if utils.IsTrue(j.input.Transcodes) {
forceTranscode := utils.IsTrue(j.input.ForceTranscodes)
task := &GenerateTranscodeTask{
Scene: *scene,
Overwrite: j.overwrite,
Force: forceTranscode,
fileNamingAlgorithm: j.fileNamingAlgo,
}
if task.isTranscodeNeeded() {

View File

@@ -15,6 +15,9 @@ type GenerateTranscodeTask struct {
Scene models.Scene
Overwrite bool
fileNamingAlgorithm models.HashAlgorithm
// is true, generate even if video is browser-supported
Force bool
}
func (t *GenerateTranscodeTask) GetDescription() string {
@@ -49,7 +52,7 @@ func (t *GenerateTranscodeTask) Start(ctc context.Context) {
audioCodec = ffmpeg.AudioCodec(t.Scene.AudioCodec.String)
}
if ffmpeg.IsStreamable(videoCodec, audioCodec, container) {
if !t.Force && ffmpeg.IsStreamable(videoCodec, audioCodec, container) {
return
}
@@ -95,6 +98,14 @@ func (t *GenerateTranscodeTask) Start(ctc context.Context) {
// used only when counting files to generate, doesn't affect the actual transcode generation
// if container is missing from DB it is treated as non supported in order not to delay the user
func (t *GenerateTranscodeTask) isTranscodeNeeded() bool {
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
if !t.Overwrite && hasTranscode {
return false
}
if t.Force {
return true
}
videoCodec := t.Scene.VideoCodec.String
container := ""
@@ -111,9 +122,5 @@ func (t *GenerateTranscodeTask) isTranscodeNeeded() bool {
return false
}
hasTranscode := HasTranscode(&t.Scene, t.fileNamingAlgorithm)
if !t.Overwrite && hasTranscode {
return false
}
return true
}

View File

@@ -1,4 +1,5 @@
### ✨ New Features
* Added option to force generation of transcodes for selected scenes. ([#2126](https://github.com/stashapp/stash/pull/2126))
* Added selective clean task. ([#2125](https://github.com/stashapp/stash/pull/2125))
* Show heatmaps and median stroke speed for interactive scenes on the scenes page. ([#2096](https://github.com/stashapp/stash/pull/2096))
* Save task options when scanning, generating and auto-tagging. ([#1949](https://github.com/stashapp/stash/pull/1949), [#2061](https://github.com/stashapp/stash/pull/2061))

View File

@@ -1,15 +1,11 @@
import React, { useState, useEffect, useMemo } from "react";
import { Form, Button } from "react-bootstrap";
import {
mutateMetadataGenerate,
useConfigureDefaults,
} from "src/core/StashService";
import { Modal, Icon, OperationButton } from "src/components/Shared";
import { mutateMetadataGenerate } from "src/core/StashService";
import { Modal, Icon } from "src/components/Shared";
import { useToast } from "src/hooks";
import * as GQL from "src/core/generated-graphql";
import { FormattedMessage, useIntl } from "react-intl";
import { ConfigurationContext } from "src/hooks/Config";
// import { DirectorySelectionDialog } from "../Settings/SettingsTasksPanel/DirectorySelectionDialog";
import { Manual } from "../Help/Manual";
import { withoutTypename } from "src/utils";
import { GenerateOptions } from "../Settings/Tasks/GenerateOptions";
@@ -25,7 +21,6 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
onClose,
}) => {
const { configuration } = React.useContext(ConfigurationContext);
const [configureDefaults] = useConfigureDefaults();
function getDefaultOptions(): GQL.GenerateMetadataInput {
return {
@@ -45,10 +40,7 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
getDefaultOptions()
);
const [configRead, setConfigRead] = useState(false);
const [paths /* , setPaths */] = useState<string[]>([]);
const [showManual, setShowManual] = useState(false);
// const [settingPaths, setSettingPaths] = useState(false);
const [savingDefaults, setSavingDefaults] = useState(false);
const [animation, setAnimation] = useState(true);
const intl = useIntl();
@@ -111,16 +103,7 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
</Form.Group>
);
}
const message = paths.length ? (
<div>
<FormattedMessage id="config.tasks.generate.generating_from_paths" />:
<ul>
{paths.map((p) => (
<li key={p}>{p}</li>
))}
</ul>
</div>
) : (
const message = (
<span>
<FormattedMessage
id="config.tasks.generate.generating_scenes"
@@ -140,27 +123,12 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
</span>
);
// function onClick() {
// setAnimation(false);
// setSettingPaths(true);
// }
return (
<Form.Group className="dialog-selected-folders">
<div>
{message}
{/* <div>
<Button
title={intl.formatMessage({ id: "actions.select_folders" })}
onClick={() => onClick()}
>
<Icon icon="folder-open" />
</Button>
</div> */}
</div>
<div>{message}</div>
</Form.Group>
);
}, [selectedIds, intl, paths]);
}, [selectedIds, intl]);
async function onGenerate() {
try {
@@ -181,58 +149,11 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
}
}
function makeDefaultGenerateInput() {
const ret = options;
// const { paths: _paths, ...withoutSpecifics } = ret;
const { overwrite: _overwrite, ...withoutSpecifics } = ret;
return withoutSpecifics;
}
function onShowManual() {
setAnimation(false);
setShowManual(true);
}
async function setAsDefault() {
try {
setSavingDefaults(true);
await configureDefaults({
variables: {
input: {
generate: makeDefaultGenerateInput(),
},
},
});
Toast.success({
content: intl.formatMessage(
{ id: "config.tasks.defaults_set" },
{ action: intl.formatMessage({ id: "actions.generate" }) }
),
});
} catch (e) {
Toast.error(e);
} finally {
setSavingDefaults(false);
}
}
// if (settingPaths) {
// return (
// <DirectorySelectionDialog
// animation={false}
// allowEmpty
// initialPaths={paths}
// onClose={(p) => {
// if (p) {
// setPaths(p);
// }
// setSettingPaths(false);
// }}
// />
// );
// }
if (showManual) {
return (
<Manual
@@ -259,12 +180,6 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
text: intl.formatMessage({ id: "actions.cancel" }),
variant: "secondary",
}}
disabled={savingDefaults}
footerButtons={
<OperationButton variant="secondary" operation={setAsDefault}>
<FormattedMessage id="actions.set_as_default" />
</OperationButton>
}
leftFooterButtons={
<Button
title="Help"
@@ -278,7 +193,11 @@ export const GenerateDialog: React.FC<ISceneGenerateDialog> = ({
<Form>
{selectionStatus}
<SettingSection>
<GenerateOptions options={options} setOptions={setOptions} />
<GenerateOptions
options={options}
setOptions={setOptions}
selection
/>
</SettingSection>
</Form>
</Modal>

View File

@@ -8,11 +8,13 @@ import {
import { useIntl } from "react-intl";
interface IGenerateOptions {
selection?: boolean;
options: GQL.GenerateMetadataInput;
setOptions: (s: GQL.GenerateMetadataInput) => void;
}
export const GenerateOptions: React.FC<IGenerateOptions> = ({
selection,
options,
setOptions: setOptionsState,
}) => {
@@ -110,6 +112,18 @@ export const GenerateOptions: React.FC<IGenerateOptions> = ({
tooltipID="dialogs.scene_gen.transcodes_tooltip"
onChange={(v) => setOptions({ transcodes: v })}
/>
{selection ? (
<BooleanSetting
id="force-transcode"
className="sub-setting"
checked={options.forceTranscodes ?? false}
disabled={!options.transcodes}
headingID="dialogs.scene_gen.force_transcodes"
tooltipID="dialogs.scene_gen.force_transcodes_tooltip"
onChange={(v) => setOptions({ forceTranscodes: v })}
/>
) : undefined}
<BooleanSetting
id="phash-task"
checked={options.phashes ?? false}

View File

@@ -585,6 +585,8 @@
},
"overwrite_filter_confirm": "Are you sure you want to overwrite existing saved query {entityName}?",
"scene_gen": {
"force_transcodes": "Force Transcode generation",
"force_transcodes_tooltip": "By default, transcodes are only generated when the video file is not supported in the browser. When enabled, transcodes will be generated even when the video file appears to be supported in the browser.",
"image_previews": "Animated Image Previews",
"image_previews_tooltip": "Animated WebP previews, only required if Preview Type is set to Animated Image.",
"interactive_heatmap_speed": "Generate heatmaps and speeds for interactive scenes",