Tauri v2 migration: asset protocol, desktop CSS polish, absolutePath in library

This commit is contained in:
ComputerTech 2026-03-28 11:49:00 +00:00
parent d2e6e2a7d7
commit 35adfa7feb
10 changed files with 127 additions and 8 deletions

View File

@ -19,10 +19,18 @@
* { * {
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
box-sizing: border-box; box-sizing: border-box;
user-select: none;
-webkit-user-select: none;
} }
html { html {
scroll-behavior: smooth; scroll-behavior: smooth;
overflow: hidden;
scrollbar-width: none;
}
html::-webkit-scrollbar {
display: none;
} }
body { body {

View File

@ -1274,6 +1274,22 @@ function updateCrossfader(val) {
} }
// Library Functions // Library Functions
// ---------------------------------------------------------------------------
// Tauri v2 asset-protocol helper
// When running inside Tauri (window.__TAURI__ is injected via withGlobalTauri)
// and the server has provided an absolutePath for the track, we convert it to
// an asset:// URL so the WebView reads the file directly from disk — no Flask
// round-trip, works with any folder under $HOME.
// Falls back to the ordinary server URL when not in Tauri or no absolutePath.
// ---------------------------------------------------------------------------
function tauriResolve(track) {
const cvt = window.__TAURI__?.core?.convertFileSrc;
if (cvt && track.absolutePath) {
return cvt(track.absolutePath);
}
return track.file;
}
async function fetchLibrary() { async function fetchLibrary() {
try { try {
const res = await fetch('library.json?t=' + new Date().getTime()); const res = await fetch('library.json?t=' + new Date().getTime());
@ -1303,7 +1319,7 @@ function renderLibrary(songs) {
// Drag data // Drag data
item.ondragstart = (e) => { item.ondragstart = (e) => {
e.dataTransfer.setData('trackFile', t.file); e.dataTransfer.setData('trackFile', tauriResolve(t));
e.dataTransfer.setData('trackTitle', t.title); e.dataTransfer.setData('trackTitle', t.title);
e.dataTransfer.setData('source', 'library'); e.dataTransfer.setData('source', 'library');
item.classList.add('dragging'); item.classList.add('dragging');
@ -1324,25 +1340,25 @@ function renderLibrary(songs) {
const btnA = document.createElement('button'); const btnA = document.createElement('button');
btnA.className = 'load-btn btn-a'; btnA.className = 'load-btn btn-a';
btnA.textContent = 'LOAD A'; btnA.textContent = 'LOAD A';
btnA.addEventListener('click', () => loadFromServer('A', t.file, t.title)); btnA.addEventListener('click', () => loadFromServer('A', tauriResolve(t), t.title));
const btnB = document.createElement('button'); const btnB = document.createElement('button');
btnB.className = 'load-btn btn-b'; btnB.className = 'load-btn btn-b';
btnB.textContent = 'LOAD B'; btnB.textContent = 'LOAD B';
btnB.addEventListener('click', () => loadFromServer('B', t.file, t.title)); btnB.addEventListener('click', () => loadFromServer('B', tauriResolve(t), t.title));
// QUEUE buttons // QUEUE buttons
const queueA = document.createElement('button'); const queueA = document.createElement('button');
queueA.className = 'load-btn queue-btn-a'; queueA.className = 'load-btn queue-btn-a';
queueA.textContent = 'Q-A'; queueA.textContent = 'Q-A';
queueA.title = 'Add to Queue A'; queueA.title = 'Add to Queue A';
queueA.addEventListener('click', () => addToQueue('A', t.file, t.title)); queueA.addEventListener('click', () => addToQueue('A', tauriResolve(t), t.title));
const queueB = document.createElement('button'); const queueB = document.createElement('button');
queueB.className = 'load-btn queue-btn-b'; queueB.className = 'load-btn queue-btn-b';
queueB.textContent = 'Q-B'; queueB.textContent = 'Q-B';
queueB.title = 'Add to Queue B'; queueB.title = 'Add to Queue B';
queueB.addEventListener('click', () => addToQueue('B', t.file, t.title)); queueB.addEventListener('click', () => addToQueue('B', tauriResolve(t), t.title));
loadActions.appendChild(btnA); loadActions.appendChild(btnA);
loadActions.appendChild(queueA); loadActions.appendChild(queueA);
@ -1351,8 +1367,9 @@ function renderLibrary(songs) {
item.appendChild(trackName); item.appendChild(trackName);
item.appendChild(loadActions); item.appendChild(loadActions);
// Add data attribute for highlighting // Add data attribute for highlighting — store the resolved URL so
item.dataset.file = t.file; // updateLibraryHighlighting() matches decks.X.currentFile correctly.
item.dataset.file = tauriResolve(t);
list.appendChild(item); list.appendChild(item);
}); });

View File

@ -306,7 +306,10 @@ def setup_shared_routes(app, index_file='index.html'):
rel_path = os.path.relpath(os.path.join(root, filename), MUSIC_FOLDER) rel_path = os.path.relpath(os.path.join(root, filename), MUSIC_FOLDER)
library.append({ library.append({
"title": os.path.splitext(filename)[0], "title": os.path.splitext(filename)[0],
"file": f"music_proxy/{rel_path}" "file": f"music_proxy/{rel_path}",
# Absolute path exposed for Tauri's asset protocol (convertFileSrc).
# The web fallback keeps using the music_proxy route above.
"absolutePath": os.path.abspath(os.path.join(root, filename))
}) })
break # Top-level only break # Top-level only
return jsonify(library) return jsonify(library)

21
src-tauri/Cargo.toml Normal file
View File

@ -0,0 +1,21 @@
[package]
name = "techdj"
version = "0.1.0"
edition = "2021"
[build-dependencies]
tauri-build = { version = "2", features = [] }
[dependencies]
tauri = { version = "2", features = [] }
tauri-plugin-fs = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# Release optimisations — keep the binary small on the 4 GB machine
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
opt-level = "s"
strip = true

3
src-tauri/build.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View File

@ -0,0 +1,11 @@
{
"$schema": "https://schema.tauri.app/config/2/acl/capability.json",
"identifier": "default",
"description": "TechDJ default permissions — read-only access to home directory for local audio",
"windows": ["main"],
"permissions": [
"core:default",
"fs:read-all",
"fs:scope-home-recursive"
]
}

10
src-tauri/src/lib.rs Normal file
View File

@ -0,0 +1,10 @@
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
// Grant the WebView direct read access to local audio files so
// convertFileSrc() can serve tracks from $HOME without going
// through the Flask proxy.
.plugin(tauri_plugin_fs::init())
.run(tauri::generate_context!())
.expect("error while running TechDJ");
}

6
src-tauri/src/main.rs Normal file
View File

@ -0,0 +1,6 @@
// Hides the console window on Windows release builds; harmless on Linux.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
techdj_lib::run()
}

38
src-tauri/tauri.conf.json Normal file
View File

@ -0,0 +1,38 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "TechDJ",
"version": "0.1.0",
"identifier": "dev.computertech.techdj",
"build": {
"frontendDist": "../"
},
"app": {
"withGlobalTauri": true,
"windows": [
{
"title": "TechDJ",
"width": 1280,
"height": 800,
"minWidth": 1024,
"minHeight": 600,
"decorations": true,
"fullscreen": false,
"resizable": true
}
],
"security": {
"assetProtocol": {
"enable": true,
"scope": [
"$HOME/**",
"$HOME/Music/**"
]
}
}
},
"bundle": {
"active": true,
"targets": ["deb"],
"icon": ["../icon.png"]
}
}

View File

@ -20,6 +20,8 @@
/* Smooth scrolling for all scrollable elements */ /* Smooth scrolling for all scrollable elements */
* { * {
-webkit-overflow-scrolling: touch; -webkit-overflow-scrolling: touch;
user-select: none;
-webkit-user-select: none;
} }
html { html {