Show metadata as read-only by default

This commit is contained in:
Dymas
2026-09-15 16:06:41 +02:00
parent 553bd6f427
commit 1a94607712
6 changed files with 106 additions and 30 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog
## 1.4.1 - 2026-09-15
- Changed title details to show metadata as read-only text by default.
- Added an explicit `Edit` action that opens the metadata form only when needed.
## 1.4.0 - 2026-09-15
- Added missing metadata fetching from AniList, with AniDB fallback when AniList has no usable match or is unavailable.
+1 -1
View File
@@ -70,7 +70,7 @@ If an older `data/metadata.json` file exists, the app imports it into SQLite on
## Metadata Fields
Use the app to edit:
Title details show metadata as normal read-only text by default. Use the `Edit` button to change:
- display title
- short description
+1 -1
View File
@@ -1 +1 @@
1.4.0
1.4.1
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "h-player",
"version": "1.4.0",
"version": "1.4.1",
"private": true,
"description": "A small private web app for browsing a folder-based video collection.",
"scripts": {
+61 -26
View File
@@ -120,25 +120,26 @@ function renderDetails(title) {
<p>${escapeHtml(title.folder)} · ${title.count} file${title.count === 1 ? "" : "s"} · ${bytes(title.size)}</p>
</div>
<div class="summary__actions">
<button id="editMetaBtn" type="button">Edit</button>
<button id="fetchMetadataBtn" type="button">Metadata</button>
<button id="makeThumbBtn" type="button">Thumbnail</button>
</div>
</div>
<form id="metaForm" class="meta-form">
<label>
<div id="metaView" class="meta-view">
<section>
<span>Display title</span>
<input name="title" value="${escapeAttr(title.title)}">
</label>
<label>
<span>Thumbnail path or URL</span>
<input name="thumbnail" value="${escapeAttr(title.thumbnail)}" placeholder="/thumbs/example.jpg">
</label>
<label>
<span>Short description</span>
<textarea name="description" rows="5" placeholder="Add a private note or synopsis">${escapeHtml(title.description)}</textarea>
</label>
<button class="primary" type="submit">Save metadata</button>
</form>
<p>${escapeHtml(title.title)}</p>
</section>
<section>
<span>Thumbnail</span>
<p>${title.thumbnail ? escapeHtml(title.thumbnail) : "No thumbnail set"}</p>
</section>
<section>
<span>Description</span>
<p>${title.description ? escapeHtml(title.description) : "No description yet"}</p>
</section>
</div>
<div id="metaEditMount"></div>
</div>
</div>
<div class="seasons">
@@ -146,18 +147,8 @@ function renderDetails(title) {
</div>
`;
document.querySelector("#metaForm").addEventListener("submit", async (event) => {
event.preventDefault();
const form = new FormData(event.currentTarget);
await api(`/api/titles/${encodeURIComponent(title.id)}`, {
method: "PATCH",
body: JSON.stringify({
title: form.get("title"),
thumbnail: form.get("thumbnail"),
description: form.get("description")
})
});
await loadLibrary();
document.querySelector("#editMetaBtn").addEventListener("click", () => {
renderMetadataForm(title);
});
document.querySelector("#makeThumbBtn").addEventListener("click", async (event) => {
@@ -187,6 +178,50 @@ function renderDetails(title) {
});
}
function renderMetadataForm(title) {
document.querySelector("#metaView").classList.add("hidden");
const mount = document.querySelector("#metaEditMount");
mount.innerHTML = `
<form id="metaForm" class="meta-form">
<label>
<span>Display title</span>
<input name="title" value="${escapeAttr(title.title)}">
</label>
<label>
<span>Thumbnail path or URL</span>
<input name="thumbnail" value="${escapeAttr(title.thumbnail)}" placeholder="/thumbs/example.jpg">
</label>
<label>
<span>Short description</span>
<textarea name="description" rows="5" placeholder="Add a private note or synopsis">${escapeHtml(title.description)}</textarea>
</label>
<div class="meta-form__actions">
<button class="primary" type="submit">Save metadata</button>
<button id="cancelMetaBtn" class="ghost" type="button">Cancel</button>
</div>
</form>
`;
document.querySelector("#cancelMetaBtn").addEventListener("click", () => {
mount.innerHTML = "";
document.querySelector("#metaView").classList.remove("hidden");
});
document.querySelector("#metaForm").addEventListener("submit", async (event) => {
event.preventDefault();
const form = new FormData(event.currentTarget);
await api(`/api/titles/${encodeURIComponent(title.id)}`, {
method: "PATCH",
body: JSON.stringify({
title: form.get("title"),
thumbnail: form.get("thumbnail"),
description: form.get("description")
})
});
await loadLibrary();
});
}
function renderSeason(season) {
return `
<section class="season">
+37 -1
View File
@@ -451,13 +451,49 @@ label {
margin-top: 0.45rem;
}
.meta-view {
display: grid;
gap: 12px;
max-width: 780px;
}
.meta-view section {
display: grid;
gap: 6px;
border: 1px solid var(--line);
border-radius: 16px;
background: rgba(255, 255, 255, 0.03);
padding: 14px;
}
.meta-view span {
color: var(--muted);
font-size: 11px;
font-weight: 800;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.meta-view p {
margin: 0;
color: var(--text);
white-space: pre-wrap;
overflow-wrap: anywhere;
}
.meta-form {
display: grid;
gap: 0.85rem;
max-width: 780px;
}
.meta-form button {
.meta-form__actions {
display: flex;
gap: 8px;
flex-wrap: wrap;
}
.meta-form .primary {
justify-self: start;
background: linear-gradient(135deg, var(--accent), var(--accent-strong));
border-color: transparent;