node build fixed
This commit is contained in:
327
seanime-2.9.10/internal/handlers/localfiles.go
Normal file
327
seanime-2.9.10/internal/handlers/localfiles.go
Normal file
@@ -0,0 +1,327 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"seanime/internal/database/db_bridge"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/library/filesystem"
|
||||
"time"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/samber/lo"
|
||||
"github.com/sourcegraph/conc/pool"
|
||||
)
|
||||
|
||||
// HandleGetLocalFiles
|
||||
//
|
||||
// @summary returns all local files.
|
||||
// @desc Reminder that local files are scanned from the library path.
|
||||
// @route /api/v1/library/local-files [GET]
|
||||
// @returns []anime.LocalFile
|
||||
func (h *Handler) HandleGetLocalFiles(c echo.Context) error {
|
||||
|
||||
lfs, _, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, lfs)
|
||||
}
|
||||
|
||||
func (h *Handler) HandleDumpLocalFilesToFile(c echo.Context) error {
|
||||
|
||||
lfs, _, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
filename := fmt.Sprintf("seanime-localfiles-%s.json", time.Now().Format("2006-01-02_15-04-05"))
|
||||
|
||||
c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
|
||||
c.Response().Header().Set("Content-Type", "application/json")
|
||||
|
||||
jsonData, err := json.MarshalIndent(lfs, "", " ")
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return c.Blob(200, "application/json", jsonData)
|
||||
}
|
||||
|
||||
// HandleImportLocalFiles
|
||||
//
|
||||
// @summary imports local files from the given path.
|
||||
// @desc This will import local files from the given path.
|
||||
// @desc The response is ignored, the client should refetch the entire library collection and media entry.
|
||||
// @route /api/v1/library/local-files/import [POST]
|
||||
func (h *Handler) HandleImportLocalFiles(c echo.Context) error {
|
||||
type body struct {
|
||||
DataFilePath string `json:"dataFilePath"`
|
||||
}
|
||||
|
||||
b := new(body)
|
||||
if err := c.Bind(b); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
contentB, err := os.ReadFile(b.DataFilePath)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
var lfs []*anime.LocalFile
|
||||
if err := json.Unmarshal(contentB, &lfs); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
if len(lfs) == 0 {
|
||||
return h.RespondWithError(c, errors.New("no local files found"))
|
||||
}
|
||||
|
||||
_, err = db_bridge.InsertLocalFiles(h.App.Database, lfs)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
h.App.Database.TrimLocalFileEntries()
|
||||
|
||||
return h.RespondWithData(c, true)
|
||||
}
|
||||
|
||||
// HandleLocalFileBulkAction
|
||||
//
|
||||
// @summary performs an action on all local files.
|
||||
// @desc This will perform the given action on all local files.
|
||||
// @desc The response is ignored, the client should refetch the entire library collection and media entry.
|
||||
// @route /api/v1/library/local-files [POST]
|
||||
// @returns []anime.LocalFile
|
||||
func (h *Handler) HandleLocalFileBulkAction(c echo.Context) error {
|
||||
|
||||
type body struct {
|
||||
Action string `json:"action"`
|
||||
}
|
||||
|
||||
b := new(body)
|
||||
if err := c.Bind(b); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Get all the local files
|
||||
lfs, lfsId, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
switch b.Action {
|
||||
case "lock":
|
||||
for _, lf := range lfs {
|
||||
// Note: Don't lock local files that are not associated with a media.
|
||||
// Else refreshing the library will ignore them.
|
||||
if lf.MediaId != 0 {
|
||||
lf.Locked = true
|
||||
}
|
||||
}
|
||||
case "unlock":
|
||||
for _, lf := range lfs {
|
||||
lf.Locked = false
|
||||
}
|
||||
}
|
||||
|
||||
// Save the local files
|
||||
retLfs, err := db_bridge.SaveLocalFiles(h.App.Database, lfsId, lfs)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, retLfs)
|
||||
}
|
||||
|
||||
// HandleUpdateLocalFileData
|
||||
//
|
||||
// @summary updates the local file with the given path.
|
||||
// @desc This will update the local file with the given path.
|
||||
// @desc The response is ignored, the client should refetch the entire library collection and media entry.
|
||||
// @route /api/v1/library/local-file [PATCH]
|
||||
// @returns []anime.LocalFile
|
||||
func (h *Handler) HandleUpdateLocalFileData(c echo.Context) error {
|
||||
|
||||
type body struct {
|
||||
Path string `json:"path"`
|
||||
Metadata *anime.LocalFileMetadata `json:"metadata"`
|
||||
Locked bool `json:"locked"`
|
||||
Ignored bool `json:"ignored"`
|
||||
MediaId int `json:"mediaId"`
|
||||
}
|
||||
|
||||
b := new(body)
|
||||
if err := c.Bind(b); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Get all the local files
|
||||
lfs, lfsId, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
lf, found := lo.Find(lfs, func(i *anime.LocalFile) bool {
|
||||
return i.HasSamePath(b.Path)
|
||||
})
|
||||
if !found {
|
||||
return h.RespondWithError(c, errors.New("local file not found"))
|
||||
}
|
||||
lf.Metadata = b.Metadata
|
||||
lf.Locked = b.Locked
|
||||
lf.Ignored = b.Ignored
|
||||
lf.MediaId = b.MediaId
|
||||
|
||||
// Save the local files
|
||||
retLfs, err := db_bridge.SaveLocalFiles(h.App.Database, lfsId, lfs)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, retLfs)
|
||||
}
|
||||
|
||||
// HandleUpdateLocalFiles
|
||||
//
|
||||
// @summary updates local files with the given paths.
|
||||
// @desc The client should refetch the entire library collection and media entry.
|
||||
// @route /api/v1/library/local-files [PATCH]
|
||||
// @returns bool
|
||||
func (h *Handler) HandleUpdateLocalFiles(c echo.Context) error {
|
||||
|
||||
type body struct {
|
||||
Paths []string `json:"paths"`
|
||||
Action string `json:"action"`
|
||||
MediaId int `json:"mediaId,omitempty"`
|
||||
}
|
||||
|
||||
b := new(body)
|
||||
if err := c.Bind(b); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Get all the local files
|
||||
lfs, lfsId, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Update the files
|
||||
for _, path := range b.Paths {
|
||||
lf, found := lo.Find(lfs, func(i *anime.LocalFile) bool {
|
||||
return i.HasSamePath(path)
|
||||
})
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
switch b.Action {
|
||||
case "lock":
|
||||
lf.Locked = true
|
||||
case "unlock":
|
||||
lf.Locked = false
|
||||
case "ignore":
|
||||
lf.MediaId = 0
|
||||
lf.Ignored = true
|
||||
lf.Locked = false
|
||||
case "unignore":
|
||||
lf.Ignored = false
|
||||
lf.Locked = false
|
||||
case "unmatch":
|
||||
lf.MediaId = 0
|
||||
lf.Locked = false
|
||||
lf.Ignored = false
|
||||
case "match":
|
||||
lf.MediaId = b.MediaId
|
||||
lf.Locked = true
|
||||
lf.Ignored = false
|
||||
}
|
||||
}
|
||||
|
||||
// Save the local files
|
||||
_, err = db_bridge.SaveLocalFiles(h.App.Database, lfsId, lfs)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, true)
|
||||
}
|
||||
|
||||
// HandleDeleteLocalFiles
|
||||
//
|
||||
// @summary deletes local files with the given paths.
|
||||
// @desc This will delete the local files with the given paths.
|
||||
// @desc The client should refetch the entire library collection and media entry.
|
||||
// @route /api/v1/library/local-files [DELETE]
|
||||
// @returns bool
|
||||
func (h *Handler) HandleDeleteLocalFiles(c echo.Context) error {
|
||||
|
||||
type body struct {
|
||||
Paths []string `json:"paths"`
|
||||
}
|
||||
|
||||
b := new(body)
|
||||
if err := c.Bind(b); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Get all the local files
|
||||
lfs, lfsId, err := db_bridge.GetLocalFiles(h.App.Database)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Delete the files
|
||||
p := pool.New().WithErrors()
|
||||
for _, path := range b.Paths {
|
||||
path := path
|
||||
p.Go(func() error {
|
||||
err := os.Remove(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if err := p.Wait(); err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
// Remove the files from the list
|
||||
lfs = lo.Filter(lfs, func(i *anime.LocalFile, _ int) bool {
|
||||
return !lo.Contains(b.Paths, i.Path)
|
||||
})
|
||||
|
||||
// Save the local files
|
||||
_, err = db_bridge.SaveLocalFiles(h.App.Database, lfsId, lfs)
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, true)
|
||||
}
|
||||
|
||||
// HandleRemoveEmptyDirectories
|
||||
//
|
||||
// @summary removes empty directories.
|
||||
// @desc This will remove empty directories in the library path.
|
||||
// @route /api/v1/library/empty-directories [DELETE]
|
||||
// @returns bool
|
||||
func (h *Handler) HandleRemoveEmptyDirectories(c echo.Context) error {
|
||||
|
||||
libraryPaths, err := h.App.Database.GetAllLibraryPathsFromSettings()
|
||||
if err != nil {
|
||||
return h.RespondWithError(c, err)
|
||||
}
|
||||
|
||||
for _, path := range libraryPaths {
|
||||
filesystem.RemoveEmptyDirectories(path, h.App.Logger)
|
||||
}
|
||||
|
||||
return h.RespondWithData(c, true)
|
||||
}
|
||||
Reference in New Issue
Block a user