mirror of
https://git.vectorsigma.ru/public/photoview.git
synced 2026-08-03 20:59:03 +00:00
Replace database, mostly video
This commit is contained in:
@@ -79,6 +79,7 @@ func MigrateDatabase(db *gorm.DB) error {
|
||||
&models.MediaURL{},
|
||||
&models.Album{},
|
||||
&models.MediaEXIF{},
|
||||
&models.VideoMetadata{},
|
||||
)
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Album struct {
|
||||
gorm.Model
|
||||
Title string
|
||||
ParentAlbum *int
|
||||
OwnerID int
|
||||
Owner User
|
||||
Path string
|
||||
PathHash string
|
||||
Title string
|
||||
ParentAlbumID *uint
|
||||
ParentAlbum *Album
|
||||
OwnerID uint
|
||||
Owner User
|
||||
Path string
|
||||
PathHash string `gorm:"unique"`
|
||||
}
|
||||
|
||||
func (a *Album) FilePath() string {
|
||||
return a.Path
|
||||
}
|
||||
|
||||
func (a *Album) BeforeSave(tx *gorm.DB) (err error) {
|
||||
hash := md5.Sum([]byte(a.Path))
|
||||
a.PathHash = hex.EncodeToString(hash[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@ type Media struct {
|
||||
DateImported time.Time
|
||||
Favorite bool
|
||||
Type MediaType
|
||||
VideoMetadataId *int
|
||||
VideoMetadataID *uint
|
||||
VideoMetadata *VideoMetadata
|
||||
SideCarPath *string
|
||||
SideCarHash *string
|
||||
}
|
||||
|
||||
@@ -1,33 +1,17 @@
|
||||
package models
|
||||
|
||||
import "database/sql"
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type VideoMetadata struct {
|
||||
MetadataID int
|
||||
gorm.Model
|
||||
Width int
|
||||
Height int
|
||||
Duration float64
|
||||
Codec *string
|
||||
Framerate *float64
|
||||
Bitrate *int
|
||||
Bitrate *string
|
||||
ColorProfile *string
|
||||
Audio *string
|
||||
}
|
||||
|
||||
func (metadata *VideoMetadata) ID() int {
|
||||
return metadata.MetadataID
|
||||
}
|
||||
|
||||
func (metadata *VideoMetadata) Media() *Media {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func NewVideoMetadataFromRow(row *sql.Row) (*VideoMetadata, error) {
|
||||
meta := VideoMetadata{}
|
||||
|
||||
if err := row.Scan(&meta.MetadataID, &meta.Width, &meta.Height, &meta.Duration, &meta.Codec, &meta.Framerate, &meta.Bitrate, &meta.ColorProfile, &meta.Audio); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &meta, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package scanner
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"os"
|
||||
@@ -176,18 +175,6 @@ func (img *EncodeMediaData) photoImage(tx *gorm.DB) (image.Image, error) {
|
||||
return nil, utils.HandleError("image decoding", err)
|
||||
}
|
||||
|
||||
// Get orientation from exif data
|
||||
row := tx.QueryRow("SELECT media_exif.orientation FROM media JOIN media_exif WHERE media.exif_id = media_exif.exif_id AND media.media_id = ?", img.media.ID)
|
||||
var orientation *int
|
||||
if err = row.Scan(&orientation); err != nil {
|
||||
// If not found use default orientation (not rotate)
|
||||
if err == sql.ErrNoRows {
|
||||
orientation = nil
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
img._photoImage = photoImg
|
||||
return img._photoImage, nil
|
||||
}
|
||||
|
||||
@@ -62,9 +62,17 @@ func processVideo(tx *gorm.DB, mediaData *EncodeMediaData, videoCachePath *strin
|
||||
return false, errors.Wrap(err, "reading file stats of web-optimized video")
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO media_url (media_id, media_name, width, height, purpose, content_type, file_size) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
video.MediaID, web_video_name, webMetadata.Width, webMetadata.Height, models.VideoWeb, "video/mp4", fileStats.Size())
|
||||
if err != nil {
|
||||
mediaURL := models.MediaURL{
|
||||
MediaID: video.ID,
|
||||
MediaName: web_video_name,
|
||||
Width: webMetadata.Width,
|
||||
Height: webMetadata.Height,
|
||||
Purpose: models.VideoWeb,
|
||||
ContentType: "video/mp4",
|
||||
FileSize: fileStats.Size(),
|
||||
}
|
||||
|
||||
if err := tx.Create(&mediaURL).Error; err != nil {
|
||||
return false, errors.Wrapf(err, "failed to insert encoded web-video into database (%s)", video.Title)
|
||||
}
|
||||
}
|
||||
@@ -94,9 +102,17 @@ func processVideo(tx *gorm.DB, mediaData *EncodeMediaData, videoCachePath *strin
|
||||
return false, errors.Wrap(err, "reading file stats of video thumbnail")
|
||||
}
|
||||
|
||||
_, err = tx.Exec("INSERT INTO media_url (media_id, media_name, width, height, purpose, content_type, file_size) VALUES (?, ?, ?, ?, ?, ?, ?)",
|
||||
video.MediaID, video_thumb_name, thumbDimensions.Width, thumbDimensions.Height, models.VideoThumbnail, "image/jpeg", fileStats.Size())
|
||||
if err != nil {
|
||||
thumbMediaURL := models.MediaURL{
|
||||
MediaID: video.ID,
|
||||
MediaName: video_thumb_name,
|
||||
Width: thumbDimensions.Width,
|
||||
Height: thumbDimensions.Height,
|
||||
Purpose: models.VideoThumbnail,
|
||||
ContentType: "image/jpeg",
|
||||
FileSize: fileStats.Size(),
|
||||
}
|
||||
|
||||
if err := tx.Create(&thumbMediaURL).Error; err != nil {
|
||||
return false, errors.Wrapf(err, "failed to insert video thumbnail image into database (%s)", video.Title)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ func ScanMedia(tx *gorm.DB, mediaPath string, albumId uint, cache *AlbumScannerC
|
||||
}
|
||||
|
||||
if media.Type == models.MediaTypeVideo {
|
||||
if err = ScanVideoMetadata(tx, media); err != nil {
|
||||
if err = ScanVideoMetadata(tx, &media); err != nil {
|
||||
log.Printf("WARN: ScanVideoMetadata for %s failed: %s\n", mediaName, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,13 +28,13 @@ func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *AlbumScanner
|
||||
|
||||
type scanInfo struct {
|
||||
path string
|
||||
parentId *int
|
||||
parentID *uint
|
||||
}
|
||||
|
||||
scanQueue := list.New()
|
||||
scanQueue.PushBack(scanInfo{
|
||||
path: user.RootPath,
|
||||
parentId: nil,
|
||||
parentID: nil,
|
||||
})
|
||||
|
||||
userAlbums := make([]*models.Album, 0)
|
||||
@@ -46,7 +46,7 @@ func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *AlbumScanner
|
||||
scanQueue.Remove(scanQueue.Front())
|
||||
|
||||
albumPath := albumInfo.path
|
||||
albumParentId := albumInfo.parentId
|
||||
albumParentID := albumInfo.parentID
|
||||
|
||||
// Read path
|
||||
dirContent, err := ioutil.ReadDir(albumPath)
|
||||
@@ -55,35 +55,33 @@ func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *AlbumScanner
|
||||
continue
|
||||
}
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
albumErrors = append(albumErrors, errors.Wrap(err, "begin database transaction"))
|
||||
continue
|
||||
}
|
||||
// Will become new album or album from db
|
||||
var album models.Album
|
||||
|
||||
log.Printf("Scanning directory: %s", albumPath)
|
||||
transErr := db.Transaction(func(tx *gorm.DB) error {
|
||||
log.Printf("Scanning directory: %s", albumPath)
|
||||
|
||||
// Make album if not exists
|
||||
albumTitle := path.Base(albumPath)
|
||||
_, err = tx.Exec("INSERT IGNORE INTO album (title, parent_album, owner_id, path, path_hash) VALUES (?, ?, ?, ?, MD5(path))", albumTitle, albumParentId, user.UserID, albumPath)
|
||||
if err != nil {
|
||||
albumErrors = append(albumErrors, errors.Wrap(err, "insert album into database"))
|
||||
tx.Rollback()
|
||||
continue
|
||||
}
|
||||
// Make album if not exists
|
||||
albumTitle := path.Base(albumPath)
|
||||
|
||||
row := tx.QueryRow("SELECT * FROM album WHERE path_hash = MD5(?)", albumPath)
|
||||
album, err := models.NewAlbumFromRow(row)
|
||||
if err != nil {
|
||||
albumErrors = append(albumErrors, errors.Wrapf(err, "get album from database (%s)", albumPath))
|
||||
tx.Rollback()
|
||||
continue
|
||||
}
|
||||
userAlbums = append(userAlbums, album)
|
||||
err = tx.FirstOrCreate(&album, models.Album{
|
||||
Title: albumTitle,
|
||||
ParentAlbumID: albumParentID,
|
||||
OwnerID: user.ID,
|
||||
Path: albumPath,
|
||||
}).Error
|
||||
|
||||
// Commit album transaction
|
||||
if err := tx.Commit(); err != nil {
|
||||
albumErrors = append(albumErrors, errors.Wrap(err, "commit database transaction"))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "insert album into database")
|
||||
}
|
||||
|
||||
userAlbums = append(userAlbums, &album)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if transErr != nil {
|
||||
albumErrors = append(albumErrors, errors.Wrap(transErr, "begin database transaction"))
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -99,7 +97,7 @@ func findAlbumsForUser(db *gorm.DB, user *models.User, album_cache *AlbumScanner
|
||||
if item.IsDir() && directoryContainsPhotos(subalbumPath, album_cache) {
|
||||
scanQueue.PushBack(scanInfo{
|
||||
path: subalbumPath,
|
||||
parentId: &album.AlbumID,
|
||||
parentID: &album.ID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,18 +52,21 @@ func ScanVideoMetadata(tx *gorm.DB, video *models.Media) error {
|
||||
}
|
||||
}
|
||||
|
||||
result, err := tx.Exec("INSERT INTO video_metadata (width, height, duration, codec, framerate, bitrate, color_profile, audio) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", stream.Width, stream.Height, data.Format.DurationSeconds, stream.CodecLongName, framerate, stream.BitRate, stream.Profile, audioText)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to insert video metadata into database (%s)", video.Title)
|
||||
videoMetadata := models.VideoMetadata{
|
||||
Width: stream.Width,
|
||||
Height: stream.Height,
|
||||
Duration: data.Format.DurationSeconds,
|
||||
Codec: &stream.CodecLongName,
|
||||
Framerate: framerate,
|
||||
Bitrate: &stream.BitRate,
|
||||
ColorProfile: &stream.Profile,
|
||||
Audio: &audioText,
|
||||
}
|
||||
|
||||
metadata_id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
video.VideoMetadata = &videoMetadata
|
||||
|
||||
if _, err = tx.Exec("UPDATE media SET video_metadata_id = ? WHERE media_id = ?", metadata_id, video.MediaID); err != nil {
|
||||
return err
|
||||
if err := tx.Save(video).Error; err != nil {
|
||||
return errors.Wrapf(err, "failed to add video metadata to database (%s)", video.Title)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user