Add Live Video Support, Update Electron, Update Mini Player

This commit is contained in:
PrestonN 2019-04-25 15:53:38 -04:00
parent e5fd7f6824
commit 896d33d434
10 changed files with 2235 additions and 1489 deletions

3040
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "FreeTube",
"productName": "FreeTube",
"version": "0.5.2",
"version": "0.5.3",
"description": "An Open Source YouTube app for privacy.",
"main": "src/js/init.js",
"scripts": {
@ -80,26 +80,26 @@
}
},
"devDependencies": {
"electron-forge": "^5.2.2",
"electron-forge-maker-appimage": "^20.28.3",
"electron-forge": "^5.2.4",
"electron-forge-maker-appimage": "^20.39.0",
"electron-installer-flatpak": "^0.8.0",
"electron-installer-snap": "^2.0.1",
"electron-prebuilt-compile": "3.0.2",
"electron-winstaller": "^2.7.0"
"electron-installer-snap": "^3.1.1",
"electron-prebuilt-compile": "4.0.0",
"electron-winstaller": "^3.0.4"
},
"dependencies": {
"autolinker": "^1.6.2",
"autolinker": "^3.0.5",
"commonjs": "0.0.1",
"dateformat": "^3.0.3",
"electron-compile": "6.4.2",
"electron-context-menu": "^0.10.0",
"electron-compile": "6.4.4",
"electron-context-menu": "^0.12.0",
"electron-squirrel-startup": "^1.0.0",
"jquery": "^3.3.1",
"jsdom": "^11.11.0",
"mustache": "^2.3.0",
"jquery": "^3.4.0",
"jsdom": "^15.0.0",
"mustache": "^3.0.1",
"nedb": "^1.8.0",
"opml-to-json": "0.0.3",
"vue": "^2.5.17",
"vue": "^2.6.10",
"ytdl-core": "^0.29.1"
}
}

View File

@ -128,12 +128,7 @@ let videoShortcutHandler = function (event) {
// F Key
event.preventDefault();
if (player.webkitDisplayingFullscreen) {
player.webkitExitFullscreen
}
else{
player.webkitRequestFullscreen();
}
$('.mejs__fullscreen-button').click();
break;
case 77:
// M Key
@ -230,11 +225,7 @@ let videoShortcutHandler = function (event) {
};
let fullscreenVideo = function (event) {
if (document.webkitFullscreenElement !== null) {
document.webkitExitFullscreen();
} else {
$('.videoPlayer').get(0).webkitRequestFullscreen();
}
$('.mejs__fullscreen-button').click();
}
/**
@ -247,7 +238,7 @@ $(document).on('click', '#showComments', showComments);
// $(document).on('click', '.videoPlayer', playPauseVideo);
// $(document).on('dblclick', '.videoPlayer', fullscreenVideo);
$(document).on('dblclick', '.videoPlayer', fullscreenVideo);
$(document).on('keydown', videoShortcutHandler);

View File

@ -44,7 +44,7 @@ app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required');
app.commandLine.appendSwitch('disable-web-security');
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
/*const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
// Someone tried to run a second instance, we should focus our window.
if (win) {
if (win.isMinimized()) win.restore()
@ -52,9 +52,9 @@ const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory)
win.webContents.send('ping', commandLine)
}
});
});*/
if (require('electron-squirrel-startup') || isSecondInstance) app.quit();
if (require('electron-squirrel-startup')) app.quit();
/**
* Initialize the Electron application

View File

@ -38,6 +38,8 @@ const shell = electron.shell; // Used to open external links into the user's nat
const clipboard = electron.clipboard;
const getOpml = require('opml-to-json'); // Gets the file type for imported files.
const fs = require('fs'); // Used to read files. Specifically in the settings page.
const url = require('url');
const path = require('path');
let dialog = electron.remote.dialog; // Used for opening file browser to export / import subscriptions.
let toastTimeout; // Timeout for toast notifications.

129
src/js/miniPlayer.js Normal file
View File

@ -0,0 +1,129 @@
/*
This file is part of FreeTube.
FreeTube is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FreeTube is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* A file for handling mini-player functionality
*/
import Vue from '../js/vue.js';
const electron = require('electron');
let mouseTimeout; // Timeout for hiding the mouse cursor on video playback
let checkedSettings = true;
let miniPlayerView = new Vue({
el: '#player',
data: {
video360p: '',
valid360p: true,
video720p: '',
valid720p: true,
videoAudio: '',
validAudio: true,
videoDash: '',
validDash: true,
videoLive: '',
validLive: false,
subtitleHtml: '',
videoThumbnail: '',
defaultPlaybackRate: '',
quality: '',
volume: '',
currentTime: '',
}
});
/**
* Hide the mouse cursor after ~3 seconds. Used to hide the video when the user
* hovers the mouse over the video player.
*
* @return {Void}
*/
function hideMouseTimeout() {
$('.videoPlayer')[0].style.cursor = 'default';
clearTimeout(mouseTimeout);
mouseTimeout = window.setTimeout(function () {
$('.videoPlayer')[0].style.cursor = 'none';
}, 2800);
}
/**
* Remove the timeout for the mouse cursor as a fallback.
*
* @return {Void}
*/
function removeMouseTimeout() {
$('.videoPlayer')[0].style.cursor = 'default';
clearTimeout(mouseTimeout);
}
function checkVideoSettings() {
if (checkedSettings === false) {
return;
}
let player = new MediaElementPlayer('player', {
features: ['playpause', 'current', 'loop', 'tracks', 'progress', 'duration', 'volume', 'stop', 'speed', 'quality', 'fullscreen'],
speeds: ['2', '1.75', '1.5', '1.25', '1', '0.75', '0.5', '0.25'],
defaultSpeed: miniPlayerView.defaultPlaybackRate,
qualityText: 'Quality',
defaultQuality: miniPlayerView.quality,
stretching: 'responsive',
startVolume: miniPlayerView.volume,
success: function(mediaElement, originalNode, instance) {
console.log(mediaElement,originalNode,instance);
instance.currentTime = miniPlayerView.currentTime;
instance.play();
checkedSettings = false;
/*if (autoplay) {
instance.play();
}
if (enableSubtitles) {
instance.options.startLanguage = 'en';
}*/
}
});
}
electron.ipcRenderer.on('ping', function(event, message) {
console.log(message);
miniPlayerView.video360p = message.video360p;
miniPlayerView.valid360p = message.valid360p;
miniPlayerView.video720p = message.video720p;
miniPlayerView.valid720p = message.valid720p;
miniPlayerView.videoAudio = message.videoAudio;
miniPlayerView.validAudio = message.validAudio;
miniPlayerView.videoDash = message.videoDash;
miniPlayerView.validDash = message.validDash;
miniPlayerView.videoLive = message.videoLive;
miniPlayerView.validLive = message.validLive;
miniPlayerView.subtitleHtml = message.subtitleHtml;
miniPlayerView.videoThumbnail = message.videoThumbnail;
miniPlayerView.defaultPlaybackRate = message.defaultPlaybackRate;
miniPlayerView.quality = message.quality;
miniPlayerView.volume = message.volume;
miniPlayerView.currentTime = message.currentTime;
window.setTimeout(checkVideoSettings, 100);
});

View File

@ -44,6 +44,8 @@ function playVideo(videoId, playlistId = '') {
playerView.video720p = undefined;
playerView.valid720p = true;
playerView.videoUrl = '';
playerView.videoLive = undefined;
playerView.validLive = false;
playerView.validDash = true;
playerView.videoDash = invidiousInstance + '/api/manifest/dash/' + videoId + '.mpd';
playerView.embededHtml = "<iframe width='560' height='315' src='https://www.youtube-nocookie.com/embed/" + videoId + "?rel=0' frameborder='0' allow='autoplay; encrypted-media' allowfullscreen></iframe>";
@ -69,69 +71,91 @@ function playVideo(videoId, playlistId = '') {
console.log(data);
let videoUrls = data.formats;
let formatUrls = data.player_response.streamingData.adaptiveFormats;
// Search through the returned object to get the 360p and 720p video URLs (If available)
Object.keys(videoUrls).forEach((key) => {
switch (videoUrls[key]['itag']) {
case '18':
playerView.video360p = decodeURIComponent(videoUrls[key]['url']);
// console.log(playerView.video360p);
break;
case '22':
playerView.video720p = decodeURIComponent(videoUrls[key]['url']);
// console.log(playerView.video720p);
break;
}
});
if (data.player_response.videoDetails.isLiveContent !== false) {
playerView.validDash = false;
playerView.valid360p = false;
playerView.valid720p = false;
playerView.validAudio = false;
// Last adaptive format will be best the quality audio stream (migrate fully to adaptive formats later)
playerView.videoAudio = decodeURIComponent(formatUrls[formatUrls.length - 1]['url']);
playerView.validLive = true;
if (typeof (playerView.videoAudio) === 'undefined') {
console.log(playerView.videoAudio);
playerView.validAudio = false;
youtubedlFinished = true;
if (youtubedlFinished && invidiousFinished) {
loadingView.seen = false;
if (subscriptionView.seen === false && aboutView.seen === false && headerView.seen === false && searchView.seen === false && settingsView.seen === false && popularView.seen === false && savedView.seen === false && historyView.seen === false && channelView.seen === false && channelVideosView.seen === false) {
playerView.seen = true;
} else {
return;
}
}
}
else {
playerView.validLive = false;
let useEmbedPlayer = false;
// Search through the returned object to get the 360p and 720p video URLs (If available)
Object.keys(videoUrls).forEach((key) => {
switch (videoUrls[key]['itag']) {
case '18':
playerView.video360p = decodeURIComponent(videoUrls[key]['url']);
// console.log(playerView.video360p);
break;
case '22':
playerView.video720p = decodeURIComponent(videoUrls[key]['url']);
// console.log(playerView.video720p);
break;
}
});
// Default to the embeded player if the URLs cannot be found.
if (typeof (playerView.video720p) === 'undefined' && typeof (playerView.video360p) === 'undefined') {
//useEmbedPlayer = true;
playerView.currentQuality = 'EMBED';
playerView.playerSeen = false;
playerView.valid720p = false;
playerView.valid360p = false;
playerView.video720p = '';
//useEmbedPlayer = true;
showToast('Unable to get video file. Reverting to embeded player.');
} else if (typeof (playerView.video720p) === 'undefined' && typeof (playerView.video360p) !== 'undefined') {
// Default to the 360p video if the 720p URL cannot be found.
console.log('Found');
playerView.videoUrl = playerView.video360p;
playerView.currentQuality = '360p';
playerView.valid720p = false;
playerView.video720p = '';
} else {
// Default to the 720p video.
playerView.videoUrl = playerView.video720p;
playerView.currentQuality = '720p';
//playerView.videoUrl = playerView.liveManifest;
// Last adaptive format will be best the quality audio stream (migrate fully to adaptive formats later)
playerView.videoAudio = decodeURIComponent(videoUrls[videoUrls.length - 1]['url']);
if (typeof (playerView.videoAudio) === 'undefined') {
console.log(playerView.videoAudio);
playerView.validAudio = false;
}
let useEmbedPlayer = false;
// Default to the embeded player if the URLs cannot be found.
if (typeof (playerView.video720p) === 'undefined' && typeof (playerView.video360p) === 'undefined') {
//useEmbedPlayer = true;
playerView.currentQuality = 'EMBED';
playerView.playerSeen = false;
playerView.valid720p = false;
playerView.valid360p = false;
playerView.video720p = '';
//useEmbedPlayer = true;
showToast('Unable to get video file. Reverting to embeded player.');
} else if (typeof (playerView.video720p) === 'undefined' && typeof (playerView.video360p) !== 'undefined') {
// Default to the 360p video if the 720p URL cannot be found.
console.log('Found');
playerView.videoUrl = playerView.video360p;
playerView.currentQuality = '360p';
playerView.valid720p = false;
playerView.video720p = '';
} else {
// Default to the 720p video.
playerView.videoUrl = playerView.video720p;
playerView.currentQuality = '720p';
//playerView.videoUrl = playerView.liveManifest;
}
if (!useEmbedPlayer &&
typeof (data.player_response.captions) !== 'undefined' &&
typeof (data.player_response.captions.playerCaptionsTracklistRenderer) !== 'undefined' &&
typeof (data.player_response.captions.playerCaptionsTracklistRenderer.captionTracks) !== 'undefined') {
data.player_response.captions.playerCaptionsTracklistRenderer.captionTracks.forEach((caption) => {
let subtitleUrl = invidiousInstance + '/api/v1/captions/' + videoId + '?label=' + caption.name.simpleText;
videoHtml = videoHtml + '<track kind="subtitles" src="' + subtitleUrl + '" srclang="' + caption.languageCode + '" label="' + caption.name.simpleText + '">';
});
playerView.subtitleHtml = videoHtml;
}
}
if (!useEmbedPlayer &&
typeof (data.player_response.captions) !== 'undefined' &&
typeof (data.player_response.captions.playerCaptionsTracklistRenderer) !== 'undefined' &&
typeof (data.player_response.captions.playerCaptionsTracklistRenderer.captionTracks) !== 'undefined') {
data.player_response.captions.playerCaptionsTracklistRenderer.captionTracks.forEach((caption) => {
let subtitleUrl = invidiousInstance + '/api/v1/captions/' + videoId + '?label=' + caption.name.simpleText;
videoHtml = videoHtml + '<track kind="subtitles" src="' + subtitleUrl + '" srclang="' + caption.languageCode + '" label="' + caption.name.simpleText + '">';
});
playerView.subtitleHtml = videoHtml;
}
youtubedlFinished = true;
if (youtubedlFinished && invidiousFinished) {
@ -272,6 +296,11 @@ function playVideo(videoId, playlistId = '') {
}
}
if (data.liveNow !== false) {
playerView.validLive = true;
playerView.videoLive = data.hlsUrl;
}
if (playlistId != '') {
playerView.playlistSeen = true;
playerView.playlistShowList = true;
@ -363,12 +392,12 @@ function openMiniPlayer() {
let videoHtml;
// Grabs whatever the HTML is for the current video player. Done this way to grab
// the HTML5 player (with varying qualities) as well as the YouTube embeded player.
if ($('.videoPlayer').length > 0) {
$('.videoPlayer').get(0).pause();
lastTime = $('.videoPlayer').get(0).currentTime;
videoHtml = $('.videoPlayer').get(0).outerHTML;
if (typeof(player) !== 'undefined') {
player.pause();
lastTime = player.currentTime;
//videoHtml = $('.videoPlayer').get(0).outerHTML;
} else {
videoHtml = $('iframe').get(0).outerHTML;
//videoHtml = $('iframe').get(0).outerHTML;
}
// Create a new browser window.
@ -377,11 +406,45 @@ function openMiniPlayer() {
let miniPlayer = new BrowserWindow({
width: 1200,
height: 710,
show: false,
title: 'FreeTube Mini-Player: ' + playerView.videoTitle,
autoHideMenuBar: true
});
miniPlayer.loadURL(url.format({
pathname: path.join(__dirname, '/templates/miniPlayer.html'),
protocol: 'file:',
slashes: true,
}));
miniPlayer.once('ready-to-show', () => {
miniPlayer.show();
let playerData = {
video360p: playerView.video360p,
valid360p: playerView.valid360p,
video720p: playerView.video720p,
valid720p: playerView.valid720p,
videoAudio: playerView.videoAudio,
validAudio: playerView.validAudio,
videoDash: playerView.videoDash,
validDash: playerView.validDash,
videoLive: playerView.videoLive,
validLive: playerView.validLive,
subtitleHtml: playerView.subtitleHtml,
videoThumbnail: playerView.videoThumbnail,
defaultPlaybackRate: player.options.defaultSpeed,
quality: player.options.defaultQuality,
volume: player.volume,
currentTime: player.currentTime,
};
miniPlayer.webContents.send('ping', playerData);
})
return;
// Use the miniPlayer.html template.
$.get('templates/miniPlayer.html', (template) => {
/*$.get('templates/miniPlayer.html', (template) => {
mustache.parse(template);
const rendered = mustache.render(template, {
videoUrl: playerView.videoUrl,
@ -390,7 +453,7 @@ function openMiniPlayer() {
});
// Render the template to the new browser window.
miniPlayer.loadURL("data:text/html;charset=utf-8," + encodeURI(rendered));
});
});*/
}
/**
@ -545,13 +608,17 @@ function checkVideoSettings() {
else {
quality = '360p';
}
break;
default:
break;
}
if (playerView.validLive) {
quality = 'Live';
}
let player = new MediaElementPlayer('player', {
features: ['playpause', 'current', 'loop', 'tracks', 'progress', 'duration', 'volume', 'stop', 'speed', 'quality', 'fullscreen'],
speeds: ['2', '1.75', '1.5', '1.25', '1', '0.75', '0.5', '0.25'],
defaultSpeed: defaultPlaybackRate,
qualityText: 'Quality',
@ -582,6 +649,7 @@ function checkVideoSettings() {
}
else {
checked360p = true;
declarePlayer();
}
if (playerView.valid720p !== false) {
@ -593,6 +661,7 @@ function checkVideoSettings() {
}
else {
checked720p = true;
declarePlayer();
}
if (playerView.validAudio !== false) {
@ -604,6 +673,7 @@ function checkVideoSettings() {
}
else {
checkedAudio = true;
declarePlayer();
}
if (playerView.validDash !== false) {
@ -615,6 +685,7 @@ function checkVideoSettings() {
}
else {
checkedDash = true;
declarePlayer();
}
return;

View File

@ -539,7 +539,6 @@ let playerView = new Vue({
firstLoad: true,
publishedDate: '',
videoUrl: '',
videoDash: '',
videoId: '',
channelId: '',
channelIcon: '',
@ -557,7 +556,10 @@ let playerView = new Vue({
valid360p: false,
video720p: '',
valid720p: false,
videoDash: '',
validDash: true,
videoLive: '',
validLive: false,
embededHtml: '',
currentSpeed: 1,
videoTitle: '',
@ -606,8 +608,8 @@ let playerView = new Vue({
}
},
embededPlayer: () => {
playerView.playerSeen = false;
playerView.currentQuality = 'EMBED';
playerView.playerSeen = !playerView.playerSeen;
checkedSettings = false;
},
copy: (site, videoId) => {
const url = 'https://' + site + '/watch?v=' + videoId;

View File

@ -15,279 +15,38 @@
along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
-->
<title>Freetube Mini-Player</title>
<style>
body {
background-color: #424242;
}
.videoPlayer {
width: 100%;
}
iframe {
width: 100%;
height: 54.9vw;
#player {
min-height: 480px;
}
</style>
<script>
window.$ = window.jQuery = require('jquery');
let startTime = '{{startTime}}';
let mouseTimeout;
$('.videoPlayer').ready(() => {
$('.videoPlayer').get(0).currentTime = startTime;
$('.videoPlayer').get(0).play();
});
/**
* Handle keyboard shortcut commands.
*/
let videoShortcutHandler = function (event) {
if (event.which == 68 && event.altKey === true) {
$('#search').focus();
}
if (event.which == 82 && event.shiftKey === false && event.ctrlKey === true && !$('#jumpToInput').is(':focus') && !$('#search').is(':focus')) {
event.stopPropagation();
event.preventDefault();
forceSubscriptions();
}
let videoPlayer = $('.videoPlayer').get(0);
if (typeof (videoPlayer) !== 'undefined' && !$('#jumpToInput').is(':focus') && !$('#search').is(':focus')) {
switch (event.which) {
case 32:
// Space Bar
event.preventDefault();
videoPlayer.paused ? videoPlayer.play() : videoPlayer.pause();
break;
case 74:
// J Key
event.preventDefault();
changeDurationBySeconds(-10);
break;
case 75:
// K Key
event.preventDefault();
videoPlayer.paused ? videoPlayer.play() : videoPlayer.pause();
break;
case 76:
// L Key
event.preventDefault();
changeDurationBySeconds(10);
break;
case 79:
// O Key
event.preventDefault();
if (videoPlayer.playbackRate > 0.25){
let rate = videoPlayer.playbackRate - 0.25;
videoPlayer.playbackRate = rate;
$('#currentSpeed').html(rate);
}
break;
case 80:
// P Key
event.preventDefault();
if (videoPlayer.playbackRate < 2){
let rate = videoPlayer.playbackRate + 0.25;
videoPlayer.playbackRate = rate;
$('#currentSpeed').html(rate);
}
break;
case 70:
// F Key
event.preventDefault();
if (videoPlayer.webkitDisplayingFullscreen) {
videoPlayer.webkitExitFullscreen
}
else{
videoPlayer.webkitRequestFullscreen();
}
break;
case 77:
// M Key
event.preventDefault();
let volume = videoPlayer.volume;
if (volume > 0) {
changeVolume(-1);
} else {
changeVolume(1);
}
break;
case 67:
// C Key
let subtitleMode = $('.videoPlayer').get(0).textTracks[0].mode;
if (subtitleMode === 'hidden') {
$('.videoPlayer').get(0).textTracks[0].mode = 'showing'
} else {
$('.videoPlayer').get(0).textTracks[0].mode = 'hidden'
}
break;
case 38:
// Up Arrow Key
event.preventDefault();
changeVolume(0.05);
break;
case 40:
// Down Arrow Key
event.preventDefault();
changeVolume(-0.05);
break;
case 37:
// Left Arrow Key
event.preventDefault();
changeDurationBySeconds(-5);
break;
case 39:
// Right Arrow Key
event.preventDefault();
changeDurationBySeconds(5);
break;
case 49:
// 1 Key
event.preventDefault();
changeDurationByPercentage(0.1);
break;
case 50:
// 2 Key
event.preventDefault();
changeDurationByPercentage(0.2);
break;
case 51:
// 3 Key
event.preventDefault();
changeDurationByPercentage(0.3);
break;
case 52:
// 4 Key
event.preventDefault();
changeDurationByPercentage(0.4);
break;
case 53:
// 5 Key
event.preventDefault();
changeDurationByPercentage(0.5);
break;
case 54:
// 6 Key
event.preventDefault();
changeDurationByPercentage(0.6);
break;
case 55:
// 7 Key
event.preventDefault();
changeDurationByPercentage(0.7);
break;
case 56:
// 8 Key
event.preventDefault();
changeDurationByPercentage(0.8);
break;
case 57:
// 9 Key
event.preventDefault();
changeDurationByPercentage(0.9);
break;
case 48:
// 0 Key
event.preventDefault();
changeDurationByPercentage(0);
break;
}
}
};
let fullscreenVideo = function (event) {
if (document.webkitFullscreenElement !== null) {
document.webkitExitFullscreen();
} else {
$('.videoPlayer').get(0).webkitRequestFullscreen();
}
}
/**
* Change the volume of the video player
*
* @param {double} amount - The volume to increase or descrease the volume by. Will be any double between 0 and 1.
*
* @return {Void}
*/
function changeVolume(amount) {
const videoPlayer = $('.videoPlayer').get(0);
let volume = videoPlayer.volume;
volume = volume + amount;
if (volume > 1) {
videoPlayer.volume = 1;
} else if (volume < 0) {
videoPlayer.volume = 0;
} else {
videoPlayer.volume = volume;
}
}
/**
* Change the duration of a video by a percentage of the duration.
*
* @param {double} percentage - The percentage to hop to of the video. Will be any double between 0 and 1.
*
* @return {Void}
*/
function changeDurationByPercentage(percentage) {
const videoPlayer = $('.videoPlayer').get(0);
videoPlayer.currentTime = videoPlayer.duration * percentage;
}
/**
* Change the duration of the current time of a video by a few seconds.
*
* @param {integer} seconds - The amount of seconds to change the video by. Integer may be positive or negative.
*
* @return {Void}
*/
function changeDurationBySeconds(seconds) {
const videoPlayer = $('.videoPlayer').get(0);
videoPlayer.currentTime = videoPlayer.currentTime + seconds;
}
/**
* Hide the mouse cursor after ~3 seconds. Used to hide the video when the user
* hovers the mouse over the video player.
*
* @return {Void}
*/
function hideMouseTimeout() {
$('.videoPlayer')[0].style.cursor = 'default';
clearTimeout(mouseTimeout);
mouseTimeout = window.setTimeout(function() {
$('.videoPlayer')[0].style.cursor = 'none';
}, 3150);
}
/**
* Remove the timeout for the mouse cursor as a fallback.
*
* @return {Void}
*/
function removeMouseTimeout() {
$('.videoPlayer')[0].style.cursor = 'default';
clearTimeout(mouseTimeout);
}
let playPauseVideo = function(event) {
let el = event.currentTarget;
el.paused ? el.play() : el.pause();
}
$(document).on('click', '.videoPlayer', playPauseVideo);
$(document).on('mouseover', '.videoPlayer', hideMouseTimeout);
$(document).on('mouseleave', '.videoPlayer', removeMouseTimeout);
$(document).on('dblclick', '.videoPlayer', fullscreenVideo);
$(document).on('keydown', videoShortcutHandler);
</script>
<video class="videoPlayer" id='videoPlayer' type="application/x-mpegURL" object-fit='cover' onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" controls="" src='{{videoUrl}}' poster='{{videoThumbnail}}' autoplay="autoplay">
<link rel="stylesheet" href="../style/mediaelementplayer.css" />
<link rel="stylesheet" href="../js/plugins/quality/quality.min.css" />
<link rel="stylesheet" href="../js/plugins/loop/loop.css" />
<link rel="stylesheet" href="../js/plugins/speed/speed.css" />
<link rel="stylesheet" href="../js/plugins/context-menu/context-menu.css" />
<video id='player' class='videoPlayer' onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" :poster="videoThumbnail" onvolumechange='updateVolume()'>
<source v-if='valid360p' data-quality='360p' type="video/mp4" :src="video360p" />
<source v-if='valid720p' data-quality='720p' type="video/mp4" :src="video720p" />
<source v-if='validAudio' data-quality='Audio' type="audio/mp4" :src="videoAudio" />
<source v-if='validDash' data-quality='Auto' type="application/dash+xml" :src="videoDash" />
<source v-if='validLive' data-quality='Live' type="application/x-mpegURL" :src="videoLive" />
<span v-html="subtitleHtml"></span>
</video>
<script>window.$ = window.jQuery = require('jquery');</script>
<script src="../js/mediaelement-and-player.min.js"></script>
<script src="../js/plugins/quality/quality.min.js"></script>
<script src="../js/plugins/quality/quality-i18n.js"></script>
<script src="../js/plugins/speed/speed.js"></script>
<script src="../js/plugins/speed/speed-i18n.js"></script>
<script src="../js/plugins/loop/loop.js"></script>
<script src="../js/plugins/loop/loop-i18n.js"></script>
<script src="../js/plugins/context-menu/context-menu.js"></script>
<script src="../js/plugins/context-menu/context-menu-i18n.js"></script>
<script src="../js/miniPlayer.js"></script>
<script src="../js/events.js"></script>

View File

@ -4,7 +4,8 @@
<source v-if='valid360p' data-quality='360p' type="video/mp4" :src="video360p" />
<source v-if='valid720p' data-quality='720p' type="video/mp4" :src="video720p" />
<source v-if='validAudio' data-quality='Audio' type="audio/mp4" :src="videoAudio" />
<source data-quality='Auto' type="application/dash+xml" :src="videoDash" />
<source v-if='validDash' data-quality='Auto' type="application/dash+xml" :src="videoDash" />
<source v-if='validLive' data-quality='Live' type="application/x-mpegURL" :src="videoLive" />
<span v-html="subtitleHtml"></span>
</video>
<!--<video class="videoPlayer" id='videoPlayer' type="application/x-mpegURL" object-fit='cover' onmousemove="hideMouseTimeout()" onmouseleave="removeMouseTimeout()" onloadstart='checkVideoSettings()' onvolumechange='updateVolume()' controls="" onended='playNextVideo()' :src='videoUrl' :poster="videoThumbnail" v-html="subtitleHtml">
@ -17,6 +18,9 @@
<div onclick='openMiniPlayer()' class='smallButton' >
MINI PLAYER <i class="fas fa-external-link-alt"></i>
</div>
<div v-on:click='embededPlayer' class='smallButton' >
TOGGLE EMBEDDED
</div>
<div class='smallButton' v-on:click='save(videoId)'>
<i id='saveIcon' :class='savedIconType' class="fa-star"></i> <span id='savedText'>{{savedText}}</span>
</div>