New player controls, css changes, big fixes
This commit is contained in:
parent
c7e76533ec
commit
59c2d0860f
@ -2,11 +2,10 @@
|
|||||||
import os, json, secrets
|
import os, json, secrets
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
from flask_oidc import OpenIDConnect
|
from flask_oidc import OpenIDConnect
|
||||||
from flask_login import current_user, login_user, logout_user, LoginManager
|
|
||||||
from flask_bcrypt import Bcrypt
|
|
||||||
|
|
||||||
|
|
||||||
# Apoplication imports
|
# Apoplication imports
|
||||||
@ -41,9 +40,6 @@ app.config.update({
|
|||||||
'OIDC_TOKEN_TYPE_HINT': 'access_token'
|
'OIDC_TOKEN_TYPE_HINT': 'access_token'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
login_manager = LoginManager(app)
|
|
||||||
bcrypt = Bcrypt(app)
|
|
||||||
oidc = OpenIDConnect(app)
|
oidc = OpenIDConnect(app)
|
||||||
def oidc_loggedin():
|
def oidc_loggedin():
|
||||||
return oidc.user_loggedin
|
return oidc.user_loggedin
|
||||||
@ -66,9 +62,7 @@ def retrieveSettings():
|
|||||||
config = retrieveSettings()
|
config = retrieveSettings()
|
||||||
|
|
||||||
|
|
||||||
from .forms import LoginForm, RegisterForm
|
from .models import db, Favorites, Settings
|
||||||
from .models import db, Favorites, Settings, User
|
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
with app.app_context(): db.create_all()
|
with app.app_context(): db.create_all()
|
||||||
from webfm import routes
|
from webfm import routes
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField, SubmitField
|
from wtforms import StringField, PasswordField, SubmitField
|
||||||
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
|
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
|
||||||
from .models import User
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -14,12 +13,4 @@ class RegisterForm(FlaskForm):
|
|||||||
submit = SubmitField("Sign Up")
|
submit = SubmitField("Sign Up")
|
||||||
|
|
||||||
def validate_username(self, username):
|
def validate_username(self, username):
|
||||||
user = User.query.filter_by(username=username.data).first()
|
pass
|
||||||
if user:
|
|
||||||
raise ValidationError("User exists already! Please use a different name!")
|
|
||||||
|
|
||||||
|
|
||||||
class LoginForm(FlaskForm):
|
|
||||||
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
|
|
||||||
password = PasswordField('Password', validators=[DataRequired(), Length(min=8, max=32)])
|
|
||||||
submit = SubmitField("Login")
|
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
# System imports
|
# System imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask_login.mixins import UserMixin
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from . import app, login_manager
|
from . import app
|
||||||
|
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
@login_manager.user_loader
|
|
||||||
def load_user(user_id):
|
|
||||||
return User.query.get(int(user_id))
|
|
||||||
|
|
||||||
|
|
||||||
class Favorites(db.Model):
|
class Favorites(db.Model):
|
||||||
link = db.Column(db.String, nullable=False, unique=True)
|
link = db.Column(db.String, nullable=False, unique=True)
|
||||||
@ -22,19 +17,10 @@ class Favorites(db.Model):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"['{self.link}', '{self.id}']"
|
return f"['{self.link}', '{self.id}']"
|
||||||
|
|
||||||
class Settings(db.Model, UserMixin):
|
class Settings(db.Model):
|
||||||
key = db.Column(db.String, nullable=False)
|
key = db.Column(db.String, nullable=False)
|
||||||
value = db.Column(db.String, nullable=False)
|
value = db.Column(db.String, nullable=False)
|
||||||
id = db.Column(db.Integer, nullable=False, primary_key=True, unique=True, autoincrement=True)
|
id = db.Column(db.Integer, nullable=False, primary_key=True, unique=True, autoincrement=True)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return f"['{self.key}', '{self.value}', '{self.id}']"
|
return f"['{self.key}', '{self.value}', '{self.id}']"
|
||||||
|
|
||||||
|
|
||||||
class User(db.Model, UserMixin):
|
|
||||||
username = db.Column(db.String, unique=True, nullable=False)
|
|
||||||
password = db.Column(db.String, nullable=False)
|
|
||||||
id = db.Column(db.Integer, primary_key=True, unique=True, autoincrement=True)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return f"['{self.username}', '{self.email}', '{self.password}', '{self.id}']"
|
|
||||||
|
@ -22,20 +22,20 @@
|
|||||||
|
|
||||||
#file-grid {
|
#file-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(14em, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(22em, 1fr));
|
||||||
grid-column-gap: 1em;
|
grid-column-gap: 1em;
|
||||||
grid-row-gap: 1em;
|
grid-row-gap: 1em;
|
||||||
margin: 2em auto;
|
margin: 2em auto;
|
||||||
width: 85%;
|
width: 85%;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: 25em;
|
height: 80vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
#path { max-width: inherit; }
|
#path { max-width: inherit; }
|
||||||
#faves-list > li { width: 100%; }
|
#faves-list > li { width: 100%; }
|
||||||
|
|
||||||
#video-container {
|
#video-container {
|
||||||
width: 30em;
|
width: inherit;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +56,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#volumeIcon {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: thin;
|
||||||
|
border-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
#volumeIcon:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* CLASSES */
|
/* CLASSES */
|
||||||
.scroller {
|
.scroller {
|
||||||
@ -63,6 +73,13 @@
|
|||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.volume-control-positioner {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 2em;
|
||||||
|
right: 50%;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.dir-style, .video-style, .file-style {
|
.dir-style, .video-style, .file-style {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -84,6 +101,7 @@
|
|||||||
|
|
||||||
.image-style,
|
.image-style,
|
||||||
.video-style {
|
.video-style {
|
||||||
|
position: relative;
|
||||||
min-height: 6.5em;
|
min-height: 6.5em;
|
||||||
width: auto;
|
width: auto;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -151,7 +169,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.video-title {
|
.video-title {
|
||||||
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
left: 0em;
|
||||||
|
bottom: 1em;
|
||||||
margin-top: 5.5em;
|
margin-top: 5.5em;
|
||||||
background-color: rgba(0, 0, 0, 0.64);
|
background-color: rgba(0, 0, 0, 0.64);
|
||||||
color: rgb(255, 255, 255);
|
color: rgb(255, 255, 255);
|
||||||
|
@ -1,9 +1,20 @@
|
|||||||
|
/* Vertical slider */
|
||||||
|
input[type=range][orient=vertical] {
|
||||||
|
writing-mode: bt-lr; /* IE */
|
||||||
|
-webkit-appearance: slider-vertical; /* WebKit */
|
||||||
|
width: 8px;
|
||||||
|
height: 175px;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#video-container::-webkit-media-controls {
|
#video-container::-webkit-media-controls {
|
||||||
display:none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#video-container::-webkit-media-controls-enclosure {
|
#video-container::-webkit-media-controls-enclosure {
|
||||||
display:none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +43,13 @@ const doAjax = (actionPath, data, action) => {
|
|||||||
// xhttp.open("POST", formatURL(actionPath), true);
|
// xhttp.open("POST", formatURL(actionPath), true);
|
||||||
xhttp.open("POST", actionPath, true);
|
xhttp.open("POST", actionPath, true);
|
||||||
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
|
if (action === "list-files") {
|
||||||
|
xhttp.setRequestHeader("Cache-Control", "no-cache, no-store");
|
||||||
|
xhttp.setRequestHeader("Pragma", "no-cache");
|
||||||
|
xhttp.setRequestHeader("Expires", "0");
|
||||||
|
}
|
||||||
|
|
||||||
// Force return to be JSON NOTE: Use application/xml to force XML
|
// Force return to be JSON NOTE: Use application/xml to force XML
|
||||||
xhttp.overrideMimeType('application/json');
|
xhttp.overrideMimeType('application/json');
|
||||||
xhttp.send(data);
|
xhttp.send(data);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
let fullScreenState = 0;
|
let fullScreenState = 0;
|
||||||
let shouldPlay = null;
|
|
||||||
let clicktapwait = 200;
|
let clicktapwait = 200;
|
||||||
|
let shouldPlay = null;
|
||||||
|
let controlsTimeout = null;
|
||||||
|
let canHideControls = true;
|
||||||
|
|
||||||
|
|
||||||
document.body.onload = (eve) => {
|
document.body.onload = (eve) => {
|
||||||
@ -21,102 +23,6 @@ document.body.onload = (eve) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function togglePlay(video) {
|
|
||||||
shouldPlay = setTimeout(function () {
|
|
||||||
shouldPlay = null;
|
|
||||||
if (video.paused) {
|
|
||||||
video.play();
|
|
||||||
} else {
|
|
||||||
video.pause();
|
|
||||||
}
|
|
||||||
}, 300);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleFullscreen(video) {
|
|
||||||
containerElm = document.getElementById("video-container");
|
|
||||||
parentElm = video.parentElement;
|
|
||||||
|
|
||||||
|
|
||||||
if (video.requestFullscreen) {
|
|
||||||
parentElm.requestFullscreen();
|
|
||||||
containerElm.style.display = "block";
|
|
||||||
} else if (video.webkitRequestFullscreen) { /* Safari */
|
|
||||||
parentElm.webkitRequestFullscreen();
|
|
||||||
containerElm.style.display = "block";
|
|
||||||
} else if (video.msRequestFullscreen) { /* IE11 */
|
|
||||||
parentElm.msRequestFullscreen();
|
|
||||||
containerElm.style.display = "block";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fullScreenState == 2) {
|
|
||||||
if (document.exitFullscreen) {
|
|
||||||
document.exitFullscreen();
|
|
||||||
containerElm.style.display = "contents";
|
|
||||||
} else if (document.webkitExitFullscreen) { /* Safari */
|
|
||||||
document.webkitExitFullscreen();
|
|
||||||
containerElm.style.display = "contents";
|
|
||||||
} else if (document.msExitFullscreen) { /* IE11 */
|
|
||||||
document.msExitFullscreen();
|
|
||||||
containerElm.style.display = "contents";
|
|
||||||
}
|
|
||||||
|
|
||||||
fullScreenState = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fullScreenState += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#video-viewer").on("click", function(eve){
|
|
||||||
const video = eve.target;
|
|
||||||
|
|
||||||
if(!shouldPlay) {
|
|
||||||
shouldPlay = setTimeout( function() {
|
|
||||||
shouldPlay = null;
|
|
||||||
togglePlay(video);
|
|
||||||
}, clicktapwait);
|
|
||||||
} else {
|
|
||||||
clearTimeout(shouldPlay); // Stop single tap callback
|
|
||||||
shouldPlay = null;
|
|
||||||
toggleFullscreen(video);
|
|
||||||
}
|
|
||||||
eve.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
$("#video-viewer").on("touchend", function(eve){
|
|
||||||
const video = eve.target;
|
|
||||||
|
|
||||||
if(!shouldPlay) {
|
|
||||||
shouldPlay = setTimeout( function() {
|
|
||||||
shouldPlay = null;
|
|
||||||
togglePlay(video);
|
|
||||||
}, clicktapwait);
|
|
||||||
} else {
|
|
||||||
clearTimeout(shouldPlay); // Stop single tap callback
|
|
||||||
shouldPlay = null;
|
|
||||||
toggleFullscreen(video);
|
|
||||||
}
|
|
||||||
eve.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
$( "#video-viewer" ).bind( "timeupdate", async function(eve) {
|
|
||||||
const video = eve.target;
|
|
||||||
const seekto = document.getElementById("seek-slider");
|
|
||||||
const vt = video.currentTime * (100 / video.duration);
|
|
||||||
seekto.value = vt;
|
|
||||||
});
|
|
||||||
|
|
||||||
$( "#seek-slider" ).bind( "change", async function(eve) {
|
|
||||||
const slider = eve.target;
|
|
||||||
let video = document.getElementById("video-viewer");
|
|
||||||
let seekto = video.duration * (slider.value / 100);
|
|
||||||
video.currentTime = seekto;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$( "#search-files-field" ).bind( "keyup", async function(eve) {
|
$( "#search-files-field" ).bind( "keyup", async function(eve) {
|
||||||
searchPage();
|
searchPage();
|
||||||
});
|
});
|
||||||
|
@ -72,7 +72,8 @@ const updateHTMLDirList = async (data) => {
|
|||||||
|
|
||||||
// Setup background if there is a 000.* in selection
|
// Setup background if there is a 000.* in selection
|
||||||
if (background_image.match(/000\.(jpg|png|gif)\b/) != null) {
|
if (background_image.match(/000\.(jpg|png|gif)\b/) != null) {
|
||||||
background_image = formatURL("files/" + images[i][1]);
|
// Due to same hash for 000 we add date to make link unique for each run to bypass cache issues...
|
||||||
|
background_image = formatURL("files/" + images[i][1] + '?d=' + Date.now());
|
||||||
updateBackground(background_image, false);
|
updateBackground(background_image, false);
|
||||||
} else {
|
} else {
|
||||||
background_image = formatURL("static/imgs/backgrounds/particles.mp4");
|
background_image = formatURL("static/imgs/backgrounds/particles.mp4");
|
||||||
@ -119,7 +120,7 @@ const updateHTMLDirList = async (data) => {
|
|||||||
hash = images[i][1];
|
hash = images[i][1];
|
||||||
|
|
||||||
if (thumbnail.match(/000\.(jpg|png|gif)\b/) == null &&
|
if (thumbnail.match(/000\.(jpg|png|gif)\b/) == null &&
|
||||||
!thumbnail.includes("favicon.png")) {
|
!thumbnail.includes("favicon.png") && !thumbnail.includes("000")) {
|
||||||
const clone = imgClone.cloneNode(true);
|
const clone = imgClone.cloneNode(true);
|
||||||
createElmBlock(insertArea, clone, thumbnail, title, hash);
|
createElmBlock(insertArea, clone, thumbnail, title, hash);
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,9 @@ const scrollFilesToTop = () => {
|
|||||||
const showMedia = async (hash, extension, type) => {
|
const showMedia = async (hash, extension, type) => {
|
||||||
document.getElementById("image-viewer").style.display = "none";
|
document.getElementById("image-viewer").style.display = "none";
|
||||||
document.getElementById("text-viewer").style.display = "none";
|
document.getElementById("text-viewer").style.display = "none";
|
||||||
document.getElementById("video-viewer").style.display = "none";
|
|
||||||
document.getElementById("pdf-viewer").style.display = "none";
|
document.getElementById("pdf-viewer").style.display = "none";
|
||||||
|
document.getElementById("video-viewer").style.display = "none";
|
||||||
|
document.getElementById("video-controls").style.display = "none";
|
||||||
|
|
||||||
if (type === "video") {
|
if (type === "video") {
|
||||||
setupVideo(hash, extension);
|
setupVideo(hash, extension);
|
||||||
@ -34,9 +35,10 @@ const showMedia = async (hash, extension, type) => {
|
|||||||
|
|
||||||
const setupVideo = async (hash, extension) => {
|
const setupVideo = async (hash, extension) => {
|
||||||
let video = document.getElementById("video-viewer");
|
let video = document.getElementById("video-viewer");
|
||||||
|
let controls = document.getElementById("video-controls");
|
||||||
video.poster = "static/imgs/icons/loading.gif";
|
video.poster = "static/imgs/icons/loading.gif";
|
||||||
video.autoplay = true;
|
|
||||||
video.style.display = "";
|
video.style.display = "";
|
||||||
|
video.src = "#"
|
||||||
video_path = "files/" + hash;
|
video_path = "files/" + hash;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -46,7 +48,7 @@ const setupVideo = async (hash, extension) => {
|
|||||||
if ( data.hasOwnProperty('path') ) {
|
if ( data.hasOwnProperty('path') ) {
|
||||||
video_path = data.path;
|
video_path = data.path;
|
||||||
} else {
|
} else {
|
||||||
displayMessage(data.message.text, data.message.type)
|
displayMessage(data.message.text, data.message.type);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
} else if ((/\.(flv|mov|m4v|mpg|mpeg)$/i).test(extension)) {
|
} else if ((/\.(flv|mov|m4v|mpg|mpeg)$/i).test(extension)) {
|
||||||
@ -56,19 +58,20 @@ const setupVideo = async (hash, extension) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((/\.(flv|f4v)$/i).test(extension)) {
|
|
||||||
$('#file-view-modal').modal({"focus": true, "show": true});
|
$('#file-view-modal').modal({"focus": true, "show": true});
|
||||||
|
controls.style.display = "none";
|
||||||
video.src = video_path;
|
video.src = video_path;
|
||||||
} else {
|
// if ((/\.(flv|f4v)$/i).test(extension)) {
|
||||||
// This is questionable in usage since it loads the full video before
|
// video.src = video_path;
|
||||||
|
// } else {
|
||||||
|
// // This is questionable in usage since it loads the full video before
|
||||||
// showing; but, seeking doesn't work otherwise...
|
// showing; but, seeking doesn't work otherwise...
|
||||||
$('#file-view-modal').modal({"focus": true, "show": true});
|
// let response = await fetch(formatURL(video_path));
|
||||||
let response = await fetch(formatURL(video_path));
|
// let vid_src = URL.createObjectURL(await response.blob()); // IE10+
|
||||||
let vid_src = URL.createObjectURL(await response.blob()); // IE10+
|
// video.src = vid_src;
|
||||||
video.src = vid_src;
|
// video.src = video_path;
|
||||||
}
|
// }
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
video.src = "#";
|
|
||||||
video.style.display = "none";
|
video.style.display = "none";
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
@ -103,7 +106,6 @@ const setupFile = async (hash, extension) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type == "text") {
|
if (type == "text") {
|
||||||
console.log(hash);
|
|
||||||
let response = await fetch(formatURL("files/" + hash));
|
let response = await fetch(formatURL("files/" + hash));
|
||||||
let textData = await response.text(); // IE10+
|
let textData = await response.text(); // IE10+
|
||||||
viewer.innerText = textData;
|
viewer.innerText = textData;
|
||||||
@ -177,14 +179,16 @@ const disableEdit = (elm) => {
|
|||||||
|
|
||||||
const updateBackground = (srcLink, isvideo = true) => {
|
const updateBackground = (srcLink, isvideo = true) => {
|
||||||
try {
|
try {
|
||||||
if (isvideo) {
|
|
||||||
let elm = document.getElementById("bg");
|
let elm = document.getElementById("bg");
|
||||||
|
|
||||||
|
console.log(srcLink);
|
||||||
|
if (isvideo) {
|
||||||
if (elm.getAttribute('src') === "") {
|
if (elm.getAttribute('src') === "") {
|
||||||
elm.src = srcLink;
|
elm.src = srcLink;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document.getElementById("bg").src = "";
|
elm.src = "";
|
||||||
document.getElementById("bg").setAttribute("poster", srcLink);
|
elm.setAttribute("poster", srcLink);
|
||||||
}
|
}
|
||||||
} catch (e) { }
|
} catch (e) { }
|
||||||
}
|
}
|
||||||
@ -223,3 +227,34 @@ const clearChildNodes = (parent) => {
|
|||||||
parent.removeChild(parent.firstChild);
|
parent.removeChild(parent.firstChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Cache Buster
|
||||||
|
const clearCache = () => {
|
||||||
|
var rep = /.*\?.*/,
|
||||||
|
links = document.getElementsByTagName('link'),
|
||||||
|
scripts = document.getElementsByTagName('script'),
|
||||||
|
links = document.getElementsByTagName('video'),
|
||||||
|
process_scripts = false;
|
||||||
|
|
||||||
|
for (var i=0; i<links.length; i++) {
|
||||||
|
var link = links[i],
|
||||||
|
href = link.href;
|
||||||
|
if(rep.test(href)) {
|
||||||
|
link.href = href+'&'+Date.now();
|
||||||
|
} else {
|
||||||
|
link.href = href+'?'+Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(process_scripts) {
|
||||||
|
for (var i=0; i<scripts.length; i++) {
|
||||||
|
var script = scripts[i],
|
||||||
|
src = script.src;
|
||||||
|
if(rep.test(src)) {
|
||||||
|
script.src = src+'&'+Date.now();
|
||||||
|
} else {
|
||||||
|
script.src = src+'?'+Date.now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
170
webfm/static/js/video-events.js
Normal file
170
webfm/static/js/video-events.js
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
const getTimeFormatted = (duration = null) => {
|
||||||
|
if (duration == null) { return "00:00"; }
|
||||||
|
|
||||||
|
let hours = (duration / 3600).toFixed(2).split(".")[0];
|
||||||
|
let minutes = (duration / 60).toFixed(2).split(".")[0];
|
||||||
|
let time = (duration / 60).toFixed(2)
|
||||||
|
let seconds = Math.floor( (time - Math.floor(time) ) * 60);
|
||||||
|
|
||||||
|
return hours + ":" + minutes + ":" + seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pauseVideo = () => {
|
||||||
|
const video = document.getElementById("video-viewer");
|
||||||
|
video.style.cursor = '';
|
||||||
|
video.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
const togglePlay = (video) => {
|
||||||
|
shouldPlay = setTimeout(function () {
|
||||||
|
let controls = document.getElementById("video-controls");
|
||||||
|
shouldPlay = null;
|
||||||
|
if (video.paused) {
|
||||||
|
video.style.cursor = 'none';
|
||||||
|
controls.style.display = "none";
|
||||||
|
video.play();
|
||||||
|
} else {
|
||||||
|
video.style.cursor = '';
|
||||||
|
controls.style.display = "";
|
||||||
|
video.pause();
|
||||||
|
}
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleFullscreen = (video) => {
|
||||||
|
containerElm = document.getElementById("video-container");
|
||||||
|
parentElm = video.parentElement;
|
||||||
|
|
||||||
|
if (video.requestFullscreen) {
|
||||||
|
parentElm.requestFullscreen();
|
||||||
|
video.style.cursor = 'none';
|
||||||
|
containerElm.style.display = "block";
|
||||||
|
} else if (video.webkitRequestFullscreen) { /* Safari */
|
||||||
|
parentElm.webkitRequestFullscreen();
|
||||||
|
video.style.cursor = 'none';
|
||||||
|
containerElm.style.display = "block";
|
||||||
|
} else if (video.msRequestFullscreen) { /* IE11 */
|
||||||
|
parentElm.msRequestFullscreen();
|
||||||
|
video.style.cursor = 'none';
|
||||||
|
containerElm.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullScreenState == 2) {
|
||||||
|
if (document.exitFullscreen) {
|
||||||
|
document.exitFullscreen();
|
||||||
|
video.style.cursor = '';
|
||||||
|
containerElm.style.display = "contents";
|
||||||
|
} else if (document.webkitExitFullscreen) { /* Safari */
|
||||||
|
document.webkitExitFullscreen();
|
||||||
|
video.style.cursor = '';
|
||||||
|
containerElm.style.display = "contents";
|
||||||
|
} else if (document.msExitFullscreen) { /* IE11 */
|
||||||
|
document.msExitFullscreen();
|
||||||
|
video.style.cursor = '';
|
||||||
|
containerElm.style.display = "contents";
|
||||||
|
}
|
||||||
|
|
||||||
|
fullScreenState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullScreenState += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleVolumeControl = () => {
|
||||||
|
const volume = document.getElementById("volume-slider");
|
||||||
|
if (volume.style.display === "none") {
|
||||||
|
volume.style.display = "";
|
||||||
|
} else {
|
||||||
|
volume.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const showControls = () => {
|
||||||
|
const video = document.getElementById("video-viewer");
|
||||||
|
const controls = document.getElementById("video-controls");
|
||||||
|
|
||||||
|
video.style.cursor = '';
|
||||||
|
controls.style.display = "";
|
||||||
|
if (controlsTimeout) {
|
||||||
|
clearTimeout(controlsTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
controlsTimeout = setTimeout(function () {
|
||||||
|
if (!video.paused) {
|
||||||
|
if (canHideControls) {
|
||||||
|
video.style.cursor = 'none';
|
||||||
|
controls.style.display = "none";
|
||||||
|
controlsTimeout = null;
|
||||||
|
} else {
|
||||||
|
showControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$("#video-viewer").on("loadedmetadata", function(eve){
|
||||||
|
let video = eve.target;
|
||||||
|
let videoDuration = document.getElementById("videoDuration");
|
||||||
|
videoDuration.innerText = getTimeFormatted(video.duration);
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#video-viewer").on("click", function(eve){
|
||||||
|
const video = eve.target;
|
||||||
|
|
||||||
|
if(!shouldPlay) {
|
||||||
|
shouldPlay = setTimeout( function() {
|
||||||
|
shouldPlay = null;
|
||||||
|
togglePlay(video);
|
||||||
|
}, clicktapwait);
|
||||||
|
} else {
|
||||||
|
clearTimeout(shouldPlay); // Stop single tap callback
|
||||||
|
shouldPlay = null;
|
||||||
|
toggleFullscreen(video);
|
||||||
|
}
|
||||||
|
eve.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#video-viewer").on("touchend", function(eve){
|
||||||
|
const video = eve.target;
|
||||||
|
|
||||||
|
if(!shouldPlay) {
|
||||||
|
shouldPlay = setTimeout( function() {
|
||||||
|
shouldPlay = null;
|
||||||
|
togglePlay(video);
|
||||||
|
}, clicktapwait);
|
||||||
|
} else {
|
||||||
|
clearTimeout(shouldPlay); // Stop single tap callback
|
||||||
|
shouldPlay = null;
|
||||||
|
toggleFullscreen(video);
|
||||||
|
}
|
||||||
|
eve.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#video-viewer" ).bind( "timeupdate", async function(eve) {
|
||||||
|
let videoDuration = document.getElementById("videoCurrentTime");
|
||||||
|
const video = eve.target;
|
||||||
|
const seekto = document.getElementById("seek-slider");
|
||||||
|
const vt = video.currentTime * (100 / video.duration);
|
||||||
|
|
||||||
|
seekto.value = vt;
|
||||||
|
videoDuration.innerText = getTimeFormatted(video.currentTime);
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#seek-slider" ).bind( "change", async function(eve) {
|
||||||
|
const slider = eve.target;
|
||||||
|
let video = document.getElementById("video-viewer");
|
||||||
|
let seekto = video.duration * (slider.value / 100);
|
||||||
|
video.currentTime = seekto;
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#volume-slider" ).bind( "change", async function(eve) {
|
||||||
|
const slider = eve.target;
|
||||||
|
let video = document.getElementById("video-viewer");
|
||||||
|
let volumeto = slider.value;
|
||||||
|
video.volume = volumeto;
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$( "#video-controls" ).bind( "mouseenter", async function(eve) { canHideControls = false; });
|
||||||
|
$( "#video-controls" ).bind( "mouseleave", async function(eve) { canHideControls = true; });
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
{% block body_header_additional %}
|
{% block body_header_additional %}
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css')}}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/base.css')}}">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css')}}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css')}}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css')}}">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap-table.min.css')}}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap-table.min.css')}}">
|
||||||
@ -36,7 +37,7 @@
|
|||||||
|
|
||||||
<button title="File viewer..." class="btn btn-secondary btn-sm"
|
<button title="File viewer..." class="btn btn-secondary btn-sm"
|
||||||
data-toggle="modal" data-target="#file-view-modal">🖼</button>
|
data-toggle="modal" data-target="#file-view-modal">🖼</button>
|
||||||
{% if current_user.is_authenticated or oidc_loggedin() %}
|
{% if oidc_loggedin() %}
|
||||||
<a href="/logout">
|
<a href="/logout">
|
||||||
<button title="Logout..." class="btn btn-danger btn-sm">
|
<button title="Logout..." class="btn btn-danger btn-sm">
|
||||||
Logout
|
Logout
|
||||||
@ -110,31 +111,48 @@
|
|||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>File Viewer:</h3>
|
<h3>File Viewer:</h3>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" onclick="pauseVideo()" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body text-center justify-content-center">
|
<div class="modal-body text-center justify-content-center">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col scroller" style="max-height: 30em; overflow: auto;">
|
<div class="col scroller" style="max-height: 70vh; overflow: auto;">
|
||||||
<!-- For video -->
|
<!-- For video -->
|
||||||
<div id="video-container" style="display: contents;">
|
<div id="video-container">
|
||||||
<video id="video-viewer"
|
<video id="video-viewer"
|
||||||
|
loop
|
||||||
src=""
|
src=""
|
||||||
autoplay=""
|
autoplay=""
|
||||||
loop
|
volume="0.75"
|
||||||
poster="{{ url_for('static', filename='imgs/icons/loading.gif')}}">
|
poster="{{ url_for('static', filename='imgs/icons/loading.gif')}}"
|
||||||
|
onmousemove="showControls()">
|
||||||
</video>
|
</video>
|
||||||
|
|
||||||
<div id="video-controls">
|
<div id="video-controls">
|
||||||
<input id="seek-slider" type="range" min="0" max="100" step="1">
|
<div class="row pl-5 pr-5">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<input id="seek-slider" class="form-control-range" type="range" min="0" value="0" max="100" step="1"/>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<span id="videoCurrentTime"></span>
|
||||||
|
/
|
||||||
|
<span id="videoDuration"></span>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-1">
|
||||||
|
<span id="volumeIcon" onclick="toggleVolumeControl()">🔈</span>
|
||||||
|
<input id="volume-slider" class="form-control-range volume-control-positioner" style="display: none;"
|
||||||
|
type="range" orient="vertical" min="0.0" max="1.0" value="0.75" step="0.05" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- For image -->
|
<!-- For image -->
|
||||||
<img id="image-viewer"
|
<img id="image-viewer"
|
||||||
style="width: 40em; height: auto; display: none;"
|
style="width: inherit; height: auto; display: none;"
|
||||||
src="" alt="" />
|
src="" alt="" />
|
||||||
|
|
||||||
<!-- For pdf -->
|
<!-- For pdf -->
|
||||||
@ -152,14 +170,14 @@
|
|||||||
|
|
||||||
<!-- For text -->
|
<!-- For text -->
|
||||||
<pre id="text-viewer"
|
<pre id="text-viewer"
|
||||||
style="width: 45em; height: auto; display: none;">
|
style="width: inherit; height: auto; display: none;">
|
||||||
</pre>
|
</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" data-dismiss="modal" class="btn btn-danger btn-sm">Close</button>
|
<button onclick="pauseVideo()" type="button" data-dismiss="modal" class="btn btn-danger btn-sm">Close</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -263,4 +281,5 @@
|
|||||||
<script src="{{ url_for('static', filename='js/ajax.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/ajax.js')}}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/ui-logic.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/ui-logic.js')}}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/events.js')}}"></script>
|
<script src="{{ url_for('static', filename='js/events.js')}}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/video-events.js')}}"></script>
|
||||||
{% endblock body_scripts_additional %}
|
{% endblock body_scripts_additional %}
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap.min.css')}}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap.min.css')}}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap-datepicker.css')}}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap/bootstrap-datepicker.css')}}">
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/overrides.css')}}">
|
|
||||||
{% block header_css_additional %}
|
{% block header_css_additional %}
|
||||||
{% endblock header_css_additional %}
|
{% endblock header_css_additional %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -126,7 +126,6 @@ class FileManager:
|
|||||||
|
|
||||||
def returnPathPartFromHash(self, partHash):
|
def returnPathPartFromHash(self, partHash):
|
||||||
hashes = [self.dotHash, self.dotdotHash]
|
hashes = [self.dotHash, self.dotdotHash]
|
||||||
print(self.pathParts)
|
|
||||||
path = "/".join(self.pathParts)
|
path = "/".join(self.pathParts)
|
||||||
pathPart = None
|
pathPart = None
|
||||||
for f in listdir(path):
|
for f in listdir(path):
|
||||||
|
Loading…
Reference in New Issue
Block a user