Restructure ffmpeg (#2392)

* Refactor transcode generation
* Move phash generation into separate package
* Refactor image thumbnail generation
* Move JSONTime to separate package
* Ffmpeg refactoring
* Refactor live transcoding
* Refactor scene marker preview generation
* Refactor preview generation
* Refactor screenshot generation
* Refactor sprite generation
* Change ffmpeg.IsStreamable to return error
* Move frame rate calculation into ffmpeg
* Refactor file locking
* Refactor title set during scan
* Add missing lockmanager instance
* Return error instead of logging in MatchContainer
This commit is contained in:
WithoutPants
2022-04-18 10:50:10 +10:00
committed by GitHub
parent cdaa191155
commit aacf07feef
89 changed files with 3208 additions and 2004 deletions

View File

@@ -5,19 +5,19 @@ type ResolutionRange struct {
}
var resolutionRanges = map[ResolutionEnum]ResolutionRange{
ResolutionEnum("VERY_LOW"): {144, 239},
ResolutionEnum("LOW"): {240, 359},
ResolutionEnum("R360P"): {360, 479},
ResolutionEnum("STANDARD"): {480, 539},
ResolutionEnum("WEB_HD"): {540, 719},
ResolutionEnum("STANDARD_HD"): {720, 1079},
ResolutionEnum("FULL_HD"): {1080, 1439},
ResolutionEnum("QUAD_HD"): {1440, 1919},
ResolutionEnum("VR_HD"): {1920, 2159},
ResolutionEnum("FOUR_K"): {2160, 2879},
ResolutionEnum("FIVE_K"): {2880, 3383},
ResolutionEnum("SIX_K"): {3384, 4319},
ResolutionEnum("EIGHT_K"): {4320, 8639},
ResolutionEnumVeryLow: {144, 239},
ResolutionEnumLow: {240, 359},
ResolutionEnumR360p: {360, 479},
ResolutionEnumStandard: {480, 539},
ResolutionEnumWebHd: {540, 719},
ResolutionEnumStandardHd: {720, 1079},
ResolutionEnumFullHd: {1080, 1439},
ResolutionEnumQuadHd: {1440, 1919},
ResolutionEnumVrHd: {1920, 2159},
ResolutionEnumFourK: {2160, 2879},
ResolutionEnumFiveK: {2880, 3383},
ResolutionEnumSixK: {3384, 4319},
ResolutionEnumEightK: {4320, 8639},
}
// GetMaxResolution returns the maximum width or height that media must be
@@ -28,6 +28,19 @@ func (r *ResolutionEnum) GetMaxResolution() int {
// GetMinResolution returns the minimum width or height that media must be
// to qualify as this resolution.
func (r *ResolutionEnum) GetMinResolution() int {
return resolutionRanges[*r].min
func (r ResolutionEnum) GetMinResolution() int {
return resolutionRanges[r].min
}
var streamingResolutionMax = map[StreamingResolutionEnum]int{
StreamingResolutionEnumLow: resolutionRanges[ResolutionEnumLow].min,
StreamingResolutionEnumStandard: resolutionRanges[ResolutionEnumStandard].min,
StreamingResolutionEnumStandardHd: resolutionRanges[ResolutionEnumStandardHd].min,
StreamingResolutionEnumFullHd: resolutionRanges[ResolutionEnumFullHd].min,
StreamingResolutionEnumFourK: resolutionRanges[ResolutionEnumFourK].min,
StreamingResolutionEnumOriginal: 0,
}
func (r StreamingResolutionEnum) GetMaxResolution() int {
return streamingResolutionMax[r]
}

View File

@@ -1,11 +1,10 @@
package models
package json
import (
"fmt"
"strings"
"time"
"github.com/stashapp/stash/pkg/logger"
"github.com/stashapp/stash/pkg/utils"
)
@@ -23,12 +22,7 @@ func (jt *JSONTime) UnmarshalJSON(b []byte) error {
}
// #731 - returning an error here causes the entire JSON parse to fail for ffprobe.
// Changing so that it logs a warning instead.
var err error
jt.Time, err = utils.ParseDateStringAsTime(s)
if err != nil {
logger.Warnf("error unmarshalling JSONTime: %s", err.Error())
}
jt.Time, _ = utils.ParseDateStringAsTime(s)
return nil
}

View File

@@ -5,25 +5,25 @@ import (
"os"
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type Gallery struct {
Path string `json:"path,omitempty"`
Checksum string `json:"checksum,omitempty"`
Zip bool `json:"zip,omitempty"`
Title string `json:"title,omitempty"`
URL string `json:"url,omitempty"`
Date string `json:"date,omitempty"`
Details string `json:"details,omitempty"`
Rating int `json:"rating,omitempty"`
Organized bool `json:"organized,omitempty"`
Studio string `json:"studio,omitempty"`
Performers []string `json:"performers,omitempty"`
Tags []string `json:"tags,omitempty"`
FileModTime models.JSONTime `json:"file_mod_time,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Path string `json:"path,omitempty"`
Checksum string `json:"checksum,omitempty"`
Zip bool `json:"zip,omitempty"`
Title string `json:"title,omitempty"`
URL string `json:"url,omitempty"`
Date string `json:"date,omitempty"`
Details string `json:"details,omitempty"`
Rating int `json:"rating,omitempty"`
Organized bool `json:"organized,omitempty"`
Studio string `json:"studio,omitempty"`
Performers []string `json:"performers,omitempty"`
Tags []string `json:"tags,omitempty"`
FileModTime json.JSONTime `json:"file_mod_time,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
func LoadGalleryFile(filePath string) (*Gallery, error) {

View File

@@ -5,29 +5,29 @@ import (
"os"
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type ImageFile struct {
ModTime models.JSONTime `json:"mod_time,omitempty"`
Size int `json:"size"`
Width int `json:"width"`
Height int `json:"height"`
ModTime json.JSONTime `json:"mod_time,omitempty"`
Size int `json:"size"`
Width int `json:"width"`
Height int `json:"height"`
}
type Image struct {
Title string `json:"title,omitempty"`
Checksum string `json:"checksum,omitempty"`
Studio string `json:"studio,omitempty"`
Rating int `json:"rating,omitempty"`
Organized bool `json:"organized,omitempty"`
OCounter int `json:"o_counter,omitempty"`
Galleries []string `json:"galleries,omitempty"`
Performers []string `json:"performers,omitempty"`
Tags []string `json:"tags,omitempty"`
File *ImageFile `json:"file,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Title string `json:"title,omitempty"`
Checksum string `json:"checksum,omitempty"`
Studio string `json:"studio,omitempty"`
Rating int `json:"rating,omitempty"`
Organized bool `json:"organized,omitempty"`
OCounter int `json:"o_counter,omitempty"`
Galleries []string `json:"galleries,omitempty"`
Performers []string `json:"performers,omitempty"`
Tags []string `json:"tags,omitempty"`
File *ImageFile `json:"file,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
func LoadImageFile(filePath string) (*Image, error) {

View File

@@ -5,23 +5,23 @@ import (
"os"
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type Movie struct {
Name string `json:"name,omitempty"`
Aliases string `json:"aliases,omitempty"`
Duration int `json:"duration,omitempty"`
Date string `json:"date,omitempty"`
Rating int `json:"rating,omitempty"`
Director string `json:"director,omitempty"`
Synopsis string `json:"sypnopsis,omitempty"`
FrontImage string `json:"front_image,omitempty"`
BackImage string `json:"back_image,omitempty"`
URL string `json:"url,omitempty"`
Studio string `json:"studio,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Name string `json:"name,omitempty"`
Aliases string `json:"aliases,omitempty"`
Duration int `json:"duration,omitempty"`
Date string `json:"date,omitempty"`
Rating int `json:"rating,omitempty"`
Director string `json:"director,omitempty"`
Synopsis string `json:"sypnopsis,omitempty"`
FrontImage string `json:"front_image,omitempty"`
BackImage string `json:"back_image,omitempty"`
URL string `json:"url,omitempty"`
Studio string `json:"studio,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
func LoadMovieFile(filePath string) (*Movie, error) {

View File

@@ -6,6 +6,7 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type Performer struct {
@@ -28,8 +29,8 @@ type Performer struct {
Favorite bool `json:"favorite,omitempty"`
Tags []string `json:"tags,omitempty"`
Image string `json:"image,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
Rating int `json:"rating,omitempty"`
Details string `json:"details,omitempty"`
DeathDate string `json:"death_date,omitempty"`

View File

@@ -6,28 +6,29 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type SceneMarker struct {
Title string `json:"title,omitempty"`
Seconds string `json:"seconds,omitempty"`
PrimaryTag string `json:"primary_tag,omitempty"`
Tags []string `json:"tags,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Title string `json:"title,omitempty"`
Seconds string `json:"seconds,omitempty"`
PrimaryTag string `json:"primary_tag,omitempty"`
Tags []string `json:"tags,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
type SceneFile struct {
ModTime models.JSONTime `json:"mod_time,omitempty"`
Size string `json:"size"`
Duration string `json:"duration"`
VideoCodec string `json:"video_codec"`
AudioCodec string `json:"audio_codec"`
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Framerate string `json:"framerate"`
Bitrate int `json:"bitrate"`
ModTime json.JSONTime `json:"mod_time,omitempty"`
Size string `json:"size"`
Duration string `json:"duration"`
VideoCodec string `json:"video_codec"`
AudioCodec string `json:"audio_codec"`
Format string `json:"format"`
Width int `json:"width"`
Height int `json:"height"`
Framerate string `json:"framerate"`
Bitrate int `json:"bitrate"`
}
type SceneMovie struct {
@@ -54,8 +55,8 @@ type Scene struct {
Markers []SceneMarker `json:"markers,omitempty"`
File *SceneFile `json:"file,omitempty"`
Cover string `json:"cover,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
StashIDs []models.StashID `json:"stash_ids,omitempty"`
}

View File

@@ -2,26 +2,27 @@ package jsonschema
import (
"fmt"
"github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"os"
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models/json"
)
type ScrapedItem struct {
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
Date string `json:"date,omitempty"`
Rating string `json:"rating,omitempty"`
Tags string `json:"tags,omitempty"`
Models string `json:"models,omitempty"`
Episode int `json:"episode,omitempty"`
GalleryFilename string `json:"gallery_filename,omitempty"`
GalleryURL string `json:"gallery_url,omitempty"`
VideoFilename string `json:"video_filename,omitempty"`
VideoURL string `json:"video_url,omitempty"`
Studio string `json:"studio,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
URL string `json:"url,omitempty"`
Date string `json:"date,omitempty"`
Rating string `json:"rating,omitempty"`
Tags string `json:"tags,omitempty"`
Models string `json:"models,omitempty"`
Episode int `json:"episode,omitempty"`
GalleryFilename string `json:"gallery_filename,omitempty"`
GalleryURL string `json:"gallery_url,omitempty"`
VideoFilename string `json:"video_filename,omitempty"`
VideoURL string `json:"video_url,omitempty"`
Studio string `json:"studio,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
func LoadScrapedFile(filePath string) ([]ScrapedItem, error) {

View File

@@ -6,6 +6,7 @@ import (
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type Studio struct {
@@ -13,8 +14,8 @@ type Studio struct {
URL string `json:"url,omitempty"`
ParentStudio string `json:"parent_studio,omitempty"`
Image string `json:"image,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
Rating int `json:"rating,omitempty"`
Details string `json:"details,omitempty"`
Aliases []string `json:"aliases,omitempty"`

View File

@@ -5,17 +5,17 @@ import (
"os"
jsoniter "github.com/json-iterator/go"
"github.com/stashapp/stash/pkg/models"
"github.com/stashapp/stash/pkg/models/json"
)
type Tag struct {
Name string `json:"name,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Image string `json:"image,omitempty"`
Parents []string `json:"parents,omitempty"`
IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"`
CreatedAt models.JSONTime `json:"created_at,omitempty"`
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
Name string `json:"name,omitempty"`
Aliases []string `json:"aliases,omitempty"`
Image string `json:"image,omitempty"`
Parents []string `json:"parents,omitempty"`
IgnoreAutoTag bool `json:"ignore_auto_tag,omitempty"`
CreatedAt json.JSONTime `json:"created_at,omitempty"`
UpdatedAt json.JSONTime `json:"updated_at,omitempty"`
}
func LoadTagFile(filePath string) (*Tag, error) {

View File

@@ -40,6 +40,12 @@ func (gp *generatedPaths) GetTmpPath(fileName string) string {
return filepath.Join(gp.Tmp, fileName)
}
// TempFile creates a temporary file using os.CreateTemp.
// It is the equivalent of calling os.CreateTemp using Tmp and pattern.
func (gp *generatedPaths) TempFile(pattern string) (*os.File, error) {
return os.CreateTemp(gp.Tmp, pattern)
}
func (gp *generatedPaths) EnsureTmpDir() error {
return fsutil.EnsureDir(gp.Tmp)
}

View File

@@ -6,23 +6,24 @@ import (
)
type sceneMarkerPaths struct {
generated generatedPaths
generatedPaths
}
func newSceneMarkerPaths(p Paths) *sceneMarkerPaths {
sp := sceneMarkerPaths{}
sp.generated = *p.Generated
sp := sceneMarkerPaths{
generatedPaths: *p.Generated,
}
return &sp
}
func (sp *sceneMarkerPaths) GetStreamPath(checksum string, seconds int) string {
return filepath.Join(sp.generated.Markers, checksum, strconv.Itoa(seconds)+".mp4")
func (sp *sceneMarkerPaths) GetVideoPreviewPath(checksum string, seconds int) string {
return filepath.Join(sp.Markers, checksum, strconv.Itoa(seconds)+".mp4")
}
func (sp *sceneMarkerPaths) GetStreamPreviewImagePath(checksum string, seconds int) string {
return filepath.Join(sp.generated.Markers, checksum, strconv.Itoa(seconds)+".webp")
func (sp *sceneMarkerPaths) GetWebpPreviewPath(checksum string, seconds int) string {
return filepath.Join(sp.Markers, checksum, strconv.Itoa(seconds)+".webp")
}
func (sp *sceneMarkerPaths) GetStreamScreenshotPath(checksum string, seconds int) string {
return filepath.Join(sp.generated.Markers, checksum, strconv.Itoa(seconds)+".jpg")
func (sp *sceneMarkerPaths) GetScreenshotPath(checksum string, seconds int) string {
return filepath.Join(sp.Markers, checksum, strconv.Itoa(seconds)+".jpg")
}

View File

@@ -7,25 +7,26 @@ import (
)
type scenePaths struct {
generated generatedPaths
generatedPaths
}
func newScenePaths(p Paths) *scenePaths {
sp := scenePaths{}
sp.generated = *p.Generated
sp := scenePaths{
generatedPaths: *p.Generated,
}
return &sp
}
func (sp *scenePaths) GetScreenshotPath(checksum string) string {
return filepath.Join(sp.generated.Screenshots, checksum+".jpg")
return filepath.Join(sp.Screenshots, checksum+".jpg")
}
func (sp *scenePaths) GetThumbnailScreenshotPath(checksum string) string {
return filepath.Join(sp.generated.Screenshots, checksum+".thumb.jpg")
return filepath.Join(sp.Screenshots, checksum+".thumb.jpg")
}
func (sp *scenePaths) GetTranscodePath(checksum string) string {
return filepath.Join(sp.generated.Transcodes, checksum+".mp4")
return filepath.Join(sp.Transcodes, checksum+".mp4")
}
func (sp *scenePaths) GetStreamPath(scenePath string, checksum string) string {
@@ -37,22 +38,22 @@ func (sp *scenePaths) GetStreamPath(scenePath string, checksum string) string {
return scenePath
}
func (sp *scenePaths) GetStreamPreviewPath(checksum string) string {
return filepath.Join(sp.generated.Screenshots, checksum+".mp4")
func (sp *scenePaths) GetVideoPreviewPath(checksum string) string {
return filepath.Join(sp.Screenshots, checksum+".mp4")
}
func (sp *scenePaths) GetStreamPreviewImagePath(checksum string) string {
return filepath.Join(sp.generated.Screenshots, checksum+".webp")
func (sp *scenePaths) GetWebpPreviewPath(checksum string) string {
return filepath.Join(sp.Screenshots, checksum+".webp")
}
func (sp *scenePaths) GetSpriteImageFilePath(checksum string) string {
return filepath.Join(sp.generated.Vtt, checksum+"_sprite.jpg")
return filepath.Join(sp.Vtt, checksum+"_sprite.jpg")
}
func (sp *scenePaths) GetSpriteVttFilePath(checksum string) string {
return filepath.Join(sp.generated.Vtt, checksum+"_thumbs.vtt")
return filepath.Join(sp.Vtt, checksum+"_thumbs.vtt")
}
func (sp *scenePaths) GetInteractiveHeatmapPath(checksum string) string {
return filepath.Join(sp.generated.InteractiveHeatmap, checksum+".png")
return filepath.Join(sp.InteractiveHeatmap, checksum+".png")
}