Compare commits

..
4 Commits
47 changed files with 240 additions and 63 deletions
+2 -2
View File
@@ -20,10 +20,10 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/marked.min.js"></script>
<script type="text/javascript" src="./js/qrcode-svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
<script src="./js/vendor/purify.min.js"></script>
<style>
#divBody {
+2 -2
View File
@@ -23,11 +23,11 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/marked.min.js"></script>
<script type="text/javascript" src="./js/qrcode-generator.min.js"></script>
<script type="text/javascript" src="./js/qrcode-svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
<script src="./js/vendor/purify.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -10,7 +10,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<!-- Initialize theme BEFORE any components load -->
<script>
+1 -1
View File
@@ -19,7 +19,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -47,7 +47,7 @@
});
</script>
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
flex-direction: column !important;
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -20,7 +20,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -22,7 +22,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+2 -2
View File
@@ -20,10 +20,10 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/marked.min.js"></script>
<script type="text/javascript" src="./js/qrcode-svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
<script src="./js/vendor/purify.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
File diff suppressed because one or more lines are too long
+3
View File
File diff suppressed because one or more lines are too long
+2
View File
File diff suppressed because one or more lines are too long
+3
View File
File diff suppressed because one or more lines are too long
+3
View File
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -1,5 +1,5 @@
{
"VERSION": "v0.1.0",
"VERSION_NUMBER": "0.1.0",
"BUILD_DATE": "2026-04-17T20:56:45.995Z"
"VERSION": "v0.7.4",
"VERSION_NUMBER": "0.7.4",
"BUILD_DATE": "2026-04-19T18:00:32.861Z"
}
+1 -1
View File
@@ -18,7 +18,7 @@
})();
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+2 -2
View File
@@ -26,10 +26,10 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/marked.min.js"></script>
<script type="text/javascript" src="./js/qrcode-generator.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
<script src="./js/vendor/purify.min.js"></script>
<style>
#divBody {
+168 -10
View File
@@ -25,8 +25,8 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/vendor/dash.all.min.js"></script>
<style>
#divBody {
@@ -932,6 +932,15 @@
min-width: 52px;
}
#musicSaveToggleBtn {
min-width: 52px;
}
#musicSaveToggleBtn[data-enabled='true'] {
border-color: var(--accent-color);
color: var(--accent-color);
}
#musicProgressWrap {
display: grid;
grid-template-columns: auto 1fr auto;
@@ -1217,6 +1226,7 @@
<div id="musicPlayerControls">
<button id="musicPlaybackModeBtn" class="btn musicControlBtn" type="button" title="Playback mode"></button>
<button id="musicSaveToggleBtn" class="btn musicControlBtn" type="button" title="Auto-save now playing track to Blossom" aria-pressed="false">💾</button>
<button id="musicPrevBtn" class="btn musicControlBtn" type="button"></button>
<button id="musicPlayPauseBtn" class="btn musicControlBtn" type="button"></button>
<button id="musicNextBtn" class="btn musicControlBtn" type="button">▶▶</button>
@@ -1367,6 +1377,7 @@
import { HamburgerMorphing } from "./hamburger_morphing/hamburger.mjs";
import { initFooterRelayStatus, updateFooterRelayStatus, initSidenavRelaySection, updateSidenavRelaySection, setRelayActivityState } from './js/relay-ui.mjs';
import { initBlossomSection, updateBlossomSection } from './js/blossom-ui.mjs';
import { uploadToServer, getDefaultBlossomServer } from './js/blossom-api.mjs';
import { initAiSectionWithLocalConfig } from './js/ai-ui.mjs';
import { GreyscaleAPI } from './js/greyscale-api.mjs';
@@ -1475,6 +1486,7 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
queueClearBtn: document.getElementById('musicQueueClearBtn'),
queueList: document.getElementById('musicQueueList'),
playbackModeBtn: document.getElementById('musicPlaybackModeBtn'),
saveToggleBtn: document.getElementById('musicSaveToggleBtn'),
shareModal: document.getElementById('musicShareModal'),
shareTarget: document.getElementById('musicShareTarget'),
shareRendered: document.getElementById('musicShareRendered'),
@@ -1531,6 +1543,7 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
};
let isHandlingRoute = false;
let playbackMode = 'normal';
let autoSaveToBlossom = false;
let currentPlayingTrackId = '';
let pendingShareUrl = '';
let pendingShareArtUrl = '';
@@ -1617,6 +1630,21 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
return message.includes('authentication required');
}
async function tryGetPubkeyWithoutPrompt({ attempts = 8, delayMs = 350 } = {}) {
for (let i = 0; i < attempts; i += 1) {
try {
const pubkey = await getPubkey();
if (pubkey) return pubkey;
} catch {
// Signer can attach slightly after initial script execution.
}
if (i < attempts - 1) {
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
return '';
}
function isReadOnlyTargetMode() {
return Boolean(targetPubkey && (!currentPubkey || targetPubkey !== currentPubkey));
}
@@ -1695,13 +1723,8 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
throw error;
}
try {
currentPubkey = await getPubkey();
isAuthenticated = Boolean(currentPubkey);
} catch {
currentPubkey = null;
isAuthenticated = false;
}
currentPubkey = await tryGetPubkeyWithoutPrompt();
isAuthenticated = Boolean(currentPubkey);
}
async function initializeAuthenticatedPageFeatures() {
@@ -1827,6 +1850,14 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
return `music-queue:${currentPubkey || 'anon'}`;
}
function getAutoSaveBlossomStorageKey() {
return `music-auto-save-blossom:${currentPubkey || 'anon'}`;
}
function getSavedTrackBlossomMapStorageKey() {
return `music-saved-track-blossom-map:${currentPubkey || 'anon'}`;
}
function normalizeQueueTrack(track) {
if (!track || typeof track !== 'object') return null;
return {
@@ -1954,6 +1985,64 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
}
}
const savedTrackBlossomUrlById = new Map();
const pendingTrackBlossomSaves = new Set();
function updateSaveToggleButton() {
if (!musicEls.saveToggleBtn) return;
musicEls.saveToggleBtn.dataset.enabled = autoSaveToBlossom ? 'true' : 'false';
musicEls.saveToggleBtn.setAttribute('aria-pressed', autoSaveToBlossom ? 'true' : 'false');
musicEls.saveToggleBtn.textContent = autoSaveToBlossom ? '💾✓' : '💾';
musicEls.saveToggleBtn.title = autoSaveToBlossom
? 'Auto-save now playing track to Blossom: ON'
: 'Auto-save now playing track to Blossom: OFF';
}
function loadAutoSaveBlossomSetting() {
try {
autoSaveToBlossom = localStorage.getItem(getAutoSaveBlossomStorageKey()) === 'true';
} catch {
autoSaveToBlossom = false;
}
updateSaveToggleButton();
}
function persistAutoSaveBlossomSetting() {
try {
localStorage.setItem(getAutoSaveBlossomStorageKey(), autoSaveToBlossom ? 'true' : 'false');
} catch {
// Ignore storage write failures.
}
}
function loadSavedTrackBlossomMap() {
savedTrackBlossomUrlById.clear();
try {
const raw = localStorage.getItem(getSavedTrackBlossomMapStorageKey());
if (!raw) return;
const parsed = JSON.parse(raw);
if (!parsed || typeof parsed !== 'object') return;
Object.entries(parsed).forEach(([trackId, url]) => {
if (!trackId || typeof url !== 'string' || !url.trim()) return;
savedTrackBlossomUrlById.set(String(trackId), url.trim());
});
} catch (error) {
console.warn('[music] Could not load saved Blossom track map:', error);
}
}
function persistSavedTrackBlossomMap() {
try {
const payload = {};
savedTrackBlossomUrlById.forEach((url, trackId) => {
payload[trackId] = url;
});
localStorage.setItem(getSavedTrackBlossomMapStorageKey(), JSON.stringify(payload));
} catch {
// Ignore storage write failures.
}
}
const mountedMusicMenus = {
myPlaylists: [],
friendPlaylists: [],
@@ -3413,6 +3502,7 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
updatePlayingResultHighlight();
saveQueueLocal();
setMusicStatus(`Playing queue: ${track.title}`, 'ok');
void maybeAutoSaveTrackToBlossom(track);
} catch (error) {
console.error(error);
setMusicStatus(`Queue playback failed: ${error.message || 'Unknown error'}`, 'error');
@@ -4327,7 +4417,7 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
}
async function loadClientZipModule() {
return import('https://cdn.jsdelivr.net/npm/client-zip@2.4.5/+esm');
return import('./js/vendor/client-zip.esm.js');
}
async function fetchDownloadBlobForTrack(track) {
@@ -4368,6 +4458,65 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
}
}
async function saveTrackToBlossom(track, { suppressStatus = true } = {}) {
const trackId = String(track?.id || '').trim();
if (!trackId) return '';
if (savedTrackBlossomUrlById.has(trackId)) {
return savedTrackBlossomUrlById.get(trackId) || '';
}
if (pendingTrackBlossomSaves.has(trackId)) return '';
const targetServer = getDefaultBlossomServer();
if (!targetServer) {
if (!suppressStatus) setMusicStatus('No Blossom server configured.', 'error');
return '';
}
pendingTrackBlossomSaves.add(trackId);
try {
if (!suppressStatus) {
setMusicStatus(`Saving to Blossom: ${track.title || 'Track'}...`, 'neutral');
}
const { blob, ext } = await fetchDownloadBlobForTrack(track);
const title = sanitizeFilenamePart(track.title || 'Unknown title') || 'Unknown title';
const artist = sanitizeFilenamePart(track.artist || 'Unknown artist') || 'Unknown artist';
const fileName = `${artist} - ${title}.${ext}`;
const file = new File([blob], fileName, {
type: blob.type || 'application/octet-stream',
});
const result = await uploadToServer(file, targetServer);
const sha256 = String(result?.sha256 || '').trim();
if (!sha256) throw new Error('Upload returned no SHA-256 hash.');
const suffix = ext ? `.${ext.replace(/^\./, '')}` : '';
const blossomUrl = `${String(result?.serverUrl || targetServer).replace(/\/$/, '')}/${sha256}${suffix}`;
savedTrackBlossomUrlById.set(trackId, blossomUrl);
persistSavedTrackBlossomMap();
if (!suppressStatus) {
setMusicStatus(`Saved to Blossom: ${track.title || 'Track'}`, 'ok');
}
return blossomUrl;
} catch (error) {
console.error('[music] saveTrackToBlossom failed:', error);
if (!suppressStatus) {
setMusicStatus(`Save to Blossom failed: ${error.message || 'Unknown error'}`, 'error');
}
return '';
} finally {
pendingTrackBlossomSaves.delete(trackId);
}
}
async function maybeAutoSaveTrackToBlossom(track) {
if (!autoSaveToBlossom) return;
await saveTrackToBlossom(track, { suppressStatus: true });
}
async function downloadMusicByIndex(index) {
if (!Number.isInteger(index) || index < 0 || index >= musicTracks.length) return;
const track = musicTracks[index];
@@ -4956,9 +5105,16 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
updatePlayingResultHighlight();
});
musicEls.playbackModeBtn?.addEventListener('click', cyclePlaybackMode);
musicEls.saveToggleBtn?.addEventListener('click', () => {
autoSaveToBlossom = !autoSaveToBlossom;
persistAutoSaveBlossomSetting();
updateSaveToggleButton();
setMusicStatus(`Auto-save to Blossom ${autoSaveToBlossom ? 'enabled' : 'disabled'}.`, 'ok');
});
setMusicPlayButtonState();
updateMusicPlayerMeta(null);
updatePlaybackModeButton();
updateSaveToggleButton();
musicEls.queueClearBtn?.addEventListener('click', clearQueue);
@@ -5059,6 +5215,8 @@ import { GreyscaleAPI } from './js/greyscale-api.mjs';
myPlaylists.clear();
}
loadQueueLocal();
loadAutoSaveBlossomSetting();
loadSavedTrackBlossomMap();
updateViewerControls();
renderMyPlaylists();
renderFriendPlaylists();
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -22,7 +22,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divQRContainer {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
</head>
<body>
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
</head>
<body>
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
</head>
<body>
+2 -2
View File
@@ -22,11 +22,11 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="../js/vendor/svg.min.js"></script>
<script src="./js/marked.min.js"></script>
<script type="text/javascript" src="./js/qrcode-generator.min.js"></script>
<script type="text/javascript" src="./js/qrcode-svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.2.6/dist/purify.min.js"></script>
<script src="../js/vendor/purify.min.js"></script>
<style>
#divBody {
+2 -2
View File
@@ -173,8 +173,8 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="../js/vendor/svg.min.js"></script>
<script src="../js/vendor/hls.min.js"></script>
</head>
<body>
+2 -2
View File
@@ -172,8 +172,8 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="../js/vendor/svg.min.js"></script>
<script src="../js/vendor/hls.min.js"></script>
</head>
<body>
+1 -1
View File
@@ -19,7 +19,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -22,7 +22,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -21,7 +21,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -47,7 +47,7 @@
});
</script>
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
/* ================================================================
+1 -1
View File
@@ -20,7 +20,7 @@
})();
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -19,7 +19,7 @@
</script>
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
#divBody {
+1 -1
View File
@@ -24,7 +24,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<!-- Strudel REPL Library (locally built from source) -->
<script type="module" src="./strudel-repl/index.js"></script>
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
</head>
<body>
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style>
/* ================================================================
+1 -1
View File
@@ -23,7 +23,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
<style media="screen">
#divBody {
+1 -1
View File
@@ -175,7 +175,7 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="./js/vendor/svg.min.js"></script>
</head>
<body>
+4 -4
View File
@@ -26,9 +26,9 @@
<link rel="shortcut icon" type="image/x-icon" href="./favicon/favicon-dots2.ico" />
<!-- SVG.js library (required by HamburgerMorphing) -->
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.0/dist/svg.min.js"></script>
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script src="./js/vendor/svg.min.js"></script>
<script src="./js/vendor/dash.all.min.js"></script>
<script src="./js/vendor/hls.min.js"></script>
<style>
#divBody {
@@ -5609,7 +5609,7 @@
}
async function loadClientZipModule() {
return import('https://cdn.jsdelivr.net/npm/client-zip@2.4.5/+esm');
return import('./js/vendor/client-zip.esm.js');
}
async function fetchDownloadBlobForTrack(track) {