file.streamTo video src inconsistently returning 404
dodo721 opened this issue · comments
What version of this package are you using?
2.0.37
What operating system, Node.js, and npm version?
OS: Ubuntu 21.10
Node.js: v14.21.2
npm: 6.14.17
What happened?
When using file.streamTo to attach a URL src to a video element, the video element returns a 404 on trying to fetch the video on most attempts, though very occasionally succeeding. If I open the URL generated in a new tab, it loads fine. Timing appears to make no difference: tests from generating the URL as the torrent generates, to waiting for a successful AJAX call first, to just a manual 20 second timeout all fail with the same inconsistency. My AJAX calls also still return status 200, even while the video element reports 404.
My code:
import React, { useEffect, useState, useRef } from 'react';
import { Button } from 'reactstrap';
import WebTorrent from 'webtorrent/dist/webtorrent.min.js';
import $ from 'jquery';
const MainDiv = () => {
const [torrent, setTorrent] = useState(null);
const [torrentProgress, setTorrentProgress] = useState("0%");
const [updateInterval, setUpdateInterval] = useState(null);
const [streamUrl, setStreamUrl] = useState(null);
const [videoStatus, setVideoStatus] = useState("Unloaded");
const videoRef = useRef();
useEffect(() => {
let client = new WebTorrent();
client.on('error', err => {
console.log('[+] Webtorrent error: ' + err.message);
});
// Sintel
const magnetURI = "magnet:?xt=urn:btih:08ada5a7a6183aae1e09d831df6748d566095a10&dn=Sintel&tr=udp%3A%2F%2Fexplodie.org%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.empire-js.us%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337&tr=wss%3A%2F%2Ftracker.btorrent.xyz&tr=wss%3A%2F%2Ftracker.fastcast.nz&tr=wss%3A%2F%2Ftracker.openwebtorrent.com&ws=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2F&xs=https%3A%2F%2Fwebtorrent.io%2Ftorrents%2Fsintel.torrent";
window.torrentClient = client;
const download = () => {
client.add(magnetURI, (torrent) => {
const interval = setInterval(() => {
// console.log('[+] Progress: ' + (torrent.progress * 100).toFixed(1) + '%')
setTorrentProgress((torrent.progress * 100).toFixed(1) + '%');
$.get(streamUrl).done((res, status, xhr) => {
setVideoStatus(xhr.status);
//console.log(xhr.status);
}).fail((res, status, xhr) => {
setVideoStatus(xhr.status);
});
}, 500);
torrent.on('done', () => {
console.log('Progress: 100%');
clearInterval(interval);
});
setUpdateInterval(interval);
setTorrent(torrent);
// TODO Figure out a better way to render these files
torrent.files.map((file, i) => {
console.log("FILE " + i, file);
if (file.name.endsWith(".mp4")) {
file.streamTo(videoRef.current);
const stream = videoRef.current.src;
//console.log("WOW I HAVE A STREAM URL???", streamUrl)
setStreamUrl(stream);
}
})
});
}
navigator.serviceWorker.register('/sw.min.js').then(reg => {
const worker = reg.active || reg.waiting || reg.installing
function checkState (worker) {
return worker.state === 'activated' && client.createServer({ controller: reg }) && download();
}
if (!checkState(worker)) {
worker.addEventListener('statechange', ({ target }) => checkState(target))
}
});
}, []);
const cancelTorrent = () => {
torrent.destroy({destroyStore:true});
setTorrent(null);
setTorrentProgress("0%");
clearInterval(updateInterval);
setUpdateInterval(null);
//unregister();
}
return <div className='main-page'>
<h1>{torrent?.name}</h1>
<p><b>Torrent Info Hash: </b>{torrent?.infoHash}</p>
<p><b>Torrent Progress: </b>{torrentProgress}</p>
<p>{videoStatus}</p>
<video id="loader" ref={videoRef}/>
<video id="player" src={videoStatus===200 ? streamUrl : null}/>
{torrent && <Button color="danger" onClick={cancelTorrent}>Clear torrent</Button>}
</div>;
};
export default MainDiv;
Additional info:
I am using NGINX to host my server on a local URL (local.milfos.com), with the following config:
# copy this to nginx sites-available, also modify etc/hosts
map $sent_http_content_type $expires {
default off;
text/html epoch;
text/css epoch;
application/javascript epoch;
~image/ epoch;
}
server {
listen 80; ## listen for ipv4; this line is default and implied
listen 443;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_certificate <REDACTED>;
ssl_certificate_key <REDACTED>;
add_header X-Frame-Options SAMEORIGIN always;
root /home/oem/MiLFOS/web;
index index.html;
server_name local.milfos.com;
expires $expires;
location / {
try_files $uri $uri/ index @backend;
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Cache-Control' 'no-cache';
}
location @backend {
proxy_pass http://localhost:3000;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
I am using the provided sw.min.js
service worker, stored in the root web directory.
What did you expect to happen?
The video element to load the generated URL src successfully.
Are you willing to submit a pull request to fix this bug?
I do not have enough knowledge of the issue to do so
if you're using nextjs to my knowledge, they patch the fetch function, check globalThis.fetch
, which breaks service worker requests [I think]
Hey, thanks for getting back to me so quick.
I'm not using nextjs - just webpack/babel compiling to a web directory, with nginx pointing to it.
I've also tried opening the page in a fresh profile with no extensions, making sure sw.min.js is the only service worker running, still to no avail.
I have found that clearing the cache gets me one successful run before it stops working again.
It seems to work until I click "Clear torrent" which destroys the torrent. After that it returns 404 on the video element again.
I've noticed these errors which may be relevant:
My package.json, for completion:
{
"name": "milfos",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"compile": "webpack --config $PWD/webpack.config.js --progress --color && ./gitstamp.sh",
"compile-watch": "node ci.js",
"compile-watch-fast": "NO_PROD=true webpack --progress --color --watch",
"server": "nodemon server/index.js"
},
"author": "dodo721",
"license": "ISC",
"dependencies": {
"@babel/runtime": "^7.16.5",
"express": "^4.18.2",
"jquery": "^3.7.0",
"lodash": "^4.17.21",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"reactstrap": "^8.10.1",
"torrent-search-api": "^2.1.4",
"webtorrent": "^2.0.37"
},
"devDependencies": {
"@babel/core": "^7.16.0",
"@babel/eslint-parser": "^7.18.9",
"@babel/plugin-proposal-class-properties": "^7.16.0",
"@babel/plugin-proposal-object-rest-spread": "^7.16.0",
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.16.0",
"@babel/plugin-transform-runtime": "^7.16.5",
"@babel/polyfill": "^7.11.5",
"@babel/preset-env": "^7.16.4",
"@babel/preset-react": "^7.16.0",
"@types/react": "^17.0.11",
"@types/react-dom": "^17.0.7",
"@types/reactstrap": "^8.5.1",
"@typescript-eslint/eslint-plugin": "^5.59.1",
"@typescript-eslint/parser": "^5.59.1",
"babel-eslint": "^10.1.0",
"babel-jest": "^27.0.2",
"babel-loader": "^8.2.3",
"babel-plugin-const-enum": "^1.2.0",
"core-js": "^3.19.3",
"css-loader": "^6.5.1",
"eslint": "^8.39.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsdoc": "^39.6.6",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.32.1",
"eslint-plugin-react-hooks": "^4.3.0",
"jsdom": "^21.0.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"mini-css-extract-plugin": "^2.4.5",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1"
},
"description": "Home media software with torrent scraping"
}
I cannot reproduce this in the examples webtorrent provides, so this has to be some issue on your end/config, seems like the service worker is completely ignored and goes directly to nginx
Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?