待ち行列への登録と状態表示を追加(新着からの登録、/queue、DATABASE_URL)
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"gitea.kazu634.com/kazu634/tver/internal/store"
|
||||
"gitea.kazu634.com/kazu634/tver/internal/tver"
|
||||
)
|
||||
|
||||
@@ -34,6 +35,10 @@ type newerOptions struct {
|
||||
}
|
||||
|
||||
type episodeView struct {
|
||||
ID string
|
||||
Genre string
|
||||
Status string
|
||||
StatusText string
|
||||
URL string
|
||||
ThumbnailURL string
|
||||
SeriesTitle string
|
||||
@@ -50,6 +55,7 @@ type newerView struct {
|
||||
HidePreviews bool
|
||||
Episodes []episodeView
|
||||
Failed bool
|
||||
ErrorText string
|
||||
}
|
||||
|
||||
func parseNewerOptions(r *http.Request) (newerOptions, error) {
|
||||
@@ -123,14 +129,34 @@ func (s *server) newerView(ctx context.Context, options newerOptions) newerView
|
||||
if err != nil {
|
||||
s.logger.Printf("TVer の新着取得に失敗(genre=%s): %s", options.genre, platformTokenPattern.ReplaceAllString(err.Error(), "${1}[REDACTED]"))
|
||||
view.Failed = true
|
||||
view.ErrorText = "新着を取得できませんでした"
|
||||
return view
|
||||
}
|
||||
visible := make([]tver.Episode, 0, len(episodes))
|
||||
for _, episode := range episodes {
|
||||
if options.hidePreviews && episode.Duration <= previewMaxSeconds {
|
||||
continue
|
||||
}
|
||||
visible = append(visible, episode)
|
||||
}
|
||||
ids := make([]string, 0, len(visible))
|
||||
for _, episode := range visible {
|
||||
ids = append(ids, episode.ID)
|
||||
}
|
||||
statuses, err := s.jobs.EpisodeStatuses(ctx, ids)
|
||||
if err != nil {
|
||||
s.logger.Printf("新着のジョブ状態取得に失敗: %v", err)
|
||||
view.Failed = true
|
||||
view.ErrorText = "状態を取得できませんでした"
|
||||
return view
|
||||
}
|
||||
for _, episode := range visible {
|
||||
endAt := time.Unix(episode.EndAt, 0).In(s.zone)
|
||||
view.Episodes = append(view.Episodes, episodeView{
|
||||
ID: episode.ID,
|
||||
Genre: options.genre,
|
||||
Status: statuses[episode.ID],
|
||||
StatusText: statusText(statuses[episode.ID]),
|
||||
URL: "https://tver.jp/episodes/" + url.PathEscape(episode.ID),
|
||||
ThumbnailURL: "https://statics.tver.jp" + episode.ThumbnailPath,
|
||||
SeriesTitle: episode.SeriesTitle,
|
||||
@@ -145,6 +171,32 @@ func (s *server) newerView(ctx context.Context, options newerOptions) newerView
|
||||
return view
|
||||
}
|
||||
|
||||
func (s *server) cachedEpisode(genre, id string) (tver.Episode, bool) {
|
||||
s.cacheMu.Lock()
|
||||
defer s.cacheMu.Unlock()
|
||||
entry, ok := s.cache[genre]
|
||||
if !ok || !s.now().Before(entry.expiresAt) {
|
||||
return tver.Episode{}, false
|
||||
}
|
||||
for _, ep := range entry.episodes {
|
||||
if ep.ID == id {
|
||||
return ep, true
|
||||
}
|
||||
}
|
||||
return tver.Episode{}, false
|
||||
}
|
||||
|
||||
func storeEpisode(ep tver.Episode) store.Episode {
|
||||
var endAt *time.Time
|
||||
if ep.EndAt > 0 {
|
||||
end := time.Unix(ep.EndAt, 0)
|
||||
endAt = &end
|
||||
}
|
||||
return store.Episode{ID: ep.ID, SeriesID: ep.SeriesID, SeriesTitle: ep.SeriesTitle,
|
||||
Title: ep.Title, BroadcasterName: ep.BroadcasterName, DurationSeconds: int(ep.Duration),
|
||||
EndAt: endAt, ThumbnailPath: ep.ThumbnailPath}
|
||||
}
|
||||
|
||||
func durationMinutes(seconds int64) int64 {
|
||||
minutes := seconds / 60
|
||||
if seconds%60 != 0 {
|
||||
|
||||
Reference in New Issue
Block a user