104 lines
3.4 KiB
TypeScript
104 lines
3.4 KiB
TypeScript
import { faker } from '@faker-js/faker';
|
|
|
|
/**
|
|
* Core Domain Service: MediaGenerationService
|
|
*
|
|
* Encapsulates business logic for generating media assets (SVGs) using Faker.
|
|
* Ensures deterministic results by seeding Faker with entity IDs.
|
|
*/
|
|
export class MediaGenerationService {
|
|
/**
|
|
* Generates a deterministic logo URL for a team
|
|
* Uses a real placeholder image service for high-quality racing logos.
|
|
*/
|
|
generateTeamLogo(teamId: string): string {
|
|
faker.seed(this.hashCode(teamId));
|
|
return `https://picsum.photos/seed/${teamId}/200/200`;
|
|
}
|
|
|
|
/**
|
|
* Generates a deterministic logo URL for a league
|
|
* Uses a real placeholder image service for high-quality league logos.
|
|
*/
|
|
generateLeagueLogo(leagueId: string): string {
|
|
faker.seed(this.hashCode(leagueId));
|
|
return `https://picsum.photos/seed/l-${leagueId}/200/200`;
|
|
}
|
|
|
|
/**
|
|
* Generates a deterministic avatar URL for a driver
|
|
* Uses a real placeholder image service for high-quality driver avatars.
|
|
*/
|
|
generateDriverAvatar(driverId: string): string {
|
|
faker.seed(this.hashCode(driverId));
|
|
return `https://i.pravatar.cc/150?u=${driverId}`;
|
|
}
|
|
|
|
/**
|
|
* Generates a deterministic cover URL for a league
|
|
* Uses a real placeholder image service for high-quality league covers.
|
|
*/
|
|
generateLeagueCover(leagueId: string): string {
|
|
faker.seed(this.hashCode(leagueId));
|
|
return `https://picsum.photos/seed/c-${leagueId}/800/200`;
|
|
}
|
|
|
|
/**
|
|
* Generates a simple PNG placeholder (base64 encoded)
|
|
* In production, this would serve actual PNG files from public assets
|
|
*/
|
|
generateDefaultPNG(variant: string): Buffer {
|
|
// For now, generate a simple colored square as PNG placeholder
|
|
// In production, this would read actual PNG files
|
|
faker.seed(this.hashCode(variant));
|
|
|
|
const color = faker.color.rgb({ format: 'hex' });
|
|
|
|
// Parse the hex color
|
|
const r = parseInt(color.slice(1, 3), 16);
|
|
const g = parseInt(color.slice(3, 5), 16);
|
|
const b = parseInt(color.slice(5, 7), 16);
|
|
|
|
// Create a minimal valid PNG (1x1 pixel) with the variant color
|
|
// This is a very basic PNG - in production you'd serve real files
|
|
// PNG header and minimal data for a 1x1 RGB pixel
|
|
const pngHeader = Buffer.from([
|
|
// PNG signature
|
|
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
|
|
// IHDR chunk (13 bytes)
|
|
0x00, 0x00, 0x00, 0x0D, // Length: 13
|
|
0x49, 0x48, 0x44, 0x52, // Type: IHDR
|
|
0x00, 0x00, 0x00, 0x01, // Width: 1
|
|
0x00, 0x00, 0x00, 0x01, // Height: 1
|
|
0x08, // Bit depth: 8
|
|
0x02, // Color type: RGB
|
|
0x00, // Compression method
|
|
0x00, // Filter method
|
|
0x00, // Interlace method
|
|
0x00, 0x00, 0x00, 0x00, // CRC (placeholder, simplified)
|
|
// IDAT chunk (image data)
|
|
0x00, 0x00, 0x00, 0x07, // Length: 7
|
|
0x49, 0x44, 0x41, 0x54, // Type: IDAT
|
|
0x08, 0x1D, // Zlib header
|
|
0x01, // Deflate block header
|
|
r, g, b, // RGB pixel data
|
|
0x00, 0x00, 0x00, 0x00, // CRC (placeholder)
|
|
// IEND chunk
|
|
0x00, 0x00, 0x00, 0x00, // Length: 0
|
|
0x49, 0x45, 0x4E, 0x44, // Type: IEND
|
|
0xAE, 0x42, 0x60, 0x82 // CRC (placeholder)
|
|
]);
|
|
|
|
return pngHeader;
|
|
}
|
|
|
|
private hashCode(str: string): number {
|
|
let hash = 0;
|
|
for (let i = 0; i < str.length; i++) {
|
|
const char = str.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash = hash & hash;
|
|
}
|
|
return Math.abs(hash);
|
|
}
|
|
} |