Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

convert.remotion.dev: Use output as input #4532

Merged
merged 1 commit into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions packages/convert/app/components/ConversionDone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {ConvertMediaContainer} from '@remotion/webcodecs';
import React, {useCallback} from 'react';
import {ConvertState, Source} from '~/lib/convert-state';
import {getNewName} from '~/lib/generate-new-name';
import {ConvertProgress} from './ConvertProgress';
import {CloneIcon} from './icons/clone';
import {Button} from './ui/button';

export const ConversionDone: React.FC<{
readonly state: ConvertState;
readonly setState: React.Dispatch<React.SetStateAction<ConvertState>>;
readonly name: string | null;
readonly container: ConvertMediaContainer;
readonly setSrc: React.Dispatch<React.SetStateAction<Source | null>>;
}> = ({state, name, container, setState, setSrc}) => {
if (state.type !== 'done') {
throw new Error('Expected state to be done');
}

const onDownload = useCallback(async () => {
if (!name) {
throw new Error('Expected name to be set');
}

try {
const file = await state.download();
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = getNewName(name, container);
a.click();
URL.revokeObjectURL(a.href);
} catch (e) {
console.error(e);
setState({type: 'error', error: e as Error});
}
}, [container, name, setState, state]);

const useAsInput = useCallback(async () => {
const file = await state.download();

setSrc({
type: 'file',
file,
});
}, [setSrc, state]);

return (
<>
<ConvertProgress state={state.state} name={name} container={container} />
<div className="h-2" />
<Button className="block w-full" type="button" onClick={onDownload}>
Download
</Button>
<div className="h-2" />
<Button
variant="ghost"
className="w-full flex flex-row justify-start"
type="button"
onClick={useAsInput}
>
<CloneIcon className="size-4" />
<div className="w-2" />
Use as input
</Button>
</>
);
};
177 changes: 71 additions & 106 deletions packages/convert/app/components/ConvertUi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {webFileReader} from '@remotion/media-parser/web-file';
import {convertMedia, ConvertMediaContainer} from '@remotion/webcodecs';
import {useCallback, useEffect, useRef, useState} from 'react';
import {ConvertState, Source} from '~/lib/convert-state';
import {getNewName} from '~/lib/generate-new-name';
import {ConversionDone} from './ConversionDone';
import {ConvertForm} from './ConvertForm';
import {ConvertProgress, convertProgressRef} from './ConvertProgress';
import {ErrorState} from './ErrorState';
Expand All @@ -25,8 +25,10 @@ export default function ConvertUI({
currentAudioCodec,
currentVideoCodec,
tracks,
setSrc,
}: {
readonly src: Source;
readonly setSrc: React.Dispatch<React.SetStateAction<Source | null>>;
readonly currentAudioCodec: MediaParserAudioCodec | null;
readonly currentVideoCodec: MediaParserVideoCodec | null;
readonly tracks: TracksField | null;
Expand Down Expand Up @@ -67,8 +69,6 @@ export default function ConvertUI({
const abortController = new AbortController();
abortSignal.current = abortController;

let _n: string | null = null;

let videoFrames = 0;

convertMedia({
Expand Down Expand Up @@ -103,7 +103,6 @@ export default function ConvertUI({
name: true,
},
onName: (n) => {
_n = n;
setName(n);
},
onAudioTrack: ({track}) => {
Expand Down Expand Up @@ -159,18 +158,7 @@ export default function ConvertUI({
}
return {
type: 'done',
download: async () => {
if (!_n) {
throw new Error('No name');
}

const file = await save();
const a = document.createElement('a');
a.href = URL.createObjectURL(file);
a.download = getNewName(_n!, container);
a.click();
URL.revokeObjectURL(a.href);
},
download: save,
state: prevState.state,
};
});
Expand Down Expand Up @@ -211,19 +199,6 @@ export default function ConvertUI({
setState({type: 'idle'});
}, []);

const onDownload = useCallback(async () => {
if (state.type !== 'done') {
throw new Error('Cannot download when not done');
}

try {
await state.download();
} catch (e) {
console.error(e);
setState({type: 'error', error: e as Error});
}
}, [state]);

useEffect(() => {
return () => {
if (abortSignal.current) {
Expand All @@ -232,84 +207,74 @@ export default function ConvertUI({
};
}, []);

if (state.type === 'error') {
return (
<>
<ErrorState error={state.error} />
<div className="h-4" />
<Button className="block w-full" type="button" onClick={dimissError}>
Dismiss
</Button>
</>
);
}

if (state.type === 'in-progress') {
return (
<>
<ConvertProgress
state={state.state}
name={name}
container={container}
/>
<div className="h-2" />
<Button className="block w-full" type="button" onClick={cancel}>
Cancel
</Button>
</>
);
}

if (state.type === 'done') {
return <ConversionDone {...{container, name, setState, state, setSrc}} />;
}

return (
<div className="w-full lg:w-[350px]">
<div className="gap-4">
{state.type === 'error' ? (
<>
<ErrorState error={state.error} />
<div className="h-4" />
<Button
className="block w-full"
type="button"
onClick={dimissError}
>
Dismiss
</Button>
</>
) : state.type === 'in-progress' ? (
<>
<ConvertProgress
state={state.state}
name={name}
container={container}
/>
<div className="h-2" />
<Button className="block w-full" type="button" onClick={cancel}>
Cancel
</Button>
</>
) : state.type === 'done' ? (
<>
<ConvertProgress
state={state.state}
name={name}
container={container}
/>
<div className="h-2" />
<Button className="block w-full" type="button" onClick={onDownload}>
Download
</Button>
</>
) : (
<>
<div className=" w-full items-center">
<div className="flex flex-row">
<CardTitle>Convert video</CardTitle>
<div className="w-2" />
<Badge variant="default">Alpha</Badge>
</div>
<div className="h-6" />
<ConvertForm
{...{
container,
setContainer,
flipHorizontal,
flipVertical,
setFlipHorizontal,
setFlipVertical,
supportedConfigs,
audioConfigIndex,
videoConfigIndex,
setAudioConfigIndex,
setVideoConfigIndex,
currentAudioCodec,
currentVideoCodec,
}}
/>
</div>
<div className="h-4" />
<Button
className="block w-full font-brand"
type="button"
variant="brand"
onClick={onClick}
>
Convert
</Button>
</>
)}
<>
<div className="w-full items-center">
<div className="flex flex-row">
<CardTitle>Convert video</CardTitle>
<div className="w-2" />
<Badge variant="default">Alpha</Badge>
</div>
<div className="h-6" />
<ConvertForm
{...{
container,
setContainer,
flipHorizontal,
flipVertical,
setFlipHorizontal,
setFlipVertical,
supportedConfigs,
audioConfigIndex,
videoConfigIndex,
setAudioConfigIndex,
setVideoConfigIndex,
currentAudioCodec,
currentVideoCodec,
}}
/>
</div>
</div>
<div className="h-4" />
<Button
className="block w-full font-brand"
type="button"
variant="brand"
onClick={onClick}
>
Convert
</Button>
</>
);
}
17 changes: 11 additions & 6 deletions packages/convert/app/components/FileAvailable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,17 @@ export const FileAvailable: React.FC<{
onTracks={onTracks}
/>
<div className="h-8 lg:h-0 lg:w-8" />
<ConvertUI
currentAudioCodec={currentAudioCodec}
currentVideoCodec={currentVideoCodec}
src={src}
tracks={tracks}
/>
<div className="w-full lg:w-[350px]">
<div className="gap-4">
<ConvertUI
currentAudioCodec={currentAudioCodec}
currentVideoCodec={currentVideoCodec}
src={src}
tracks={tracks}
setSrc={setSrc}
/>
</div>
</div>
</div>
</div>
</div>
Expand Down
10 changes: 10 additions & 0 deletions packages/convert/app/components/icons/clone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {SVGProps} from 'react';

export const CloneIcon: React.FC<SVGProps<SVGSVGElement>> = (props) => (
<svg {...props} viewBox="0 0 512 512">
<path
fill="currentcolor"
d="M288 448L64 448l0-224 64 0 0-64-64 0c-35.3 0-64 28.7-64 64L0 448c0 35.3 28.7 64 64 64l224 0c35.3 0 64-28.7 64-64l0-64-64 0 0 64zm-64-96l224 0c35.3 0 64-28.7 64-64l0-224c0-35.3-28.7-64-64-64L224 0c-35.3 0-64 28.7-64 64l0 224c0 35.3 28.7 64 64 64z"
/>
</svg>
);
4 changes: 2 additions & 2 deletions packages/convert/app/lib/convert-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export type Source =
}
| {
type: 'file';
file: File;
file: Blob;
};

export type ConvertState =
Expand All @@ -17,7 +17,7 @@ export type ConvertState =
| {type: 'in-progress'; abortConversion: () => void; state: ConvertMediaState}
| {
type: 'done';
download: () => Promise<void>;
download: () => Promise<Blob>;
state: ConvertMediaState;
}
| {
Expand Down
6 changes: 5 additions & 1 deletion packages/convert/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@ const Index = () => {
return (
<div className="font-sans min-h-screen bg-slate-50">
{src ? (
<FileAvailable src={src} setSrc={setSrc} />
<FileAvailable
key={src.type === 'url' ? src.url : src.file.name}
src={src}
setSrc={setSrc}
/>
) : (
<PickFile setSrc={setSrc} />
)}
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/docs/media-parser/parse-media.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const result = await parseMedia({

### `src`

Either a local file path, or a URL, or a `File` object.
Either a local file path, or a URL, or a `File` or `Blob` object.
If you pass a local file path, you must also pass [`nodeReader`](/docs/media-parser/node-reader) as the `reader` argument.
If you pass a `File` object, you must also pass [`webFileReader`](/docs/media-parser/web-file-reader) as the `reader` argument.

Expand Down
2 changes: 1 addition & 1 deletion packages/docs/docs/webcodecs/convert-media.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ await convertMedia({

### `src`

A `string` or `File`.
A `string` or `File` or `Blob`.
If it is a `string`, it must be a URL.
If it is a `File`, the `reader` field must be set to [`webFileReader`](/docs/media-parser/web-file-reader).

Expand Down
Loading
Loading