Quick Example
import videodb
conn = videodb.connect()
coll = conn.get_collection()
video = coll.get_video("m-xxx")
# Stream from search results
results = video.search("product demo")
stream_url = results.compile()
# Stream from timestamps
stream_url = video.generate_stream([(10, 30), (45, 60)])
# Get download URL
download_url = video.download(name="sample video")
import { connect } from 'videodb';
const conn = connect();
const coll = await conn.getCollection();
const video = await coll.getVideo("m-xxx");
// Stream from search results
const results = await video.search("product demo");
const streamUrl = await results.compile();
// Stream from timestamps
const streamUrl2 = await video.generateStream([[10, 30], [45, 60]]);
// Get download URL
const downloadUrl = await video.download("sample video");
Stream Generation
From Search Results
Search returns matching segments. Generate a stream to play them as a single video.# Search for content
results = video.search("key moments")
# Generate playable stream
stream_url = results.compile()
# https://stream.videodb.io/v3/published/manifests/{id}.m3u8
# Play in browser
results.play()
// Search for content
const results = await video.search("key moments");
// Generate playable stream
const streamUrl = await results.compile();
// https://stream.videodb.io/v3/published/manifests/{id}.m3u8
// Play in browser
await results.play();
From Timestamps
Create streams from specific time ranges.# Define time segments (start, end) in seconds
timestamps = [
(0, 15), # Intro
(120, 180), # Main content
(300, 330) # Conclusion
]
stream_url = video.generate_stream(timestamps)
// Define time segments [start, end] in seconds
const timestamps = [
[0, 15], // Intro
[120, 180], // Main content
[300, 330] // Conclusion
];
const streamUrl = await video.generateStream(timestamps);
From Timeline
Export composed timelines as streams.from videodb.editor import Timeline, VideoAsset
# Build timeline
timeline = Timeline(conn)
timeline.add_inline(VideoAsset(video.id, start=10, end=30))
timeline.add_inline(VideoAsset(video.id, start=60, end=90))
# Generate stream
stream_url = timeline.generate_stream()
import { Timeline, VideoAsset } from 'videodb';
// Build timeline
const timeline = new Timeline(conn);
timeline.addInline(new VideoAsset(video.id, 10, 30));
timeline.addInline(new VideoAsset(video.id, 60, 90));
// Generate stream
const streamUrl = await timeline.generateStream();
Stream URL Format
All generated streams use HLS format:https://stream.videodb.io/v3/published/manifests/{manifest-id}.m3u8
| Property | Value |
|---|---|
| Format | HLS (HTTP Live Streaming) |
| Container | .m3u8 manifest with .ts segments |
| Compatibility | All modern browsers, native apps |
Download and Export
Get Video URL
# Full video download URL
download_url = video.download(name="sample video")
# https://cdn.videodb.io/v3/{collection}/{video}.mp4
// Full video download URL
const downloadUrl = await video.download("sample video");
// https://cdn.videodb.io/v3/{collection}/{video}.mp4
Get Audio URL
# Audio-only download
audio_url = audio.generate_url()
// Audio-only download
const audioUrl = await audio.generateUrl();
Get Image URL
# Generated image URL
image_url = image.generate_url()
// Generated image URL
const imageUrl = await image.generateUrl();
Embedding Streams
HTML5 Video
<video controls>
<source
src="https://stream.videodb.io/v3/published/manifests/{id}.m3u8"
type="application/x-mpegURL"
>
</video>
With HLS.js
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<video id="video" controls></video>
<script>
const video = document.getElementById('video');
const streamUrl = 'https://stream.videodb.io/v3/...';
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(streamUrl);
hls.attachMedia(video);
}
</script>
React Component
import Hls from 'hls.js';
import { useRef, useEffect } from 'react';
function VideoPlayer({ streamUrl }) {
const videoRef = useRef(null);
useEffect(() => {
if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(streamUrl);
hls.attachMedia(videoRef.current);
return () => hls.destroy();
}
}, [streamUrl]);
return <video ref={videoRef} controls />;
}
VideoDB Console Player
Use the built-in player:https://console.videodb.io/player?url={encoded_stream_url}
Clip Export Patterns
Export Search Results as Clips
results = video.search("highlight moments")
# Export each match as separate stream
clips = []
for shot in results.get_shots():
clip_url = shot.generate_stream()
clips.append({
"start": shot.start,
"end": shot.end,
"url": clip_url,
"text": shot.text
})
const results = await video.search("highlight moments");
// Export each match as separate stream
const clips = [];
for (const shot of results.shots) {
const clipUrl = await shot.generateStream();
clips.push({
start: shot.start,
end: shot.end,
url: clipUrl,
text: shot.text
});
}
Batch Export
def export_clips(video, timestamps, prefix="clip"):
"""Export multiple clips from a video"""
exports = []
for i, (start, end) in enumerate(timestamps):
stream_url = video.generate_stream([(start, end)])
exports.append({
"name": f"{prefix}_{i+1}",
"start": start,
"end": end,
"duration": end - start,
"url": stream_url
})
return exports
# Export intro, middle, outro
clips = export_clips(video, [
(0, 30),
(120, 180),
(300, 330)
])
async function exportClips(video, timestamps, prefix = "clip") {
const exports = [];
for (let i = 0; i < timestamps.length; i++) {
const [start, end] = timestamps[i];
const streamUrl = await video.generateStream([[start, end]]);
exports.push({
name: `${prefix}_${i + 1}`,
start,
end,
duration: end - start,
url: streamUrl
});
}
return exports;
}
// Export intro, middle, outro
const clips = await exportClips(video, [
[0, 30],
[120, 180],
[300, 330]
]);
Combine Multiple Videos
Merge Clips from Different Videos
from videodb.editor import Timeline, VideoAsset
video1 = coll.get_video("m-first")
video2 = coll.get_video("m-second")
video3 = coll.get_video("m-third")
# Create combined timeline
timeline = Timeline(conn)
timeline.add_inline(VideoAsset(video1.id, start=0, end=30))
timeline.add_inline(VideoAsset(video2.id, start=10, end=40))
timeline.add_inline(VideoAsset(video3.id, start=0, end=20))
# Generate merged stream
merged_url = timeline.generate_stream()
import { Timeline, VideoAsset } from 'videodb';
const video1 = await coll.getVideo("m-first");
const video2 = await coll.getVideo("m-second");
const video3 = await coll.getVideo("m-third");
// Create combined timeline
const timeline = new Timeline(conn);
timeline.addInline(new VideoAsset(video1.id, 0, 30));
timeline.addInline(new VideoAsset(video2.id, 10, 40));
timeline.addInline(new VideoAsset(video3.id, 0, 20));
// Generate merged stream
const mergedUrl = await timeline.generateStream();
Collection Highlights
from videodb.editor import Timeline, VideoAsset
# Search across collection
results = coll.search("best moments")
# Build highlight reel from top results
timeline = Timeline(conn)
for shot in results.get_shots()[:10]: # Top 10
video_asset = VideoAsset(id=shot.video_id, start=shot.start)
clip = Clip(asset=video_asset, duration=shot.end - shot.start)
track = Track()
track.add_clip(0, clip)
timeline.add_track(track)
highlight_url = timeline.generate_stream()
import { Timeline, VideoAsset } from 'videodb';
// Search across collection
const results = await coll.search("best moments");
// Build highlight reel from top results
const timeline = new Timeline(conn);
for (const shot of results.shots.slice(0, 10)) { // Top 10
const videoAsset = new VideoAsset(shot.videoId, { start: shot.start });
const clip = new Clip({ asset: videoAsset, duration: shot.end - shot.start });
const track = new Track();
track.addClip(0, clip);
timeline.addTrack(track);
}
const highlightUrl = await timeline.generateStream();
URL Lifecycle
| Stage | Duration | Notes |
|---|---|---|
| Generation | Instant | Stream URL returned immediately |
| Playback | 24 hours | URL valid for playback |
| Regeneration | Anytime | Call generate_stream again for new URL |
Refresh Expired URLs
def get_fresh_stream(video, timestamps, cache={}):
"""Get stream URL, regenerating if needed"""
cache_key = f"{video.id}:{timestamps}"
# Check cache and expiry
if cache_key in cache:
cached = cache[cache_key]
if cached["expires"] > time.time():
return cached["url"]
# Generate fresh URL
url = video.generate_stream(timestamps)
cache[cache_key] = {
"url": url,
"expires": time.time() + 23 * 3600 # 23 hours
}
return url
const cache = new Map();
async function getFreshStream(video, timestamps) {
const cacheKey = `${video.id}:${JSON.stringify(timestamps)}`;
// Check cache and expiry
const cached = cache.get(cacheKey);
if (cached && cached.expires > Date.now()) {
return cached.url;
}
// Generate fresh URL
const url = await video.generateStream(timestamps);
cache.set(cacheKey, {
url,
expires: Date.now() + 23 * 60 * 60 * 1000 // 23 hours
});
return url;
}
Reframe and Aspect Ratio Conversion
reframe()
Convert a video to a different aspect ratio. Useful for repurposing landscape content to vertical formats for social media.
# Reframe to vertical (9:16) for social media
vertical_video = video.reframe(target="vertical", mode="smart")
# Custom aspect ratio (square)
square_video = video.reframe(target={"width": 1, "height": 1})
# Reframe a specific time range
clip = video.reframe(start=10.0, end=60.0, target="vertical")
# Async with callback
video.reframe(
start=10.0,
end=60.0,
target="vertical",
callback_url="https://example.com/webhook"
)
| Parameter | Type | Description |
|---|---|---|
target | str or dict | "vertical", "square", "landscape", or {"width": int, "height": int} |
mode | str | "simple" or "smart" (default). Smart mode uses object-aware tracking. |
start | float | Optional start time in seconds |
end | float | Optional end time in seconds |
callback_url | str | Optional URL for async completion callback |
smart_vertical_reframe()
Convenience method that reframes to vertical (9:16) with smart object tracking in a single call:
vertical = video.smart_vertical_reframe()
Next Steps
Publishing Patterns
Embed players and share content
Timeline Architecture
Build complex compositions