Greasy Fork

Greasy Fork is available in English.

手机端浏览器功能扩展(原yandex视频横屏插件)

手机端类似yandex浏览器添加额外的功能。例如:双击视频全屏,手势滑动等。

当前为 2019-10-03 提交的版本,查看 最新版本

// ==UserScript==
// @name           手机端浏览器功能扩展(原yandex视频横屏插件)
// @name:en        Add additional functions to mobile browser
// @description    手机端类似yandex浏览器添加额外的功能。例如:双击视频全屏,手势滑动等。
// @description:en Add additional functions to mobile browser(like yandex browser).For example, double-click full-screen video and gesture control.
// @version        3.1.2
// @author         L.Xavier
// @namespace      http://greasyfork.icu/zh-CN/users/128493
// @match          *://*/*
// @grant          none
// @run-at         document-end
// @note           功能说明:1.全屏下强制为横屏观看,支持重力感应切换方向(需要设备支持)。(新版浏览器已更新该功能,本脚本可解决某些网站以及桌面版网页仍然无法横屏播放的问题)   2.添加双击全屏功能。一些网站全屏按钮无法使视频进入全屏模式(例如m.bilibili.com),新增在视频播放状态下,双击全屏(支持双击退出全屏)。该功能需要关闭yandex浏览器的"忽略网站的禁止字体缩放请求"功能,不关闭双击会缩放网页。   3.竖屏模式。有些视频更适宜在竖屏状态下观看,新增摇一摇切换竖屏,再次摇一摇换回横屏(脚本3.1.0版本移除该功能!)。  4.添加手势操作,会JavaScript的小伙伴可自己添加手势功能。现有手势,→↑回到顶部,→↓回到底部,→←后退,←→前进,←视频进度后退,→视频进度前进。
// @v1.1.0        2019-01-01 - 1.添加竖屏模式。有些视频更适宜在竖屏状态下观看,全屏状态下,手机竖直摆放时会重新回到竖屏模式。2.添加双击全屏功能。一些网站全屏按钮无法使视频进入全屏模式(例如m.bilibili.com),新增在视频播放状态下,双击全屏(支持双击退出全屏)。该功能需要关闭yandex浏览器的"忽略网站的禁止字体缩放请求"功能,不关闭双击会缩放网页。
// @v1.1.1        2019-01-02 - 优化了代码逻辑
// @v1.1.2        2019-01-12 - Yandex浏览器版本18.11.1(安卓自2018年12月26日,版本号979),切换竖屏会退出全屏状态,暂时取消竖屏模式,其他保持不变。不是该版本浏览器,有竖屏观看需要的可以安装本脚本历史版本1.1.1。
// @v1.2.1        2019-02-01 - 重写了一部分代码,使之使用更加人性化。重新添加竖屏观看模式。使用方法,摇一摇切换竖屏观看,再摇一摇可换回横屏观看(可调节灵敏度,SHAKE_THRESHOLD参数,越小越灵敏)。火狐浏览器(安卓)使用该版本,除了双击全屏,其他功能正常。
// @v1.2.2        2019-02-03 - 防止误操作,摇一摇调整为全屏下执行。
// @v1.2.3        2019-02-04 - 修复了摇一摇短时间内可能触发两次的问题。
// @v1.2.4        2019-02-09 - 修复了后加载视频,某些功能可能需要多次点击才能生效的问题。
// @v1.2.5        2019-02-13 - 调整视频标签查找逻辑和事件方法,添加了更新说明。
// @v2.0.0        2019-08-22 - 新增视频滑动进行前进后退功能;修复在已有视频标签下,重新请求视频源双击全屏无效问题。
// @v2.1.0        2019-08-24 - 完善视频滑动前进后退进度,添加进度时间小tip(可能不同手机会有位置不居中的问题,大家可以用bilibili的桌面版页面测试)。优化代码逻辑。
// @v3.0.0        2019-10-02 - 横屏播放调整为桌面版启动,旧版yandex无横屏的小伙伴可以更新版本或用本脚本旧版本。因显示优先级问题,去除视频时间tip。新添加手势功能,有爱的小伙伴可自行玩耍,添加新手势。现有手势,→↑回到顶部,→↓回到底部,→←后退,←→前进,←视频进度后退,→视频进度前进。
// @v3.1.0        2019-10-03 - 调整视频横屏播放逻辑,修复脚本与浏览器竖屏播放功能冲突问题。去除摇一摇竖屏功能。
// @v3.1.1        2019-10-03 - 调整手势灵敏度
// @v3.1.2        2019-10-03 - 修复语法错误导致的横屏逻辑失效问题
// @note         注:(yandex视频横屏插件更名为手机端浏览器功能扩展) 新版yandex浏览器已支持横屏播放,但某些网站全屏播放以及页面切换到电脑端模式播放仍无法横屏播放,本脚本可以完美解决。本脚本给有这类需求的人,以及使用该脚本双击功能习惯的朋友,有爱自取!(双击功能使用说明:在视频播放状态下,双击网页(包含该视频标签)任何一处,即可全屏,不需要再按小按钮了)
// ==/UserScript==
(function() {
    'use strict';
    //重力感应
    var oriHway='landscape-primary',oriHgamma=0,oriHbeta=0,isLock=false;

    function orientationHandler(event){
        oriHgamma=Math.round(event.gamma);
        oriHbeta=Math.abs(Math.round(event.beta));
        if((oriHbeta<45 && Math.abs(oriHgamma)>25) || (oriHbeta>135 && Math.abs(oriHgamma)>25)){
            oriHway=((oriHgamma>25 && oriHbeta<45) || (oriHgamma<-25 && oriHbeta>135)) ? 'landscape-secondary' : 'landscape-primary';
        }
        if(!isLock){screen.orientation.lock(oriHway);}
    }

    //滑屏进度
    var angx=0,angy=0,angle=0;
    var startx=0,starty=0,endx=0,endy=0,direction='',isReady_touch=true;
    var videoRect=null,videox=0,videoy=0,videow=0,videoh=0;
    var way='',turn=0,_startx=0,_starty=0;

    //根据起点终点返回方向
    function getDirection(startx,starty,endx,endy){
        angx=endx-startx;
        angy=endy-starty;
        //如果滑动距离太短
        if(Math.abs(angx)<20 && Math.abs(angy)<20){
            return '';
        }
        angle=Math.atan2(angy,angx)*180/Math.PI;
        if(angle>-135 && angle<-45){
            return 'U';
        }else if(angle>45 && angle<135){
            return 'D';
        }else if((angle>=135 && angle<=180) || (angle>=-180 && angle<=-135)){
            return 'L';
        }else if(angle>=-45 && angle<=45){
            return 'R';
        }
    }

    function sliderbackListener(){
        //手指接触屏幕
        document.body.addEventListener('touchstart',function(e){
            startx=e.changedTouches[0].clientX;
            starty=e.changedTouches[0].clientY;
            _startx=startx;
            _starty=starty;
            if(videoplay){
                videoRect=videoplay.getBoundingClientRect();
                videox=videoRect.x;
                videoy=videoRect.y;
                videow=videoRect.width;
                videoh=videoRect.height;
          }
      }, false);
      //手指滑动屏幕
      document.body.addEventListener('touchmove',function(e){
          if(e.targetTouches.length>1 || e.scale && e.scale!==1) return;
          event.preventDefault();
          endx=e.changedTouches[0].clientX;
          endy=e.changedTouches[0].clientY;
          direction=getDirection(_startx,_starty,endx,endy);
          if(direction){
              if(way.length==turn){
                  way+=direction;
                  _startx=endx;
                  _starty=endy;
              }else{
                  if(way.charAt(way.length-1)==direction){
                      _startx=endx;
                      _starty=endy;
                  }else{
                      way+=direction;
                      turn++;
                  }
              }
          }
      },false);
      //手指离开屏幕。手势功能区,RU代表先右滑再上滑,新加手势,添加新case代码即可
      document.body.addEventListener('touchend', function(e){
          if(isReady_touch){
              switch(way){
                  case 'RU':
                      document.documentElement.scrollTop=0;
                      break;
                  case 'RD':
                      document.documentElement.scrollTop=document.documentElement.scrollHeight;
                      break;
                  case 'RL':
                      history.go(-1);
                      break;
                  case 'LR':
                      history.go(1);
                      break;
                  case 'L':
                      //左滑事件
                      if(videoplay && startx>videox && startx<(videox+videow) && starty>videoy && starty<(videoy+videoh)){
                          videoplay.currentTime+=(endx-startx)/videow*videoplay.duration;
                      }
                      break;
                  case 'R':
                      //右滑事件
                      if(videoplay && startx>videox && startx<(videox+videow) && starty>videoy && starty<(videoy+videoh)){
                          videoplay.currentTime+=(endx-startx)/videow*videoplay.duration;
                      }
                      break;
                  /*按照模板添加手势即可
                  case '滑动顺序':
                        执行功能代码;
                        break;
                  写在这后面,滑动顺序无字数限制如RDLU等,但尽量符合自己手势习惯*/
              }
              way='';
              turn=0;
              isReady_touch=false;
              setTimeout(function(){isReady_touch=true;},100);
          }
      }, false);
    }

    //双击全屏
    function dblfull(){
        if(videoplay){
            if(document.webkitFullscreenElement){document.webkitExitFullscreen();}
            else{videoplay.webkitRequestFullScreen();}
        }
    }

    //全局Ajax触发回调
    !(function(){
        if(typeof window.CustomEvent==='function') return false;
        function CustomEvent(event,params){
            params=params || {bubbles:false,cancelable:false,detail:undefined};
            var evt=document.createEvent('CustomEvent');
            evt.initCustomEvent(event,params.bubbles,params.cancelable,params.detail);
            return evt;
        }
        CustomEvent.prototype=window.Event.prototype;
        window.CustomEvent=CustomEvent;
    })();

    !(function(){
        function ajaxEventTrigger(event){
            var ajaxEvent=new CustomEvent(event,{detail:this});
            window.dispatchEvent(ajaxEvent);
        }
        var oldXHR=window.XMLHttpRequest;
        function newXHR(){
            var realXHR=new oldXHR();
            realXHR.addEventListener('abort',function(){ajaxEventTrigger.call(this,'ajaxAbort');},false);
            realXHR.addEventListener('error',function(){ajaxEventTrigger.call(this,'ajaxError');},false);
            realXHR.addEventListener('load',function(){ajaxEventTrigger.call(this,'ajaxLoad');},false);
            realXHR.addEventListener('loadstart',function(){ajaxEventTrigger.call(this,'ajaxLoadStart');},false);
            realXHR.addEventListener('progress',function(){ajaxEventTrigger.call(this,'ajaxProgress');},false);
            realXHR.addEventListener('timeout',function(){ajaxEventTrigger.call(this,'ajaxTimeout');},false);
            realXHR.addEventListener('loadend',function(){ajaxEventTrigger.call(this,'ajaxLoadEnd');},false);
            realXHR.addEventListener('readystatechange',function(){ajaxEventTrigger.call(this,'ajaxReadyStateChange');},false);
            return realXHR;
        }
        window.XMLHttpRequest=newXHR;
    })();

    //video标签查找
    var videoEle=document.getElementsByTagName('video');
    var videoplay=null,vi=0,isReady_ajax=true;

    function setVideo(e){
        videoplay=this;
        if(videoplay.videoWidth>=videoplay.videoHeight){
            isLock=false;
            screen.orientation.lock(oriHway);
        }else{
            isLock=true;
            screen.orientation.unlock();
        }
    }

    function videoEvent(){
        if(isReady_ajax){
            isReady_ajax=false;
            setTimeout(function(){
                for(vi=0;vi<videoEle.length;vi++){
                    if(!videoEle[vi].playing){videoEle[vi].addEventListener('playing',setVideo,false);}
                }
                isReady_ajax=true;
            },1000);
        }
    }

    //事件绑定
    window.addEventListener('ajaxReadyStateChange',videoEvent,false);
    window.addEventListener('deviceorientation',orientationHandler,false);
    document.body.addEventListener('dblclick',dblfull,false);
    sliderbackListener();
    videoEvent();

})();