Files
jellybit/web/templates/partials/download_main.html
T
avandClaude Opus 4.8 5948f4d219 Веб-UI: режиссёр в блоке «Распознано как» на странице загрузки
На /download/{id} поле «Режиссёр» было захардкожено прочерком, хотя экран
ревью режиссёра уже выводит: слоистое разрешение полей ярлыка было заперто в
неэкспортируемом worker.effectiveDisplayName. Из-за этого билдеры вью видели
только слой распознавания+матч (rd.Plan.Director) без слоя контекста — то же
на экране ревью.

Вынес разрешение в экспортируемую naming.EffectiveFields(parsedContext, plan)
LabelFields с методом Label(): выбор слоя по сырым значениям (как прежде),
выбранные скаляры возвращаются очищенными (sanitize идемпотентен, display_name
побайтно тот же). effectiveDisplayName стал тонкой обёрткой; страница загрузки
и экран ревью берут режиссёра из той же функции — согласованно с заголовком.

OpenSpec: web-ui (ADDED «Режиссёр в блоке распознавания страницы загрузки»),
review (MODIFIED «Инфо и предпросмотр выбранного источника» — слоистое
разрешение с фолбэком на контекст). Change заархивирован. Беклог: закрыта
rezhisser-v-kartochke-zagruzki.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-17 21:21:27 +03:00

131 lines
9.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "download_main"}}
<main class="main" id="download-main"{{if .SelfPoll}} hx-get="/download/{{.ID}}" hx-trigger="every 3s" hx-select="#download-main" hx-swap="outerHTML"{{end}}>
<a class="back-link" href="/">← ко всем загрузкам</a>
{{if .Error}}<div class="result-banner" style="background:var(--st-err-bg);border-color:color-mix(in srgb,var(--st-err) 35%,transparent)"><h2 style="color:var(--st-err)">{{.Error}}</h2></div>{{end}}
{{if .ActionError}}<div class="result-banner" style="background:var(--st-err-bg);border-color:color-mix(in srgb,var(--st-err) 35%,transparent)"><h2 style="color:var(--st-err)">{{.ActionError}}</h2></div>{{end}}
<!-- Шапка -->
<div class="review-head" style="margin-bottom:var(--sp-4)">
<div>
<div class="review-title" style="font-size:var(--fs-xl)">{{.Title}}</div>
<div class="hash-row" style="margin-top:9px">
{{template "status_badge" .State}}
<span class="hash">{{.ID}}</span>
<button class="copy-btn" type="button" onclick="copyHash(this,'{{.ID}}')">⧉ копировать</button>
</div>
{{if .Added}}<p class="muted" style="margin:var(--sp-2) 0 0">Добавлено {{.Added}} <span class="ago">({{.AddedAgo}})</span></p>{{end}}
{{if .Note}}<p class="muted" style="margin:var(--sp-2) 0 0">{{.Note}}</p>{{end}}
</div>
<div class="card-acts" style="align-items:center">
{{if .Reviewable}}<a class="btn btn-primary" href="/review/{{.ID}}">Ревью →</a>{{end}}
{{if .Nameable}}<form method="post" action="/ui/downloads/{{.ID}}/refresh-name" hx-post="/ui/downloads/{{.ID}}/refresh-name" hx-target="#download-main" hx-swap="outerHTML"><button class="btn" type="submit" title="Перелить распознанное название в имя загрузки и раздачи">Обновить имя</button></form>{{end}}
{{if .Undoable}}<form method="post" action="/ui/downloads/{{.ID}}/undo" hx-post="/ui/downloads/{{.ID}}/undo" hx-target="#download-main" hx-swap="outerHTML"><input type="hidden" name="surface" value="download"><button class="btn btn-danger" type="submit">↩ Откатить</button></form>{{end}}
{{if .Relinkable}}<form method="post" action="/ui/downloads/{{.ID}}/relink" hx-post="/ui/downloads/{{.ID}}/relink" hx-target="#download-main" hx-swap="outerHTML"><input type="hidden" name="surface" value="download"><button class="btn" type="submit">Привязать заново</button></form>{{end}}
{{if .Retriable}}<form method="post" action="/ui/downloads/{{.ID}}/retry" hx-post="/ui/downloads/{{.ID}}/retry" hx-target="#download-main" hx-swap="outerHTML"><input type="hidden" name="surface" value="download"><button class="btn" type="submit">Повторить</button></form>{{end}}
{{if not .Terminal}}<form method="post" action="/ui/downloads/{{.ID}}/cancel" hx-post="/ui/downloads/{{.ID}}/cancel" hx-target="#download-main" hx-swap="outerHTML"><input type="hidden" name="surface" value="download"><button class="btn btn-danger" type="submit">Отменить</button></form>{{end}}
</div>
</div>
<!-- Распознано как -->
<div class="section">
<div class="section-head"><h2>Распознано как</h2></div>
{{if .HasPlan}}
<dl class="kv">
<dt>Название</dt><dd>{{.RecTitle}}</dd>
<dt>Ориг. название</dt><dd>{{if .OriginalTitle}}{{.OriginalTitle}}{{else}}<span class="faint"></span>{{end}}</dd>
<dt>Тип</dt><dd>{{if .IsSeries}}сериал{{else if eq .MediaType "movie"}}фильм{{else}}{{.MediaType}}{{end}}</dd>
{{if .IsSeries}}<dt>Сезон</dt><dd>{{if .Season}}{{.Season}}{{else}}<span class="faint"></span>{{end}}</dd>{{end}}
<dt>Год</dt><dd>{{if .Year}}{{.Year}}{{else}}<span class="faint"></span>{{end}}</dd>
<dt>Режиссёр</dt><dd>{{if .Director}}{{.Director}}{{else}}<span class="faint"></span>{{end}}</dd>
<dt>База</dt><dd>{{if .Provider}}{{if .MatchURL}}<a class="ext-link" href="{{.MatchURL}}" target="_blank" rel="noopener">{{.Provider}} · {{.ProviderID}} ↗</a>{{else}}{{.Provider}} · <span class="mono">{{.ProviderID}}</span>{{end}}{{else if .NoBase}}без базы{{else}}<span class="faint"></span>{{end}}</dd>
<dt>Уверенность</dt><dd class="mono">{{if .Confidence}}{{.Confidence}}{{else}}<span class="faint"></span>{{end}}</dd>
</dl>
{{else}}
<p class="muted" style="margin:0">Ещё не распознано.</p>
{{end}}
</div>
<!-- Файлы и раскладка -->
{{if .HasPlan}}
<div class="section">
<div class="section-head"><h2>Файлы и раскладка</h2><span class="hint">файл источника → целевой хардлинк</span></div>
{{template "layout_widget" .Files}}
<p class="faint" style="font-size:var(--fs-xs);margin:var(--sp-3) 0 0">
Целевые файлы связаны хардлинками — место не дублируется, исходник остаётся на раздаче.
</p>
</div>
{{end}}
<!-- Раздача (живая статистика; секция деградирует, если торрент не сидирует) -->
{{template "seeding" .Seeding}}
<!-- История -->
<div class="section">
<div class="section-head"><h2>История</h2></div>
<ul class="timeline">
{{if .CreatedAt}}<li class="tl-item is-done"><div class="tl-t">Добавлено</div><time>{{.CreatedAt}}</time></li>{{end}}
<li class="tl-item is-now"><div class="tl-t">{{badgeLabel .State}} <span class="badge st-{{.State}}">текущее</span></div>{{if .UpdatedAt}}<time>{{.UpdatedAt}}</time>{{end}}</li>
</ul>
</div>
<!-- Контекст -->
{{if .Context}}
<div class="section">
<div class="section-head"><h2>Контекст</h2><span class="hint">сообщение при добавлении</span></div>
<p style="margin:0;color:var(--text-dim)">«{{.Context}}»</p>
</div>
{{end}}
<!-- Информация о торренте -->
<div class="section">
<div class="section-head"><h2>Информация о торренте</h2><span class="hint">сырой источник и infohash</span></div>
<dl class="kv">
<dt>Тип источника</dt><dd>{{.SourceType}}</dd>
{{range .Infohashes}}<dt>infohash</dt><dd class="mono">{{.}}</dd>{{end}}
</dl>
{{if .SourceFull}}
<div class="src-block">
<code class="src-full">{{.SourceFull}}</code>
<button class="copy-btn" type="button" onclick="copyHash(this,'{{.SourceFull}}')">⧉ копировать</button>
</div>
{{end}}
</div>
<!-- Опасная зона: закрытие (только смена статуса) и полное удаление (снять
хардлинки + снести раздачу). Секция скрыта в details (раскрыть сознательно).
С JS hx-confirm показывает диалог подтверждения; без JS гейт — только
раскрытие details и явный submit (диалога нет). -->
{{if or .Dismissable .Deletable}}
<details class="section danger-zone" style="margin-bottom:0;border-color:color-mix(in srgb,var(--st-err) 35%,transparent)">
<summary style="color:var(--st-err);cursor:pointer;font-weight:600">Опасная зона</summary>
{{if .Dismissable}}
<p class="muted" style="margin:var(--sp-3) 0">
Закрытие снимет запись из активного списка (перевод в «отменено») —
<strong>файлы и раздачу не трогает</strong>. Стоп-кран для зависшей, спорной
или лишней загрузки; при необходимости позже можно привязать заново.
</p>
<form method="post" action="/ui/downloads/{{.ID}}/dismiss"
hx-post="/ui/downloads/{{.ID}}/dismiss" hx-target="#download-main" hx-swap="outerHTML"
hx-confirm="Закрыть загрузку? Запись уйдёт в «отменено». Файлы и раздача останутся нетронутыми.">
<input type="hidden" name="surface" value="download">
<button class="btn btn-danger" type="submit">Закрыть загрузку</button>
</form>
{{end}}
{{if .Deletable}}
<p class="muted" style="margin:var(--sp-3) 0">
Полное удаление снимет библиотечные хардлинки <strong>и</strong> снесёт раздачу
с файлами из qBittorrent — освободит место. Действие необратимо.
</p>
<form method="post" action="/ui/downloads/{{.ID}}/delete"
hx-post="/ui/downloads/{{.ID}}/delete" hx-target="#download-main" hx-swap="outerHTML"
hx-confirm="Удалить загрузку? Раздача и файлы будут снесены, место освобождено. Действие необратимо.">
<input type="hidden" name="surface" value="download">
<button class="btn btn-danger" type="submit">Удалить загрузку</button>
</form>
{{end}}
</details>
{{end}}
</main>
{{end}}