Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions RELEASE_NOTES_1.15.1.md
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "splicerr",
"version": "1.15.0",
"version": "1.15.1",
"description": "",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
33 changes: 33 additions & 0 deletions src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,38 @@ fn bridge_install_path() -> Result<Option<String>, String> {
}
}

#[tauri::command]
fn bridge_install_paths() -> Result<Vec<String>, 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<String, String> {
#[cfg(target_os = "windows")]
Expand Down Expand Up @@ -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
Expand Down
5 changes: 4 additions & 1 deletion src/lib/components/audio-player.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -34,13 +35,15 @@
class: className,
onnext,
onprev,
onopenpack,
...restProps
}: {
class?: string
onnext: MouseEventHandler<HTMLButtonElement> &
MouseEventHandler<HTMLAnchorElement>
onprev: MouseEventHandler<HTMLButtonElement> &
MouseEventHandler<HTMLAnchorElement>
onopenpack?: (pack: PackAsset) => void
} = $props()

const currentPack = $derived(globalAudio.currentAsset?.parents.items[0])
Expand Down Expand Up @@ -148,7 +151,7 @@
</div>
{#if globalAudio.currentAsset}
<div class="flex gap-4 items-center shrink min-w-64">
<PackPreview side="top" pack={currentPack} />
<PackPreview side="top" pack={currentPack} {onopenpack} />
<div class="text-muted-foreground">
{#if globalAudio.currentAsset.asset_category_slug in assetIcons}
{@const Icon =
Expand Down
80 changes: 78 additions & 2 deletions src/lib/components/pack-preview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,85 @@
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;`
)

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)
}
})
</script>

{#if pack}
<HoverCard.Root>
<HoverCard.Trigger
class="flex-shrink-0"
onclick={() => 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()}
>
<img
src={imgSrc}
Expand All @@ -44,12 +95,37 @@
/>
</HoverCard.Trigger>
<HoverCard.Content {side} class="flex flex-col justify-center gap-2">
<button onclick={() => pack && openUrl(packURL)}>
<button
title="Open pack in Splicerr"
onclick={(event) => {
event.stopPropagation()
openPackInApp()
}}
oncontextmenu={(event) => {
event.preventDefault()
event.stopPropagation()
contextMenu = { x: event.clientX, y: event.clientY }
}}
>
<img src={imgSrc} alt={name} class="w-full rounded" />
</button>
<p>{name}</p>
</HoverCard.Content>
</HoverCard.Root>
{#if contextMenu}
<button
class="fixed z-[100] flex items-center gap-2 rounded-md border border-white/10 bg-popover px-3 py-2 text-sm text-popover-foreground shadow-lg hover:bg-muted"
style={`left: ${contextMenu.x}px; top: ${contextMenu.y}px;`}
onclick={(event) => {
event.stopPropagation()
openPackOnSplice()
}}
oncontextmenu={(event) => event.preventDefault()}
>
<ExternalLink size="16" />
View on Splice
</button>
{/if}
{:else}
<div
class={cn(
Expand Down
26 changes: 15 additions & 11 deletions src/lib/components/settings-dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
let uninstallingBridge = $state(false)
let bridgeInstalled = $state<boolean | null>(null)
let bridgeInstallStatus = $state<string | null>(null)
let bridgeInstallPath = $state<string | null>(null)
let bridgeInstallPaths = $state<string[]>([])

async function refreshBridgeInstallState() {
try {
bridgeInstalled = await invoke<boolean>("bridge_plugins_installed")
bridgeInstallPath = await invoke<string | null>("bridge_install_path")
bridgeInstallPaths = await invoke<string[]>("bridge_install_paths")
} catch (err) {
bridgeInstallStatus = String(err)
}
Expand Down Expand Up @@ -252,15 +252,19 @@
{bridgeInstallStatus}
</p>
{/if}
{#if bridgeInstalled && bridgeInstallPath}
<button
type="button"
class="text-primary text-sm text-left break-all underline-offset-4 hover:underline focus:outline-none"
title="Reveal in file manager"
onclick={() => revealItemInDir(bridgeInstallPath!)}
>
{bridgeInstallPath}
</button>
{#if bridgeInstalled && bridgeInstallPaths.length > 0}
<div class="flex flex-col gap-1">
{#each bridgeInstallPaths as bridgeInstallPath}
<button
type="button"
class="text-primary text-sm text-left break-all underline-offset-4 hover:underline focus:outline-none"
title="Reveal in file manager"
onclick={() => revealItemInDir(bridgeInstallPath)}
>
{bridgeInstallPath}
</button>
{/each}
</div>
{/if}
</div>
<div class="flex flex-col gap-2">
Expand Down
41 changes: 41 additions & 0 deletions src/lib/shared/store.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(),
Expand All @@ -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 })
Expand Down Expand Up @@ -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,
})
Expand Down
21 changes: 20 additions & 1 deletion src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,33 @@
})

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
}
})
loadCollections()
startDawSync()
return () => stopDawSync()
return () => {
window.removeEventListener("dragover", preventFileNavigation, true)
window.removeEventListener("drop", preventFileNavigation, true)
stopDawSync()
}
})
</script>

Expand Down
Loading