Files
evilspins/server/utils/fileScanner.ts
valere b9a3d0184f
All checks were successful
Deploy App / build (push) Successful in 10s
Deploy App / deploy (push) Successful in 11s
yeah
2026-02-02 21:00:28 +01:00

120 lines
3.4 KiB
TypeScript

import { readdir, readFile } from 'node:fs/promises'
import { join, extname, basename } from 'node:path'
import { createHash } from 'node:crypto'
import { slugify } from './slugify'
import { getCardFromDate } from './getCardFromDate'
import type { Card } from '@/types/types'
const listAudioExts = ['.mp3', '.opus', 'flac']
const listImageExts = ['.jpg', '.jpeg', '.webp']
export async function scanMusicFolder(folderPath: string): Promise<Card[]> {
try {
const files = await readdir(folderPath)
const cardMap = new Map<string, Card>()
// D'abord, on traite tous les fichiers audio
for (const file of files) {
const ext = extname(file).toLowerCase()
// On ne traite que les fichiers audio
if (!listAudioExts.includes(ext)) continue
const parsed = await parseFilename(join(folderPath, file))
if (parsed) {
// On vérifie s'il existe une image avec le même nom de base
const baseName = basename(file, ext)
let imageUrl = ''
// On cherche une image correspondante
for (const imgExt of listImageExts) {
const potentialImage = baseName + imgExt
if (files.includes(potentialImage)) {
imageUrl = process.env.URL_PREFIX + baseName + imgExt
break
}
}
cardMap.set(parsed.esid, {
...parsed,
url_audio: process.env.URL_PREFIX + baseName + ext,
url_image: imageUrl,
suit: parsed.suit,
rank: parsed.rank
})
}
}
return Array.from(cardMap.values())
} catch (error) {
console.error('Erreur lors du scan du dossier:', error)
throw error
}
}
async function parseFilename(
filename: string
): Promise<Omit<Card, 'url_audio' | 'url_image'> | null> {
// Format: yyyymmddhh__artist__title.ext
const nameWithoutExt = basename(filename, extname(filename))
const parts = nameWithoutExt.split('__')
if (parts.length !== 3) {
console.warn(`Nom de fichier invalide: ${filename}`)
return null
}
const [datetime, artist, title] = parts
if (!datetime || !artist || !title) {
console.warn(`Format de fichier invalide: ${filename} - manque des parties`)
return null
}
if (datetime.length !== 10) {
console.warn(`Format de date invalide: ${filename}`)
return null
}
// Utilisation d'un hash basé sur le contenu du fichier pour un ESID stable
let fileHash = ''
try {
const fileContent = await readFile(filename)
fileHash = createHash('md5').update(fileContent).digest('hex').substring(0, 8)
} catch (error) {
console.warn(`Impossible de lire le fichier pour générer le hash: ${filename}`)
fileHash = createHash('md5').update(filename).digest('hex').substring(0, 8)
}
const year = datetime.substring(0, 4)
const month = datetime.substring(4, 6)
const day = datetime.substring(6, 8)
const hour = datetime.substring(8, 10)
// Créer l'ID unique pour la card
const esid = createHash('md5')
.update(`${year}${month}${day}${hour}${artist}${title}`)
.digest('hex')
const date = new Date(
parseInt(year, 10),
parseInt(month, 10) - 1,
parseInt(day, 10),
parseInt(hour, 10)
)
const card = getCardFromDate(date)
return {
year,
month,
day,
hour,
artist: artist.replace(/_/g, ' '), // Remplacer les _ par des espaces
title: title.replace(/_/g, ' '),
esid,
slug: slugify(`${artist} ${title}`),
createdAt: date,
suit: card.suit,
rank: card.rank
}
}