92e5326437
confirm_and_apply no longer marks candidates confirmed before their apply job actually succeeds (a stuck/skipped_lock run was silently vanishing confirmed deletes without deleting anything), switches the fuzzy pass to --apply-pairs to avoid a full rescan on every confirm, and adds a job timeout so a hung subprocess can't hold the global pipeline lock forever. dedup-library.sh's Pass 2-4 use gawk-only features (gensub, POSIX interval regex) but were running under mawk (Debian's default awk) in the deployed image, throwing silent syntax errors on every run -- switched those invocations to gawk explicitly and added it to the Dockerfile. Also: per-track delete button on the library list/detail pages, and two CSS fixes (the primary button's hover gradient was getting clobbered by the base .btn:hover rule's plain background, and the select dropdown arrow had no background-size so it rendered oversized).
63 lines
2.4 KiB
HTML
63 lines
2.4 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ item.artist }} — {{ item.title }} — alembic{% endblock %}
|
|
{% block content %}
|
|
<a class="back-link" href="/library">← back to library</a>
|
|
|
|
<div class="page-header">
|
|
<div>
|
|
<h1>{{ item.artist }} — {{ item.title }}</h1>
|
|
<p class="subtitle muted mono truncate" style="max-width:none;">{{ item.path }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{% if request.query_params.get('changed') %}
|
|
<div class="notice success">Updated {{ request.query_params.get('changed') }} field(s).</div>
|
|
{% endif %}
|
|
|
|
<h2>Edit tags</h2>
|
|
<div class="panel" style="max-width:560px;">
|
|
<form method="post" action="/library/track/{{ item.id }}">
|
|
{% for field in editable_fields %}
|
|
<div class="field">
|
|
<label for="{{ field }}">{{ field }}</label>
|
|
<input type="text" id="{{ field }}" name="{{ field }}" value="{{ item.get(field, '') or '' }}">
|
|
</div>
|
|
{% endfor %}
|
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
</form>
|
|
</div>
|
|
|
|
<h2>Set genre for this artist (all their tracks)</h2>
|
|
<div class="panel" style="max-width:560px;">
|
|
<form method="post" action="/library/track/{{ item.id }}/genre">
|
|
<input type="hidden" name="artist" value="{{ item.artist }}">
|
|
<div class="field">
|
|
<label for="genre">Genre</label>
|
|
<input type="text" id="genre" name="genre" required placeholder="IDM; Electronic">
|
|
</div>
|
|
<button type="submit" class="btn">Set genre</button>
|
|
</form>
|
|
</div>
|
|
|
|
<h2>Re-fetch metadata from Spotify/iTunes URL</h2>
|
|
<div class="panel" style="max-width:560px;">
|
|
<form method="post" action="/library/track/{{ item.id }}/retag">
|
|
<div class="field">
|
|
<label for="url">URL</label>
|
|
<input type="text" id="url" name="url" required>
|
|
</div>
|
|
<label class="checkbox-field"><input type="checkbox" name="keep_genre" value="true"> Keep existing genre</label>
|
|
<button type="submit" class="btn">Retag</button>
|
|
</form>
|
|
</div>
|
|
|
|
<h2>Danger zone</h2>
|
|
<div class="panel" style="max-width:560px;">
|
|
<p class="muted" style="margin-top:0;">Removes this track from beets and deletes the file from disk. Not reversible.</p>
|
|
<form method="post" action="/library/track/{{ item.id }}/delete"
|
|
onsubmit="return confirm('Delete {{ item.artist }} — {{ item.title }}? This removes the file from disk permanently.')">
|
|
<button type="submit" class="btn btn-danger">Delete this track</button>
|
|
</form>
|
|
</div>
|
|
{% endblock %}
|