sanity-plugin-mux-input 2.4.1 → 2.6.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/README.md +59 -55
- package/dist/index.js +511 -1079
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +515 -1083
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -19
- package/src/actions/secrets.ts +19 -9
- package/src/components/ConfigureApi.tsx +2 -0
- package/src/components/EditThumbnailDialog.tsx +122 -0
- package/src/components/MuxLogo.tsx +26 -447
- package/src/components/PlayerActionsMenu.tsx +13 -0
- package/src/components/UploadConfiguration.tsx +29 -26
- package/src/components/Uploader.tsx +21 -15
- package/src/components/VideoDetails/useVideoDetails.ts +5 -5
- package/src/components/VideoPlayer.tsx +66 -49
- package/src/components/VideoThumbnail.tsx +15 -8
- package/src/components/uploadConfiguration/PlaybackPolicy.tsx +44 -0
- package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +60 -0
- package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +29 -0
- package/src/context/DialogStateContext.tsx +36 -0
- package/src/hooks/useAssets.ts +26 -29
- package/src/util/createUrlParamsObject.ts +25 -0
- package/src/util/formatSeconds.ts +28 -1
- package/src/util/getAnimatedPosterSrc.ts +5 -13
- package/src/util/getPosterSrc.ts +10 -15
- package/src/util/getVideoMetadata.ts +1 -1
- package/src/util/types.ts +7 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-mux-input",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -41,8 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
|
|
44
|
-
"
|
|
45
|
-
"dev": "plugin-kit link-watch --strict",
|
|
44
|
+
"dev": "sanity dev",
|
|
46
45
|
"format": "prettier --write --cache --ignore-unknown .",
|
|
47
46
|
"link-watch": "plugin-kit link-watch",
|
|
48
47
|
"lint": "eslint .",
|
|
@@ -71,39 +70,36 @@
|
|
|
71
70
|
"use-error-boundary": "^2.0.6"
|
|
72
71
|
},
|
|
73
72
|
"devDependencies": {
|
|
74
|
-
"@sanity/client": "^6.
|
|
75
|
-
"@sanity/pkg-utils": "^6.
|
|
73
|
+
"@sanity/client": "^6.28.1",
|
|
74
|
+
"@sanity/pkg-utils": "^6.13.4",
|
|
76
75
|
"@sanity/plugin-kit": "4.0.19",
|
|
77
76
|
"@sanity/semantic-release-preset": "^5.0.0",
|
|
78
|
-
"@sanity/vision": "^3.
|
|
79
|
-
"@types/lodash": "^4.17.
|
|
80
|
-
"@types/react": "^18.3.
|
|
77
|
+
"@sanity/vision": "^3.77.2",
|
|
78
|
+
"@types/lodash": "^4.17.15",
|
|
79
|
+
"@types/react": "^18.3.18",
|
|
81
80
|
"@types/react-is": "^18.3.1",
|
|
82
|
-
"@types/styled-components": "^5.1.34",
|
|
83
81
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
84
82
|
"@typescript-eslint/parser": "^7.18.0",
|
|
85
83
|
"eslint": "^8.57.1",
|
|
86
84
|
"eslint-config-prettier": "^9.1.0",
|
|
87
85
|
"eslint-config-react-app": "^7.0.1",
|
|
88
|
-
"eslint-config-sanity": "^7.1.
|
|
86
|
+
"eslint-config-sanity": "^7.1.4",
|
|
89
87
|
"eslint-plugin-import": "^2.31.0",
|
|
90
|
-
"eslint-plugin-prettier": "^5.2.
|
|
88
|
+
"eslint-plugin-prettier": "^5.2.3",
|
|
91
89
|
"eslint-plugin-react-hooks": "^5.1.0",
|
|
92
90
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
93
91
|
"husky": "^9.0.11",
|
|
94
92
|
"lint-staged": "^15.2.2",
|
|
95
93
|
"npm-run-all2": "^5.0.2",
|
|
96
|
-
"prettier": "^3.
|
|
97
|
-
"prettier-plugin-packagejson": "^2.5.
|
|
94
|
+
"prettier": "^3.5.2",
|
|
95
|
+
"prettier-plugin-packagejson": "^2.5.9",
|
|
98
96
|
"react": "^18.3.1",
|
|
99
97
|
"react-dom": "^18.3.1",
|
|
100
98
|
"react-is": "^18.3.1",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"typescript": "^5.7.2",
|
|
106
|
-
"yalc": "1.0.0-pre.53"
|
|
99
|
+
"sanity": "^3.77.2",
|
|
100
|
+
"semantic-release": "^24.2.3",
|
|
101
|
+
"styled-components": "^6.1.15",
|
|
102
|
+
"typescript": "5.7.3"
|
|
107
103
|
},
|
|
108
104
|
"peerDependencies": {
|
|
109
105
|
"react": "^18",
|
package/src/actions/secrets.ts
CHANGED
|
@@ -32,15 +32,25 @@ export function saveSecrets(
|
|
|
32
32
|
return client.createOrReplace(doc)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function createSigningKeys(client: SanityClient) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
export async function createSigningKeys(client: SanityClient) {
|
|
36
|
+
try {
|
|
37
|
+
const {dataset} = client.config()
|
|
38
|
+
const res = await client.request<{
|
|
39
|
+
data: {private_key: string; id: string; created_at: string}
|
|
40
|
+
}>({
|
|
41
|
+
url: `/addons/mux/signing-keys/${dataset}`,
|
|
42
|
+
withCredentials: true,
|
|
43
|
+
method: 'POST',
|
|
44
|
+
})
|
|
45
|
+
return res
|
|
46
|
+
} catch (error: any) {
|
|
47
|
+
console.error('Error creating signing keys', error)
|
|
48
|
+
const message =
|
|
49
|
+
error.response?.statusCode === 401
|
|
50
|
+
? 'Unauthorized - Failed to create the Signing Key. Please ensure that the token has "System" permissions'
|
|
51
|
+
: error.message
|
|
52
|
+
throw new Error(message)
|
|
53
|
+
}
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
export function testSecrets(client: SanityClient) {
|
|
@@ -139,6 +139,8 @@ function ConfigureApi({secrets, setDialogState}: Props) {
|
|
|
139
139
|
The access token needs permissions: <strong>Mux Video </strong>
|
|
140
140
|
(Full Access) and <strong>Mux Data</strong> (Read)
|
|
141
141
|
<br />
|
|
142
|
+
To use Signed URLs, the token must also have System permissions.
|
|
143
|
+
<br />
|
|
142
144
|
The credentials will be stored safely in a hidden document only available to
|
|
143
145
|
editors.
|
|
144
146
|
</Text>
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import {Button, Dialog, Flex, Stack, Text, TextInput} from '@sanity/ui'
|
|
2
|
+
import React, {useId, useMemo, useState} from 'react'
|
|
3
|
+
import {getDevicePixelRatio} from 'use-device-pixel-ratio'
|
|
4
|
+
|
|
5
|
+
import {useDialogStateContext} from '../context/DialogStateContext'
|
|
6
|
+
import {useClient} from '../hooks/useClient'
|
|
7
|
+
import {
|
|
8
|
+
formatSecondsToHHMMSS,
|
|
9
|
+
getSecondsFromTimeFormat,
|
|
10
|
+
isValidTimeFormat,
|
|
11
|
+
} from '../util/formatSeconds'
|
|
12
|
+
import type {VideoAssetDocument} from '../util/types'
|
|
13
|
+
import VideoThumbnail from './VideoThumbnail'
|
|
14
|
+
|
|
15
|
+
export interface Props {
|
|
16
|
+
asset: VideoAssetDocument
|
|
17
|
+
currentTime?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default function EditThumbnailDialog({asset, currentTime = 0}: Props) {
|
|
21
|
+
const client = useClient()
|
|
22
|
+
|
|
23
|
+
const {setDialogState} = useDialogStateContext()
|
|
24
|
+
const dialogId = `EditThumbnailDialog${useId()}`
|
|
25
|
+
|
|
26
|
+
const [timeFormatted, setTimeFormatted] = useState<string>(() =>
|
|
27
|
+
formatSecondsToHHMMSS(currentTime)
|
|
28
|
+
)
|
|
29
|
+
const [nextTime, setNextTime] = useState<number>(currentTime)
|
|
30
|
+
const [inputError, setInputError] = useState<string>('')
|
|
31
|
+
|
|
32
|
+
const assetWithNewThumbnail = useMemo(() => ({...asset, thumbTime: nextTime}), [asset, nextTime])
|
|
33
|
+
const [saving, setSaving] = useState(false)
|
|
34
|
+
const [saveThumbnailError, setSaveThumbnailError] = useState<Error | null>(null)
|
|
35
|
+
const handleSave = () => {
|
|
36
|
+
setSaving(true)
|
|
37
|
+
client
|
|
38
|
+
.patch(asset._id!)
|
|
39
|
+
.set({thumbTime: nextTime})
|
|
40
|
+
.commit({returnDocuments: false})
|
|
41
|
+
.then(() => void setDialogState(false))
|
|
42
|
+
.catch(setSaveThumbnailError)
|
|
43
|
+
.finally(() => void setSaving(false))
|
|
44
|
+
}
|
|
45
|
+
const width = 300 * getDevicePixelRatio({maxDpr: 2})
|
|
46
|
+
|
|
47
|
+
if (saveThumbnailError) {
|
|
48
|
+
// eslint-disable-next-line no-warning-comments
|
|
49
|
+
// @TODO handle errors more gracefully
|
|
50
|
+
throw saveThumbnailError
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const handleInputChange = (event: React.FormEvent<HTMLInputElement>) => {
|
|
54
|
+
const value = event.currentTarget.value
|
|
55
|
+
setTimeFormatted(value)
|
|
56
|
+
|
|
57
|
+
if (isValidTimeFormat(value)) {
|
|
58
|
+
setInputError('')
|
|
59
|
+
const totalSeconds = getSecondsFromTimeFormat(value)
|
|
60
|
+
setNextTime(totalSeconds)
|
|
61
|
+
} else {
|
|
62
|
+
setInputError('Invalid time format')
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Dialog
|
|
68
|
+
id={dialogId}
|
|
69
|
+
header="Edit thumbnail"
|
|
70
|
+
onClose={() => setDialogState(false)}
|
|
71
|
+
footer={
|
|
72
|
+
<Stack padding={3}>
|
|
73
|
+
<Button
|
|
74
|
+
key="thumbnail"
|
|
75
|
+
disabled={inputError !== ''}
|
|
76
|
+
mode="ghost"
|
|
77
|
+
tone="primary"
|
|
78
|
+
loading={saving}
|
|
79
|
+
onClick={handleSave}
|
|
80
|
+
text="Set new thumbnail"
|
|
81
|
+
/>
|
|
82
|
+
</Stack>
|
|
83
|
+
}
|
|
84
|
+
>
|
|
85
|
+
<Stack space={3} padding={3}>
|
|
86
|
+
<Stack space={2}>
|
|
87
|
+
<Text size={1} weight="semibold">
|
|
88
|
+
Current:
|
|
89
|
+
</Text>
|
|
90
|
+
<VideoThumbnail asset={asset} width={width} staticImage />
|
|
91
|
+
</Stack>
|
|
92
|
+
<Stack space={2}>
|
|
93
|
+
<Text size={1} weight="semibold">
|
|
94
|
+
New:
|
|
95
|
+
</Text>
|
|
96
|
+
<VideoThumbnail asset={assetWithNewThumbnail} width={width} staticImage />
|
|
97
|
+
</Stack>
|
|
98
|
+
|
|
99
|
+
<Stack space={2}>
|
|
100
|
+
<Flex align={'center'} justify={'center'}>
|
|
101
|
+
<Text size={5} weight="semibold">
|
|
102
|
+
Or
|
|
103
|
+
</Text>
|
|
104
|
+
</Flex>
|
|
105
|
+
</Stack>
|
|
106
|
+
|
|
107
|
+
<Stack space={2}>
|
|
108
|
+
<Text size={1} weight="semibold">
|
|
109
|
+
Selected time for thumbnail (hh:mm:ss):
|
|
110
|
+
</Text>
|
|
111
|
+
<TextInput
|
|
112
|
+
size={1}
|
|
113
|
+
value={timeFormatted}
|
|
114
|
+
placeholder="hh:mm:ss"
|
|
115
|
+
onChange={handleInputChange}
|
|
116
|
+
customValidity={inputError}
|
|
117
|
+
/>
|
|
118
|
+
</Stack>
|
|
119
|
+
</Stack>
|
|
120
|
+
</Dialog>
|
|
121
|
+
)
|
|
122
|
+
}
|