Files
djk/internal/app/ui_rankings.go
T

110 lines
2.9 KiB
Go

package app
import (
"context"
"fmt"
"net/http"
"strconv"
"time"
)
func (a *UIApp) handleRankings(writer http.ResponseWriter, request *http.Request) {
if request.Method != http.MethodGet {
writeJSON(writer, http.StatusMethodNotAllowed, map[string]string{"error": "method not allowed"})
return
}
id := request.URL.Query().Get("board")
if id == "" {
writeJSON(writer, http.StatusOK, map[string]any{"boards": sourceRankingBoards(request.Context())})
return
}
board, found := findRankingBoard(id)
pageText := firstNonEmpty(request.URL.Query().Get("page"), "1")
page, err := strconv.Atoi(pageText)
if !found || err != nil || page < 1 || page > 500 || board.Source == "huangguo" && page != 1 {
writeJSON(writer, http.StatusBadRequest, map[string]string{"error": "榜单或页码无效"})
return
}
if !requireSource(writer, request.Context(), board.Source) {
return
}
ctx, cancel := context.WithTimeout(request.Context(), 40*time.Second)
defer cancel()
result, err := a.downloader.loadRankingPage(ctx, board, page, request.URL.Query().Get("refresh") == "1")
if err != nil {
if request.Context().Err() != nil {
return
}
fmt.Printf("%s榜单获取失败: %v\n", board.Source, publicError(err))
writeJSON(writer, http.StatusBadGateway, map[string]string{"error": "站点榜单暂不可用,请稍后重试"})
return
}
if ctx.Err() != nil {
return
}
a.acceptRankingDramas(result)
a.mu.Lock()
saved := a.librarySaved && !a.libraryDirty
a.mu.Unlock()
writeJSON(writer, http.StatusOK, struct {
rankingPage
Saved bool `json:"saved"`
}{result, saved})
}
func (a *UIApp) acceptRankingDramas(page rankingPage) {
if len(page.Items) == 0 {
return
}
key := page.BoardID + ":" + strconv.Itoa(page.Page)
a.mu.Lock()
if a.rankingApplied == nil {
a.rankingApplied = map[string]time.Time{}
}
if a.rankingApplied[key].Equal(page.FetchedAt) {
a.mu.Unlock()
return
}
if len(a.rankingApplied) >= 256 {
a.rankingApplied = map[string]time.Time{}
}
a.rankingApplied[key] = page.FetchedAt
fresh := make([]Drama, 0, len(page.Items))
for _, item := range page.Items {
fresh = append(fresh, item.Drama)
}
a.normalizeDramaCovers(fresh)
newDramas := a.newSortMetadataDramasLocked(fresh)
if page.Stale {
a.dramas = mergeLoadedDramas(fresh, a.dramas, nil)
} else {
a.dramas = mergeLoadedDramas(a.dramas, fresh, nil)
}
a.enqueueSortMetadataLocked(newDramas, false)
if a.librarySources == nil {
a.librarySources = map[string]librarySourceState{}
}
source := dramaProvider(fresh[0])
state := a.librarySources[source]
state.Count = 0
for _, drama := range a.dramas {
if dramaProvider(drama) == source {
state.Count++
}
}
if state.Status == "" {
state.Status = "ready"
}
if page.FetchedAt.After(state.UpdatedAt) {
state.UpdatedAt = page.FetchedAt
}
a.librarySources[source] = state
if page.FetchedAt.After(a.loadedAt) {
a.loadedAt = page.FetchedAt
}
a.libraryDirty = true
a.libraryRevision++
a.mu.Unlock()
a.persistLibrary()
}