tube/media/video.go
Heinrich 'Henrik' Langos 7a4ef5b6df feat: Add YAML support for added / modified metadata (#37)
This change introduces the ability to read additional
or modified metadata like title or description from a
YAML file.
Just like thumbnails are read from "filename.jpg", we now
look for "filename.yml" and override the meta data that
is embedded in the video file.

This is my very first look at golang, so please tell me if, or rather "where" I went wrong. ;-)

Co-authored-by: Heinrich Langos <gumbo2000@noreply@mills.io>
Reviewed-on: https://git.mills.io/prologic/tube/pulls/37
Co-authored-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io>
Co-committed-by: Heinrich 'Henrik' Langos <gumbo2000@noreply@mills.io>
2022-11-25 01:29:44 +00:00

122 lines
2.4 KiB
Go

package media
import (
"fmt"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strings"
"time"
"git.mills.io/prologic/tube/utils"
"github.com/dhowden/tag"
"gopkg.in/yaml.v3"
)
// Video represents metadata for a single video.
type Video struct {
ID string
Title string
Album string
Description string
Thumb []byte
ThumbType string
Modified string
Size int64
Path string
Timestamp time.Time
Views int64
}
func getTagsFromYml(v *Video) error {
ymlFileName := fmt.Sprintf("%s.yml", strings.TrimSuffix(v.Path, filepath.Ext(v.Path)))
if !utils.FileExists(ymlFileName) {
return nil
}
ymlFile, err := ioutil.ReadFile(ymlFileName)
if err != nil {
return err
}
err = yaml.Unmarshal(ymlFile, v)
if err != nil {
return err
}
log.Println("Got tags from yml for", v.Path)
return nil
}
// ParseVideo parses a video file's metadata and returns a Video.
func ParseVideo(p *Path, name string) (*Video, error) {
pth := path.Join(p.Path, name)
f, err := os.Open(pth)
if err != nil {
return nil, err
}
defer f.Close()
info, err := f.Stat()
if err != nil {
return nil, err
}
size := info.Size()
timestamp := info.ModTime()
modified := timestamp.Format("2006-01-02 03:04 PM")
// ID is name without extension
idx := strings.LastIndex(name, ".")
if idx == -1 {
idx = len(name)
}
id := name[:idx]
if len(p.Prefix) > 0 {
// if there's a prefix prepend it to the ID
id = path.Join(p.Prefix, name[:idx])
}
m, err := tag.ReadFrom(f)
if err != nil {
return nil, err
}
title := m.Title()
// Default title is filename
if title == "" {
title = strings.TrimSuffix(name, filepath.Ext(name))
}
v := &Video{
ID: id,
Title: title,
Album: m.Album(),
Description: m.Comment(),
Modified: modified,
Size: size,
Path: pth,
Timestamp: timestamp,
}
// read yml if exists
err = getTagsFromYml(v)
if err != nil {
log.Println("Failed to read yml for", v.Path)
}
// Add thumbnail (if exists)
pic := m.Picture()
if pic != nil {
v.Thumb = pic.Data
v.ThumbType = pic.MIMEType
} else {
thumbFn := fmt.Sprintf("%s.jpg", strings.TrimSuffix(pth, filepath.Ext(pth)))
if utils.FileExists(thumbFn) {
data, err := ioutil.ReadFile(fmt.Sprintf("%s.jpg", strings.TrimSuffix(pth, filepath.Ext(pth))))
if err != nil {
return nil, err
}
v.Thumb = data
v.ThumbType = "image/jpeg"
}
}
return v, nil
}