ライブラリを番組一覧・番組ページ・再生の3段にする(ステップ12)

This commit is contained in:
2026-10-10 12:18:58 +09:00
parent 511365f0d4
commit 6586d7edd2
12 changed files with 766 additions and 28 deletions
+63
View File
@@ -42,6 +42,14 @@ type Job struct {
CreatedAt, UpdatedAt time.Time
}
type LibrarySeries struct {
SeriesID, SeriesTitle, LatestTitle string
BroadcasterName, ThumbnailPath string
EpisodeCount, TotalSizeBytes int64
LatestFinishedAt *time.Time
Subscribed bool
}
type Progress struct {
Phase string
DownloadedBytes *int64
@@ -138,6 +146,61 @@ func (s *Store) ListSucceededJobs(ctx context.Context, limit int) ([]Job, error)
return jobs, rows.Err()
}
func (s *Store) ListLibrarySeries(ctx context.Context) ([]LibrarySeries, error) {
rows, err := s.pool.Query(ctx, `WITH totals AS (
SELECT series_id, count(*) AS episode_count,
COALESCE(sum(file_size_bytes), 0) AS total_size_bytes
FROM download_jobs WHERE status='succeeded' GROUP BY series_id
), latest AS (
SELECT DISTINCT ON (series_id) series_id, series_title, title,
broadcaster_name, thumbnail_path, finished_at, id
FROM download_jobs WHERE status='succeeded'
ORDER BY series_id, finished_at DESC NULLS LAST, id DESC
)
SELECT l.series_id, l.series_title, l.title, l.broadcaster_name,
l.thumbnail_path, t.episode_count, t.total_size_bytes, l.finished_at,
EXISTS (SELECT 1 FROM subscriptions s WHERE s.series_id=l.series_id)
FROM latest l JOIN totals t USING (series_id)
ORDER BY l.finished_at DESC NULLS LAST, l.id DESC`)
if err != nil {
return nil, err
}
defer rows.Close()
var result []LibrarySeries
for rows.Next() {
var item LibrarySeries
if err := rows.Scan(&item.SeriesID, &item.SeriesTitle, &item.LatestTitle,
&item.BroadcasterName, &item.ThumbnailPath, &item.EpisodeCount,
&item.TotalSizeBytes, &item.LatestFinishedAt, &item.Subscribed); err != nil {
return nil, err
}
result = append(result, item)
}
return result, rows.Err()
}
func (s *Store) ListSucceededJobsBySeries(ctx context.Context, seriesID string) ([]Job, error) {
if seriesID == "" {
return nil, errors.New("series ID must not be empty")
}
rows, err := s.pool.Query(ctx, `SELECT `+jobColumns+` FROM download_jobs
WHERE status='succeeded' AND series_id=$1
ORDER BY finished_at DESC NULLS LAST, id DESC`, seriesID)
if err != nil {
return nil, err
}
defer rows.Close()
var jobs []Job
for rows.Next() {
job, err := scanJob(rows)
if err != nil {
return nil, err
}
jobs = append(jobs, job)
}
return jobs, rows.Err()
}
func (s *Store) DeleteSucceededJob(ctx context.Context, id int64) error {
tag, err := s.pool.Exec(ctx, `DELETE FROM download_jobs WHERE id=$1 AND status='succeeded'`, id)
return transitionResult(tag.RowsAffected(), err)