Baseline: full tree snapshot after git repository loss

The previous .git directory was found gutted (only info/ remained), so
history is unrecoverable locally. This commit restores version control
with the tree exactly as it stands: the working app, the preview-tracks
launcher on the artist hero, the scrollable-track-previews design bundle
(docs + approved mockups), and the Phase 0 validation artifacts.
This commit is contained in:
KeelrLeek committed 2026-07-22 17:57:00 -05:00
commit a667b4b28e
161 files changed
+53170

No files matched your search

+154
View File
@@ -0,0 +1,154 @@
// Thin wrapper over Tauri IPC so components never import tauri directly.
import { invoke as tauriInvoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { mockInvoke } from "./mockLibrary.js";
// mockInvoke is inert (returns undefined) unless localStorage.mockLibrary === "1".
const invoke = (cmd, args) => mockInvoke(cmd, args) ?? tauriInvoke(cmd, args);
// Artist-page payloads are keyed by a Deezer id all the way through the
// backend. Reject a mismatched response at the IPC boundary so a provider,
// cache, or future command regression cannot populate another artist's page.
// String comparison deliberately accepts route-string ids and numeric Tauri
// ids as the same identity without coercing the u64 argument sent to Rust.
const artistIdKey = (value) => (value == null ? "" : String(value).trim());
const sameArtistId = (left, right) => {
const leftKey = artistIdKey(left);
return !!leftKey && leftKey === artistIdKey(right);
};
const checkedArtistPayload = (command, artistId) =>
invoke(command, { artistId }).then((payload) => {
if (!sameArtistId(payload?.artist?.id, artistId)) {
throw new Error(`${command} returned a mismatched artist identity`);
}
return payload;
});
const checkedArtistIdentity = (artistId, artist) =>
invoke("catalog_artist_identity", { artistId, artist }).then((payload) => {
if (!sameArtistId(payload?.artist_id ?? payload?.artistId, artistId)) {
throw new Error("catalog_artist_identity returned a mismatched artist identity");
}
return payload;
});
const checkedAlbumPayload = (albumId) =>
invoke("catalog_album", { albumId }).then((payload) => {
if (!sameArtistId(payload?.album?.id, albumId)) {
throw new Error("catalog_album returned a mismatched album identity");
}
return payload;
});
export const appStatus = () => invoke("app_status");
export const getCredentials = () => invoke("get_credentials");
export const connectAndLogin = (username, password, remember) =>
invoke("connect_and_login", { username, password, remember });
export const connectStored = () => invoke("connect_stored");
export const disconnect = () => invoke("disconnect");
export const startSearch = (query) => invoke("start_search", { query });
export const excludedSearchPhrases = () => invoke("excluded_search_phrases");
export const stopSearch = (token) => invoke("stop_search", { token });
export const downloadFile = (username, path, size) =>
invoke("download_file", { username, path, size });
export const copyStreamToFolder = (files, folder) =>
invoke("copy_stream_to_folder", { files, folder });
export const saveToLibrary = (files) => invoke("save_to_library", { files });
export const cancelDownload = (id) => invoke("cancel_download", { id });
export const showInFolder = (path) => invoke("show_in_folder", { path });
export const refreshArtistArt = () => invoke("refresh_artist_art");
export const playStream = (username, path, size, duration) =>
invoke("play_stream", { username, path, size, duration });
export const playLocal = (path, duration) => invoke("play_local", { path, duration });
export const preloadLocal = (path, duration) => invoke("preload_local", { path, duration });
export const playerControl = (action, value, rate) =>
invoke("player_control", { action, value: value ?? null, rate: rate ?? null });
export const waveform = (path, buckets) => invoke("waveform", { path, buckets });
export const libraryAlbums = () => invoke("library_albums");
export const albumTracks = (albumId) => invoke("album_tracks", { albumId });
export const recordPlay = (artist, title) => invoke("record_play", { artist, title });
export const addPlaySeconds = (playId, secs) => invoke("add_play_seconds", { playId, secs });
export const artistPlayStats = (artist) => invoke("artist_play_stats", { artist });
// The WebView blocks target="_blank"; external links open via the backend.
export const openExternal = (url) => invoke("open_external", { url });
export const albumArt = (path) => invoke("album_art", { path });
export const refreshAlbumArt = (albumId) => invoke("refresh_album_art", { albumId });
export const refreshAllAlbumArt = () => invoke("refresh_all_album_art");
export const getSettings = () => invoke("get_settings");
export const setSettings = (patch) => invoke("set_settings", patch);
export const forgetCredentials = () => invoke("forget_credentials");
export const pickFolder = () => invoke("pick_folder");
export const listPlaylists = () => invoke("list_playlists");
export const createPlaylist = (name) => invoke("create_playlist", { name });
export const deletePlaylist = (id) => invoke("delete_playlist", { id });
export const playlistTracks = (id) => invoke("playlist_tracks", { id });
export const addToPlaylist = (playlistId, tracks) =>
invoke("add_to_playlist", { playlistId, tracks });
export const removeFromPlaylist = (playlistId, position) =>
invoke("remove_from_playlist", { playlistId, position });
export const catalogSearch = (query) => invoke("catalog_search", { query });
export const catalogArtist = (artistId) => checkedArtistPayload("catalog_artist", artistId);
export const catalogArtistArt = (artistId) =>
checkedArtistPayload("catalog_artist_art", artistId);
export const catalogArtistLogos = (artistId) => invoke("catalog_artist_logos", { artistId });
// Deferred MusicBrainz pass (socials + MB-only releases). Rate-limited at
// 1 req/s upstream, so it is fetched after the page renders, never before.
export const catalogArtistSocials = (artistId) =>
invoke("catalog_artist_socials", { artistId });
export const catalogArtistBio = (artistId, artist) =>
invoke("catalog_artist_bio", { artistId: artistId ?? null, artist });
export const catalogArtistIdentity = (artistId, artist) =>
checkedArtistIdentity(artistId, artist);
export const catalogCachedCoverLogo = (artistId) =>
invoke("catalog_cached_cover_logo", { artistId });
export const catalogCoverLogo = (artistId, artist, covers) =>
invoke("catalog_cover_logo", { artistId, artist, covers });
export const catalogArtistHeroSeed = (artistId) =>
invoke("catalog_artist_hero_seed", { artistId });
export const catalogArtistOverview = (artistId) =>
checkedArtistPayload("catalog_artist_overview", artistId);
export const pickArtistHero = (artistId) => invoke("pick_artist_hero", { artistId });
export const clearArtistHero = (artistId) => invoke("clear_artist_hero", { artistId });
export const catalogRelated = (artistId) => invoke("catalog_related", { artistId });
export const catalogAlbum = (albumId) => checkedAlbumPayload(albumId);
export const catalogAlbumInfo = (artistId, artist, title) =>
invoke("catalog_album_info", { artistId: artistId ?? null, artist, title });
export const catalogArt = (url) => invoke("catalog_art", { url });
export const catalogCover = (artistId, artist, title, cover) =>
invoke("catalog_cover", { artistId: artistId ?? null, artist, title, cover });
export const invalidateCatalogCover = (artistId, artist, title, cover) =>
invoke("invalidate_catalog_cover", { artistId: artistId ?? null, artist, title, cover });
export const catalogHeroPreview = (url) => invoke("catalog_hero_preview", { url });
export const catalogHeroGpuSource = (url, plan = null) =>
invoke("catalog_hero_gpu_source", { url, plan });
export const catalogCachedHeroArt = (url) => invoke("catalog_cached_hero_art", { url });
export const catalogHeroArt = (url, plan = null) =>
invoke("catalog_hero_art", { url, plan });
export const preloadStream = (username, path, size) =>
invoke("preload_stream", { username, path, size });
export const preloadCachedStream = (username, path, size, duration) =>
invoke("preload_cached_stream", { username, path, size, duration });
export const streamWaveform = (username, path, size, buckets) =>
invoke("stream_waveform", { username, path, size, buckets });
// Window chrome (the app draws its own titlebar; decorations are off).
import { getCurrentWindow } from "@tauri-apps/api/window";
export const win = {
minimize: () => getCurrentWindow().minimize(),
toggleMaximize: () => getCurrentWindow().toggleMaximize(),
close: () => getCurrentWindow().close(),
isMinimized: () => getCurrentWindow().isMinimized(),
isFocused: () => getCurrentWindow().isFocused(),
isMaximized: () => getCurrentWindow().isMaximized(),
// returns Promise<unlisten>
onResized: (handler) => getCurrentWindow().onResized(handler),
onFocusChanged: (handler) => getCurrentWindow().onFocusChanged(handler),
};
// Subscribe to a backend event; returns an unlisten function.
// No-ops outside Tauri (e.g. plain-browser preview).
export function onEvent(name, handler) {
const un = listen(name, (e) => handler(e.payload)).catch(() => () => {});
return () => un.then((f) => f());
}