136 lines
13 KiB
HTML
136 lines
13 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<meta name="color-scheme" content="dark">
|
||
<title>Serato Doctor</title>
|
||
<link rel="stylesheet" href="/app.css?v=3">
|
||
<link rel="stylesheet" href="/recovery.css?v=3">
|
||
<link rel="stylesheet" href="/layout-fixes.css?v=3">
|
||
</head>
|
||
<body>
|
||
<div class="ambient ambient-one"></div>
|
||
<div class="ambient ambient-two"></div>
|
||
<div class="shell">
|
||
<aside class="sidebar">
|
||
<a class="brand" href="/" aria-label="Serato Doctor home">
|
||
<span class="brand-mark">SD</span>
|
||
<span><strong>Serato</strong><small>Doctor</small></span>
|
||
</a>
|
||
<nav aria-label="Primary navigation">
|
||
<a class="nav-item active" href="#dashboard"><span>⌁</span> Dashboard</a>
|
||
<a class="nav-item" href="#scan"><span>◎</span> New analysis</a>
|
||
<a class="nav-item" href="#diagnostics"><span>◇</span> Diagnostics</a>
|
||
<a class="nav-item" href="#recovery"><span>↶</span> Recovery</a>
|
||
</nav>
|
||
<div class="safety-card">
|
||
<span class="safety-icon">✓</span>
|
||
<div><strong>Protected mode</strong><p>Analysis is read-only. Repairs require a preview and backup.</p></div>
|
||
</div>
|
||
<div class="sidebar-foot">Local interface · v0.1</div>
|
||
</aside>
|
||
|
||
<main>
|
||
<header class="topbar">
|
||
<div><p class="eyebrow">Library intelligence</p><h1>Good evening.</h1></div>
|
||
<div class="status-pill"><span></span> Local & private</div>
|
||
</header>
|
||
|
||
<section id="scan" class="scan-panel panel">
|
||
<div class="panel-copy">
|
||
<p class="eyebrow">Start here</p>
|
||
<h2>Analyze your library</h2>
|
||
<p>Point Serato Doctor at your Serato and music folders. We inspect references, duplicates, smart crates, and symlinks without changing a thing.</p>
|
||
</div>
|
||
<form id="analysis-form">
|
||
<label>Serato folder
|
||
<input id="serato-path" name="serato" value="~/Music/_Serato_" required>
|
||
</label>
|
||
<label>Music folder
|
||
<input id="music-path" name="music" value="~/Music/Jukebox" required>
|
||
</label>
|
||
<label class="wide">Historical reference roots <span>optional · one per line</span>
|
||
<textarea id="reference-roots" rows="2" placeholder="/Users/old-user/OneDrive/Jukebox"></textarea>
|
||
</label>
|
||
<button id="analyze-button" type="submit"><span>Analyze library</span><b>→</b></button>
|
||
</form>
|
||
<div id="error-message" class="error" role="alert" hidden></div>
|
||
</section>
|
||
|
||
<section id="dashboard" class="results" aria-live="polite" hidden>
|
||
<div class="section-heading"><div><p class="eyebrow">Latest analysis</p><h2>Library health</h2></div><span id="analysis-time"></span></div>
|
||
<div class="hero-grid">
|
||
<article class="score-card panel">
|
||
<button class="info-button" type="button" aria-label="About library health" aria-expanded="false" data-info="Your health score is the percentage of saved, non-smart crate entries whose filenames were found in the selected music folder. Smart crates are left out because Serato rebuilds them from rules.">i</button>
|
||
<div class="score-ring" id="score-ring"><div><strong id="health-score">—</strong><span>health</span></div></div>
|
||
<div><p class="score-label">Reference integrity</p><h3 id="health-message">Ready to analyze</h3><p id="score-basis">We only score evidence we can defend.</p></div>
|
||
</article>
|
||
<div class="metrics-grid">
|
||
<article class="metric panel"><button class="info-button" type="button" aria-label="About tracks" aria-expanded="false" data-info="Audio files found inside the music folder you selected. This is the collection Serato Doctor compared with your crates and database.">i</button><span>Tracks scanned</span><strong data-field="disk_tracks">—</strong><small>audio files found</small></article>
|
||
<article class="metric panel warning drill-trigger" role="button" tabindex="0" data-detail="database_missing_tracks"><button class="info-button" type="button" aria-label="About missing tracks in Serato" aria-expanded="false" data-info="Tracks in Serato's database whose saved file location no longer exists. This should be close to the orange or unmapped track count you see in Serato.">i</button><span>Missing tracks in Serato</span><strong data-field="database_missing_paths">—</strong><small><b data-field="database_missing_unique_filenames">—</b> unique filenames · click for list</small></article>
|
||
<article class="metric panel drill-trigger" role="button" tabindex="0" data-detail="unused_tracks"><button class="info-button" type="button" aria-label="About unused tracks" aria-expanded="false" data-info="Files in the selected music folder whose filename is not used by any loaded crate. They may still be valid library tracks; this is informational, not a deletion recommendation.">i</button><span>Unused tracks</span><strong data-field="unused_tracks">—</strong><small>not referenced by crates · click for list</small></article>
|
||
<article class="metric panel drill-trigger" role="button" tabindex="0" data-detail="suggested_matches"><button class="info-button" type="button" aria-label="About suggested matches" aria-expanded="false" data-info="Missing crate entries with a filename-related candidate, such as an added OneDrive conflict number. Suggestions are evidence for review, never automatic repairs.">i</button><span>Suggested matches</span><strong data-field="suggested_matches">—</strong><small>explainable candidates · click for list</small></article>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="diagnostics" class="diagnostics panel">
|
||
<div class="section-heading"><div><p class="eyebrow">Full picture</p><h2>Diagnostics</h2></div><span class="read-only-tag">No changes made</span></div>
|
||
<div class="diagnostic-list">
|
||
<div><span class="diag-icon violet">◇</span><p><strong>Crates</strong><small><b data-field="static_crates">—</b> regular · <b data-field="smart_crates">—</b> smart · <b data-field="smart_crate_containers">—</b> dynamic containers</small></p><button class="info-button" type="button" aria-label="About crates" aria-expanded="false" data-info="Regular crates are lists you maintain by hand. Smart crates are rebuilt by Serato from rules, so their generated references are not scored as broken.">i</button></div>
|
||
<div class="drill-trigger" role="button" tabindex="0" data-detail="duplicate_filenames"><span class="diag-icon amber">≋</span><p><strong>Duplicate filenames</strong><small><b data-field="duplicate_filename_groups">—</b> exact groups · <b data-field="duplicate_files">—</b> extra files · click for list</small></p><button class="info-button" type="button" aria-label="About duplicate filenames" aria-expanded="false" data-info="Different files with the same filename after case and Unicode cleanup. They need review, but matching names alone do not mean either file should be deleted.">i</button></div>
|
||
<div class="drill-trigger" role="button" tabindex="0" data-detail="cloud_conflicts"><span class="diag-icon blue">⌁</span><p><strong>Possible cloud conflicts</strong><small><b data-field="suspected_cloud_conflict_groups">—</b> groups · <b data-field="suspected_cloud_conflict_files">—</b> extra files · click for list</small></p><button class="info-button" type="button" aria-label="About cloud conflicts" aria-expanded="false" data-info="Filename families such as Track.mp3 and Track 2.mp3. OneDrive often creates these during sync conflicts, but numbered song titles can also be legitimate.">i</button></div>
|
||
<div class="drill-trigger" role="button" tabindex="0" data-detail="broken_symlinks"><span class="diag-icon red">↗</span><p><strong>Broken shortcuts</strong><small><b data-field="broken_symlinks">—</b> unresolved symbolic links · click for list</small></p><button class="info-button" type="button" aria-label="About broken shortcuts" aria-expanded="false" data-info="Shortcut-style symbolic links whose destination no longer exists. Serato Doctor reports them but never removes or recreates them automatically.">i</button></div>
|
||
<div class="drill-trigger" role="button" tabindex="0" data-detail="old_crate_references"><span class="diag-icon violet">▦</span><p><strong>Old crate references</strong><small><b data-field="missing_references">—</b> appearances · <b data-field="unique_missing_filenames">—</b> unique filenames · click for list</small></p><button class="info-button" type="button" aria-label="About old crate references" aria-expanded="false" data-info="Saved spots in regular crates whose exact filename was not found in the selected music folder. The same track can appear in several crates, so appearances are higher than unique filenames. These are separate from Serato's unmapped-track count.">i</button></div>
|
||
<div><span class="diag-icon amber">⌕</span><p><strong>Database coverage</strong><small><b data-field="database_entries">—</b> Serato entries · <b data-field="tracks_missing_from_database">—</b> scanned tracks absent</small></p><button class="info-button" type="button" aria-label="About database coverage" aria-expanded="false" data-info="Compares filenames in Serato's database with the selected music folder. A scanned track absent from the database may not have been imported, or may be represented under another filename.">i</button></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="drilldowns" class="drilldowns panel">
|
||
<div class="section-heading"><div><p class="eyebrow">Look closer</p><h2 id="drilldown-title">Choose a diagnostic</h2></div><span id="drilldown-count">Read-only examples</span></div>
|
||
<p id="drilldown-summary">Click a metric above to see example files and saved paths behind that number.</p>
|
||
<div id="drilldown-list" class="detail-list"></div>
|
||
</div>
|
||
|
||
<div id="duplicate-repair" class="repair-panel panel" hidden>
|
||
<div class="section-heading"><div><p class="eyebrow">Batch cleanup</p><h2>Review all selected changes</h2></div><span class="repair-tag">One backup · one apply</span></div>
|
||
<p>Approved choices are combined into one plan. Skipped groups remain untouched, and Serato’s database V2 is never edited.</p>
|
||
<div id="repair-choice" class="repair-choice"></div>
|
||
<div class="backup-options">
|
||
<label>Backups to keep <input id="backup-limit" type="number" min="1" value="10"></label>
|
||
<label class="check-label"><input id="keep-all-backups" type="checkbox"> Keep every backup</label>
|
||
</div>
|
||
<div id="repair-preview" class="repair-preview" hidden></div>
|
||
<div class="repair-actions">
|
||
<button id="preview-repair" type="button">Preview all selected changes</button>
|
||
<button id="apply-repair" class="danger-action" type="button" disabled>Apply all selected changes</button>
|
||
<button id="restore-repair" type="button" hidden>Restore this backup</button>
|
||
</div>
|
||
<div id="repair-message" class="repair-message" role="status"></div>
|
||
</div>
|
||
</section>
|
||
|
||
<section id="recovery" class="recovery-panel panel">
|
||
<div class="section-heading"><div><p class="eyebrow">Safety net</p><h2>Backup recovery</h2></div><button id="load-backups" type="button">Check backups</button></div>
|
||
<p>Repair backups appear here automatically before any duplicate is consolidated. Review saved snapshots, disk usage, and restore history.</p>
|
||
<div id="backup-summary" class="backup-summary">Analyze your library, then choose a duplicate to preview its automatic backup.</div>
|
||
<div id="backup-list" class="backup-list"></div>
|
||
</section>
|
||
<div id="audio-preview" class="audio-preview" hidden>
|
||
<div><span>Now previewing</span><strong id="audio-preview-name"></strong></div>
|
||
<audio id="audio-player" controls preload="metadata"></audio>
|
||
<button id="close-audio-preview" type="button" aria-label="Close audio preview">×</button>
|
||
</div>
|
||
<dialog id="batch-preview-modal" class="batch-preview-modal">
|
||
<div class="modal-heading"><div><p class="eyebrow">Final dry-run</p><h2>Here’s exactly what will happen</h2></div><button id="close-batch-preview" type="button" aria-label="Close preview">×</button></div>
|
||
<p id="batch-preview-summary"></p>
|
||
<div id="batch-preview-list" class="batch-preview-list"></div>
|
||
<div class="modal-safety"><span>✓</span><p><strong>Backup happens first</strong><small id="batch-preview-safety"></small></p></div>
|
||
<div class="modal-actions"><button id="continue-reviewing" type="button">Close and continue reviewing</button><button id="accept-preview" type="button">Looks right</button></div>
|
||
</dialog>
|
||
</main>
|
||
</div>
|
||
<script src="/app.js?v=6" defer></script>
|
||
</body>
|
||
</html>
|