// ==UserScript== // @name 移动端谷歌内核浏览器功能扩展 // @name:en Google Kernel Browser Function Extended to Mobile Phone // @description 移动端谷歌内核浏览器功能以及视频播放功能扩展 // @description:en Google Kernel Browser and Video Playing Function Extended to Mobile Phone // @version 3.0.0 // @author L.Xavier // @namespace https://greasyfork.org/zh-CN/users/128493 // @match *://*/* // @grant none // @run-at document-end // @note 功能说明:为了移动版yandex浏览器或其他类似可装扩展浏览器,添加功能扩展。 1.全屏下强制为横屏观看,支持重力感应切换方向(需要设备支持)。(新版已更新该功能,调整为桌面版网页触发) 2.添加双击全屏功能。一些网站全屏按钮无法使视频进入全屏模式(例如m.bilibili.com),新增在视频播放状态下,双击全屏(支持双击退出全屏)。该功能需要关闭yandex浏览器的"忽略网站的禁止字体缩放请求"功能,不关闭双击会缩放网页。3.竖屏模式。有些视频更适宜在竖屏状态下观看,新增摇一摇切换竖屏,再次摇一摇换回横屏(与横屏功能一同调整)。 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。新添加手势功能,有爱的小伙伴可自行玩耍,添加新手势。 // @note 注:新版yandex浏览器已支持横屏播放,但页面切换到电脑端模式仍不支持,本脚本可以完美解决。本脚本给有这类需求的人,以及使用该脚本双击功能习惯的朋友,有爱自取!(双击功能使用说明:在视频播放状态下,双击网页(包含该视频标签)任何一处,即可全屏,不需要再按小按钮了) // @downloadURL none // ==/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 SHAKE_THRESHOLD=1800;//摇一摇灵敏度,越小越灵敏 var acceleration=null,curTime=new Date().getTime(),last_update=curTime,diffTime=0,speed=0; var x=0,y=0,z=0,last_x=0,last_y=0,last_z=0,isReady_shake=true; function deviceMotionHandler(eventData) { if(document.webkitFullscreenElement && isReady_shake){ acceleration=eventData.accelerationIncludingGravity; curTime=new Date().getTime(); if ((curTime-last_update)>10) { diffTime=curTime-last_update; last_update=curTime; x=acceleration.x; y=acceleration.y; z=acceleration.z; speed=Math.abs(x+y+z-last_x-last_y-last_z)/diffTime*1000; if (speed>SHAKE_THRESHOLD) { if(isLock){ isLock=false; screen.orientation.lock(oriHway); } else{ isLock=true; screen.orientation.lock('portrait-primary'); } isReady_shake=false; setTimeout(function(){isReady_shake=true;},1000); } last_x=x; last_y=y; last_z=z; } } } //滑屏进度 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)<10 && Math.abs(angy)<10) { return '';//滑动距离过短 } angle=Math.atan2(angy,angx)*180/Math.PI; if(angle>-135 && angle<-45) { return 'U';//UP 上滑 }else if(angle>45 && angle<135) { return 'D';//DOWN 下滑 }else if((angle>=135 && angle<=180) || (angle>=-180 && angle<=-135)) { return 'L';//LEFT 左滑 }else if(angle>=-45 && angle<=45) { return 'R';//RIGHT 右滑 } } 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){videoplay.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; })(); //事件绑定 var videoEle=document.getElementsByTagName('video'); var videoplay=null,vi=0,isReady_ajax=true,isBind=false; function setVideo(e){videoplay=this;} function videoEvent(){ if(isReady_ajax){ isReady_ajax=false; setTimeout(function(){ for(vi=0;vi0){ if(!/Android|webOS|iPhone|iPod/i.test(navigator.userAgent)){ window.addEventListener('deviceorientation',orientationHandler,false); window.addEventListener('devicemotion',deviceMotionHandler,false); } document.body.addEventListener('dblclick',dblfull,false); isBind=true; } isReady_ajax=true; },1000); } } window.addEventListener('ajaxReadyStateChange',videoEvent,false); sliderbackListener(); videoEvent(); })();