Files
seanime-docker/seanime-2.9.10/internal/handlers/playlist.go
2025-09-20 14:08:38 +01:00

186 lines
4.3 KiB
Go

package handlers
import (
"errors"
"github.com/labstack/echo/v4"
"seanime/internal/database/db_bridge"
"seanime/internal/library/anime"
"seanime/internal/util"
"strconv"
)
// HandleCreatePlaylist
//
// @summary creates a new playlist.
// @desc This will create a new playlist with the given name and local file paths.
// @desc The response is ignored, the client should re-fetch the playlists after this.
// @route /api/v1/playlist [POST]
// @returns anime.Playlist
func (h *Handler) HandleCreatePlaylist(c echo.Context) error {
type body struct {
Name string `json:"name"`
Paths []string `json:"paths"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
// Get the local files
dbLfs, _, err := db_bridge.GetLocalFiles(h.App.Database)
if err != nil {
return h.RespondWithError(c, err)
}
// Filter the local files
lfs := make([]*anime.LocalFile, 0)
for _, path := range b.Paths {
for _, lf := range dbLfs {
if lf.GetNormalizedPath() == util.NormalizePath(path) {
lfs = append(lfs, lf)
break
}
}
}
// Create the playlist
playlist := anime.NewPlaylist(b.Name)
playlist.SetLocalFiles(lfs)
// Save the playlist
if err := db_bridge.SavePlaylist(h.App.Database, playlist); err != nil {
return h.RespondWithError(c, err)
}
return h.RespondWithData(c, playlist)
}
// HandleGetPlaylists
//
// @summary returns all playlists.
// @route /api/v1/playlists [GET]
// @returns []anime.Playlist
func (h *Handler) HandleGetPlaylists(c echo.Context) error {
playlists, err := db_bridge.GetPlaylists(h.App.Database)
if err != nil {
return h.RespondWithError(c, err)
}
return h.RespondWithData(c, playlists)
}
// HandleUpdatePlaylist
//
// @summary updates a playlist.
// @returns the updated playlist
// @desc The response is ignored, the client should re-fetch the playlists after this.
// @route /api/v1/playlist [PATCH]
// @param id - int - true - "The ID of the playlist to update."
// @returns anime.Playlist
func (h *Handler) HandleUpdatePlaylist(c echo.Context) error {
type body struct {
DbId uint `json:"dbId"`
Name string `json:"name"`
Paths []string `json:"paths"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
// Get the local files
dbLfs, _, err := db_bridge.GetLocalFiles(h.App.Database)
if err != nil {
return h.RespondWithError(c, err)
}
// Filter the local files
lfs := make([]*anime.LocalFile, 0)
for _, path := range b.Paths {
for _, lf := range dbLfs {
if lf.GetNormalizedPath() == util.NormalizePath(path) {
lfs = append(lfs, lf)
break
}
}
}
// Recreate playlist
playlist := anime.NewPlaylist(b.Name)
playlist.DbId = b.DbId
playlist.Name = b.Name
playlist.SetLocalFiles(lfs)
// Save the playlist
if err := db_bridge.UpdatePlaylist(h.App.Database, playlist); err != nil {
return h.RespondWithError(c, err)
}
return h.RespondWithData(c, playlist)
}
// HandleDeletePlaylist
//
// @summary deletes a playlist.
// @route /api/v1/playlist [DELETE]
// @returns bool
func (h *Handler) HandleDeletePlaylist(c echo.Context) error {
type body struct {
DbId uint `json:"dbId"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
if err := db_bridge.DeletePlaylist(h.App.Database, b.DbId); err != nil {
return h.RespondWithError(c, err)
}
return h.RespondWithData(c, true)
}
// HandleGetPlaylistEpisodes
//
// @summary returns all the local files of a playlist media entry that have not been watched.
// @route /api/v1/playlist/episodes/{id}/{progress} [GET]
// @param id - int - true - "The ID of the media entry."
// @param progress - int - true - "The progress of the media entry."
// @returns []anime.LocalFile
func (h *Handler) HandleGetPlaylistEpisodes(c echo.Context) error {
lfs, _, err := db_bridge.GetLocalFiles(h.App.Database)
if err != nil {
return h.RespondWithError(c, err)
}
lfw := anime.NewLocalFileWrapper(lfs)
// Params
mId, err := strconv.Atoi(c.Param("id"))
if err != nil {
return h.RespondWithError(c, err)
}
progress, err := strconv.Atoi(c.Param("progress"))
if err != nil {
return h.RespondWithError(c, err)
}
group, found := lfw.GetLocalEntryById(mId)
if !found {
return h.RespondWithError(c, errors.New("media entry not found"))
}
toWatch := group.GetUnwatchedLocalFiles(progress)
return h.RespondWithData(c, toWatch)
}