torrent-online 1.5.9 → 1.6.0

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 +38 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "torrent-online",
3
- "version": "1.5.9",
3
+ "version": "1.6.0",
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
@@ -776,7 +776,20 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
776
776
  if (s.codec_type === 'audio') tracks.push({ a: ai++, lang, title, codec: s.codec_name });
777
777
  else if (s.codec_type === 'subtitle') subs.push({ s: si++, lang, title, codec: s.codec_name });
778
778
  }
779
- return json(200, { ffmpeg: true, tracks, subs });
779
+ const vs = (j.streams || []).find(s => s.codec_type === 'video');
780
+ let vc = '';
781
+ if (vs) {
782
+ if (vs.codec_name === 'h264') {
783
+ const P = { Baseline: '42', Main: '4D', Extended: '58', High: '64', 'High 10': '6E', 'High 4:2:2': '76', 'High 4:4:4': 'F4' };
784
+ const idc = P[vs.profile] || '64';
785
+ const lvl = Number.isFinite(vs.level) ? ('0' + Math.round(vs.level / 10).toString(16)).slice(-2) : '28';
786
+ vc = 'avc1.' + idc + '00' + lvl;
787
+ } else if (vs.codec_name === 'hevc') {
788
+ vc = Number.isFinite(vs.level) ? 'hvc1.1.6.L' + Math.round(vs.level / 10) + '.B0' : 'hvc1.1.6.L120.B0';
789
+ } else if (vs.codec_name === 'av1') vc = 'av01.0.04M.08';
790
+ else if (vs.codec_name === 'vp9') vc = 'vp09.00.10.08';
791
+ }
792
+ return json(200, { ffmpeg: true, tracks, subs, vc });
780
793
  } catch (e2) { return json(200, { ffmpeg: true, tracks: [], subs: [], retry: true }); }
781
794
  }
782
795
  const mR = /^\/remux\/(\d+)\/(\d+)$/.exec(p);
@@ -835,28 +848,42 @@ async function webReq(req, res, client, st, opts, cacheDir, base) {
835
848
  '<style>body{margin:0;background:#000;color:#ddd;font:14px system-ui;display:flex;flex-direction:column;height:100vh;box-sizing:border-box}' +
836
849
  '.bar{display:flex;gap:10px;align-items:center;padding:6px 10px;flex-wrap:wrap}' +
837
850
  'select{background:#1b1b1f;color:#ddd;border:1px solid #333;border-radius:6px;padding:4px;max-width:340px}' +
838
- 'video{flex:1;width:100%;min-height:0;background:#000}</style>' +
851
+ 'video{flex:1;width:100%;min-height:0;background:#000}' +
852
+ '#ov{position:fixed;inset:0;display:none;align-items:center;justify-content:center;background:rgba(0,0,0,.45);cursor:pointer;font-size:72px;color:#fff}</style>' +
839
853
  '<div class=bar><b>' + esc(f.name) + '</b><select id=a style=display:none></select><select id=s style=display:none></select><span id=n></span></div>' +
840
- '<video id=v controls autoplay muted playsinline src="' + base + '/s/' + mV[1] + '/' + mV[2] + '"></video>' +
841
- '<script>var B=' + JSON.stringify(base) + ',ID=' + mV[1] + ',I=' + mV[2] + ';' +
842
- 'var v=document.getElementById("v"),aS=document.getElementById("a"),sS=document.getElementById("s"),n=document.getElementById("n");' +
843
- 'var MF=' + (webFriendly ? 1 : 0) + ';' +
844
- 'var tries=0;' +
854
+ '<video id=v controls autoplay playsinline src="' + base + '/s/' + mV[1] + '/' + mV[2] + '"></video>' +
855
+ '<div id=ov>▶</div>' +
856
+ '<script>var B=' + JSON.stringify(base) + ',ID=' + mV[1] + ',I=' + mV[2] + ',MF=' + (webFriendly ? 1 : 0) + ';' +
857
+ 'var v=document.getElementById("v"),aS=document.getElementById("a"),sS=document.getElementById("s"),n=document.getElementById("n"),ov=document.getElementById("ov");' +
858
+ 'ov.onclick=function(){v.play().catch(function(){});ov.style.display="none"};' +
859
+ 'var tries=0,ms=null,VC="";' +
860
+ 'var MSEOK=function(){return ("MediaSource" in window)&&VC&&MediaSource.isTypeSupported("video/mp4;codecs=\'" + VC + ",mp4a.40.2\'")};' +
861
+ 'var stopMse=function(){if(ms){try{ms.endOfStream()}catch(e){}ms=null}};' +
862
+ 'var mse=function(u){stopMse();var m=new MediaSource();v.src=URL.createObjectURL(m);' +
863
+ 'm.addEventListener("sourceopen",function(){var sb=m.addSourceBuffer("video/mp4;codecs=\'" + VC + ",mp4a.40.2\'");sb.mode="sequence";var q=[];' +
864
+ 'sb.addEventListener("updateend",function(){if(q.length){try{sb.appendBuffer(q.shift())}catch(e){}}});' +
865
+ 'fetch(u).then(function(r){var rd=r.body.getReader();var pump=function(){rd.read().then(function(res){' +
866
+ 'if(res.done){try{if(!sb.updating&&!q.length)m.endOfStream()}catch(e){}return;}' +
867
+ 'q.push(res.value);if(q.length<400&&!sb.updating){try{sb.appendBuffer(q.shift())}catch(e){}}pump()}).catch(function(){})};pump();});' +
868
+ 'v.play().catch(function(){ov.style.display="flex"})})};' +
845
869
  'var load=function(){fetch(B+"/api/tracks/"+ID+"/"+I).then(function(r){return r.json()}).then(function(d){' +
846
870
  'if(d.retry&&tries++<15){n.textContent="⏳ готовлю файл к стриму…";setTimeout(load,4000);return;}' +
847
871
  'if(d.error)n.textContent="⚠ "+d.error;' +
848
- 'var A=d.tracks||[],S=d.subs||[];' +
872
+ 'var A=d.tracks||[],S=d.subs||[];VC=d.vc||"";' +
849
873
  'if(!d.ffmpeg){return;}' +
850
874
  'if(A.length<2&&!S.length&&MF){return;}' +
851
875
  'A.forEach(function(t){var o=document.createElement("option");o.value=t.a;o.textContent="♪ "+(t.lang&&t.lang!=="und"?t.lang:"дорожка "+(t.a+1))+(t.title?" — "+t.title:"")+" ["+t.codec+"]";aS.appendChild(o)});' +
852
876
  'if(A.length>1){aS.value=A[0].a;aS.style.display=""}' +
853
877
  'if(S.length){var o0=document.createElement("option");o0.value="";o0.textContent="без субтитров";sS.appendChild(o0);' +
854
878
  '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=""}' +
855
- '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().catch(function(){})};' +
879
+ 'var go=function(){var t=v.currentTime;var s=sS.value;' +
880
+ 'var u=B+"/remux/"+ID+"/"+I+"?a="+(aS.style.display!==""?aS.value:0)+(s!==""?"&s="+s:"");' +
881
+ 'if(s===""&&MSEOK()){mse(u)}else{stopMse();v.src=u;v.load();v.addEventListener("loadedmetadata",function once(){v.currentTime=t;v.removeEventListener("loadedmetadata",once)});v.play().catch(function(){ov.style.display="flex"})}};' +
856
882
  'aS.onchange=go;sS.onchange=go;go();' +
857
- 'v.addEventListener("playing",function(){n.textContent=""});v.addEventListener("volumechange",function(){if(!v.muted)n.title="звук включён"});' +
883
+ '}).catch(function(){if(tries++<15)setTimeout(load,4000)})};' +
884
+ 'v.addEventListener("playing",function(){n.textContent="";ov.style.display="none"});' +
858
885
  'setInterval(function(){fetch(B+"/api/status").then(function(r){return r.json()}).then(function(l){var t=l.find(function(x){return x.id===ID});if(t&&v.readyState<2)n.textContent="⏬ "+t.speed+" · пиры "+t.peers+(t.progress>0?" · "+t.progress+"%":"")}).catch(function(){})},2000);' +
859
- '}).catch(function(){if(tries++<15)setTimeout(load,4000)})};load();</script>');
886
+ 'load();</script>');
860
887
  return;
861
888
  }
862
889
  res.statusCode = 404; res.end('not found');