mirror of
https://github.com/FJurmanovic/sugarr.git
synced 2026-11-11 07:41:08 +00:00
106 lines
2.7 KiB
Go
106 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"text/tabwriter"
|
|
|
|
"github.com/fjurmanovic/sugarr/internal/model"
|
|
"github.com/fjurmanovic/sugarr/internal/service"
|
|
"github.com/fjurmanovic/sugarr/internal/utl/configs"
|
|
"github.com/fjurmanovic/sugarr/internal/utl/server"
|
|
"github.com/robfig/cron/v3"
|
|
"github.com/rs/zerolog"
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
const version = "0.0.1"
|
|
|
|
func main() {
|
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
|
|
|
cfg, err := configs.Load()
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("Failed to load config")
|
|
}
|
|
|
|
printBanner(cfg)
|
|
|
|
rec := service.NewRecommender(cfg)
|
|
|
|
// Cron scheduler
|
|
if cfg.CronEnabled {
|
|
c := cron.New()
|
|
if _, err := c.AddFunc(cfg.CronSchedule, func() {
|
|
log.Info().Msg("Cron: running recommendation pipeline")
|
|
recs, err := rec.Run()
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("Cron: pipeline failed")
|
|
return
|
|
}
|
|
if cfg.RadarrEnabled {
|
|
rec.AutoRequest(recs)
|
|
}
|
|
logRecommendations(recs)
|
|
}); err != nil {
|
|
log.Fatal().Err(err).Msg("Invalid cron schedule")
|
|
}
|
|
c.Start()
|
|
defer c.Stop()
|
|
log.Info().Msgf("Cron scheduled: %s", cfg.CronSchedule)
|
|
}
|
|
|
|
// HTTP API — blocks until server exits
|
|
if cfg.APIEnabled {
|
|
if err := server.Start(cfg, rec); err != nil {
|
|
log.Fatal().Err(err).Msg("HTTP server failed")
|
|
}
|
|
return
|
|
}
|
|
|
|
// One-shot mode: no API, no cron
|
|
if !cfg.CronEnabled {
|
|
recs, err := rec.Run()
|
|
if err != nil {
|
|
log.Fatal().Err(err).Msg("Recommendation pipeline failed")
|
|
}
|
|
printTable(recs)
|
|
return
|
|
}
|
|
|
|
// Cron-only mode: block forever
|
|
select {}
|
|
}
|
|
|
|
func printBanner(cfg *configs.Config) {
|
|
log.Info().Msg("sugarr starting")
|
|
log.Info().Msgf(" Version: %s", version)
|
|
log.Info().Msgf(" Jellyfin: %s (user: %s)", cfg.JellyfinURL, cfg.JellyfinUserID)
|
|
log.Info().Msgf(" LLM: enabled=%v model=%s", cfg.LLMEnabled, cfg.LLMModel)
|
|
log.Info().Msgf(" Radarr: enabled=%v", cfg.RadarrEnabled)
|
|
log.Info().Msgf(" Cron: enabled=%v schedule=%s", cfg.CronEnabled, cfg.CronSchedule)
|
|
log.Info().Msgf(" API: enabled=%v port=%d", cfg.APIEnabled, cfg.APIPort)
|
|
log.Info().Msgf(" Count: %d recommendations", cfg.RecommendCount)
|
|
}
|
|
|
|
func logRecommendations(recs []model.Recommendation) {
|
|
log.Info().Msgf("Recommendations (%d):", len(recs))
|
|
for i, r := range recs {
|
|
log.Info().Msgf(" %d. %s (%d) [tmdb:%d] — %s", i+1, r.Title, r.Year, r.TMDbID, r.Reason)
|
|
}
|
|
}
|
|
|
|
func printTable(recs []model.Recommendation) {
|
|
if len(recs) == 0 {
|
|
fmt.Println("No recommendations found.")
|
|
return
|
|
}
|
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
|
fmt.Fprintln(w, "#\tTitle\tYear\tTMDb ID\tReason")
|
|
fmt.Fprintln(w, "-\t-----\t----\t-------\t------")
|
|
for i, r := range recs {
|
|
fmt.Fprintf(w, "%d\t%s\t%d\t%d\t%s\n", i+1, r.Title, r.Year, r.TMDbID, r.Reason)
|
|
}
|
|
w.Flush()
|
|
}
|