Support for multiple Tautulli servers

Not functional as of yet, but configurable
This commit is contained in:
aunefyren 2022-10-20 21:38:55 +02:00
parent dd51c329e0
commit 7d073207cd
4 changed files with 173 additions and 143 deletions

View file

@ -99,10 +99,14 @@
"wrapperr_sort_duration":"Sort by duration", "wrapperr_sort_duration":"Sort by duration",
"get_user_show_stats_buddy":true "get_user_show_stats_buddy":true
}, },
"tautulli_config": { "tautulli_config": [
{
"tautulli_name" : "Tautulli",
"tautulli_id": 0,
"tautulli_port": 80, "tautulli_port": 80,
"tautulli_length": 5000 "tautulli_length": 5000
}, }
],
"wrapped_start": 1640991600, "wrapped_start": 1640991600,
"wrapped_end": 1672527540, "wrapped_end": 1672527540,
"wrapperr_port" : 8282, "wrapperr_port" : 8282,

View file

@ -10,7 +10,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
var wrapperr_version_parameter = "v3.0.4" var wrapperr_version_parameter = "v3.1.0"
var config_path, _ = filepath.Abs("./config/config.json") var config_path, _ = filepath.Abs("./config/config.json")
var default_config_path, _ = filepath.Abs("./config_default.json") var default_config_path, _ = filepath.Abs("./config_default.json")
@ -36,7 +36,7 @@ func GetConfigState() (bool, error) {
} }
// Check if certain parameters are set. These are essential paramteres the user must configure for basic functionality. // Check if certain parameters are set. These are essential paramteres the user must configure for basic functionality.
if config.TautulliConfig.TautulliApiKey != "" && config.TautulliConfig.TautulliIP != "" && config.TautulliConfig.TautulliLength != 0 && config.Timezone != "" && config.WrappedStart != 0 && config.WrappedEnd != 0 && config.WrapperrVersion != "" { if config.TautulliConfig[0].TautulliApiKey != "" && config.TautulliConfig[0].TautulliIP != "" && config.TautulliConfig[0].TautulliLength != 0 && config.Timezone != "" && config.WrappedStart != 0 && config.WrappedEnd != 0 && config.WrapperrVersion != "" {
return true, nil return true, nil
} else { } else {
return false, nil return false, nil
@ -120,7 +120,12 @@ func CreateConfigFile() error {
config.UseCache = true config.UseCache = true
config.PlexAuth = true config.PlexAuth = true
config.UseLogs = true config.UseLogs = true
config.TautulliConfig.TautulliGrouping = true
var tautulli_config = TautulliConfig{
TautulliGrouping: true,
}
config.TautulliConfig = append(config.TautulliConfig, tautulli_config)
config.CreateShareLinks = true config.CreateShareLinks = true
config.WinterTheme = true config.WinterTheme = true
config.WrapperrCustomize.StatsTopListLength = 10 config.WrapperrCustomize.StatsTopListLength = 10
@ -219,14 +224,14 @@ func GetConfig() (*WrapperrConfig, error) {
config.WrappedEnd = config_default.WrappedEnd // If no start time, set to 31 Dec config.WrappedEnd = config_default.WrappedEnd // If no start time, set to 31 Dec
} }
// Set Tautulli length to 5000 if none is set // Set Tautulli length to 5000 if zero is set
if config.TautulliConfig.TautulliLength == 0 { if config.TautulliConfig[0].TautulliLength == 0 {
config.TautulliConfig.TautulliLength = config_default.TautulliConfig.TautulliLength config.TautulliConfig[0].TautulliLength = config_default.TautulliConfig[0].TautulliLength
} }
// Set Tautulli port to 80 if none is set // Set Tautulli port to 80 if zero is set
if config.TautulliConfig.TautulliPort == 0 { if config.TautulliConfig[0].TautulliPort == 0 {
config.TautulliConfig.TautulliPort = config_default.TautulliConfig.TautulliPort config.TautulliConfig[0].TautulliPort = config_default.TautulliConfig[0].TautulliPort
} }
if config.WrapperrCustomize.StatsTopListLength < 0 { if config.WrapperrCustomize.StatsTopListLength < 0 {

View file

@ -39,7 +39,7 @@ type AdminConfig struct {
} }
type WrapperrConfig struct { type WrapperrConfig struct {
TautulliConfig TautulliConfig `json:"tautulli_config"` TautulliConfig []TautulliConfig `json:"tautulli_config"`
WrapperrCustomize WrapperrCustomize `json:"wrapperr_customize"` WrapperrCustomize WrapperrCustomize `json:"wrapperr_customize"`
WrapperrVersion string `json:"wrapperr_version"` WrapperrVersion string `json:"wrapperr_version"`
Timezone string `json:"timezone"` Timezone string `json:"timezone"`
@ -67,6 +67,8 @@ type TautulliConfig struct {
TautulliLibraries string `json:"tautulli_libraries"` TautulliLibraries string `json:"tautulli_libraries"`
TautulliGrouping bool `json:"tautulli_grouping"` TautulliGrouping bool `json:"tautulli_grouping"`
TautulliHttps bool `json:"tautulli_https"` TautulliHttps bool `json:"tautulli_https"`
TautulliName string `json:"tautulli_name"`
TautulliID int `json:"tautulli_id"`
} }
type WrapperrCustomize struct { type WrapperrCustomize struct {
@ -211,7 +213,7 @@ type WrapperrFunctions struct {
type SetWrapperrConfig struct { type SetWrapperrConfig struct {
ClearCache bool `json:"clear_cache"` ClearCache bool `json:"clear_cache"`
DataType string `json:"data_type"` DataType string `json:"data_type"`
TautulliConfig TautulliConfig `json:"tautulli_config"` TautulliConfig []TautulliConfig `json:"tautulli_config"`
WrapperrCustomize WrapperrCustomize `json:"wrapperr_customize"` WrapperrCustomize WrapperrCustomize `json:"wrapperr_customize"`
WrapperrData struct { WrapperrData struct {
UseCache bool `json:"use_cache"` UseCache bool `json:"use_cache"`

View file

@ -38,16 +38,19 @@ func ApiWrapperGetStatistics(w http.ResponseWriter, r *http.Request) {
log.Println("1. Configuration check passed." + ip_string) log.Println("1. Configuration check passed." + ip_string)
tautulli_state, err := TautulliTestConnection(config.TautulliConfig.TautulliPort, config.TautulliConfig.TautulliIP, config.TautulliConfig.TautulliHttps, config.TautulliConfig.TautulliRoot, config.TautulliConfig.TautulliApiKey) // Check every Tautulli server
for i := 0; i < len(config.TautulliConfig); i++ {
tautulli_state, err := TautulliTestConnection(config.TautulliConfig[i].TautulliPort, config.TautulliConfig[i].TautulliIP, config.TautulliConfig[i].TautulliHttps, config.TautulliConfig[i].TautulliRoot, config.TautulliConfig[i].TautulliApiKey)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
respond_default_error(w, r, errors.New("Failed to reach Tautulli server."), 500) respond_default_error(w, r, errors.New("Failed to reach Tautulli server '"+config.TautulliConfig[i].TautulliName+"'."), 500)
return return
} else if !tautulli_state { } else if !tautulli_state {
log.Println("Failed to ping Tautulli server before retrieving statistics.") log.Println("Failed to ping Tautulli server '" + config.TautulliConfig[i].TautulliName + "' before retrieving statistics.")
respond_default_error(w, r, errors.New("Failed to reach Tautulli server."), 400) respond_default_error(w, r, errors.New("Failed to reach Tautulli server '"+config.TautulliConfig[i].TautulliName+"'."), 400)
return return
} }
}
log.Println("2. Tautulli check passed." + ip_string) log.Println("2. Tautulli check passed." + ip_string)
@ -105,16 +108,25 @@ func ApiWrapperGetStatistics(w http.ResponseWriter, r *http.Request) {
// If no auth has been passed, caching mode is false, and user is not admin, search for the Plex details using Tautulli and PlexIdentity // If no auth has been passed, caching mode is false, and user is not admin, search for the Plex details using Tautulli and PlexIdentity
if !auth_passed && !wrapperr_request.CachingMode && !admin { if !auth_passed && !wrapperr_request.CachingMode && !admin {
new_id, new_username, err := TautulliGetUserId(config.TautulliConfig.TautulliPort, config.TautulliConfig.TautulliIP, config.TautulliConfig.TautulliHttps, config.TautulliConfig.TautulliRoot, config.TautulliConfig.TautulliApiKey, wrapperr_request.PlexIdentity)
if err != nil {
log.Println(err)
respond_default_error(w, r, errors.New("Could not find user."), 500)
return
}
UserNameFound := false
for i := 0; i < len(config.TautulliConfig); i++ {
new_id, new_username, err := TautulliGetUserId(config.TautulliConfig[i].TautulliPort, config.TautulliConfig[i].TautulliIP, config.TautulliConfig[i].TautulliHttps, config.TautulliConfig[i].TautulliRoot, config.TautulliConfig[i].TautulliApiKey, wrapperr_request.PlexIdentity)
if err == nil {
UserNameFound = true
user_name = new_username user_name = new_username
user_id = new_id user_id = new_id
} }
}
if !UserNameFound {
log.Println(err)
respond_default_error(w, r, errors.New("Could not find a matching user."), 500)
return
}
}
// If caching mode is false and user is admin, return bad request error // If caching mode is false and user is admin, return bad request error
if !wrapperr_request.CachingMode && admin { if !wrapperr_request.CachingMode && admin {
@ -222,12 +234,17 @@ func ApiWrapperGetStatistics(w http.ResponseWriter, r *http.Request) {
func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int, config *WrapperrConfig) ([]WrapperrDay, bool, error) { func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int, config *WrapperrConfig) ([]WrapperrDay, bool, error) {
// Define object with end date from wrapped period
end_loop_date := time.Unix(int64(config.WrappedEnd), 0)
// Define variables // Define variables
var complete_date_loop bool = true var complete_date_loop bool = true
var use_loop_interval bool = true var use_loop_interval bool = true
var found_date bool = false
var found_date_index int = 0
// Go through each Tautulli server
for q := 0; q < len(config.TautulliConfig); q++ {
// Define object with end date from wrapped period
end_loop_date := time.Unix(int64(config.WrappedEnd), 0)
// If loop_interval is less than one, do not utilize the loop interval and set use_loop_interval to false // If loop_interval is less than one, do not utilize the loop interval and set use_loop_interval to false
if loop_interval < 1 { if loop_interval < 1 {
@ -235,7 +252,7 @@ func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int
} }
// Split the string containing libraries. If the result is zero, set the first object in the array to an empty string // Split the string containing libraries. If the result is zero, set the first object in the array to an empty string
libraries := strings.Split(config.TautulliConfig.TautulliLibraries, ",") libraries := strings.Split(config.TautulliConfig[q].TautulliLibraries, ",")
if len(libraries) < 1 { if len(libraries) < 1 {
libraries[0] = "" libraries[0] = ""
} }
@ -252,8 +269,15 @@ func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int
break break
} }
var found_date bool = false // Clean array to populate with results
var found_date_index int = 0 wrapperr_day := WrapperrDay{
Date: current_loop_date,
Data: nil,
DataComplete: true,
}
found_date = false
found_date_index = 0
for j := 0; j < len(wrapperr_data); j++ { for j := 0; j < len(wrapperr_data); j++ {
time_temp, err := time.Parse("2006-01-02", wrapperr_data[j].Date) time_temp, err := time.Parse("2006-01-02", wrapperr_data[j].Date)
@ -272,21 +296,14 @@ func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int
if found_date && wrapperr_data[found_date_index].DataComplete { if found_date && wrapperr_data[found_date_index].DataComplete {
continue continue
} else if found_date && !wrapperr_data[found_date_index].DataComplete { } else if found_date && !wrapperr_data[found_date_index].DataComplete {
log.Println("Date " + current_loop_date + " marked as incomplete in cache. Refreshing.") log.Println("Date " + current_loop_date + " from server '" + config.TautulliConfig[q].TautulliName + "' marked as incomplete in cache. Refreshing.")
} else if !found_date { } else if !found_date {
log.Println("Downloading day: " + current_loop_date) log.Println("Downloading day: " + current_loop_date + " from server '" + config.TautulliConfig[q].TautulliName + "'.")
} else { } else {
log.Println("Unknown date error. Skipping.") log.Println("Unknown date error from server '" + config.TautulliConfig[q].TautulliName + "'. Skipping.")
continue continue
} }
// Clean array to populate with results
wrapperr_day := WrapperrDay{
Date: current_loop_date,
Data: nil,
DataComplete: true,
}
// Loop through selected libraries // Loop through selected libraries
for library_loop := 0; library_loop < len(libraries); library_loop++ { for library_loop := 0; library_loop < len(libraries); library_loop++ {
@ -300,13 +317,13 @@ func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int
library_str = "&section_id=" + strings.TrimSpace(libraries[library_loop]) library_str = "&section_id=" + strings.TrimSpace(libraries[library_loop])
} }
if config.TautulliConfig.TautulliGrouping { if config.TautulliConfig[q].TautulliGrouping {
grouping = "1" grouping = "1"
} else { } else {
grouping = "0" grouping = "0"
} }
tautulli_data, err := TautulliDownloadStatistics(config.TautulliConfig.TautulliPort, config.TautulliConfig.TautulliIP, config.TautulliConfig.TautulliHttps, config.TautulliConfig.TautulliRoot, config.TautulliConfig.TautulliApiKey, config.TautulliConfig.TautulliLength, library_str, grouping, current_loop_date) tautulli_data, err := TautulliDownloadStatistics(config.TautulliConfig[q].TautulliPort, config.TautulliConfig[q].TautulliIP, config.TautulliConfig[q].TautulliHttps, config.TautulliConfig[q].TautulliRoot, config.TautulliConfig[q].TautulliApiKey, config.TautulliConfig[q].TautulliLength, library_str, grouping, current_loop_date)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
} }
@ -361,6 +378,8 @@ func WrapperrDownloadDays(ID int, wrapperr_data []WrapperrDay, loop_interval int
} }
}
return wrapperr_data, complete_date_loop, nil return wrapperr_data, complete_date_loop, nil
} }