
diff --git a/js/app.js b/js/app.js
index eb198d3..417c357 100644
--- a/js/app.js
+++ b/js/app.js
@@ -511,12 +511,12 @@ class bitvidApp {
{ kinds: [0], authors: [pubkey], limit: 1 },
]);
let displayName = "User";
- let picture = "assets/jpg/default-profile.jpg";
+ let picture = "assets/svg/default-profile.svg";
if (events.length && events[0].content) {
const data = JSON.parse(events[0].content);
displayName = data.name || data.display_name || "User";
- picture = data.picture || "assets/jpg/default-profile.jpg";
+ picture = data.picture || "assets/svg/default-profile.svg";
}
// If you have a top-bar avatar (profileAvatar)
@@ -707,7 +707,14 @@ class bitvidApp {
this.activeIntervals = [];
}
- // 2) Cleanup resources (this stops the torrent, etc.)
+ // *** EXPLICITLY CANCEL THE SERVICE WORKER STREAM ***
+ try {
+ await fetch("/webtorrent/cancel/", { mode: "no-cors" });
+ } catch (err) {
+ // Silently ignore if offline or the request fails
+ }
+
+ // 2) Cleanup resources (stops WebTorrent, etc.)
await this.cleanup();
// 3) Hide the modal
@@ -945,7 +952,7 @@ class bitvidApp {
@@ -1011,7 +1018,7 @@ class bitvidApp {
const data = JSON.parse(userEvents[0].content);
const profile = {
name: data.name || data.display_name || "Unknown",
- picture: data.picture || "assets/jpg/default-profile.jpg",
+ picture: data.picture || "assets/svg/default-profile.svg",
};
// Store into the cache with a timestamp
@@ -1401,7 +1408,7 @@ class bitvidApp {
video.alreadyDecrypted = true;
}
- // 5) Show the modal
+ // 5) Show the modal and set the "please stand by" poster
this.currentVideo = video;
this.currentMagnetUri = video.magnet;
this.showModalWithPoster();
@@ -1464,13 +1471,49 @@ class bitvidApp {
const cacheBustedMagnet = video.magnet + "&ts=" + Date.now();
this.log("Starting video stream with:", cacheBustedMagnet);
+ // 11) Set autoplay preferences:
+ // Read user preference from localStorage (if not set, default to muted)
+ const storedUnmuted = localStorage.getItem("unmutedAutoplay");
+ const userWantsUnmuted = storedUnmuted === "true";
+ this.modalVideo.muted = !userWantsUnmuted;
+ this.log(
+ "Autoplay preference - unmuted:",
+ userWantsUnmuted,
+ "=> muted:",
+ this.modalVideo.muted
+ );
+
+ // Attach a volumechange listener to update the stored preference
+ this.modalVideo.addEventListener("volumechange", () => {
+ localStorage.setItem(
+ "unmutedAutoplay",
+ (!this.modalVideo.muted).toString()
+ );
+ this.log(
+ "Volume changed, new unmuted preference:",
+ !this.modalVideo.muted
+ );
+ });
+
+ // 12) Start torrent streaming
const realTorrent = await torrentClient.streamVideo(
cacheBustedMagnet,
this.modalVideo
);
- // 11) Start intervals to update stats
- // *** Slower stats update => 3 seconds
+ // 13) Attempt to autoplay; if unmuted autoplay fails, fall back to muted
+ this.modalVideo.play().catch((err) => {
+ this.log("Autoplay failed:", err);
+ if (!this.modalVideo.muted) {
+ this.log("Falling back to muted autoplay.");
+ this.modalVideo.muted = true;
+ this.modalVideo.play().catch((err2) => {
+ this.log("Muted autoplay also failed:", err2);
+ });
+ }
+ });
+
+ // 14) Start intervals to update torrent stats (every 3 seconds)
const updateInterval = setInterval(() => {
if (!document.body.contains(this.modalVideo)) {
clearInterval(updateInterval);
@@ -1480,7 +1523,7 @@ class bitvidApp {
}, 3000);
this.activeIntervals.push(updateInterval);
- // (Optional) Mirror small inline stats into the modal
+ // 15) (Optional) Mirror small inline stats into the modal
const mirrorInterval = setInterval(() => {
if (!document.body.contains(this.modalVideo)) {
clearInterval(mirrorInterval);
diff --git a/js/sidebar.js b/js/sidebar.js
index 1b6239f..e2eacf9 100644
--- a/js/sidebar.js
+++ b/js/sidebar.js
@@ -1,46 +1,29 @@
import { loadView } from "./viewManager.js";
+import { viewInitRegistry } from "./viewManager.js";
-/**
- * Wire up the sidebar links.
- * Home => loads the "most-recent-videos" partial and re-renders videos
- * Explore => loads explore.html with a "Coming Soon" message
- * Subscriptions => loads subscriptions.html with a "Coming Soon" message
- */
export function setupSidebarNavigation() {
- // 1) Home
- const homeLink = document.querySelector('a[href="#view=most-recent-videos"]');
- if (homeLink) {
- homeLink.addEventListener("click", (e) => {
+ // Grab all primary nav links that use the "#view=..." pattern
+ const sidebarLinks = document.querySelectorAll('#sidebar a[href^="#view="]');
+ sidebarLinks.forEach((link) => {
+ link.addEventListener("click", (e) => {
e.preventDefault();
- loadView("views/most-recent-videos.html").then(() => {
- // Once the partial is loaded, reassign #videoList + call loadVideos
- if (window.app && window.app.loadVideos) {
- window.app.videoList = document.getElementById("videoList");
- window.app.loadVideos();
+ // For a link like "#view=most-recent-videos", parse out "most-recent-videos"
+ const href = link.getAttribute("href") || "";
+ const viewMatch = href.match(/#view=(.+)/);
+ if (!viewMatch || !viewMatch[1]) {
+ return;
+ }
+ const viewName = viewMatch[1]; // e.g. "most-recent-videos"
+ const viewUrl = `views/${viewName}.html`;
+
+ // Load the partial view
+ loadView(viewUrl).then(() => {
+ // If there's a post-load function for this view, call it
+ const initFn = viewInitRegistry[viewName];
+ if (typeof initFn === "function") {
+ initFn();
}
});
});
- }
-
- // 2) Explore
- const exploreLink = document.querySelector('a[href="#view=explore"]');
- if (exploreLink) {
- exploreLink.addEventListener("click", (e) => {
- e.preventDefault();
- loadView("views/explore.html");
- // We just show the partial. No dynamic videos needed yet.
- });
- }
-
- // 3) Subscriptions
- const subscriptionsLink = document.querySelector(
- 'a[href="#view=subscriptions"]'
- );
- if (subscriptionsLink) {
- subscriptionsLink.addEventListener("click", (e) => {
- e.preventDefault();
- loadView("views/subscriptions.html");
- // Also "Coming Soon" in that partial for now.
- });
- }
+ });
}
diff --git a/js/viewManager.js b/js/viewManager.js
index 6fc488c..6b2cddf 100644
--- a/js/viewManager.js
+++ b/js/viewManager.js
@@ -15,3 +15,23 @@ export async function loadView(viewUrl) {
"Failed to load content.
";
}
}
+
+export const viewInitRegistry = {
+ "most-recent-videos": () => {
+ if (window.app && window.app.loadVideos) {
+ window.app.videoList = document.getElementById("videoList");
+ window.app.loadVideos();
+ }
+ // Force the profiles to update after the new view is in place.
+ if (window.app && window.app.forceRefreshAllProfiles) {
+ window.app.forceRefreshAllProfiles();
+ }
+ },
+ explore: () => {
+ console.log("Explore view loaded.");
+ },
+ subscriptions: () => {
+ console.log("Subscriptions view loaded.");
+ },
+ // Add additional view-specific functions here as needed.
+};
diff --git a/js/webtorrent.js b/js/webtorrent.js
index 80b96ab..0e82b2e 100644
--- a/js/webtorrent.js
+++ b/js/webtorrent.js
@@ -176,7 +176,7 @@ export class TorrentClient {
return reject(new Error("No compatible video file found in torrent"));
}
- videoElement.muted = false;
+ videoElement.muted = true;
videoElement.crossOrigin = "anonymous";
videoElement.addEventListener("error", (e) => {