add moodules

This commit is contained in:
2026-04-17 23:42:24 +01:00
parent 532458ecfa
commit a7fbb2c466
54 changed files with 3074 additions and 74 deletions
@@ -0,0 +1,56 @@
import { Injectable, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { Client } from 'minio';
import { randomUUID } from 'crypto';
@Injectable()
export class MinioService implements OnModuleInit {
private client: Client | null = null;
private bucket: string;
constructor(private readonly config: ConfigService) {
this.bucket = this.config.get<string>('minio.bucket', 'tvone');
}
async onModuleInit() {
const accessKey = this.config.get<string>('minio.accessKey', '');
const secretKey = this.config.get<string>('minio.secretKey', '');
if (!accessKey || !secretKey) {
return;
}
this.client = new Client({
endPoint: this.config.get<string>('minio.endpoint', 'localhost'),
port: this.config.get<number>('minio.port', 9000),
useSSL: this.config.get<boolean>('minio.useSsl', false),
accessKey,
secretKey,
});
const exists = await this.client.bucketExists(this.bucket).catch(() => false);
if (!exists) {
await this.client.makeBucket(this.bucket, '');
}
}
isConfigured(): boolean {
return this.client !== null;
}
async putObject(
objectName: string,
buffer: Buffer,
contentType: string,
): Promise<string> {
if (!this.client) {
throw new Error('MinIO is not configured (MINIO_ACCESS_KEY / MINIO_SECRET_KEY)');
}
await this.client.putObject(this.bucket, objectName, buffer, buffer.length, {
'Content-Type': contentType,
});
return objectName;
}
buildOriginalsKey(prefix: string, originalName: string): string {
const safe = originalName.replace(/[^a-zA-Z0-9._-]/g, '_');
return `${prefix}/${randomUUID()}-${safe}`;
}
}
@@ -0,0 +1,10 @@
import { Global, Module } from '@nestjs/common';
import { MinioService } from './minio.service';
import { ThumborUrlService } from './thumbor-url.service';
@Global()
@Module({
providers: [MinioService, ThumborUrlService],
exports: [MinioService, ThumborUrlService],
})
export class StorageModule {}
@@ -0,0 +1,25 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
/**
* Builds Thumbor-style URLs for the CDN/Varnish layer in front of Thumbor.
* Example path segment: /800x0/smart/originals/articles/abc.jpg
*/
@Injectable()
export class ThumborUrlService {
constructor(private readonly config: ConfigService) {}
imageUrl(fileKey: string, options?: { width?: number; height?: number; smart?: boolean }) {
const base = this.config.get<string>('thumbor.publicBaseUrl', '');
if (!base) {
return { path: `/${fileKey}`, full: null as string | null };
}
const w = options?.width ?? 0;
const h = options?.height ?? 0;
const smart = options?.smart !== false ? 'smart' : 'fit-in';
const dims = `${w}x${h}`;
const path = `/${dims}/${smart}/${fileKey}`;
const normalizedBase = base.endsWith('/') ? base.slice(0, -1) : base;
return { path, full: `${normalizedBase}${path}` };
}
}