library: rename Scan nav/page to Library, show audio codecs per row
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m4s
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m4s
Per-row audio codec summary (distinct lowercased codecs across an item's audio streams) via scalar subquery on media_streams, rendered as "ac3 · aac" in a new monospace Audio column. v2026.04.15.9 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "netfelix-audio-fix",
|
||||
"version": "2026.04.15.8",
|
||||
"version": "2026.04.15.9",
|
||||
"scripts": {
|
||||
"dev:server": "NODE_ENV=development bun --hot server/index.tsx",
|
||||
"dev:client": "vite",
|
||||
|
||||
@@ -163,7 +163,11 @@ app.get("/items", (c) => {
|
||||
`
|
||||
SELECT id, jellyfin_id, name, type, series_name, season_number, episode_number,
|
||||
scan_status, original_language, orig_lang_source, container, file_size, file_path,
|
||||
last_scanned_at, ingest_source
|
||||
last_scanned_at, ingest_source,
|
||||
(SELECT GROUP_CONCAT(DISTINCT LOWER(codec))
|
||||
FROM media_streams
|
||||
WHERE item_id = media_items.id AND type = 'Audio' AND codec IS NOT NULL
|
||||
) AS audio_codecs
|
||||
FROM media_items
|
||||
${where.sql}
|
||||
ORDER BY COALESCE(last_scanned_at, created_at) DESC, id DESC
|
||||
@@ -186,6 +190,7 @@ app.get("/items", (c) => {
|
||||
file_path: string;
|
||||
last_scanned_at: string | null;
|
||||
ingest_source: string | null;
|
||||
audio_codecs: string | null;
|
||||
}>;
|
||||
const total = (db.prepare(`SELECT COUNT(*) as n FROM media_items ${where.sql}`).get(...where.args) as { n: number }).n;
|
||||
return c.json({ rows, total, hasMore: query.offset + rows.length < total, query });
|
||||
|
||||
@@ -37,6 +37,7 @@ interface ScanItemsRow {
|
||||
file_path: string;
|
||||
last_scanned_at: string | null;
|
||||
ingest_source: "scan" | "webhook" | null;
|
||||
audio_codecs: string | null;
|
||||
}
|
||||
|
||||
interface ScanItemsResponse {
|
||||
@@ -397,7 +398,7 @@ export function ScanPage() {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h1 className="text-xl font-bold m-0">Scan</h1>
|
||||
<h1 className="text-xl font-bold m-0">Library</h1>
|
||||
<MqttBadge />
|
||||
</div>
|
||||
|
||||
@@ -581,22 +582,32 @@ export function ScanPage() {
|
||||
<table className="w-full border-collapse text-[0.8rem]">
|
||||
<thead>
|
||||
<tr>
|
||||
{["Scanned", "Name", "Type", "Series / Ep", "Language", "Container", "Size", "Source", "Status", "Path"].map(
|
||||
(h) => (
|
||||
<th
|
||||
key={h}
|
||||
className="text-left text-[0.66rem] font-bold uppercase tracking-[0.05em] text-gray-500 py-1 px-2 border-b border-gray-200 whitespace-nowrap"
|
||||
>
|
||||
{h}
|
||||
</th>
|
||||
),
|
||||
)}
|
||||
{[
|
||||
"Scanned",
|
||||
"Name",
|
||||
"Type",
|
||||
"Series / Ep",
|
||||
"Language",
|
||||
"Audio",
|
||||
"Container",
|
||||
"Size",
|
||||
"Source",
|
||||
"Status",
|
||||
"Path",
|
||||
].map((h) => (
|
||||
<th
|
||||
key={h}
|
||||
className="text-left text-[0.66rem] font-bold uppercase tracking-[0.05em] text-gray-500 py-1 px-2 border-b border-gray-200 whitespace-nowrap"
|
||||
>
|
||||
{h}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{itemsRows.length === 0 && !itemsLoading && (
|
||||
<tr>
|
||||
<td colSpan={10} className="py-3 px-2 text-gray-400">
|
||||
<td colSpan={11} className="py-3 px-2 text-gray-400">
|
||||
No items match the current filters.
|
||||
</td>
|
||||
</tr>
|
||||
@@ -616,6 +627,9 @@ export function ScanPage() {
|
||||
<div>{row.original_language ?? "—"}</div>
|
||||
<div className="text-[0.68rem] text-gray-500">{row.orig_lang_source ?? "—"}</div>
|
||||
</td>
|
||||
<td className="py-1.5 px-2 border-b border-gray-100 font-mono text-[0.72rem]">
|
||||
{row.audio_codecs ? row.audio_codecs.split(",").join(" · ") : "—"}
|
||||
</td>
|
||||
<td className="py-1.5 px-2 border-b border-gray-100">{row.container ?? "—"}</td>
|
||||
<td className="py-1.5 px-2 border-b border-gray-100 whitespace-nowrap">{formatFileSize(row.file_size)}</td>
|
||||
<td className="py-1.5 px-2 border-b border-gray-100">
|
||||
|
||||
@@ -65,7 +65,7 @@ function RootLayout() {
|
||||
<VersionBadge />
|
||||
<div className="flex flex-wrap items-center gap-0.5">
|
||||
<NavLink to="/" exact>
|
||||
Scan
|
||||
Library
|
||||
</NavLink>
|
||||
<NavLink to="/pipeline">Pipeline</NavLink>
|
||||
<NavLink to="/review/subtitles">Subtitles</NavLink>
|
||||
|
||||
Reference in New Issue
Block a user