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