Greasy Fork

Greasy Fork is available in English.

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

手机端类似yandex浏览器添加额外的功能。例如:双击视频全屏,滑动手势操作等。现有手势,→↑回到顶部,→↓回到底部,→←后退,←→前进,←视频进度后退,→视频进度前进。

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

// ==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.2.1
// @author         L.Xavier
// @namespace      http://greasyfork.icu/zh-CN/users/128493
// @match          *://*/*
// @grant          GM_setValue
// @grant          GM_getValue
// @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 - 修复语法错误导致的横屏逻辑失效问题
// @v3.2.0        2019-10-06 - 精简优化代码。调整视频滑动进度函数,使进度随滑动距离成指数增加,减小在短距离时的时间进度。调整手势功能代码逻辑,下个版本将添加手势功能设置UI,可自己添加修改手势操作。
// @v3.2.1        2019-10-15 - 修复因代码冲突导致的视频标签查找问题,调整查找视频标签逻辑。调整视频滑动进度判断逻辑。
// @note         注:(yandex视频横屏插件更名为手机端浏览器功能扩展) 新版yandex浏览器已支持横屏播放,但某些网站全屏播放以及页面切换到电脑端模式播放仍无法横屏播放,本脚本可以完美解决。本脚本给有这类需求的人,以及使用该脚本双击功能习惯的朋友,有爱自取!(双击功能使用说明:在视频播放状态下,双击网页(包含该视频标签)任何一处,即可全屏,不需要再按小按钮了)
// ==/UserScript==
(function() {
    'use strict';
    //重力感应
    var oriHway='landscape-primary',oriHgamma=0,oriHbeta=0,isLock=false;

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

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

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

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

    function videoEvent(){
        if(isReady_find){
            isReady_find=false;
            setTimeout(function(){
                if(videoEle.length>videoNum || (videoPlayer && !(videoPlayer in videoEle))){
                    for(vi=0;vi<videoEle.length;vi++){
                        videoEle[vi].addEventListener('playing',setVideo,false);
                    }
                    if(!videoNum){
                        window.addEventListener('deviceorientation',orientationHandler,false);
                        document.body.addEventListener('dblclick',dblfull,false);
                        videoPlayer=videoEle[0];
                    }
                    videoNum=videoEle.length;
                }
                isReady_find=true;
            },1000);
        }
    }

    //手指滑动
    var angX=0,angY=0,startX=0,startY=0,endX=0,endY=0;
    var direction='',path='',_startX=0,_startY=0,isReady_touch=true;
    var videoRect=null,videoX=0,videoY=0,videoW=0,videoH=0;

    //手势功能数据
    var gesture={
        '↑→↓←':'打开设置',
        '→←':'后退',
        '←→':'前进',
        '→↑':'回到顶部',
        '→↓':'回到底部',
        '←↓':'刷新页面'
    };
    var pathFn={
        '打开设置':'init()',
        '后退':'history.go(-1);',
        '前进':'history.go(1);',
        '回到顶部':'document.documentElement.scrollTop=0;',
        '回到底部':'document.documentElement.scrollTop=document.documentElement.scrollHeight;',
        '刷新页面':'location.reload();'
    };
    gesture=GM_getValue('gesture',gesture);
    pathFn=GM_getValue('pathFn',pathFn);

    //根据起点终点返回方向
    function getDirection(startX,startY,endX,endY){
        angX=(endX>startX) ? endX-startX : startX-endX;
        angY=(endY>startY) ? endY-startY : startY-endY;
        if(angX>angY){direction=(endX>startX) ? '→' : '←';}
        else{direction=(endY>startY) ? '↓' : '↑';}
    }

    //手指滑动事件绑定
    function sliderbackListener(){
        //手指接触屏幕
        document.body.addEventListener('touchstart',function(e){
            startX=e.changedTouches[0].clientX;
            startY=e.changedTouches[0].clientY;
            _startX=startX;_startY=startY;
            videoEvent();
        }, false);
        //手指滑动屏幕
        document.body.addEventListener('touchmove',function(e){
            e.preventDefault();
            if(e.targetTouches.length==1 || e.scale==1){
                endX=e.changedTouches[0].clientX;
                endY=e.changedTouches[0].clientY;
                getDirection(_startX,_startY,endX,endY);
                if(angX>50 || angY>50){
                    _startX=endX;_startY=endY;
                    if(path.charAt(path.length-1)!=direction){path+=direction;}
                }
            }
        },false);
        //手指离开屏幕。
        document.body.addEventListener('touchend', function(e){
            if(isReady_touch){
                endX=e.changedTouches[0].clientX;
                endY=e.changedTouches[0].clientY;
                getDirection(startX,startY,endX,endY);
                if(path.length<2 && videoPlayer && angX>angY){
                    videoRect=videoPlayer.getBoundingClientRect();
                    videoX=videoRect.x;
                    videoY=videoRect.y;
                    videoW=videoRect.width;
                    videoH=videoRect.height;
                    if(startX>videoX && startX<(videoX+videoW) && startY>videoY && startY<(videoY+videoH)){
                        angX=endX-startX;
                        videoPlayer.currentTime+=angX*angX*angX/20000;
                    }
                }else if(gesture[path]){
                    try{eval(pathFn[gesture[path]]);}
                    catch(error){alert('“'+path+'” 手势执行脚本错误:\n'+error+' !');}
                }
                path='';isReady_touch=false;
                setTimeout(function(){isReady_touch=true;},100);
            }
        }, false);
    }

    sliderbackListener();

    //手势操作设置UI
    function init(){
        alert('打开设置');
    }

})();