Browse Source

Update content utils

Make utils methods consistent.
pull/1/head
TheoryOfNekomata 11 months ago
parent
commit
8391669d6c
12 changed files with 110 additions and 91 deletions
  1. +26
    -0
      packages/audio-utils/src/client.ts
  2. +3
    -0
      packages/audio-utils/src/common.ts
  3. +12
    -34
      packages/audio-utils/src/index.ts
  4. +4
    -9
      packages/image-utils/src/client.ts
  5. +4
    -2
      packages/image-utils/src/index.ts
  6. +3
    -3
      packages/image-utils/src/server.ts
  7. +4
    -4
      packages/text-utils/src/index.ts
  8. +25
    -0
      packages/video-utils/src/client.ts
  9. +5
    -0
      packages/video-utils/src/common.ts
  10. +12
    -32
      packages/video-utils/src/index.ts
  11. +1
    -0
      packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx
  12. +11
    -7
      packages/web-kitchensink-reactnext/src/utils/blob.ts

+ 26
- 0
packages/audio-utils/src/client.ts View File

@@ -0,0 +1,26 @@
import WaveSurfer from 'wavesurfer.js';
import { AudioMetadata } from './common';

export const getMetadataFromUrl = (audioUrl: string) => new Promise<Partial<AudioMetadata>>((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);
}
});

+ 3
- 0
packages/audio-utils/src/common.ts View File

@@ -0,0 +1,3 @@
export interface AudioMetadata {
duration?: number;
}

+ 12
- 34
packages/audio-utils/src/index.ts View File

@@ -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<AudioMetadata>(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<AudioMetadata>;
}

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<AudioMetadata>;
};

await waveSurferInstance.load(audioUrl);
} catch (err) {
reject(err);
}
});
export * from './common';

+ 4
- 9
packages/image-utils/src/client.ts View File

@@ -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<Partial<ImageMetadata>> => {
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<ImageMetadata> => doGetImageMetadata(thisImage, options);
export const getMetadataFromElement = (thisImage: HTMLImageElement, options?: GetImageMetadataOptions): Promise<Partial<ImageMetadata>> => doGetImageMetadata(thisImage, options);

export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMetadataOptions): Promise<ImageMetadata> => new Promise((resolve, reject) => {
export const getMetadataFromUrl = (imageUrl: string, options = {} as GetImageMetadataOptions): Promise<Partial<ImageMetadata>> => 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;
});

+ 4
- 2
packages/image-utils/src/index.ts View File

@@ -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<ImageMetadata>;
}

if (typeof window !== 'undefined') {


+ 3
- 3
packages/image-utils/src/server.ts View File

@@ -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<Partial<ImageMetadata>> => {
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<ImageMetadata> => doGetImageMetadata(imageUrl, options);
export const getMetadataFromUrl = (imageUrl: string, options?: GetImageMetadataOptions): Promise<Partial<ImageMetadata>> => doGetImageMetadata(imageUrl, options);

export const getMetadataFromBuffer = (buffer: Buffer, options?: GetImageMetadataOptions): Promise<ImageMetadata> => doGetImageMetadata(buffer, options);
export const getMetadataFromBuffer = (buffer: Buffer, options?: GetImageMetadataOptions): Promise<Partial<ImageMetadata>> => doGetImageMetadata(buffer, options);

+ 4
- 4
packages/text-utils/src/index.ts View File

@@ -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<TextMetadata> => {
const lineNormalizedContents = contents.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
@@ -65,7 +65,7 @@ export const getTextMetadata = (contents: string, filename?: string): Promise<Te
scheme: value.aliasOf,
schemeTitle: value.title,
linesOfCode: countLinesOfCode(lines, value.aliasOf),
}
};
}

return {
@@ -81,7 +81,7 @@ export const getTextMetadata = (contents: string, filename?: string): Promise<Te
{
contents,
lineCount,
} as TextMetadata
} as TextMetadata,
);

if (typeof metadata.scheme !== 'string') {
@@ -90,4 +90,4 @@ export const getTextMetadata = (contents: string, filename?: string): Promise<Te
}

return Promise.resolve(metadata);
}
};

+ 25
- 0
packages/video-utils/src/client.ts View File

@@ -0,0 +1,25 @@
import {VideoMetadata} from './common';

export const getMetadataFromUrl = async (videoUrl: string) => new Promise<Partial<VideoMetadata>>((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);
});

+ 5
- 0
packages/video-utils/src/common.ts View File

@@ -0,0 +1,5 @@
export interface VideoMetadata {
width?: number;
height?: number;
duration?: number;
}

+ 12
- 32
packages/video-utils/src/index.ts View File

@@ -1,35 +1,15 @@
export interface VideoFileMetadata {
width?: number;
height?: number;
duration?: number;
}

export const getVideoMetadata = (videoUrl?: string) => new Promise<VideoFileMetadata>((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';

+ 1
- 0
packages/web-kitchensink-reactnext/src/packages/react-wavesurfer/SpectrogramCanvas/index.tsx View File

@@ -16,6 +16,7 @@ export const SpectrogramCanvas = React.forwardRef<SpectrogramCanvasDerivedElemen
className,
children,
controls,
// TODO organize props for color
waveColor,
progressColor,
cursorColor,


+ 11
- 7
packages/web-kitchensink-reactnext/src/utils/blob.ts View File

@@ -1,8 +1,8 @@
import * as mimeTypes from 'mime-types';
import {getTextMetadata, TextMetadata} from '@modal-soft/text-utils';
import {getMetadataFromUrl, ImageMetadata} from '@modal-soft/image-utils';
import {getAudioMetadata, AudioMetadata} from '@modal-soft/audio-utils';
import {getVideoMetadata, VideoFileMetadata} from '@modal-soft/video-utils';
import {getMetadataFromUrl as getImageMetadataFromUrl, ImageMetadata} from '@modal-soft/image-utils';
import {getMetadataFromUrl as getAudioMetadataFromUrl, AudioMetadata} from '@modal-soft/audio-utils';
import {getMetadataFromUrl as getVideoMetadataFromUrl, VideoMetadata} from '@modal-soft/video-utils';

const MIME_TYPE_DESCRIPTIONS = {
'image/gif': 'GIF Image',
@@ -164,7 +164,7 @@ export interface ImageFile extends FileWithResolvedContentType {

export const augmentImageFile = async <T extends Partial<FileWithDataUrl>>(file: T): Promise<ImageFile> => {
const fileMutable = file as unknown as Record<string, ImageMetadata>;
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 <T extends Partial<FileWithDataUrl>>(file: T): Promise<AudioFile> => {
const fileMutable = file as unknown as Record<string, AudioMetadata>;
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 <T extends Partial<FileWithDataUrl>>(file

export interface VideoFile extends FileWithResolvedContentType {
resolvedType: ContentType.VIDEO;
metadata?: VideoFileMetadata;
metadata?: VideoMetadata;
}

export const augmentVideoFile = async <T extends Partial<FileWithDataUrl>>(file: T): Promise<VideoFile> => {
const fileMutable = file as unknown as Record<string, AudioMetadata>;
fileMutable.metadata = await getVideoMetadata(file.url);
fileMutable.metadata = await getVideoMetadataFromUrl(file.url);
return fileMutable as unknown as VideoFile;
};

Loading…
Cancel
Save