mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2025-09-09 15:38:44 +00:00
update
This commit is contained in:
@@ -41,7 +41,7 @@ export class TorrentClient {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If it's already active
|
// If it's already active, resolve immediately
|
||||||
if (checkActivation()) return;
|
if (checkActivation()) return;
|
||||||
|
|
||||||
registration.addEventListener("activate", () => {
|
registration.addEventListener("activate", () => {
|
||||||
@@ -88,11 +88,11 @@ export class TorrentClient {
|
|||||||
for (const reg of registrations) {
|
for (const reg of registrations) {
|
||||||
await reg.unregister();
|
await reg.unregister();
|
||||||
}
|
}
|
||||||
// A short wait to ensure old workers are gone
|
// Short delay to ensure old workers are removed
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register sw.min.js at the root path "/sw.min.js", with scope "/"
|
// Register sw.min.js from the root (Netlify serves it at /sw.min.js)
|
||||||
this.log("Registering service worker at /sw.min.js...");
|
this.log("Registering service worker at /sw.min.js...");
|
||||||
const registration = await navigator.serviceWorker.register("/sw.min.js", {
|
const registration = await navigator.serviceWorker.register("/sw.min.js", {
|
||||||
scope: "/",
|
scope: "/",
|
||||||
@@ -123,7 +123,7 @@ export class TorrentClient {
|
|||||||
await this.waitForServiceWorkerActivation(registration);
|
await this.waitForServiceWorkerActivation(registration);
|
||||||
this.log("Service worker activated");
|
this.log("Service worker activated");
|
||||||
|
|
||||||
// Double-check the SW is fully ready
|
// Ensure the service worker is fully ready
|
||||||
const readyRegistration = await Promise.race([
|
const readyRegistration = await Promise.race([
|
||||||
navigator.serviceWorker.ready,
|
navigator.serviceWorker.ready,
|
||||||
new Promise((_, reject) =>
|
new Promise((_, reject) =>
|
||||||
@@ -148,7 +148,6 @@ export class TorrentClient {
|
|||||||
|
|
||||||
// Minimal handleChromeTorrent
|
// Minimal handleChromeTorrent
|
||||||
handleChromeTorrent(torrent, videoElement, resolve, reject) {
|
handleChromeTorrent(torrent, videoElement, resolve, reject) {
|
||||||
// Listen for warnings, e.g. potential CORS blocks
|
|
||||||
torrent.on("warning", (err) => {
|
torrent.on("warning", (err) => {
|
||||||
if (err && typeof err.message === "string") {
|
if (err && typeof err.message === "string") {
|
||||||
if (
|
if (
|
||||||
@@ -179,16 +178,13 @@ export class TorrentClient {
|
|||||||
return reject(new Error("No compatible video file found in torrent"));
|
return reject(new Error("No compatible video file found in torrent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mute & cross-origin
|
|
||||||
videoElement.muted = true;
|
videoElement.muted = true;
|
||||||
videoElement.crossOrigin = "anonymous";
|
videoElement.crossOrigin = "anonymous";
|
||||||
|
|
||||||
// Handle video-level errors
|
|
||||||
videoElement.addEventListener("error", (e) => {
|
videoElement.addEventListener("error", (e) => {
|
||||||
this.log("Video error:", e.target.error);
|
this.log("Video error:", e.target.error);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Attempt autoplay when canplay
|
|
||||||
videoElement.addEventListener("canplay", () => {
|
videoElement.addEventListener("canplay", () => {
|
||||||
videoElement.play().catch((err) => {
|
videoElement.play().catch((err) => {
|
||||||
this.log("Autoplay failed:", err);
|
this.log("Autoplay failed:", err);
|
||||||
@@ -249,7 +245,7 @@ export class TorrentClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initiates streaming of a torrent magnet to a <video> element.
|
* Initiates streaming of a torrent magnet to a <video> element.
|
||||||
* Use `setupServiceWorker()` first to ensure the SW is registered.
|
* Ensures the service worker is registered first.
|
||||||
*/
|
*/
|
||||||
async streamVideo(magnetURI, videoElement) {
|
async streamVideo(magnetURI, videoElement) {
|
||||||
try {
|
try {
|
||||||
@@ -259,13 +255,9 @@ export class TorrentClient {
|
|||||||
throw new Error("Service worker setup failed");
|
throw new Error("Service worker setup failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) Optionally configure a pathPrefix here if your SW
|
// Create the WebTorrent server with the registered service worker.
|
||||||
// intercepts /webtorrent/ or /src/webtorrent
|
// (If you need to specify a custom URL prefix for torrent streaming,
|
||||||
// this.client.createServer({
|
// pass a pathPrefix option here.)
|
||||||
// controller: registration,
|
|
||||||
// pathPrefix: "/webtorrent",
|
|
||||||
// });
|
|
||||||
|
|
||||||
this.client.createServer({ controller: registration });
|
this.client.createServer({ controller: registration });
|
||||||
this.log("WebTorrent server created");
|
this.log("WebTorrent server created");
|
||||||
|
|
||||||
@@ -297,7 +289,7 @@ export class TorrentClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up resources
|
* Clean up resources.
|
||||||
*/
|
*/
|
||||||
async cleanup() {
|
async cleanup() {
|
||||||
try {
|
try {
|
||||||
|
121
src/sw.min.js
vendored
121
src/sw.min.js
vendored
@@ -15,38 +15,36 @@
|
|||||||
self.skipWaiting();
|
self.skipWaiting();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Claim clients on activation
|
// Claim clients on activation and clear caches
|
||||||
self.addEventListener("activate", (event) => {
|
self.addEventListener("activate", (event) => {
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
Promise.all([
|
Promise.all([
|
||||||
clients.claim(),
|
clients.claim(),
|
||||||
self.skipWaiting(),
|
self.skipWaiting(),
|
||||||
caches
|
caches.keys().then((cacheNames) =>
|
||||||
.keys()
|
Promise.all(cacheNames.map((cacheName) => caches.delete(cacheName)))
|
||||||
.then((cacheNames) =>
|
),
|
||||||
Promise.all(cacheNames.map((cacheName) => caches.delete(cacheName)))
|
|
||||||
),
|
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle fetch events
|
// Handle fetch events
|
||||||
self.addEventListener("fetch", (s) => {
|
self.addEventListener("fetch", (event) => {
|
||||||
const t = ((s) => {
|
const responsePromise = (() => {
|
||||||
const { url: t } = s.request;
|
const requestURL = event.request.url;
|
||||||
|
// Only handle WebTorrent streaming requests
|
||||||
// Only handle webtorrent requests
|
// Since our SW is registered with scope "/" the expected URL prefix is "/webtorrent/"
|
||||||
if (!t.includes(self.registration.scope + "webtorrent/")) {
|
if (!requestURL.includes("/webtorrent/")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle keepalive requests
|
// Handle keepalive requests
|
||||||
if (t.includes(self.registration.scope + "webtorrent/keepalive/")) {
|
if (requestURL.includes("/webtorrent/keepalive/")) {
|
||||||
return new Response();
|
return new Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle cancel requests
|
// Handle cancel requests
|
||||||
if (t.includes(self.registration.scope + "webtorrent/cancel/")) {
|
if (requestURL.includes("/webtorrent/cancel/")) {
|
||||||
return new Response(
|
return new Response(
|
||||||
new ReadableStream({
|
new ReadableStream({
|
||||||
cancel() {
|
cancel() {
|
||||||
@@ -57,87 +55,86 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle streaming requests
|
// Handle streaming requests
|
||||||
return (async function ({ request: s }) {
|
return (async function ({ request }) {
|
||||||
const { url: t, method: n, headers: o, destination: a } = s;
|
const { url, method, headers, destination } = request;
|
||||||
|
|
||||||
// Get all window clients
|
// Get all window clients
|
||||||
const l = await clients.matchAll({
|
const windowClients = await clients.matchAll({
|
||||||
type: "window",
|
type: "window",
|
||||||
includeUncontrolled: true,
|
includeUncontrolled: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create message channel and wait for response
|
// Create a message channel and wait for a response from a client
|
||||||
const [r, i] = await new Promise((e) => {
|
const [clientResponse, port] = await new Promise((resolve) => {
|
||||||
for (const s of l) {
|
for (const client of windowClients) {
|
||||||
const l = new MessageChannel(),
|
const channel = new MessageChannel();
|
||||||
{ port1: r, port2: i } = l;
|
channel.port1.onmessage = ({ data }) => {
|
||||||
r.onmessage = ({ data: s }) => {
|
resolve([data, channel.port1]);
|
||||||
e([s, r]);
|
|
||||||
};
|
};
|
||||||
s.postMessage(
|
client.postMessage(
|
||||||
{
|
{
|
||||||
url: t,
|
url,
|
||||||
method: n,
|
method,
|
||||||
headers: Object.fromEntries(o.entries()),
|
headers: Object.fromEntries(headers.entries()),
|
||||||
scope: self.registration.scope,
|
scope: self.registration.scope,
|
||||||
destination: a,
|
destination,
|
||||||
type: "webtorrent",
|
type: "webtorrent",
|
||||||
},
|
},
|
||||||
[i]
|
[channel.port2]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let c = null;
|
let timeoutId = null;
|
||||||
|
const closeChannel = () => {
|
||||||
const d = () => {
|
port.postMessage(false);
|
||||||
i.postMessage(false);
|
clearTimeout(timeoutId);
|
||||||
clearTimeout(c);
|
port.onmessage = null;
|
||||||
i.onmessage = null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle non-streaming response
|
// If the response is not a streaming request, return a normal response
|
||||||
if (r.body !== "STREAM") {
|
if (clientResponse.body !== "STREAM") {
|
||||||
d();
|
closeChannel();
|
||||||
return new Response(r.body, r);
|
return new Response(clientResponse.body, clientResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle streaming response
|
// Otherwise, handle streaming response using a ReadableStream
|
||||||
return new Response(
|
return new Response(
|
||||||
new ReadableStream({
|
new ReadableStream({
|
||||||
pull: (s) =>
|
pull(controller) {
|
||||||
new Promise((t) => {
|
return new Promise((resolvePull) => {
|
||||||
i.onmessage = ({ data: e }) => {
|
port.onmessage = ({ data }) => {
|
||||||
if (e) {
|
if (data) {
|
||||||
s.enqueue(e);
|
controller.enqueue(data);
|
||||||
} else {
|
} else {
|
||||||
d();
|
closeChannel();
|
||||||
s.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
t();
|
resolvePull();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!cancelled && a !== "document") {
|
if (!cancelled && destination !== "document") {
|
||||||
clearTimeout(c);
|
clearTimeout(timeoutId);
|
||||||
c = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
d();
|
closeChannel();
|
||||||
t();
|
resolvePull();
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
i.postMessage(true);
|
port.postMessage(true);
|
||||||
}),
|
});
|
||||||
|
},
|
||||||
cancel() {
|
cancel() {
|
||||||
d();
|
closeChannel();
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
r
|
clientResponse
|
||||||
);
|
);
|
||||||
})(s);
|
})(event);
|
||||||
})(s);
|
})();
|
||||||
|
|
||||||
if (t) {
|
if (responsePromise) {
|
||||||
s.respondWith(t);
|
event.respondWith(responsePromise);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
Reference in New Issue
Block a user