Last active
November 9, 2018 11:35
-
-
Save zhjgithub/38bff8b658af77b7c102a69e37b2f120 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Udacity Chinese courses video playback controller | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Enable forward/backward and play/pause for current mouse hovering video if more than one video tag on the page. | |
// @author organism <neuqzhj@gmail.com> | |
// @source https://gist.github.com/zhjgithub/38bff8b658af77b7c102a69e37b2f120 | |
// @match https://classroom.udacity.com/* | |
// @run-at document-end | |
// @grant none | |
// ==/UserScript== | |
/* | |
Inspired By HTML5播放器增强插件 from https://greasyfork.org/users/49622 | |
*/ | |
(function() { | |
'use strict'; | |
const playbackRateRange = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]; | |
const controller = { | |
player: function() { | |
return this.currentVideo; | |
}, | |
_isFocused: false, | |
isFocused: function() { | |
return this._isFocused; | |
}, | |
setPlayer: function(video) { | |
if (this.currentVideo != video) { | |
this.currentVideo = video; | |
this.videoPlayButton = video.parentNode.querySelector('button.video-play'); | |
this.videoPlayButton.focus(); | |
this.playbackRateIndex = 2; | |
video.parentNode.appendChild(this._tips); | |
} | |
this._isFocused = true; | |
}, | |
clearPlayer: function() { | |
this._isFocused = false; | |
}, | |
tips: function(str) { | |
const tips = this._tips; | |
const style = tips.style; | |
tips.innerText = str; | |
for (var i = 0; i < 3; i++) { | |
if (this.on_off[i]) clearTimeout(this.on_off[i]); | |
} | |
style.display = 'block'; | |
this.on_off[0] = setTimeout(function() { | |
style.opacity = 1; | |
}, 50); | |
this.on_off[1] = setTimeout(function() { | |
style.opacity = 0; | |
}, 1000); | |
this.on_off[2] = setTimeout(function() { | |
style.display = 'none'; | |
}, 2000); | |
}, | |
on_off: new Array(3), | |
init: function() { | |
if (this.load || document.querySelectorAll('video').length === 0) { | |
return; | |
} | |
var _this = this; | |
this.load = true; | |
setTimeout(function() { | |
// console.log('检测到HTML5视频!'); | |
_this.load = false; | |
_this.setFocusListener(); | |
_this.initTips(); | |
document.onkeydown = _this.button; | |
const currentFocusedVideo = document.querySelector( | |
'video:hover' | |
); | |
if (currentFocusedVideo) { | |
_this.setPlayer(currentFocusedVideo); | |
} | |
}, 1000); | |
}, | |
load: false, | |
button: function(event) { | |
if (event.altKey || event.ctrlKey || event.shiftKey) return; | |
if (!controller.isFocused()) return; | |
let handled = false; | |
const _this = controller; | |
if (event.key === 'ArrowRight' || event.key === 'n') { | |
//方向键右→:快进3秒 | |
_this.player().currentTime += 3; | |
_this.tips('快进:3秒'); | |
handled = true; | |
} else if (event.key === 'ArrowLeft' || event.key === 'b') { | |
//方向键左←:后退3秒 | |
_this.player().currentTime -= 3; | |
_this.tips('后退:3秒'); | |
handled = true; | |
} else if(event.key === ','){ | |
_this.player().currentTime -= 15; | |
_this.tips('后退:15秒'); | |
handled = true; | |
} else if(event.key === '.'){ | |
_this.player().currentTime += 15; | |
_this.tips('快进:15秒'); | |
handled = true; | |
} else if (event.key === 'ArrowUp') { | |
//方向键上↑:音量升高 1% | |
if (_this.player().volume < 1) { | |
_this.player().volume += 0.01; | |
} | |
_this.player().volume = _this.player().volume.toFixed(2); | |
_this.tips( | |
'音量:' + parseInt(_this.player().volume * 100) + '%' | |
); | |
handled = true; | |
} else if (event.key === 'ArrowDown') { | |
//方向键下↓:音量降低 1% | |
if (_this.player().volume > 0) { | |
_this.player().volume -= 0.01; | |
} | |
_this.player().volume = _this.player().volume.toFixed(2); | |
_this.tips( | |
'音量:' + parseInt(_this.player().volume * 100) + '%' | |
); | |
handled = true; | |
} else if (event.key === ' ') { | |
let onlyShowTips = false; | |
if (document.activeElement === _this.videoPlayButton) { | |
onlyShowTips = true; | |
} | |
//空格键:暂停/播放 | |
if (_this.player().paused) { | |
if (!onlyShowTips) _this.player().play(); | |
_this.tips('播放'); | |
} else { | |
if (!onlyShowTips) _this.player().pause(); | |
_this.tips('暂停'); | |
} | |
handled = true; | |
} else if (event.key === 'z') { | |
_this.changePlaybackSpeed('rest'); | |
_this.tips('播放速度复位'); | |
handled = true; | |
} else if (event.key === 'x') { | |
_this.changePlaybackSpeed('-'); | |
_this.tips(`播放速度${playbackRateRange[_this.playbackRateIndex]}`); | |
handled = true; | |
} else if (event.key === 'c') { | |
_this.changePlaybackSpeed('+'); | |
_this.tips(`播放速度${playbackRateRange[_this.playbackRateIndex]}`); | |
handled = true; | |
} | |
if (handled) { | |
event.stopPropagation(); | |
event.preventDefault(); | |
} | |
}, | |
changePlaybackSpeed: function (value) { | |
if (value === '+') { | |
if (this.playbackRateIndex >= playbackRateRange.length - 1) return; | |
this.playbackRateIndex += 1; | |
} else if (value === '-') { | |
if (this.playbackRateIndex <= 0) return; | |
this.playbackRateIndex -= 1; | |
} else { | |
this.playbackRateIndex = 2; | |
} | |
this.player().parentNode.querySelector(`input[name="playback-speed"][value="${playbackRateRange[this.playbackRateIndex]}"]`) | |
.click(); | |
}, | |
onmouseover: function(event) { | |
controller.setPlayer(event.target); | |
}, | |
onmouseout: function(event) { | |
controller.clearPlayer(); | |
}, | |
setFocusListener: function() { | |
const allVideos = document.querySelectorAll('video'); | |
allVideos.forEach(element => { | |
element.onmouseover = this.onmouseover; | |
element.onmouseout = this.onmouseout; | |
}, this); | |
}, | |
initTips: function() { | |
if (this._tips) { | |
return; | |
} | |
const tips = document.createElement('div'); | |
this._tips = tips; | |
tips.setAttribute('id', 'video-playback-control-tips'); | |
tips.setAttribute( | |
'style', | |
"pointer-events: none;position: absolute;z-index: 999999;padding: 10px;background: rgba(0,0,0,0.8);color:white;top: 50%;left: 50%;transform: translate(-50%,-50%);transition: all 500ms ease;opacity: 0;display: none; -webkit-font-smoothing: subpixel-antialiased;font-family: 'microsoft yahei', Verdana, Geneva, sans-serif;-webkit-user-select: none;" | |
); | |
tips.style.fontSize = '20px'; | |
} | |
}; | |
controller.init(); | |
document.addEventListener('DOMNodeInserted', function() { | |
controller.init(); | |
}); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment