PageSourceSearch

https://www.hamienet.com/assets/AdvancedSearchPage-tGa2266t.js

js hamienet.com collected 2026-09-24 18:59:07 UTC 65,656 bytes, 1,274 lines download raw bytes

1import { r as reactExports, j as jsxRuntimeExports, R as React } from "./vendor-react-Bay9Y7Lb.js";
2import { a as api } from "./index-D0Bmh-UX.js";
3import { V as VideoCard } from "./main-CznOH3wZ.js";
4import { u as useShouldShowAd, A as AdSlot } from "./AdSlot-CPW4Sb2o.js";
5import { u as useTranslation } from "./vendor-i18n-R-bMoYp_.js";
6import { cz as SlidersHorizontal, c3 as RotateCcw, bS as Mic, cA as ChevronUp, cB as ChevronDown, bg as Music, cj as Layers, cC as Drum, bi as Sparkles, bT as Volume2, cn as FileMusic, bJ as PanelsTopLeft, cD as Headphones, cE as Key, bn as Globe, bF as CircleQuestionMark, bf as Search, c8 as ArrowUpDown, cv as LayoutGrid, cw as List, bA as Eye, aW as X } from "./vendor-dVNaLJx_.js";
7import "./vendor-react-three-MDLA5jog.js";
8import "./utils-BYCVoSTN.js";
9import "./synth-BE1TSTD4.js";
10import "./wasm-synth-adapter-BrqgBX1y.js";
11import "./vendor-spessasynth-DH8n6o_V.js";
12import "./vendor-audio-DH3w0BzW.js";
13import "./Waveform-MxtdejK7.js";
14import "./vendor-framer-C8eEgkdL.js";
15import "./labTools-BATZiaPB.js";
16import "./UserAvatar-BQN4jlY-.js";
17const NOTE_NAMES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
18const getNoteName = (midiNumber) => {
19  const octave = Math.floor(midiNumber / 12) - 1;
20  const noteIndex = midiNumber % 12;
21  return `${NOTE_NAMES[noteIndex]}${octave}`;
22};
23const COMMON_INSTRUMENTS = [
24  { name: "Piano", program: 0 },
25  { name: "Bright Piano", program: 1 },
26  { name: "Electric Piano", program: 4 },
27  { name: "Harpsichord", program: 6 },
28  { name: "Celesta", program: 8 },
29  { name: "Organ", program: 16 },
30  { name: "Accordion", program: 21 },
31  { name: "Nylon Guitar", program: 24 },
32  { name: "Steel Guitar", program: 25 },
33  { name: "Electric Guitar", program: 27 },
34  { name: "Acoustic Bass", program: 32 },
35  { name: "Electric Bass", program: 33 },
36  { name: "Violin", program: 40 },
37  { name: "Cello", program: 42 },
38  { name: "Harp", program: 46 },
39  { name: "Timpani", program: 47 },
40  { name: "String Ensemble", program: 48 },
41  { name: "Trumpet", program: 56 },
42  { name: "Trombone", program: 57 },
43  { name: "Tuba", program: 58 },
44  { name: "Soprano Sax", program: 64 },
45  { name: "Alto Sax", program: 65 },
46  { name: "Tenor Sax", program: 66 },
47  { name: "Oboe", program: 68 },
48  { name: "Bassoon", program: 70 },
49  { name: "Clarinet", program: 71 },
50  { name: "Flute", program: 73 },
51  { name: "Recorder", program: 74 },
52  { name: "Synth Lead", program: 80 },
53  { name: "Synth Pad", program: 88 },
54  { name: "Sitar", program: 104 },
55  { name: "Banjo", program: 105 },
56  { name: "Steel Drums", program: 114 }
57];
58const GENRES = ["Classical", "Jazz", "Pop", "Rock", "Electronic", "Soundtrack", "Game Music", "Folk", "Hip Hop", "R&B", "Anime"];
59const MOODS = ["Energetic", "Calm", "Melancholy", "Epic", "Happy", "Dark", "Romantic", "Chill", "Dreamy", "Mysterious"];
60const KEYS = [
61  "C major",
62  "C minor",
63  "G major",
64  "G minor",
65  "D major",
66  "D minor",
67  "A major",
68  "A minor",
69  "E major",
70  "E minor",
71  "B major",
72  "B minor",
73  "F major",
74  "F minor",
75  "B- major",
76  "B- minor",
77  "E- major",
78  "E- minor",
79  "A- major",
80  "D- major",
81  "F# minor",
82  "C# minor"
83];
84const TIME_SIGNATURES = ["4/4", "3/4", "2/4", "6/8", "12/8", "5/4"];
85const DIFFICULTIES = ["Beginner", "Intermediate", "Advanced", "Virtuoso"];
86const AdvancedSearchPage = ({
87  searchQuery,
88  onSelectTrack,
89  onToggleWatchLater,
90  watchLaterSet,
91  onAddToQueue,
92  onAddToPlaylist,
93  theme = "dark"
94}) => {
95  const { t } = useTranslation();
96  const shouldShowExploreAd = useShouldShowAd("exploreList");
97  const [viewMode, setViewMode] = reactExports.useState(() => {
98    return localStorage.getItem("hamie_view_mode") || "grid";
99  });
100  const [expanded, setExpanded] = reactExports.useState({
101    music: true,
102    instruments: true,
103    complexity: true,
104    classification: true,
105    community: false,
106    origin: false,
107    melody: false
108  });
109  const toggleSection = (section) => {
110    setExpanded((prev) => ({ ...prev, [section]: !prev[section] }));
111  };
112  const getInitialFilters = () => {
113    const params = new URLSearchParams(window.location.search);
114    return {
115      q: params.get("q") || "",
116      tempo_min: params.get("tempo_min") || "",
117      tempo_max: params.get("tempo_max") || "",
118      key: params.getAll("key"),
119      time_sig: params.getAll("time_sig"),
120      difficulty: params.getAll("difficulty"),
121      instruments: params.getAll("instruments"),
122      has_drums: params.get("has_drums") === "true",
123      has_lyrics: params.get("has_lyrics") === "true",
124      has_sheets: params.get("has_sheets") === "true",
125      has_stems: params.get("has_stems") === "true",
126      has_analysis: params.get("has_analysis") === "true",
127      duration_min: params.get("duration_min") || "",
128      duration_max: params.get("duration_max") || "",
129      note_count_min: params.get("note_count_min") || "",
130      note_count_max: params.get("note_count_max") || "",
131      track_count_min: params.get("track_count_min") || "",
132      track_count_max: params.get("track_count_max") || "",
133      genre: params.getAll("genre"),
134      mood: params.getAll("mood"),
135      min_views: params.get("min_views") || "",
136      min_likes: params.get("min_likes") || "",
137      country: params.get("country") || "",
138      sort: params.get("sort") || "recent",
139      melody_notes: params.get("melody_notes") || "",
140      melody_mode: params.get("melody_mode") || "easy"
141    };
142  };
143  const [filters, setFilters] = reactExports.useState(getInitialFilters);
144  const [localQ, setLocalQ] = reactExports.useState(filters.q);
145  const [localTempoMin, setLocalTempoMin] = reactExports.useState(filters.tempo_min);
146  const [localTempoMax, setLocalTempoMax] = reactExports.useState(filters.tempo_max);
147  const [localDurationMin, setLocalDurationMin] = reactExports.useState(filters.duration_min);
148  const [localDurationMax, setLocalDurationMax] = reactExports.useState(filters.duration_max);
149  const [localNoteMin, setLocalNoteMin] = reactExports.useState(filters.note_count_min);
150  const [localNoteMax, setLocalNoteMax] = reactExports.useState(filters.note_count_max);
151  const [localTrackMin, setLocalTrackMin] = reactExports.useState(filters.track_count_min);
152  const [localTrackMax, setLocalTrackMax] = reactExports.useState(filters.track_count_max);
153  const [hits, setHits] = reactExports.useState([]);
154  const [facetDistribution, setFacetDistribution] = reactExports.useState({});
155  const [nbHits, setNbHits] = reactExports.useState(0);
156  const [loading, setLoading] = reactExports.useState(false);
157  const [isSidebarOpen, setIsSidebarOpen] = reactExports.useState(true);
158  const [melodyNotes, setMelodyNotes] = reactExports.useState(() => {
159    const raw = new URLSearchParams(window.location.search).get("melody_notes");
160    return raw ? raw.split(",").map(Number).filter((n) => !isNaN(n)) : [];
161  });
162  const [melodyMode, setMelodyMode] = reactExports.useState(filters.melody_mode);
163  const [searchTarget, setSearchTarget] = reactExports.useState(
164    new URLSearchParams(window.location.search).get("target") || "everything"
165  );
166  const fetchResults = reactExports.useCallback(async () => {
167    var _a, _b;
168    setLoading(true);
169    try {
170      let mergedHits = [];
171      let nextFacet = {};
172      let totalNb = 0;
173      const promises = [];
174      if (searchTarget === "everything" || searchTarget === "midi") {
175        promises.push(
176          api.advancedSearch({
177            ...filters,
178            melody_notes: melodyNotes.join(","),
179            melody_mode: melodyMode
180          }).then((res) => ({ type: "midi", res })).catch((err) => {
181            console.error("[Advanced Search Midi Error]", err);
182            return { type: "midi", res: null };
183          })
184        );
185      }
186      if (searchTarget === "everything" || searchTarget === "lyrics") {
187        if (filters.q.trim()) {
188          promises.push(
189            api.searchLyrics(filters.q).then((res) => ({ type: "lyrics", res })).catch((err) => {
190              console.error("[Advanced Search Lyrics Error]", err);
191              return { type: "lyrics", res: null };
192            })
193          );
194        } else if (searchTarget === "lyrics") {
195          setHits([]);
196          setFacetDistribution({});
197          setNbHits(0);
198          setLoading(false);
199          return;
200        }
201      }
202      const results = await Promise.all(promises);
203      const midiData = (_a = results.find((r) => r.type === "midi")) == null ? void 0 : _a.res;
204      const lyricData = (_b = results.find((r) => r.type === "lyrics")) == null ? void 0 : _b.res;
205      if (searchTarget === "midi") {
206        mergedHits = (midiData == null ? void 0 : midiData.hits) || [];
207        nextFacet = (midiData == null ? void 0 : midiData.facetDistribution) || {};
208        totalNb = (midiData == null ? void 0 : midiData.nbHits) || 0;
209      } else if (searchTarget === "lyrics") {
210        mergedHits = ((lyricData == null ? void 0 : lyricData.results) || []).map((l) => ({ ...l, _isLyric: true }));
211        totalNb = (lyricData == null ? void 0 : lyricData.total) || 0;
212      } else {
213        const midis = (midiData == null ? void 0 : midiData.hits) || [];
214        const lyrics = ((lyricData == null ? void 0 : lyricData.results) || []).map((l) => ({ ...l, _isLyric: true }));
215        nextFacet = (midiData == null ? void 0 : midiData.facetDistribution) || {};
216        totalNb = ((midiData == null ? void 0 : midiData.nbHits) || 0) + ((lyricData == null ? void 0 : lyricData.total) || 0);
217        const interleaved = [];
218        const maxLen = Math.max(midis.length, lyrics.length);
219        for (let i = 0; i < maxLen; i++) {
220          if (midis[i]) interleaved.push(midis[i]);
221          if (lyrics[i]) interleaved.push(lyrics[i]);
222        }
223        mergedHits = interleaved;
224      }
225      setHits(mergedHits);
226      setFacetDistribution(nextFacet);
227      setNbHits(totalNb);
228    } catch (e) {
229      console.error("[Advanced Search Fetch Error]", e);
230    } finally {
231      setLoading(false);
232    }
233  }, [filters, melodyNotes, melodyMode, searchTarget]);
234  reactExports.useEffect(() => {
235    const nextFilters = {
236      ...filters,
237      melody_notes: melodyNotes.join(","),
238      melody_mode: melodyMode,
239      target: searchTarget
240    };
241    const params = new URLSearchParams();
242    for (const [key, val] of Object.entries(nextFilters)) {
243      if (val === void 0 || val === null || val === "" || val === false) continue;
244      if (Array.isArray(val)) {
245        val.forEach((v) => params.append(key, v));
246      } else if (typeof val === "boolean") {
247        if (val) params.set(key, "true");
248      } else {
249        params.set(key, String(val));
250      }
251    }
252    const searchStr = params.toString();
253    const nextUrl = window.location.pathname + (searchStr ? `?${searchStr}` : "");
254    if (window.location.search !== `?${searchStr}` && window.location.search !== searchStr) {
255      window.history.replaceState(null, "", nextUrl);
256    }
257  }, [filters, melodyNotes, melodyMode, searchTarget]);
258  reactExports.useEffect(() => {
259    const timer = setTimeout(() => {
260      fetchResults();
261    }, 300);
262    return () => clearTimeout(timer);
263  }, [filters, melodyNotes, melodyMode, searchTarget, fetchResults]);
264  reactExports.useEffect(() => {
265    const onPopState = () => {
266      const init = getInitialFilters();
267      setFilters(init);
268      setLocalQ(init.q);
269      setLocalTempoMin(init.tempo_min);
270      setLocalTempoMax(init.tempo_max);
271      setLocalDurationMin(init.duration_min);
272      setLocalDurationMax(init.duration_max);
273      setLocalNoteMin(init.note_count_min);
274      setLocalNoteMax(init.note_count_max);
275      setLocalTrackMin(init.track_count_min);
276      setLocalTrackMax(init.track_count_max);
277      const raw = new URLSearchParams(window.location.search).get("melody_notes");
278      setMelodyNotes(raw ? raw.split(",").map(Number).filter((n) => !isNaN(n)) : []);
279      setMelodyMode(new URLSearchParams(window.location.search).get("melody_mode") || "easy");
280      setSearchTarget(new URLSearchParams(window.location.search).get("target") || "everything");
281    };
282    window.addEventListener("popstate", onPopState);
283    return () => window.removeEventListener("popstate", onPopState);
284  }, []);
285  reactExports.useEffect(() => {
286    if (searchQuery !== void 0) {
287      setLocalQ(searchQuery);
288      setFilters((prev) => {
289        if (prev.q !== searchQuery) {
290          setLocalTempoMin("");
291          setLocalTempoMax("");
292          setLocalDurationMin("");
293          setLocalDurationMax("");
294          setLocalNoteMin("");
295          setLocalNoteMax("");
296          setLocalTrackMin("");
297          setLocalTrackMax("");
298          setMelodyNotes([]);
299          setMelodyMode("easy");
300          return {
301            q: searchQuery,
302            tempo_min: "",
303            tempo_max: "",
304            key: [],
305            time_sig: [],
306            difficulty: [],
307            instruments: [],
308            has_drums: false,
309            has_lyrics: false,
310            has_sheets: false,
311            has_stems: false,
312            has_analysis: false,
313            duration_min: "",
314            duration_max: "",
315            note_count_min: "",
316            note_count_max: "",
317            track_count_min: "",
318            track_count_max: "",
319            genre: [],
320            mood: [],
321            min_views: "",
322            min_likes: "",
323            country: "",
324            sort: "recent",
325            melody_notes: "",
326            melody_mode: "easy"
327          };
328        }
329        return prev;
330      });
331    }
332  }, [searchQuery]);
333  const handleTextChange = (e) => {
334    const val = e.target.value;
335    setLocalQ(val);
336    setFilters((prev) => ({ ...prev, q: val }));
337  };
338  const handleFilterToggle = (key, val) => {
339    setFilters((prev) => {
340      const arr = [...prev[key] || []];
341      const idx = arr.indexOf(val);
342      if (idx > -1) {
343        arr.splice(idx, 1);
344      } else {
345        arr.push(val);
346      }
347      return { ...prev, [key]: arr };
348    });
349  };
350  const handleBooleanToggle = (key) => {
351    setFilters((prev) => ({ ...prev, [key]: !prev[key] }));
352  };
353  const handleRangeChange = (key, val) => {
354    setFilters((prev) => ({ ...prev, [key]: val }));
355  };
356  const handleReset = () => {
357    setLocalQ("");
358    setLocalTempoMin("");
359    setLocalTempoMax("");
360    setLocalDurationMin("");
361    setLocalDurationMax("");
362    setLocalNoteMin("");
363    setLocalNoteMax("");
364    setLocalTrackMin("");
365    setLocalTrackMax("");
366    setMelodyNotes([]);
367    setFilters({
368      q: "",
369      tempo_min: "",
370      tempo_max: "",
371      key: [],
372      time_sig: [],
373      difficulty: [],
374      instruments: [],
375      has_drums: false,
376      has_lyrics: false,
377      has_sheets: false,
378      has_stems: false,
379      has_analysis: false,
380      duration_min: "",
381      duration_max: "",
382      note_count_min: "",
383      note_count_max: "",
384      track_count_min: "",
385      track_count_max: "",
386      genre: [],
387      mood: [],
388      min_views: "",
389      min_likes: "",
390      country: "",
391      sort: "recent",
392      melody_notes: "",
393      melody_mode: "easy"
394    });
395  };
396  const playMidiNote = (note) => {
397    try {
398      const ctx = new (window.AudioContext || window.webkitAudioContext)();
399      const osc = ctx.createOscillator();
400      const gain = ctx.createGain();
401      const freq = 440 * Math.pow(2, (note - 69) / 12);
402      osc.frequency.setValueAtTime(freq, ctx.currentTime);
403      osc.type = "sine";
404      gain.gain.setValueAtTime(0.15, ctx.currentTime);
405      gain.gain.exponentialRampToValueAtTime(1e-3, ctx.currentTime + 0.4);
406      osc.connect(gain);
407      gain.connect(ctx.destination);
408      osc.start();
409      osc.stop(ctx.currentTime + 0.4);
410    } catch (e) {
411      console.warn("AudioContext playback blocked:", e);
412    }
413  };
414  const handlePianoKeyPress = (note) => {
415    playMidiNote(note);
416    setMelodyNotes((prev) => [...prev, note]);
417  };
418  const removeLastNote = () => {
419    setMelodyNotes((prev) => prev.slice(0, -1));
420  };
421  const getFacetCount = (facetKey, val) => {
422    var _a;
423    return ((_a = facetDistribution == null ? void 0 : facetDistribution[facetKey]) == null ? void 0 : _a[val]) || 0;
424  };
425  const getActiveFilterCount = () => {
426    let count = 0;
427    if (filters.q) count++;
428    if (filters.tempo_min || filters.tempo_max) count++;
429    if (filters.duration_min || filters.duration_max) count++;
430    if (filters.note_count_min || filters.note_count_max) count++;
431    if (filters.track_count_min || filters.track_count_max) count++;
432    if (filters.country) count++;
433    if (filters.min_views) count++;
434    if (filters.min_likes) count++;
435    if (filters.has_drums) count++;
436    if (filters.has_lyrics) count++;
437    if (filters.has_sheets) count++;
438    if (filters.has_stems) count++;
439    if (filters.has_analysis) count++;
440    count += filters.key.length;
441    count += filters.time_sig.length;
442    count += filters.difficulty.length;
443    count += filters.instruments.length;
444    count += filters.genre.length;
445    count += filters.mood.length;
446    if (melodyNotes.length > 0) count++;
447    return count;
448  };
449  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `advanced-search-page`, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-container", children: [
450    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:hidden w-full flex justify-between mb-4", children: [
451      /* @__PURE__ */ jsxRuntimeExports.jsxs(
452        "button",
453        {
454          onClick: () => setIsSidebarOpen(!isSidebarOpen),
455          className: "flex items-center gap-2 px-4 py-2.5 bg-zinc-900 rounded-xl font-bold border border-zinc-800 text-xs text-white",
456          children: [
457            /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersHorizontal, { size: 14 }),
458            isSidebarOpen ? "Hide Filters" : "Show Filters"
459          ]
460        }
461      ),
462      /* @__PURE__ */ jsxRuntimeExports.jsxs(
463        "button",
464        {
465          onClick: handleReset,
466          className: "flex items-center gap-2 px-4 py-2.5 bg-zinc-900 rounded-xl font-bold border border-zinc-800 text-xs text-white",
467          children: [
468            /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 14 }),
469            "Reset"
470          ]
471        }
472      )
473    ] }),
474    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `as-sidebar ${!isSidebarOpen ? "collapsed" : ""} ${searchTarget === "lyrics" ? "opacity-30 pointer-events-none grayscale" : ""}`, children: [
475      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center pb-2 border-b border-zinc-200 dark:border-zinc-800", children: [
476        /* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-sm font-black uppercase tracking-wider flex items-center gap-2 text-zinc-900 dark:text-white", children: [
477          /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersHorizontal, { size: 14, className: "text-indigo-500" }),
478          t("search.advancedFilters", "Advanced Filters")
479        ] }),
480        /* @__PURE__ */ jsxRuntimeExports.jsxs(
481          "button",
482          {
483            onClick: handleReset,
484            className: "text-[10px] font-black text-indigo-500 hover:text-indigo-600 dark:hover:text-indigo-400 uppercase tracking-widest flex items-center gap-1 bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded",
485            children: [
486              /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCcw, { size: 10 }),
487              t("search.resetAll", "Reset All")
488            ]
489          }
490        )
491      ] }),
492      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
493        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("melody"), children: [
494          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
495            /* @__PURE__ */ jsxRuntimeExports.jsx(Mic, { size: 12, className: "text-pink-500" }),
496            t("search.melodyKeyboardSearch", "Melody Keyboard Search")
497          ] }),
498          expanded.melody ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
499        ] }),
500        expanded.melody && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
501          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 font-semibold mb-2", children: "Click keys below to input melody intervals. Restricts results to tracks matching the melody pattern." }),
502          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
503            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex bg-zinc-950 p-2 rounded-xl border border-zinc-800 justify-center gap-1 overflow-x-auto", children: [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76].map((note) => {
504              const isBlack = [1, 3, 6, 8, 10].includes(note % 12);
505              return /* @__PURE__ */ jsxRuntimeExports.jsx(
506                "button",
507                {
508                  onClick: () => handlePianoKeyPress(note),
509                  className: `h-16 w-6 rounded-b transition-all active:scale-95 shrink-0 ${isBlack ? "bg-zinc-850 border border-zinc-950 text-white z-10 -mx-1.5 h-11 w-4.5" : "bg-white border border-zinc-300 text-zinc-900"}`,
510                  style: {
511                    boxShadow: isBlack ? "inset 0 -3px 0 rgba(0,0,0,0.5)" : "inset 0 -3px 0 rgba(0,0,0,0.1)"
512                  },
513                  title: getNoteName(note)
514                },
515                note
516              );
517            }) }),
518            melodyNotes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 p-2 bg-zinc-100 dark:bg-zinc-900 rounded-xl border border-zinc-200 dark:border-zinc-850", children: [
519              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [
520                /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-bold uppercase tracking-wider text-zinc-500", children: [
521                  "Notes Sequence (",
522                  melodyNotes.length,
523                  ")"
524                ] }),
525                /* @__PURE__ */ jsxRuntimeExports.jsx(
526                  "button",
527                  {
528                    onClick: removeLastNote,
529                    className: "text-[9px] font-bold text-red-500 hover:underline uppercase",
530                    children: "Delete Last"
531                  }
532                )
533              ] }),
534              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1 max-h-16 overflow-y-auto custom-scrollbar", children: melodyNotes.map((note, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold px-1.5 py-0.5 bg-indigo-500/10 text-indigo-500 border border-indigo-500/20 rounded", children: getNoteName(note) }, i)) }),
535              /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 mt-1", children: [
536                /* @__PURE__ */ jsxRuntimeExports.jsx(
537                  "button",
538                  {
539                    onClick: () => setMelodyMode("easy"),
540                    className: `flex-1 text-[9px] font-black py-1 rounded border uppercase tracking-wider ${melodyMode === "easy" ? "bg-indigo-500 text-white border-indigo-500" : "bg-transparent text-zinc-400 border-zinc-700"}`,
541                    children: "Easy (Parsons)"
542                  }
543                ),
544                /* @__PURE__ */ jsxRuntimeExports.jsx(
545                  "button",
546                  {
547                    onClick: () => setMelodyMode("advanced"),
548                    className: `flex-1 text-[9px] font-black py-1 rounded border uppercase tracking-wider ${melodyMode === "advanced" ? "bg-indigo-500 text-white border-indigo-500" : "bg-transparent text-zinc-400 border-zinc-700"}`,
549                    children: "Exact Intervals"
550                  }
551                )
552              ] })
553            ] })
554          ] })
555        ] })
556      ] }),
557      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
558        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("music"), children: [
559          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
560            /* @__PURE__ */ jsxRuntimeExports.jsx(Music, { size: 12, className: "text-indigo-500" }),
561            t("search.musicalProperties", "Musical Properties")
562          ] }),
563          expanded.music ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
564        ] }),
565        expanded.music && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
566          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
567            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.keySignature", "Key Signature") }),
568            /* @__PURE__ */ jsxRuntimeExports.jsxs(
569              "select",
570              {
571                value: filters.key[0] || "",
572                onChange: (e) => setFilters((prev) => ({ ...prev, key: e.target.value ? [e.target.value] : [] })),
573                className: "as-select",
574                children: [
575                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "", children: t("search.anyKey", "Any Key") }),
576                  KEYS.map((k) => /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: k, children: [
577                    k,
578                    " ",
579                    getFacetCount("keySignature", k) > 0 ? `(${getFacetCount("keySignature", k)})` : ""
580                  ] }, k))
581                ]
582              }
583            )
584          ] }),
585          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
586            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-range-labels", children: [
587              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("search.tempoBpm", "Tempo / BPM") }),
588              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
589                filters.tempo_min || "40",
590                " - ",
591                filters.tempo_max || "240"
592              ] })
593            ] }),
594            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-inputs", children: [
595              /* @__PURE__ */ jsxRuntimeExports.jsx(
596                "input",
597                {
598                  type: "number",
599                  placeholder: "Min",
600                  value: localTempoMin,
601                  onChange: (e) => {
602                    setLocalTempoMin(e.target.value);
603                    handleRangeChange("tempo_min", e.target.value);
604                  },
605                  className: "as-range-input"
606                }
607              ),
608              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "-" }),
609              /* @__PURE__ */ jsxRuntimeExports.jsx(
610                "input",
611                {
612                  type: "number",
613                  placeholder: "Max",
614                  value: localTempoMax,
615                  onChange: (e) => {
616                    setLocalTempoMax(e.target.value);
617                    handleRangeChange("tempo_max", e.target.value);
618                  },
619                  className: "as-range-input"
620                }
621              )
622            ] })
623          ] }),
624          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
625            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.timeSignature", "Time Signature") }),
626            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "as-chips-grid", children: TIME_SIGNATURES.map((sig) => {
627              const isActive = filters.time_sig.includes(sig);
628              const count = getFacetCount("timeSignature", sig);
629              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
630                "button",
631                {
632                  onClick: () => handleFilterToggle("time_sig", sig),
633                  className: `as-chip ${isActive ? "active" : ""}`,
634                  children: [
635                    sig,
636                    count > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip-count", children: [
637                      "(",
638                      count,
639                      ")"
640                    ] })
641                  ]
642                },
643                sig
644              );
645            }) })
646          ] })
647        ] })
648      ] }),
649      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
650        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("instruments"), children: [
651          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
652            /* @__PURE__ */ jsxRuntimeExports.jsx(Layers, { size: 12, className: "text-emerald-500" }),
653            t("search.instrumentation", "Instrumentation")
654          ] }),
655          expanded.instruments ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
656        ] }),
657        expanded.instruments && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
658          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
659            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-range-labels", children: [
660              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t("search.numberOfTracks", "Number of Tracks") }),
661              /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
662                filters.track_count_min || "1",
663                " - ",
664                filters.track_count_max || "32+"
665              ] })
666            ] }),
667            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-inputs", children: [
668              /* @__PURE__ */ jsxRuntimeExports.jsx(
669                "input",
670                {
671                  type: "number",
672                  placeholder: "Min",
673                  value: localTrackMin,
674                  onChange: (e) => {
675                    setLocalTrackMin(e.target.value);
676                    handleRangeChange("track_count_min", e.target.value);
677                  },
678                  className: "as-range-input"
679                }
680              ),
681              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "-" }),
682              /* @__PURE__ */ jsxRuntimeExports.jsx(
683                "input",
684                {
685                  type: "number",
686                  placeholder: "Max",
687                  value: localTrackMax,
688                  onChange: (e) => {
689                    setLocalTrackMax(e.target.value);
690                    handleRangeChange("track_count_max", e.target.value);
691                  },
692                  className: "as-range-input"
693                }
694              )
695            ] })
696          ] }),
697          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-toggle-wrapper", children: [
698            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
699              /* @__PURE__ */ jsxRuntimeExports.jsx(Drum, { size: 12, className: "text-zinc-400" }),
700              t("search.hasDrums", "Has Drums/Percussion")
701            ] }),
702            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "as-switch", children: [
703              /* @__PURE__ */ jsxRuntimeExports.jsx(
704                "input",
705                {
706                  type: "checkbox",
707                  checked: filters.has_drums,
708                  onChange: () => handleBooleanToggle("has_drums")
709                }
710              ),
711              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-slider" })
712            ] })
713          ] }),
714          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
715            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.instrumentsUsed", "Instruments Used") }),
716            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "as-chips-grid max-h-48 overflow-y-auto custom-scrollbar p-1 border border-zinc-200 dark:border-zinc-800 rounded-lg", children: COMMON_INSTRUMENTS.map((inst) => {
717              const isActive = filters.instruments.includes(String(inst.program));
718              const count = getFacetCount("instrumentNames", inst.name);
719              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
720                "button",
721                {
722                  onClick: () => handleFilterToggle("instruments", String(inst.program)),
723                  className: `as-chip ${isActive ? "active" : ""}`,
724                  children: [
725                    t(`instruments.${inst.name}`, inst.name),
726                    count > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip-count", children: [
727                      "(",
728                      count,
729                      ")"
730                    ] })
731                  ]
732                },
733                inst.program
734              );
735            }) })
736          ] })
737        ] })
738      ] }),
739      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
740        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("complexity"), children: [
741          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
742            /* @__PURE__ */ jsxRuntimeExports.jsx(SlidersHorizontal, { size: 12, className: "text-amber-500" }),
743            t("search.difficultyComplexity", "Difficulty & Complexity")
744          ] }),
745          expanded.complexity ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
746        ] }),
747        expanded.complexity && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
748          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
749            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.difficulty", "Difficulty") }),
750            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "as-chips-grid", children: DIFFICULTIES.map((diff) => {
751              const isActive = filters.difficulty.includes(diff);
752              const count = getFacetCount("difficulty", diff);
753              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
754                "button",
755                {
756                  onClick: () => handleFilterToggle("difficulty", diff),
757                  className: `as-chip ${isActive ? "active" : ""}`,
758                  children: [
759                    t(`difficulties.${diff}`, diff),
760                    count > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip-count", children: [
761                      "(",
762                      count,
763                      ")"
764                    ] })
765                  ]
766                },
767                diff
768              );
769            }) })
770          ] }),
771          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
772            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.durationSeconds", "Duration (seconds)") }),
773            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-inputs", children: [
774              /* @__PURE__ */ jsxRuntimeExports.jsx(
775                "input",
776                {
777                  type: "number",
778                  placeholder: "Min",
779                  value: localDurationMin,
780                  onChange: (e) => {
781                    setLocalDurationMin(e.target.value);
782                    handleRangeChange("duration_min", e.target.value);
783                  },
784                  className: "as-range-input"
785                }
786              ),
787              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "-" }),
788              /* @__PURE__ */ jsxRuntimeExports.jsx(
789                "input",
790                {
791                  type: "number",
792                  placeholder: "Max",
793                  value: localDurationMax,
794                  onChange: (e) => {
795                    setLocalDurationMax(e.target.value);
796                    handleRangeChange("duration_max", e.target.value);
797                  },
798                  className: "as-range-input"
799                }
800              )
801            ] })
802          ] }),
803          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
804            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.noteCountNotes", "Note Count (Notes)") }),
805            /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-inputs", children: [
806              /* @__PURE__ */ jsxRuntimeExports.jsx(
807                "input",
808                {
809                  type: "number",
810                  placeholder: "Min",
811                  value: localNoteMin,
812                  onChange: (e) => {
813                    setLocalNoteMin(e.target.value);
814                    handleRangeChange("note_count_min", e.target.value);
815                  },
816                  className: "as-range-input"
817                }
818              ),
819              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500", children: "-" }),
820              /* @__PURE__ */ jsxRuntimeExports.jsx(
821                "input",
822                {
823                  type: "number",
824                  placeholder: "Max",
825                  value: localNoteMax,
826                  onChange: (e) => {
827                    setLocalNoteMax(e.target.value);
828                    handleRangeChange("note_count_max", e.target.value);
829                  },
830                  className: "as-range-input"
831                }
832              )
833            ] })
834          ] })
835        ] })
836      ] }),
837      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
838        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("classification"), children: [
839          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
840            /* @__PURE__ */ jsxRuntimeExports.jsx(Sparkles, { size: 12, className: "text-purple-500" }),
841            t("search.genreMood", "Genre & Mood")
842          ] }),
843          expanded.classification ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
844        ] }),
845        expanded.classification && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
846          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
847            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.genres", "Genres") }),
848            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "as-chips-grid max-h-36 overflow-y-auto custom-scrollbar p-1", children: GENRES.map((g) => {
849              const isActive = filters.genre.includes(g);
850              const count = getFacetCount("genreTags", g);
851              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
852                "button",
853                {
854                  onClick: () => handleFilterToggle("genre", g),
855                  className: `as-chip ${isActive ? "active" : ""}`,
856                  children: [
857                    t(`genres.${g}`, g),
858                    count > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip-count", children: [
859                      "(",
860                      count,
861                      ")"
862                    ] })
863                  ]
864                },
865                g
866              );
867            }) })
868          ] }),
869          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
870            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.moods", "Moods") }),
871            /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "as-chips-grid max-h-36 overflow-y-auto custom-scrollbar p-1", children: MOODS.map((m) => {
872              const isActive = filters.mood.includes(m);
873              const count = getFacetCount("moodTags", m);
874              return /* @__PURE__ */ jsxRuntimeExports.jsxs(
875                "button",
876                {
877                  onClick: () => handleFilterToggle("mood", m),
878                  className: `as-chip ${isActive ? "active" : ""}`,
879                  children: [
880                    t(`moods.${m}`, m),
881                    count > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip-count", children: [
882                      "(",
883                      count,
884                      ")"
885                    ] })
886                  ]
887                },
888                m
889              );
890            }) })
891          ] })
892        ] })
893      ] }),
894      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
895        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("origin"), children: [
896          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
897            /* @__PURE__ */ jsxRuntimeExports.jsx(Volume2, { size: 12, className: "text-pink-400" }),
898            t("search.availabilityOrigin", "Availability & Origin")
899          ] }),
900          expanded.origin ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
901        ] }),
902        expanded.origin && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
903          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-toggle-wrapper", children: [
904            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
905              /* @__PURE__ */ jsxRuntimeExports.jsx(FileMusic, { size: 12, className: "text-zinc-400" }),
906              t("search.hasSheetMusic", "Has Sheet Music")
907            ] }),
908            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "as-switch", children: [
909              /* @__PURE__ */ jsxRuntimeExports.jsx(
910                "input",
911                {
912                  type: "checkbox",
913                  checked: filters.has_sheets,
914                  onChange: () => handleBooleanToggle("has_sheets")
915                }
916              ),
917              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-slider" })
918            ] })
919          ] }),
920          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-toggle-wrapper", children: [
921            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
922              /* @__PURE__ */ jsxRuntimeExports.jsx(PanelsTopLeft, { size: 12, className: "text-zinc-400" }),
923              t("search.hasSeparatedStems", "Has Separated Stems")
924            ] }),
925            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "as-switch", children: [
926              /* @__PURE__ */ jsxRuntimeExports.jsx(
927                "input",
928                {
929                  type: "checkbox",
930                  checked: filters.has_stems,
931                  onChange: () => handleBooleanToggle("has_stems")
932                }
933              ),
934              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-slider" })
935            ] })
936          ] }),
937          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-toggle-wrapper", children: [
938            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
939              /* @__PURE__ */ jsxRuntimeExports.jsx(Headphones, { size: 12, className: "text-zinc-400" }),
940              t("search.hasLyrics", "Has Lyrics")
941            ] }),
942            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "as-switch", children: [
943              /* @__PURE__ */ jsxRuntimeExports.jsx(
944                "input",
945                {
946                  type: "checkbox",
947                  checked: filters.has_lyrics,
948                  onChange: () => handleBooleanToggle("has_lyrics")
949                }
950              ),
951              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-slider" })
952            ] })
953          ] }),
954          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-toggle-wrapper", children: [
955            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
956              /* @__PURE__ */ jsxRuntimeExports.jsx(Key, { size: 12, className: "text-zinc-400" }),
957              t("search.hasHarmonicAnalysis", "Has Harmonic Analysis")
958            ] }),
959            /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "as-switch", children: [
960              /* @__PURE__ */ jsxRuntimeExports.jsx(
961                "input",
962                {
963                  type: "checkbox",
964                  checked: filters.has_analysis,
965                  onChange: () => handleBooleanToggle("has_analysis")
966                }
967              ),
968              /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-slider" })
969            ] })
970          ] }),
971          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper mt-2", children: [
972            /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-range-labels", children: [
973              /* @__PURE__ */ jsxRuntimeExports.jsx(Globe, { size: 11, className: "text-zinc-400 inline mr-1" }),
974              t("search.geotaggedCountry", "Geotagged Origin Country")
975            ] }),
976            /* @__PURE__ */ jsxRuntimeExports.jsx(
977              "input",
978              {
979                type: "text",
980                placeholder: "e.g. US, JP, DE",
981                value: filters.country,
982                onChange: (e) => handleRangeChange("country", e.target.value.toUpperCase().slice(0, 2)),
983                className: "as-range-input"
984              }
985            )
986          ] })
987        ] })
988      ] }),
989      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-accordion-section", children: [
990        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-header", onClick: () => toggleSection("community"), children: [
991          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-2", children: [
992            /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { size: 12, className: "text-zinc-400" }),
993            t("search.communityMetrics", "Community Metrics")
994          ] }),
995          expanded.community ? /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronUp, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(ChevronDown, { size: 14 })
996        ] }),
997        expanded.community && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-section-content", children: [
998          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
999            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.minViews", "Minimum Views") }),
1000            /* @__PURE__ */ jsxRuntimeExports.jsx(
1001              "input",
1002              {
1003                type: "number",
1004                placeholder: "e.g. 50",
1005                value: filters.min_views,
1006                onChange: (e) => handleRangeChange("min_views", e.target.value),
1007                className: "as-range-input"
1008              }
1009            )
1010          ] }),
1011          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-range-wrapper", children: [
1012            /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "as-range-labels", children: t("search.minLikes", "Minimum Likes") }),
1013            /* @__PURE__ */ jsxRuntimeExports.jsx(
1014              "input",
1015              {
1016                type: "number",
1017                placeholder: "e.g. 5",
1018                value: filters.min_likes,
1019                onChange: (e) => handleRangeChange("min_likes", e.target.value),
1020                className: "as-range-input"
1021              }
1022            )
1023          ] })
1024        ] })
1025      ] })
1026    ] }),
1027    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-main", children: [
1028      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-header-card", children: [
1029        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-200 dark:bg-zinc-800/80 p-1 rounded-xl mb-4 w-full self-start shadow-inner text-sm font-bold border border-zinc-300 dark:border-zinc-700", children: [
1030          /* @__PURE__ */ jsxRuntimeExports.jsx(
1031            "button",
1032            {
1033              onClick: () => setSearchTarget("everything"),
1034              className: `flex-1 px-6 py-2 rounded-lg transition-all ${searchTarget === "everything" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,
1035              children: t("search.targetEverything", "Everything")
1036            }
1037          ),
1038          /* @__PURE__ */ jsxRuntimeExports.jsx(
1039            "button",
1040            {
1041              onClick: () => setSearchTarget("midi"),
1042              className: `flex-1 px-6 py-2 rounded-lg transition-all ${searchTarget === "midi" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,
1043              children: t("search.targetMidi", "MIDI Tracks")
1044            }
1045          ),
1046          /* @__PURE__ */ jsxRuntimeExports.jsx(
1047            "button",
1048            {
1049              onClick: () => setSearchTarget("lyrics"),
1050              className: `flex-1 px-6 py-2 rounded-lg transition-all ${searchTarget === "lyrics" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-500 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-200"}`,
1051              children: t("search.targetLyrics", "Lyrics")
1052            }
1053          )
1054        ] }),
1055        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-search-input-wrapper", children: [
1056          /* @__PURE__ */ jsxRuntimeExports.jsx(Search, { className: "as-search-icon", size: 16 }),
1057          /* @__PURE__ */ jsxRuntimeExports.jsx(
1058            "input",
1059            {
1060              type: "text",
1061              placeholder: t("search.searchPlaceholder", "Search MIDI title, artist, or tags..."),
1062              value: localQ,
1063              onChange: handleTextChange,
1064              className: "as-search-input-field"
1065            }
1066          )
1067        ] }),
1068        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-info-controls", children: [
1069          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-results-count", children: [
1070            nbHits,
1071            " ",
1072            nbHits === 1 ? "result" : "results",
1073            " found"
1074          ] }),
1075          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1076            /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowUpDown, { size: 14, className: "text-zinc-500" }),
1077            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1078              "select",
1079              {
1080                value: filters.sort,
1081                onChange: (e) => handleRangeChange("sort", e.target.value),
1082                className: "as-select py-1.5 px-3 text-xs w-36",
1083                children: [
1084                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "recent", children: t("search.sortRecent", "Recent") }),
1085                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "popular", children: t("search.sortPopular", "Popularity") }),
1086                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "top-rated", children: t("search.sortTopRated", "Top Rated") }),
1087                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "plays", children: t("search.sortPlays", "Most Played") }),
1088                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "tempo-asc", children: t("search.sortTempoAsc", "Tempo (Low to High)") }),
1089                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "tempo-desc", children: t("search.sortTempoDesc", "Tempo (High to Low)") }),
1090                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "duration-asc", children: t("search.sortDurationAsc", "Duration (Short to Long)") }),
1091                  /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "duration-desc", children: t("search.sortDurationDesc", "Duration (Long to Short)") })
1092                ]
1093              }
1094            )
1095          ] }),
1096          /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center bg-zinc-100 dark:bg-zinc-800 p-1 rounded-xl shadow-inner shrink-0", children: [
1097            /* @__PURE__ */ jsxRuntimeExports.jsx(
1098              "button",
1099              {
1100                onClick: () => {
1101                  setViewMode("grid");
1102                  localStorage.setItem("hamie_view_mode", "grid");
1103                },
1104                className: `p-1.5 rounded-lg transition-all ${viewMode === "grid" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300"}`,
1105                title: "Grid View",
1106                children: /* @__PURE__ */ jsxRuntimeExports.jsx(LayoutGrid, { size: 16 })
1107              }
1108            ),
1109            /* @__PURE__ */ jsxRuntimeExports.jsx(
1110              "button",
1111              {
1112                onClick: () => {
1113                  setViewMode("list");
1114                  localStorage.setItem("hamie_view_mode", "list");
1115                },
1116                className: `p-1.5 rounded-lg transition-all ${viewMode === "list" ? "bg-white dark:bg-zinc-700 text-indigo-600 shadow-sm" : "text-zinc-400 hover:text-zinc-600 dark:hover:text-zinc-300"}`,
1117                title: "List View",
1118                children: /* @__PURE__ */ jsxRuntimeExports.jsx(List, { size: 16 })
1119              }
1120            )
1121          ] })
1122        ] })
1123      ] }),
1124      getActiveFilterCount() > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-active-filters bg-zinc-100 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-2.5 flex items-center justify-between", children: [
1125        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1.5 items-center", children: [
1126          /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase text-zinc-500 mr-2 tracking-wider", children: t("search.activeFilters", "Active Filters:") }),
1127          filters.q && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1128            'Text: "',
1129            filters.q,
1130            '"',
1131            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => {
1132              setLocalQ("");
1133              handleRangeChange("q", "");
1134            } })
1135          ] }),
1136          melodyNotes.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px] bg-pink-600 border-pink-600", children: [
1137            t("search.filterMelody", "Melody Sequence"),
1138            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => setMelodyNotes([]) })
1139          ] }),
1140          filters.key.map((k) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1141            "Key: ",
1142            k,
1143            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("key", k) })
1144          ] }, k)),
1145          filters.time_sig.map((s) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1146            "Sig: ",
1147            s,
1148            /* @__P
1148URE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("time_sig", s) })
1149          ] }, s)),
1150          filters.difficulty.map((d) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1151            "Diff: ",
1152            d,
1153            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("difficulty", d) })
1154          ] }, d)),
1155          filters.genre.map((g) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px] bg-purple-600 border-purple-600", children: [
1156            g,
1157            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("genre", g) })
1158          ] }, g)),
1159          filters.mood.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px] bg-purple-600 border-purple-600", children: [
1160            m,
1161            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("mood", m) })
1162          ] }, m)),
1163          filters.instruments.map((prog) => {
1164            const inst = COMMON_INSTRUMENTS.find((i) => String(i.program) === prog);
1165            return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px] bg-emerald-600 border-emerald-600", children: [
1166              "Inst: ",
1167              (inst == null ? void 0 : inst.name) || prog,
1168              /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleFilterToggle("instruments", prog) })
1169            ] }, prog);
1170          }),
1171          filters.has_drums && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1172            t("search.filterDrums", "Drums"),
1173            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleRangeChange("has_drums", "") })
1174          ] }),
1175          filters.has_lyrics && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1176            t("search.targetLyrics", "Lyrics"),
1177            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleRangeChange("has_lyrics", "") })
1178          ] }),
1179          filters.has_sheets && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1180            t("search.filterSheets", "Sheet Music"),
1181            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleRangeChange("has_sheets", "") })
1182          ] }),
1183          filters.has_stems && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1184            t("search.filterStems", "Stems"),
1185            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleRangeChange("has_stems", "") })
1186          ] }),
1187          filters.has_analysis && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1188            t("search.filterAnalyzed", "Analyzed"),
1189            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => handleRangeChange("has_analysis", "") })
1190          ] }),
1191          (filters.tempo_min || filters.tempo_max) && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "as-chip active py-1 text-[10px]", children: [
1192            "Tempo: ",
1193            filters.tempo_min || "40",
1194            "-",
1195            filters.tempo_max || "240",
1196            " BPM",
1197            /* @__PURE__ */ jsxRuntimeExports.jsx(X, { size: 10, onClick: () => {
1198              setLocalTempoMin("");
1199              setLocalTempoMax("");
1200              setFilters((prev) => ({ ...prev, tempo_min: "", tempo_max: "" }));
1201            } })
1202          ] })
1203        ] }),
1204        /* @__PURE__ */ jsxRuntimeExports.jsx(
1205          "button",
1206          {
1207            onClick: handleReset,
1208            className: "as-clear-all-btn text-[10px] whitespace-nowrap",
1209            children: t("search.clearAll", "Clear All")
1210          }
1211        )
1212      ] }),
1213      loading ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex h-96 items-center justify-center min-h-[50vh]", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin" }) }) : hits.length > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "as-tracks-grid" : "flex flex-col gap-4 w-full", children: hits.map((track, idx) => {
1214        const showAd = (idx + 1) % 12 === 0;
1215        if (track._isLyric) {
1216          return /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
1217            /* @__PURE__ */ jsxRuntimeExports.jsxs(
1218              "div",
1219              {
1220                onClick: () => window.location.href = `/lyrics/${track.id}`,
1221                className: `p-4 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 hover:border-indigo-500 rounded-xl cursor-pointer shadow-sm hover:shadow-md transition flex flex-col justify-between ${viewMode === "grid" ? "aspect-video" : "w-full flex-row items-center h-20"}`,
1222                children: [
1223                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
1224                    /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-zinc-900 dark:text-white group-hover:text-indigo-400 transition mb-1 text-base line-clamp-1", children: track.title }),
1225                    /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 text-xs text-zinc-500 line-clamp-1", children: [
1226                      track.artist && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-indigo-400 font-medium", children: track.artist }),
1227                      track.album && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: track.album })
1228                    ] })
1229                  ] }),
1230                  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `flex items-center gap-3 text-xs text-zinc-500 ${viewMode === "grid" ? "mt-4" : "ml-auto"}`, children: [
1231                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1 font-bold text-indigo-500 bg-indigo-500/10 px-2 py-1 rounded", children: [
1232                      /* @__PURE__ */ jsxRuntimeExports.jsx(Mic, { size: 12 }),
1233                      t("search.targetLyrics", "Lyrics")
1234                    ] }),
1235                    /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [
1236                      /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 12 }),
1237                      track.views || 0
1238                    ] })
1239                  ] })
1240                ]
1241              },
1242              `lyric-${track.id}`
1243            ),
1244            showAd && shouldShowExploreAd && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "col-span-1" : "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { type: "exploreList", className: "!my-0 h-full min-h-[200px]" }) })
1245          ] }, `lyric-frag-${track.id}-${idx}`);
1246        }
1247        return /* @__PURE__ */ jsxRuntimeExports.jsxs(React.Fragment, { children: [
1248          /* @__PURE__ */ jsxRuntimeExports.jsx(
1249            VideoCard,
1250            {
1251              track,
1252              onSelect: onSelectTrack,
1253              onToggleWatchLater,
1254              isWatchLater: watchLaterSet.has(String(track.id)),
1255              onAddToQueue,
1256              onAddToPlaylist,
1257              variant: viewMode
1258            },
1259            `midi-${track.id}`
1260          ),
1261          showAd && shouldShowExploreAd && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: viewMode === "grid" ? "col-span-1" : "w-full", children: /* @__PURE__ */ jsxRuntimeExports.jsx(AdSlot, { type: "exploreList", className: "!my-0 h-full min-h-[200px]" }) })
1262        ] }, `midi-frag-${track.id}-${idx}`);
1263      }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "as-empty-state", children: [
1264        /* @__PURE__ */ jsxRuntimeExports.jsx(CircleQuestionMark, { size: 48, className: "text-zinc-600 animate-pulse" }),
1265        /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "as-empty-title", children: t("search.noMatchingTracks", "No matching MIDI tracks") }),
1266        /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "as-empty-desc", children: t("search.noMatchingDesc", "We couldn't find any results matching your filter combination. Try resetting some filters or typing a different query.") })
1267      ] })
1268    ] })
1269  ] }) });
1270};
1271export {
1272  AdvancedSearchPage,
1273  AdvancedSearchPage as default
1274};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.