The browser page is gone, with its shim, its shell CSS and its suite. build.py has no --tauri flag and one output: the app's page. The patch lists lose the SHARED_ prefix, which only ever meant "shared between the two builds", and test-pdf.js was quietly loading the browser page — it reads the app's now. Space plays and pauses, in the main window off the player at the bottom and in the mixer off the same transport. It is swallowed rather than passed on: that stops the window scrolling, and stops a focused button taking the same press as a second activation, which toggles twice and looks like a dead key. Typing, and any dialog other than the mixer, keep it. Deciding what is in front needs both markers — closing does not always remove .open, and .modal without it is display:none regardless of the hidden attribute. The mixer footer put the next file's name adrift in the middle of the row. The margin-left: auto meant to park it beside Close could do nothing, because the framework's flex: 1 1 auto had both nav groups growing to fill the row and left no free space to absorb. Pinned to flex: 0 0 auto. The file-detail modal shares the markup and follows. Bulk track rename wrote nothing, on every file, and had never worked. A rename is keyed on the name it replaces rather than a path, so the frame-rate pass threw reading edit.path off it — before any byte was written, so nothing was corrupted, only untouched. The failure handler discarded the reason and the run still ended on a tidy Done, which is why 0 saved read as progress; it now names the file and the cause in the log. 429 checks. The gap that hid the rename bug was end-to-end: the writer was unit tested and the panel rendered, and nothing drove one into the other.
397 lines
18 KiB
HTML
397 lines
18 KiB
HTML
<div id="bwfa-app-1" class="bwfa-scope bwfa-app" data-bwfa-app aria-label="BWF Metadata Analyser">
|
|
<div class="bwfa-header">
|
|
<h2 class="bwfa-title">BWF Metadata Analyser</h2>
|
|
<p class="bwfa-privacy-note">
|
|
<span class="badge badge-success" aria-hidden="true">Local only</span>
|
|
Your files are read directly in this browser tab and never leave your computer.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bwfa-dropzone" data-bwfa-dropzone tabindex="0" role="button"
|
|
aria-label="Select or drop a folder or files of BWF/WAV recordings">
|
|
<p class="bwfa-dropzone-text" data-bwfa-dropzone-text></p>
|
|
<div class="bwfa-dropzone-actions">
|
|
<button type="button" class="btn btn-primary" data-bwfa-select-folder>Select Folder</button>
|
|
<button type="button" class="btn btn-secondary" data-bwfa-select-files>Select Files</button>
|
|
<button type="button" class="btn btn-outline" data-bwfa-clear disabled>Clear</button>
|
|
</div>
|
|
<p class="bwfa-dropzone-subnote">
|
|
On iPhone/iPad, if the folder picker won't let you select a folder you've navigated into, use "Select Files" and choose the recordings directly instead — this is a known iOS quirk with folder pickers in general, not specific to this tool.
|
|
</p>
|
|
<input
|
|
type="file"
|
|
class="bwfa-visually-hidden"
|
|
data-bwfa-file-input
|
|
webkitdirectory
|
|
directory
|
|
multiple
|
|
accept=".wav,.bwf,.broadcastwave"
|
|
/>
|
|
<input
|
|
type="file"
|
|
class="bwfa-visually-hidden"
|
|
data-bwfa-files-input
|
|
multiple
|
|
accept=".wav,.bwf,.broadcastwave"
|
|
/>
|
|
</div>
|
|
|
|
<div class="bwfa-edit-entry" data-bwfa-edit-entry hidden>
|
|
<div class="bwfa-edit-divider"><span>or</span></div>
|
|
<div class="bwfa-launch-logo" aria-hidden="true"></div>
|
|
<button type="button" class="btn btn-outline" data-bwfa-edit-folder>Edit Metadata in a Folder…</button>
|
|
<span class="bwfa-current-folder" data-bwfa-current-folder hidden></span>
|
|
<p class="bwfa-dropzone-subnote">
|
|
This opens files for editing rather than just viewing. Saving a change writes it directly back to the original file on your disk — there is no undo, and no automatic backup is made. Available in Chromium-based browsers only (Chrome, Edge, Opera, Arc); Firefox and Safari, including iPhone/iPad, cannot write to local files from a webpage at all.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="bwfa-status" data-bwfa-status role="status" aria-live="polite"></div>
|
|
|
|
<div class="bwfa-progress progress" data-bwfa-progress-wrap hidden>
|
|
<div class="progress-bar" data-bwfa-progress-bar style="width:0%"></div>
|
|
</div>
|
|
|
|
<div class="bwfa-results" data-bwfa-results hidden>
|
|
<div class="bwfa-toolbar">
|
|
<div class="form-group bwfa-search-group">
|
|
<input
|
|
type="search"
|
|
class="form-control"
|
|
data-bwfa-search
|
|
placeholder="Filter by filename, scene, take…"
|
|
/>
|
|
</div>
|
|
<div class="bwfa-export-actions">
|
|
<!-- Columns moved to the cogwheel in the table's first header
|
|
cell. The button stays here, hidden, because the analyser
|
|
wires a listener to it at startup. -->
|
|
<div class="dropdown bwfa-legacy-export" data-bwfa-columns-dropdown>
|
|
<button type="button" class="btn btn-outline" data-bwfa-columns-toggle>Columns</button>
|
|
</div>
|
|
<button type="button" class="btn btn-outline" data-bwfa-bulk-edit-toggle hidden>Bulk Edit</button>
|
|
<button type="button" class="btn btn-outline" data-bwfa-report-open>Sound Report</button>
|
|
<!-- The three buttons the report modal replaced. Kept in the DOM,
|
|
hidden by CSS: the analyser wires its export pipeline to
|
|
them at startup, and the modal drives them rather than
|
|
duplicating any of it. -->
|
|
<button type="button" class="btn btn-outline bwfa-legacy-export" data-bwfa-export-fields-toggle>Export Fields</button>
|
|
<button type="button" class="btn btn-secondary bwfa-legacy-export" data-bwfa-export-csv>Export CSV</button>
|
|
<button type="button" class="btn btn-secondary bwfa-legacy-export" data-bwfa-export-pdf>Export PDF</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bwfa-editing-note" data-bwfa-editing-note hidden>
|
|
<span class="badge badge-warning">Editing</span>
|
|
Changes save directly to the original files on disk.
|
|
</div>
|
|
|
|
<div class="bwfa-bulk-edit-panel" data-bwfa-bulk-edit-panel hidden>
|
|
<div class="bwfa-bulk-edit-header">
|
|
<h4>Bulk Edit</h4>
|
|
<p data-bwfa-bulk-edit-count></p>
|
|
</div>
|
|
<div class="bwfa-bulk-edit-fields" data-bwfa-bulk-edit-fields></div>
|
|
<div class="bwfa-bulk-tracks" data-bwfa-bulk-tracks hidden></div>
|
|
<div class="bwfa-bulk-edit-actions">
|
|
<div class="bwfa-bulk-edit-progress" data-bwfa-bulk-edit-progress hidden></div>
|
|
<button type="button" class="btn btn-outline" data-bwfa-bulk-edit-cancel>Cancel</button>
|
|
<button type="button" class="btn btn-primary" data-bwfa-bulk-edit-apply disabled>Apply</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bwfa-player" data-bwfa-player hidden>
|
|
<div class="bwfa-player-label">
|
|
<span class="badge badge-info" data-bwfa-player-badge>Now playing</span>
|
|
<span class="bwfa-player-filename" data-bwfa-player-filename></span>
|
|
<button type="button" class="btn btn-sm btn-outline bwfa-player-edit"
|
|
data-bwfa-player-edit>Edit</button>
|
|
<span class="bwfa-player-decoding" data-bwfa-player-decoding hidden>Decoding…</span>
|
|
<button type="button" class="bwfa-round-btn bwfa-mixer-open"
|
|
data-bwfa-mixer-open aria-label="Mixer">
|
|
<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true">
|
|
<circle cx="8" cy="8" r="5.6" fill="none" stroke="currentColor"
|
|
stroke-width="1.4"/>
|
|
<path d="M8 3.6 V 8" stroke="currentColor" stroke-width="1.6"
|
|
stroke-linecap="round"/>
|
|
</svg>
|
|
</button>
|
|
<button type="button" class="bwfa-round-btn bwfa-spectro-open"
|
|
data-bwfa-spectro-open aria-label="Spectrogram">
|
|
<svg viewBox="0 0 16 16" width="14" height="14" aria-hidden="true">
|
|
<rect x="1" y="9" width="2" height="5" rx="0.6"/>
|
|
<rect x="4.5" y="5" width="2" height="9" rx="0.6"/>
|
|
<rect x="8" y="2" width="2" height="12" rx="0.6"/>
|
|
<rect x="11.5" y="6.5" width="2" height="7.5" rx="0.6"/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="modal-backdrop bwfa-mixer-backdrop" data-bwfa-mixer-backdrop hidden></div>
|
|
<div class="modal bwfa-mixer-modal" data-bwfa-mixer hidden>
|
|
<div class="modal-dialog bwfa-mixer-dialog" role="dialog" aria-modal="true"
|
|
aria-label="Mixer">
|
|
<button type="button" class="modal-close" data-bwfa-mixer-close
|
|
aria-label="Close">×</button>
|
|
<div class="modal-header">
|
|
<div class="bwfa-modal-title-group">
|
|
<h3 class="modal-title">Mixer</h3>
|
|
<span class="bwfa-modal-filename" data-bwfa-mixer-filename></span>
|
|
</div>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="bwfa-mixer-strips" data-bwfa-mixer-strips></div>
|
|
<div class="bwfa-player-transport bwfa-mixer-transport">
|
|
<button type="button" class="btn btn-sm btn-primary bwfa-player-playpause"
|
|
data-bwfa-mixer-playpause><span class="bwfa-btn-label"
|
|
data-bwfa-label>Play</span></button>
|
|
<span class="bwfa-player-time" data-bwfa-mixer-elapsed>00:00:00</span>
|
|
<canvas class="bwfa-player-waveform" data-bwfa-mixer-waveform
|
|
width="700" height="56"
|
|
aria-label="Waveform — click to seek"></canvas>
|
|
<span class="bwfa-player-time" data-bwfa-mixer-duration>00:00:00</span>
|
|
</div>
|
|
<p class="bwfa-mixer-note">This mix is for listening only. Exports and
|
|
reports ignore it.</p>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<div class="bwfa-modal-nav bwfa-modal-nav-back">
|
|
<button type="button" class="btn btn-sm btn-outline"
|
|
data-bwfa-mixer-prev aria-label="Previous file">‹</button>
|
|
<span class="bwfa-modal-nav-name" data-bwfa-mixer-prev-name></span>
|
|
</div>
|
|
<div class="bwfa-modal-nav bwfa-modal-nav-on">
|
|
<span class="bwfa-modal-nav-name" data-bwfa-mixer-next-name></span>
|
|
<button type="button" class="btn btn-sm btn-outline"
|
|
data-bwfa-mixer-next aria-label="Next file">›</button>
|
|
</div>
|
|
<button type="button" class="btn btn-outline" data-bwfa-mixer-close>Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-backdrop bwfa-spectro-backdrop" data-bwfa-spectro-backdrop hidden></div>
|
|
<div class="modal bwfa-spectro-modal" data-bwfa-spectro hidden>
|
|
<div class="modal-dialog bwfa-spectro-dialog" role="dialog" aria-modal="true"
|
|
aria-label="Spectrogram">
|
|
<button type="button" class="modal-close" data-bwfa-spectro-close
|
|
aria-label="Close">×</button>
|
|
<div class="bwfa-spectro-head">
|
|
<h4 data-bwfa-spectro-title>Spectrogram</h4>
|
|
<p data-bwfa-spectro-note></p>
|
|
<button type="button" class="btn btn-sm btn-outline bwfa-spectro-save"
|
|
data-bwfa-spectro-save>Save Image</button>
|
|
</div>
|
|
<div class="bwfa-spectro-plot">
|
|
<div class="bwfa-spectro-scale" data-bwfa-spectro-scale></div>
|
|
<canvas class="bwfa-spectro-canvas" data-bwfa-spectro-canvas></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="bwfa-player-transport">
|
|
<button type="button" class="btn btn-sm btn-primary bwfa-player-playpause" data-bwfa-player-playpause><span class="bwfa-btn-label" data-bwfa-label>Play</span></button>
|
|
<span class="bwfa-player-time" data-bwfa-player-elapsed>00:00:00</span>
|
|
<canvas class="bwfa-player-waveform" data-bwfa-player-waveform width="700" height="56"
|
|
aria-label="Waveform — click to seek"></canvas>
|
|
<span class="bwfa-player-time" data-bwfa-player-duration>00:00:00</span>
|
|
</div>
|
|
<div class="bwfa-channel-row" data-bwfa-channel-row>
|
|
<span class="bwfa-channel-hint">Click a channel to mute it, double-click to solo it:</span>
|
|
<div class="chip-group bwfa-channel-chips" data-bwfa-channel-chips></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped table-hover bwfa-table">
|
|
<thead data-bwfa-table-head></thead>
|
|
<tbody data-bwfa-table-body></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bwfa-empty" data-bwfa-empty>No files analysed yet.</div>
|
|
|
|
<!-- Which columns the table shows. Opened by the cogwheel above the Play
|
|
column, since that's where you are when you want it. -->
|
|
<div class="modal-backdrop" data-bwfa-columns-backdrop hidden></div>
|
|
<div class="modal" data-bwfa-columns-modal role="dialog" aria-modal="true"
|
|
aria-labelledby="bwfa-app-1-columns-title" hidden>
|
|
<div class="modal-dialog bwfa-columns-dialog">
|
|
<div class="modal-header">
|
|
<h3 class="modal-title" id="bwfa-app-1-columns-title">Settings</h3>
|
|
<button type="button" class="modal-close" data-bwfa-columns-close aria-label="Close">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<details class="bwfa-settings-section" data-bwfa-settings="appearance">
|
|
<summary>Appearance</summary>
|
|
<div class="bwfa-settings-body">
|
|
<div class="bwfa-choice-list">
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-theme" value="auto" checked data-bwfa-theme-mode>
|
|
<span>Match the system<small>Follow macOS as it changes through the day</small></span>
|
|
</label>
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-theme" value="light" data-bwfa-theme-mode>
|
|
<span>Light<small>Paper white, whatever the system is doing</small></span>
|
|
</label>
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-theme" value="dark" data-bwfa-theme-mode>
|
|
<span>Dark<small>Anthracite, for a night shoot or a dark suite</small></span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
<details class="bwfa-settings-section" data-bwfa-settings="playback">
|
|
<summary>When a file finishes</summary>
|
|
<div class="bwfa-settings-body">
|
|
<div class="bwfa-choice-list">
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-playback-mode" value="stop" checked
|
|
data-bwfa-playback-mode>
|
|
<span>Stop<small>Hold it in the player, ready to play again</small></span>
|
|
</label>
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-playback-mode" value="next" data-bwfa-playback-mode>
|
|
<span>Play the next file<small>Work down the list as it's sorted and filtered</small></span>
|
|
</label>
|
|
<label class="bwfa-choice">
|
|
<input type="radio" name="bwfa-app-1-playback-mode" value="repeat" data-bwfa-playback-mode>
|
|
<span>Repeat it<small>Loop the same file until you stop it</small></span>
|
|
</label>
|
|
</div>
|
|
<div class="bwfa-settings-action" data-bwfa-audio-reset-row>
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-audio-reset>Restart the app</button>
|
|
<small>If a file plays with no sound at all, this rebuilds the audio path
|
|
and reloads the window — the same thing quitting and reopening does,
|
|
without the quitting. The folder comes back with it.</small>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
<details class="bwfa-settings-section" data-bwfa-settings="columns">
|
|
<summary>Columns in the table</summary>
|
|
<div class="bwfa-settings-body">
|
|
<div class="bwfa-columns-menu" data-bwfa-columns-menu></div>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary" data-bwfa-columns-close>Done</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- The sound report: who it's for, what format it lands in, and which
|
|
fields it carries. One field list for both formats, because a sound
|
|
report is a sound report whichever way it's written. -->
|
|
<div class="modal-backdrop" data-bwfa-export-backdrop hidden></div>
|
|
<div class="modal" data-bwfa-export-modal role="dialog" aria-modal="true"
|
|
aria-labelledby="bwfa-app-1-export-title" hidden>
|
|
<div class="modal-dialog bwfa-export-dialog">
|
|
<div class="modal-header">
|
|
<div class="bwfa-modal-title-group">
|
|
<h3 class="modal-title" id="bwfa-app-1-export-title">Sound Report</h3>
|
|
<span class="bwfa-modal-filename" data-bwfa-report-subject></span>
|
|
</div>
|
|
<button type="button" class="modal-close" data-bwfa-export-close aria-label="Close">×</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="bwfa-report-details">
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-company">Production company</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-company"
|
|
data-bwfa-report-field="company" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-project">Project / show name</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-project"
|
|
data-bwfa-report-field="project" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-director">Director</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-director"
|
|
data-bwfa-report-field="director" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-mixer">Sound mixer</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-mixer"
|
|
data-bwfa-report-field="mixer" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-phone">Mixer phone</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-phone"
|
|
data-bwfa-report-field="phone" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-email">Mixer email</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-email"
|
|
data-bwfa-report-field="email" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-note">Note</label>
|
|
<input type="text" class="form-control" id="bwfa-app-1-report-note"
|
|
data-bwfa-report-field="note" autocomplete="off">
|
|
</div>
|
|
<div class="bwfa-report-row">
|
|
<label class="form-label" for="bwfa-app-1-report-format">Output format</label>
|
|
<select class="form-select" id="bwfa-app-1-report-format" data-bwfa-report-format>
|
|
<option value="pdf" selected>PDF (sound report)</option>
|
|
<option value="csv">CSV (spreadsheet)</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bwfa-report-fields-head">
|
|
<h4>Fields in the report</h4>
|
|
<span class="bwfa-report-count" data-bwfa-export-count></span>
|
|
<div class="bwfa-export-actions-row">
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-export-all>Select all</button>
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-export-none>Select none</button>
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-export-defaults>Restore defaults</button>
|
|
</div>
|
|
</div>
|
|
<div class="bwfa-export-fields" data-bwfa-export-fields></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline" data-bwfa-export-close>Cancel</button>
|
|
<button type="button" class="btn btn-primary" data-bwfa-report-create>Create Report</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-backdrop" data-bwfa-modal-backdrop hidden></div>
|
|
<div
|
|
class="modal"
|
|
data-bwfa-modal
|
|
role="dialog"
|
|
aria-modal="true"
|
|
aria-labelledby="bwfa-app-1-modal-title"
|
|
hidden
|
|
>
|
|
<div class="modal-dialog bwfa-modal-dialog">
|
|
<div class="modal-header">
|
|
<div class="bwfa-modal-title-group">
|
|
<h3 class="modal-title" id="bwfa-app-1-modal-title">File metadata</h3>
|
|
<span class="bwfa-modal-filename" data-bwfa-modal-filename></span>
|
|
</div>
|
|
<button type="button" class="modal-close" data-bwfa-modal-close aria-label="Close">×</button>
|
|
</div>
|
|
<div class="modal-body" data-bwfa-modal-body></div>
|
|
<div class="modal-footer">
|
|
<div class="bwfa-modal-nav bwfa-modal-nav-back">
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-modal-prev
|
|
aria-label="Previous file">‹</button>
|
|
<span class="bwfa-modal-nav-name" data-bwfa-modal-prev-name></span>
|
|
</div>
|
|
<div class="bwfa-modal-nav bwfa-modal-nav-on">
|
|
<span class="bwfa-modal-nav-name" data-bwfa-modal-next-name></span>
|
|
<button type="button" class="btn btn-sm btn-outline" data-bwfa-modal-next
|
|
aria-label="Next file">›</button>
|
|
</div>
|
|
<button type="button" class="btn btn-primary" data-bwfa-modal-save hidden disabled>Save</button>
|
|
<button type="button" class="btn btn-secondary" data-bwfa-modal-play>Play</button>
|
|
<button type="button" class="btn btn-outline" data-bwfa-modal-close>Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|