// nolint:gomnd,exhaustivestruct package main import ( "context" "encoding/json" "fmt" "io/ioutil" "net/http" "os" "time" "git.xsfx.dev/xsteadfastx/logginghandler" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) // Logic Jellyfin URL. type Logic struct { InternalURL string ExternalURL string } // PublicInfo Chromecast configuration Payload. type PublicInfo struct { LocalAddress string `json:"LocalAddress,omitempty"` ServerName string `json:"ServerName"` Version string `json:"Version"` ProductName string `json:"ProductName"` OperatingSystem string `json:"OperatingSystem"` ID string `json:"Id"` StartupWizardCompleted bool `json:"StartupWizardCompleted"` } // nolint:funlen func (l Logic) ServeHTTP(w http.ResponseWriter, r *http.Request) { logger := logginghandler.Logger(r) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // nolint:gomnd defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("%s/System/Info/Public", l.InternalURL), nil) if err != nil { logger.Error().Msg(err.Error()) http.Error(w, "could not create request jellyfin", http.StatusInternalServerError) return } resp, err := http.DefaultClient.Do(req) if err != nil { logger.Error().Msg(err.Error()) http.Error(w, "could not access jellyfin", http.StatusInternalServerError) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { logger.Error().Msg(err.Error()) http.Error(w, "could not read body", http.StatusInternalServerError) return } logger.Debug().Str("body", string(body)).Msg("read body") var jd PublicInfo if err := json.Unmarshal(body, &jd); err != nil { logger.Error().Msg(err.Error()) http.Error(w, "could not unmarshal body", http.StatusInternalServerError) return } var nd PublicInfo nd.ServerName = jd.ServerName nd.Version = jd.Version nd.ProductName = jd.ProductName nd.OperatingSystem = jd.OperatingSystem nd.ID = jd.ID nd.StartupWizardCompleted = jd.StartupWizardCompleted // When there is no external url defined, it wont include it in the response. if l.ExternalURL != "" { nd.LocalAddress = l.ExternalURL } bd, err := json.Marshal(nd) if err != nil { logger.Error().Msg(err.Error()) http.Error(w, "could not marshal body", http.StatusInternalServerError) return } if _, err := w.Write(bd); err != nil { logger.Error().Msg(err.Error()) } } func main() { log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) log.Logger = log.Logger.With().Caller().Logger() viper.SetEnvPrefix("jellyfixer") if err := viper.BindEnv("internal_url"); err != nil { log.Fatal().Msg(err.Error()) } if err := viper.BindEnv("external_url"); err != nil { log.Fatal().Msg(err.Error()) } if len(os.Args) == 2 { viper.SetConfigFile(os.Args[1]) } viper.AutomaticEnv() if viper.GetString("internal_url") == "" { log.Fatal().Msg("needs key 'internal_url'") } l := Logic{ InternalURL: viper.GetString("internal_url"), ExternalURL: viper.GetString("external_url"), } handler := logginghandler.Handler(l) http.Handle("/", handler) log.Info().Msg("starting server...") log.Fatal().Msg(http.ListenAndServe("0.0.0.0:8088", nil).Error()) }