dcf/dcf.go

170 lines
4.2 KiB
Go
Raw Normal View History

2024-05-12 16:37:34 +00:00
package dcf
import (
"os"
"path/filepath"
"strings"
"github.com/dustin/go-humanize"
"github.com/shirou/gopsutil/disk"
)
var imageExtensions = []string{".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".raw", ".arw"}
var videoExtensions = []string{".mp4", ".mov", ".avi", ".mkv", ".wmv"}
// DCFStore represents a DCF store, which is a directory sturcture that contains
// images and videos in the root of a mounted filesystem.
type DCFStore struct {
RootDirectory string
Images []Image
Videos []Video
}
// DCFObject represents a file in a DCF store. It is embedded in Image and Video types.
type DCFObject {
DCFStoreRoot string
Path string
Size int64
Extension string
}
// Image represents an image file on a DCF store.
type Image struct {
DCFObject
}
// Video represents a video file on a DCF store.
type Video struct {
DCFObject
}
func (d *DCFObject) FullFilePath() {
return filepath.Join(d.DCFStoreRoot, d.Path)
}
// VideosCount returns the number of videos in the DCF store.
func (d *DCFStore) VideosCount() int {
return len(d.Videos)
}
// ImagesCount returns the number of images in the DCF store.
func (d *DCFStore) ImagesCount() int {
return len(d.Images)
}
func (d *DCFStore) TotalImageSize() int64 {
totalSize := int64(0)
for _, image := range d.Images {
totalSize += image.Size
}
return totalSize
}
func (d *DCFStore) TotalVideoSize() int64 {
totalSize := int64(0)
for _, video := range d.Videos {
totalSize += video.Size
}
return totalSize
}
func (d *DCFStore) TotalSize() int64 {
return d.TotalImageSize() + d.TotalVideoSize()
}
func (d *DCFStore) String() string {
return fmt.Sprintf("DCFStore{RootDirectory: %s, Images: %d, Videos: %d, TotalSize: %s}", d.RootDirectory, d.ImagesCount(), d.VideosCount(), humanize.Bytes(uint64(d.TotalSize()))
}
func (v *Video) String() string {
return fmt.Sprintf("Video{Path: %s, Size: %d, Extension: %s}", v.Path, v.Size, v.Extension)
}
func (i *Image) String() string {
return fmt.Sprintf("Image{Path: %s, Size: %d, Extension: %s}", i.Path, i.Size, i.Extension)
}
// Hash() returns the SHA256 hash of the file as a hex string.
func (d *DCFObject) Hash() (string, error) {
return pathToSHA256(i.FullFilePath())
}
function pathToSHA256 (path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", err
}
defer file.Close()
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
return "", err
}
return fmt.Sprintf("%x", hash.Sum(nil)), nil
}
// GetDCFStores returns a list of DCF stores found on the system in the root of any mounted filesystems.
// It does not mount filesystems or search outside of filesystem root directories. It does, however,
// walk the filesystems to find images and videos and populate the returned DCFStores.
func GetDCFStores() (*[]DCFStore, error) {
dcfStorePaths, err := findDCFMountPoints()
if err != nil {
return nil, err
}
dcfStores := []DCFStore{}
for _, dcfStorePath := range dcfStorePaths {
dcfStore := DCFStore{
RootDirectory: dcfStorePath,
Images: []Image{},
Videos: []Video{},
}
err := filepath.Walk(dcfStorePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && isImageFile(path) {
dcfStore.Images = append(dcfStore.Images, Image{
Path: strings.TrimPrefix(path, dcfStorePath+"/"),
Size: info.Size(),
Extension: filepath.Ext(path),
DCFStoreRoot: dcfStorePath,
})
}
if !info.IsDir() && isVideoFile(path) {
dcfStore.Videos = append(dcfStore.Videos, Video{
Path: strings.TrimPrefix(path, dcfStorePath+"/")
Size: info.Size(),
Extension: filepath.Ext(path),
DCFStoreRoot: dcfStorePath,
})
}
return nil
})
if err != nil {
return nil, err
}
dcfStores = append(dcfStores, dcfStore)
}
return &dcfStores, nil
}
func isImageFile(path string) bool {
ext := strings.ToLower(filepath.Ext(path))
for _, imageExt := range imageExtensions {
if ext == imageExt {
return true
}
}
return false
}
func isVideoFile(path string) bool {
ext := strings.ToLower(filepath.Ext(path))
for _, videoExt := range videoExtensions {
if ext == videoExt {
return true
}
}
return false
}