android: a folder of audio files, and a paste of track links

The paste door now reads itself the way the desktop's does: one track link
in the paste and every line is looked up on its own public page
(playlist_import_track_links), which is the way past Spotify's 100-track
public ceiling — the wait screen counts them as they arrive. A fourth door
imports a folder of audio files off this phone, picked with the storage
plugin's own document-tree picker; playlist_import_folder grew a path
argument for it, because on Android it had no dialog to open and always
answered nothing. A YouTube playlist link needed no door at all — the link
one already dispatches it.
This commit is contained in:
KeelrLeek committed 2026-09-13 23:32:00 -05:00
1 parent 24c6857847
commit c737809325
9 files changed
+215 -47

No files matched your search

+14 -3
View File
@@ -13,7 +13,7 @@
import { streamSong, saveSong, streamCatalogAlbum, saveCatalogAlbum } from "./resolve.svelte.js";
import { catalog, yearOf } from "./catalog.svelte.js";
import { pls, bulk, bulkable, runBulk, coverFor, queueable, entryOf, playFrom, shufflePlay, togglePin, renamePlaylist, describePlaylist, duplicatePlaylist, deletePlaylist, removeItems, addEntries, createPlaylist, moveItem, coverFromPhoto, coverClear } from "./playlists.svelte.js";
import { DOORS, start as startImport } from "./importer.svelte.js";
import { DOORS, start as startImport, pickImportFolder, startFolder } from "./importer.svelte.js";
import { slsk, refreshRooms, disconnect, openThread, addBuddy, removeBuddy, leaveRoom } from "./slsk.svelte.js";
import { lib, albumById, albumsBy, tracksOf, loadLibrary, refreshPlaylists, refreshRecents } from "./lib.svelte.js";
import { lyr, nudge, searchCandidates, closeCandidates, chooseCandidate, forgetLyrics, pasteLyrics, setAutoSync, openTapSync, tapProgress, reduceVocals, backToOriginal } from "./lyrics.svelte.js";
@@ -146,6 +146,17 @@
onsubmit: (v) => { push("import", {}); void startImport(door, v); },
});
}
/* the folder door picks FIRST: the review only opens for a folder that
was chosen, and a tree with no path on this phone cannot be walked */
async function folderDoor() {
closeHalf();
try {
const path = await pickImportFolder();
if (!path) return;
push("import", {});
void startFolder(path);
} catch (e) { oops(e); }
}
/* find a local match — the desktop's repair panel, on a sheet: the
library searched by the row's name, a pick relinks the row (an
unknown placeholder adopts the track's identity; the original line
@@ -494,10 +505,10 @@
<div class="sheet-title">Import a playlist</div>
<div class="sheet-rows">
{#each DOORS as [door, icon, t, m] (door)}
{@render row(icon, t, m, () => importPrompt(door))}
{@render row(icon, t, m, () => (door === "folder" ? folderDoor() : importPrompt(door)))}
{/each}
</div>
<div class="sec-note" style="padding-bottom: 14px">A playlist file or a folder of audio files imports on the desktop, where the files are.</div>
<div class="sec-note" style="padding-bottom: 14px">A playlist file — M3U, XSPF, PLS or CSV — imports on the desktop; the phone has no file picker for one yet.</div>
{:else if kind === "plmatch" && shown?.arg?.item}
{@const p = shown.arg.playlist}
{@const item = shown.arg.item}