183 lines
4.1 KiB
Go

// internal/utils/files.go
package utils
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"math/rand"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
func init() {
// Seed the random number generator
rand.Seed(time.Now().UnixNano())
}
// EnsureDir makes sure the directory exists
func EnsureDir(dir string) error {
return os.MkdirAll(dir, 0755)
}
// FileExists checks if a file exists and is not a directory
func FileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}
// GetRandomFile returns a random file from the specified directory
// It only includes files with the given extensions (no dot, e.g. "jpg", "png")
// If extensions is empty, it includes all files
func GetRandomFile(dir string, extensions []string) (string, error) {
files, err := os.ReadDir(dir)
if err != nil {
return "", fmt.Errorf("failed to read directory: %w", err)
}
// Filter files based on extensions
var validFiles []string
for _, file := range files {
if file.IsDir() {
continue
}
if len(extensions) == 0 {
validFiles = append(validFiles, file.Name())
continue
}
ext := strings.TrimPrefix(filepath.Ext(file.Name()), ".")
for _, validExt := range extensions {
if strings.EqualFold(ext, validExt) {
validFiles = append(validFiles, file.Name())
break
}
}
}
if len(validFiles) == 0 {
return "", fmt.Errorf("no valid files found in directory")
}
// Pick a random file
randomIndex := rand.Intn(len(validFiles))
return filepath.Join(dir, validFiles[randomIndex]), nil
}
// MoveFile moves a file from src to dst
func MoveFile(src, dst string) error {
// Ensure the destination directory exists
if err := EnsureDir(filepath.Dir(dst)); err != nil {
return err
}
// First try to rename (which works within the same filesystem)
err := os.Rename(src, dst)
if err == nil {
return nil
}
// If rename fails (e.g., across filesystems), copy and delete the original
if err := CopyFile(src, dst); err != nil {
return err
}
return os.Remove(src)
}
// CopyFile copies a file from src to dst
func CopyFile(src, dst string) error {
// Ensure the destination directory exists
if err := EnsureDir(filepath.Dir(dst)); err != nil {
return err
}
// Open the source file
sourceFile, err := os.Open(src)
if err != nil {
return err
}
defer sourceFile.Close()
// Create the destination file
destFile, err := os.Create(dst)
if err != nil {
return err
}
defer destFile.Close()
// Copy the content
_, err = io.Copy(destFile, sourceFile)
if err != nil {
return err
}
// Flush the write buffer to disk
return destFile.Sync()
}
// CalculateFileHash returns the SHA-256 hash of a file
func CalculateFileHash(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
hasher := sha256.New()
if _, err := io.Copy(hasher, file); err != nil {
return "", err
}
return hex.EncodeToString(hasher.Sum(nil)), nil
}
// GetFileContentType tries to determine the content type of a file
func GetFileContentType(filePath string) (string, error) {
// Open the file
file, err := os.Open(filePath)
if err != nil {
return "", err
}
defer file.Close()
// Read the first 512 bytes to determine the content type
buffer := make([]byte, 512)
_, err = file.Read(buffer)
if err != nil && err != io.EOF {
return "", err
}
// Reset the file pointer
_, err = file.Seek(0, 0)
if err != nil {
return "", err
}
// Detect the content type
contentType := http.DetectContentType(buffer)
return contentType, nil
}
// GetSupportedImageExtensions returns a list of supported image extensions
func GetSupportedImageExtensions() []string {
return []string{"jpg", "jpeg", "png", "gif", "webp", "avif"}
}
// GetSupportedVideoExtensions returns a list of supported video extensions
func GetSupportedVideoExtensions() []string {
return []string{"mp4", "webm", "mov", "avi"}
}
// GetAllSupportedMediaExtensions returns all supported media extensions
func GetAllSupportedMediaExtensions() []string {
return append(GetSupportedImageExtensions(), GetSupportedVideoExtensions()...)
}