summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/model/media.go140
-rw-r--r--internal/model/media_test.go27
-rw-r--r--internal/model/model.go2
3 files changed, 167 insertions, 2 deletions
diff --git a/internal/model/media.go b/internal/model/media.go
new file mode 100644
index 0000000..cae1c8d
--- /dev/null
+++ b/internal/model/media.go
@@ -0,0 +1,140 @@
+// Package model defines the core domain entities.
+package model
+
+import "time"
+
+// MediaType distinguishes between video and audio files.
+type MediaType string
+
+const (
+ MediaTypeVideo MediaType = "video"
+ MediaTypeAudio MediaType = "audio"
+)
+
+// Role defines the level of access a user has to a set.
+type Role string
+
+const (
+ RoleOwner Role = "owner"
+ RoleViewer Role = "viewer"
+)
+
+// User represents an application account.
+type User struct {
+ ID int64
+ Username string
+ PasswordHash string
+ IsAdmin bool
+ CreatedAt time.Time
+}
+
+// Set represents a top-level media collection (a directory under MEDIA_ROOT).
+type Set struct {
+ ID int64
+ Name string
+ RootPath string
+ CoverThumbnailPath string
+ CreatedAt time.Time
+}
+
+// SetPermission grants a user access to a set.
+type SetPermission struct {
+ SetID int64
+ UserID int64
+ Role Role
+ CreatedAt time.Time
+}
+
+// Media represents a single audio or video file within a set.
+type Media struct {
+ ID int64
+ SetID int64
+ RelPath string
+ FileName string
+ AbsPath string
+ Type MediaType
+ Duration float64
+ Codec string
+ Resolution string
+ Bitrate int
+ FileSizeBytes int64
+ ThumbnailPath string
+ PlayCount int
+ DeletedAt *time.Time
+ CreatedAt time.Time
+}
+
+// Tag is a label that can be attached to media items.
+type Tag struct {
+ ID int64
+ Name string
+}
+
+// Session is an authenticated browser session.
+type Session struct {
+ ID string
+ UserID int64
+ ExpiresAt time.Time
+ CreatedAt time.Time
+}
+
+// Share is a time-bounded public link to a media item.
+type Share struct {
+ Token string
+ MediaID int64
+ CreatedBy int64
+ CreatedAt time.Time
+ ExpiresAt time.Time
+ MaxUses *int
+ UsedCount int
+}
+
+// Note is a per-user, per-media text note.
+type Note struct {
+ ID int64
+ MediaID int64
+ UserID int64
+ Content string
+ CreatedAt time.Time
+ UpdatedAt time.Time
+}
+
+// PlaybackProgress stores the last known playback position.
+type PlaybackProgress struct {
+ UserID int64
+ MediaID int64
+ PositionSeconds float64
+ UpdatedAt time.Time
+}
+
+// PlaybackAccumulator tracks deltas for the 60-second playback counter rule.
+type PlaybackAccumulator struct {
+ SessionID string
+ MediaID int64
+ LastPosition float64
+ AccumulatedSeconds float64
+ Counted bool
+ UpdatedAt time.Time
+}
+
+// Favorite records that a user has favorited a media item.
+type Favorite struct {
+ UserID int64
+ MediaID int64
+ CreatedAt time.Time
+}
+
+// MediaTag is the join table between media and tags.
+type MediaTag struct {
+ MediaID int64
+ TagID int64
+}
+
+// Metadata holds extracted file properties from ffprobe and os.Stat.
+type Metadata struct {
+ Duration float64
+ Codec string
+ Resolution string
+ Bitrate int
+ FileSizeBytes int64
+}
diff --git a/internal/model/media_test.go b/internal/model/media_test.go
new file mode 100644
index 0000000..49d877c
--- /dev/null
+++ b/internal/model/media_test.go
@@ -0,0 +1,27 @@
+package model
+
+import (
+ "testing"
+ "time"
+)
+
+func TestStructsInstantiate(t *testing.T) {
+ now := time.Now()
+ _ = User{ID: 1, Username: "u", PasswordHash: "h", IsAdmin: true, CreatedAt: now}
+ _ = Set{ID: 1, Name: "s", RootPath: "/r", CreatedAt: now}
+ _ = Media{ID: 1, SetID: 1, RelPath: "r", FileName: "f", AbsPath: "a", Type: MediaTypeVideo, Duration: 1, DeletedAt: &now, CreatedAt: now}
+ _ = Tag{ID: 1, Name: "t"}
+ _ = Session{ID: "s", UserID: 1, ExpiresAt: now, CreatedAt: now}
+ max := 1
+ _ = Share{Token: "t", MediaID: 1, CreatedBy: 1, CreatedAt: now, ExpiresAt: now, MaxUses: &max}
+ _ = Note{ID: 1, MediaID: 1, UserID: 1, Content: "c", CreatedAt: now, UpdatedAt: now}
+ _ = PlaybackProgress{UserID: 1, MediaID: 1, PositionSeconds: 1, UpdatedAt: now}
+ _ = PlaybackAccumulator{SessionID: "s", MediaID: 1, UpdatedAt: now}
+ _ = Favorite{UserID: 1, MediaID: 1, CreatedAt: now}
+ _ = MediaTag{MediaID: 1, TagID: 1}
+ _ = SetPermission{SetID: 1, UserID: 1, Role: RoleOwner, CreatedAt: now}
+ _ = Metadata{Duration: 1, Codec: "c", Resolution: "r", Bitrate: 1, FileSizeBytes: 1}
+ if MediaTypeVideo != "video" || MediaTypeAudio != "audio" || RoleOwner != "owner" || RoleViewer != "viewer" {
+ t.Fatal("constants mismatch")
+ }
+}
diff --git a/internal/model/model.go b/internal/model/model.go
deleted file mode 100644
index 8061bf6..0000000
--- a/internal/model/model.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package model defines the core domain entities.
-package model