mirror of
https://github.com/gabehf/Koito.git
synced 2026-03-07 13:38:15 -08:00
* wip * chore: update counts to allow unix timeframe * feat: add db functions for counting new items * wip: endpoint working * wip * wip: initial ui done * add header, adjust ui * add time listened toggle * fix layout, year param * param fixes
174 lines
4.5 KiB
Go
174 lines
4.5 KiB
Go
// package handlers implements route handlers
|
|
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gabehf/koito/internal/db"
|
|
"github.com/gabehf/koito/internal/logger"
|
|
)
|
|
|
|
const defaultLimitSize = 100
|
|
const maximumLimit = 500
|
|
|
|
func OptsFromRequest(r *http.Request) db.GetItemsOpts {
|
|
l := logger.FromContext(r.Context())
|
|
|
|
l.Debug().Msg("OptsFromRequest: Parsing query parameters")
|
|
|
|
limitStr := r.URL.Query().Get("limit")
|
|
limit, err := strconv.Atoi(limitStr)
|
|
if err != nil {
|
|
l.Debug().Msgf("OptsFromRequest: Query parameter 'limit' not specified, using default %d", defaultLimitSize)
|
|
limit = defaultLimitSize
|
|
}
|
|
if limit > maximumLimit {
|
|
l.Debug().Msgf("OptsFromRequest: Limit exceeds maximum %d, using default %d", maximumLimit, defaultLimitSize)
|
|
limit = defaultLimitSize
|
|
}
|
|
|
|
pageStr := r.URL.Query().Get("page")
|
|
page, _ := strconv.Atoi(pageStr)
|
|
if page < 1 {
|
|
l.Debug().Msg("OptsFromRequest: Page parameter is less than 1, defaulting to 1")
|
|
page = 1
|
|
}
|
|
|
|
weekStr := r.URL.Query().Get("week")
|
|
week, _ := strconv.Atoi(weekStr)
|
|
monthStr := r.URL.Query().Get("month")
|
|
month, _ := strconv.Atoi(monthStr)
|
|
yearStr := r.URL.Query().Get("year")
|
|
year, _ := strconv.Atoi(yearStr)
|
|
fromStr := r.URL.Query().Get("from")
|
|
from, _ := strconv.Atoi(fromStr)
|
|
toStr := r.URL.Query().Get("to")
|
|
to, _ := strconv.Atoi(toStr)
|
|
|
|
artistIdStr := r.URL.Query().Get("artist_id")
|
|
artistId, _ := strconv.Atoi(artistIdStr)
|
|
albumIdStr := r.URL.Query().Get("album_id")
|
|
albumId, _ := strconv.Atoi(albumIdStr)
|
|
trackIdStr := r.URL.Query().Get("track_id")
|
|
trackId, _ := strconv.Atoi(trackIdStr)
|
|
|
|
var period db.Period
|
|
switch strings.ToLower(r.URL.Query().Get("period")) {
|
|
case "day":
|
|
period = db.PeriodDay
|
|
case "week":
|
|
period = db.PeriodWeek
|
|
case "month":
|
|
period = db.PeriodMonth
|
|
case "year":
|
|
period = db.PeriodYear
|
|
case "all_time":
|
|
period = db.PeriodAllTime
|
|
default:
|
|
l.Debug().Msgf("OptsFromRequest: Using default value '%s' for period", db.PeriodDay)
|
|
period = db.PeriodDay
|
|
}
|
|
|
|
l.Debug().Msgf("OptsFromRequest: Parsed options: limit=%d, page=%d, week=%d, month=%d, year=%d, from=%d, to=%d, artist_id=%d, album_id=%d, track_id=%d, period=%s",
|
|
limit, page, week, month, year, from, to, artistId, albumId, trackId, period)
|
|
|
|
return db.GetItemsOpts{
|
|
Limit: limit,
|
|
Period: period,
|
|
Page: page,
|
|
Week: week,
|
|
Month: month,
|
|
Year: year,
|
|
From: int64(from),
|
|
To: int64(to),
|
|
ArtistID: artistId,
|
|
AlbumID: albumId,
|
|
TrackID: trackId,
|
|
}
|
|
}
|
|
|
|
// Takes a request and returns a db.Timeframe representing the week, month, year, period, or unix
|
|
// time range specified by the request parameters
|
|
func TimeframeFromRequest(r *http.Request) db.Timeframe {
|
|
opts := OptsFromRequest(r)
|
|
now := time.Now()
|
|
loc := now.Location()
|
|
|
|
// if 'from' is set, but 'to' is not set, assume 'to' should be now
|
|
if opts.From != 0 && opts.To == 0 {
|
|
opts.To = now.Unix()
|
|
}
|
|
|
|
// YEAR
|
|
if opts.Year != 0 && opts.Month == 0 && opts.Week == 0 {
|
|
start := time.Date(opts.Year, 1, 1, 0, 0, 0, 0, loc)
|
|
end := time.Date(opts.Year+1, 1, 1, 0, 0, 0, 0, loc).Add(-time.Second)
|
|
|
|
opts.From = start.Unix()
|
|
opts.To = end.Unix()
|
|
}
|
|
|
|
// MONTH (+ optional year)
|
|
if opts.Month != 0 {
|
|
year := opts.Year
|
|
if year == 0 {
|
|
year = now.Year()
|
|
if int(now.Month()) < opts.Month {
|
|
year--
|
|
}
|
|
}
|
|
|
|
start := time.Date(year, time.Month(opts.Month), 1, 0, 0, 0, 0, loc)
|
|
end := endOfMonth(year, time.Month(opts.Month), loc)
|
|
|
|
opts.From = start.Unix()
|
|
opts.To = end.Unix()
|
|
}
|
|
|
|
// WEEK (+ optional year)
|
|
if opts.Week != 0 {
|
|
year := opts.Year
|
|
if year == 0 {
|
|
year = now.Year()
|
|
|
|
_, currentWeek := now.ISOWeek()
|
|
if currentWeek < opts.Week {
|
|
year--
|
|
}
|
|
}
|
|
|
|
// ISO week 1 is defined as the week with Jan 4 in it
|
|
jan4 := time.Date(year, 1, 4, 0, 0, 0, 0, loc)
|
|
week1Start := startOfWeek(jan4)
|
|
|
|
start := week1Start.AddDate(0, 0, (opts.Week-1)*7)
|
|
end := endOfWeek(start)
|
|
|
|
opts.From = start.Unix()
|
|
opts.To = end.Unix()
|
|
}
|
|
|
|
return db.Timeframe{
|
|
Period: opts.Period,
|
|
T1u: opts.From,
|
|
T2u: opts.To,
|
|
}
|
|
}
|
|
func startOfWeek(t time.Time) time.Time {
|
|
// ISO week: Monday = 1
|
|
weekday := int(t.Weekday())
|
|
if weekday == 0 { // Sunday
|
|
weekday = 7
|
|
}
|
|
return time.Date(t.Year(), t.Month(), t.Day()-weekday+1, 0, 0, 0, 0, t.Location())
|
|
}
|
|
func endOfWeek(t time.Time) time.Time {
|
|
return startOfWeek(t).AddDate(0, 0, 7).Add(-time.Second)
|
|
}
|
|
func endOfMonth(year int, month time.Month, loc *time.Location) time.Time {
|
|
startNextMonth := time.Date(year, month+1, 1, 0, 0, 0, 0, loc)
|
|
return startNextMonth.Add(-time.Second)
|
|
}
|