From b3d38762a726ca411b2bd0a024088d34aabbe8de Mon Sep 17 00:00:00 2001 From: dreamoff Date: Mon, 29 Jun 2026 17:40:50 +0200 Subject: [PATCH] Release Splicerr 1.15.1 fixes --- RELEASE_NOTES_1.15.1.md | 7 ++ package.json | 2 +- src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/src/lib.rs | 33 ++++++++++ src/lib/components/audio-player.svelte | 5 +- src/lib/components/pack-preview.svelte | 80 ++++++++++++++++++++++- src/lib/components/settings-dialog.svelte | 26 ++++---- src/lib/shared/store.svelte.ts | 41 ++++++++++++ src/routes/+layout.svelte | 21 +++++- src/routes/+page.svelte | 31 ++++++++- src/routes/sample-list-entry.svelte | 4 +- 12 files changed, 234 insertions(+), 20 deletions(-) create mode 100644 RELEASE_NOTES_1.15.1.md diff --git a/RELEASE_NOTES_1.15.1.md b/RELEASE_NOTES_1.15.1.md new file mode 100644 index 0000000..7fdacd4 --- /dev/null +++ b/RELEASE_NOTES_1.15.1.md @@ -0,0 +1,7 @@ +# Splicerr v1.15.1 - Pack navigation and drag/drop fixes + +- Prevented dropped audio/file URLs from navigating the app window into the browser media player view. +- Changed pack artwork left-click behavior to open the pack's samples inside Splicerr. +- Moved the external Splice pack link to a right-click context menu action: "View on Splice". +- Added an in-app pack filter using the parent pack UUID, with a text-search fallback when the UUID is unavailable. +- Updated the DAW Bridge settings status on macOS to show both installed plug-in locations: AU component and VST3. diff --git a/package.json b/package.json index 5e47d4f..d4c2bbd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "splicerr", - "version": "1.15.0", + "version": "1.15.1", "description": "", "type": "module", "scripts": { diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b1f8344..89db616 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3929,7 +3929,7 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "splicerr" -version = "1.15.0" +version = "1.15.1" dependencies = [ "base64 0.22.1", "serde", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 1f8c6e2..3cf548b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "splicerr" -version = "1.15.0" +version = "1.15.1" description = "Yet another Splice frontend, inspired by ascpixi" authors = ["kosro"] edition = "2021" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5449481..30632d1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -498,6 +498,38 @@ fn bridge_install_path() -> Result, String> { } } +#[tauri::command] +fn bridge_install_paths() -> Result, String> { + #[cfg(target_os = "macos")] + { + return Ok(vec![ + Path::new(SYSTEM_COMPONENTS_DIR) + .join("Splicerr Bridge.component") + .to_string_lossy() + .into_owned(), + Path::new(SYSTEM_VST3_DIR) + .join("Splicerr Bridge.vst3") + .to_string_lossy() + .into_owned(), + ]); + } + + #[cfg(target_os = "windows")] + { + return Ok(vec![ + windows_vst3_dir()? + .join(BRIDGE_VST3_BUNDLE) + .to_string_lossy() + .into_owned(), + ]); + } + + #[cfg(not(any(target_os = "macos", target_os = "windows")))] + { + Ok(Vec::new()) + } +} + #[tauri::command] fn install_bridge_plugins(app: tauri::AppHandle) -> Result { #[cfg(target_os = "windows")] @@ -675,6 +707,7 @@ pub fn run() { daw_set_playback_enabled, bridge_plugins_installed, bridge_install_path, + bridge_install_paths, install_bridge_plugins, uninstall_bridge_plugins, open_devtools diff --git a/src/lib/components/audio-player.svelte b/src/lib/components/audio-player.svelte index 0c5ed75..35d73bd 100644 --- a/src/lib/components/audio-player.svelte +++ b/src/lib/components/audio-player.svelte @@ -7,6 +7,7 @@ import SkipBack from "lucide-svelte/icons/skip-back" import { globalAudio } from "$lib/shared/audio.svelte" import type { MouseEventHandler } from "svelte/elements" + import type { PackAsset } from "$lib/splice/types" import LoaderCircle from "lucide-svelte/icons/loader-circle" import { loading } from "$lib/shared/loading.svelte" import PackPreview from "$lib/components/pack-preview.svelte" @@ -34,6 +35,7 @@ class: className, onnext, onprev, + onopenpack, ...restProps }: { class?: string @@ -41,6 +43,7 @@ MouseEventHandler onprev: MouseEventHandler & MouseEventHandler + onopenpack?: (pack: PackAsset) => void } = $props() const currentPack = $derived(globalAudio.currentAsset?.parents.items[0]) @@ -148,7 +151,7 @@ {#if globalAudio.currentAsset}
- +
{#if globalAudio.currentAsset.asset_category_slug in assetIcons} {@const Icon = diff --git a/src/lib/components/pack-preview.svelte b/src/lib/components/pack-preview.svelte index af9dec7..4ed7a4d 100644 --- a/src/lib/components/pack-preview.svelte +++ b/src/lib/components/pack-preview.svelte @@ -3,20 +3,26 @@ import type { PackAsset } from "$lib/splice/types" import { openUrl } from "@tauri-apps/plugin-opener" import { cn } from "$lib/utils" + import { onMount } from "svelte" + import ExternalLink from "lucide-svelte/icons/external-link" + const { pack, side = "right", size = 12, class: className, + onopenpack, }: { pack: PackAsset | undefined side?: "right" | "top" | "bottom" | "left" size?: number class?: string + onopenpack?: (pack: PackAsset) => void } = $props() const name = $derived(pack?.name.split("/").slice(-1)[0]) const imgSrc = $derived(pack?.files[0].url) + let contextMenu = $state<{ x: number; y: number } | null>(null) const sizeStyle = $derived( `width: ${size * 0.25}rem; height: ${size * 0.25}rem;` ) @@ -24,13 +30,58 @@ const packURL = $derived( `https://splice.com/sounds/packs/${pack?.permalink_base_url}/${pack?.permalink_slug}` ) + + const openPackInApp = () => { + if (!pack) return + onopenpack?.(pack) + } + + const openPackOnSplice = () => { + if (!pack) return + contextMenu = null + openUrl(packURL) + } + + const handleKeydown = (event: KeyboardEvent) => { + if (event.key === "Enter" || event.key === " ") { + event.preventDefault() + openPackInApp() + } + } + + onMount(() => { + const closeContextMenu = () => (contextMenu = null) + const closeOnEscape = (event: KeyboardEvent) => { + if (event.key === "Escape") closeContextMenu() + } + window.addEventListener("click", closeContextMenu) + window.addEventListener("keydown", closeOnEscape) + return () => { + window.removeEventListener("click", closeContextMenu) + window.removeEventListener("keydown", closeOnEscape) + } + }) {#if pack} pack && openUrl(packURL)} + role="button" + tabindex={0} + title="Open pack in Splicerr" + onclick={(event) => { + event.stopPropagation() + openPackInApp() + }} + onkeydown={handleKeydown} + oncontextmenu={(event) => { + event.preventDefault() + event.stopPropagation() + contextMenu = { x: event.clientX, y: event.clientY } + }} + onmousedown={(event) => event.stopPropagation()} + ondragstart={(event) => event.preventDefault()} > -

{name}

+ {#if contextMenu} + + {/if} {:else}
(null) let bridgeInstallStatus = $state(null) - let bridgeInstallPath = $state(null) + let bridgeInstallPaths = $state([]) async function refreshBridgeInstallState() { try { bridgeInstalled = await invoke("bridge_plugins_installed") - bridgeInstallPath = await invoke("bridge_install_path") + bridgeInstallPaths = await invoke("bridge_install_paths") } catch (err) { bridgeInstallStatus = String(err) } @@ -252,15 +252,19 @@ {bridgeInstallStatus}

{/if} - {#if bridgeInstalled && bridgeInstallPath} - + {#if bridgeInstalled && bridgeInstallPaths.length > 0} +
+ {#each bridgeInstallPaths as bridgeInstallPath} + + {/each} +
{/if}
diff --git a/src/lib/shared/store.svelte.ts b/src/lib/shared/store.svelte.ts index cace404..3a8cc55 100644 --- a/src/lib/shared/store.svelte.ts +++ b/src/lib/shared/store.svelte.ts @@ -58,6 +58,8 @@ export const queryStore = $state({ random_seed: randomSeed(), order: "DESC" as SortOrder, page: 1, + parent_asset_uuid: null as string | null, + parent_asset_name: null as string | null, asset_category_slug: null as AssetCategorySlug | null, bpm: null as string | null, min_bpm: null as number | null, @@ -73,6 +75,7 @@ const queryIdentity = $derived({ sort: queryStore.sort, order: queryStore.order, random_seed: queryStore.random_seed, + parent_asset_uuid: queryStore.parent_asset_uuid, tags: dataStore.tags, asset_category_slug: queryStore.asset_category_slug, bpm: queryStore.bpm?.toString(), @@ -89,6 +92,43 @@ export const storeCallbacks = $state({ let currentQueryIdentity: string = "" +export function openPackSamples(pack: { uuid?: string; name?: string } | null) { + const packName = pack?.name?.split("/").slice(-1)[0] ?? null + queryStore.page = 1 + queryStore.query = pack?.uuid ? "" : packName?.split(/\s+/)[0] ?? "" + queryStore.parent_asset_uuid = pack?.uuid ?? null + queryStore.parent_asset_name = packName + queryStore.sort = pack?.uuid ? "name" : DEFAULT_SORT + queryStore.order = "ASC" + queryStore.random_seed = randomSeed() + dataStore.tags = [] + queryStore.asset_category_slug = null + queryStore.bpm = null + queryStore.min_bpm = null + queryStore.max_bpm = null + queryStore.key = null + queryStore.chord_type = null + fetchAssets() +} + +export function closePackSamples() { + queryStore.page = 1 + queryStore.parent_asset_uuid = null + queryStore.parent_asset_name = null + queryStore.query = "" + queryStore.sort = DEFAULT_SORT + queryStore.order = "DESC" + queryStore.random_seed = randomSeed() + dataStore.tags = [] + queryStore.asset_category_slug = null + queryStore.bpm = null + queryStore.min_bpm = null + queryStore.max_bpm = null + queryStore.key = null + queryStore.chord_type = null + fetchAssets() +} + async function fetchBinaryResponse(url: string, signal?: AbortSignal) { try { return await window.fetch(url, { signal }) @@ -138,6 +178,7 @@ export const fetchAssets = () => { loading.assets = true querySplice(SamplesSearch, { ...queryIdentity, + parent_asset_type: queryStore.parent_asset_uuid ? "pack" : null, page: queryStore.page, limit: PER_PAGE, }) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 4542182..c210602 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -22,6 +22,21 @@ }) onMount(() => { + const preventFileNavigation = (event: DragEvent) => { + const types = Array.from(event.dataTransfer?.types ?? []) + if ( + types.includes("Files") || + types.includes("text/uri-list") || + types.includes("public.file-url") + ) { + event.preventDefault() + event.stopPropagation() + } + } + + window.addEventListener("dragover", preventFileNavigation, true) + window.addEventListener("drop", preventFileNavigation, true) + loadConfig().then(() => { if (!isSamplesDirValid()) { settingsDialog.open = true @@ -29,7 +44,11 @@ }) loadCollections() startDawSync() - return () => stopDawSync() + return () => { + window.removeEventListener("dragover", preventFileNavigation, true) + window.removeEventListener("drop", preventFileNavigation, true) + stopDawSync() + } }) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index e7f9182..9f5baa9 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -29,6 +29,8 @@ fetchAssets, DEFAULT_SORT, randomSeed, + openPackSamples, + closePackSamples, } from "$lib/shared/store.svelte" import KeySelect from "$lib/components/key-select.svelte" import CollectionsSidebar from "$lib/components/collections-sidebar.svelte" @@ -39,6 +41,7 @@ removeSample, } from "$lib/shared/collections.svelte" import { dawSync } from "$lib/shared/daw-sync.svelte" + import type { PackAsset } from "$lib/splice/types" // Single source of truth for the active view. The header, list, empty state // and row actions all key off this one derived, so they can never disagree @@ -180,6 +183,13 @@ fetchAssets() } + const openPack = (pack: PackAsset) => { + viewStore.mode = "browse" + viewStore.collectionUuid = null + viewStore.tagFilter = [] + openPackSamples(pack) + } + const selectOrPlaySample = (sampleAsset: (typeof shownSamples)[number]) => { if (dawSync.connected) { globalAudio.selectSampleAsset(sampleAsset, false) @@ -281,6 +291,24 @@ {/if}
+ {#if view.kind === "browse" && queryStore.parent_asset_name} +
+ + Pack: {queryStore.parent_asset_name} + + +
+ {/if} + {#if view.kind === "browse"}
{ if (view.kind === "collection") removeSample( @@ -542,5 +571,5 @@
- +
diff --git a/src/routes/sample-list-entry.svelte b/src/routes/sample-list-entry.svelte index d5f8906..d2bfae4 100644 --- a/src/routes/sample-list-entry.svelte +++ b/src/routes/sample-list-entry.svelte @@ -46,6 +46,7 @@ playing, sampleAsset, collectionUuid = null, + onopenpack, onremove, }: { class?: string @@ -54,6 +55,7 @@ sampleAsset: SampleAsset // When set, this row is rendered inside a collection view. collectionUuid?: string | null + onopenpack?: (pack: SampleAsset["parents"]["items"][number]) => void onremove?: () => void } = $props() @@ -122,7 +124,7 @@ }} ondragstart={(event) => handleSampleDrag(event, sampleAsset)} > - +