Add chat hiding mentions follow counts waveform and post fixes
This commit is contained in:
@@ -13,6 +13,8 @@ describe('post media response util', () => {
|
||||
expect(media.mediaType).toBe(PostType.AUDIO);
|
||||
expect(media.durationSeconds).toBe(42);
|
||||
expect(media.waveformPeaks).toHaveLength(100);
|
||||
expect(media.waveformPeaksPreview).toHaveLength(100);
|
||||
expect(media.waveformPeaksDetailed.length).toBeGreaterThanOrEqual(100);
|
||||
expect(media.waveformPeaks.every((value) => Number.isInteger(value))).toBe(true);
|
||||
expect(media.waveformPeaks.every((value) => value >= 0 && value <= 100)).toBe(true);
|
||||
});
|
||||
@@ -26,5 +28,7 @@ describe('post media response util', () => {
|
||||
|
||||
expect(media.mediaType).toBe(PostType.IMAGE);
|
||||
expect(media.waveformPeaks).toEqual([]);
|
||||
expect(media.waveformPeaksPreview).toEqual([]);
|
||||
expect(media.waveformPeaksDetailed).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PostType } from '../enums/post-type.enum';
|
||||
import { normalizeWaveformPeaks } from './waveform.util';
|
||||
import { buildWaveformPeakSet } from './waveform.util';
|
||||
|
||||
type VariantSet = {
|
||||
originalUrl?: string;
|
||||
@@ -19,6 +19,8 @@ type PostMediaInput = {
|
||||
thumbnailUrl?: string;
|
||||
thumbnailVariants?: VariantSet;
|
||||
waveformPeaks?: number[];
|
||||
waveformPeaksPreview?: number[];
|
||||
waveformPeaksDetailed?: number[];
|
||||
durationSeconds?: number | null;
|
||||
};
|
||||
|
||||
@@ -88,8 +90,17 @@ export const buildPostMediaResponse = (post: PostMediaInput) => {
|
||||
: mediaType === PostType.VIDEO || mediaType === PostType.AUDIO
|
||||
? thumbnailUrl
|
||||
: '';
|
||||
const waveformPeaks =
|
||||
mediaType === PostType.AUDIO ? normalizeWaveformPeaks(post.waveformPeaks ?? []) : [];
|
||||
const waveformSet =
|
||||
mediaType === PostType.AUDIO
|
||||
? buildWaveformPeakSet(
|
||||
post.waveformPeaksDetailed?.length
|
||||
? post.waveformPeaksDetailed
|
||||
: post.waveformPeaksPreview?.length
|
||||
? post.waveformPeaksPreview
|
||||
: post.waveformPeaks,
|
||||
post.durationSeconds,
|
||||
)
|
||||
: { waveformPeaks: [], waveformPeaksPreview: [], waveformPeaksDetailed: [] };
|
||||
|
||||
return {
|
||||
mediaType,
|
||||
@@ -102,7 +113,9 @@ export const buildPostMediaResponse = (post: PostMediaInput) => {
|
||||
audioUrl: post.audioUrl ?? '',
|
||||
images,
|
||||
durationSeconds: post.durationSeconds ?? null,
|
||||
waveformPeaks,
|
||||
waveformPeaks: waveformSet.waveformPeaks,
|
||||
waveformPeaksPreview: waveformSet.waveformPeaksPreview,
|
||||
waveformPeaksDetailed: waveformSet.waveformPeaksDetailed,
|
||||
isPlayable: mediaType === PostType.VIDEO ? !!preferredPlaybackUrl : mediaType === PostType.AUDIO ? !!post.audioUrl : false,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import {
|
||||
buildWaveformPeakSet,
|
||||
generateWaveformPeakSetFromBuffer,
|
||||
generateWaveformPeaksFromBuffer,
|
||||
generateWaveformPeaksFromSeed,
|
||||
getDetailedWaveformPeakCount,
|
||||
normalizeWaveformPeaks,
|
||||
} from './waveform.util';
|
||||
|
||||
@@ -109,4 +112,29 @@ describe('waveform util', () => {
|
||||
expect(peaks.slice(0, 40).some((value) => value < 60)).toBe(true);
|
||||
expect(peaks.slice(60).some((value) => value > 80)).toBe(true);
|
||||
});
|
||||
|
||||
it('generates detailed peaks for long audio without changing preview size', () => {
|
||||
const detailedCount = getDetailedWaveformPeakCount(180);
|
||||
const waveformSet = buildWaveformPeakSet(
|
||||
Array.from({ length: 1400 }, (_, index) => (index % 17) + 1),
|
||||
180,
|
||||
);
|
||||
|
||||
expect(detailedCount).toBeGreaterThanOrEqual(600);
|
||||
expectDisplaySafeWaveform(waveformSet.waveformPeaksPreview, 100);
|
||||
expectDisplaySafeWaveform(waveformSet.waveformPeaks, 100);
|
||||
expect(waveformSet.waveformPeaksDetailed.length).toBeGreaterThanOrEqual(600);
|
||||
expect(waveformSet.waveformPeaksDetailed.length).toBeLessThanOrEqual(1200);
|
||||
expect(waveformSet.waveformPeaksDetailed.every((value) => value >= 0 && value <= 100)).toBe(true);
|
||||
});
|
||||
|
||||
it('generates preview and detailed peak sets from buffers', () => {
|
||||
const wavBuffer = createPcmWavBuffer((frame) => 0.15 + (frame / 7999) * 0.7);
|
||||
const waveformSet = generateWaveformPeakSetFromBuffer(wavBuffer, 240);
|
||||
|
||||
expectDisplaySafeWaveform(waveformSet.waveformPeaksPreview, 100);
|
||||
expect(waveformSet.waveformPeaksDetailed.length).toBeGreaterThanOrEqual(600);
|
||||
expect(waveformSet.waveformPeaksDetailed.length).toBeLessThanOrEqual(1200);
|
||||
expect(new Set(waveformSet.waveformPeaksDetailed).size).toBeGreaterThan(8);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
export const DEFAULT_WAVEFORM_PEAK_COUNT = 100;
|
||||
export const DEFAULT_DETAILED_WAVEFORM_PEAK_COUNT = 800;
|
||||
const MIN_DISPLAY_WAVEFORM_PEAKS = 80;
|
||||
const MAX_DISPLAY_WAVEFORM_PEAKS = 120;
|
||||
const MIN_DETAILED_WAVEFORM_PEAKS = 100;
|
||||
const LONG_AUDIO_MIN_DETAILED_WAVEFORM_PEAKS = 600;
|
||||
const MAX_DETAILED_WAVEFORM_PEAKS = 1200;
|
||||
|
||||
export type WaveformPeakSet = {
|
||||
waveformPeaks: number[];
|
||||
waveformPeaksPreview: number[];
|
||||
waveformPeaksDetailed: number[];
|
||||
};
|
||||
|
||||
export const getDefaultWaveformPeakCount = (): number => {
|
||||
const configured = Number(process.env.AUDIO_WAVEFORM_PEAKS);
|
||||
@@ -17,6 +27,19 @@ export const getDefaultWaveformPeakCount = (): number => {
|
||||
|
||||
const clampPeak = (value: number): number => Math.max(0, Math.min(100, Math.round(value)));
|
||||
|
||||
const clampSampleCount = (
|
||||
targetCount: number,
|
||||
fallback: number,
|
||||
min: number,
|
||||
max: number,
|
||||
): number => {
|
||||
if (!Number.isInteger(targetCount) || targetCount < min || targetCount > max) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return targetCount;
|
||||
};
|
||||
|
||||
const fallbackWaveform = (samples: number): number[] =>
|
||||
Array.from({ length: samples }, (_, index) => {
|
||||
const wave = Math.sin((index / Math.max(1, samples - 1)) * Math.PI * 6);
|
||||
@@ -154,12 +177,12 @@ export const normalizeWaveformPeaks = (
|
||||
input: unknown[] | undefined,
|
||||
targetCount = getDefaultWaveformPeakCount(),
|
||||
): number[] => {
|
||||
const samples =
|
||||
Number.isInteger(targetCount) &&
|
||||
targetCount >= MIN_DISPLAY_WAVEFORM_PEAKS &&
|
||||
targetCount <= MAX_DISPLAY_WAVEFORM_PEAKS
|
||||
? targetCount
|
||||
: DEFAULT_WAVEFORM_PEAK_COUNT;
|
||||
const samples = clampSampleCount(
|
||||
targetCount,
|
||||
DEFAULT_WAVEFORM_PEAK_COUNT,
|
||||
MIN_DISPLAY_WAVEFORM_PEAKS,
|
||||
MAX_DETAILED_WAVEFORM_PEAKS,
|
||||
);
|
||||
|
||||
if (!input?.length) {
|
||||
return fallbackWaveform(samples);
|
||||
@@ -255,3 +278,61 @@ export const generateWaveformPeaksFromSeed = (
|
||||
|
||||
return normalizeWaveformPeaks(peaks, samples);
|
||||
};
|
||||
|
||||
export const getDetailedWaveformPeakCount = (durationSeconds?: number | null): number => {
|
||||
if (!Number.isFinite(durationSeconds) || !durationSeconds || durationSeconds <= 0) {
|
||||
return DEFAULT_DETAILED_WAVEFORM_PEAK_COUNT;
|
||||
}
|
||||
|
||||
const byQuarterSecond = Math.ceil(durationSeconds / 0.25);
|
||||
const minimum = durationSeconds >= 120 ? LONG_AUDIO_MIN_DETAILED_WAVEFORM_PEAKS : MIN_DETAILED_WAVEFORM_PEAKS;
|
||||
return Math.max(minimum, Math.min(MAX_DETAILED_WAVEFORM_PEAKS, byQuarterSecond));
|
||||
};
|
||||
|
||||
export const buildWaveformPeakSet = (
|
||||
input: unknown[] | undefined,
|
||||
durationSeconds?: number | null,
|
||||
): WaveformPeakSet => {
|
||||
const preview = normalizeWaveformPeaks(input, getDefaultWaveformPeakCount());
|
||||
const detailed = normalizeWaveformPeaks(
|
||||
input?.length ? input : preview,
|
||||
getDetailedWaveformPeakCount(durationSeconds),
|
||||
);
|
||||
|
||||
return {
|
||||
waveformPeaks: preview,
|
||||
waveformPeaksPreview: preview,
|
||||
waveformPeaksDetailed: detailed,
|
||||
};
|
||||
};
|
||||
|
||||
export const generateWaveformPeakSetFromBuffer = (
|
||||
buffer: Buffer,
|
||||
durationSeconds?: number | null,
|
||||
): WaveformPeakSet => {
|
||||
const detailed = generateWaveformPeaksFromBuffer(
|
||||
buffer,
|
||||
getDetailedWaveformPeakCount(durationSeconds),
|
||||
);
|
||||
const preview = normalizeWaveformPeaks(detailed, getDefaultWaveformPeakCount());
|
||||
|
||||
return {
|
||||
waveformPeaks: preview,
|
||||
waveformPeaksPreview: preview,
|
||||
waveformPeaksDetailed: detailed,
|
||||
};
|
||||
};
|
||||
|
||||
export const generateWaveformPeakSetFromSeed = (
|
||||
seed: string,
|
||||
durationSeconds?: number | null,
|
||||
): WaveformPeakSet => {
|
||||
const detailed = generateWaveformPeaksFromSeed(seed, getDetailedWaveformPeakCount(durationSeconds));
|
||||
const preview = normalizeWaveformPeaks(detailed, getDefaultWaveformPeakCount());
|
||||
|
||||
return {
|
||||
waveformPeaks: preview,
|
||||
waveformPeaksPreview: preview,
|
||||
waveformPeaksDetailed: detailed,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user