sanity-plugin-mux-input 2.3.4 → 2.3.6
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 +36 -6
- package/{lib/index.d.cts → dist/index.d.mts} +9 -2
- package/{lib → dist}/index.d.ts +9 -2
- package/{lib/index.cjs → dist/index.js} +247 -143
- package/dist/index.js.map +1 -0
- package/{lib/index.esm.js → dist/index.mjs} +250 -146
- package/dist/index.mjs.map +1 -0
- package/package.json +50 -48
- package/src/_exports/index.ts +4 -3
- package/src/actions/upload.ts +1 -1
- package/src/components/FileInputArea.tsx +4 -3
- package/src/components/TextTracksEditor.tsx +76 -173
- package/src/components/UploadConfiguration.tsx +23 -23
- package/src/components/Uploader.tsx +1 -1
- package/src/components/VideoDetails/VideoDetails.tsx +1 -1
- package/src/components/VideoInBrowser.tsx +21 -2
- package/src/components/VideoPlayer.tsx +15 -2
- package/src/components/VideoThumbnail.tsx +1 -1
- package/src/components/documentPreview/PaneItemPreview.tsx +10 -7
- package/src/hooks/useImportMuxAssets.ts +7 -3
- package/src/schema.ts +181 -0
- package/src/util/constants.ts +2 -0
- package/src/util/generateJwt.ts +2 -2
- package/src/util/types.ts +10 -2
- package/lib/index.cjs.map +0 -1
- package/lib/index.esm.js.map +0 -1
- package/lib/index.js +0 -4314
- package/lib/index.js.map +0 -1
- package/src/schema.tsx +0 -42
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sanity-plugin-mux-input",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.6",
|
|
4
4
|
"description": "An input component that integrates Sanity Studio with Mux video encoding/hosting service.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -22,105 +22,107 @@
|
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"author": "Sanity.io <hello@sanity.io>",
|
|
24
24
|
"sideEffects": false,
|
|
25
|
-
"type": "
|
|
25
|
+
"type": "commonjs",
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
28
28
|
"source": "./src/_exports/index.ts",
|
|
29
|
-
"import": "./
|
|
30
|
-
"
|
|
31
|
-
"default": "./lib/index.js"
|
|
29
|
+
"import": "./dist/index.mjs",
|
|
30
|
+
"default": "./dist/index.js"
|
|
32
31
|
},
|
|
33
32
|
"./package.json": "./package.json"
|
|
34
33
|
},
|
|
35
|
-
"main": "./
|
|
36
|
-
"
|
|
37
|
-
"source": "./src/_exports/index.ts",
|
|
38
|
-
"types": "./lib/index.d.ts",
|
|
34
|
+
"main": "./dist/index.js",
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
39
36
|
"files": [
|
|
40
37
|
"src",
|
|
41
|
-
"
|
|
38
|
+
"dist",
|
|
42
39
|
"sanity.json",
|
|
43
40
|
"v2-incompatible.js"
|
|
44
41
|
],
|
|
45
42
|
"scripts": {
|
|
46
|
-
"build": "
|
|
43
|
+
"build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
|
|
47
44
|
"clean": "rimraf lib",
|
|
48
|
-
"dev": "plugin-kit link-watch",
|
|
45
|
+
"dev": "plugin-kit link-watch --strict",
|
|
49
46
|
"format": "prettier --write --cache --ignore-unknown .",
|
|
50
47
|
"link-watch": "plugin-kit link-watch",
|
|
51
48
|
"lint": "eslint .",
|
|
52
49
|
"prepare": "husky install || true",
|
|
53
|
-
"prepublishOnly": "run
|
|
50
|
+
"prepublishOnly": "npm run build",
|
|
54
51
|
"test": "npm run lint && npm run type-check && npm run build",
|
|
55
52
|
"type-check": "tsc --noEmit",
|
|
56
53
|
"watch": "pkg-utils watch --strict"
|
|
57
54
|
},
|
|
58
55
|
"dependencies": {
|
|
59
|
-
"@mux/mux-player-react": "^2.
|
|
60
|
-
"@mux/upchunk": "^3.
|
|
61
|
-
"@sanity/icons": "^
|
|
56
|
+
"@mux/mux-player-react": "^2.6.0",
|
|
57
|
+
"@mux/upchunk": "^3.4.0",
|
|
58
|
+
"@sanity/icons": "^3.0.0",
|
|
62
59
|
"@sanity/incompatible-plugin": "^1.0.4",
|
|
63
|
-
"@sanity/ui": "^2.1.
|
|
60
|
+
"@sanity/ui": "^2.1.11",
|
|
64
61
|
"@sanity/uuid": "^3.0.2",
|
|
65
62
|
"iso-639-1": "^3.1.2",
|
|
66
63
|
"jsonwebtoken-esm": "^1.0.5",
|
|
67
64
|
"lodash": "^4.17.21",
|
|
68
|
-
"react-rx": "^
|
|
65
|
+
"react-rx": "^3.0.0",
|
|
69
66
|
"rxjs": "^7.8.1",
|
|
70
67
|
"scroll-into-view-if-needed": "^3.1.0",
|
|
71
68
|
"suspend-react": "^0.1.3",
|
|
72
69
|
"swr": "^2.2.5",
|
|
73
|
-
"type-fest": "^4.
|
|
70
|
+
"type-fest": "^4.18.2",
|
|
71
|
+
"use-error-boundary": "^2.0.6"
|
|
74
72
|
},
|
|
75
73
|
"devDependencies": {
|
|
76
|
-
"@
|
|
77
|
-
"@
|
|
78
|
-
"@sanity/
|
|
79
|
-
"@sanity/
|
|
80
|
-
"@sanity/
|
|
81
|
-
"@
|
|
82
|
-
"@
|
|
83
|
-
"@types/
|
|
84
|
-
"@types/
|
|
85
|
-
"@
|
|
86
|
-
"@typescript-eslint/
|
|
87
|
-
"@typescript-eslint/parser": "^7.6.0",
|
|
88
|
-
"cz-conventional-changelog": "^3.3.0",
|
|
74
|
+
"@sanity/client": "^6.18.2",
|
|
75
|
+
"@sanity/pkg-utils": "^6.8.16",
|
|
76
|
+
"@sanity/plugin-kit": "4.0.12",
|
|
77
|
+
"@sanity/semantic-release-preset": "^5.0.0",
|
|
78
|
+
"@sanity/vision": "^3.42.1",
|
|
79
|
+
"@types/lodash": "^4.17.4",
|
|
80
|
+
"@types/react": "^18.3.2",
|
|
81
|
+
"@types/react-is": "^18.3.0",
|
|
82
|
+
"@types/styled-components": "^5.1.34",
|
|
83
|
+
"@typescript-eslint/eslint-plugin": "^7.0.2",
|
|
84
|
+
"@typescript-eslint/parser": "^7.0.2",
|
|
89
85
|
"eslint": "^8.57.0",
|
|
90
86
|
"eslint-config-prettier": "^9.1.0",
|
|
87
|
+
"eslint-config-react-app": "^7.0.1",
|
|
91
88
|
"eslint-config-sanity": "^7.1.2",
|
|
92
89
|
"eslint-plugin-import": "^2.29.1",
|
|
93
90
|
"eslint-plugin-prettier": "^5.1.3",
|
|
94
|
-
"eslint-plugin-react-hooks": "^4.6.
|
|
95
|
-
"eslint-plugin-simple-import-sort": "^12.
|
|
91
|
+
"eslint-plugin-react-hooks": "^4.6.2",
|
|
92
|
+
"eslint-plugin-simple-import-sort": "^12.1.0",
|
|
96
93
|
"husky": "^9.0.11",
|
|
97
94
|
"lint-staged": "^15.2.2",
|
|
98
95
|
"npm-run-all2": "^5.0.0",
|
|
99
96
|
"prettier": "^3.2.5",
|
|
100
|
-
"prettier-plugin-packagejson": "^2.
|
|
101
|
-
"react": "^18.
|
|
102
|
-
"react-dom": "^18.
|
|
103
|
-
"react-is": "^18.
|
|
104
|
-
"rimraf": "^5.0.
|
|
105
|
-
"sanity": "^3.
|
|
106
|
-
"semantic-release": "^
|
|
107
|
-
"styled-components": "^6.1.
|
|
108
|
-
"typescript": "5.4.
|
|
109
|
-
"use-error-boundary": "^2.0.6",
|
|
97
|
+
"prettier-plugin-packagejson": "^2.5.0",
|
|
98
|
+
"react": "^18.3.1",
|
|
99
|
+
"react-dom": "^18.3.1",
|
|
100
|
+
"react-is": "^18.3.1",
|
|
101
|
+
"rimraf": "^5.0.7",
|
|
102
|
+
"sanity": "^3.42.1",
|
|
103
|
+
"semantic-release": "^24.0.0",
|
|
104
|
+
"styled-components": "^6.1.11",
|
|
105
|
+
"typescript": "^5.4.5",
|
|
110
106
|
"yalc": "1.0.0-pre.53"
|
|
111
107
|
},
|
|
112
108
|
"peerDependencies": {
|
|
113
109
|
"react": "^18",
|
|
114
110
|
"react-is": "^18",
|
|
115
|
-
"sanity": "^3",
|
|
116
|
-
"styled-components": "^6"
|
|
111
|
+
"sanity": "^3.42.0",
|
|
112
|
+
"styled-components": "^5 || ^6"
|
|
117
113
|
},
|
|
118
114
|
"engines": {
|
|
119
|
-
"node": ">=
|
|
115
|
+
"node": ">=18"
|
|
120
116
|
},
|
|
121
117
|
"publishConfig": {
|
|
122
118
|
"access": "public",
|
|
123
119
|
"provenance": true
|
|
124
120
|
},
|
|
125
|
-
"sanityExchangeUrl": "https://www.sanity.io/plugins/sanity-plugin-mux-input"
|
|
121
|
+
"sanityExchangeUrl": "https://www.sanity.io/plugins/sanity-plugin-mux-input",
|
|
122
|
+
"browserslist": "extends @sanity/browserslist-config",
|
|
123
|
+
"sanityPlugin": {
|
|
124
|
+
"verifyPackage": {
|
|
125
|
+
"srcIndex": false
|
|
126
|
+
}
|
|
127
|
+
}
|
|
126
128
|
}
|
package/src/_exports/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {definePlugin} from 'sanity'
|
|
2
|
+
|
|
2
3
|
import createStudioTool, {DEFAULT_TOOL_CONFIG} from '../components/StudioTool'
|
|
3
4
|
import {muxVideoCustomRendering} from '../plugin'
|
|
4
|
-
import {
|
|
5
|
+
import {muxVideoSchema, schemaTypes} from '../schema'
|
|
5
6
|
import type {PluginConfig} from '../util/types'
|
|
6
7
|
export type {VideoAssetDocument} from '../util/types'
|
|
7
8
|
|
|
@@ -20,9 +21,9 @@ export const muxInput = definePlugin<Partial<PluginConfig> | void>((userConfig)
|
|
|
20
21
|
name: 'mux-input',
|
|
21
22
|
schema: {
|
|
22
23
|
types: [
|
|
23
|
-
|
|
24
|
+
...schemaTypes,
|
|
24
25
|
{
|
|
25
|
-
...
|
|
26
|
+
...muxVideoSchema,
|
|
26
27
|
...muxVideoCustomRendering(config),
|
|
27
28
|
},
|
|
28
29
|
],
|
package/src/actions/upload.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {uuid as generateUuid} from '@sanity/uuid'
|
|
2
|
-
import {concat, defer, from, of, throwError
|
|
2
|
+
import {concat, defer, from, type Observable, of, throwError} from 'rxjs'
|
|
3
3
|
import {catchError, mergeMap, mergeMapTo, switchMap} from 'rxjs/operators'
|
|
4
4
|
import type {SanityClient} from 'sanity'
|
|
5
5
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {PropsWithChildren, useRef, useState} from 'react'
|
|
2
|
-
import {Box, Button, Card, CardTone, Flex, Inline, Text} from '@sanity/ui'
|
|
3
|
-
import {FileInputButton} from './FileInputButton'
|
|
4
1
|
import {UploadIcon} from '@sanity/icons'
|
|
2
|
+
import {Box, Button, Card, CardTone, Flex, Inline, Text} from '@sanity/ui'
|
|
3
|
+
import {PropsWithChildren, useRef, useState} from 'react'
|
|
4
|
+
|
|
5
5
|
import {extractDroppedFiles} from '../util/extractFiles'
|
|
6
|
+
import {FileInputButton} from './FileInputButton'
|
|
6
7
|
|
|
7
8
|
interface FileInputAreaProps extends PropsWithChildren {
|
|
8
9
|
accept?: string
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {Autocomplete,
|
|
1
|
+
import {TranslateIcon} from '@sanity/icons'
|
|
2
|
+
import {Autocomplete, Box, Card, Checkbox, Flex, Stack, Text} from '@sanity/ui'
|
|
3
|
+
import {uuid} from '@sanity/uuid'
|
|
3
4
|
import LanguagesList from 'iso-639-1'
|
|
4
5
|
import {Dispatch} from 'react'
|
|
5
|
-
|
|
6
|
-
import {uuid} from '@sanity/uuid'
|
|
7
6
|
import {FormField} from 'sanity'
|
|
8
|
-
|
|
9
|
-
import
|
|
7
|
+
|
|
8
|
+
import {type PluginConfig, SUPPORTED_MUX_LANGUAGES, UploadTextTrack} from '../util/types'
|
|
10
9
|
|
|
11
10
|
const ALL_LANGUAGE_CODES = LanguagesList.getAllCodes().map((code) => ({
|
|
12
11
|
value: code,
|
|
@@ -25,190 +24,94 @@ const SUBTITLE_LANGUAGES: Record<
|
|
|
25
24
|
captions: ALL_LANGUAGE_CODES,
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
/**
|
|
29
|
-
* Subtitles and Captions are uploaded via .srt and .vtt files, which we can't currently support
|
|
30
|
-
* due to the lack of a server to receive Mux's requests to these files' URLs.
|
|
31
|
-
*
|
|
32
|
-
* For now, only auto-generated subtitles are supported.
|
|
33
|
-
*/
|
|
34
|
-
const TRACK_TYPES = [
|
|
35
|
-
{value: 'autogenerated', label: 'Auto-generated Subtitles'},
|
|
36
|
-
// {value: 'subtitles', label: 'Subtitles'},
|
|
37
|
-
// {value: 'captions', label: 'Closed Captions'},
|
|
38
|
-
] as const
|
|
39
|
-
|
|
40
27
|
type TrackSubAction =
|
|
41
|
-
| {subAction: 'add'}
|
|
28
|
+
| {subAction: 'add'; value: Partial<UploadTextTrack>}
|
|
42
29
|
| {subAction: 'update'; value: Partial<UploadTextTrack>}
|
|
43
30
|
| {subAction: 'delete'}
|
|
44
31
|
|
|
45
32
|
export type TrackAction = {action: 'track'; id: string} & TrackSubAction
|
|
46
33
|
|
|
47
|
-
/**
|
|
48
|
-
* Handles editing of a single text track, dispatching actions back to the
|
|
49
|
-
* parent UploadConfiguration state object for changing internal state.
|
|
50
|
-
*/
|
|
51
|
-
function TrackEditor({
|
|
52
|
-
canAutoGenerate,
|
|
53
|
-
track,
|
|
54
|
-
dispatch,
|
|
55
|
-
}: {
|
|
56
|
-
canAutoGenerate: boolean
|
|
57
|
-
track: Partial<UploadTextTrack> & {_id: string}
|
|
58
|
-
dispatch: Dispatch<TrackAction>
|
|
59
|
-
}) {
|
|
60
|
-
const {_id: id, type} = track
|
|
61
|
-
const dispatchTrackAction = (args: TrackSubAction) => dispatch({action: 'track', id, ...args})
|
|
62
|
-
|
|
63
|
-
const trackTypes = TRACK_TYPES.filter(
|
|
64
|
-
({value}) => !(value === 'autogenerated' && !canAutoGenerate)
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
if (trackTypes.length === 0) return null
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<Card border padding={3} radius={2} style={{position: 'relative'}}>
|
|
71
|
-
<Stack space={3}>
|
|
72
|
-
{trackTypes.length > 1 && (
|
|
73
|
-
<FormField title="Auto-generated subtitles">
|
|
74
|
-
<Flex gap={3}>
|
|
75
|
-
{trackTypes.map(({value, label}) => {
|
|
76
|
-
const inputId = `${id}--type-${value}`
|
|
77
|
-
return (
|
|
78
|
-
<Flex key={value} align="center" gap={2}>
|
|
79
|
-
<Radio
|
|
80
|
-
checked={type === value}
|
|
81
|
-
name="track-type"
|
|
82
|
-
onChange={(e) =>
|
|
83
|
-
dispatchTrackAction({
|
|
84
|
-
subAction: 'update',
|
|
85
|
-
value: {
|
|
86
|
-
type: e.currentTarget.value as UploadTextTrack['type'],
|
|
87
|
-
},
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
value={value}
|
|
91
|
-
id={inputId}
|
|
92
|
-
/>
|
|
93
|
-
<Text as="label" htmlFor={inputId}>
|
|
94
|
-
{label}
|
|
95
|
-
</Text>
|
|
96
|
-
</Flex>
|
|
97
|
-
)
|
|
98
|
-
})}
|
|
99
|
-
</Flex>
|
|
100
|
-
</FormField>
|
|
101
|
-
)}
|
|
102
|
-
|
|
103
|
-
<Autocomplete
|
|
104
|
-
id={`${id}--language`}
|
|
105
|
-
value={track.language_code}
|
|
106
|
-
onChange={(newValue) =>
|
|
107
|
-
dispatchTrackAction({
|
|
108
|
-
subAction: 'update',
|
|
109
|
-
value: {
|
|
110
|
-
language_code: newValue,
|
|
111
|
-
name: LanguagesList.getNativeName(newValue),
|
|
112
|
-
},
|
|
113
|
-
})
|
|
114
|
-
}
|
|
115
|
-
options={SUBTITLE_LANGUAGES[track.type!]}
|
|
116
|
-
icon={TranslateIcon}
|
|
117
|
-
placeholder="Select language"
|
|
118
|
-
filterOption={(query, option) =>
|
|
119
|
-
option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
|
|
120
|
-
option.value.toLowerCase().indexOf(query.toLowerCase()) > -1
|
|
121
|
-
}
|
|
122
|
-
openButton
|
|
123
|
-
renderValue={(value) =>
|
|
124
|
-
SUBTITLE_LANGUAGES[track.type!].find((l) => l.value === value)?.label || value
|
|
125
|
-
}
|
|
126
|
-
renderOption={(option) => (
|
|
127
|
-
<Card data-as="button" padding={3} radius={2} tone="inherit">
|
|
128
|
-
<Text size={2} textOverflow="ellipsis">
|
|
129
|
-
{option.label} ({option.value})
|
|
130
|
-
</Text>
|
|
131
|
-
</Card>
|
|
132
|
-
)}
|
|
133
|
-
/>
|
|
134
|
-
|
|
135
|
-
<Flex>
|
|
136
|
-
<Button
|
|
137
|
-
icon={TrashIcon}
|
|
138
|
-
tone="critical"
|
|
139
|
-
mode="ghost"
|
|
140
|
-
onClick={() => dispatchTrackAction({subAction: 'delete'})}
|
|
141
|
-
text="Delete"
|
|
142
|
-
/>
|
|
143
|
-
</Flex>
|
|
144
|
-
</Stack>
|
|
145
|
-
</Card>
|
|
146
|
-
)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
34
|
export default function TextTracksEditor({
|
|
150
|
-
canAutoGenerate,
|
|
151
35
|
tracks,
|
|
152
36
|
dispatch,
|
|
37
|
+
defaultLang,
|
|
153
38
|
}: {
|
|
154
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Although the schema for tracks is an array, which we'll eventually support to allow uploading
|
|
41
|
+
* multiple custom subtitles, for now we only support a single auto-generated track.
|
|
42
|
+
*/
|
|
155
43
|
tracks: (Partial<UploadTextTrack> & {_id: string})[]
|
|
156
44
|
dispatch: Dispatch<TrackAction>
|
|
45
|
+
defaultLang: PluginConfig['defaultAutogeneratedSubtitleLang']
|
|
157
46
|
}) {
|
|
158
|
-
const
|
|
159
|
-
({value}) => !(value === 'autogenerated' && !canAutoGenerate)
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
if (trackTypes.length === 0) return null
|
|
163
|
-
|
|
47
|
+
const track = tracks[0]
|
|
164
48
|
return (
|
|
165
|
-
<FormField
|
|
166
|
-
title="Captions & Subtitles"
|
|
167
|
-
description="Provide text tracks for video accessibility."
|
|
168
|
-
>
|
|
49
|
+
<FormField title="Auto-generated subtitle or caption">
|
|
169
50
|
<Stack space={2}>
|
|
170
|
-
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
51
|
+
<Flex align="center">
|
|
52
|
+
<Checkbox
|
|
53
|
+
id="include-autogenerated-track"
|
|
54
|
+
style={{display: 'block'}}
|
|
55
|
+
checked={!!track?.language_code}
|
|
56
|
+
onChange={() => {
|
|
57
|
+
if (track) {
|
|
58
|
+
dispatch({action: 'track', id: track._id, subAction: 'delete'})
|
|
59
|
+
} else {
|
|
60
|
+
dispatch({
|
|
61
|
+
action: 'track',
|
|
62
|
+
id: uuid(),
|
|
63
|
+
subAction: 'add',
|
|
64
|
+
value: {
|
|
65
|
+
type: 'autogenerated',
|
|
66
|
+
name: defaultLang || undefined,
|
|
67
|
+
language_code: defaultLang || undefined,
|
|
68
|
+
},
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
<Box flex={1} paddingLeft={3}>
|
|
74
|
+
<Text>
|
|
75
|
+
<label htmlFor="checkbox">Generate captions</label>
|
|
76
|
+
</Text>
|
|
77
|
+
</Box>
|
|
78
|
+
</Flex>
|
|
79
|
+
{track && (
|
|
80
|
+
<Autocomplete
|
|
81
|
+
id={`text-tract-editor--language`}
|
|
82
|
+
value={track.language_code}
|
|
83
|
+
onChange={(newValue) =>
|
|
84
|
+
dispatch({
|
|
85
|
+
action: 'track',
|
|
86
|
+
id: track._id,
|
|
87
|
+
subAction: 'update',
|
|
88
|
+
value: {
|
|
89
|
+
language_code: newValue,
|
|
90
|
+
name: LanguagesList.getNativeName(newValue),
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
options={SUBTITLE_LANGUAGES[track.type!]}
|
|
95
|
+
icon={TranslateIcon}
|
|
96
|
+
placeholder="Select language"
|
|
97
|
+
filterOption={(query, option) =>
|
|
98
|
+
option.label.toLowerCase().indexOf(query.toLowerCase()) > -1 ||
|
|
99
|
+
option.value.toLowerCase().indexOf(query.toLowerCase()) > -1
|
|
100
|
+
}
|
|
101
|
+
openButton
|
|
102
|
+
renderValue={(value) =>
|
|
103
|
+
SUBTITLE_LANGUAGES[track.type!].find((l) => l.value === value)?.label || value
|
|
104
|
+
}
|
|
105
|
+
renderOption={(option) => (
|
|
106
|
+
<Card data-as="button" padding={3} radius={2} tone="inherit">
|
|
107
|
+
<Text size={2} textOverflow="ellipsis">
|
|
108
|
+
{option.label} ({option.value})
|
|
109
|
+
</Text>
|
|
110
|
+
</Card>
|
|
111
|
+
)}
|
|
176
112
|
/>
|
|
177
|
-
)
|
|
178
|
-
<Button
|
|
179
|
-
icon={AddIcon}
|
|
180
|
-
onClick={() => dispatch({action: 'track', id: uuid(), subAction: 'add'})}
|
|
181
|
-
text="New caption/subtitle"
|
|
182
|
-
mode="ghost"
|
|
183
|
-
/>
|
|
113
|
+
)}
|
|
184
114
|
</Stack>
|
|
185
115
|
</FormField>
|
|
186
116
|
)
|
|
187
117
|
}
|
|
188
|
-
|
|
189
|
-
function getFileTextContents(file: File) {
|
|
190
|
-
return new Promise<string>((resolve, reject) => {
|
|
191
|
-
const reader = new FileReader()
|
|
192
|
-
|
|
193
|
-
reader.onload = () => {
|
|
194
|
-
if (typeof reader.result === 'string') {
|
|
195
|
-
resolve(reader.result)
|
|
196
|
-
} else {
|
|
197
|
-
reject(new Error('Could not read file'))
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
reader.onerror = reject
|
|
202
|
-
|
|
203
|
-
reader.readAsText(file)
|
|
204
|
-
})
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
async function fileToTrackFile(file: File) {
|
|
208
|
-
return {
|
|
209
|
-
name: file.name,
|
|
210
|
-
size: file.size,
|
|
211
|
-
type: file.type,
|
|
212
|
-
contents: await getFileTextContents(file),
|
|
213
|
-
}
|
|
214
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {DocumentVideoIcon, UploadIcon} from '@sanity/icons'
|
|
2
|
-
import {Button, Card, Checkbox, Dialog, Flex, Label, Radio, Stack, Text} from '@sanity/ui'
|
|
2
|
+
import {Box, Button, Card, Checkbox, Dialog, Flex, Label, Radio, Stack, Text} from '@sanity/ui'
|
|
3
3
|
import {uuid} from '@sanity/uuid'
|
|
4
4
|
import LanguagesList from 'iso-639-1'
|
|
5
5
|
import {useEffect, useId, useReducer, useRef} from 'react'
|
|
@@ -61,17 +61,16 @@ export default function UploadConfiguration({
|
|
|
61
61
|
}) {
|
|
62
62
|
const id = useId()
|
|
63
63
|
const autoTextTracks = useRef<NonNullable<UploadConfig['text_tracks']>>(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
({
|
|
64
|
+
pluginConfig.encoding_tier === 'smart' && pluginConfig.defaultAutogeneratedSubtitleLang
|
|
65
|
+
? [
|
|
66
|
+
{
|
|
68
67
|
_id: uuid(),
|
|
69
68
|
type: 'autogenerated',
|
|
70
|
-
language_code,
|
|
71
|
-
name: LanguagesList.getNativeName(
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
[]
|
|
69
|
+
language_code: pluginConfig.defaultAutogeneratedSubtitleLang,
|
|
70
|
+
name: LanguagesList.getNativeName(pluginConfig.defaultAutogeneratedSubtitleLang),
|
|
71
|
+
} satisfies AutogeneratedTextTrack,
|
|
72
|
+
]
|
|
73
|
+
: []
|
|
75
74
|
).current
|
|
76
75
|
|
|
77
76
|
const [config, dispatch] = useReducer(
|
|
@@ -109,11 +108,10 @@ export default function UploadConfiguration({
|
|
|
109
108
|
case 'add':
|
|
110
109
|
// Exit early if track already exists
|
|
111
110
|
if (target_track_i !== -1) break
|
|
112
|
-
text_tracks.push(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
)
|
|
111
|
+
text_tracks.push({
|
|
112
|
+
_id: action.id,
|
|
113
|
+
...action.value,
|
|
114
|
+
} as AutogeneratedTextTrack)
|
|
117
115
|
break
|
|
118
116
|
case 'update':
|
|
119
117
|
if (target_track_i === -1) break
|
|
@@ -332,20 +330,22 @@ export default function UploadConfiguration({
|
|
|
332
330
|
</Stack>
|
|
333
331
|
)}
|
|
334
332
|
|
|
335
|
-
{!disableTextTrackConfig && (
|
|
333
|
+
{!disableTextTrackConfig && config.encoding_tier === 'smart' && (
|
|
336
334
|
<TextTracksEditor
|
|
337
|
-
canAutoGenerate={config.encoding_tier === 'smart'}
|
|
338
335
|
tracks={config.text_tracks}
|
|
339
336
|
dispatch={dispatch}
|
|
337
|
+
defaultLang={pluginConfig.defaultAutogeneratedSubtitleLang}
|
|
340
338
|
/>
|
|
341
339
|
)}
|
|
342
340
|
|
|
343
|
-
<
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
341
|
+
<Box marginTop={4}>
|
|
342
|
+
<Button
|
|
343
|
+
icon={UploadIcon}
|
|
344
|
+
text="Upload"
|
|
345
|
+
tone="positive"
|
|
346
|
+
onClick={() => startUpload(formatUploadConfig(config))}
|
|
347
|
+
/>
|
|
348
|
+
</Box>
|
|
349
349
|
</Stack>
|
|
350
350
|
</Dialog>
|
|
351
351
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {ErrorOutlineIcon} from '@sanity/icons'
|
|
2
2
|
import {Button, CardTone, Flex, Text, useToast} from '@sanity/ui'
|
|
3
3
|
import React, {useEffect, useReducer, useRef, useState} from 'react'
|
|
4
|
-
import {Subject, Subscription
|
|
4
|
+
import {type Observable, Subject, Subscription} from 'rxjs'
|
|
5
5
|
import {takeUntil, tap} from 'rxjs/operators'
|
|
6
6
|
import type {SanityClient} from 'sanity'
|
|
7
7
|
import {PatchEvent, set, setIfMissing} from 'sanity'
|
|
@@ -8,7 +8,7 @@ import {getPlaybackPolicy} from '../util/getPlaybackPolicy'
|
|
|
8
8
|
import {VideoAssetDocument} from '../util/types'
|
|
9
9
|
import IconInfo from './IconInfo'
|
|
10
10
|
import VideoMetadata from './VideoMetadata'
|
|
11
|
-
import VideoPlayer from './VideoPlayer'
|
|
11
|
+
import VideoPlayer, {assetIsAudio} from './VideoPlayer'
|
|
12
12
|
import VideoThumbnail from './VideoThumbnail'
|
|
13
13
|
|
|
14
14
|
const PlayButton = styled.button`
|
|
@@ -143,7 +143,26 @@ export default function VideoInBrowser({
|
|
|
143
143
|
<div data-play>
|
|
144
144
|
<PlayIcon />
|
|
145
145
|
</div>
|
|
146
|
-
|
|
146
|
+
{assetIsAudio(asset) ? (
|
|
147
|
+
<div
|
|
148
|
+
style={{
|
|
149
|
+
aspectRatio: THUMBNAIL_ASPECT_RATIO,
|
|
150
|
+
display: 'flex',
|
|
151
|
+
alignItems: 'center',
|
|
152
|
+
justifyContent: 'center',
|
|
153
|
+
}}
|
|
154
|
+
>
|
|
155
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="3em" viewBox="0 0 24 24">
|
|
156
|
+
<path
|
|
157
|
+
fill="currentColor"
|
|
158
|
+
style={{opacity: '0.65'}}
|
|
159
|
+
d="M10.75 19q.95 0 1.6-.65t.65-1.6V13h3v-2h-4v3.875q-.275-.2-.587-.288t-.663-.087q-.95 0-1.6.65t-.65 1.6t.65 1.6t1.6.65M6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h8l6 6v12q0 .825-.587 1.413T18 22zm7-13V4H6v16h12V9zM6 4v5zv16z"
|
|
160
|
+
/>
|
|
161
|
+
</svg>
|
|
162
|
+
</div>
|
|
163
|
+
) : (
|
|
164
|
+
<VideoThumbnail asset={asset} />
|
|
165
|
+
)}
|
|
147
166
|
</PlayButton>
|
|
148
167
|
)}
|
|
149
168
|
<VideoMetadata asset={asset} />
|