Spaces:
Sleeping
Sleeping
Julian Bilcke
commited on
Commit
·
e4d3d8a
1
Parent(s):
0f35d4c
work in progress on the comment system
Browse files- src/app/interface/channel-card/index.tsx +1 -6
- src/app/interface/comment-card/index.tsx +70 -0
- src/app/interface/comment-list/index.tsx +27 -0
- src/app/interface/default-avatar/impl.tsx +48 -0
- src/app/interface/default-avatar/index.tsx +4 -45
- src/app/interface/video-card/index.tsx +7 -11
- src/app/views/public-channel-view/index.tsx +7 -11
- src/app/views/public-video-view/index.tsx +7 -11
- src/types.ts +43 -0
src/app/interface/channel-card/index.tsx
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
import { useState } from "react"
|
| 2 |
-
import dynamic from "next/dynamic"
|
| 3 |
|
| 4 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
| 5 |
import { IoAdd } from "react-icons/io5"
|
|
@@ -7,12 +6,8 @@ import { IoAdd } from "react-icons/io5"
|
|
| 7 |
import { cn } from "@/lib/utils"
|
| 8 |
import { ChannelInfo } from "@/types"
|
| 9 |
import { isCertifiedUser } from "@/app/certification"
|
| 10 |
-
import
|
| 11 |
|
| 12 |
-
const DefaultAvatar = dynamic(() => import("../default-avatar"), {
|
| 13 |
-
loading: () => null,
|
| 14 |
-
})
|
| 15 |
-
|
| 16 |
export function ChannelCard({
|
| 17 |
channel,
|
| 18 |
onClick,
|
|
|
|
| 1 |
import { useState } from "react"
|
|
|
|
| 2 |
|
| 3 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
| 4 |
import { IoAdd } from "react-icons/io5"
|
|
|
|
| 6 |
import { cn } from "@/lib/utils"
|
| 7 |
import { ChannelInfo } from "@/types"
|
| 8 |
import { isCertifiedUser } from "@/app/certification"
|
| 9 |
+
import { DefaultAvatar } from "../default-avatar"
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
export function ChannelCard({
|
| 12 |
channel,
|
| 13 |
onClick,
|
src/app/interface/comment-card/index.tsx
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { cn } from "@/lib/utils"
|
| 2 |
+
import { VideoComment } from "@/types"
|
| 3 |
+
import { useEffect, useState } from "react"
|
| 4 |
+
import { DefaultAvatar } from "../default-avatar"
|
| 5 |
+
|
| 6 |
+
export function CommentCard({
|
| 7 |
+
comment,
|
| 8 |
+
replies = []
|
| 9 |
+
}: {
|
| 10 |
+
comment?: VideoComment,
|
| 11 |
+
replies: VideoComment[]
|
| 12 |
+
}) {
|
| 13 |
+
|
| 14 |
+
const [userThumbnail, setUserThumbnail] = useState(comment?.user?.thumbnail || "")
|
| 15 |
+
|
| 16 |
+
useEffect(() => {
|
| 17 |
+
setUserThumbnail(comment?.user?.thumbnail || "")
|
| 18 |
+
|
| 19 |
+
}, [comment?.user?.thumbnail])
|
| 20 |
+
|
| 21 |
+
if (!comment) { return null }
|
| 22 |
+
|
| 23 |
+
const handleBadUserThumbnail = () => {
|
| 24 |
+
try {
|
| 25 |
+
if (userThumbnail) {
|
| 26 |
+
setUserThumbnail("")
|
| 27 |
+
}
|
| 28 |
+
} catch (err) {
|
| 29 |
+
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
return (
|
| 35 |
+
<div className={cn(
|
| 36 |
+
`flex flex-col`,
|
| 37 |
+
|
| 38 |
+
)}>
|
| 39 |
+
{/* THE COMMENT INFO - HORIZONTAL */}
|
| 40 |
+
<div className={cn(
|
| 41 |
+
`flex flex-col`,
|
| 42 |
+
|
| 43 |
+
)}>
|
| 44 |
+
<div
|
| 45 |
+
className={cn(
|
| 46 |
+
`flex flex-col items-center justify-center`,
|
| 47 |
+
`rounded-full overflow-hidden`,
|
| 48 |
+
`w-26 h-26`
|
| 49 |
+
)}
|
| 50 |
+
>
|
| 51 |
+
{comment.user.thumbnail
|
| 52 |
+
? <img
|
| 53 |
+
src={comment.user.thumbnail}
|
| 54 |
+
onError={handleBadUserThumbnail}
|
| 55 |
+
/>
|
| 56 |
+
: <DefaultAvatar
|
| 57 |
+
username={comment.user.userName}
|
| 58 |
+
bgColor="#fde047"
|
| 59 |
+
textColor="#1c1917"
|
| 60 |
+
width={104}
|
| 61 |
+
roundShape
|
| 62 |
+
/>}
|
| 63 |
+
</div>
|
| 64 |
+
</div>
|
| 65 |
+
|
| 66 |
+
{/* THE REPLIES */}
|
| 67 |
+
{/* TODO */}
|
| 68 |
+
</div>
|
| 69 |
+
)
|
| 70 |
+
}
|
src/app/interface/comment-list/index.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client"
|
| 2 |
+
|
| 3 |
+
import { cn } from "@/lib/utils"
|
| 4 |
+
import { VideoComment } from "@/types"
|
| 5 |
+
import { CommentCard } from "../comment-card"
|
| 6 |
+
|
| 7 |
+
export function CommentList({
|
| 8 |
+
comments = []
|
| 9 |
+
}: {
|
| 10 |
+
comments: VideoComment[]
|
| 11 |
+
}) {
|
| 12 |
+
|
| 13 |
+
return (
|
| 14 |
+
<div className={cn(
|
| 15 |
+
`flex flex-col`,
|
| 16 |
+
`w-full space-y-4`
|
| 17 |
+
)}>
|
| 18 |
+
{comments.map(comment => (
|
| 19 |
+
<CommentCard
|
| 20 |
+
key={comment.id}
|
| 21 |
+
comment={comment}
|
| 22 |
+
replies={[]}
|
| 23 |
+
/>
|
| 24 |
+
))}
|
| 25 |
+
</div>
|
| 26 |
+
)
|
| 27 |
+
}
|
src/app/interface/default-avatar/impl.tsx
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client"
|
| 2 |
+
|
| 3 |
+
import RSA from "react-string-avatar"
|
| 4 |
+
|
| 5 |
+
export type DefaultAvatarProps = {
|
| 6 |
+
username?: string
|
| 7 |
+
initials?: string
|
| 8 |
+
bgColor?: string
|
| 9 |
+
textColor?: string
|
| 10 |
+
roundShape?: boolean
|
| 11 |
+
cornerRadius?: number
|
| 12 |
+
pictureFormat?: string
|
| 13 |
+
pictureResolution?: number
|
| 14 |
+
width?: number
|
| 15 |
+
pixelated?: boolean
|
| 16 |
+
wrapper?: boolean
|
| 17 |
+
wrapperStyle?: Record<string, any>
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
export type DefaultAvatarComponent = (props: DefaultAvatarProps) => JSX.Element
|
| 21 |
+
|
| 22 |
+
const ReactStringAvatar = RSA as DefaultAvatarComponent
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
export default function DefaultAvatarImpl({
|
| 26 |
+
username,
|
| 27 |
+
initials: customInitials,
|
| 28 |
+
...props
|
| 29 |
+
}: DefaultAvatarProps): JSX.Element {
|
| 30 |
+
|
| 31 |
+
const usernameInitials = `${username || ""}`
|
| 32 |
+
.trim()
|
| 33 |
+
.replaceAll("_", " ")
|
| 34 |
+
.replaceAll("-", " ")
|
| 35 |
+
.replace(/([a-z])([A-Z])/g, '$1 $2') // split the camel case
|
| 36 |
+
.split(" ") // split words
|
| 37 |
+
.map(u => u.trim()[0]) // take first char
|
| 38 |
+
.slice(0, 2) // keep first 2 chars
|
| 39 |
+
.join("")
|
| 40 |
+
.toUpperCase()
|
| 41 |
+
|
| 42 |
+
return (
|
| 43 |
+
<ReactStringAvatar
|
| 44 |
+
initials={customInitials || usernameInitials}
|
| 45 |
+
{...props}
|
| 46 |
+
/>
|
| 47 |
+
)
|
| 48 |
+
}
|
src/app/interface/default-avatar/index.tsx
CHANGED
|
@@ -1,48 +1,7 @@
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
-
import
|
| 4 |
|
| 5 |
-
export
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
bgColor?: string
|
| 9 |
-
textColor?: string
|
| 10 |
-
roundShape?: boolean
|
| 11 |
-
cornerRadius?: number
|
| 12 |
-
pictureFormat?: string
|
| 13 |
-
pictureResolution?: number
|
| 14 |
-
width?: number
|
| 15 |
-
pixelated?: boolean
|
| 16 |
-
wrapper?: boolean
|
| 17 |
-
wrapperStyle?: Record<string, any>
|
| 18 |
-
}
|
| 19 |
-
|
| 20 |
-
export type DefaultAvatarComponent = (props: DefaultAvatarProps) => JSX.Element
|
| 21 |
-
|
| 22 |
-
const ReactStringAvatar = RSA as DefaultAvatarComponent
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
export default function DefaultAvatar({
|
| 26 |
-
username,
|
| 27 |
-
initials: customInitials,
|
| 28 |
-
...props
|
| 29 |
-
}: DefaultAvatarProps): JSX.Element {
|
| 30 |
-
|
| 31 |
-
const usernameInitials = `${username || ""}`
|
| 32 |
-
.trim()
|
| 33 |
-
.replaceAll("_", " ")
|
| 34 |
-
.replaceAll("-", " ")
|
| 35 |
-
.replace(/([a-z])([A-Z])/g, '$1 $2') // split the camel case
|
| 36 |
-
.split(" ") // split words
|
| 37 |
-
.map(u => u.trim()[0]) // take first char
|
| 38 |
-
.slice(0, 2) // keep first 2 chars
|
| 39 |
-
.join("")
|
| 40 |
-
.toUpperCase()
|
| 41 |
-
|
| 42 |
-
return (
|
| 43 |
-
<ReactStringAvatar
|
| 44 |
-
initials={customInitials || usernameInitials}
|
| 45 |
-
{...props}
|
| 46 |
-
/>
|
| 47 |
-
)
|
| 48 |
-
}
|
|
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
+
import dynamic from "next/dynamic"
|
| 4 |
|
| 5 |
+
export const DefaultAvatar = dynamic(() => import("./impl"), {
|
| 6 |
+
loading: () => null,
|
| 7 |
+
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
src/app/interface/video-card/index.tsx
CHANGED
|
@@ -11,11 +11,7 @@ import { formatDuration } from "@/lib/formatDuration"
|
|
| 11 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
| 12 |
import { isCertifiedUser } from "@/app/certification"
|
| 13 |
import { transparentImage } from "@/lib/transparentImage"
|
| 14 |
-
|
| 15 |
-
const DefaultAvatar = dynamic(() => import("../default-avatar"), {
|
| 16 |
-
loading: () => null,
|
| 17 |
-
})
|
| 18 |
-
|
| 19 |
|
| 20 |
export function VideoCard({
|
| 21 |
video,
|
|
@@ -184,12 +180,12 @@ export function VideoCard({
|
|
| 184 |
</div>
|
| 185 |
</div>
|
| 186 |
: <DefaultAvatar
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
<div className={cn(
|
| 194 |
`flex flex-col`,
|
| 195 |
isCompact ? `` : `flex-grow`
|
|
|
|
| 11 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
| 12 |
import { isCertifiedUser } from "@/app/certification"
|
| 13 |
import { transparentImage } from "@/lib/transparentImage"
|
| 14 |
+
import { DefaultAvatar } from "../default-avatar"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
export function VideoCard({
|
| 17 |
video,
|
|
|
|
| 180 |
</div>
|
| 181 |
</div>
|
| 182 |
: <DefaultAvatar
|
| 183 |
+
username={video.channel.datasetUser}
|
| 184 |
+
bgColor="#fde047"
|
| 185 |
+
textColor="#1c1917"
|
| 186 |
+
width={36}
|
| 187 |
+
roundShape
|
| 188 |
+
/>}
|
| 189 |
<div className={cn(
|
| 190 |
`flex flex-col`,
|
| 191 |
isCompact ? `` : `flex-grow`
|
src/app/views/public-channel-view/index.tsx
CHANGED
|
@@ -1,16 +1,12 @@
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
import { useEffect, useState, useTransition } from "react"
|
| 4 |
-
import dynamic from "next/dynamic"
|
| 5 |
|
| 6 |
import { useStore } from "@/app/state/useStore"
|
| 7 |
import { cn } from "@/lib/utils"
|
| 8 |
import { VideoList } from "@/app/interface/video-list"
|
| 9 |
import { getChannelVideos } from "@/app/server/actions/ai-tube-hf/getChannelVideos"
|
| 10 |
-
|
| 11 |
-
const DefaultAvatar = dynamic(() => import("../../interface/default-avatar"), {
|
| 12 |
-
loading: () => null,
|
| 13 |
-
})
|
| 14 |
|
| 15 |
export function PublicChannelView() {
|
| 16 |
const [_isPending, startTransition] = useTransition()
|
|
@@ -66,12 +62,12 @@ export function PublicChannelView() {
|
|
| 66 |
className="w-full h-full overflow-hidden object-cover"
|
| 67 |
/>
|
| 68 |
: <DefaultAvatar
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
</div>
|
| 76 |
|
| 77 |
{/* CHANNEL INFO - HORIZONTAL */}
|
|
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
import { useEffect, useState, useTransition } from "react"
|
|
|
|
| 4 |
|
| 5 |
import { useStore } from "@/app/state/useStore"
|
| 6 |
import { cn } from "@/lib/utils"
|
| 7 |
import { VideoList } from "@/app/interface/video-list"
|
| 8 |
import { getChannelVideos } from "@/app/server/actions/ai-tube-hf/getChannelVideos"
|
| 9 |
+
import { DefaultAvatar } from "@/app/interface/default-avatar"
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
export function PublicChannelView() {
|
| 12 |
const [_isPending, startTransition] = useTransition()
|
|
|
|
| 62 |
className="w-full h-full overflow-hidden object-cover"
|
| 63 |
/>
|
| 64 |
: <DefaultAvatar
|
| 65 |
+
username={publicChannel.datasetUser}
|
| 66 |
+
bgColor="#fde047"
|
| 67 |
+
textColor="#1c1917"
|
| 68 |
+
width={160}
|
| 69 |
+
roundShape
|
| 70 |
+
/>}
|
| 71 |
</div>
|
| 72 |
|
| 73 |
{/* CHANNEL INFO - HORIZONTAL */}
|
src/app/views/public-video-view/index.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
import { useEffect, useState, useTransition } from "react"
|
| 4 |
-
import dynamic from "next/dynamic"
|
| 5 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
| 6 |
import { PiShareFatLight } from "react-icons/pi"
|
| 7 |
import CopyToClipboard from "react-copy-to-clipboard"
|
|
@@ -18,10 +17,7 @@ import { RecommendedVideos } from "@/app/interface/recommended-videos"
|
|
| 18 |
import { isCertifiedUser } from "@/app/certification"
|
| 19 |
import { watchVideo } from "@/app/server/actions/stats"
|
| 20 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
| 21 |
-
|
| 22 |
-
const DefaultAvatar = dynamic(() => import("../../interface/default-avatar"), {
|
| 23 |
-
loading: () => null,
|
| 24 |
-
})
|
| 25 |
|
| 26 |
export function PublicVideoView() {
|
| 27 |
const [_pending, startTransition] = useTransition()
|
|
@@ -160,12 +156,12 @@ export function PublicVideoView() {
|
|
| 160 |
</div>
|
| 161 |
</div>
|
| 162 |
: <DefaultAvatar
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
</div>
|
| 170 |
</a>
|
| 171 |
|
|
|
|
| 1 |
"use client"
|
| 2 |
|
| 3 |
import { useEffect, useState, useTransition } from "react"
|
|
|
|
| 4 |
import { RiCheckboxCircleFill } from "react-icons/ri"
|
| 5 |
import { PiShareFatLight } from "react-icons/pi"
|
| 6 |
import CopyToClipboard from "react-copy-to-clipboard"
|
|
|
|
| 17 |
import { isCertifiedUser } from "@/app/certification"
|
| 18 |
import { watchVideo } from "@/app/server/actions/stats"
|
| 19 |
import { formatTimeAgo } from "@/lib/formatTimeAgo"
|
| 20 |
+
import { DefaultAvatar } from "@/app/interface/default-avatar"
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
export function PublicVideoView() {
|
| 23 |
const [_pending, startTransition] = useTransition()
|
|
|
|
| 156 |
</div>
|
| 157 |
</div>
|
| 158 |
: <DefaultAvatar
|
| 159 |
+
username={video.channel.datasetUser}
|
| 160 |
+
bgColor="#fde047"
|
| 161 |
+
textColor="#1c1917"
|
| 162 |
+
width={36}
|
| 163 |
+
roundShape
|
| 164 |
+
/>}
|
| 165 |
</div>
|
| 166 |
</a>
|
| 167 |
|
src/types.ts
CHANGED
|
@@ -441,6 +441,48 @@ export type VideoInfo = {
|
|
| 441 |
orientation: VideoOrientation
|
| 442 |
}
|
| 443 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
export type VideoGenerationModel =
|
| 445 |
| "HotshotXL"
|
| 446 |
| "SVD"
|
|
@@ -473,6 +515,7 @@ export type InterfaceView =
|
|
| 473 |
| "public_music_videos" // public music videos - it's a special category, because music is *cool*
|
| 474 |
| "not_found"
|
| 475 |
|
|
|
|
| 476 |
export type Settings = {
|
| 477 |
huggingfaceApiKey: string
|
| 478 |
}
|
|
|
|
| 441 |
orientation: VideoOrientation
|
| 442 |
}
|
| 443 |
|
| 444 |
+
export type PublicUserInfo = {
|
| 445 |
+
id: string
|
| 446 |
+
|
| 447 |
+
type: "normal" | "admin"
|
| 448 |
+
|
| 449 |
+
userName: string
|
| 450 |
+
|
| 451 |
+
firstName: string
|
| 452 |
+
|
| 453 |
+
lastName: string
|
| 454 |
+
|
| 455 |
+
thumbnail: string
|
| 456 |
+
|
| 457 |
+
channels: ChannelInfo[]
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
export type PrivateUserInfo = PublicUserInfo & {
|
| 461 |
+
|
| 462 |
+
// the Hugging Face API token is confidential!
|
| 463 |
+
hfApiToken: string
|
| 464 |
+
}
|
| 465 |
+
|
| 466 |
+
export type VideoComment = {
|
| 467 |
+
id: string
|
| 468 |
+
|
| 469 |
+
user: PublicUserInfo
|
| 470 |
+
|
| 471 |
+
// if the video comment is in response to another comment,
|
| 472 |
+
// then "inReplyTo" will contain the other video comment id
|
| 473 |
+
inReplyTo?: string
|
| 474 |
+
|
| 475 |
+
createdAt: string
|
| 476 |
+
updatedAt: string
|
| 477 |
+
message: string
|
| 478 |
+
|
| 479 |
+
// how many likes did the comment receive
|
| 480 |
+
nbLikes: number
|
| 481 |
+
|
| 482 |
+
// if the comment was appreciated by the video owner
|
| 483 |
+
appreciated: number
|
| 484 |
+
}
|
| 485 |
+
|
| 486 |
export type VideoGenerationModel =
|
| 487 |
| "HotshotXL"
|
| 488 |
| "SVD"
|
|
|
|
| 515 |
| "public_music_videos" // public music videos - it's a special category, because music is *cool*
|
| 516 |
| "not_found"
|
| 517 |
|
| 518 |
+
|
| 519 |
export type Settings = {
|
| 520 |
huggingfaceApiKey: string
|
| 521 |
}
|