refactor: Apply PR #6112 review feedback for Media Assets feature

- Move composables to platform/assets directory structure
- Extract interface-based abstraction (IAssetsProvider) for cloud/internal implementations
- Move constants to module scope to avoid re-initialization
- Extract helper functions (truncateFilename, assetMappers) for reusability
- Rename getMediaTypeFromFilename to return singular form (image/video/audio)
- Add deprecated plural version for backward compatibility
- Add comprehensive test coverage for new utility functions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jin Yi
2025-10-20 17:40:47 +09:00
parent 2398e26712
commit dcd6bb6519
9 changed files with 368 additions and 131 deletions

View File

@@ -475,50 +475,92 @@ export function formatDuration(milliseconds: number): string {
return parts.join(' ')
}
// Module scope constants to avoid re-initialization on every call
const IMAGE_EXTENSIONS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']
const VIDEO_EXTENSIONS = ['mp4', 'webm', 'mov', 'avi']
const AUDIO_EXTENSIONS = ['mp3', 'wav', 'ogg', 'flac']
const THREE_D_EXTENSIONS = ['obj', 'fbx', 'gltf', 'glb']
/**
* Determines the media type from a filename's extension
* @param filename The filename to analyze
* @returns The media type: 'images', 'videos', 'audios', '3D' for gallery compatibility
* Truncates a filename while preserving the extension
* @param filename The filename to truncate
* @param maxLength Maximum length for the filename without extension
* @returns Truncated filename with extension preserved
*/
export function getMediaTypeFromFilename(filename: string): string {
if (!filename) return 'images'
const ext = filename.split('.').pop()?.toLowerCase()
if (!ext) return 'images'
export function truncateFilename(
filename: string,
maxLength: number = 20
): string {
if (!filename || filename.length <= maxLength) {
return filename
}
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']
const videoExts = ['mp4', 'webm', 'mov', 'avi']
const audioExts = ['mp3', 'wav', 'ogg', 'flac']
const threeDExts = ['obj', 'fbx', 'gltf', 'glb']
const lastDotIndex = filename.lastIndexOf('.')
const nameWithoutExt =
lastDotIndex > -1 ? filename.substring(0, lastDotIndex) : filename
const extension = lastDotIndex > -1 ? filename.substring(lastDotIndex) : ''
if (imageExts.includes(ext)) return 'images'
if (videoExts.includes(ext)) return 'videos'
if (audioExts.includes(ext)) return 'audios'
if (threeDExts.includes(ext)) return '3D'
// If the name without extension is short enough, return as is
if (nameWithoutExt.length <= maxLength) {
return filename
}
return 'images'
// Calculate how to split the truncation
const halfLength = Math.floor((maxLength - 3) / 2) // -3 for '...'
const start = nameWithoutExt.substring(0, halfLength)
const end = nameWithoutExt.substring(nameWithoutExt.length - halfLength)
return `${start}...${end}${extension}`
}
/**
* Determines the media kind from a filename's extension
* Determines the media type from a filename's extension (singular form)
* @param filename The filename to analyze
* @returns The media kind: 'image', 'video', 'audio', or '3D'
* @returns The media type: 'image', 'video', 'audio', or '3D'
*/
export function getMediaKindFromFilename(
export function getMediaTypeFromFilename(
filename: string
): 'image' | 'video' | 'audio' | '3D' {
if (!filename) return 'image'
const ext = filename.split('.').pop()?.toLowerCase()
if (!ext) return 'image'
const imageExts = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']
const videoExts = ['mp4', 'webm', 'mov', 'avi']
const audioExts = ['mp3', 'wav', 'ogg', 'flac']
const threeDExts = ['obj', 'fbx', 'gltf', 'glb']
if (imageExts.includes(ext)) return 'image'
if (videoExts.includes(ext)) return 'video'
if (audioExts.includes(ext)) return 'audio'
if (threeDExts.includes(ext)) return '3D'
if (IMAGE_EXTENSIONS.includes(ext)) return 'image'
if (VIDEO_EXTENSIONS.includes(ext)) return 'video'
if (AUDIO_EXTENSIONS.includes(ext)) return 'audio'
if (THREE_D_EXTENSIONS.includes(ext)) return '3D'
return 'image'
}
/**
* @deprecated Use getMediaTypeFromFilename instead - returns plural form for legacy compatibility
* @param filename The filename to analyze
* @returns The media type in plural form: 'images', 'videos', 'audios', '3D'
*/
export function getMediaTypeFromFilenamePlural(filename: string): string {
const type = getMediaTypeFromFilename(filename)
switch (type) {
case 'image':
return 'images'
case 'video':
return 'videos'
case 'audio':
return 'audios'
case '3D':
return '3D'
default:
return 'images'
}
}
/**
* @deprecated Use getMediaTypeFromFilename instead - kept for backward compatibility
* @param filename The filename to analyze
* @returns The media kind: 'image', 'video', 'audio', or '3D'
*/
export function getMediaKindFromFilename(
filename: string
): 'image' | 'video' | 'audio' | '3D' {
return getMediaTypeFromFilename(filename)
}