{{define "detail.html"}} {{template "layout_head" .}} {{/* Detail sidebar: image tags grouped by category + related tags */}} {{template "layout_mid" .}}
{{/* Search bar: mirrors the gallery's #gallery-header so the input stays visually in place when switching between gallery and detail. Plain GET submit to / - no HTMX, since detail has no #gallery-grid target. The tag-suggest dropdown uses the same endpoint and ids gallery does so applySearchSuggest and initSuggestDismiss work unchanged. */}} {{/* Missing image banner */}} {{if .Image.IsMissing}}
⚠ This file is no longer present on disk.
{{end}}
{{/* Lookup / source-fetch outcomes and errors sit with the action flash so every job result reads from one spot; the tag-editor lookup's pending pill renders in #fetch-pending below the add-tag bar instead. */}} {{if .MonloaderPaired}}
{{end}} {{/* Top bar: back link | prev/next + download/fav (mirrors body column layout) */}}
{{if .RefURL}} ‹ Previous image {{else if or .BackQuery .BackSort}} ‹ Search {{else}} ‹ Search {{end}} {{if .Filename}} / {{.Filename}} {{end}}
{{if .PrevID}} ← Prev {{else}} {{end}} {{if .NextID}} Next → {{else}} {{end}}
{{if and (not (or (eq .Image.FileType "mp4") (eq .Image.FileType "webm"))) (not .IsManga) (not .Image.IsMissing)}} {{end}}

Source: add

{{template "suggest_input" dict "Name" "site" "InputID" "source-site-input" "Endpoint" "/internal/source/suggest" "SuggestID" "source-suggest"}}

Collection: add

{{template "suggest_input" dict "Name" "collection" "InputID" "collection-name-input" "Endpoint" "/internal/collection/suggest" "SuggestID" "collection-suggest"}}

Commentary:

Original source:

Add annotation

Position and size in original-image pixels{{if .Image.Width}} (image is {{deref .Image.Width}} × {{deref .Image.Height}}){{end}}.

Note

Original source

{{if .EnabledTaggers}}

Auto-tag this image. Pick which tagger to run.

{{range .EnabledTaggers}}{{end}}
{{end}}

Declare a relation between this image and another.

This image

image {{.Image.ID}}

Other image

Pick the other image and a relation type.

{{/* Left: media + nav */}}
{{/* Media */}}
{{if or (eq .Image.FileType "mp4") (eq .Image.FileType "webm")}} {{else if .IsManga}} Cover of manga {{.Image.ID}} {{else}}
image {{.Image.ID}} {{if .Annotations}}
{{range .Annotations}}
{{.Body}}
{{end}}
{{end}}
{{if .Annotations}}
{{end}} {{end}}
{{if .IsManga}}
Open in reader (R) {{if .Image.PageCount}}{{if gt (deref .Image.PageCount) 1}} See all pages (P) {{end}}{{end}}
{{end}} {{/* The operator's own note and hand-drawn annotations, under the image like a booru post page. Per-source commentary and pulled annotations live in the source panels beside the metadata. */}}
Personal note {{if .Image.Note}} {{else}} {{end}}
{{if .Image.Note}}
{{.Image.Note}}
{{end}}
Annotations
{{if .ManualAnnotations}}
    {{range .ManualAnnotations}}
  • {{if .Body}}{{.Body}}{{else}}(no text){{end}}
  • {{end}}
{{end}}
{{/* Tag editor */}}

Tags

{{template "partials/tag_list.html" (dict "ImageID" .Image.ID "ImageTags" .ImageTags "Aliases" .Aliases "CSRFToken" .CSRFToken)}}
{{if .EnabledTaggers}} {{end}} {{if .MonloaderPaired}} {{if .MonloaderPTR}} {{else}} {{end}} {{end}}
{{if .MonloaderPaired}}
{{end}} {{if and .MonloaderPaired .MonloaderPTR}}

Look up this file's tags and source via monloader:

{{if .MonloaderPTRSyncing}}

The Public Tag Repository is still syncing, so its answers come from partial data.

{{end}}
{{end}}
{{/* Danger zone: delete + a remove-tags dialog. Rendered via a partial so HTMX tag-list updates can refresh it via OOB swap. */}} {{template "partials/detail_danger_zone.html" (dict "ImageID" .Image.ID "ImageTags" .ImageTags "HasUserTags" .HasUserTags "ImageTaggers" .ImageTaggers "ImageSources" .ImageSources "CanTransfer" (gt (len .Galleries) 1) "CSRFToken" .CSRFToken "BackQuery" .BackQuery "BackSort" .BackSort "BackOrder" .BackOrder "BackPage" .BackPage "BackSeed" .BackSeed "Ref" .Ref "CurrentFolder" .Image.FolderPath)}} {{if gt (len .Galleries) 1}}

Transfer this image to another gallery:

The image and its tags, sources and notes are copied into the target gallery.

Relations and collections are not carried over.

{{end}}
{{/* Right: metadata panel */}}
Metadata
{{/* Basic metadata table */}} {{if .Image.Width}} {{end}} {{if .Image.DurationSec}} {{end}} {{if .Image.Origin}}{{end}} {{if and .IsManga .Image.PageCount}} {{end}} {{if .Image.AutoTaggedAt}} {{end}} {{if .Image.IsMissing}} {{end}}
Image ID
Path{{.Image.CanonicalPath}}
Type{{.Image.FileType}} {{if and .Image.SourceType (ne .Image.SourceType "none")}} AI {{if eq .Image.SourceType "a1111,comfyui"}} a1111 comfyui {{else}} {{.Image.SourceType}} {{end}} {{end}}
Resolution{{deref .Image.Width}} × {{deref .Image.Height}}
Duration{{printf "%.1f" (deref64f .Image.DurationSec)}} s
File size{{humanBytes .Image.FileSize}}
SHA-256
pHash {{if .Image.Phash}} {{$hex := phashHex .Image.Phash}} [search near-duplicates] {{else}} (not computed)
{{end}}
Ingested{{localTime .Image.IngestedAt}}
Added via{{.Image.Origin}}
Pages{{deref .Image.PageCount}}
Auto-tagged{{localTimePtr .Image.AutoTaggedAt}}
Status⚠ File missing from disk
{{/* Editable fields sit below the read-only metadata so a click on [edit] is visually separated from the rest of the panel. */}}
Sources {{if .Sources}}
    {{range $i, $src := .Sources}}
  • {{if .Site}}{{.Site}}{{if gt .Similarity 0.0}} ~{{printf "%.0f" .Similarity}}%{{end}}{{if .URL}} [open]{{end}}{{else}}{{.URL}}{{if gt .Similarity 0.0}} ~{{printf "%.0f" .Similarity}}%{{end}}{{end}} {{if gt $i 0}}
    {{end}} {{if not (isPTRSite .Site)}}{{end}} {{if and .URL $.MonloaderPaired}}
    {{else if and $.MonloaderPaired (isPTRSite .Site)}}
    {{end}}
  • {{end}}
{{else}}(none){{end}}
Original {{if .Image.OriginalSource}}{{urlDomain .Image.OriginalSource}}{{else}}(none){{end}} {{if .Image.OriginalSource}}
{{end}}
Collections {{if .Collections}}
    {{range .Collections}}
  • {{.Name}}{{if .Order}} #{{deref .Order}}{{end}}
  • {{end}}
{{else}}(none){{end}}
{{/* SD Generation metadata */}} {{if .SDMeta}}
► Generation data (SD / Forge)
{{if .SDMeta.GenerationHash}}
{{end}} {{if .SDMeta.Prompt}}
Prompt
{{.SDMeta.Prompt}}
{{end}} {{if .SDMeta.NegativePrompt}}
Negative prompt
{{.SDMeta.NegativePrompt}}
{{end}} {{if .SDMeta.ParsedParams}}
Parameters
{{range .SDMeta.ParsedParams}} {{end}}
{{.Key}} {{if isLongValue .Val}}
{{truncate .Val 140}}…
{{.Val}}
{{else}}{{.Val}}{{end}}
{{else if or .SDMeta.Model .SDMeta.Seed .SDMeta.Sampler .SDMeta.Steps .SDMeta.CFGScale}}
Parameters
{{if .SDMeta.Model}}{{end}} {{if .SDMeta.Seed}}{{end}} {{if .SDMeta.Sampler}}{{end}} {{if .SDMeta.Steps}}{{end}} {{if .SDMeta.CFGScale}}{{end}}
Model {{if isLongValue .SDMeta.Model}}
{{truncate .SDMeta.Model 140}}…
{{.SDMeta.Model}}
{{else}}{{.SDMeta.Model}}{{end}}
Seed{{deref64 .SDMeta.Seed}}
Sampler{{.SDMeta.Sampler}}
Steps{{deref .SDMeta.Steps}}
CFG Scale{{printf "%.1f" (deref64f .SDMeta.CFGScale)}}
{{end}}
{{end}} {{if .GenericMeta}}
► Other metadata
{{range .GenericMeta}} {{end}}
{{.Key}} {{if isLongValue .Val}}
{{truncate .Val 140}}…
{{.Val}}
{{else}}{{.Val}}{{end}}
{{end}} {{if .ComfyMeta}}
► Generation data (ComfyUI) {{if .ComfyMeta.GenerationHash}} {{end}} {{if .ComfyNodes}}
{{range .ComfyNodes}}
[{{.Key}}] {{.Title}}{{if ne .Title .ClassType}} {{.ClassType}}{{end}}
{{if .Params}} {{range .Params}} {{end}}
{{.Name}} {{if .IsRef}}{{.Value}}{{else if isLongValue .Value}}
{{truncate .Value 140}}…
{{.Value}}
{{else}}{{.Value}}{{end}}
{{end}}
{{end}}
{{else}}

No workflow nodes extracted.

{{end}}
{{end}} {{if .MangaMeta}}
► Comic / manga metadata
{{if .MangaMeta.Title}}{{end}} {{if .MangaMeta.Series}}{{end}} {{if .MangaMeta.Number}}{{end}} {{if .MangaMeta.Volume}}{{end}} {{if .MangaMeta.Count}}{{end}} {{if .MangaMeta.Year}}{{end}} {{if .MangaMeta.Writer}}{{end}} {{if .MangaMeta.Penciller}}{{end}} {{if .MangaMeta.Inker}}{{end}} {{if .MangaMeta.Colorist}}{{end}} {{if .MangaMeta.Letterer}}{{end}} {{if .MangaMeta.CoverArtist}}{{end}} {{if .MangaMeta.Editor}}{{end}} {{if .MangaMeta.Publisher}}{{end}} {{if .MangaMeta.Imprint}}{{end}} {{if .MangaMeta.Genre}}{{end}} {{if .MangaMeta.Web}}{{end}} {{if .MangaMeta.LanguageISO}}{{end}} {{if .MangaMeta.Format}}{{end}} {{if .MangaMeta.Manga}}{{end}} {{if .MangaMeta.AgeRating}}{{end}} {{if .MangaMeta.CommunityRating}}{{end}} {{if .MangaMeta.XMLPageCount}}{{end}}
Title{{.MangaMeta.Title}}
Series{{.MangaMeta.Series}}
Number{{.MangaMeta.Number}}
Volume{{.MangaMeta.Volume}}
Issue count{{deref .MangaMeta.Count}}
Date{{deref .MangaMeta.Year}}{{if .MangaMeta.Month}}-{{deref .MangaMeta.Month}}{{end}}{{if .MangaMeta.Day}}-{{deref .MangaMeta.Day}}{{end}}
Writer{{.MangaMeta.Writer}}
Penciller{{.MangaMeta.Penciller}}
Inker{{.MangaMeta.Inker}}
Colorist{{.MangaMeta.Colorist}}
Letterer{{.MangaMeta.Letterer}}
Cover artist{{.MangaMeta.CoverArtist}}
Editor{{.MangaMeta.Editor}}
Publisher{{.MangaMeta.Publisher}}
Imprint{{.MangaMeta.Imprint}}
Genre{{.MangaMeta.Genre}}
Web{{if or (hasPrefix .MangaMeta.Web "http://") (hasPrefix .MangaMeta.Web "https://")}}{{.MangaMeta.Web}}{{else}}{{.MangaMeta.Web}}{{end}}
Language{{.MangaMeta.LanguageISO}}
Format{{.MangaMeta.Format}}
Manga{{.MangaMeta.Manga}}
Age rating{{.MangaMeta.AgeRating}}
Community rating{{printf "%.2f" (deref64f .MangaMeta.CommunityRating)}}
XML page count{{deref .MangaMeta.XMLPageCount}}
{{if .MangaMeta.Summary}}
Summary
{{.MangaMeta.Summary}}
{{end}} {{if .MangaMeta.Notes}}
Notes
{{.MangaMeta.Notes}}
{{end}} {{if .MangaMeta.RawXML}}
Raw ComicInfo.xml
{{.MangaMeta.RawXML}}
{{end}}
{{end}}
{{/* One collapsible panel per source, carrying that origin's commentary and pulled annotations. The origin itself is edited from the metadata Sources row; here only the commentary body and the boxes are. */}} {{range .SourcePanels}}
{{if .Site}}{{.Site}}{{else}}source{{end}}
{{if .Annotations}} {{end}}
Original {{if .OriginalLines}}{{end}} {{if .Original}}
{{end}}
Commentary {{if .Commentary}}
{{.Commentary}}
{{end}} {{if .Commentary}}
{{end}}
Annotations
    {{range .Annotations}}
  • {{if .Body}}{{.Body}}{{else}}(no text){{end}}
  • {{end}}
{{end}}
{{/* end detail-meta-col */}}
{{template "layout_end" .}} {{end}}