feat: Enhance user color and banner management
- Updated `useUserColor` hook to support fetching and embedding user color from avatar metadata with authentication. - Introduced `useUserBanner` hook for managing user banners stored in avatar metadata, including fetching and embedding functionality. - Added `fetchAndExtractMetadata` utility to retrieve both color and banner from images. - Implemented `CustomStatusDialog` component for users to set and clear custom status messages. - Modified `SettingsTab` to include custom status functionality and improved user experience. - Enhanced image metadata utilities to support banner extraction and embedding in PNG format. - Updated sidebar settings to handle user profile changes more gracefully.
This commit is contained in:
@@ -1,16 +1,28 @@
|
||||
/**
|
||||
* Unified image metadata utilities for embedding/extracting user color
|
||||
* Unified image metadata utilities for embedding/extracting user color and banner
|
||||
* Supports PNG, WebP, JPEG, and GIF formats
|
||||
*/
|
||||
|
||||
/* eslint-disable no-plusplus */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { embedColorInPNG, extractColorFromPNG, removeColorFromPNG } from './pngMetadata';
|
||||
import {
|
||||
embedColorInPNG,
|
||||
extractColorFromPNG,
|
||||
removeColorFromPNG,
|
||||
embedMetadataInPNG,
|
||||
extractMetadataFromPNG,
|
||||
extractBannerFromPNG,
|
||||
} from './pngMetadata';
|
||||
import { embedColorInWebP, extractColorFromWebP, removeColorFromWebP } from './webpMetadata';
|
||||
import { embedColorInJPEG, extractColorFromJPEG, removeColorFromJPEG } from './jpegMetadata';
|
||||
import { embedColorInGIF, extractColorFromGIF, removeColorFromGIF } from './gifMetadata';
|
||||
|
||||
export type ImageMetadata = {
|
||||
color?: string;
|
||||
banner?: string;
|
||||
};
|
||||
|
||||
/** PNG signature bytes */
|
||||
const PNG_SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];
|
||||
|
||||
@@ -114,6 +126,48 @@ export function extractColorFromImage(imageData: ArrayBuffer | Uint8Array): stri
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract paarrot banner URL from image data (any supported format)
|
||||
* @param imageData - Raw image data as ArrayBuffer or Uint8Array
|
||||
* @returns The banner MXC URL if found, or undefined
|
||||
*/
|
||||
export function extractBannerFromImage(imageData: ArrayBuffer | Uint8Array): string | undefined {
|
||||
const format = detectImageFormat(imageData);
|
||||
|
||||
switch (format) {
|
||||
case 'png':
|
||||
return extractBannerFromPNG(imageData);
|
||||
// For now, only PNG supports banner. Add other formats later
|
||||
default:
|
||||
console.warn('[extractBannerFromImage] Format not yet supported for banner');
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all paarrot metadata from image data (any supported format)
|
||||
* @param imageData - Raw image data as ArrayBuffer or Uint8Array
|
||||
* @returns Object with color and banner if found
|
||||
*/
|
||||
export function extractMetadataFromImage(imageData: ArrayBuffer | Uint8Array): ImageMetadata {
|
||||
const format = detectImageFormat(imageData);
|
||||
|
||||
switch (format) {
|
||||
case 'png':
|
||||
return extractMetadataFromPNG(imageData);
|
||||
// For other formats, extract color only for now
|
||||
case 'webp':
|
||||
case 'jpeg':
|
||||
case 'gif': {
|
||||
const color = extractColorFromImage(imageData);
|
||||
return color ? { color } : {};
|
||||
}
|
||||
default:
|
||||
console.warn('[extractMetadataFromImage] Unknown image format');
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed paarrot color into image data (PNG, WebP, JPEG, or GIF)
|
||||
* @param imageData - Raw image data as ArrayBuffer or Uint8Array
|
||||
@@ -138,6 +192,36 @@ export function embedColorInImage(imageData: ArrayBuffer | Uint8Array, color: st
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embed paarrot metadata (color and/or banner) into image data
|
||||
* Preserves existing metadata that is not being updated
|
||||
* @param imageData - Raw image data as ArrayBuffer or Uint8Array
|
||||
* @param metadata - Object with color and/or banner to embed
|
||||
* @returns New image data with embedded metadata, or null if not a supported format
|
||||
*/
|
||||
export function embedMetadataInImage(
|
||||
imageData: ArrayBuffer | Uint8Array,
|
||||
metadata: ImageMetadata
|
||||
): Uint8Array | null {
|
||||
const format = detectImageFormat(imageData);
|
||||
|
||||
switch (format) {
|
||||
case 'png':
|
||||
return embedMetadataInPNG(imageData, metadata);
|
||||
// For other formats, only embed color for now
|
||||
case 'webp':
|
||||
case 'jpeg':
|
||||
case 'gif':
|
||||
if (metadata.color) {
|
||||
return embedColorInImage(imageData, metadata.color);
|
||||
}
|
||||
return null;
|
||||
default:
|
||||
console.warn('[embedMetadataInImage] Unknown image format, cannot embed metadata');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove paarrot color from image data (PNG, WebP, JPEG, or GIF)
|
||||
* @param imageData - Raw image data as ArrayBuffer or Uint8Array
|
||||
@@ -198,13 +282,17 @@ export function getExtension(format: ImageFormat): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and extract color from an image URL (supports PNG and WebP)
|
||||
* Fetch and extract color from an image URL (supports all formats)
|
||||
* @param url - HTTP URL to fetch the image from
|
||||
* @param accessToken - Optional access token for authenticated media
|
||||
* @returns The color string if found, or undefined
|
||||
*/
|
||||
export async function fetchAndExtractColor(url: string): Promise<string | undefined> {
|
||||
export async function fetchAndExtractColor(url: string, accessToken?: string | null): Promise<string | undefined> {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,
|
||||
});
|
||||
if (!response.ok) return undefined;
|
||||
|
||||
const data = await response.arrayBuffer();
|
||||
@@ -213,3 +301,24 @@ export async function fetchAndExtractColor(url: string): Promise<string | undefi
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and extract all metadata from an image URL
|
||||
* @param url - HTTP URL to fetch the image from
|
||||
* @param accessToken - Optional access token for authenticated media
|
||||
* @returns Object with color and banner if found
|
||||
*/
|
||||
export async function fetchAndExtractMetadata(url: string, accessToken?: string | null): Promise<ImageMetadata> {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'GET',
|
||||
headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,
|
||||
});
|
||||
if (!response.ok) return {};
|
||||
|
||||
const data = await response.arrayBuffer();
|
||||
return extractMetadataFromImage(data);
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user