diff --git a/packages/audio-utils/src/client.ts b/packages/audio-utils/src/client.ts new file mode 100644 index 0000000..a114804 --- /dev/null +++ b/packages/audio-utils/src/client.ts @@ -0,0 +1,26 @@ +import WaveSurfer from 'wavesurfer.js'; +import { AudioMetadata } from './common'; + +export const getMetadataFromUrl = (audioUrl: string) => new Promise>((resolve, reject) => { + try { + const dummyContainer = window.document.createElement('div'); + // TODO remove wavesurfer dependency + const waveSurferInstance = WaveSurfer.create({ + container: dummyContainer, + }); + + waveSurferInstance.on('ready', () => { + const metadata = { + duration: waveSurferInstance.getDuration(), + }; + + waveSurferInstance.destroy(); + dummyContainer.remove(); + resolve(metadata); + }); + + void waveSurferInstance.load(audioUrl); + } catch (err) { + reject(err); + } +}); diff --git a/packages/audio-utils/src/common.ts b/packages/audio-utils/src/common.ts new file mode 100644 index 0000000..b847793 --- /dev/null +++ b/packages/audio-utils/src/common.ts @@ -0,0 +1,3 @@ +export interface AudioMetadata { + duration?: number; +} diff --git a/packages/audio-utils/src/index.ts b/packages/audio-utils/src/index.ts index ea57f6b..fe90af8 100644 --- a/packages/audio-utils/src/index.ts +++ b/packages/audio-utils/src/index.ts @@ -1,39 +1,17 @@ -import WaveSurfer from 'wavesurfer.js'; +import {AudioMetadata} from './common'; -export interface AudioMetadata { - duration?: number; -} - -export const getAudioMetadata = (audioUrl?: string, fileType?: string) => new Promise(async (resolve, reject) => { - // TODO server side - if (fileType === 'audio/mid') { - resolve({}); - return; +export const getMetadataFromUrl = async (audioUrl?: string) => { + if (typeof audioUrl === 'undefined') { + return {} as Partial; } - try { - const dummyContainer = window.document.createElement('div'); - const waveSurferInstance = WaveSurfer.create({ - container: dummyContainer, - }); - - waveSurferInstance.on('ready', async () => { - const metadata = { - duration: waveSurferInstance.getDuration(), - }; - - waveSurferInstance.destroy(); - dummyContainer.remove(); - resolve(metadata); - }); + if (typeof window !== 'undefined') { + const { getMetadataFromUrl: client } = await import('./client'); + return client(audioUrl); + } - if (audioUrl === undefined) { - resolve({}); - return; - } + // TODO server side + return {} as Partial; +}; - await waveSurferInstance.load(audioUrl); - } catch (err) { - reject(err); - } -}); +export * from './common'; diff --git a/packages/image-utils/src/client.ts b/packages/image-utils/src/client.ts index 5f4769e..9230895 100644 --- a/packages/image-utils/src/client.ts +++ b/packages/image-utils/src/client.ts @@ -1,7 +1,7 @@ import ColorThief from 'colorthief'; import {DEFAULT_PALETTE_COLOR_COUNT, GetImageMetadataOptions, ImageMetadata} from './common'; -const doGetImageMetadata = async (thisImage: HTMLImageElement, options = {} as GetImageMetadataOptions) => { +const doGetImageMetadata = async (thisImage: HTMLImageElement, options = {} as GetImageMetadataOptions): Promise> => { const { paletteColorCount = DEFAULT_PALETTE_COLOR_COUNT } = options; const colorThief = new ColorThief(); const palette = await colorThief.getPalette(thisImage, paletteColorCount); @@ -12,9 +12,9 @@ const doGetImageMetadata = async (thisImage: HTMLImageElement, options = {} as G }; }; -export const getMetadataFromElement = (thisImage: HTMLImageElement, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(thisImage, options); +export const getMetadataFromElement = (thisImage: HTMLImageElement, options?: GetImageMetadataOptions): Promise> => doGetImageMetadata(thisImage, options); -export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMetadataOptions): Promise => new Promise((resolve, reject) => { +export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMetadataOptions): Promise> => new Promise((resolve, reject) => { const image = new Image(); image.addEventListener('load', async (imageLoadEvent) => { @@ -25,14 +25,9 @@ export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMet }); image.addEventListener('error', () => { - reject(new Error('Could not load file as image')); + reject(new Error('Could not load URL as image')); image.remove(); }); - if (imageUrl === undefined) { - resolve({}); - return; - } - image.src = imageUrl; }); diff --git a/packages/image-utils/src/index.ts b/packages/image-utils/src/index.ts index 7214b05..1b6bf76 100644 --- a/packages/image-utils/src/index.ts +++ b/packages/image-utils/src/index.ts @@ -1,6 +1,8 @@ +import {ImageMetadata} from './common'; + export const getMetadataFromUrl = async (imageUrl?: string) => { - if (imageUrl === undefined) { - return {}; + if (typeof imageUrl === 'undefined') { + return {} as Partial; } if (typeof window !== 'undefined') { diff --git a/packages/image-utils/src/server.ts b/packages/image-utils/src/server.ts index 96d54ad..574ada9 100644 --- a/packages/image-utils/src/server.ts +++ b/packages/image-utils/src/server.ts @@ -1,6 +1,6 @@ import {DEFAULT_PALETTE_COLOR_COUNT, GetImageMetadataOptions, ImageMetadata} from './common'; -const doGetImageMetadata = async (input: string | Buffer, options = {} as GetImageMetadataOptions) => { +const doGetImageMetadata = async (input: string | Buffer, options = {} as GetImageMetadataOptions): Promise> => { const { paletteColorCount = DEFAULT_PALETTE_COLOR_COUNT } = options; const { imageSize, disableFS } = await import('image-size'); disableFS(true); @@ -14,6 +14,6 @@ const doGetImageMetadata = async (input: string | Buffer, options = {} as GetIma }; }; -export const getMetadataFromUrl = (imageUrl: string, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(imageUrl, options); +export const getMetadataFromUrl = (imageUrl: string, options?: GetImageMetadataOptions): Promise> => doGetImageMetadata(imageUrl, options); -export const getMetadataFromBuffer = (buffer: Buffer, options?: GetImageMetadataOptions): Promise => doGetImageMetadata(buffer, options); +export const getMetadataFromBuffer = (buffer: Buffer, options?: GetImageMetadataOptions): Promise> => doGetImageMetadata(buffer, options); diff --git a/packages/text-utils/src/index.ts b/packages/text-utils/src/index.ts index bd020b3..3be9001 100644 --- a/packages/text-utils/src/index.ts +++ b/packages/text-utils/src/index.ts @@ -50,7 +50,7 @@ const countLinesOfCode = (lines: string[], scheme: string): number => { //return lines.filter((line) => !line.trim().startsWith('//')).length; return lines.filter((line) => line.trim().length > 0).length; -} +}; export const getTextMetadata = (contents: string, filename?: string): Promise => { const lineNormalizedContents = contents.replace(/\r\n/g, '\n').replace(/\r/g, '\n'); @@ -65,7 +65,7 @@ export const getTextMetadata = (contents: string, filename?: string): Promise new Promise>((resolve, reject) => { + const video = window.document.createElement('video'); + const source = window.document.createElement('source'); + + video.addEventListener('loadedmetadata', (videoLoadEvent) => { + const thisVideo = videoLoadEvent.currentTarget as HTMLVideoElement; + const metadata = { + width: thisVideo.videoWidth, + height: thisVideo.videoHeight, + duration: thisVideo.duration, + }; + video.remove(); + resolve(metadata); + }); + + video.addEventListener('error', () => { + reject(new Error('Could not load file as video')); + video.remove(); + }); + + source.src = videoUrl; + video.appendChild(source); +}); diff --git a/packages/video-utils/src/common.ts b/packages/video-utils/src/common.ts new file mode 100644 index 0000000..b6fc668 --- /dev/null +++ b/packages/video-utils/src/common.ts @@ -0,0 +1,5 @@ +export interface VideoMetadata { + width?: number; + height?: number; + duration?: number; +} diff --git a/packages/video-utils/src/index.ts b/packages/video-utils/src/index.ts index cf8476c..0f979f0 100644 --- a/packages/video-utils/src/index.ts +++ b/packages/video-utils/src/index.ts @@ -1,35 +1,15 @@ -export interface VideoFileMetadata { - width?: number; - height?: number; - duration?: number; -} - -export const getVideoMetadata = (videoUrl?: string) => new Promise((resolve, reject) => { - // TODO server side - const video = window.document.createElement('video'); - const source = window.document.createElement('source'); - - video.addEventListener('loadedmetadata', (videoLoadEvent) => { - const thisVideo = videoLoadEvent.currentTarget as HTMLVideoElement; - const metadata = { - width: thisVideo.videoWidth, - height: thisVideo.videoHeight, - duration: thisVideo.duration, - }; - video.remove(); - resolve(metadata); - }); - - video.addEventListener('error', () => { - reject(new Error('Could not load file as video')); - video.remove(); - }); - +export const getMetadataFromUrl = async (videoUrl?: string) => { if (typeof videoUrl === 'undefined') { - resolve({}); - return; + return {}; } - source.src = videoUrl; - video.appendChild(source); -}); + if (typeof window !== 'undefined') { + const { getMetadataFromUrl: client } = await import('./client'); + return client(videoUrl); + } + + // TODO server side + return {}; +}; + +export * from './common'; diff --git a/packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx b/packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx index e9c9baa..2c088c2 100644 --- a/packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx +++ b/packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx @@ -16,6 +16,7 @@ export const SpectrogramCanvas = React.forwardRef>(file: T): Promise => { const fileMutable = file as unknown as Record; - fileMutable.metadata = await getMetadataFromUrl(file.url); + fileMutable.metadata = await getImageMetadataFromUrl(file.url); return fileMutable as unknown as ImageFile; }; @@ -175,7 +175,11 @@ export interface AudioFile extends FileWithResolvedContentType { export const augmentAudioFile = async >(file: T): Promise => { const fileMutable = file as unknown as Record; - fileMutable.metadata = await getAudioMetadata(file.url, file.type); + if (file.type === 'audio/mid') { + fileMutable.metadata = {}; + } else { + fileMutable.metadata = await getAudioMetadataFromUrl(file.url); + } return fileMutable as unknown as AudioFile; }; @@ -200,11 +204,11 @@ export const augmentBinaryFile = async >(file export interface VideoFile extends FileWithResolvedContentType { resolvedType: ContentType.VIDEO; - metadata?: VideoFileMetadata; + metadata?: VideoMetadata; } export const augmentVideoFile = async >(file: T): Promise => { const fileMutable = file as unknown as Record; - fileMutable.metadata = await getVideoMetadata(file.url); + fileMutable.metadata = await getVideoMetadataFromUrl(file.url); return fileMutable as unknown as VideoFile; };