mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 12:24:38 +03:00
Added created / updated timestamp to exported JSON
This commit is contained in:
@@ -3,6 +3,7 @@ package jsonschema
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -24,6 +25,8 @@ type Performer struct {
|
|||||||
Aliases string `json:"aliases,omitempty"`
|
Aliases string `json:"aliases,omitempty"`
|
||||||
Favorite bool `json:"favorite,omitempty"`
|
Favorite bool `json:"favorite,omitempty"`
|
||||||
Image string `json:"image,omitempty"`
|
Image string `json:"image,omitempty"`
|
||||||
|
CreatedAt models.JSONTime `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadPerformerFile(filePath string) (*Performer, error) {
|
func LoadPerformerFile(filePath string) (*Performer, error) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package jsonschema
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -11,6 +12,8 @@ type SceneMarker struct {
|
|||||||
Seconds string `json:"seconds,omitempty"`
|
Seconds string `json:"seconds,omitempty"`
|
||||||
PrimaryTag string `json:"primary_tag,omitempty"`
|
PrimaryTag string `json:"primary_tag,omitempty"`
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
CreatedAt models.JSONTime `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SceneFile struct {
|
type SceneFile struct {
|
||||||
@@ -36,6 +39,8 @@ type Scene struct {
|
|||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
Markers []SceneMarker `json:"markers,omitempty"`
|
Markers []SceneMarker `json:"markers,omitempty"`
|
||||||
File *SceneFile `json:"file,omitempty"`
|
File *SceneFile `json:"file,omitempty"`
|
||||||
|
CreatedAt models.JSONTime `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadSceneFile(filePath string) (*Scene, error) {
|
func LoadSceneFile(filePath string) (*Scene, error) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package jsonschema
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/stashapp/stash/pkg/models"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -10,6 +11,8 @@ type Studio struct {
|
|||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
Image string `json:"image,omitempty"`
|
Image string `json:"image,omitempty"`
|
||||||
|
CreatedAt models.JSONTime `json:"created_at,omitempty"`
|
||||||
|
UpdatedAt models.JSONTime `json:"updated_at,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadStudioFile(filePath string) (*Studio, error) {
|
func LoadStudioFile(filePath string) (*Studio, error) {
|
||||||
|
|||||||
@@ -60,7 +60,10 @@ func (t *ExportTask) ExportScenes(ctx context.Context) {
|
|||||||
logger.Progressf("[scenes] %d of %d", index, len(scenes))
|
logger.Progressf("[scenes] %d of %d", index, len(scenes))
|
||||||
|
|
||||||
t.Mappings.Scenes = append(t.Mappings.Scenes, jsonschema.PathMapping{Path: scene.Path, Checksum: scene.Checksum})
|
t.Mappings.Scenes = append(t.Mappings.Scenes, jsonschema.PathMapping{Path: scene.Path, Checksum: scene.Checksum})
|
||||||
newSceneJSON := jsonschema.Scene{}
|
newSceneJSON := jsonschema.Scene{
|
||||||
|
CreatedAt: models.JSONTime{Time: scene.CreatedAt.Timestamp},
|
||||||
|
UpdatedAt: models.JSONTime{Time: scene.UpdatedAt.Timestamp},
|
||||||
|
}
|
||||||
|
|
||||||
var studioName string
|
var studioName string
|
||||||
if scene.StudioID.Valid {
|
if scene.StudioID.Valid {
|
||||||
@@ -129,6 +132,8 @@ func (t *ExportTask) ExportScenes(ctx context.Context) {
|
|||||||
Seconds: t.getDecimalString(sceneMarker.Seconds),
|
Seconds: t.getDecimalString(sceneMarker.Seconds),
|
||||||
PrimaryTag: primaryTag.Name,
|
PrimaryTag: primaryTag.Name,
|
||||||
Tags: t.getTagNames(sceneMarkerTags),
|
Tags: t.getTagNames(sceneMarkerTags),
|
||||||
|
CreatedAt: models.JSONTime{Time: sceneMarker.CreatedAt.Timestamp},
|
||||||
|
UpdatedAt: models.JSONTime{Time: sceneMarker.UpdatedAt.Timestamp},
|
||||||
}
|
}
|
||||||
|
|
||||||
newSceneJSON.Markers = append(newSceneJSON.Markers, sceneMarkerJSON)
|
newSceneJSON.Markers = append(newSceneJSON.Markers, sceneMarkerJSON)
|
||||||
@@ -208,7 +213,10 @@ func (t *ExportTask) ExportPerformers(ctx context.Context) {
|
|||||||
|
|
||||||
t.Mappings.Performers = append(t.Mappings.Performers, jsonschema.NameMapping{Name: performer.Name.String, Checksum: performer.Checksum})
|
t.Mappings.Performers = append(t.Mappings.Performers, jsonschema.NameMapping{Name: performer.Name.String, Checksum: performer.Checksum})
|
||||||
|
|
||||||
newPerformerJSON := jsonschema.Performer{}
|
newPerformerJSON := jsonschema.Performer{
|
||||||
|
CreatedAt: models.JSONTime{Time: performer.CreatedAt.Timestamp},
|
||||||
|
UpdatedAt: models.JSONTime{Time: performer.UpdatedAt.Timestamp},
|
||||||
|
}
|
||||||
|
|
||||||
if performer.Name.Valid {
|
if performer.Name.Valid {
|
||||||
newPerformerJSON.Name = performer.Name.String
|
newPerformerJSON.Name = performer.Name.String
|
||||||
@@ -291,7 +299,10 @@ func (t *ExportTask) ExportStudios(ctx context.Context) {
|
|||||||
|
|
||||||
t.Mappings.Studios = append(t.Mappings.Studios, jsonschema.NameMapping{Name: studio.Name.String, Checksum: studio.Checksum})
|
t.Mappings.Studios = append(t.Mappings.Studios, jsonschema.NameMapping{Name: studio.Name.String, Checksum: studio.Checksum})
|
||||||
|
|
||||||
newStudioJSON := jsonschema.Studio{}
|
newStudioJSON := jsonschema.Studio{
|
||||||
|
CreatedAt: models.JSONTime{Time: studio.CreatedAt.Timestamp},
|
||||||
|
UpdatedAt: models.JSONTime{Time: studio.UpdatedAt.Timestamp},
|
||||||
|
}
|
||||||
|
|
||||||
if studio.Name.Valid {
|
if studio.Name.Valid {
|
||||||
newStudioJSON.Name = studio.Name.String
|
newStudioJSON.Name = studio.Name.String
|
||||||
|
|||||||
@@ -73,13 +73,12 @@ func (t *ImportTask) ImportPerformers(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populate a new performer from the input
|
// Populate a new performer from the input
|
||||||
currentTime := time.Now()
|
|
||||||
newPerformer := models.Performer{
|
newPerformer := models.Performer{
|
||||||
Image: imageData,
|
Image: imageData,
|
||||||
Checksum: checksum,
|
Checksum: checksum,
|
||||||
Favorite: sql.NullBool{Bool: performerJSON.Favorite, Valid: true},
|
Favorite: sql.NullBool{Bool: performerJSON.Favorite, Valid: true},
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(performerJSON.CreatedAt)},
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(performerJSON.UpdatedAt)},
|
||||||
}
|
}
|
||||||
|
|
||||||
if performerJSON.Name != "" {
|
if performerJSON.Name != "" {
|
||||||
@@ -169,14 +168,13 @@ func (t *ImportTask) ImportStudios(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Populate a new studio from the input
|
// Populate a new studio from the input
|
||||||
currentTime := time.Now()
|
|
||||||
newStudio := models.Studio{
|
newStudio := models.Studio{
|
||||||
Image: imageData,
|
Image: imageData,
|
||||||
Checksum: checksum,
|
Checksum: checksum,
|
||||||
Name: sql.NullString{String: studioJSON.Name, Valid: true},
|
Name: sql.NullString{String: studioJSON.Name, Valid: true},
|
||||||
URL: sql.NullString{String: studioJSON.URL, Valid: true},
|
URL: sql.NullString{String: studioJSON.URL, Valid: true},
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(studioJSON.CreatedAt)},
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(studioJSON.UpdatedAt)},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = qb.Create(newStudio, tx)
|
_, err = qb.Create(newStudio, tx)
|
||||||
@@ -308,12 +306,6 @@ func (t *ImportTask) ImportScrapedItems(ctx context.Context) {
|
|||||||
index := i + 1
|
index := i + 1
|
||||||
logger.Progressf("[scraped sites] %d of %d", index, len(t.Mappings.Scenes))
|
logger.Progressf("[scraped sites] %d of %d", index, len(t.Mappings.Scenes))
|
||||||
|
|
||||||
var updatedAt time.Time
|
|
||||||
if currentTime.Location() != nil {
|
|
||||||
updatedAt = mappingJSON.UpdatedAt.Time.In(currentTime.Location())
|
|
||||||
} else {
|
|
||||||
updatedAt = mappingJSON.UpdatedAt.Time
|
|
||||||
}
|
|
||||||
newScrapedItem := models.ScrapedItem{
|
newScrapedItem := models.ScrapedItem{
|
||||||
Title: sql.NullString{String: mappingJSON.Title, Valid: true},
|
Title: sql.NullString{String: mappingJSON.Title, Valid: true},
|
||||||
Description: sql.NullString{String: mappingJSON.Description, Valid: true},
|
Description: sql.NullString{String: mappingJSON.Description, Valid: true},
|
||||||
@@ -328,7 +320,7 @@ func (t *ImportTask) ImportScrapedItems(ctx context.Context) {
|
|||||||
VideoFilename: sql.NullString{String: mappingJSON.VideoFilename, Valid: true},
|
VideoFilename: sql.NullString{String: mappingJSON.VideoFilename, Valid: true},
|
||||||
VideoURL: sql.NullString{String: mappingJSON.VideoURL, Valid: true},
|
VideoURL: sql.NullString{String: mappingJSON.VideoURL, Valid: true},
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: updatedAt},
|
UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(mappingJSON.UpdatedAt)},
|
||||||
}
|
}
|
||||||
|
|
||||||
studio, err := sqb.FindByName(mappingJSON.Studio, tx)
|
studio, err := sqb.FindByName(mappingJSON.Studio, tx)
|
||||||
@@ -356,7 +348,6 @@ func (t *ImportTask) ImportScenes(ctx context.Context) {
|
|||||||
tx := database.DB.MustBeginTx(ctx, nil)
|
tx := database.DB.MustBeginTx(ctx, nil)
|
||||||
qb := models.NewSceneQueryBuilder()
|
qb := models.NewSceneQueryBuilder()
|
||||||
jqb := models.NewJoinsQueryBuilder()
|
jqb := models.NewJoinsQueryBuilder()
|
||||||
currentTime := time.Now()
|
|
||||||
|
|
||||||
for i, mappingJSON := range t.Mappings.Scenes {
|
for i, mappingJSON := range t.Mappings.Scenes {
|
||||||
index := i + 1
|
index := i + 1
|
||||||
@@ -371,8 +362,6 @@ func (t *ImportTask) ImportScenes(ctx context.Context) {
|
|||||||
newScene := models.Scene{
|
newScene := models.Scene{
|
||||||
Checksum: mappingJSON.Checksum,
|
Checksum: mappingJSON.Checksum,
|
||||||
Path: mappingJSON.Path,
|
Path: mappingJSON.Path,
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sceneJSON, err := instance.JSON.getScene(mappingJSON.Checksum)
|
sceneJSON, err := instance.JSON.getScene(mappingJSON.Checksum)
|
||||||
@@ -398,6 +387,8 @@ func (t *ImportTask) ImportScenes(ctx context.Context) {
|
|||||||
if sceneJSON.Rating != 0 {
|
if sceneJSON.Rating != 0 {
|
||||||
newScene.Rating = sql.NullInt64{Int64: int64(sceneJSON.Rating), Valid: true}
|
newScene.Rating = sql.NullInt64{Int64: int64(sceneJSON.Rating), Valid: true}
|
||||||
}
|
}
|
||||||
|
newScene.CreatedAt = models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(sceneJSON.CreatedAt)}
|
||||||
|
newScene.UpdatedAt = models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(sceneJSON.UpdatedAt)}
|
||||||
|
|
||||||
if sceneJSON.File != nil {
|
if sceneJSON.File != nil {
|
||||||
if sceneJSON.File.Size != "" {
|
if sceneJSON.File.Size != "" {
|
||||||
@@ -520,8 +511,8 @@ func (t *ImportTask) ImportScenes(ctx context.Context) {
|
|||||||
Title: marker.Title,
|
Title: marker.Title,
|
||||||
Seconds: seconds,
|
Seconds: seconds,
|
||||||
SceneID: sql.NullInt64{Int64: int64(scene.ID), Valid: true},
|
SceneID: sql.NullInt64{Int64: int64(scene.ID), Valid: true},
|
||||||
CreatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
CreatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(marker.CreatedAt)},
|
||||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: currentTime},
|
UpdatedAt: models.SQLiteTimestamp{Timestamp: t.getTimeFromJSONTime(marker.UpdatedAt)},
|
||||||
}
|
}
|
||||||
|
|
||||||
primaryTag, err := tqb.FindByName(marker.PrimaryTag, tx)
|
primaryTag, err := tqb.FindByName(marker.PrimaryTag, tx)
|
||||||
@@ -636,3 +627,21 @@ func (t *ImportTask) getUnique(s []string) []string {
|
|||||||
}
|
}
|
||||||
return s[:j]
|
return s[:j]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentLocation = time.Now().Location()
|
||||||
|
|
||||||
|
func (t *ImportTask) getTimeFromJSONTime(jsonTime models.JSONTime) time.Time {
|
||||||
|
if currentLocation != nil {
|
||||||
|
if jsonTime.IsZero() {
|
||||||
|
return time.Now().In(currentLocation)
|
||||||
|
} else {
|
||||||
|
return jsonTime.Time.In(currentLocation)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if jsonTime.IsZero() {
|
||||||
|
return time.Now()
|
||||||
|
} else {
|
||||||
|
return jsonTime.Time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
|
// Btoi transforms a boolean to an int. 1 for true, false otherwise
|
||||||
func Btoi(b bool) int {
|
func Btoi(b bool) int {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FileType uses the filetype package to determine the given file path's type
|
||||||
func FileType(filePath string) (types.Type, error) {
|
func FileType(filePath string) (types.Type, error) {
|
||||||
file, _ := os.Open(filePath)
|
file, _ := os.Open(filePath)
|
||||||
|
|
||||||
@@ -20,6 +21,7 @@ func FileType(filePath string) (types.Type, error) {
|
|||||||
return filetype.Match(head)
|
return filetype.Match(head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileExists returns true if the given path exists
|
||||||
func FileExists(path string) (bool, error) {
|
func FileExists(path string) (bool, error) {
|
||||||
_, err := os.Stat(path)
|
_, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -31,6 +33,7 @@ func FileExists(path string) (bool, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DirExists returns true if the given path exists and is a directory
|
||||||
func DirExists(path string) (bool, error) {
|
func DirExists(path string) (bool, error) {
|
||||||
exists, _ := FileExists(path)
|
exists, _ := FileExists(path)
|
||||||
fileInfo, _ := os.Stat(path)
|
fileInfo, _ := os.Stat(path)
|
||||||
@@ -40,6 +43,7 @@ func DirExists(path string) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Touch creates an empty file at the given path if it doesn't already exist
|
||||||
func Touch(path string) error {
|
func Touch(path string) error {
|
||||||
var _, err = os.Stat(path)
|
var _, err = os.Stat(path)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@@ -52,6 +56,7 @@ func Touch(path string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnsureDir will create a directory at the given path if it doesn't already exist
|
||||||
func EnsureDir(path string) error {
|
func EnsureDir(path string) error {
|
||||||
exists, err := FileExists(path)
|
exists, err := FileExists(path)
|
||||||
if !exists {
|
if !exists {
|
||||||
@@ -61,10 +66,12 @@ func EnsureDir(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveDir removes the given file path along with all of its contents
|
||||||
func RemoveDir(path string) error {
|
func RemoveDir(path string) error {
|
||||||
return os.RemoveAll(path)
|
return os.RemoveAll(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EmptyDir will recursively remove the contents of a directory at the given path
|
||||||
func EmptyDir(path string) error {
|
func EmptyDir(path string) error {
|
||||||
d, err := os.Open(path)
|
d, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -87,6 +94,7 @@ func EmptyDir(path string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListDir will return the contents of a given directory path as a string slice
|
||||||
func ListDir(path string) []string {
|
func ListDir(path string) []string {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
path = GetHomeDirectory()
|
path = GetHomeDirectory()
|
||||||
@@ -117,6 +125,7 @@ func ListDir(path string) []string {
|
|||||||
return dirPaths
|
return dirPaths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHomeDirectory returns the path of the user's home directory. ~ on Unix and C:\Users\UserName on Windows
|
||||||
func GetHomeDirectory() string {
|
func GetHomeDirectory() string {
|
||||||
currentUser, err := user.Current()
|
currentUser, err := user.Current()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ProcessBase64Image transforms a base64 encoded string from a form post and returns the MD5 hash of the data and the
|
||||||
|
// image itself as a byte slice.
|
||||||
func ProcessBase64Image(imageString string) (string, []byte, error) {
|
func ProcessBase64Image(imageString string) (string, []byte, error) {
|
||||||
if imageString == "" {
|
if imageString == "" {
|
||||||
return "", nil, fmt.Errorf("empty image string")
|
return "", nil, fmt.Errorf("empty image string")
|
||||||
@@ -27,10 +29,12 @@ func ProcessBase64Image(imageString string) (string, []byte, error) {
|
|||||||
return MD5FromBytes(imageData), imageData, nil
|
return MD5FromBytes(imageData), imageData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDataFromBase64String returns the given base64 encoded string as a byte slice
|
||||||
func GetDataFromBase64String(encodedString string) ([]byte, error) {
|
func GetDataFromBase64String(encodedString string) ([]byte, error) {
|
||||||
return base64.StdEncoding.DecodeString(encodedString)
|
return base64.StdEncoding.DecodeString(encodedString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBase64StringFromData returns the given byte slice as a base64 encoded string
|
||||||
func GetBase64StringFromData(data []byte) string {
|
func GetBase64StringFromData(data []byte) string {
|
||||||
return base64.StdEncoding.EncodeToString(data)
|
return base64.StdEncoding.EncodeToString(data)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user