Tauri v2 migration: asset protocol, desktop CSS polish, absolutePath in library
This commit is contained in:
parent
d2e6e2a7d7
commit
35adfa7feb
|
|
@ -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 {
|
||||||
|
|
|
||||||
31
script.js
31
script.js
|
|
@ -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);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn main() {
|
||||||
|
tauri_build::build()
|
||||||
|
}
|
||||||
|
|
@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -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");
|
||||||
|
}
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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"]
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue