diff --git a/Album-Title.html b/Album-Title.html
new file mode 100644
index 0000000..5830e47
--- /dev/null
+++ b/Album-Title.html
@@ -0,0 +1,101 @@
+
+
+
+ Use normal HTML formatting, inline.
",
+ "loopModeDefault": "none"
+}
diff --git a/index.html b/index.html
deleted file mode 100644
index fc7e41b..0000000
--- a/index.html
+++ /dev/null
@@ -1,1766 +0,0 @@
-
-
-
-
+
+
+
+
${i + 1}.
+
${entry.title}
+
+
+ ${
+ entry.info
+ ? `
`
+ : ""
+ }
+
+
+ ${
+ entry.info
+ ? `
+
+ `
+ : ""
+ }
+
`
+ );
+ let trackEl = tracksEl.lastChild;
+ entry.trackEl = trackEl;
+ let buttonEl = trackEl.querySelector("button");
+ if (entry.feature) {
+ featureIndex = i;
+ }
+ if (entry.locked && featureIndex === i) {
+ featureIndex++;
+ }
+ if (entry.info) {
+ let infoContainerEl = trackEl.querySelector(".infoContainer");
+ trackEl.querySelector(".toggleInfo").addEventListener("click", (e) => {
+ infoContainerEl.style.height =
+ trackEl.querySelector(".info").clientHeight + "px";
+ entry.infoToggled = infoContainerEl.classList.toggle("active");
+ if (entry.info && entry.infoToggled) {
+ infoContainerEl.removeAttribute("inert");
+ } else {
+ infoContainerEl.setAttribute("inert", "");
+ }
+ if (config.theme.infoStyle === "overlaid-toggle") {
+ if (entry.info && entry.infoToggled) {
+ mediaInfoEl.innerHTML = entry.info;
+ mediaInfoContainer.classList.add("active");
+ } else {
+ mediaInfoEl.innerHTML = "";
+ mediaInfoContainer.classList.remove("active");
+ }
+ }
+ });
+ }
+ if (!entry.previewFade && entry.previewFade !== false) {
+ entry.previewFade = true; //default true
+ }
+ if (typeof entry.loopCount === "number" && entry.loopCount > 0) {
+ entry.remainingLoops = entry.loopCount;
+ trackEl.classList.add("looped");
+ buttonEl.setAttribute("title", "loop count");
+ updateLoops(entry);
+ }
+ if (!entry.locked) {
+ buttonEl.onclick = () => {
+ loadedFirst = true;
+ autoPlay = true;
+ playEntry(entry);
+ };
+ let loaderEl;
+ if (entry.type === "video") {
+ loaderEl = document.createElement("video");
+ } else {
+ loaderEl = document.createElement("audio");
+ }
+ if (entry.previewStart || entry.previewEnd) {
+ entry.preview = true;
+ }
+ let needsPreviewEnd = false;
+ if (!entry.previewEnd) {
+ needsPreviewEnd = true;
+ }
+ entry.originalDuration =
+ (entry.originalDuration && fromHMS(entry.originalDuration)) || 1;
+ entry.previewStart =
+ (entry.previewStart && fromHMS(entry.previewStart)) || 0;
+ entry.previewEnd =
+ (entry.previewEnd && fromHMS(entry.previewEnd)) ||
+ entry.originalDuration;
+ entry.previewDuration = entry.previewEnd - entry.previewStart;
+ loaderEl.addEventListener("loadedmetadata", (e) => {
+ entry.duration = e.target.duration;
+ entry.needsDuration = false;
+ entry.previewStart = entry.previewStart || 0;
+ if (needsPreviewEnd) {
+ entry.previewEnd = entry.duration;
+ }
+ entry.originalDuration = Math.max(
+ entry.originalDuration,
+ entry.duration,
+ entry.previewEnd
+ );
+ entry.previewDuration = entry.previewEnd - entry.previewStart;
+
+ //make assumptions about the audio start points
+ if (entry.duration < entry.previewDuration) {
+ //smaller than given preview duration
+ //left align to preview
+ entry.audioStart = entry.previewStart;
+ } else if (
+ entry.duration <
+ entry.originalDuration - entry.previewStart
+ ) {
+ //else, smaller than region between preview start and original end
+ //left align to preview
+ entry.audioStart = entry.previewStart;
+ } else if (entry.duration < entry.originalDuration) {
+ //else, smaller than original duration
+ //right align to original
+ entry.audioStart = entry.originalDuration - entry.duration;
+ } else {
+ //larger than original duration
+ //left align to original
+ entry.audioStart = 0;
+ }
+ entry.audioEnd = entry.audioStart + entry.duration;
+
+ let durationText = toHMS(entry.duration);
+ if (entry.preview) {
+ durationText += " (preview)";
+ }
+ trackEl.querySelector(".duration").textContent = durationText;
+ if (entry === currentEntry) {
+ updateTrackPreview();
+ // updateScrubPosition(entry.previewStart / entry.originalDuration);
+ updateScrubPosition(0);
+ updatePreviewVolume(0);
+ }
+ });
+ loaderEl.addEventListener("error", (e) => {
+ entry.error = true;
+ entry.errorMessage = e.target.error;
+ removeLoading(entry, true);
+ buttonEl.classList.add("error", "icon-warning");
+ buttonEl.setAttribute("title", "error loading file");
+ });
+ loaderEl.addEventListener("canplay", (e) => {
+ removeLoading(entry, true);
+
+ if (entry.feature && entry.autoplay) {
+ playerEl.play();
+ }
+ });
+ loaderEl.volume = 0;
+ loaderEl.src = entry.file;
+ entry.started = false;
+ entry.loading = true;
+ entry.loaderEl = loaderEl;
+ }
+ });
+ loadEntry(media[mod(featureIndex, media.length)]);
+}
+
+function loadCover(cover) {
+ if (cover) {
+ let src = cover;
+ if (mediaImageEl.src == src) {
+ return; //already loaded
+ }
+ if (!/:\/\//.test(src)) {
+ //if not a url
+ src = mediaDir + src;
+ }
+ mediaImageEl.src = src;
+ mediaImageEl.classList.add("active");
+ mediaImageEl.style.visibility = "visible";
+ } else {
+ mediaImageEl.style.visibility = "hidden";
+ }
+}
+
+function setCover(cover, size) {
+ if (cover) {
+ config.cover = cover;
+ size && (config.coverSize = size);
+ loadCover(cover);
+ }
+}
+
+playerEl.addEventListener("canplay", (e) => {
+ removeLoading(currentEntry);
+ if (currentEntry.needsDuration) {
+ currentEntry.duration = playerEl.duration;
+ currentEntry.needsDuration = false;
+ }
+ if (autoPlay && !currentEntry.started) {
+ currentEntry.started = true;
+ if (!currentEntry.needsDuration) {
+ playerEl.currentTime =
+ currentEntry.previewStart - currentEntry.audioStart;
+ }
+ playerEl.play();
+ }
+ if (!loadedFirst) {
+ autoPlay = true;
+ }
+});
+playerEl.addEventListener("waiting", (e) => {
+ setLoading(currentEntry, 0);
+});
+playerEl.addEventListener("play", (e) => {
+ if (
+ currentEntry.preview &&
+ playerEl.currentTime < currentEntry.previewStart - currentEntry.audioStart
+ ) {
+ playerEl.currentTime = currentEntry.previewStart - currentEntry.audioStart;
+ }
+ bigButtonEl.classList.add("pause");
+ currentEntry.started = true;
+ currentEntry.trackEl.querySelector("button").classList.add("pause");
+ if (currentEntry.type === "video") {
+ mediaVideoEl.play();
+ }
+});
+playerEl.addEventListener("pause", (e) => {
+ bigButtonEl.classList.remove("pause");
+ currentEntry.trackEl.querySelector("button").classList.remove("pause");
+ if (currentEntry.type === "video") {
+ mediaVideoEl.pause();
+ }
+});
+playerEl.addEventListener("volumechange", (e) => {
+ if (config.theme.nativePlayer) {
+ volume = e.target.volume;
+ localStorageSet("volume", volume);
+ }
+ if (currentEntry.type === "video") {
+ if (config.theme.nativePlayer) {
+ mediaVideoEl.volume = e.target.volume;
+ } else {
+ mediaVideoEl.volume = 0;
+ }
+ }
+});
+mediaVideoEl.addEventListener("volumechange", (e) => {
+ if (currentEntry.type === "video" && config.theme.nativePlayer) {
+ volume = e.target.volume;
+ localStorageSet("volume", volume);
+ }
+});
+playerEl.addEventListener("timeupdate", (e) => {
+ let buffer = 0.18;
+ if (!scrubberDragged) {
+ if (currentEntry.duration && !currentEntry.needsDuration) {
+ if (currentEntry.started) {
+ let time = e.target.currentTime;
+ if (time > currentEntry.previewEnd - currentEntry.audioStart - buffer) {
+ nextTrack(false);
+ } else {
+ let t = time / currentEntry.duration;
+ updatePreviewVolume(t);
+ updateScrubPosition(t);
+ }
+ } else {
+ }
+ } else {
+ let time = e.target.currentTime;
+ if (time > e.target.duration - buffer) {
+ nextTrack(false);
+ }
+ }
+ }
+});
+playerEl.addEventListener("ended", (e) => {
+ if (!scrubberDragged) {
+ nextTrack(false);
+ }
+});
+mediaVideoEl.addEventListener("ended", (e) => {
+ if (currentEntry.type === "video" && config.theme.nativePlayer) {
+ nextTrack(false);
+ }
+});
+
+bigButtonEl.addEventListener("click", (e) => {
+ playEntry(currentEntry);
+});
+
+volumeIconEl.addEventListener("click", (e) => {
+ toggleMute();
+});
+
+let volumeDragged = false;
+volumeTrackContainerEl.addEventListener("mousedown", (e) => {
+ volumeDragged = true;
+ scrubVolume(e.clientX);
+});
+
+let volumeHovered = false;
+volumeContainerEl.addEventListener("mouseenter", (e) => {
+ if (!scrubberDragged) {
+ volumeHovered = true;
+ volumeContainerEl.classList.add("hover");
+ }
+});
+volumeContainerEl.addEventListener("mouseleave", (e) => {
+ volumeHovered = false;
+ if (!volumeDragged) {
+ volumeContainerEl.classList.remove("hover");
+ }
+});
+
+function toggleMute() {
+ muted = !muted;
+ setVolume(volume, muted);
+}
+
+function scrubVolume(x) {
+ if (volumeDragged) {
+ let trackX = volumeTrackEl.getBoundingClientRect().x;
+ x -= trackX;
+ let scrubberWidth = 6;
+ let trackWidth = volumeTrackEl.clientWidth;
+ let t =
+ 1 -
+ Math.max(
+ 0,
+ Math.min(1, (x - scrubberWidth / 2) / (trackWidth - scrubberWidth))
+ );
+ setVolume(t);
+ }
+}
+
+function endVolumeScrub() {
+ if (!volumeHovered) {
+ volumeContainerEl.classList.remove("hover");
+ }
+}
+
+function setVolume(vol, mute = false) {
+ volume = vol;
+ localStorageSet("volume", volume);
+ localStorageSet("muted", mute ? 1 : 0);
+ vol = mute ? 0 : vol;
+ if (currentEntry.type === "video") {
+ if (config.theme.nativePlayer) {
+ mediaVideoEl.volume = volume;
+ playerEl.volume = 0;
+ } else {
+ mediaVideoEl.volume = 0;
+ playerEl.volume = vol;
+ }
+ } else {
+ playerEl.volume = vol;
+ }
+ let scrubberWidth = 6;
+ let trackWidth = volumeTrackEl.clientWidth;
+ volumeFillEl.style.left = (1 - vol) * (trackWidth - scrubberWidth) + "px";
+ volumeIconEl.classList.remove(...volumeIcons);
+ if (vol <= 0) {
+ volumeIconEl.classList.add(volumeIcons[0]);
+ } else if (vol <= 0.5) {
+ volumeIconEl.classList.add(volumeIcons[1]);
+ } else {
+ volumeIconEl.classList.add(volumeIcons[2]);
+ }
+}
+
+document.addEventListener("keydown", (e) => {
+ if (e.key === " " && e.target === document.body) {
+ playEntry(currentEntry);
+ e.preventDefault();
+ }
+});
+
+let scrubberDragged = false;
+scrubberTrackContainerEl.addEventListener("pointerdown", (e) => {
+ scrubberDragged = true;
+ currentEntry.started = true;
+ scrub(e.clientX);
+});
+document.addEventListener("pointerup", (e) => {
+ if (scrubberDragged) {
+ scrubberDragged = false;
+ endScrub();
+ }
+ if (volumeDragged) {
+ volumeDragged = false;
+ endVolumeScrub();
+ }
+});
+document.addEventListener("pointermove", (e) => {
+ scrub(e.clientX);
+ scrubVolume(e.clientX);
+});
+document.addEventListener("pointercancel", (e) => {
+ console.log(e);
+});
+
+nextTrackEl.addEventListener("click", (e) => {
+ nextTrack();
+});
+prevTrackEl.addEventListener("click", (e) => {
+ prevTrack();
+});
+loopSwitchEl.addEventListener("click", (e) => {
+ loopSwitch();
+});
+
+function updateTrackPreview() {
+ if (currentEntry.needsDuration) {
+ return;
+ }
+ //reset to prevent compounding width calculation issues
+ scrubberTrackPreviewEl.style.removeProperty("margin-left");
+ scrubberTrackPreviewEl.style.removeProperty("width");
+ scrubberEl.style.removeProperty("left");
+ scrubberFillEl.style.removeProperty("width");
+ if (currentEntry.preview) {
+ let fullWidth = scrubberEl.parentElement.parentElement.clientWidth;
+ scrubberTrackPreviewEl.style.marginLeft =
+ (currentEntry.previewStart / currentEntry.originalDuration) * 100 + "%";
+ scrubberTrackPreviewEl.style.width =
+ ((currentEntry.previewEnd - currentEntry.previewStart) /
+ currentEntry.originalDuration) *
+ 100 +
+ "%";
+ }
+}
+
+function updatePreviewVolume(t) {
+ if (currentEntry.preview && currentEntry.previewFade && !muted) {
+ if (currentEntry.needsDuration) {
+ playEntry.volume = 0;
+ } else {
+ //rebase t to full (assumed) duration
+ t = currentEntry.audioStart + t * currentEntry.duration;
+ //clip to preview
+ t = Math.max(
+ currentEntry.previewStart,
+ Math.min(currentEntry.previewEnd, t)
+ );
+ let inTime = t - currentEntry.previewStart;
+ let outTime = currentEntry.previewEnd - t;
+ playerEl.volume =
+ volume * Math.max(0, Math.min(1, inTime / 1, outTime / 1)); //1 second fade in/out
+ }
+ }
+}
+
+//t: 0-1 value in relation to the actual audio start/end
+function updateScrubPosition(t) {
+ if (currentEntry.needsDuration) {
+ return;
+ }
+ //rebase t to full (assumed) duration
+ t = currentEntry.audioStart + t * currentEntry.duration;
+ //clip to preview
+ t = Math.max(currentEntry.previewStart, Math.min(currentEntry.previewEnd, t));
+ scrubPosition = (t - currentEntry.audioStart) / currentEntry.duration;
+ let time = t;
+ //rebase
+ t = t / currentEntry.originalDuration;
+ //relative to preview region
+ let scrubberT =
+ (t * currentEntry.originalDuration - currentEntry.previewStart) /
+ currentEntry.previewDuration;
+ let scrubberWidth = scrubberEl.clientWidth;
+ let trackWidth = scrubberEl.parentElement.clientWidth;
+
+ scrubberEl.style.left =
+ ((scrubberT * (trackWidth - scrubberWidth)) / trackWidth) * 100 + "%";
+ scrubberFillEl.style.width = scrubberT * 100 + "%";
+
+ //let time = timePosition * currentEntry.duration;
+ let timeText = "";
+ if (currentEntry.preview) {
+ timeText += "(preview)