手机遥控电脑打开网页电视(nodejs)

我用的koa框架,app.js之类的省略。系统用的debian,浏览器用的firefox,windows应该也能用。

firefox要装插件ModHeader修改http请求头,因为有的视频网址有限制。再装一个CORS Unblock插件。还要把浏览器的打开后禁止自动播放禁止。取消禁止视频全屏。

手机控制端:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">   
    <title></title> 
 <style type="text/css">   
    body{text-align:center;margin:0 auto;}
 </style>
 <style type="text/css">
  .button {
    //padding: 10px 0;
    margin: 10px 20px;
    font-size: 18px;
    color: #000;
    border-radius: 25px;
    height: 25px;
    width: 100px;
    border: 0px;
    background-color: #eee;
    box-shadow: 0 8px 16px #888;
    outline: 1px;
    cursor: pointer;
  }
  .button:active {
    color: #00f;
    background-color: #0f0;
	transform: translateY(4px);
	box-shadow: 0 4px 16px #ff0
}


  body {
    padding: 0 0
  }

  @media only screen and (min-width: 500px) {
    body {
      padding: 0 200px
    }
  }
</style>
</head>

<body>    

<script src="/p/js/vue.min.js"></script>
<script src="/p/js/tv.js"></script>
<br><br>
<div id="app">
  <div v-for="(v,k,i) in tvurl" style="display:inline-block">
    <div class="button" v-bind:id="'btn'+i" v-on:click="dakai(v,i)">{{k}}</div>
  </div><br><br><br><br><br><br>
  <div v-for="item in caidan">
    <div v-for="subitem in item" style="display:inline-block">    
        <button class="button"  v-on:click="fasong($event)">{{subitem}}</button>
    </div><br>    
  </div>
</div>

<script>
vm = new Vue({
    el: '#app',
    data: {
      tvurl: tv ,
      caidan:[
        ["打开","刷新","关闭"],
        [],
	["暂停","播放"],
	[],
	["全屏","退出全屏"],
	["上"],
	["下"],
	["加","减"],
	[],
	["+","-"]
	],
     },
    methods: {
    fasong: function (e){
console.log(e.currentTarget.innerText)
fetch("/yaokongfasong/"+e.currentTarget.innerText)
}
    }
  })
  
function dakai(v,i){
fetch("/yaokongfasong/btn"+i)
}


//firefox  about:config    full-screen-api.allow-trusted-requests-only  false       full-screen-api.approval-required
</script>
</body>

</html>

koa控制器:

 const util = require('util');
 const exec = util.promisify(require('child_process').exec);
 const WebSocket = require('ws');
const url = require('url');
 let yaokongws={};
 
function sleep(time){
 return new Promise((resolve) => setTimeout(resolve, time));
}

  let wss = new WebSocket.Server({
        server: server2
    });
  
   wss.on('connection', function (ws,req) {   
    let location = url.parse(req.url, true);
    console.log(req.url);
    if (location.pathname !== '/ws/yaokong') {
            ws.close(4000, 'Invalid URL');
            return;
            }
     })
     
  yaokongws.ws=wss;
  
  
  
  module.exports = {
  'GET /yaokongfasong/:cmd': async (ctx, next) => {
    var cmd = ctx.params.cmd;   
    if (cmd==="+"){        
    await exec("amixer sset Master 5%+")   
    return
    }
    else if (cmd==="-"){    
    const { stdout, stderr } =await exec("amixer sget Master" )     
    let aa=stdout.match(/ \[([0-9]{1,3})%\] /);
    bb=Number(aa[1])-5
    bb=bb<0?0:bb;
    await exec("amixer sset Master "+ bb +"%")   
    return
    }
    else if (cmd==="播放"){        
    await exec("xdotool mousemove_relative 1 1")   
    }
    else if (cmd==="打开"){  
    try{  
    const { stdout, stderr }=await exec("ps -e|grep -s firefox");
    }
    catch(e){
     exec("firefox");
     await sleep(2500);
    }
    exec("firefox  http://192.168.123.200:3000/p/iptv_.htm &") ; 
    }
    try{
    console.log(yaokongws.ws.clients.size);
    [...yaokongws.ws.clients][yaokongws.ws.clients.size-1].send(cmd);
    }
    catch(e){console.log("cuo")}
    }
  }

电脑端网页:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">   
 <style type="text/css">
  body{text-align:center;margin:0 auto;}
  .button {
    padding: 10px 0;
    margin: 20;
    font-size: 18px;
    color: #000;
    border-radius: 25px;
    height: 25px;
    width: 100px;
    border: 0px;
    //background-color: #eee;
    box-shadow: 0 8px 16px #888;
    //outline: none;
  }  
  .vd{
 width: 100vw; 
 height: calc(100vw * 0.5625);
  object-fit: fill;
  }
 @media only screen and (min-width: 1280px) {
   .vd{
  width: 1280px;
  height: 720px;
  object-fit: fill;
  }
 
   }
</style>
</head>
<body> 

<script src="/p/js/hls.js"></script>
<script src="/p/js/flv.js"></script>
<script src="/p/js/vue.min.js"></script>

<div>
  <video class="vd"  id="videoElement"  allowfullscreen="true" ></video>
  <br><br>
 
</div>
<div id="app">
  <div v-for="(v,k,i) in tvurl" style="display:inline-block">
    <div class="button" v-bind:id="'btn'+i" v-on:click="dakai(v,i)">{{k}}</div>
  </div>
</div><br>
 <input type="text" id="tvu" />
  <input type="button" id="dakai" onclick="dakai(tvu.value)" value="打开" /><br><br>

<script src="/p/js/tv.js"></script>
<script>
  var video = document.getElementById('videoElement');
  var curidx=3;
  var flvPlayer = null;
  var hls=null;
  function dakai(url,idx) {
    curidx=idx;
    if (url.endsWith("flv")) {
      if (flvPlayer) {
        this.flvPlayer.pause();
        this.flvPlayer.unload();
        this.flvPlayer.detachMediaElement();
        this.flvPlayer.destroy();
        this.flvPlayer = null;
      }
      flvPlayer = flvjs.createPlayer({
        type: 'flv',
        url: url
      });
      flvPlayer.attachMediaElement(video);
      flvPlayer.load();
      flvPlayer.play();
    }
    else {
      if (flvPlayer) {
        this.flvPlayer.pause();
        this.flvPlayer.unload();
        this.flvPlayer.detachMediaElement();
        this.flvPlayer.destroy();
        this.flvPlayer = null;
      }
      if (hls) {
        hls.stopLoad();
        hls.detachMedia();
        hls.destroy();
        hls = null;
      }      
      hls = new window.Hls()
      hls.attachMedia(video)
      hls.on(Hls.Events.MANIFEST_PARSED, function () {
        video.play()
      })
      hls.loadSource(url)
    }
  }


vm = new Vue({
    el: '#app',
    data: { tvurl: tv }
  })
  /*
  cdns = "http://www.baidu.com.cdns.cfd/url/?id=";
  pms = []
  t = []
  for (let i in j) {
    pms.push(fetch(cdns + j[i]));
    t.push(i);
  }
  Promise.all(pms).then(a => a.forEach((b, i) => { vm.tvurl[t[i]] = b.url.substr(37) }))
  */
fetch("http://www.baidu.com.cdns.cfd/html/?id=hebws").then(b => vm.$set(vm.tvurl,"河北",b.url.substr(37)));

async function tianjia(ming,can,ur,matchurl="<source src="){
const response = await fetch(ur+can);
const body = await response.text();
let re=new RegExp(matchurl+'\\"(.*?)\\"');
let aa=body.match(re);
vm.$set(vm.tvurl,ming,aa[1]);
}

a={
凤凰中文2: "fhzw",
凤凰资讯: "fhzx",
}
for (let b in a){
tianjia(b,a[b],'http://player.200877926.top/1691/_others/fh.php?id=')
}
c={
湖南: "hunan",
cctv2: "cctv2",
江苏: "jiangsu",
凤凰中文: "fhzw",
btv:"beijing",
天津:"tianjin",
cctvfyyy:"cctvfyyy",
}

for (let b in c){
tianjia(b,c[b],'http://player.200877926.top/1691/cq/cqyx.php?id=','\\"url\\": ')
}

tianjia("东方卫视","dongfang","http://player.200877926.top/1691/sh/shanghai.php?id=")
tianjia("cctv","cctv1","http://player.200877926.top/1691/sd/weihai.php?id=")

window.onload = () => dakai(vm.tvurl['浙江'],3);

ws=new WebSocket('ws://127.0.0.1:3000/ws/yaokong') ;
ws.onmessage=function onMessage(event){
minglingduixiang={
  上:()=>document.querySelector('#btn'+(curidx-1)).click(),
  下:()=>document.querySelector('#btn'+(curidx+1)).click(),
  加:()=>video.volume=video.volume+0.05,
  减:()=>video.volume=video.volume-0.05,
  全屏:()=>video.requestFullscreen(),
  退出全屏:()=>document.exitFullscreen(),
  暂停:()=>video.pause(),
  播放:()=>video.play(),
  刷新:()=>window.location.reload(),
  关闭:()=>window.close(),
}
if(minglingduixiang[event.data]){
minglingduixiang[event.data]();
return;
}

if(event.data.startsWith("btn")){
document.querySelector("#"+event.data).click();
}
}
</script>
</body>

</html>

tv.js:

tv = {
   cctv: '',
   cctv2: ' ',
   凤凰中文: ' ',
   河北: '',
    河北农民: 'https://event.pull.hebtv.com/jishi/nongminpindao.m3u8',
    btv: '',
    东方卫视: ' ',    
    天津:'',
    浙江: 'http://hw-m-l.cztv.com/channels/lantian/channel01/1080p.m3u8',    
    湖南: '',
    江苏: '',
    HKS: 'http://zhibo.hkstv.tv/livestream/mutfysrq/playlist.m3u8',
   郑州广播: 'https://live.ximalaya.com/radio-first-page-app/live/476/64.m3u8?transcode=ts',
   怀集广播: 'https://live.ximalaya.com/radio-first-page-app/live/966/64.m3u8?transcode=ts',
   经典fm: 'https://live.ximalaya.com/radio-first-page-app/live/2689/64.m3u8?transcode=ts',   
    //保定: 'http://live.bdgdw.com/channel1/sd/live.m3u8?_upt=743267691684327305',     
    俄罗斯: 'https://brics.bonus-tv.ru/cdn/brics/chinese/tracks-v1a1/mono.m3u8',
    ndt: 'https://ntd02.akamaized.net/NTDA/tracks-v4a1/mono.m3u8',
    //大爱2: 'https://pulltv2.wanfudaluye.com/live/tv2.m3u8',
    cetv1:'http://txycsbl.centv.cn/zb/0628cetv1.m3u8',    
  }

有空把websocket改成SSE

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值