diff --git a/src/app/components/SearchCommoServe.tsx b/src/app/components/SearchCommoServe.tsx
index a865ab7..c278c0e 100644
--- a/src/app/components/SearchCommoServe.tsx
+++ b/src/app/components/SearchCommoServe.tsx
@@ -4,6 +4,7 @@ import { toast } from 'sonner';
import { humanFileSize, basename, joinPath, putFileContents } from '../webdav';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './ui/dialog';
import { MarqueeText } from './ui/marquee-text';
+import { EntryIcon } from './MediaEntry';
// ─── API ──────────────────────────────────────────────────────────────────────
@@ -16,7 +17,6 @@ function leetFetch(path: string, query?: Record) {
if (query) Object.entries(query).forEach(([k, v]) => url.searchParams.set(k, v));
return fetch(url.toString(), {
headers: {
- 'User-Agent': 'Assembly Query',
'Client-Id': 'Commodore',
},
});
@@ -29,6 +29,17 @@ async function leetJson(path: string, query?: Record): Promis
return data as T;
}
+// CommoServe may wrap arrays in an object — unwrap the first array value found.
+function extractArray(data: unknown): T[] {
+ if (Array.isArray(data)) return data as T[];
+ if (data && typeof data === 'object') {
+ for (const v of Object.values(data as object)) {
+ if (Array.isArray(v) && v.length > 0) return v as T[];
+ }
+ }
+ return [];
+}
+
// ─── Types ────────────────────────────────────────────────────────────────────
interface ContentItem {
@@ -55,13 +66,6 @@ interface ContentEntry {
date: number;
}
-interface CategoryMapping {
- id: number;
- name?: string;
- title?: string;
- [k: string]: unknown;
-}
-
interface PresetValue {
aqlKey: string;
name?: string;
@@ -166,9 +170,6 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [searchError, setSearchError] = useState(null);
const [corsBlocked, setCorsBlocked] = useState(false);
- const [categoryFilter, setCategoryFilter] = useState(() => _store.categoryFilter);
-
- const [categories, setCategories] = useState([]);
const [presets, setPresets] = useState([]);
const [activePreset, setActivePreset] = useState(null);
@@ -186,17 +187,16 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
const [sortDir, setSortDir] = useState(() => _store.sortDir);
useEffect(() => {
- _store.query = query;
- _store.results = results;
- _store.offset = offset;
- _store.hasMore = hasMore;
- _store.hasSearched = hasSearched;
- _store.categoryFilter = categoryFilter;
- _store.showFilter = showFilter;
- _store.filterText = filterText;
- _store.sortField = sortField;
- _store.sortDir = sortDir;
- }, [query, results, offset, hasMore, hasSearched, categoryFilter, showFilter, filterText, sortField, sortDir]);
+ _store.query = query;
+ _store.results = results;
+ _store.offset = offset;
+ _store.hasMore = hasMore;
+ _store.hasSearched = hasSearched;
+ _store.showFilter = showFilter;
+ _store.filterText = filterText;
+ _store.sortField = sortField;
+ _store.sortDir = sortDir;
+ }, [query, results, offset, hasMore, hasSearched, showFilter, filterText, sortField, sortDir]);
useEffect(() => {
if (_store.scrollTop > 0 && scrollRef.current)
@@ -204,30 +204,22 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
}, []);
useEffect(() => {
- const isCors = (e: any) => /failed to fetch|networkerror/i.test(e?.message ?? '');
- leetJson('/search/categories').then(setCategories).catch(e => { if (isCors(e)) setCorsBlocked(true); });
- leetJson('/search/aql/presets').then(setPresets).catch(e => { if (isCors(e)) setCorsBlocked(true); });
+ leetJson('/search/aql/presets').then(d => setPresets(extractArray(d))).catch(() => {});
}, []);
- const categoryName = useMemo(() => {
- const map: Record = {};
- for (const c of categories) map[c.id] = (c.name ?? c.title ?? String(c.id)) as string;
- return map;
- }, [categories]);
-
// ── Search ──────────────────────────────────────────────────────────────────
- const doSearch = async (q: string, cat: number | null, fromOffset: number, append = false) => {
+ const doSearch = async (q: string, fromOffset: number, append = false) => {
if (!append) setIsSearching(true);
else setIsLoadingMore(true);
setSearchError(null);
try {
- let aql = q.trim();
- if (cat !== null) aql = aql ? `${aql} category:${cat}` : `category:${cat}`;
- const data = await leetJson(
+ const aql = q.trim();
+ const raw = await leetJson(
`/search/aql/${fromOffset}/${PAGE_SIZE}`,
aql ? { query: aql } : undefined,
);
+ const data = extractArray(raw);
if (append) setResults(prev => [...prev, ...data]);
else setResults(data);
setOffset(fromOffset + data.length);
@@ -242,8 +234,8 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
}
};
- const handleSearch = () => { setFilterText(''); doSearch(query, categoryFilter, 0); };
- const handleLoadMore = () => doSearch(query, categoryFilter, offset, true);
+ const handleSearch = () => { setFilterText(''); doSearch(query, 0); };
+ const handleLoadMore = () => doSearch(query, offset, true);
const applyPreset = (group: PresetGroup, value: PresetValue) => {
const prefix = PRESET_PREFIX[group.type];
@@ -253,7 +245,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
const trimmed = query.trim();
const next = trimmed ? `${trimmed} ${token}` : token;
setQuery(next);
- doSearch(next, categoryFilter, 0);
+ doSearch(next, 0);
};
// ── Filter / sort ────────────────────────────────────────────────────────────
@@ -309,8 +301,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
const downloadToSd = async (item: ContentItem, entry: ContentEntry) => {
setDownloading(entry.id);
try {
- const url = downloadUrl(item, entry);
- const res = await fetch(url);
+ const res = await fetch(downloadUrl(item, entry));
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.arrayBuffer();
const dest = joinPath(DOWNLOAD_DIR, entryFilename(entry));
@@ -350,6 +341,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
return s;
}, [config]);
+
// ── Render ────────────────────────────────────────────────────────────────────
return (
@@ -432,28 +424,6 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
)}
- {categories.length > 0 && (
-
-
- {categories.map(c => {
- const name = (c.name ?? c.title ?? String(c.id)) as string;
- return (
-
- );
- })}
-
- )}
{/* Filter + sort bar */}
@@ -528,9 +498,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
{isSearching && }
{visibleResults.length}{results.length !== visibleResults.length ? ` of ${results.length}` : ''} result{visibleResults.length !== 1 ? 's' : ''}{hasMore ? '+' : ''}
- {visibleResults.map(item => {
- const catLabel = categoryName[item.category] ?? `Cat ${item.category}`;
- return (
+ {visibleResults.map(item => (
{item.name}
- {catLabel}
{item.place === 1 && }
@@ -580,8 +547,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
- );
- })}
+ ))}
{hasMore && (
@@ -681,6 +647,7 @@ export default function SearchCommoServe({ config, setConfig, onClose }: SearchC
key={entry.id}
className={`px-4 py-3 rounded-lg border flex items-center gap-3 ${isMounted ? 'border-blue-300 bg-blue-50' : 'border-neutral-200'}`}
>
+
{fname}
{humanFileSize(entry.size)}