Skip to content

Commit

Permalink
first version of the video analyzer
Browse files Browse the repository at this point in the history
  • Loading branch information
jbilcke-hf committed Jul 22, 2024
1 parent d827205 commit 5bd8810
Show file tree
Hide file tree
Showing 20 changed files with 932 additions and 243 deletions.
176 changes: 88 additions & 88 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
"dependencies": {
"@aitube/broadway": "0.0.22",
"@aitube/clap": "0.0.30",
"@aitube/clapper-services": "0.0.29",
"@aitube/clapper-services": "0.0.34",
"@aitube/engine": "0.0.26",
"@aitube/timeline": "0.0.43",
"@aitube/timeline": "0.0.44",
"@fal-ai/serverless-client": "^0.13.0",
"@ffmpeg/ffmpeg": "^0.12.10",
"@ffmpeg/util": "^0.12.1",
Expand Down
3 changes: 3 additions & 0 deletions public/images/onboarding/get-started.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/images/onboarding/get-started.xcf
Git LFS file not shown
3 changes: 3 additions & 0 deletions public/images/onboarding/pick-an-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/images/onboarding/pick-an-example.xcf
Git LFS file not shown
67 changes: 60 additions & 7 deletions src/app/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex'
import { useSearchParams } from 'next/navigation'
import { DndProvider, useDrop } from 'react-dnd'
import { HTML5Backend, NativeTypes } from 'react-dnd-html5-backend'
import { useTimeline } from '@aitube/timeline'

import { Toaster } from '@/components/ui/sonner'
import { cn } from '@/lib/utils'
Expand All @@ -14,22 +13,23 @@ import { Monitor } from '@/components/monitor'

import { SettingsDialog } from '@/components/settings'
import { LoadingDialog } from '@/components/dialogs/loader/LoadingDialog'
import { useUI } from '@/services/ui'
import { useUI, useIO } from '@/services'
import { TopBar } from '@/components/toolbars/top-bar'
import { Timeline } from '@/components/core/timeline'
import { useIO } from '@/services/io/useIO'
import { ChatView } from '@/components/assistant/ChatView'
import { Editors } from '@/components/editors/Editors'
import { useTheme } from '@/services/ui/useTheme'

type DroppableThing = { files: File[] }

function MainContent() {
const ref = useRef<HTMLDivElement>(null)
const isEmpty = useTimeline((s) => s.isEmpty)
const showWelcomeScreen = useUI((s) => s.showWelcomeScreen)
const showTimeline = useUI((s) => s.showTimeline)
const showAssistant = useUI((s) => s.showAssistant)

const theme = useTheme()
const openFiles = useIO((s) => s.openFiles)
const isTopMenuOpen = useUI((s) => s.isTopMenuOpen)

const [{ isOver, canDrop }, connectFileDrop] = useDrop({
accept: [NativeTypes.FILE],
Expand Down Expand Up @@ -67,8 +67,7 @@ function MainContent() {
<TopBar />
<div
className={cn(
`flex h-[calc(100vh-40px)] w-screen flex-row overflow-hidden`,
isEmpty ? 'opacity-0' : 'opacity-100'
`flex h-[calc(100vh-40px)] w-screen flex-row overflow-hidden`
)}
>
<ReflexContainer orientation="vertical">
Expand Down Expand Up @@ -109,6 +108,60 @@ function MainContent() {
</ReflexContainer>
</div>

<div
className={cn(
showWelcomeScreen
? 'pointer-events-auto z-[101] flex'
: 'pointer-events-none hidden',
`fixed top-[40px] h-[calc(100vh-40px)] w-screen flex-row overflow-hidden`,
`items-center justify-center`,
`bg-stone-950`
)}
>
<div
className="flex h-full w-full items-center justify-center"
style={{
backgroundImage:
'repeating-radial-gradient( circle at 0 0, transparent 0, #000000 7px ), repeating-linear-gradient( #37353455, #373534 )',
}}
>
<div
className={cn(
`pointer-events-none absolute left-[100px] top-[20px]`,
`opacity-90`
)}
>
<img
src="/images/onboarding/get-started.png"
width="180"
className=""
></img>
</div>
<div
className={cn(
`pointer-events-none absolute left-[305px] top-[140px]`,
`transition-all duration-200 ease-out`,
isTopMenuOpen ? 'scale-100 opacity-90' : 'scale-90 opacity-0'
)}
>
<img src="/images/onboarding/pick-an-example.png" width="140"></img>
</div>
<div className="flex flex-col items-center justify-center space-y-6">
<h1 className="text-6xl font-bold">
Welcome to{' '}
<span className="" style={{ color: theme.defaultPrimaryColor }}>
Clapper
</span>
.
</h1>
<div className="flex flex-col items-center justify-center space-y-2 text-center text-2xl font-semibold">
<p>A free and open-source AI video editor,</p>
<p>designed for the age of generative filmmaking.</p>
</div>
</div>
</div>
</div>

<SettingsDialog />
<LoadingDialog />
<Toaster />
Expand Down
60 changes: 45 additions & 15 deletions src/components/toolbars/top-menu/file/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
import { useOpenFilePicker, useQueryStringParams } from '@/lib/hooks'
import { IframeWarning } from '@/components/dialogs/iframe-warning'
import { useIO, useUI } from '@/services'
import { newClap } from '@aitube/clap'

export function TopMenuFile() {
const { clapUrl } = useQueryStringParams({
Expand Down Expand Up @@ -44,6 +45,9 @@ export function TopMenuFile() {

const hasBetaAccess = useUI((s) => s.hasBetaAccess)

const showWelcomeScreen = useUI((s) => s.showWelcomeScreen)
const setShowWelcomeScreen = useUI((s) => s.setShowWelcomeScreen)

useEffect(() => {
;(async () => {
if (!clapUrl) {
Expand All @@ -67,21 +71,21 @@ export function TopMenuFile() {
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
{hasBetaAccess && (
<MenubarItem
onClick={() => {
openClapUrl('/samples/claps/empty_project.clap')
}}
>
New Project<MenubarShortcut>⌘N</MenubarShortcut>
</MenubarItem>
)}
<MenubarItem
onClick={() => {
setClap(newClap())
setShowWelcomeScreen(false)
}}
>
New Project<MenubarShortcut>⌘N</MenubarShortcut>
</MenubarItem>
<MenubarSeparator />
<MenubarItem
onClick={() => {
openFilePicker()
}}
>
Open file (.clap, .txt)<MenubarShortcut>⌘O</MenubarShortcut>
Open project (.clap)<MenubarShortcut>⌘O</MenubarShortcut>
</MenubarItem>
<MenubarItem
onClick={() => {
Expand All @@ -92,7 +96,7 @@ export function TopMenuFile() {
</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Examples</MenubarSubTrigger>
<MenubarSubTrigger>Import an example</MenubarSubTrigger>
<MenubarSubContent>
<MenubarItem
onClick={() => {
Expand Down Expand Up @@ -157,20 +161,46 @@ export function TopMenuFile() {
<MenubarSeparator />
<MenubarItem
onClick={() => {
saveVideoFile()
openFilePicker()
}}
>
Import screenplay (.txt)
</MenubarItem>
<MenubarItem
onClick={() => {
openFilePicker()
}}
>
Import video (.mp4)
</MenubarItem>
{/*
In case we want to show a video import wizard UI:
<MenubarItem
onClick={() => {
openFilePicker()
}}
>
Export project to MP4
Import video (.mp4)
</MenubarItem>
<MenubarSeparator />
*/}

<MenubarSeparator />
<MenubarItem
onClick={() => {
saveVideoFile()
}}
>
Export full video (.mp4)
</MenubarItem>
<MenubarItem
onClick={() => {
saveZipFile()
}}
>
Export project to .zip
Export all assets (.zip)
</MenubarItem>
<MenubarSeparator />
{/*
<MenubarItem onClick={() => {
saveKdenline()
Expand Down
9 changes: 8 additions & 1 deletion src/components/toolbars/top-menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,17 @@ import { TopMenuPlugins } from './plugins'
export function TopMenu() {
const isBusyResolving = useResolver((s) => s.isBusyResolving)

const setIsTopMenuOpen = useUI((s) => s.setIsTopMenuOpen)

const hasBetaAccess = useUI((s) => s.hasBetaAccess)

return (
<Menubar className="ml-1 w-full">
<Menubar
className="ml-1 w-full"
onValueChange={(value) => {
setIsTopMenuOpen(!!value)
}}
>
<TopMenuLogo />
<TopMenuFile />
{hasBetaAccess && <TopMenuEdit />}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
export const HARD_LIMIT_NB_MAX_ASSETS_TO_GENERATE_IN_PARALLEL = 32

export const APP_NAME = 'Clapper.app'
export const APP_REVISION = 'r20240722-0205'
export const APP_REVISION = 'r20240722-2258'

export const APP_DOMAIN = 'Clapper.app'
export const APP_LINK = 'https://clapper.app'
36 changes: 31 additions & 5 deletions src/lib/hooks/useOpenFilePicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,24 @@ import { useFilePicker } from 'use-file-picker'
import { parseFileName } from '@/services/io/parseFileName'
import { useIO } from '@/services/io/useIO'

const supportedExtensions = ['clap', 'txt']
const defaultSupportedExtensions = ['clap', 'txt', 'mp4', 'mp3']

export function useOpenFilePicker() {
export function useOpenFilePicker(
{
supportedExtensions = defaultSupportedExtensions,
}: {
supportedExtensions: string[]
} = {
supportedExtensions: defaultSupportedExtensions,
}
) {
const [isLoading, setIsLoading] = useState(false)
const openClapBlob = useIO((s) => s.openClapBlob)
const openScreenplay = useIO((s) => s.openScreenplay)
const openVideo = useIO((s) => s.openVideo)

const { openFilePicker, filesContent, loading } = useFilePicker({
accept: ['clap', 'txt'].map((ext) => `.${ext}`),
accept: supportedExtensions.map((ext) => `.${ext}`),
readAs: 'ArrayBuffer',
})

Expand All @@ -27,7 +36,7 @@ export function useOpenFilePicker() {

const { fileName, projectName, extension } = parseFileName(input)

if (!supportedExtensions.includes(extension)) {
if (!defaultSupportedExtensions.includes(extension)) {
console.error(`unsupported extension "${extension}"`)
return
}
Expand All @@ -52,10 +61,27 @@ export function useOpenFilePicker() {
} finally {
setIsLoading(false)
}
} else if (extension === 'mp4') {
try {
setIsLoading(true)
await openVideo(projectName, fileName, blob)
} catch (err) {
console.error('failed to load the Clap file:', err)
} finally {
setIsLoading(false)
}
} else if (extension === 'mp3') {
alert('Initializing a project from a mp3 is not supported yet')
}
}
fn()
}, [fileData?.name, fileData?.content, openClapBlob, openScreenplay])
}, [
fileData?.name,
fileData?.content,
openClapBlob,
openScreenplay,
openVideo,
])

return {
openFilePicker,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/base64DataUriToFile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export function base64DataUriToFile(dataUrl: string, fileName: string) {
var arr = dataUrl.split(',')
var arr = `${dataUrl || ''}`.split(',')
const st = `${arr[0] || ''}`
const mime = `${st.match(/:(.*?);/)?.[1] || ''}`
const bstr = atob(arr[arr.length - 1])
Expand Down
Loading

0 comments on commit 5bd8810

Please sign in to comment.