Sprint 1 — Auto-refresh after download:
- New [[mediaserver]] TOML section with kind/url/token/sections
- mediaserver.Refresh() fans out to Plex (partial via section ID auto-mapping
from file path prefix) and Jellyfin/Emby (full library scan)
- Manager.OnFinalized callback wired in daemon to trigger refresh after
organize() completes — keeps engine package free of mediaserver dep
- New unarr mediaserver {setup,list,remove,test} commands
- unarr init wizard offers to configure refresh when a server is detected
Sprint 2 — .strm instant mode (cloud + agent):
- Mode strm-to-library handled in daemon dispatch: writes a one-line .strm
file pointing to the cloud-resolved debrid HTTPS URL, then triggers refresh
- engine.WriteStrm + StrmDestForTask mirror organize()'s naming so Plex/Jellyfin
see the expected folder structure (Movies/Title (Year)/, TV Shows/Show/Season XX/)
- Atomic write (temp + rename) so partial files never get indexed
- Reports completed/failed status to the cloud via existing agent client
70 lines
2.3 KiB
Go
70 lines
2.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"github.com/torrentclaw/unarr/internal/agent"
|
|
"github.com/torrentclaw/unarr/internal/config"
|
|
"github.com/torrentclaw/unarr/internal/engine"
|
|
"github.com/torrentclaw/unarr/internal/mediaserver"
|
|
)
|
|
|
|
// handleStrmToLibrary processes a Mode="strm-to-library" task by writing a
|
|
// one-line .strm file to the user's media library and triggering a
|
|
// Plex/Jellyfin/Emby refresh. No actual download happens; the .strm points
|
|
// at the cloud-resolved debrid HTTPS URL, and the media server streams from
|
|
// there when the user presses play.
|
|
//
|
|
// Reports completion (or failure) back to the cloud via the agent client.
|
|
func handleStrmToLibrary(ctx context.Context, t agent.Task, cfg config.Config, agentClient *agent.Client) {
|
|
short := agent.ShortID(t.ID)
|
|
|
|
if t.DirectURL == "" {
|
|
log.Printf("[%s] strm-to-library: missing directUrl from server", short)
|
|
reportStrmFailure(ctx, agentClient, t.ID, "missing directUrl")
|
|
return
|
|
}
|
|
|
|
organizeCfg := engine.OrganizeConfig{
|
|
Enabled: cfg.Organize.Enabled,
|
|
MoviesDir: cfg.Organize.MoviesDir,
|
|
TVShowsDir: cfg.Organize.TVShowsDir,
|
|
OutputDir: cfg.Download.Dir,
|
|
}
|
|
|
|
finalPath, err := engine.WriteStrm(t, organizeCfg)
|
|
if err != nil {
|
|
log.Printf("[%s] strm-to-library write failed: %v", short, err)
|
|
reportStrmFailure(ctx, agentClient, t.ID, err.Error())
|
|
return
|
|
}
|
|
|
|
log.Printf("[%s] strm-to-library wrote %s", short, finalPath)
|
|
|
|
// Trigger media-server refresh if any are configured. Errors are logged
|
|
// inside Refresh and never propagate — the .strm is on disk, so the
|
|
// next periodic scan would pick it up regardless.
|
|
if len(cfg.MediaServers) > 0 {
|
|
mediaserver.Refresh(cfg.MediaServers, finalPath)
|
|
}
|
|
|
|
if _, reportErr := agentClient.ReportStatus(ctx, agent.StatusUpdate{
|
|
TaskID: t.ID,
|
|
Status: "completed",
|
|
Progress: 100,
|
|
FilePath: finalPath,
|
|
}); reportErr != nil {
|
|
log.Printf("[%s] strm-to-library: status report failed: %v", short, reportErr)
|
|
}
|
|
}
|
|
|
|
func reportStrmFailure(ctx context.Context, agentClient *agent.Client, taskID, msg string) {
|
|
if _, err := agentClient.ReportStatus(ctx, agent.StatusUpdate{
|
|
TaskID: taskID,
|
|
Status: "failed",
|
|
ErrorMessage: msg,
|
|
}); err != nil {
|
|
log.Printf("[%s] strm failure report failed: %v", agent.ShortID(taskID), err)
|
|
}
|
|
}
|