sanity-plugin-mux-input 3.0.4 → 4.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.
Files changed (130) hide show
  1. package/README.md +0 -2
  2. package/dist/index.d.ts +134 -193
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +2893 -4417
  5. package/dist/index.js.map +1 -1
  6. package/package.json +33 -43
  7. package/dist/index.cjs +0 -7270
  8. package/dist/index.cjs.map +0 -1
  9. package/dist/index.d.cts +0 -347
  10. package/sanity.json +0 -8
  11. package/src/_exports/index.ts +0 -73
  12. package/src/actions/assets.ts +0 -152
  13. package/src/actions/secrets.ts +0 -111
  14. package/src/actions/upload.ts +0 -310
  15. package/src/clients/upChunkObservable.ts +0 -54
  16. package/src/components/AddCaptionDialog.tsx +0 -440
  17. package/src/components/CaptionsDialog.tsx +0 -23
  18. package/src/components/ConfigureApi.styled.tsx +0 -19
  19. package/src/components/ConfigureApi.tsx +0 -296
  20. package/src/components/DraggableWatermark.tsx +0 -877
  21. package/src/components/EditCaptionDialog.tsx +0 -510
  22. package/src/components/EditThumbnailDialog.tsx +0 -122
  23. package/src/components/ErrorBoundaryCard.tsx +0 -96
  24. package/src/components/FileInputButton.tsx +0 -54
  25. package/src/components/FileInputMenuItem.styled.tsx +0 -36
  26. package/src/components/FileInputMenuItem.tsx +0 -85
  27. package/src/components/FormField.tsx +0 -38
  28. package/src/components/IconInfo.tsx +0 -22
  29. package/src/components/ImportVideosFromMux.tsx +0 -342
  30. package/src/components/Input.styled.tsx +0 -22
  31. package/src/components/Input.tsx +0 -78
  32. package/src/components/InputBrowser.tsx +0 -41
  33. package/src/components/InputError.tsx +0 -17
  34. package/src/components/MuxLogo.tsx +0 -42
  35. package/src/components/Onboard.tsx +0 -65
  36. package/src/components/PageSelector.tsx +0 -54
  37. package/src/components/Player.styled.tsx +0 -55
  38. package/src/components/Player.tsx +0 -117
  39. package/src/components/PlayerActionsMenu.tsx +0 -190
  40. package/src/components/ResyncMetadata.tsx +0 -280
  41. package/src/components/SelectAsset.tsx +0 -39
  42. package/src/components/SelectSortOptions.tsx +0 -45
  43. package/src/components/SpinnerBox.tsx +0 -16
  44. package/src/components/StudioTool.tsx +0 -24
  45. package/src/components/TextTracksEditor.tsx +0 -117
  46. package/src/components/TextTracksManager.tsx +0 -737
  47. package/src/components/UploadConfiguration.tsx +0 -694
  48. package/src/components/UploadPlaceholder.tsx +0 -88
  49. package/src/components/UploadProgress.tsx +0 -80
  50. package/src/components/Uploader.styled.tsx +0 -66
  51. package/src/components/Uploader.tsx +0 -498
  52. package/src/components/VideoDetails/DeleteDialog.tsx +0 -147
  53. package/src/components/VideoDetails/VideoDetails.tsx +0 -358
  54. package/src/components/VideoDetails/VideoReferences.tsx +0 -63
  55. package/src/components/VideoDetails/useVideoDetails.ts +0 -103
  56. package/src/components/VideoInBrowser.tsx +0 -245
  57. package/src/components/VideoMetadata.tsx +0 -45
  58. package/src/components/VideoPlayer.tsx +0 -235
  59. package/src/components/VideoThumbnail.tsx +0 -138
  60. package/src/components/VideosBrowser.tsx +0 -100
  61. package/src/components/documentPreview/DocumentPreview.tsx +0 -83
  62. package/src/components/documentPreview/DraftStatus.tsx +0 -34
  63. package/src/components/documentPreview/MissingSchemaType.tsx +0 -32
  64. package/src/components/documentPreview/PaneItemPreview.tsx +0 -74
  65. package/src/components/documentPreview/PublishedStatus.tsx +0 -35
  66. package/src/components/documentPreview/TimeAgo.tsx +0 -12
  67. package/src/components/documentPreview/paneItemTypes.ts +0 -7
  68. package/src/components/icons/Audio.tsx +0 -13
  69. package/src/components/icons/Resolution.tsx +0 -12
  70. package/src/components/icons/StopWatch.tsx +0 -20
  71. package/src/components/icons/ToolIcon.tsx +0 -19
  72. package/src/components/uploadConfiguration/PlaybackPolicy.tsx +0 -133
  73. package/src/components/uploadConfiguration/PlaybackPolicyOption.tsx +0 -76
  74. package/src/components/uploadConfiguration/PlaybackPolicyWarning.tsx +0 -29
  75. package/src/components/uploadConfiguration/ResolutionTierSelector.tsx +0 -72
  76. package/src/components/uploadConfiguration/StaticRenditionSelector.tsx +0 -180
  77. package/src/components/withFocusRing/helpers.ts +0 -24
  78. package/src/components/withFocusRing/index.ts +0 -1
  79. package/src/components/withFocusRing/withFocusRing.ts +0 -30
  80. package/src/context/DialogStateContext.tsx +0 -36
  81. package/src/context/DrmPlaybackWarningContext.tsx +0 -93
  82. package/src/hooks/useAccessControl.ts +0 -13
  83. package/src/hooks/useAssetDocumentValues.ts +0 -11
  84. package/src/hooks/useAssets.ts +0 -68
  85. package/src/hooks/useCancelUpload.ts +0 -22
  86. package/src/hooks/useClient.ts +0 -8
  87. package/src/hooks/useDialogState.ts +0 -11
  88. package/src/hooks/useDocReferences.ts +0 -21
  89. package/src/hooks/useFetchFileSize.ts +0 -54
  90. package/src/hooks/useImportMuxAssets.ts +0 -132
  91. package/src/hooks/useInView.ts +0 -42
  92. package/src/hooks/useMediaMetadata.ts +0 -103
  93. package/src/hooks/useMuxAssets.ts +0 -179
  94. package/src/hooks/useMuxPolling.ts +0 -49
  95. package/src/hooks/useResyncAsset.ts +0 -110
  96. package/src/hooks/useResyncMuxMetadata.ts +0 -176
  97. package/src/hooks/useSaveSecrets.ts +0 -78
  98. package/src/hooks/useSecretsDocumentValues.ts +0 -38
  99. package/src/hooks/useSecretsFormState.ts +0 -47
  100. package/src/plugin.tsx +0 -31
  101. package/src/sanity-ui.d.ts +0 -5
  102. package/src/schema.ts +0 -196
  103. package/src/util/addKeysToMuxData.ts +0 -30
  104. package/src/util/areSecretsSignable.ts +0 -5
  105. package/src/util/asserters.ts +0 -36
  106. package/src/util/assetTitlePlaceholder.ts +0 -31
  107. package/src/util/constants.ts +0 -15
  108. package/src/util/convertWatermarkToMux.ts +0 -160
  109. package/src/util/createSearchFilter.ts +0 -76
  110. package/src/util/createUrlParamsObject.ts +0 -29
  111. package/src/util/extractFiles.ts +0 -67
  112. package/src/util/formatBytes.ts +0 -32
  113. package/src/util/formatDriveShareLink.ts +0 -64
  114. package/src/util/formatSeconds.ts +0 -49
  115. package/src/util/generateJwt.ts +0 -57
  116. package/src/util/getAnimatedPosterSrc.ts +0 -26
  117. package/src/util/getPlaybackPolicy.ts +0 -69
  118. package/src/util/getPosterSrc.ts +0 -28
  119. package/src/util/getStoryboardSrc.ts +0 -27
  120. package/src/util/getVideoMetadata.ts +0 -23
  121. package/src/util/getVideoSrc.ts +0 -23
  122. package/src/util/isSigned.ts +0 -20
  123. package/src/util/parsers.ts +0 -5
  124. package/src/util/pluginVersion.ts +0 -1
  125. package/src/util/readSecrets.ts +0 -38
  126. package/src/util/roundPxString.ts +0 -16
  127. package/src/util/textTracks.ts +0 -222
  128. package/src/util/tryWithSuspend.ts +0 -22
  129. package/src/util/types.ts +0 -596
  130. package/v2-incompatible.js +0 -11
@@ -1,78 +0,0 @@
1
- import {Card} from '@sanity/ui'
2
- import {memo, Suspense} from 'react'
3
-
4
- import {useAccessControl} from '../hooks/useAccessControl'
5
- import {useAssetDocumentValues} from '../hooks/useAssetDocumentValues'
6
- import {useClient} from '../hooks/useClient'
7
- import {useDialogState} from '../hooks/useDialogState'
8
- import {useMuxPolling} from '../hooks/useMuxPolling'
9
- import {useSecretsDocumentValues} from '../hooks/useSecretsDocumentValues'
10
- import type {MuxInputProps, PluginConfig} from '../util/types'
11
- import {ConfigureApiDialog} from './ConfigureApi'
12
- import ErrorBoundaryCard from './ErrorBoundaryCard'
13
- import {InputFallback} from './Input.styled'
14
- import Onboard from './Onboard'
15
- import Uploader from './Uploader'
16
-
17
- export interface InputProps extends MuxInputProps {
18
- config: PluginConfig
19
- }
20
- const Input = (props: InputProps) => {
21
- const client = useClient()
22
- const secretDocumentValues = useSecretsDocumentValues()
23
- const assetDocumentValues = useAssetDocumentValues(props.value?.asset)
24
- const poll = useMuxPolling(props.readOnly ? undefined : assetDocumentValues?.value || undefined)
25
- const [dialogState, setDialogState] = useDialogState()
26
- const {hasConfigAccess} = useAccessControl(props.config)
27
-
28
- const error = secretDocumentValues.error || assetDocumentValues.error || poll.error /*||
29
- // @TODO move errored logic to Uploader, where handleRemoveVideo can be called
30
- (assetDocumentValues.value?.status === 'errored'
31
- ? new Error(assetDocumentValues.value.data?.errors?.messages?.join(' '))
32
- : undefined)
33
- // */
34
- if (error) {
35
- // @TODO deal with it more gracefully
36
- throw error
37
- }
38
- const isLoading = secretDocumentValues.isLoading || assetDocumentValues.isLoading
39
-
40
- return (
41
- <Card>
42
- <ErrorBoundaryCard schemaType={props.schemaType}>
43
- <Suspense fallback={<InputFallback />}>
44
- {isLoading ? (
45
- <InputFallback />
46
- ) : (
47
- <>
48
- {secretDocumentValues.value.needsSetup && !assetDocumentValues.value ? (
49
- <Onboard setDialogState={setDialogState} config={props.config} />
50
- ) : (
51
- <Uploader
52
- {...props}
53
- config={props.config}
54
- onChange={props.onChange}
55
- client={client}
56
- secrets={secretDocumentValues.value.secrets}
57
- asset={assetDocumentValues.value}
58
- dialogState={dialogState}
59
- setDialogState={setDialogState}
60
- needsSetup={secretDocumentValues.value.needsSetup}
61
- />
62
- )}
63
-
64
- {dialogState === 'secrets' && hasConfigAccess && (
65
- <ConfigureApiDialog
66
- setDialogState={setDialogState}
67
- secrets={secretDocumentValues.value.secrets}
68
- />
69
- )}
70
- </>
71
- )}
72
- </Suspense>
73
- </ErrorBoundaryCard>
74
- </Card>
75
- )
76
- }
77
-
78
- export default memo(Input)
@@ -1,41 +0,0 @@
1
- import {Dialog} from '@sanity/ui'
2
- import {useCallback, useId} from 'react'
3
- import {styled} from 'styled-components'
4
-
5
- import type {SetDialogState} from '../hooks/useDialogState'
6
- import SelectAsset, {type Props as SelectAssetProps} from './SelectAsset'
7
-
8
- /** To prevent Content Layout Shift (CLS), ensure that the dialog always occupies the entire available height. */
9
- const StyledDialog = styled(Dialog)`
10
- > div[data-ui='DialogCard'] > div[data-ui='Card'] {
11
- height: 100%;
12
- }
13
- `
14
-
15
- export default function InputBrowser({
16
- setDialogState,
17
- asset,
18
- onChange,
19
- config,
20
- }: Pick<SelectAssetProps, 'onChange' | 'asset' | 'config'> & {
21
- setDialogState: SetDialogState
22
- }) {
23
- const id = `InputBrowser${useId()}`
24
- const handleClose = useCallback(() => setDialogState(false), [setDialogState])
25
- return (
26
- <StyledDialog
27
- __unstable_autoFocus
28
- header="Select video"
29
- id={id}
30
- onClose={handleClose}
31
- width={2}
32
- >
33
- <SelectAsset
34
- config={config}
35
- asset={asset}
36
- onChange={onChange}
37
- setDialogState={setDialogState}
38
- />
39
- </StyledDialog>
40
- )
41
- }
@@ -1,17 +0,0 @@
1
- import {Box, Dialog, Text} from '@sanity/ui'
2
- import {useId} from 'react'
3
-
4
- interface Props {
5
- error: Error
6
- onClose: () => void
7
- }
8
- export default function InputError({onClose, error}: Props) {
9
- const id = `InputError${useId()}`
10
- return (
11
- <Dialog animate header={error.name} id={id} onClose={onClose}>
12
- <Box padding={4}>
13
- <Text>{error.message}</Text>
14
- </Box>
15
- </Dialog>
16
- )
17
- }
@@ -1,42 +0,0 @@
1
- import {useTheme_v2} from '@sanity/ui'
2
- import {CSSProperties, useId, useMemo} from 'react'
3
-
4
- export interface Props {
5
- height?: number
6
- }
7
- export default function MuxLogo({height = 26}: Props) {
8
- const id = useId()
9
- const theme = useTheme_v2()
10
- const fillColor = theme.color._dark ? 'white' : 'black'
11
- const titleId = useMemo(() => `${id}-title`, [id])
12
-
13
- const pathStyle: CSSProperties = {
14
- fillRule: 'nonzero',
15
- }
16
-
17
- return (
18
- <svg
19
- aria-labelledby={titleId}
20
- style={{height: `${height}px`}}
21
- viewBox="0 0 1600 500"
22
- version="1.1"
23
- xmlns="http://www.w3.org/2000/svg"
24
- xmlSpace="preserve"
25
- >
26
- <g id="Layer-1" fill={fillColor}>
27
- <path
28
- d="M994.287,93.486c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m0,-93.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,68.943 -56.09,125.033 -125.032,125.033c-68.942,-0 -125.03,-56.09 -125.03,-125.033l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486c-34.509,-0 -62.484,27.976 -62.484,62.486l0,187.511c0,137.853 112.149,250.003 249.999,250.003c137.851,-0 250.001,-112.15 250.001,-250.003l0,-187.511c0,-34.51 -27.976,-62.486 -62.485,-62.486"
29
- style={pathStyle}
30
- />
31
- <path
32
- d="M1537.51,468.511c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m-275.883,-218.509l-143.33,143.329c-24.402,24.402 -24.402,63.966 0,88.368c24.402,24.402 63.967,24.402 88.369,-0l143.33,-143.329l143.328,143.329c24.402,24.4 63.967,24.402 88.369,-0c24.403,-24.402 24.403,-63.966 0.001,-88.368l-143.33,-143.329l0.001,-0.004l143.329,-143.329c24.402,-24.402 24.402,-63.965 0,-88.367c-24.402,-24.402 -63.967,-24.402 -88.369,-0l-143.329,143.328l-143.329,-143.328c-24.402,-24.401 -63.967,-24.402 -88.369,-0c-24.402,24.402 -24.402,63.965 0,88.367l143.329,143.329l0,0.004Z"
33
- style={pathStyle}
34
- />
35
- <path
36
- d="M437.511,468.521c-17.121,-0 -31,-13.879 -31,-31c0,-17.121 13.879,-31 31,-31c17.121,-0 31,13.879 31,31c0,17.121 -13.879,31 -31,31m23.915,-463.762c-23.348,-9.672 -50.226,-4.327 -68.096,13.544l-143.331,143.329l-143.33,-143.329c-17.871,-17.871 -44.747,-23.216 -68.096,-13.544c-23.349,9.671 -38.574,32.455 -38.574,57.729l0,375.026c0,34.51 27.977,62.486 62.487,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-224.173l80.843,80.844c24.404,24.402 63.965,24.402 88.369,-0l80.843,-80.844l0,224.173c0,34.51 27.976,62.486 62.486,62.486c34.51,-0 62.486,-27.976 62.486,-62.486l0,-375.026c0,-25.274 -15.224,-48.058 -38.573,-57.729"
37
- style={pathStyle}
38
- />
39
- </g>
40
- </svg>
41
- )
42
- }
@@ -1,65 +0,0 @@
1
- import {PlugIcon} from '@sanity/icons'
2
- import {Button, Card, Flex, Grid, Heading, Inline, Text} from '@sanity/ui'
3
- import {useCallback} from 'react'
4
-
5
- import {useAccessControl} from '../hooks/useAccessControl'
6
- import type {SetDialogState} from '../hooks/useDialogState'
7
- import {PluginConfig} from '../util/types'
8
- import MuxLogo from './MuxLogo'
9
-
10
- interface OnboardProps {
11
- setDialogState: SetDialogState
12
- config: PluginConfig
13
- }
14
-
15
- export default function Onboard(props: OnboardProps) {
16
- const {setDialogState} = props
17
- const handleOpen = useCallback(() => setDialogState('secrets'), [setDialogState])
18
- const {hasConfigAccess} = useAccessControl(props.config)
19
-
20
- return (
21
- <>
22
- <div style={{padding: 2}}>
23
- <Card
24
- display="flex"
25
- sizing="border"
26
- style={{
27
- aspectRatio: '16/9',
28
- width: '100%',
29
- boxShadow: 'var(--card-bg-color) 0 0 0 2px',
30
- }}
31
- paddingX={[2, 3, 4, 4]}
32
- radius={1}
33
- tone="transparent"
34
- >
35
- <Flex justify="flex-start" align="center">
36
- <Grid columns={1} gap={[2, 3, 4, 4]}>
37
- <Inline paddingY={1}>
38
- <div style={{height: '32px'}}>
39
- <MuxLogo />
40
- </div>
41
- </Inline>
42
- <Inline paddingY={1}>
43
- <Heading size={[0, 1, 2, 2]}>
44
- Upload and preview videos directly from your studio.
45
- </Heading>
46
- </Inline>
47
- <Inline paddingY={1}>
48
- {hasConfigAccess ? (
49
- <Button mode="ghost" icon={PlugIcon} text="Configure API" onClick={handleOpen} />
50
- ) : (
51
- <Card padding={[3, 3, 3]} radius={2} shadow={1} tone="critical">
52
- <Text>
53
- You do not have access to configure the Mux API. Please contact your
54
- administrator.
55
- </Text>
56
- </Card>
57
- )}
58
- </Inline>
59
- </Grid>
60
- </Flex>
61
- </Card>
62
- </div>
63
- </>
64
- )
65
- }
@@ -1,54 +0,0 @@
1
- import {ChevronLeftIcon, ChevronRightIcon} from '@sanity/icons'
2
- import {Button, Label} from '@sanity/ui'
3
- import {Dispatch, SetStateAction, useEffect} from 'react'
4
-
5
- const PageSelector = (props: {
6
- page: number
7
- setPage: Dispatch<SetStateAction<number>>
8
- total: number
9
- }) => {
10
- const page = props.page
11
- const setPage = props.setPage
12
-
13
- useEffect(() => {
14
- // Constraint in bounds.
15
- const clamped = Math.min(props.total - 1, Math.max(0, page))
16
- if (page !== clamped) {
17
- setPage(clamped)
18
- }
19
- }, [page, props.total, setPage])
20
-
21
- return (
22
- <>
23
- <Button
24
- icon={ChevronLeftIcon}
25
- mode="bleed"
26
- padding={3}
27
- style={{cursor: 'pointer'}}
28
- disabled={page <= 0}
29
- onClick={() => {
30
- setPage((p) => {
31
- return Math.min(props.total - 1, Math.max(0, p - 1))
32
- })
33
- }}
34
- />
35
- <Label muted>
36
- Page {page + 1}/{props.total}
37
- </Label>
38
- <Button
39
- icon={ChevronRightIcon}
40
- mode="bleed"
41
- padding={3}
42
- style={{cursor: 'pointer'}}
43
- disabled={page >= props.total - 1}
44
- onClick={() => {
45
- setPage((p) => {
46
- return Math.min(props.total - 1, Math.max(0, p + 1))
47
- })
48
- }}
49
- />
50
- </>
51
- )
52
- }
53
-
54
- export default PageSelector
@@ -1,55 +0,0 @@
1
- import {Suspense, useState} from 'react'
2
- import {styled} from 'styled-components'
3
-
4
- import {useClient} from '../hooks/useClient'
5
- import {getStoryboardSrc} from '../util/getStoryboardSrc'
6
- import type {VideoAssetDocument} from '../util/types'
7
-
8
- export const StyledCenterControls = styled.div`
9
- && {
10
- --media-background-color: transparent;
11
- --media-button-icon-width: 100%;
12
- --media-button-icon-height: auto;
13
- pointer-events: none;
14
- width: 100%;
15
- display: flex;
16
- flex-flow: row;
17
- align-items: center;
18
- justify-content: center;
19
- media-play-button {
20
- --media-control-background: transparent;
21
- --media-control-hover-background: transparent;
22
- padding: 0;
23
- width: max(27px, min(9%, 90px));
24
- }
25
- }
26
- `
27
-
28
- export const TopControls = styled.div`
29
- position: absolute;
30
- top: 0;
31
- right: 0;
32
- justify-content: flex-end;
33
- button {
34
- height: auto;
35
- }
36
- `
37
-
38
- export interface PosterImageProps {
39
- asset: VideoAssetDocument
40
- }
41
- export interface ThumbnailsMetadataTrackProps {
42
- asset: VideoAssetDocument
43
- }
44
- export function ThumbnailsMetadataTrack({asset}: ThumbnailsMetadataTrackProps) {
45
- const client = useClient()
46
- // Why useState instead of useMemo? Because we really really only want to run it exactly once and useMemo doesn't make that guarantee
47
- const [src] = useState<string>(() => getStoryboardSrc({asset, client}))
48
-
49
- return (
50
- /* We use Suspense here because `getStoryboardSrc` uses suspend() under the hood */
51
- <Suspense fallback={null}>
52
- <track label="thumbnails" default kind="metadata" src={src} />
53
- </Suspense>
54
- )
55
- }
@@ -1,117 +0,0 @@
1
- import {Card, Text} from '@sanity/ui'
2
- import React, {useEffect, useMemo, useRef} from 'react'
3
-
4
- import {useCancelUpload} from '../hooks/useCancelUpload'
5
- import type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'
6
- import {TopControls} from './Player.styled'
7
- import {UploadProgress} from './UploadProgress'
8
- import VideoPlayer from './VideoPlayer'
9
-
10
- interface Props extends Pick<MuxInputProps, 'onChange' | 'readOnly'> {
11
- buttons?: React.ReactNode
12
- asset: VideoAssetDocument
13
- config?: PluginConfig
14
- }
15
-
16
- const Player = ({asset, buttons, readOnly, onChange, config}: Props) => {
17
- const isLoading = useMemo<boolean | string>(() => {
18
- if (asset?.status === 'preparing') {
19
- return 'Preparing the video'
20
- }
21
- if (asset?.status === 'waiting_for_upload') {
22
- return 'Waiting for upload to start'
23
- }
24
- if (asset?.status === 'waiting') {
25
- return 'Processing upload'
26
- }
27
- if (asset?.status === 'ready') {
28
- return false
29
- }
30
- if (typeof asset?.status === 'undefined') {
31
- return false
32
- }
33
-
34
- return true
35
- }, [asset])
36
- const isPreparingStaticRenditions = useMemo<boolean>(() => {
37
- // Legacy: If static_renditions has a status field, it was created with mp4_support (deprecated)
38
- // We don't process this old format, just return false
39
- // Note: 'disabled' status is valid in the new format when no renditions were requested
40
- if (
41
- asset?.data?.static_renditions?.status &&
42
- asset?.data?.static_renditions?.status !== 'disabled'
43
- ) {
44
- return false
45
- }
46
-
47
- // Check if any file in static_renditions is still preparing
48
- const files = asset?.data?.static_renditions?.files
49
- if (!files || files.length === 0) {
50
- return false
51
- }
52
- return files.some((file) => file.status === 'preparing')
53
- }, [asset?.data?.static_renditions?.status, asset?.data?.static_renditions?.files])
54
- const playRef = useRef<HTMLDivElement>(null)
55
- const muteRef = useRef<HTMLDivElement>(null)
56
- const handleCancelUpload = useCancelUpload(asset, onChange)
57
-
58
- useEffect(() => {
59
- const style = document.createElement('style')
60
- style.innerHTML = 'button svg { vertical-align: middle; }'
61
-
62
- if (playRef.current?.shadowRoot) {
63
- playRef.current.shadowRoot.appendChild(style)
64
- }
65
- if (muteRef?.current?.shadowRoot) {
66
- muteRef.current.shadowRoot.appendChild(style.cloneNode(true))
67
- }
68
- }, [])
69
-
70
- useEffect(() => {
71
- if (asset?.status === 'errored') {
72
- handleCancelUpload()
73
- // eslint-disable-next-line no-warning-comments
74
- // @TODO use better error handling
75
- throw new Error(asset.data?.errors?.messages?.join(' '))
76
- }
77
- }, [asset.data?.errors?.messages, asset?.status, handleCancelUpload])
78
-
79
- if (!asset || !asset.status) {
80
- return null
81
- }
82
-
83
- if (isLoading) {
84
- return (
85
- <UploadProgress
86
- progress={100}
87
- filename={asset?.filename}
88
- text={(isLoading !== true && isLoading) || 'Waiting for Mux to complete the upload'}
89
- onCancel={readOnly ? undefined : () => handleCancelUpload()}
90
- />
91
- )
92
- }
93
-
94
- return (
95
- <VideoPlayer asset={asset} hlsConfig={config?.hlsConfig}>
96
- {buttons && <TopControls slot="top-chrome">{buttons}</TopControls>}
97
- {isPreparingStaticRenditions && (
98
- <Card
99
- padding={2}
100
- radius={1}
101
- style={{
102
- background: 'var(--card-fg-color)',
103
- position: 'absolute',
104
- top: '0.5em',
105
- left: '0.5em',
106
- }}
107
- >
108
- <Text size={1} style={{color: 'var(--card-bg-color)'}}>
109
- MUX is preparing static renditions, please stand by
110
- </Text>
111
- </Card>
112
- )}
113
- </VideoPlayer>
114
- )
115
- }
116
-
117
- export default Player
@@ -1,190 +0,0 @@
1
- import {
2
- EllipsisHorizontalIcon,
3
- ImageIcon,
4
- LockIcon,
5
- PlugIcon,
6
- ResetIcon,
7
- SearchIcon,
8
- SyncIcon,
9
- TranslateIcon,
10
- UploadIcon,
11
- } from '@sanity/icons'
12
- import {
13
- Box,
14
- Button,
15
- Card,
16
- Inline,
17
- Label,
18
- Menu,
19
- MenuDivider,
20
- MenuItem,
21
- Popover,
22
- Text,
23
- Tooltip,
24
- useClickOutsideEvent,
25
- } from '@sanity/ui'
26
- import {memo, useCallback, useEffect, useMemo, useState} from 'react'
27
- import {PatchEvent, unset} from 'sanity'
28
- import {styled} from 'styled-components'
29
-
30
- import {useAccessControl} from '../hooks/useAccessControl'
31
- import {type DialogState, type SetDialogState} from '../hooks/useDialogState'
32
- import {useResyncAsset} from '../hooks/useResyncAsset'
33
- import {getPlaybackPolicy} from '../util/getPlaybackPolicy'
34
- import type {MuxInputProps, PluginConfig, VideoAssetDocument} from '../util/types'
35
- import {FileInputMenuItem} from './FileInputMenuItem'
36
-
37
- const LockCard = styled(Card)`
38
- position: absolute;
39
- top: 0;
40
- left: 0;
41
- opacity: 0.6;
42
- mix-blend-mode: screen;
43
- background: transparent;
44
- `
45
-
46
- const LockButton = styled(Button)`
47
- background: transparent;
48
- color: white;
49
- `
50
-
51
- // @TODO: add support for audio type (asset._type) when uploading an audio file so we can hide the thumbnail option.
52
- const isVideoAsset = (asset: VideoAssetDocument) => {
53
- return asset._type === 'mux.videoAsset'
54
- }
55
-
56
- function PlayerActionsMenu(
57
- props: Pick<MuxInputProps, 'onChange' | 'readOnly'> & {
58
- asset: VideoAssetDocument
59
- onSelect: (files: File[]) => void
60
- dialogState: DialogState
61
- setDialogState: SetDialogState
62
- config: PluginConfig
63
- accept: string
64
- }
65
- ) {
66
- const {asset, readOnly, dialogState, setDialogState, onChange, onSelect, accept} = props
67
- const [open, setOpen] = useState(false)
68
- const [menuElement, setMenuRef] = useState<HTMLDivElement | null>(null)
69
- const isSigned = useMemo(() => getPlaybackPolicy(asset)?.policy === 'signed', [asset])
70
- const {hasConfigAccess} = useAccessControl(props.config)
71
- const {resyncAsset, isResyncing} = useResyncAsset({showToast: true})
72
-
73
- const onReset = useCallback(() => onChange(PatchEvent.from(unset([]))), [onChange])
74
-
75
- const handleResync = useCallback(async () => {
76
- setOpen(false)
77
- await resyncAsset(asset)
78
- }, [resyncAsset, asset])
79
-
80
- useEffect(() => {
81
- if (open && dialogState) {
82
- setOpen(false)
83
- }
84
- }, [dialogState, open])
85
-
86
- useClickOutsideEvent(
87
- () => setOpen(false),
88
- () => [menuElement]
89
- )
90
-
91
- return (
92
- <Inline space={1} padding={2}>
93
- {isSigned && (
94
- <Tooltip
95
- animate
96
- content={
97
- <Box padding={2}>
98
- <Text muted size={1}>
99
- Signed playback policy
100
- </Text>
101
- </Box>
102
- }
103
- placement="right"
104
- portal
105
- >
106
- <LockCard radius={2} margin={2} scheme="dark" tone="positive">
107
- <LockButton icon={LockIcon} mode="bleed" tone="positive" />
108
- </LockCard>
109
- </Tooltip>
110
- )}
111
- <Popover
112
- animate
113
- content={
114
- <Menu ref={setMenuRef}>
115
- <Box padding={2}>
116
- <Label muted size={1}>
117
- Replace
118
- </Label>
119
- </Box>
120
- <FileInputMenuItem
121
- accept={accept}
122
- icon={UploadIcon}
123
- onSelect={onSelect}
124
- text="Upload"
125
- disabled={readOnly}
126
- fontSize={1}
127
- />
128
- <MenuItem
129
- icon={SearchIcon}
130
- text="Browse"
131
- onClick={() => setDialogState('select-video')}
132
- />
133
- {isVideoAsset(asset) && (
134
- <>
135
- <MenuItem
136
- icon={ImageIcon}
137
- text="Thumbnail"
138
- onClick={() => setDialogState('edit-thumbnail')}
139
- />
140
- <MenuItem
141
- icon={TranslateIcon}
142
- text="Captions"
143
- onClick={() => setDialogState('edit-captions')}
144
- />
145
- <MenuItem
146
- icon={SyncIcon}
147
- text="Resync from Mux"
148
- onClick={handleResync}
149
- disabled={readOnly || isResyncing}
150
- />
151
- </>
152
- )}
153
- <MenuDivider />
154
- {hasConfigAccess && (
155
- <>
156
- <MenuItem
157
- icon={PlugIcon}
158
- text="Configure API"
159
- onClick={() => setDialogState('secrets')}
160
- />
161
- <MenuDivider />
162
- </>
163
- )}
164
- <MenuItem
165
- tone="critical"
166
- icon={ResetIcon}
167
- text="Clear field"
168
- onClick={onReset}
169
- disabled={readOnly}
170
- />
171
- </Menu>
172
- }
173
- portal
174
- open={open}
175
- >
176
- <Button
177
- icon={EllipsisHorizontalIcon}
178
- mode="ghost"
179
- fontSize={1}
180
- onClick={() => {
181
- setDialogState(false)
182
- setOpen(true)
183
- }}
184
- />
185
- </Popover>
186
- </Inline>
187
- )
188
- }
189
-
190
- export default memo(PlayerActionsMenu)