@frkntmbs/strapi-plugin-video-optimizer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +286 -0
- package/admin/custom.d.ts +8 -0
- package/admin/src/buildVersion.ts +3 -0
- package/admin/src/components/AssetOptimizationLabel.tsx +61 -0
- package/admin/src/components/BridgeProviders.tsx +123 -0
- package/admin/src/components/MediaLibraryCacheBridge.tsx +24 -0
- package/admin/src/components/MediaLibraryCardActionsBridge.tsx +249 -0
- package/admin/src/components/MediaLibraryJobWatcher.tsx +136 -0
- package/admin/src/components/MediaLibraryProgressBridge.tsx +97 -0
- package/admin/src/components/OptimizationChoicePicker.tsx +65 -0
- package/admin/src/components/OptimizationResizeFields.tsx +120 -0
- package/admin/src/components/OptimizationVideoFields.tsx +217 -0
- package/admin/src/components/UploadEnhancerBridge.tsx +205 -0
- package/admin/src/components/upload/PendingAssetStep.tsx +97 -0
- package/admin/src/defaultGlobalSettings.ts +32 -0
- package/admin/src/hooks/useDefaultOptimizationMode.ts +24 -0
- package/admin/src/hooks/useUploadWithOptimizer.ts +45 -0
- package/admin/src/index.ts +84 -0
- package/admin/src/pages/SettingsPage.tsx +208 -0
- package/admin/src/pluginId.ts +79 -0
- package/admin/src/translations/en.json +74 -0
- package/admin/src/translations/tr.json +74 -0
- package/admin/src/utils/adminFetch.ts +57 -0
- package/admin/src/utils/captureQueryClient.ts +34 -0
- package/admin/src/utils/debugMediaLibraryProgress.ts +70 -0
- package/admin/src/utils/extractAssetDimensions.ts +22 -0
- package/admin/src/utils/initJobPoller.ts +173 -0
- package/admin/src/utils/initMediaLibraryCardActions.ts +308 -0
- package/admin/src/utils/initMediaLibraryProgress.ts +219 -0
- package/admin/src/utils/initUploadEnhancer.ts +447 -0
- package/admin/src/utils/invalidateMediaLibrary.ts +203 -0
- package/admin/src/utils/jobProgressStore.ts +113 -0
- package/admin/src/utils/mediaLibraryCardMatch.ts +414 -0
- package/admin/src/utils/mediaLibraryCardStore.ts +223 -0
- package/admin/src/utils/mediaLibraryQueryBridge.ts +113 -0
- package/admin/src/utils/mediaLibraryRoute.ts +9 -0
- package/admin/src/utils/optimizationFields.ts +17 -0
- package/admin/src/utils/probeVideoDimensions.ts +94 -0
- package/admin/src/utils/uploadAssetStore.ts +670 -0
- package/admin/tsconfig.json +8 -0
- package/dist/admin/SettingsPage-CN2fR83m.js +150 -0
- package/dist/admin/SettingsPage-D6e536P0.mjs +150 -0
- package/dist/admin/en-CqM903j3.js +77 -0
- package/dist/admin/en-CsHicGzL.mjs +77 -0
- package/dist/admin/index-BjWoS0YU.js +2542 -0
- package/dist/admin/index-Cs_uiChW.mjs +2541 -0
- package/dist/admin/index-DOuHOS2G.js +8799 -0
- package/dist/admin/index-rAmxCQz6.mjs +8781 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.mjs +4 -0
- package/dist/admin/tr-Y0-ANilh.mjs +77 -0
- package/dist/admin/tr-muzHkdC4.js +77 -0
- package/dist/server/index.js +1538 -0
- package/dist/server/index.mjs +1533 -0
- package/package.json +100 -0
- package/server/index.js +1 -0
- package/server/src/bootstrap.ts +377 -0
- package/server/src/buildVersion.ts +1 -0
- package/server/src/config/defaults.ts +91 -0
- package/server/src/config/index.ts +51 -0
- package/server/src/constants.ts +83 -0
- package/server/src/controllers/index.ts +7 -0
- package/server/src/controllers/job.ts +102 -0
- package/server/src/controllers/preference.ts +206 -0
- package/server/src/index.ts +15 -0
- package/server/src/register.ts +19 -0
- package/server/src/routes/index.ts +103 -0
- package/server/src/services/index.ts +9 -0
- package/server/src/services/job-queue.ts +663 -0
- package/server/src/services/optimizer.ts +284 -0
- package/server/src/services/preference.ts +172 -0
- package/server/src/utils/request-context.ts +7 -0
- package/server/src/utils/upload-preferences-context.ts +202 -0
- package/server/tsconfig.json +8 -0
- package/strapi-admin.js +7 -0
- package/strapi-server.js +7 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const designSystem = require("@strapi/design-system");
|
|
6
|
+
const icons = require("@strapi/icons");
|
|
7
|
+
const admin = require("@strapi/strapi/admin");
|
|
8
|
+
const index = require("./index-DOuHOS2G.js");
|
|
9
|
+
const SETTINGS_READ = [{ action: "plugin::video-optimizer.settings.read", subject: null }];
|
|
10
|
+
const SETTINGS_UPDATE = [{ action: "plugin::video-optimizer.settings.update", subject: null }];
|
|
11
|
+
const CHOICES = ["original", "global", "custom"];
|
|
12
|
+
const SettingsPage = () => {
|
|
13
|
+
const { formatMessage } = index.useIntl();
|
|
14
|
+
const { get, put } = admin.useFetchClient();
|
|
15
|
+
const { toggleNotification } = admin.useNotification();
|
|
16
|
+
const { allowedActions: readActions } = admin.useRBAC(SETTINGS_READ);
|
|
17
|
+
const { allowedActions: updateActions } = admin.useRBAC(SETTINGS_UPDATE);
|
|
18
|
+
const canReadGlobal = readActions.canRead;
|
|
19
|
+
const canUpdateGlobal = updateActions.canUpdate;
|
|
20
|
+
const [globalSettings, setGlobalSettings] = React.useState(index.DEFAULT_GLOBAL_SETTINGS);
|
|
21
|
+
const [isLoading, setIsLoading] = React.useState(true);
|
|
22
|
+
const [isSaving, setIsSaving] = React.useState(false);
|
|
23
|
+
React.useEffect(() => {
|
|
24
|
+
const load = async () => {
|
|
25
|
+
if (!canReadGlobal) {
|
|
26
|
+
setIsLoading(false);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const { data: settings } = await get(`/${index.PLUGIN_ID}/settings`);
|
|
31
|
+
setGlobalSettings(index.mergeGlobalSettings(settings));
|
|
32
|
+
} catch {
|
|
33
|
+
toggleNotification({
|
|
34
|
+
type: "danger",
|
|
35
|
+
message: formatMessage({ id: index.getTranslationKey("settings.error") })
|
|
36
|
+
});
|
|
37
|
+
} finally {
|
|
38
|
+
setIsLoading(false);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
load();
|
|
42
|
+
}, [canReadGlobal, formatMessage, get, toggleNotification]);
|
|
43
|
+
const handleSave = async () => {
|
|
44
|
+
if (!canUpdateGlobal) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setIsSaving(true);
|
|
48
|
+
try {
|
|
49
|
+
await put(`/${index.PLUGIN_ID}/settings`, globalSettings);
|
|
50
|
+
toggleNotification({
|
|
51
|
+
type: "success",
|
|
52
|
+
message: formatMessage({ id: index.getTranslationKey("settings.saved") })
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
toggleNotification({
|
|
56
|
+
type: "danger",
|
|
57
|
+
message: formatMessage({ id: index.getTranslationKey("settings.error") })
|
|
58
|
+
});
|
|
59
|
+
} finally {
|
|
60
|
+
setIsSaving(false);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (isLoading) {
|
|
64
|
+
return /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Loading, {});
|
|
65
|
+
}
|
|
66
|
+
if (!canReadGlobal) {
|
|
67
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: formatMessage({ id: index.getTranslationKey("settings.page.title") }) }),
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx(admin.Layouts.Header, { title: formatMessage({ id: index.getTranslationKey("settings.page.title") }), subtitle: formatMessage({ id: index.getTranslationKey("settings.page.description") }) }),
|
|
70
|
+
/* @__PURE__ */ jsxRuntime.jsx(admin.Layouts.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({ id: index.getTranslationKey("settings.global.noPermission") }) }) })
|
|
71
|
+
] });
|
|
72
|
+
}
|
|
73
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
|
|
74
|
+
/* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: formatMessage({ id: index.getTranslationKey("settings.page.title") }) }),
|
|
75
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
admin.Layouts.Header,
|
|
77
|
+
{
|
|
78
|
+
title: formatMessage({ id: index.getTranslationKey("settings.page.title") }),
|
|
79
|
+
subtitle: formatMessage({ id: index.getTranslationKey("settings.page.description") }),
|
|
80
|
+
primaryAction: canUpdateGlobal ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleSave, loading: isSaving, startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Check, {}), size: "S", children: formatMessage({ id: index.getTranslationKey("settings.save") }) }) : void 0
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsxRuntime.jsx(admin.Layouts.Content, { children: /* @__PURE__ */ jsxRuntime.jsx(admin.Layouts.Root, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
84
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
85
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: index.getTranslationKey("settings.global.defaultChoiceTitle") }) }),
|
|
86
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({ id: index.getTranslationKey("settings.global.defaultChoiceDescription") }) }) }),
|
|
87
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Root, { gap: 6, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "defaultChoice", children: [
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({ id: index.getTranslationKey("settings.global.defaultChoice") }) }),
|
|
89
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelect, { value: globalSettings.defaultChoice, onChange: (value) => setGlobalSettings((prev) => ({ ...prev, defaultChoice: value })), disabled: !canUpdateGlobal || isSaving, children: CHOICES.map((choice) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { value: choice, children: formatMessage({ id: index.getTranslationKey(`choice.${choice}`) }) }, choice)) }),
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: formatMessage({ id: index.getTranslationKey("settings.global.defaultChoiceHint") }) })
|
|
91
|
+
] }) }) })
|
|
92
|
+
] }),
|
|
93
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
94
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: index.getTranslationKey("settings.global.profileTitle") }) }),
|
|
95
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({ id: index.getTranslationKey("settings.global.profileDescription") }) }) }),
|
|
96
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, children: [
|
|
97
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.OptimizationVideoFields, { value: globalSettings, onChange: (patch) => setGlobalSettings((prev) => ({ ...prev, ...patch })), disabled: !canUpdateGlobal || isSaving, namePrefix: "global" }),
|
|
98
|
+
/* @__PURE__ */ jsxRuntime.jsx(index.OptimizationResizeFields, { value: globalSettings, onChange: (patch) => setGlobalSettings((prev) => ({ ...prev, ...patch })), disabled: !canUpdateGlobal || isSaving, namePrefix: "global", variant: "global" })
|
|
99
|
+
] })
|
|
100
|
+
] }),
|
|
101
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
102
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: index.getTranslationKey("settings.global.concurrencyTitle") }) }),
|
|
103
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({ id: index.getTranslationKey("settings.global.concurrencyDescription") }) }) }),
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 6, children: [
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "maxConcurrentJobs", children: [
|
|
106
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({ id: index.getTranslationKey("settings.global.maxConcurrentJobs") }) }),
|
|
107
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
108
|
+
designSystem.TextInput,
|
|
109
|
+
{
|
|
110
|
+
type: "number",
|
|
111
|
+
min: 1,
|
|
112
|
+
max: index.MAX_CONCURRENT_JOBS_LIMIT,
|
|
113
|
+
value: String(globalSettings.maxConcurrentJobs),
|
|
114
|
+
onChange: (event) => setGlobalSettings((prev) => ({
|
|
115
|
+
...prev,
|
|
116
|
+
maxConcurrentJobs: index.clampMaxConcurrentJobs(Number(event.target.value) || 1)
|
|
117
|
+
})),
|
|
118
|
+
disabled: !canUpdateGlobal || isSaving
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: formatMessage({ id: index.getTranslationKey("settings.global.maxConcurrentJobsHint") }) })
|
|
122
|
+
] }) }),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Field.Root, { name: "maxFfmpegThreads", children: [
|
|
124
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: formatMessage({ id: index.getTranslationKey("settings.global.maxFfmpegThreads") }) }),
|
|
125
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
126
|
+
designSystem.TextInput,
|
|
127
|
+
{
|
|
128
|
+
type: "number",
|
|
129
|
+
min: 1,
|
|
130
|
+
max: index.MAX_FFMPEG_THREADS_LIMIT,
|
|
131
|
+
value: String(globalSettings.maxFfmpegThreads),
|
|
132
|
+
onChange: (event) => setGlobalSettings((prev) => ({
|
|
133
|
+
...prev,
|
|
134
|
+
maxFfmpegThreads: index.clampMaxFfmpegThreads(Number(event.target.value) || 1)
|
|
135
|
+
})),
|
|
136
|
+
disabled: !canUpdateGlobal || isSaving
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, { children: formatMessage({ id: index.getTranslationKey("settings.global.maxFfmpegThreadsHint") }) })
|
|
140
|
+
] }) })
|
|
141
|
+
] })
|
|
142
|
+
] })
|
|
143
|
+
] }) }) })
|
|
144
|
+
] });
|
|
145
|
+
};
|
|
146
|
+
const ProtectedSettingsPage = () => {
|
|
147
|
+
return /* @__PURE__ */ jsxRuntime.jsx(SettingsPage, {});
|
|
148
|
+
};
|
|
149
|
+
exports.ProtectedSettingsPage = ProtectedSettingsPage;
|
|
150
|
+
exports.SettingsPage = SettingsPage;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { Typography, Button, Flex, Box, Grid, Field, SingleSelect, SingleSelectOption, TextInput } from "@strapi/design-system";
|
|
4
|
+
import { Check } from "@strapi/icons";
|
|
5
|
+
import { useFetchClient, useNotification, useRBAC, Page, Layouts } from "@strapi/strapi/admin";
|
|
6
|
+
import { u as useIntl, D as DEFAULT_GLOBAL_SETTINGS, g as getTranslationKey, O as OptimizationVideoFields, a as OptimizationResizeFields, M as MAX_CONCURRENT_JOBS_LIMIT, c as clampMaxConcurrentJobs, b as MAX_FFMPEG_THREADS_LIMIT, d as clampMaxFfmpegThreads, P as PLUGIN_ID, m as mergeGlobalSettings } from "./index-rAmxCQz6.mjs";
|
|
7
|
+
const SETTINGS_READ = [{ action: "plugin::video-optimizer.settings.read", subject: null }];
|
|
8
|
+
const SETTINGS_UPDATE = [{ action: "plugin::video-optimizer.settings.update", subject: null }];
|
|
9
|
+
const CHOICES = ["original", "global", "custom"];
|
|
10
|
+
const SettingsPage = () => {
|
|
11
|
+
const { formatMessage } = useIntl();
|
|
12
|
+
const { get, put } = useFetchClient();
|
|
13
|
+
const { toggleNotification } = useNotification();
|
|
14
|
+
const { allowedActions: readActions } = useRBAC(SETTINGS_READ);
|
|
15
|
+
const { allowedActions: updateActions } = useRBAC(SETTINGS_UPDATE);
|
|
16
|
+
const canReadGlobal = readActions.canRead;
|
|
17
|
+
const canUpdateGlobal = updateActions.canUpdate;
|
|
18
|
+
const [globalSettings, setGlobalSettings] = useState(DEFAULT_GLOBAL_SETTINGS);
|
|
19
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
20
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
const load = async () => {
|
|
23
|
+
if (!canReadGlobal) {
|
|
24
|
+
setIsLoading(false);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const { data: settings } = await get(`/${PLUGIN_ID}/settings`);
|
|
29
|
+
setGlobalSettings(mergeGlobalSettings(settings));
|
|
30
|
+
} catch {
|
|
31
|
+
toggleNotification({
|
|
32
|
+
type: "danger",
|
|
33
|
+
message: formatMessage({ id: getTranslationKey("settings.error") })
|
|
34
|
+
});
|
|
35
|
+
} finally {
|
|
36
|
+
setIsLoading(false);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
load();
|
|
40
|
+
}, [canReadGlobal, formatMessage, get, toggleNotification]);
|
|
41
|
+
const handleSave = async () => {
|
|
42
|
+
if (!canUpdateGlobal) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
setIsSaving(true);
|
|
46
|
+
try {
|
|
47
|
+
await put(`/${PLUGIN_ID}/settings`, globalSettings);
|
|
48
|
+
toggleNotification({
|
|
49
|
+
type: "success",
|
|
50
|
+
message: formatMessage({ id: getTranslationKey("settings.saved") })
|
|
51
|
+
});
|
|
52
|
+
} catch {
|
|
53
|
+
toggleNotification({
|
|
54
|
+
type: "danger",
|
|
55
|
+
message: formatMessage({ id: getTranslationKey("settings.error") })
|
|
56
|
+
});
|
|
57
|
+
} finally {
|
|
58
|
+
setIsSaving(false);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
if (isLoading) {
|
|
62
|
+
return /* @__PURE__ */ jsx(Page.Loading, {});
|
|
63
|
+
}
|
|
64
|
+
if (!canReadGlobal) {
|
|
65
|
+
return /* @__PURE__ */ jsxs(Page.Main, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Page.Title, { children: formatMessage({ id: getTranslationKey("settings.page.title") }) }),
|
|
67
|
+
/* @__PURE__ */ jsx(Layouts.Header, { title: formatMessage({ id: getTranslationKey("settings.page.title") }), subtitle: formatMessage({ id: getTranslationKey("settings.page.description") }) }),
|
|
68
|
+
/* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({ id: getTranslationKey("settings.global.noPermission") }) }) })
|
|
69
|
+
] });
|
|
70
|
+
}
|
|
71
|
+
return /* @__PURE__ */ jsxs(Page.Main, { children: [
|
|
72
|
+
/* @__PURE__ */ jsx(Page.Title, { children: formatMessage({ id: getTranslationKey("settings.page.title") }) }),
|
|
73
|
+
/* @__PURE__ */ jsx(
|
|
74
|
+
Layouts.Header,
|
|
75
|
+
{
|
|
76
|
+
title: formatMessage({ id: getTranslationKey("settings.page.title") }),
|
|
77
|
+
subtitle: formatMessage({ id: getTranslationKey("settings.page.description") }),
|
|
78
|
+
primaryAction: canUpdateGlobal ? /* @__PURE__ */ jsx(Button, { onClick: handleSave, loading: isSaving, startIcon: /* @__PURE__ */ jsx(Check, {}), size: "S", children: formatMessage({ id: getTranslationKey("settings.save") }) }) : void 0
|
|
79
|
+
}
|
|
80
|
+
),
|
|
81
|
+
/* @__PURE__ */ jsx(Layouts.Content, { children: /* @__PURE__ */ jsx(Layouts.Root, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 6, children: [
|
|
82
|
+
/* @__PURE__ */ jsxs(Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
83
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: getTranslationKey("settings.global.defaultChoiceTitle") }) }),
|
|
84
|
+
/* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({ id: getTranslationKey("settings.global.defaultChoiceDescription") }) }) }),
|
|
85
|
+
/* @__PURE__ */ jsx(Grid.Root, { gap: 6, children: /* @__PURE__ */ jsx(Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxs(Field.Root, { name: "defaultChoice", children: [
|
|
86
|
+
/* @__PURE__ */ jsx(Field.Label, { children: formatMessage({ id: getTranslationKey("settings.global.defaultChoice") }) }),
|
|
87
|
+
/* @__PURE__ */ jsx(SingleSelect, { value: globalSettings.defaultChoice, onChange: (value) => setGlobalSettings((prev) => ({ ...prev, defaultChoice: value })), disabled: !canUpdateGlobal || isSaving, children: CHOICES.map((choice) => /* @__PURE__ */ jsx(SingleSelectOption, { value: choice, children: formatMessage({ id: getTranslationKey(`choice.${choice}`) }) }, choice)) }),
|
|
88
|
+
/* @__PURE__ */ jsx(Field.Hint, { children: formatMessage({ id: getTranslationKey("settings.global.defaultChoiceHint") }) })
|
|
89
|
+
] }) }) })
|
|
90
|
+
] }),
|
|
91
|
+
/* @__PURE__ */ jsxs(Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
92
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: getTranslationKey("settings.global.profileTitle") }) }),
|
|
93
|
+
/* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({ id: getTranslationKey("settings.global.profileDescription") }) }) }),
|
|
94
|
+
/* @__PURE__ */ jsxs(Grid.Root, { gap: 6, children: [
|
|
95
|
+
/* @__PURE__ */ jsx(OptimizationVideoFields, { value: globalSettings, onChange: (patch) => setGlobalSettings((prev) => ({ ...prev, ...patch })), disabled: !canUpdateGlobal || isSaving, namePrefix: "global" }),
|
|
96
|
+
/* @__PURE__ */ jsx(OptimizationResizeFields, { value: globalSettings, onChange: (patch) => setGlobalSettings((prev) => ({ ...prev, ...patch })), disabled: !canUpdateGlobal || isSaving, namePrefix: "global", variant: "global" })
|
|
97
|
+
] })
|
|
98
|
+
] }),
|
|
99
|
+
/* @__PURE__ */ jsxs(Box, { background: "neutral0", padding: 6, shadow: "filterShadow", hasRadius: true, children: [
|
|
100
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", tag: "h2", children: formatMessage({ id: getTranslationKey("settings.global.concurrencyTitle") }) }),
|
|
101
|
+
/* @__PURE__ */ jsx(Box, { paddingTop: 2, paddingBottom: 4, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({ id: getTranslationKey("settings.global.concurrencyDescription") }) }) }),
|
|
102
|
+
/* @__PURE__ */ jsxs(Grid.Root, { gap: 6, children: [
|
|
103
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxs(Field.Root, { name: "maxConcurrentJobs", children: [
|
|
104
|
+
/* @__PURE__ */ jsx(Field.Label, { children: formatMessage({ id: getTranslationKey("settings.global.maxConcurrentJobs") }) }),
|
|
105
|
+
/* @__PURE__ */ jsx(
|
|
106
|
+
TextInput,
|
|
107
|
+
{
|
|
108
|
+
type: "number",
|
|
109
|
+
min: 1,
|
|
110
|
+
max: MAX_CONCURRENT_JOBS_LIMIT,
|
|
111
|
+
value: String(globalSettings.maxConcurrentJobs),
|
|
112
|
+
onChange: (event) => setGlobalSettings((prev) => ({
|
|
113
|
+
...prev,
|
|
114
|
+
maxConcurrentJobs: clampMaxConcurrentJobs(Number(event.target.value) || 1)
|
|
115
|
+
})),
|
|
116
|
+
disabled: !canUpdateGlobal || isSaving
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
/* @__PURE__ */ jsx(Field.Hint, { children: formatMessage({ id: getTranslationKey("settings.global.maxConcurrentJobsHint") }) })
|
|
120
|
+
] }) }),
|
|
121
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, xs: 12, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsxs(Field.Root, { name: "maxFfmpegThreads", children: [
|
|
122
|
+
/* @__PURE__ */ jsx(Field.Label, { children: formatMessage({ id: getTranslationKey("settings.global.maxFfmpegThreads") }) }),
|
|
123
|
+
/* @__PURE__ */ jsx(
|
|
124
|
+
TextInput,
|
|
125
|
+
{
|
|
126
|
+
type: "number",
|
|
127
|
+
min: 1,
|
|
128
|
+
max: MAX_FFMPEG_THREADS_LIMIT,
|
|
129
|
+
value: String(globalSettings.maxFfmpegThreads),
|
|
130
|
+
onChange: (event) => setGlobalSettings((prev) => ({
|
|
131
|
+
...prev,
|
|
132
|
+
maxFfmpegThreads: clampMaxFfmpegThreads(Number(event.target.value) || 1)
|
|
133
|
+
})),
|
|
134
|
+
disabled: !canUpdateGlobal || isSaving
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
/* @__PURE__ */ jsx(Field.Hint, { children: formatMessage({ id: getTranslationKey("settings.global.maxFfmpegThreadsHint") }) })
|
|
138
|
+
] }) })
|
|
139
|
+
] })
|
|
140
|
+
] })
|
|
141
|
+
] }) }) })
|
|
142
|
+
] });
|
|
143
|
+
};
|
|
144
|
+
const ProtectedSettingsPage = () => {
|
|
145
|
+
return /* @__PURE__ */ jsx(SettingsPage, {});
|
|
146
|
+
};
|
|
147
|
+
export {
|
|
148
|
+
ProtectedSettingsPage,
|
|
149
|
+
SettingsPage
|
|
150
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const en = {
|
|
4
|
+
"plugin.name": "Video Optimizer",
|
|
5
|
+
"settings.section-label": "Video Optimizer",
|
|
6
|
+
"settings.page.title": "Video Optimizer Settings",
|
|
7
|
+
"settings.page.description": "Configure global defaults used when uploading videos. Each video can be overridden in the upload dialog.",
|
|
8
|
+
"settings.format.mp4": "MP4 (H.264)",
|
|
9
|
+
"settings.format.webm": "WebM (VP9)",
|
|
10
|
+
"settings.audioMode.keep": "Keep original audio",
|
|
11
|
+
"settings.audioMode.remove": "Remove audio",
|
|
12
|
+
"settings.audioMode.compress": "Compress audio",
|
|
13
|
+
"settings.global.title": "Global settings",
|
|
14
|
+
"settings.global.description": "Default optimization settings for all video uploads. Individual videos can be changed in the Media Library upload dialog.",
|
|
15
|
+
"settings.global.defaultChoiceTitle": "Default upload choice",
|
|
16
|
+
"settings.global.defaultChoiceDescription": "Choose which option is pre-selected when opening the upload dialog for a new video.",
|
|
17
|
+
"settings.global.defaultChoice": "Default choice",
|
|
18
|
+
"settings.global.defaultChoiceHint": "This choice is applied automatically unless changed per video in the upload dialog.",
|
|
19
|
+
"settings.global.profileTitle": "Global optimization profile",
|
|
20
|
+
"settings.global.profileDescription": "Used when a video is set to Apply global settings, and as the starting values for Custom.",
|
|
21
|
+
"settings.global.defaultFormat": "Output format",
|
|
22
|
+
"settings.global.videoCodec": "Video codec",
|
|
23
|
+
"settings.global.crf": "CRF (quality)",
|
|
24
|
+
"settings.global.crfHint": "Lower values mean better quality and larger files (0–51).",
|
|
25
|
+
"settings.global.preset": "Encode preset",
|
|
26
|
+
"settings.global.audioMode": "Audio handling",
|
|
27
|
+
"settings.global.audioBitrate": "Audio bitrate",
|
|
28
|
+
"settings.global.codecHint": "Codec is selected automatically based on the output format.",
|
|
29
|
+
"settings.global.concurrencyTitle": "Processing concurrency",
|
|
30
|
+
"settings.global.concurrencyDescription": "Control how many FFmpeg jobs can run at the same time on this server.",
|
|
31
|
+
"settings.global.maxConcurrentJobs": "Max concurrent jobs",
|
|
32
|
+
"settings.global.maxConcurrentJobsHint": "1 is recommended on small servers. Can be set between 1 and 32.",
|
|
33
|
+
"settings.global.maxFfmpegThreads": "Max FFmpeg threads per job",
|
|
34
|
+
"settings.global.maxFfmpegThreadsHint": "Limits CPU usage per encode. Use 1–2 on weak VPS servers. Range: 1–8.",
|
|
35
|
+
"settings.resize.title": "Output dimensions",
|
|
36
|
+
"settings.resize.width": "Width (px)",
|
|
37
|
+
"settings.resize.height": "Height (px)",
|
|
38
|
+
"settings.resize.hint": "Defaults to the original video size. Change either value to resize; the other updates to keep aspect ratio.",
|
|
39
|
+
"settings.resize.globalHint": "Videos larger than this are scaled down while preserving aspect ratio.",
|
|
40
|
+
"settings.global.noPermission": "You do not have permission to view global Video Optimizer settings.",
|
|
41
|
+
"settings.save": "Save",
|
|
42
|
+
"settings.saved": "Settings saved",
|
|
43
|
+
"settings.error": "Failed to save settings",
|
|
44
|
+
"choice.original": "Keep original",
|
|
45
|
+
"choice.original.description": "No optimization is applied. The file is uploaded exactly as selected.",
|
|
46
|
+
"choice.global": "Apply global settings",
|
|
47
|
+
"choice.global.description": "Uses the global optimization profile configured in Settings.",
|
|
48
|
+
"choice.custom": "Custom",
|
|
49
|
+
"choice.custom.description": "Configure format and quality settings specifically for this video.",
|
|
50
|
+
"upload.optimization.label": "Optimization",
|
|
51
|
+
"upload.button.label": "Optimization settings",
|
|
52
|
+
"upload.modal.title": "Video optimization",
|
|
53
|
+
"upload.modal.save": "Save",
|
|
54
|
+
"upload.modal.cancel": "Cancel",
|
|
55
|
+
"upload.mode.footer.global": "Global: {mode}",
|
|
56
|
+
"upload.mode.footer.custom": "Custom: {mode}",
|
|
57
|
+
"jobs.status.queued": "Queued for optimization",
|
|
58
|
+
"jobs.status.processing": "Optimizing",
|
|
59
|
+
"jobs.status.completed": "Optimization completed",
|
|
60
|
+
"jobs.status.failed": "Optimization failed",
|
|
61
|
+
"jobs.stage.queued": "Waiting in queue",
|
|
62
|
+
"jobs.stage.preparing": "Preparing",
|
|
63
|
+
"jobs.stage.encoding": "Encoding video",
|
|
64
|
+
"jobs.stage.finalizing": "Finalizing",
|
|
65
|
+
"jobs.stage.completed": "Completed",
|
|
66
|
+
"jobs.stage.failed": "Failed",
|
|
67
|
+
"jobs.panel.title": "Video optimization",
|
|
68
|
+
"jobs.card.progress": "Optimizing: {progress}% → {format}",
|
|
69
|
+
"jobs.card.queued": "In queue",
|
|
70
|
+
"jobs.notification.completed": "Video #{fileId} optimized successfully. Media Library refreshed.",
|
|
71
|
+
"jobs.notification.failed": "Video optimization failed: {error}",
|
|
72
|
+
"mediaLibrary.button.optimize": "Optimize video",
|
|
73
|
+
"mediaLibrary.button.cancel": "Cancel optimization",
|
|
74
|
+
"mediaLibrary.modal.title": "Video optimization",
|
|
75
|
+
"mediaLibrary.modal.start": "Start optimization"
|
|
76
|
+
};
|
|
77
|
+
exports.default = en;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const en = {
|
|
2
|
+
"plugin.name": "Video Optimizer",
|
|
3
|
+
"settings.section-label": "Video Optimizer",
|
|
4
|
+
"settings.page.title": "Video Optimizer Settings",
|
|
5
|
+
"settings.page.description": "Configure global defaults used when uploading videos. Each video can be overridden in the upload dialog.",
|
|
6
|
+
"settings.format.mp4": "MP4 (H.264)",
|
|
7
|
+
"settings.format.webm": "WebM (VP9)",
|
|
8
|
+
"settings.audioMode.keep": "Keep original audio",
|
|
9
|
+
"settings.audioMode.remove": "Remove audio",
|
|
10
|
+
"settings.audioMode.compress": "Compress audio",
|
|
11
|
+
"settings.global.title": "Global settings",
|
|
12
|
+
"settings.global.description": "Default optimization settings for all video uploads. Individual videos can be changed in the Media Library upload dialog.",
|
|
13
|
+
"settings.global.defaultChoiceTitle": "Default upload choice",
|
|
14
|
+
"settings.global.defaultChoiceDescription": "Choose which option is pre-selected when opening the upload dialog for a new video.",
|
|
15
|
+
"settings.global.defaultChoice": "Default choice",
|
|
16
|
+
"settings.global.defaultChoiceHint": "This choice is applied automatically unless changed per video in the upload dialog.",
|
|
17
|
+
"settings.global.profileTitle": "Global optimization profile",
|
|
18
|
+
"settings.global.profileDescription": "Used when a video is set to Apply global settings, and as the starting values for Custom.",
|
|
19
|
+
"settings.global.defaultFormat": "Output format",
|
|
20
|
+
"settings.global.videoCodec": "Video codec",
|
|
21
|
+
"settings.global.crf": "CRF (quality)",
|
|
22
|
+
"settings.global.crfHint": "Lower values mean better quality and larger files (0–51).",
|
|
23
|
+
"settings.global.preset": "Encode preset",
|
|
24
|
+
"settings.global.audioMode": "Audio handling",
|
|
25
|
+
"settings.global.audioBitrate": "Audio bitrate",
|
|
26
|
+
"settings.global.codecHint": "Codec is selected automatically based on the output format.",
|
|
27
|
+
"settings.global.concurrencyTitle": "Processing concurrency",
|
|
28
|
+
"settings.global.concurrencyDescription": "Control how many FFmpeg jobs can run at the same time on this server.",
|
|
29
|
+
"settings.global.maxConcurrentJobs": "Max concurrent jobs",
|
|
30
|
+
"settings.global.maxConcurrentJobsHint": "1 is recommended on small servers. Can be set between 1 and 32.",
|
|
31
|
+
"settings.global.maxFfmpegThreads": "Max FFmpeg threads per job",
|
|
32
|
+
"settings.global.maxFfmpegThreadsHint": "Limits CPU usage per encode. Use 1–2 on weak VPS servers. Range: 1–8.",
|
|
33
|
+
"settings.resize.title": "Output dimensions",
|
|
34
|
+
"settings.resize.width": "Width (px)",
|
|
35
|
+
"settings.resize.height": "Height (px)",
|
|
36
|
+
"settings.resize.hint": "Defaults to the original video size. Change either value to resize; the other updates to keep aspect ratio.",
|
|
37
|
+
"settings.resize.globalHint": "Videos larger than this are scaled down while preserving aspect ratio.",
|
|
38
|
+
"settings.global.noPermission": "You do not have permission to view global Video Optimizer settings.",
|
|
39
|
+
"settings.save": "Save",
|
|
40
|
+
"settings.saved": "Settings saved",
|
|
41
|
+
"settings.error": "Failed to save settings",
|
|
42
|
+
"choice.original": "Keep original",
|
|
43
|
+
"choice.original.description": "No optimization is applied. The file is uploaded exactly as selected.",
|
|
44
|
+
"choice.global": "Apply global settings",
|
|
45
|
+
"choice.global.description": "Uses the global optimization profile configured in Settings.",
|
|
46
|
+
"choice.custom": "Custom",
|
|
47
|
+
"choice.custom.description": "Configure format and quality settings specifically for this video.",
|
|
48
|
+
"upload.optimization.label": "Optimization",
|
|
49
|
+
"upload.button.label": "Optimization settings",
|
|
50
|
+
"upload.modal.title": "Video optimization",
|
|
51
|
+
"upload.modal.save": "Save",
|
|
52
|
+
"upload.modal.cancel": "Cancel",
|
|
53
|
+
"upload.mode.footer.global": "Global: {mode}",
|
|
54
|
+
"upload.mode.footer.custom": "Custom: {mode}",
|
|
55
|
+
"jobs.status.queued": "Queued for optimization",
|
|
56
|
+
"jobs.status.processing": "Optimizing",
|
|
57
|
+
"jobs.status.completed": "Optimization completed",
|
|
58
|
+
"jobs.status.failed": "Optimization failed",
|
|
59
|
+
"jobs.stage.queued": "Waiting in queue",
|
|
60
|
+
"jobs.stage.preparing": "Preparing",
|
|
61
|
+
"jobs.stage.encoding": "Encoding video",
|
|
62
|
+
"jobs.stage.finalizing": "Finalizing",
|
|
63
|
+
"jobs.stage.completed": "Completed",
|
|
64
|
+
"jobs.stage.failed": "Failed",
|
|
65
|
+
"jobs.panel.title": "Video optimization",
|
|
66
|
+
"jobs.card.progress": "Optimizing: {progress}% → {format}",
|
|
67
|
+
"jobs.card.queued": "In queue",
|
|
68
|
+
"jobs.notification.completed": "Video #{fileId} optimized successfully. Media Library refreshed.",
|
|
69
|
+
"jobs.notification.failed": "Video optimization failed: {error}",
|
|
70
|
+
"mediaLibrary.button.optimize": "Optimize video",
|
|
71
|
+
"mediaLibrary.button.cancel": "Cancel optimization",
|
|
72
|
+
"mediaLibrary.modal.title": "Video optimization",
|
|
73
|
+
"mediaLibrary.modal.start": "Start optimization"
|
|
74
|
+
};
|
|
75
|
+
export {
|
|
76
|
+
en as default
|
|
77
|
+
};
|