153 lines
4.1 KiB
Go
153 lines
4.1 KiB
Go
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
|
|
}
|