diff --git a/web/src/utils/cameraUtil.ts b/web/src/utils/cameraUtil.ts index ae7b8001a..caebd7ff0 100644 --- a/web/src/utils/cameraUtil.ts +++ b/web/src/utils/cameraUtil.ts @@ -1,39 +1,4 @@ -// ==================== Camera Name Processing ==================== - -/** - * Generates a fixed-length hash from a camera name for use as a valid camera identifier. - * Works safely with Unicode input while outputting Latin-only identifiers. - * - * @param name - The original camera name/display name - * @returns A valid camera identifier (lowercase, alphanumeric, max 8 chars) - */ -export function generateFixedHash(name: string): string { - // Safely encode Unicode as UTF-8 bytes - const utf8Bytes = new TextEncoder().encode(name); - - // Convert to base64 manually - let binary = ""; - for (const byte of utf8Bytes) { - binary += String.fromCharCode(byte); - } - const base64 = btoa(binary); - - // Strip out non-alphanumeric characters and truncate - const cleanHash = base64.replace(/[^a-zA-Z0-9]/g, "").substring(0, 8); - - return `cam_${cleanHash.toLowerCase()}`; -} - -/** - * Checks if a string is a valid camera name identifier. - * Valid camera names contain only ASCII letters, numbers, underscores, and hyphens. - * - * @param name - The camera name to validate - * @returns True if the name is valid, false otherwise - */ -export function isValidCameraName(name: string): boolean { - return /^[a-zA-Z0-9_-]+$/.test(name); -} +import { generateFixedHash, isValidId } from "./stringUtil"; /** * Processes a user-entered camera name and returns both the final camera name @@ -48,7 +13,7 @@ export function processCameraName(userInput: string): { } { const normalizedInput = userInput.replace(/\s+/g, "_").toLowerCase(); - if (isValidCameraName(normalizedInput)) { + if (isValidId(normalizedInput)) { return { finalCameraName: normalizedInput, friendlyName: userInput.includes(" ") ? userInput : undefined, @@ -56,7 +21,7 @@ export function processCameraName(userInput: string): { } return { - finalCameraName: generateFixedHash(userInput), + finalCameraName: generateFixedHash(userInput, "cam"), friendlyName: userInput, }; } diff --git a/web/src/utils/stringUtil.ts b/web/src/utils/stringUtil.ts index 57f142119..716f922fe 100644 --- a/web/src/utils/stringUtil.ts +++ b/web/src/utils/stringUtil.ts @@ -9,3 +9,39 @@ export const capitalizeAll = (text: string): string => { .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "); }; + +/** + * Generates a fixed-length hash from a camera name for use as a valid camera identifier. + * Works safely with Unicode input while outputting Latin-only identifiers. + * + * @param name - The original camera name/display name + * @param prefix - Optional prefix for the identifier + * @returns A valid camera identifier (lowercase, alphanumeric, max 8 chars) + */ +export function generateFixedHash(name: string, prefix: string = "id"): string { + // Safely encode Unicode as UTF-8 bytes + const utf8Bytes = new TextEncoder().encode(name); + + // Convert to base64 manually + let binary = ""; + for (const byte of utf8Bytes) { + binary += String.fromCharCode(byte); + } + const base64 = btoa(binary); + + // Strip out non-alphanumeric characters and truncate + const cleanHash = base64.replace(/[^a-zA-Z0-9]/g, "").substring(0, 8); + + return `${prefix}_${cleanHash.toLowerCase()}`; +} + +/** + * Checks if a string is a valid camera name identifier. + * Valid camera names contain only ASCII letters, numbers, underscores, and hyphens. + * + * @param name - The camera name to validate + * @returns True if the name is valid, false otherwise + */ +export function isValidId(name: string): boolean { + return /^[a-zA-Z0-9_-]+$/.test(name); +}