2023-10-24 00:18:16 +00:00
|
|
|
package api
|
2023-09-18 23:57:18 +00:00
|
|
|
|
2023-10-01 23:17:22 +00:00
|
|
|
import (
|
2023-11-29 01:05:50 +00:00
|
|
|
"errors"
|
2023-10-01 23:17:22 +00:00
|
|
|
"fmt"
|
|
|
|
"math"
|
2024-02-25 01:45:26 +00:00
|
|
|
"path/filepath"
|
2024-01-24 04:00:51 +00:00
|
|
|
"reflect"
|
2024-02-25 01:45:26 +00:00
|
|
|
"strings"
|
2023-10-24 00:18:16 +00:00
|
|
|
|
2024-01-11 01:23:36 +00:00
|
|
|
"reichard.io/antholume/database"
|
|
|
|
"reichard.io/antholume/graph"
|
2024-02-25 01:45:26 +00:00
|
|
|
"reichard.io/antholume/metadata"
|
2023-10-01 23:17:22 +00:00
|
|
|
)
|
|
|
|
|
2024-03-11 17:13:26 +00:00
|
|
|
func getTimeZones() []string {
|
|
|
|
return []string{
|
|
|
|
"Africa/Cairo",
|
|
|
|
"Africa/Johannesburg",
|
|
|
|
"Africa/Lagos",
|
|
|
|
"Africa/Nairobi",
|
|
|
|
"America/Adak",
|
|
|
|
"America/Anchorage",
|
|
|
|
"America/Buenos_Aires",
|
|
|
|
"America/Chicago",
|
|
|
|
"America/Denver",
|
|
|
|
"America/Los_Angeles",
|
|
|
|
"America/Mexico_City",
|
|
|
|
"America/New_York",
|
|
|
|
"America/Nuuk",
|
|
|
|
"America/Phoenix",
|
|
|
|
"America/Puerto_Rico",
|
|
|
|
"America/Sao_Paulo",
|
|
|
|
"America/St_Johns",
|
|
|
|
"America/Toronto",
|
|
|
|
"Asia/Dubai",
|
|
|
|
"Asia/Hong_Kong",
|
|
|
|
"Asia/Kolkata",
|
|
|
|
"Asia/Seoul",
|
|
|
|
"Asia/Shanghai",
|
|
|
|
"Asia/Singapore",
|
|
|
|
"Asia/Tokyo",
|
|
|
|
"Atlantic/Azores",
|
|
|
|
"Australia/Melbourne",
|
|
|
|
"Australia/Sydney",
|
|
|
|
"Europe/Berlin",
|
|
|
|
"Europe/London",
|
|
|
|
"Europe/Moscow",
|
|
|
|
"Europe/Paris",
|
|
|
|
"Pacific/Auckland",
|
|
|
|
"Pacific/Honolulu",
|
|
|
|
}
|
2023-09-18 23:57:18 +00:00
|
|
|
}
|
2023-10-01 23:17:22 +00:00
|
|
|
|
2023-10-24 00:18:16 +00:00
|
|
|
func niceSeconds(input int64) (result string) {
|
2023-10-03 20:47:38 +00:00
|
|
|
if input == 0 {
|
|
|
|
return "N/A"
|
|
|
|
}
|
|
|
|
|
2023-10-01 23:17:22 +00:00
|
|
|
days := math.Floor(float64(input) / 60 / 60 / 24)
|
|
|
|
seconds := input % (60 * 60 * 24)
|
|
|
|
hours := math.Floor(float64(seconds) / 60 / 60)
|
|
|
|
seconds = input % (60 * 60)
|
|
|
|
minutes := math.Floor(float64(seconds) / 60)
|
|
|
|
seconds = input % 60
|
|
|
|
|
|
|
|
if days > 0 {
|
|
|
|
result += fmt.Sprintf("%dd ", int(days))
|
|
|
|
}
|
|
|
|
if hours > 0 {
|
|
|
|
result += fmt.Sprintf("%dh ", int(hours))
|
|
|
|
}
|
|
|
|
if minutes > 0 {
|
|
|
|
result += fmt.Sprintf("%dm ", int(minutes))
|
|
|
|
}
|
|
|
|
if seconds > 0 {
|
|
|
|
result += fmt.Sprintf("%ds", int(seconds))
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2023-10-07 01:25:56 +00:00
|
|
|
|
2024-01-24 04:00:51 +00:00
|
|
|
func niceNumbers(input int64) string {
|
|
|
|
if input == 0 {
|
|
|
|
return "0"
|
|
|
|
}
|
|
|
|
|
|
|
|
abbreviations := []string{"", "k", "M", "B", "T"}
|
|
|
|
abbrevIndex := int(math.Log10(float64(input)) / 3)
|
|
|
|
scaledNumber := float64(input) / math.Pow(10, float64(abbrevIndex*3))
|
|
|
|
|
|
|
|
if scaledNumber >= 100 {
|
|
|
|
return fmt.Sprintf("%.0f%s", scaledNumber, abbreviations[abbrevIndex])
|
|
|
|
} else if scaledNumber >= 10 {
|
|
|
|
return fmt.Sprintf("%.1f%s", scaledNumber, abbreviations[abbrevIndex])
|
|
|
|
} else {
|
|
|
|
return fmt.Sprintf("%.2f%s", scaledNumber, abbreviations[abbrevIndex])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-24 00:18:16 +00:00
|
|
|
// Convert Database Array -> Int64 Array
|
|
|
|
func getSVGGraphData(inputData []database.GetDailyReadStatsRow, svgWidth int, svgHeight int) graph.SVGGraphData {
|
|
|
|
var intData []int64
|
|
|
|
for _, item := range inputData {
|
|
|
|
intData = append(intData, item.MinutesRead)
|
|
|
|
}
|
|
|
|
|
|
|
|
return graph.GetSVGGraphData(intData, svgWidth, svgHeight)
|
|
|
|
}
|
2023-11-29 01:05:50 +00:00
|
|
|
|
2024-05-26 00:04:26 +00:00
|
|
|
func dict(values ...any) (map[string]any, error) {
|
2023-11-29 01:05:50 +00:00
|
|
|
if len(values)%2 != 0 {
|
|
|
|
return nil, errors.New("invalid dict call")
|
|
|
|
}
|
2024-05-26 00:04:26 +00:00
|
|
|
dict := make(map[string]any, len(values)/2)
|
2023-11-29 01:05:50 +00:00
|
|
|
for i := 0; i < len(values); i += 2 {
|
|
|
|
key, ok := values[i].(string)
|
|
|
|
if !ok {
|
|
|
|
return nil, errors.New("dict keys must be strings")
|
|
|
|
}
|
|
|
|
dict[key] = values[i+1]
|
|
|
|
}
|
|
|
|
return dict, nil
|
|
|
|
}
|
2024-01-24 04:00:51 +00:00
|
|
|
|
2024-05-26 00:04:26 +00:00
|
|
|
func fields(value any) (map[string]any, error) {
|
2024-01-24 04:00:51 +00:00
|
|
|
v := reflect.Indirect(reflect.ValueOf(value))
|
|
|
|
if v.Kind() != reflect.Struct {
|
|
|
|
return nil, fmt.Errorf("%T is not a struct", value)
|
|
|
|
}
|
2024-05-26 00:04:26 +00:00
|
|
|
m := make(map[string]any)
|
2024-01-24 04:00:51 +00:00
|
|
|
t := v.Type()
|
|
|
|
for i := 0; i < t.NumField(); i++ {
|
|
|
|
sv := t.Field(i)
|
|
|
|
m[sv.Name] = v.Field(i).Interface()
|
|
|
|
}
|
|
|
|
return m, nil
|
|
|
|
}
|
2024-02-25 01:45:26 +00:00
|
|
|
|
2024-05-26 00:04:26 +00:00
|
|
|
func slice(elements ...any) []any {
|
|
|
|
return elements
|
|
|
|
}
|
|
|
|
|
2024-02-25 01:45:26 +00:00
|
|
|
func deriveBaseFileName(metadataInfo *metadata.MetadataInfo) string {
|
|
|
|
// Derive New FileName
|
|
|
|
var newFileName string
|
|
|
|
if *metadataInfo.Author != "" {
|
|
|
|
newFileName = newFileName + *metadataInfo.Author
|
|
|
|
} else {
|
|
|
|
newFileName = newFileName + "Unknown"
|
|
|
|
}
|
|
|
|
if *metadataInfo.Title != "" {
|
|
|
|
newFileName = newFileName + " - " + *metadataInfo.Title
|
|
|
|
} else {
|
|
|
|
newFileName = newFileName + " - Unknown"
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove Slashes
|
|
|
|
fileName := strings.ReplaceAll(newFileName, "/", "")
|
|
|
|
return "." + filepath.Clean(fmt.Sprintf("/%s [%s]%s", fileName, *metadataInfo.PartialMD5, metadataInfo.Type))
|
|
|
|
}
|
2024-05-18 20:47:26 +00:00
|
|
|
|
|
|
|
func importStatusPriority(status importStatus) int {
|
|
|
|
switch status {
|
|
|
|
case importFailed:
|
|
|
|
return 1
|
|
|
|
case importExists:
|
|
|
|
return 2
|
|
|
|
default:
|
|
|
|
return 3
|
|
|
|
}
|
|
|
|
}
|