torrent-online 1.5.5 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/wtui.js +11 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torrent-online",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "type": "module",
5
5
  "description": "Stream .torrent / magnet to VLC or browser — torrent streaming for macOS/Linux without a torrent client. Стрим торрентов в VLC или браузер.",
6
6
  "keywords": [
package/wtui.js CHANGED
@@ -641,6 +641,7 @@ function makeWebServer(client, st, opts, cacheDir, base) {
641
641
 
642
642
  async function webReq(req, res, client, st, opts, cacheDir, base) {
643
643
  const u = new URL(req.url, 'http://127.0.0.1');
644
+ const ensureSel = (e, i) => { const f = e?.t.files[i]; if (f && !e.sel.has(i)) { e.sel.add(i); try { f.select(); } catch {} } };
644
645
  let p = u.pathname;
645
646
  if (base) {
646
647
  if (p !== base && !p.startsWith(base + '/')) { res.statusCode = 404; res.end('not found'); return; }
@@ -724,6 +725,7 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
724
725
  const e = st.torrents.get(Number(mS[1]));
725
726
  const f = e?.t.files[Number(mS[2])];
726
727
  if (!f) { res.statusCode = 404; res.end('not found'); return; }
728
+ ensureSel(e, Number(mS[2]));
727
729
  return serveFile(req, res, f);
728
730
  }
729
731
  const mT = /^\/api\/tracks\/(\d+)\/(\d+)$/.exec(p);
@@ -731,6 +733,7 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
731
733
  const e = st.torrents.get(Number(mT[1]));
732
734
  const f = e?.t.files[Number(mT[2])];
733
735
  if (!f) return json(404, { error: 'нет файла' });
736
+ ensureSel(e, Number(mT[2]));
734
737
  const ffprobe = detectFFBin('ffprobe');
735
738
  if (!ffprobe) return json(200, { ffmpeg: false, tracks: [] });
736
739
  const url = 'http://127.0.0.1:' + st.port + base + '/s/' + mT[1] + '/' + mT[2];
@@ -746,13 +749,14 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
746
749
  else if (s.codec_type === 'subtitle') subs.push({ s: si++, lang, title, codec: s.codec_name });
747
750
  }
748
751
  return json(200, { ffmpeg: true, tracks, subs });
749
- } catch (e2) { return json(200, { ffmpeg: true, tracks: [], subs: [], error: String((e2 && e2.message) || e2).slice(0, 160) }); }
752
+ } catch (e2) { return json(200, { ffmpeg: true, tracks: [], subs: [], retry: true }); }
750
753
  }
751
754
  const mR = /^\/remux\/(\d+)\/(\d+)$/.exec(p);
752
755
  if (mR) {
753
756
  const e = st.torrents.get(Number(mR[1]));
754
757
  const f = e?.t.files[Number(mR[2])];
755
758
  if (!f) { res.statusCode = 404; res.end('not found'); return; }
759
+ ensureSel(e, Number(mR[2]));
756
760
  const ffmpeg = detectFFBin('ffmpeg');
757
761
  if (!ffmpeg) { res.statusCode = 500; res.end('ffmpeg не найден'); return; }
758
762
  const a = u.searchParams.get('a') || '0';
@@ -774,6 +778,7 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
774
778
  const e = st.torrents.get(Number(mV[1]));
775
779
  const f = e?.t.files[Number(mV[2])];
776
780
  if (!f) { res.statusCode = 404; res.end('not found'); return; }
781
+ ensureSel(e, Number(mV[2]));
777
782
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
778
783
  res.end('<!doctype html><meta charset=utf-8><title>' + esc(f.name) + '</title>' +
779
784
  '<style>body{margin:0;background:#000;color:#ddd;font:14px system-ui;display:flex;flex-direction:column;height:100vh;box-sizing:border-box}' +
@@ -784,7 +789,9 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
784
789
  '<video id=v controls autoplay src="' + base + '/s/' + mV[1] + '/' + mV[2] + '"></video>' +
785
790
  '<script>var B=' + JSON.stringify(base) + ',ID=' + mV[1] + ',I=' + mV[2] + ';' +
786
791
  'var v=document.getElementById("v"),aS=document.getElementById("a"),sS=document.getElementById("s"),n=document.getElementById("n");' +
787
- 'fetch(B+"/api/tracks/"+ID+"/"+I).then(function(r){return r.json()}).then(function(d){' +
792
+ 'var tries=0;' +
793
+ 'var load=function(){fetch(B+"/api/tracks/"+ID+"/"+I).then(function(r){return r.json()}).then(function(d){' +
794
+ 'if(d.retry&&tries++<15){n.textContent="⏳ готовлю файл к стриму…";setTimeout(load,4000);return;}' +
788
795
  'if(d.error)n.textContent="⚠ "+d.error;' +
789
796
  'var A=d.tracks||[],S=d.subs||[];' +
790
797
  'if(!d.ffmpeg||A.length<2){return;}' +
@@ -794,7 +801,7 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
794
801
  'S.forEach(function(t){var o=document.createElement("option");o.value=t.s;o.textContent="💬 "+(t.lang&&t.lang!=="und"?t.lang:"субтитры "+(t.s+1))+(t.title?" — "+t.title:"");sS.appendChild(o)});sS.style.display=""}' +
795
802
  'var go=function(){var t=v.currentTime;v.src=B+"/remux/"+ID+"/"+I+"?a="+aS.value+(sS.value!==""?"&s="+sS.value:"");v.load();v.addEventListener("loadedmetadata",function once(){v.currentTime=t;v.removeEventListener("loadedmetadata",once)});v.play()};' +
796
803
  'aS.onchange=go;sS.onchange=go;go();' +
797
- '}).catch(function(){})</script>');
804
+ '}).catch(function(){if(tries++<15)setTimeout(load,4000)})};load();</script>');
798
805
  return;
799
806
  }
800
807
  res.statusCode = 404; res.end('not found');
@@ -814,6 +821,7 @@ async function startWeb(opts, srcArg) {
814
821
  const dup = [...st.torrents.values()].find(e => e.t.infoHash === t.infoHash);
815
822
  if (dup) { try { t.destroy(); } catch {} return; }
816
823
  t.files.forEach(f => f.deselect()); // webtorrent по умолчанию выбирает все файлы
824
+ try { t.fileSelector = (tt, index, file) => (file._selections && file._selections.length ? 2 : 0); } catch {}
817
825
  const sel = new Set();
818
826
  const vids = t.files.map((f, i) => ({ f, i })).filter(x => VIDEO_EXT.has(path.extname(x.f.name).toLowerCase()));
819
827
  if (st.autoSelect) {