node build fixed

This commit is contained in:
ra_ma
2025-09-20 14:08:38 +01:00
parent c6ebbe069d
commit 3d298fa434
1516 changed files with 535727 additions and 2 deletions

View File

@@ -0,0 +1,264 @@
package handlers
import (
"errors"
"path/filepath"
"seanime/internal/api/anilist"
"seanime/internal/database/db_bridge"
"seanime/internal/events"
hibiketorrent "seanime/internal/extension/hibike/torrent"
"seanime/internal/torrent_clients/torrent_client"
"seanime/internal/util"
"github.com/labstack/echo/v4"
)
// HandleGetActiveTorrentList
//
// @summary returns all active torrents.
// @desc This handler is used by the client to display the active torrents.
//
// @route /api/v1/torrent-client/list [GET]
// @returns []torrent_client.Torrent
func (h *Handler) HandleGetActiveTorrentList(c echo.Context) error {
// Get torrent list
res, err := h.App.TorrentClientRepository.GetActiveTorrents()
// If an error occurred, try to start the torrent client and get the list again
// DEVNOTE: We try to get the list first because this route is called repeatedly by the client.
if err != nil {
ok := h.App.TorrentClientRepository.Start()
if !ok {
return h.RespondWithError(c, errors.New("could not start torrent client, verify your settings"))
}
res, err = h.App.TorrentClientRepository.GetActiveTorrents()
}
return h.RespondWithData(c, res)
}
// HandleTorrentClientAction
//
// @summary performs an action on a torrent.
// @desc This handler is used to pause, resume or remove a torrent.
// @route /api/v1/torrent-client/action [POST]
// @returns bool
func (h *Handler) HandleTorrentClientAction(c echo.Context) error {
type body struct {
Hash string `json:"hash"`
Action string `json:"action"`
Dir string `json:"dir"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
if b.Hash == "" || b.Action == "" {
return h.RespondWithError(c, errors.New("missing arguments"))
}
switch b.Action {
case "pause":
err := h.App.TorrentClientRepository.PauseTorrents([]string{b.Hash})
if err != nil {
return h.RespondWithError(c, err)
}
case "resume":
err := h.App.TorrentClientRepository.ResumeTorrents([]string{b.Hash})
if err != nil {
return h.RespondWithError(c, err)
}
case "remove":
err := h.App.TorrentClientRepository.RemoveTorrents([]string{b.Hash})
if err != nil {
return h.RespondWithError(c, err)
}
case "open":
if b.Dir == "" {
return h.RespondWithError(c, errors.New("directory not found"))
}
OpenDirInExplorer(b.Dir)
}
return h.RespondWithData(c, true)
}
// HandleTorrentClientDownload
//
// @summary adds torrents to the torrent client.
// @desc It fetches the magnets from the provided URLs and adds them to the torrent client.
// @desc If smart select is enabled, it will try to select the best torrent based on the missing episodes.
// @route /api/v1/torrent-client/download [POST]
// @returns bool
func (h *Handler) HandleTorrentClientDownload(c echo.Context) error {
type body struct {
Torrents []hibiketorrent.AnimeTorrent `json:"torrents"`
Destination string `json:"destination"`
SmartSelect struct {
Enabled bool `json:"enabled"`
MissingEpisodeNumbers []int `json:"missingEpisodeNumbers"`
} `json:"smartSelect"`
Media *anilist.BaseAnime `json:"media"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
if b.Destination == "" {
return h.RespondWithError(c, errors.New("destination not found"))
}
if !filepath.IsAbs(b.Destination) {
return h.RespondWithError(c, errors.New("destination path must be absolute"))
}
// Check that the destination path is a library path
//libraryPaths, err := h.App.Database.GetAllLibraryPathsFromSettings()
//if err != nil {
// return h.RespondWithError(c, err)
//}
//isInLibrary := util.IsSubdirectoryOfAny(libraryPaths, b.Destination)
//if !isInLibrary {
// return h.RespondWithError(c, errors.New("destination path is not a library path"))
//}
// try to start torrent client if it's not running
ok := h.App.TorrentClientRepository.Start()
if !ok {
return h.RespondWithError(c, errors.New("could not contact torrent client, verify your settings or make sure it's running"))
}
completeAnime, err := h.App.AnilistPlatform.GetAnimeWithRelations(c.Request().Context(), b.Media.ID)
if err != nil {
return h.RespondWithError(c, err)
}
if b.SmartSelect.Enabled {
if len(b.Torrents) > 1 {
return h.RespondWithError(c, errors.New("smart select is not supported for multiple torrents"))
}
// smart select
err = h.App.TorrentClientRepository.SmartSelect(&torrent_client.SmartSelectParams{
Torrent: &b.Torrents[0],
EpisodeNumbers: b.SmartSelect.MissingEpisodeNumbers,
Media: completeAnime,
Destination: b.Destination,
Platform: h.App.AnilistPlatform,
ShouldAddTorrent: true,
})
if err != nil {
return h.RespondWithError(c, err)
}
} else {
// Get magnets
magnets := make([]string, 0)
for _, t := range b.Torrents {
// Get the torrent's provider extension
providerExtension, ok := h.App.TorrentRepository.GetAnimeProviderExtension(t.Provider)
if !ok {
return h.RespondWithError(c, errors.New("provider extension not found for torrent"))
}
// Get the torrent magnet link
magnet, err := providerExtension.GetProvider().GetTorrentMagnetLink(&t)
if err != nil {
return h.RespondWithError(c, err)
}
magnets = append(magnets, magnet)
}
// try to add torrents to client, on error return error
err = h.App.TorrentClientRepository.AddMagnets(magnets, b.Destination)
if err != nil {
return h.RespondWithError(c, err)
}
}
// Add the media to the collection (if it wasn't already)
go func() {
defer util.HandlePanicInModuleThen("handlers/HandleTorrentClientDownload", func() {})
if b.Media != nil {
// Check if the media is already in the collection
animeCollection, err := h.App.GetAnimeCollection(false)
if err != nil {
return
}
_, found := animeCollection.FindAnime(b.Media.ID)
if found {
return
}
// Add the media to the collection
err = h.App.AnilistPlatform.AddMediaToCollection(c.Request().Context(), []int{b.Media.ID})
if err != nil {
h.App.Logger.Error().Err(err).Msg("anilist: Failed to add media to collection")
}
ac, _ := h.App.RefreshAnimeCollection()
h.App.WSEventManager.SendEvent(events.RefreshedAnilistAnimeCollection, ac)
}
}()
return h.RespondWithData(c, true)
}
// HandleTorrentClientAddMagnetFromRule
//
// @summary adds magnets to the torrent client based on the AutoDownloader item.
// @desc This is used to download torrents that were queued by the AutoDownloader.
// @desc The item will be removed from the queue if the magnet was added successfully.
// @desc The AutoDownloader items should be re-fetched after this.
// @route /api/v1/torrent-client/rule-magnet [POST]
// @returns bool
func (h *Handler) HandleTorrentClientAddMagnetFromRule(c echo.Context) error {
type body struct {
MagnetUrl string `json:"magnetUrl"`
RuleId uint `json:"ruleId"`
QueuedItemId uint `json:"queuedItemId"`
}
var b body
if err := c.Bind(&b); err != nil {
return h.RespondWithError(c, err)
}
if b.MagnetUrl == "" || b.RuleId == 0 {
return h.RespondWithError(c, errors.New("missing parameters"))
}
// Get rule from database
rule, err := db_bridge.GetAutoDownloaderRule(h.App.Database, b.RuleId)
if err != nil {
return h.RespondWithError(c, err)
}
// try to start torrent client if it's not running
ok := h.App.TorrentClientRepository.Start()
if !ok {
return h.RespondWithError(c, errors.New("could not start torrent client, verify your settings"))
}
// try to add torrents to client, on error return error
err = h.App.TorrentClientRepository.AddMagnets([]string{b.MagnetUrl}, rule.Destination)
if err != nil {
return h.RespondWithError(c, err)
}
if b.QueuedItemId > 0 {
// the magnet was added successfully, remove the item from the queue
err = h.App.Database.DeleteAutoDownloaderItem(b.QueuedItemId)
}
return h.RespondWithData(c, true)
}