This guide explains how to parse the thumbnail pack and extract all the thumbnails
The thumbnail pack is a TAR archive. To unpack it you can use the js-untar, which can process TAR archives directly on the browser.
The archive can contain several JPEG image files. The name of each file has two parts separated by a dot: <capture-time>.<source-name>
.
The following file defines the processThumbnails
function for downloading the thumbnail pack URL and extracting all thumbnails in it:
import untar from 'js-untar';
/**
* Downloads a file and get content as ArrayBuffer
*
* @param {string} fileUrl
* @param {AbortSignal} [signal]
* @returns {Promise<ArrayBuffer>}
*/
export async function downloadFileToBuffer(fileUrl, signal) {
if (!fileUrl?.startsWith('http')) {
throw Error('Invalid URL: ' + fileUrl);
}
const resp = await fetch(fileUrl, { signal, cache: 'force-cache' });
const data = await resp.arrayBuffer();
return data.slice(0);
}
/**
* @param {Blob} blob
*/
export function blobAsDataUrl(blob) {
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(reader.error);
reader.abort = () => reject(new Error('aborted'));
reader.readAsDataURL(blob);
});
}
/**
* Downloads and process all thumbnails
*
* @param {Array<ThumbnailPack>} thumbnails
* @param {AbortSignal} [signal]
* @yields {VideoThumbnailData}
*/
export async function* processThumbnails(thumbnails, signal) {
for (const thumbnail of thumbnails || []) {
try {
const buffer = await downloadFileToBuffer(thumbnail.url, signal);
if (!buffer?.byteLength) {
console.debug('Empty buffer for', thumbnail.url);
continue;
}
const files = await untar(buffer);
for (const file of files) {
if (file.size !== file.buffer.byteLength) continue;
const nameParts = file.name.split('.');
if (nameParts.length !== 2) continue;
const ts = Number(nameParts[0]);
const source = nameParts[1];
const blob = new Blob([file.buffer], { type: 'image/jpeg' });
const src = await blobAsDataUrl(blob);
/** @type {VideoThumbnailData} */
const item = { source, src, ts };
yield item;
}
} catch (err) {
console.warn('Failed to process recording thumbnail', thumbnail, err);
}
}
}
/**
* @typedef {object} VideoThumbnailData
* @property {number} [ts] UNIX Timestamp
* @property {string} [source] Input source name
* @property {string} [src] The image url
* @property {any} [error]
*/
Here is a sample usage of the above function for extracting all thumbnails from the API response:
async function retrieveThumbnails(saiKey, endpointId) {
const sdk = require('api')('@smarterai/v4#bg74lc3bl801lxij');
sdk.auth(saiKey);
const result = await sdk.thumbnailList({endpointId: endpointId});
const thumbnails = [];
for await (const thumb of processThumbnails(result.thumbnailPacks)) {
thumbnails.push(thumb);
}
return thumbnails;
}