summaryrefslogtreecommitdiff
path: root/internal/model/media.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-05-03 19:17:04 +0300
committerPaul Buetow <paul@buetow.org>2026-05-03 19:17:04 +0300
commit30c2b0fe8232cc748ab2bded6ab4d76febe32425 (patch)
tree985578b326a1ff8fe7af395bf08471857376b8fc /internal/model/media.go
parent687b86cdeef2192272f0945ddd496322a9113f9e (diff)
fix(admin): fix rescan goroutine lifecycle and race on shared ScanProgress
- Protect adminService scan state (cancel func + progress pointer) with sync.Mutex. - Allocate fresh ScanProgress per trigger and pass it to the scanner, eliminating races on the previously shared progress struct. - Cancel previous scan context before starting a new one. - Add tests for cancellation, fresh progress per scan, concurrent triggers, and empty progress when never started. - Fix race-prone tests by polling Running==true before waiting for completion.
Diffstat (limited to 'internal/model/media.go')
-rw-r--r--internal/model/media.go61
1 files changed, 40 insertions, 21 deletions
diff --git a/internal/model/media.go b/internal/model/media.go
index b1b4ef3..74492c1 100644
--- a/internal/model/media.go
+++ b/internal/model/media.go
@@ -9,6 +9,7 @@ type MediaType string
const (
MediaTypeVideo MediaType = "video"
MediaTypeAudio MediaType = "audio"
+ MediaTypeImage MediaType = "image"
)
// Role defines the level of access a user has to a set.
@@ -46,23 +47,32 @@ type SetPermission struct {
CreatedAt time.Time `json:"created_at"`
}
-// Media represents a single audio or video file within a set.
+// Media represents a single media file within a set.
type Media struct {
- ID int64 `json:"id"`
- SetID int64 `json:"set_id"`
- RelPath string `json:"rel_path"`
- FileName string `json:"file_name"`
- AbsPath string `json:"abs_path"`
- Type MediaType `json:"type"`
- Duration float64 `json:"duration"`
- Codec string `json:"codec"`
- Resolution string `json:"resolution"`
- Bitrate int `json:"bitrate"`
- FileSizeBytes int64 `json:"file_size_bytes"`
- ThumbnailPath string `json:"thumbnail_path"`
- PlayCount int `json:"play_count"`
- DeletedAt *time.Time `json:"deleted_at"`
- CreatedAt time.Time `json:"created_at"`
+ ID int64 `json:"id"`
+ SetID int64 `json:"set_id"`
+ RelPath string `json:"rel_path"`
+ FileName string `json:"file_name"`
+ AbsPath string `json:"abs_path"`
+ Type MediaType `json:"type"`
+ Duration float64 `json:"duration"`
+ Codec string `json:"codec"`
+ Resolution string `json:"resolution"`
+ Bitrate int `json:"bitrate"`
+ FileSizeBytes int64 `json:"file_size_bytes"`
+ Width int `json:"width"`
+ Height int `json:"height"`
+ EXIFCamera string `json:"exif_camera"`
+ EXIFLens string `json:"exif_lens"`
+ EXIFDate string `json:"exif_date"`
+ EXIFISO string `json:"exif_iso"`
+ EXIFFNumber string `json:"exif_f_number"`
+ EXIFExposure string `json:"exif_exposure"`
+ EXIFFocalLength string `json:"exif_focal_length"`
+ ThumbnailPath string `json:"thumbnail_path"`
+ PlayCount int `json:"play_count"`
+ DeletedAt *time.Time `json:"deleted_at"`
+ CreatedAt time.Time `json:"created_at"`
}
// Tag is a label that can be attached to media items.
@@ -133,9 +143,18 @@ type MediaTag struct {
// Metadata holds extracted file properties from ffprobe and os.Stat.
type Metadata struct {
- Duration float64 `json:"duration"`
- Codec string `json:"codec"`
- Resolution string `json:"resolution"`
- Bitrate int `json:"bitrate"`
- FileSizeBytes int64 `json:"file_size_bytes"`
+ Duration float64 `json:"duration"`
+ Codec string `json:"codec"`
+ Resolution string `json:"resolution"`
+ Bitrate int `json:"bitrate"`
+ FileSizeBytes int64 `json:"file_size_bytes"`
+ Width int `json:"width"`
+ Height int `json:"height"`
+ EXIFCamera string `json:"exif_camera"`
+ EXIFLens string `json:"exif_lens"`
+ EXIFDate string `json:"exif_date"`
+ EXIFISO string `json:"exif_iso"`
+ EXIFFNumber string `json:"exif_f_number"`
+ EXIFExposure string `json:"exif_exposure"`
+ EXIFFocalLength string `json:"exif_focal_length"`
}