본문으로 건너뛰기

Shorts (숏폼 콘텐츠)

📌 Shorts 는 일반 비디오와 동일한 업로드 경로를 사용합니다. 다만 cb.video.uploadcb.video.storage.upload현재 chunk 단계 정렬 대기이므로, 당분간 raw fetch (POST /v1/public/uploads/initPUT .../chunkPOST .../complete)로 업로드한 뒤 콘솔/메타데이터로 Shorts 로 분류하세요. SDK 에는 별도의 createShort / remixShort 메서드가 없습니다.

Shorts 피드 조회

typescript
const result = await cb.video.getShortsFeed({
    cursor: undefined,  // 다음 페이지 토큰 (null/undefined 면 첫 페이지)
    limit: 10
})

console.log(result)
// {
//   items: Shorts[],
//   next_cursor?: string
// }

트렌딩 Shorts

typescript
const trending = await cb.video.getTrendingShorts(20)

단일 Shorts 조회

typescript
const short = await cb.video.getShorts('shorts-id')

무한 스크롤 구현

tsx
import { useState, useEffect, useRef } from 'react'
import type { Shorts } from 'connectbase-client'

export function ShortsFeed() {
    const [items, setItems] = useState<Shorts[]>([])
    const [cursor, setCursor] = useState<string | undefined>(undefined)
    const [hasMore, setHasMore] = useState(true)
    const sentinelRef = useRef<HTMLDivElement>(null)

    const loadMore = async () => {
        if (!hasMore) return
        const result = await cb.video.getShortsFeed({ cursor, limit: 5 })
        setItems((prev) => [...prev, ...result.items])
        setCursor(result.next_cursor)
        if (!result.next_cursor) setHasMore(false)
    }

    useEffect(() => {
        loadMore()
    }, [])

    useEffect(() => {
        const el = sentinelRef.current
        if (!el) return
        const observer = new IntersectionObserver(([entry]) => {
            if (entry.isIntersecting) loadMore()
        })
        observer.observe(el)
        return () => observer.disconnect()
    }, [cursor, hasMore])

    return (
        <div>
            {items.map((s) => (
                <ShortVideoItem key={s.id} short={s} />
            ))}
            <div ref={sentinelRef} />
        </div>
    )
}