Show metadata as read-only by default
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user