/* Copyright © 2023 Evan Fiordeliso */ package cmd import ( "os" "github.com/dgraph-io/badger/v2" "github.com/spf13/cobra" "github.com/spf13/viper" "go.fifitido.net/ytdl-web/app/controllers" "go.fifitido.net/ytdl-web/config" "go.fifitido.net/ytdl-web/pkg/server" "go.fifitido.net/ytdl-web/pkg/utils" "go.fifitido.net/ytdl-web/pkg/ytdl" "go.fifitido.net/ytdl-web/pkg/ytdl/cache" "golang.org/x/exp/slog" ) var ( cfgFile string cfg *config.Config rootCmd = &cobra.Command{ Use: "ytdl-web", Short: "A web frontend for yt-dlp", Long: `YTDL Web A web application that grabs the links to videos from over a thousand websites using the yt-dlp project under the hood.`, RunE: func(cmd *cobra.Command, args []string) error { logger := slog.Default() db, err := badger.Open( badger. DefaultOptions(cfg.Cache.DirPath). WithLogger(utils.NewBadgerLogger(logger.With("module", "badger"))), ) if err != nil { return err } defer db.Close() cache := cache.NewDefaultMetadataCache(db) ytdl := ytdl.NewYtdl(cfg, slog.Default(), cache) s := server.New( server.DefaultServerOptions(). WithListenAddr(viper.GetString("http.listen")). WithListenPort(viper.GetInt("http.port")). WithLogger(logger.With("module", "server")), ) s.MountController("/", controllers.NewHomeController(ytdl)) s.MountController("/download", controllers.NewDownloadController(ytdl)) return s.ListenAndServe() }, } ) func Execute() { err := rootCmd.Execute() if err != nil { os.Exit(1) } } func init() { cobra.OnInitialize(initConfig) rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $XDG_CONFIG_HOME/ytdl-web/config.yml)") rootCmd.PersistentFlags().IntP("port", "p", 8080, "port to listen on") rootCmd.PersistentFlags().StringP("listen", "l", "", "address to listen on") rootCmd.PersistentFlags().StringP("base-path", "b", "", "the base path, used when behind reverse proxy") rootCmd.PersistentFlags().StringP("ytdlp-path", "y", "", "the path to the yt-dlp binary, used when it is not in $PATH") rootCmd.PersistentFlags().BoolP("cookies-enabled", "C", false, "whether cookies are enabled") rootCmd.PersistentFlags().StringP("cookies", "c", "", "the path to the cookies file") // trunk-ignore-begin(golangci-lint/errcheck): Ignoring errors viper.BindPFlag("http.port", rootCmd.PersistentFlags().Lookup("port")) viper.BindPFlag("http.listen", rootCmd.PersistentFlags().Lookup("listen")) viper.BindPFlag("http.basePath", rootCmd.PersistentFlags().Lookup("base-path")) viper.BindPFlag("ytdlp.binaryPath", rootCmd.PersistentFlags().Lookup("ytdlp-path")) viper.BindPFlag("cookies.enabled", rootCmd.PersistentFlags().Lookup("cookies-enabled")) viper.BindPFlag("cookies.filePath", rootCmd.PersistentFlags().Lookup("cookies")) // trunk-ignore-end(golangci-lint/errcheck) } func initConfig() { var err error if cfgFile != "" { cfg, err = config.LoadConfig(cfgFile) } else { cfg, err = config.LoadConfig() } if err != nil { slog.Error("Error loading configuration", slog.String("error", err.Error())) os.Exit(1) } initLogging() slog.Info("Configuration loaded") } func initLogging() { var handler slog.Handler if cfg.IsProduction() { handler = slog.HandlerOptions{ AddSource: true, Level: slog.LevelInfo, }.NewJSONHandler(os.Stdout) } else { handler = slog.HandlerOptions{ AddSource: true, Level: slog.LevelDebug, }.NewTextHandler(os.Stdout) } slog.SetDefault(slog.New(handler)) }