feat: add public watchlist export
This commit is contained in:
152
internal/watchlist/export.go
Normal file
152
internal/watchlist/export.go
Normal file
@@ -0,0 +1,152 @@
|
||||
package watchlist
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"mal/internal/domain"
|
||||
)
|
||||
|
||||
type publicWatchlist struct {
|
||||
SchemaVersion string `json:"schema_version"`
|
||||
GeneratedAt time.Time `json:"generated_at"`
|
||||
UserID string `json:"user_id"`
|
||||
Summary watchlistSummary `json:"summary"`
|
||||
Entries []publicWatchlistEntry `json:"entries"`
|
||||
}
|
||||
|
||||
type watchlistSummary struct {
|
||||
Total int `json:"total"`
|
||||
Watching int `json:"watching"`
|
||||
Completed int `json:"completed"`
|
||||
PlanToWatch int `json:"plan_to_watch"`
|
||||
OnHold int `json:"on_hold"`
|
||||
Dropped int `json:"dropped"`
|
||||
}
|
||||
|
||||
type publicWatchlistEntry struct {
|
||||
MALID int64 `json:"mal_id"`
|
||||
Status string `json:"status"`
|
||||
AddedAt time.Time `json:"added_at"`
|
||||
CompletedAt *time.Time `json:"completed_at"`
|
||||
CompletionDateAccuracy *string `json:"completion_date_accuracy"`
|
||||
LastWatchedAt *time.Time `json:"last_watched_at"`
|
||||
Progress watchlistProgress `json:"progress"`
|
||||
Titles watchlistTitles `json:"titles"`
|
||||
}
|
||||
|
||||
type watchlistProgress struct {
|
||||
CurrentEpisode *int64 `json:"current_episode"`
|
||||
CurrentTimeSeconds *float64 `json:"current_time_seconds"`
|
||||
}
|
||||
|
||||
type watchlistTitles struct {
|
||||
Preferred string `json:"preferred"`
|
||||
Original string `json:"original"`
|
||||
English *string `json:"english"`
|
||||
Japanese *string `json:"japanese"`
|
||||
}
|
||||
|
||||
func newPublicWatchlist(userID string, rows []domain.UserWatchListRow, generatedAt time.Time) publicWatchlist {
|
||||
export := publicWatchlist{
|
||||
SchemaVersion: "1.0",
|
||||
GeneratedAt: generatedAt,
|
||||
UserID: userID,
|
||||
Entries: make([]publicWatchlistEntry, 0, len(rows)),
|
||||
}
|
||||
|
||||
for _, row := range rows {
|
||||
export.Summary.add(row.Status)
|
||||
export.Entries = append(export.Entries, newPublicWatchlistEntry(row))
|
||||
}
|
||||
|
||||
return export
|
||||
}
|
||||
|
||||
func (s *watchlistSummary) add(status string) {
|
||||
s.Total++
|
||||
switch status {
|
||||
case "watching":
|
||||
s.Watching++
|
||||
case "completed":
|
||||
s.Completed++
|
||||
case "plan_to_watch":
|
||||
s.PlanToWatch++
|
||||
case "on_hold":
|
||||
s.OnHold++
|
||||
case "dropped":
|
||||
s.Dropped++
|
||||
}
|
||||
}
|
||||
|
||||
func newPublicWatchlistEntry(row domain.UserWatchListRow) publicWatchlistEntry {
|
||||
currentEpisode := nullableInt64(row.CurrentEpisode.Int64, row.CurrentEpisode.Valid)
|
||||
currentTimeSeconds := nullableFloat64(row.CurrentTimeSeconds, row.CurrentEpisode.Valid)
|
||||
lastWatchedAt := nullableTime(row.LastEpisodeAt.Time, row.LastEpisodeAt.Valid)
|
||||
if row.PlaybackCurrentEpisode.Valid {
|
||||
currentEpisode = &row.PlaybackCurrentEpisode.Int64
|
||||
currentTimeSeconds = nullableFloat64(row.PlaybackCurrentTimeSeconds.Float64, row.PlaybackCurrentTimeSeconds.Valid)
|
||||
lastWatchedAt = nullableTime(row.PlaybackUpdatedAt.Time, row.PlaybackUpdatedAt.Valid)
|
||||
}
|
||||
|
||||
entry := publicWatchlistEntry{
|
||||
MALID: row.AnimeID,
|
||||
Status: row.Status,
|
||||
AddedAt: row.CreatedAt,
|
||||
LastWatchedAt: lastWatchedAt,
|
||||
Progress: watchlistProgress{
|
||||
CurrentEpisode: currentEpisode,
|
||||
CurrentTimeSeconds: currentTimeSeconds,
|
||||
},
|
||||
Titles: watchlistTitles{
|
||||
Preferred: row.DisplayTitle(),
|
||||
Original: row.TitleOriginal,
|
||||
English: nullableString(row.TitleEnglish.String, row.TitleEnglish.Valid),
|
||||
Japanese: nullableString(row.TitleJapanese.String, row.TitleJapanese.Valid),
|
||||
},
|
||||
}
|
||||
|
||||
if row.Status == "completed" {
|
||||
accuracy := "exact"
|
||||
if row.CompletedAt.Valid {
|
||||
entry.CompletedAt = &row.CompletedAt.Time
|
||||
if row.CompletedAtEstimated {
|
||||
accuracy = "estimated_from_historical_update"
|
||||
}
|
||||
} else {
|
||||
entry.CompletedAt = &row.UpdatedAt
|
||||
accuracy = "estimated_from_historical_update"
|
||||
}
|
||||
entry.CompletionDateAccuracy = &accuracy
|
||||
}
|
||||
|
||||
return entry
|
||||
}
|
||||
|
||||
func nullableString(value string, valid bool) *string {
|
||||
if !valid || strings.TrimSpace(value) == "" {
|
||||
return nil
|
||||
}
|
||||
return &value
|
||||
}
|
||||
|
||||
func nullableInt64(value int64, valid bool) *int64 {
|
||||
if !valid {
|
||||
return nil
|
||||
}
|
||||
return &value
|
||||
}
|
||||
|
||||
func nullableFloat64(value float64, valid bool) *float64 {
|
||||
if !valid {
|
||||
return nil
|
||||
}
|
||||
return &value
|
||||
}
|
||||
|
||||
func nullableTime(value time.Time, valid bool) *time.Time {
|
||||
if !valid {
|
||||
return nil
|
||||
}
|
||||
return &value
|
||||
}
|
||||
Reference in New Issue
Block a user