Веб-UI: обзор жизненного цикла в карточке загрузки
Карточка списка на главной теперь даёт краткий обзор «от загрузки до
решения об удалении»: метка «ID:» перед идентификатором, дата добавления
(абсолютная + относительная, всегда), размер раздачи и рейтинг отдачи.
Спойлер контекста убран — контекст смотрят на /download/{id}.
Данные:
- рейтинг и общий размер — из живого снимка воркера (qbt total_size →
worker.Live.TotalSize); размер доступен для любой раздачи в снимке;
- размер-фолбэк, когда торрента нет в qBittorrent (orphaned) — сумма
размеров разложенных файлов: новая колонка file_link.size, layouter
пишет размер при линковке, ридер LayoutSizeByDownload суммирует по
странице одним запросом (дедуп по dst_path);
- дата — source_added_at → фолбэк created_at, показ в TZ сервера.
handleIndex читает снимок для всех карточек (map-lookup), рейтинг/размер
статичны на рендере (без поллинга). Миграция 0007, ER-схема обновлена.
Change download-card-lifecycle-overview влит в спеки и заархивирован.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,11 +14,11 @@ import (
|
||||
func TestPollBuildsLiveSnapshot(t *testing.T) {
|
||||
qb := &fakeQbt{torrents: []qbt.Torrent{
|
||||
// Качается (Category пуст → discover не усыновляет, store не мешает).
|
||||
{Hash: "aaa", State: "downloading", Progress: 0.5, Dlspeed: 1000, Eta: 120},
|
||||
{Hash: "aaa", State: "downloading", Progress: 0.5, Dlspeed: 1000, Eta: 120, TotalSize: 4096},
|
||||
// Сидирует, торрент v2 (три ключа).
|
||||
{
|
||||
Hash: "bbb", InfohashV1: "bbb1", InfohashV2: "BBB2",
|
||||
State: "uploading", Progress: 1.0,
|
||||
State: "uploading", Progress: 1.0, TotalSize: 8192,
|
||||
Ratio: 2.5, NumSeeds: 3, NumLeechs: 1, Uploaded: 999, Upspeed: 50,
|
||||
},
|
||||
}}
|
||||
@@ -38,6 +38,9 @@ func TestPollBuildsLiveSnapshot(t *testing.T) {
|
||||
if dl.Progress != 0.5 || dl.DlSpeed != 1000 || dl.ETA != 120 {
|
||||
t.Errorf("телеметрия качания неверна: %+v", dl)
|
||||
}
|
||||
if dl.TotalSize != 4096 {
|
||||
t.Errorf("полный размер качающейся задачи: got %d, want 4096", dl.TotalSize)
|
||||
}
|
||||
|
||||
// Сидирующая задача находится по любому из трёх хэшей (lowercase).
|
||||
for _, h := range []string{"bbb", "bbb1", "BBB2", "bbb2"} {
|
||||
@@ -51,6 +54,9 @@ func TestPollBuildsLiveSnapshot(t *testing.T) {
|
||||
if sd.Ratio != 2.5 || sd.Seeds != 3 || sd.Peers != 1 || sd.Uploaded != 999 || sd.UpSpeed != 50 {
|
||||
t.Errorf("ключ %q: статистика раздачи неверна: %+v", h, sd)
|
||||
}
|
||||
if sd.TotalSize != 8192 {
|
||||
t.Errorf("ключ %q: полный размер раздачи: got %d, want 8192", h, sd.TotalSize)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := w.Live("unknownhash"); ok {
|
||||
|
||||
@@ -278,6 +278,7 @@ func (w *Worker) linkPlan(ctx context.Context, d *store.Download, plan recognize
|
||||
DstPath: r.Link.Dst,
|
||||
Kind: string(r.Link.Kind),
|
||||
Status: string(r.Status),
|
||||
Size: r.Size,
|
||||
})
|
||||
}
|
||||
if len(fl) > 0 {
|
||||
|
||||
+17
-15
@@ -150,26 +150,28 @@ type Live struct {
|
||||
State string // сырое состояние qBittorrent
|
||||
Seeding bool // торрент завершён и раздаётся
|
||||
|
||||
Ratio float64 // рейтинг отдачи (может быть <0 = ∞/н/д)
|
||||
Seeds int // подключённые сиды
|
||||
Peers int // подключённые личи
|
||||
Uploaded int64 // отдано всего, байт
|
||||
UpSpeed int64 // скорость отдачи, байт/с
|
||||
TotalSize int64 // полный размер раздачи, байт (доступен для любой раздачи в снимке)
|
||||
Ratio float64 // рейтинг отдачи (может быть <0 = ∞/н/д)
|
||||
Seeds int // подключённые сиды
|
||||
Peers int // подключённые личи
|
||||
Uploaded int64 // отдано всего, байт
|
||||
UpSpeed int64 // скорость отдачи, байт/с
|
||||
}
|
||||
|
||||
// liveFrom собирает Live из торрента qBittorrent (Seeding — через classify).
|
||||
func liveFrom(t qbt.Torrent) Live {
|
||||
return Live{
|
||||
Progress: t.Progress,
|
||||
DlSpeed: t.Dlspeed,
|
||||
ETA: t.Eta,
|
||||
State: t.State,
|
||||
Seeding: classify(t.State) == classReady,
|
||||
Ratio: t.Ratio,
|
||||
Seeds: t.NumSeeds,
|
||||
Peers: t.NumLeechs,
|
||||
Uploaded: t.Uploaded,
|
||||
UpSpeed: t.Upspeed,
|
||||
Progress: t.Progress,
|
||||
DlSpeed: t.Dlspeed,
|
||||
ETA: t.Eta,
|
||||
State: t.State,
|
||||
Seeding: classify(t.State) == classReady,
|
||||
TotalSize: t.TotalSize,
|
||||
Ratio: t.Ratio,
|
||||
Seeds: t.NumSeeds,
|
||||
Peers: t.NumLeechs,
|
||||
Uploaded: t.Uploaded,
|
||||
UpSpeed: t.Upspeed,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user