140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/photoview/photoview/api/utils"
|
|
"github.com/pkg/errors"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type Media struct {
|
|
Model
|
|
Title string `gorm:"not null"`
|
|
Path string `gorm:"not null"`
|
|
PathHash string `gorm:"not null;unique"`
|
|
AlbumID int `gorm:"not null;index"`
|
|
Album Album `gorm:"constraint:OnDelete:CASCADE;"`
|
|
ExifID *int `gorm:"index"`
|
|
Exif *MediaEXIF `gorm:"constraint:OnDelete:CASCADE;"`
|
|
MediaURL []MediaURL `gorm:"constraint:OnDelete:CASCADE;"`
|
|
DateShot time.Time `gorm:"not null"`
|
|
Type MediaType `gorm:"not null;index"`
|
|
VideoMetadataID *int `gorm:"index"`
|
|
VideoMetadata *VideoMetadata `gorm:"constraint:OnDelete:CASCADE;"`
|
|
SideCarPath *string
|
|
SideCarHash *string `gorm:"unique"`
|
|
Faces []*ImageFace `gorm:"constraint:OnDelete:CASCADE;"`
|
|
Blurhash *string `gorm:""`
|
|
|
|
// Only used internally
|
|
CounterpartPath *string `gorm:"-"`
|
|
}
|
|
|
|
func (Media) TableName() string {
|
|
return "media"
|
|
}
|
|
|
|
func (m *Media) BeforeSave(tx *gorm.DB) error {
|
|
// Update path hash
|
|
m.PathHash = MD5Hash(m.Path)
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *Media) Date() time.Time {
|
|
return m.DateShot
|
|
}
|
|
|
|
func (m *Media) Thumbnail() (*MediaURL, error) {
|
|
if len(m.MediaURL) == 0 {
|
|
return nil, errors.New("media.MediaURL is empty")
|
|
}
|
|
|
|
for _, url := range m.MediaURL {
|
|
if url.Purpose == PhotoThumbnail || url.Purpose == VideoThumbnail {
|
|
url.Media = m
|
|
return &url, nil
|
|
}
|
|
}
|
|
|
|
return nil, nil
|
|
}
|
|
|
|
type MediaType string
|
|
|
|
const (
|
|
MediaTypePhoto MediaType = "photo"
|
|
MediaTypeVideo MediaType = "video"
|
|
)
|
|
|
|
var AllMediaType = []MediaType{
|
|
MediaTypePhoto,
|
|
MediaTypeVideo,
|
|
}
|
|
|
|
type MediaPurpose string
|
|
|
|
const (
|
|
PhotoThumbnail MediaPurpose = "thumbnail"
|
|
PhotoHighRes MediaPurpose = "high-res"
|
|
MediaOriginal MediaPurpose = "original"
|
|
VideoWeb MediaPurpose = "video-web"
|
|
VideoThumbnail MediaPurpose = "video-thumbnail"
|
|
)
|
|
|
|
type MediaURL struct {
|
|
Model
|
|
MediaID int `gorm:"not null;index"`
|
|
Media *Media `gorm:"constraint:OnDelete:CASCADE;"`
|
|
MediaName string `gorm:"not null;index"`
|
|
Width int `gorm:"not null"`
|
|
Height int `gorm:"not null"`
|
|
Purpose MediaPurpose `gorm:"not null;index"`
|
|
ContentType string `gorm:"not null"`
|
|
FileSize int64 `gorm:"not null"`
|
|
}
|
|
|
|
func (p *MediaURL) URL() string {
|
|
|
|
imageURL := utils.ApiEndpointUrl()
|
|
if p.Purpose != VideoWeb {
|
|
imageURL.Path = path.Join(imageURL.Path, "photo", p.MediaName)
|
|
} else {
|
|
imageURL.Path = path.Join(imageURL.Path, "video", p.MediaName)
|
|
}
|
|
|
|
return imageURL.String()
|
|
}
|
|
|
|
func (p *MediaURL) CachedPath() (string, error) {
|
|
var cachedPath string
|
|
|
|
if p.Media == nil {
|
|
return "", errors.New("mediaURL.Media is nil")
|
|
}
|
|
|
|
if p.Purpose == PhotoThumbnail || p.Purpose == PhotoHighRes || p.Purpose == VideoThumbnail || p.Purpose == VideoWeb {
|
|
cachedPath = path.Join(utils.MediaCachePath(), strconv.Itoa(int(p.Media.AlbumID)), strconv.Itoa(int(p.MediaID)), p.MediaName)
|
|
} else if p.Purpose == MediaOriginal {
|
|
cachedPath = p.Media.Path
|
|
} else {
|
|
return "", errors.New(fmt.Sprintf("cannot determine cache path for purpose (%s)", p.Purpose))
|
|
}
|
|
|
|
return cachedPath, nil
|
|
}
|
|
|
|
func SanitizeMediaName(mediaName string) string {
|
|
result := mediaName
|
|
result = strings.ReplaceAll(result, "/", "")
|
|
result = strings.ReplaceAll(result, "\\", "")
|
|
result = strings.ReplaceAll(result, " ", "_")
|
|
result = strings.ReplaceAll(result, ".", "_")
|
|
return result
|
|
}
|