Revert "Flag slave-only songs whose album or artist the master has"
This reverts commit 4bae674.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4bae6742a4
commit
095e294f4b
9 files changed
+15
-281
No files matched your search
@@ -57,7 +57,6 @@ export type Summary = {
|
||||
review: number;
|
||||
upgrades: number;
|
||||
ignored: number;
|
||||
missing?: { album?: number; artist?: number };
|
||||
reclaimable_bytes: number;
|
||||
linked_bytes: number;
|
||||
};
|
||||
@@ -133,7 +132,6 @@ export type Match = {
|
||||
verdict?: Verdict;
|
||||
note: string;
|
||||
reason: string;
|
||||
missing: "" | "album" | "artist";
|
||||
link_target: string;
|
||||
ignored: boolean;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { AlertTriangle, ArrowRight, ArrowUpCircle, Disc3, Download, FolderSearch, ListMusic, ChevronDown, ChevronRight, CopyCheck, CopyMinus, EyeOff, Eye, Link2, Search, Crown } from "lucide-react";
|
||||
import { AlertTriangle, ArrowRight, ArrowUpCircle, Disc3, Download, ListMusic, ChevronDown, ChevronRight, CopyCheck, CopyMinus, EyeOff, Eye, Link2, Search, Crown } from "lucide-react";
|
||||
import { ApiError, api, type Match, type Page, type Pair, type ProbeInfo } from "../api";
|
||||
import { Alert, Badge, Button, Card, Empty, Modal, Spinner, cx, formatBytes, formatDuration, inputCls, statusTone } from "../ui";
|
||||
import { useToast } from "../toast";
|
||||
@@ -13,7 +13,6 @@ const filters = [
|
||||
{ id: "identical", label: "Identical" },
|
||||
{ id: "linked", label: "Linked" },
|
||||
{ id: "unmatched", label: "Slave only" },
|
||||
{ id: "missing", label: "Missing from master" },
|
||||
{ id: "error", label: "Errors" },
|
||||
{ id: "ignored", label: "Ignored" },
|
||||
{ id: "", label: "All" },
|
||||
@@ -87,21 +86,8 @@ export function Review({ pair }: { pair: Pair }) {
|
||||
});
|
||||
|
||||
const c = pair.summary.counts;
|
||||
const miss = pair.summary.missing ?? {};
|
||||
const count = (id: string) =>
|
||||
id === "review"
|
||||
? pair.summary.review
|
||||
: id === "upgrade"
|
||||
? pair.summary.upgrades
|
||||
: id === "ignored"
|
||||
? pair.summary.ignored
|
||||
: id === "missing"
|
||||
? (miss.album ?? 0) + (miss.artist ?? 0)
|
||||
: id === ""
|
||||
? undefined
|
||||
: c[id] ?? 0;
|
||||
// The missing filter has two levels; the chip covers all three.
|
||||
const active = (id: string) => status === id || (id === "missing" && status.startsWith("missing_"));
|
||||
id === "review" ? pair.summary.review : id === "upgrade" ? pair.summary.upgrades : id === "ignored" ? pair.summary.ignored : id === "" ? undefined : c[id] ?? 0;
|
||||
const identical = c.identical ?? 0;
|
||||
const running = pair.job?.state === "running";
|
||||
|
||||
@@ -114,7 +100,7 @@ export function Review({ pair }: { pair: Pair }) {
|
||||
onClick={() => setStatus(f.id)}
|
||||
className={cx(
|
||||
"flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs cursor-pointer",
|
||||
active(f.id) ? "border-accent bg-accent/15 text-white" : "border-line text-muted hover:text-white",
|
||||
status === f.id ? "border-accent bg-accent/15 text-white" : "border-line text-muted hover:text-white",
|
||||
)}
|
||||
>
|
||||
{f.label}
|
||||
@@ -153,7 +139,7 @@ export function Review({ pair }: { pair: Pair }) {
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<ExportMenu pairId={pair.id} status={status} query={debounced} viewCount={list.data?.total} filterLabel={filters.find((f) => active(f.id))?.label ?? "All"} />
|
||||
<ExportMenu pairId={pair.id} status={status} query={debounced} viewCount={list.data?.total} filterLabel={filters.find((f) => f.id === status)?.label ?? "All"} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -162,7 +148,6 @@ export function Review({ pair }: { pair: Pair }) {
|
||||
<Duplicates pair={pair} />
|
||||
) : (
|
||||
<>
|
||||
{status.startsWith("missing") && <MissingIntro pair={pair} status={status} setStatus={setStatus} />}
|
||||
|
||||
{status === "identical" && identical > 0 && (
|
||||
<Card className="flex flex-wrap items-center justify-between gap-3 p-4">
|
||||
@@ -248,50 +233,6 @@ export function Review({ pair }: { pair: Pair }) {
|
||||
);
|
||||
}
|
||||
|
||||
function MissingIntro({ pair, status, setStatus }: { pair: Pair; status: string; setStatus: (s: string) => void }) {
|
||||
const miss = pair.summary.missing ?? {};
|
||||
const levels = [
|
||||
{ id: "missing", label: "All", n: (miss.album ?? 0) + (miss.artist ?? 0) },
|
||||
{ id: "missing_album", label: "Album in master", n: miss.album ?? 0 },
|
||||
{ id: "missing_artist", label: "Only the artist in master", n: miss.artist ?? 0 },
|
||||
];
|
||||
return (
|
||||
<Card className="space-y-3 p-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<FolderSearch className="mt-0.5 size-5 shrink-0 text-accent" />
|
||||
<div className="text-sm">
|
||||
<div className="font-medium">Songs the master library is missing</div>
|
||||
<div className="mt-0.5 text-muted">
|
||||
These songs are only in the slave library, but the master has their artist, and often the album too. For example, the slave has{" "}
|
||||
<i>Caravan Palace/Robot Face/Waterguns</i> and the master has the <i>Caravan Palace/Robot Face</i> album without that song. Add them to
|
||||
the master to complete it, then scan again to link them. Nothing here is changed automatically.
|
||||
</div>
|
||||
{!pair.approx_matching && (
|
||||
<div className="mt-1.5 text-xs text-amber-300/90">
|
||||
Approximate matching is off for this pair, so a song filed under a slightly different name or another release (a single vs. the
|
||||
album) shows up here too. Turn it on in Edit to find those.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1 rounded-lg border border-line p-0.5 sm:w-fit">
|
||||
{levels.map((l) => (
|
||||
<button
|
||||
key={l.id}
|
||||
onClick={() => setStatus(l.id)}
|
||||
className={cx(
|
||||
"flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs cursor-pointer",
|
||||
status === l.id ? "bg-panel-2 text-white" : "text-muted hover:text-white",
|
||||
)}
|
||||
>
|
||||
{l.label} <span className="tabular-nums opacity-70">{l.n}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function ExportMenu({ pairId, status, query, viewCount, filterLabel }: { pairId: number; status: string; query: string; viewCount?: number; filterLabel: string }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
useEffect(() => {
|
||||
@@ -394,9 +335,6 @@ export function MatchRow({ m, selected, onToggle }: { m: Match; selected?: boole
|
||||
<div className="flex w-28 shrink-0 flex-col items-start gap-1">
|
||||
<Badge tone={statusTone[m.status]}>{m.status}</Badge>
|
||||
{m.kind !== "path" && m.kind !== "none" && <span className="text-[10px] text-muted">{kindLabel[m.kind]}</span>}
|
||||
{m.status === "unmatched" && m.missing && (
|
||||
<span className="text-[10px] text-amber-300/90">{m.missing === "album" ? "album in master" : "artist in master"}</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="min-w-0 flex-1" onClick={() => reviewable && setOpen(!open)}>
|
||||
<PathLine m={m} />
|
||||
|
||||
Reference in new issue
Block a user