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,255 @@
package debrid_client
import (
"context"
"fmt"
"path/filepath"
"seanime/internal/api/anilist"
"seanime/internal/api/metadata"
"seanime/internal/database/db"
"seanime/internal/database/models"
"seanime/internal/debrid/debrid"
"seanime/internal/debrid/realdebrid"
"seanime/internal/debrid/torbox"
"seanime/internal/directstream"
"seanime/internal/events"
"seanime/internal/library/playbackmanager"
"seanime/internal/platforms/platform"
"seanime/internal/torrents/torrent"
"seanime/internal/util/result"
"github.com/rs/zerolog"
"github.com/samber/mo"
)
var (
ErrProviderNotSet = fmt.Errorf("debrid: Provider not set")
)
type (
Repository struct {
provider mo.Option[debrid.Provider]
logger *zerolog.Logger
db *db.Database
settings *models.DebridSettings
wsEventManager events.WSEventManagerInterface
ctxMap *result.Map[string, context.CancelFunc]
downloadLoopCancelFunc context.CancelFunc
torrentRepository *torrent.Repository
directStreamManager *directstream.Manager
playbackManager *playbackmanager.PlaybackManager
streamManager *StreamManager
completeAnimeCache *anilist.CompleteAnimeCache
metadataProvider metadata.Provider
platform platform.Platform
previousStreamOptions mo.Option[*StartStreamOptions]
}
NewRepositoryOptions struct {
Logger *zerolog.Logger
WSEventManager events.WSEventManagerInterface
Database *db.Database
TorrentRepository *torrent.Repository
PlaybackManager *playbackmanager.PlaybackManager
DirectStreamManager *directstream.Manager
MetadataProvider metadata.Provider
Platform platform.Platform
}
)
func NewRepository(opts *NewRepositoryOptions) (ret *Repository) {
ret = &Repository{
provider: mo.None[debrid.Provider](),
logger: opts.Logger,
wsEventManager: opts.WSEventManager,
db: opts.Database,
settings: &models.DebridSettings{
Enabled: false,
},
torrentRepository: opts.TorrentRepository,
platform: opts.Platform,
playbackManager: opts.PlaybackManager,
metadataProvider: opts.MetadataProvider,
completeAnimeCache: anilist.NewCompleteAnimeCache(),
ctxMap: result.NewResultMap[string, context.CancelFunc](),
previousStreamOptions: mo.None[*StartStreamOptions](),
directStreamManager: opts.DirectStreamManager,
}
ret.streamManager = NewStreamManager(ret)
return
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func (r *Repository) startOrStopDownloadLoop() {
// Cancel the previous download loop if it's running
if r.downloadLoopCancelFunc != nil {
r.downloadLoopCancelFunc()
}
// Start the download loop if the provider is set and enabled
if r.settings.Enabled && r.provider.IsPresent() {
ctx, cancel := context.WithCancel(context.Background())
r.downloadLoopCancelFunc = cancel
r.launchDownloadLoop(ctx)
}
}
// InitializeProvider is called each time the settings change
func (r *Repository) InitializeProvider(settings *models.DebridSettings) error {
r.settings = settings
if !settings.Enabled {
r.provider = mo.None[debrid.Provider]()
// Stop the download loop if it's running
r.startOrStopDownloadLoop()
return nil
}
switch settings.Provider {
case "torbox":
r.provider = mo.Some(torbox.NewTorBox(r.logger))
case "realdebrid":
r.provider = mo.Some(realdebrid.NewRealDebrid(r.logger))
default:
r.provider = mo.None[debrid.Provider]()
}
if r.provider.IsAbsent() {
r.logger.Warn().Str("provider", settings.Provider).Msg("debrid: No provider set")
// Stop the download loop if it's running
r.startOrStopDownloadLoop()
return nil
}
// Authenticate the provider
err := r.provider.MustGet().Authenticate(r.settings.ApiKey)
if err != nil {
r.logger.Err(err).Msg("debrid: Failed to authenticate")
r.provider = mo.None[debrid.Provider]()
// Cancel the download loop if it's running
if r.downloadLoopCancelFunc != nil {
r.downloadLoopCancelFunc()
}
return err
}
// Start the download loop
r.startOrStopDownloadLoop()
return nil
}
func (r *Repository) GetProvider() (debrid.Provider, error) {
p, found := r.provider.Get()
if !found {
return nil, ErrProviderNotSet
}
return p, nil
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// AddAndQueueTorrent adds a torrent to the debrid service and queues it for automatic download
func (r *Repository) AddAndQueueTorrent(opts debrid.AddTorrentOptions, destination string, mId int) (string, error) {
provider, err := r.GetProvider()
if err != nil {
return "", err
}
if !filepath.IsAbs(destination) {
return "", fmt.Errorf("debrid: Failed to add torrent, destination must be an absolute path")
}
// Add the torrent to the debrid service
torrentItemId, err := provider.AddTorrent(opts)
if err != nil {
return "", err
}
// Add the torrent item to the database (so it can be downloaded automatically once it's ready)
// We ignore the error since it's non-critical
_ = r.db.InsertDebridTorrentItem(&models.DebridTorrentItem{
TorrentItemID: torrentItemId,
Destination: destination,
Provider: provider.GetSettings().ID,
MediaId: mId,
})
return torrentItemId, nil
}
// GetTorrentInfo retrieves information about a torrent.
// This is used for file section for debrid streaming.
// On Real Debrid, this adds the torrent to the user's account.
func (r *Repository) GetTorrentInfo(opts debrid.GetTorrentInfoOptions) (*debrid.TorrentInfo, error) {
provider, err := r.GetProvider()
if err != nil {
return nil, err
}
torrentInfo, err := provider.GetTorrentInfo(opts)
if err != nil {
return nil, err
}
// Remove non-video files
torrentInfo.Files = debrid.FilterVideoFiles(torrentInfo.Files)
return torrentInfo, nil
}
func (r *Repository) HasProvider() bool {
return r.provider.IsPresent()
}
func (r *Repository) GetSettings() *models.DebridSettings {
return r.settings
}
// CancelDownload cancels the download for the given item ID
func (r *Repository) CancelDownload(itemID string) error {
cancelFunc, found := r.ctxMap.Get(itemID)
if !found {
return fmt.Errorf("no download found for item ID: %s", itemID)
}
// Call the cancel function to cancel the download
if cancelFunc != nil {
cancelFunc()
}
r.ctxMap.Delete(itemID)
// Notify that the download has been cancelled
r.wsEventManager.SendEvent(events.DebridDownloadProgress, map[string]interface{}{
"status": "cancelled",
"itemID": itemID,
})
return nil
}
func (r *Repository) StartStream(ctx context.Context, opts *StartStreamOptions) error {
return r.streamManager.startStream(ctx, opts)
}
func (r *Repository) GetStreamURL() (string, bool) {
return r.streamManager.currentStreamUrl, r.streamManager.currentStreamUrl != ""
}
func (r *Repository) CancelStream(opts *CancelStreamOptions) {
r.streamManager.cancelStream(opts)
}
func (r *Repository) GetPreviousStreamOptions() (*StartStreamOptions, bool) {
return r.previousStreamOptions.Get()
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////