From a4755dd281d59b30b73780bd8cff7d7978854a07 Mon Sep 17 00:00:00 2001 From: maximstewart Date: Mon, 21 Dec 2020 13:02:34 -0600 Subject: [PATCH] player updates, layout updates, base oidc added --- create_venv.sh | 40 ++++++++ requirements.txt => linux-requirements.txt | 0 start.sh => linux-start.sh | 2 +- socket_run.sh | 4 +- webfm/__init__.py | 63 +++++++++---- webfm/client_secrets.json | 15 +++ webfm/routes/pages/Login.py | 3 +- webfm/routes/pages/Register.py | 4 +- webfm/static/css/main.css | 30 +++++- webfm/static/css/overrides.css | 11 +++ webfm/static/js/ajax.js | 7 +- webfm/static/js/events.js | 101 ++++++++++++++++++++- webfm/static/js/favorites.js | 3 + webfm/templates/error.html | 6 +- webfm/templates/index.html | 36 +++----- webfm/templates/layout.html | 14 ++- webfm/templates/login.html | 2 +- windows-requirements.txt | 9 ++ 18 files changed, 279 insertions(+), 71 deletions(-) create mode 100755 create_venv.sh rename requirements.txt => linux-requirements.txt (100%) rename start.sh => linux-start.sh (78%) create mode 100644 webfm/client_secrets.json create mode 100644 windows-requirements.txt diff --git a/create_venv.sh b/create_venv.sh new file mode 100755 index 0000000..e39ae87 --- /dev/null +++ b/create_venv.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +. CONFIG.sh + +# set -o xtrace ## To debug scripts +# set -o errexit ## To exit on error +# set -o errunset ## To exit if a variable is referenced but not set + + +function main() { + rm -rf venv/ + + clear + python -m venv venv/ + sleep 2 + source "./venv/bin/activate" + + ANSR="-1" + while [[ $ANSR != "0" ]] && [[ $ANSR != "1" ]] && [[ $ANSR != "2" ]]; do + clear + menu_mesage + read -p "--> : " ANSR + done + case $ANSR in + "1" ) pip install -r linux-requirements.txt;; + "2" ) pip install -r windows-requirements.txt;; + "0" ) exit;; + * ) echo "Don't know how you got here but that's a bad sign...";; + esac +} + +function menu_mesage() { + echo "NOTE: Make sure to have Python 3 installed!" + echo -e "\nWhat do you want to do?" + echo -e "\t1) Generate Linux/Mac supported venv. (Installs Repuirements)" + echo -e "\t2) Generate Windows supported venv. (Installs Repuirements)" + echo -e "\t0) EXIT" +} + +main $@; diff --git a/requirements.txt b/linux-requirements.txt similarity index 100% rename from requirements.txt rename to linux-requirements.txt diff --git a/start.sh b/linux-start.sh similarity index 78% rename from start.sh rename to linux-start.sh index 3d32181..de5688a 100755 --- a/start.sh +++ b/linux-start.sh @@ -10,6 +10,6 @@ function main() { cd "${SCRIPTPATH}" echo "Working Dir: " $(pwd) source "./venv/bin/activate" - gunicorn wsgi:app -b 0.0.0.0:8080 # : IE : + gunicorn wsgi:app -b 0.0.0.0:8080 -p app.pid # : IE : } main $@; diff --git a/socket_run.sh b/socket_run.sh index 9088654..2a70ceb 100755 --- a/socket_run.sh +++ b/socket_run.sh @@ -9,9 +9,9 @@ function main() { SCRIPTPATH="$( cd "$(dirname "")" >/dev/null 2>&1 ; pwd -P )" cd "${SCRIPTPATH}" echo "Working Dir: " $(pwd) + source "./venv/bin/activate" mkdir /tmp/apps - ./venv/bin/gunicorn \ - --bind unix:/tmp/apps/webfm.sock wsgi:app + gunicorn --bind unix:/tmp/apps/webfm.sock wsgi:app -p app.pid } main $@; diff --git a/webfm/__init__.py b/webfm/__init__.py index 2abba50..932a1d9 100644 --- a/webfm/__init__.py +++ b/webfm/__init__.py @@ -1,29 +1,58 @@ -# system import +# System import import os, json, secrets from datetime import timedelta -# Flask imports -from flask import Flask, Blueprint +# Lib imports +from flask import Flask +from flask_oidc import OpenIDConnect from flask_login import current_user, login_user, logout_user, LoginManager from flask_bcrypt import Bcrypt +# Apoplication imports + + # Configs and 'init' -app = Flask(__name__) -app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///static/db/webfm.db" -app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False -app.config['TITLE'] = 'WebFM' +APP_NAME = 'WebFM' +ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__)) +CONFIG_FILE = ROOT_FILE_PTH + "/config.json" +# This path is submitted as the redirect URI in certain code flows. +REDIRECT_LINK = "https%3A%2F%2Fwww.webfm.com%2F" + + +app = Flask(__name__) +app.config.update({ + "TITLE": APP_NAME, + 'DEBUG': False, + 'SECRET_KEY': secrets.token_hex(32), + 'PERMANENT_SESSION_LIFETIME': timedelta(days = 7).total_seconds(), + "SQLALCHEMY_DATABASE_URI": "sqlite:///static/db/webfm.db", + "SQLALCHEMY_TRACK_MODIFICATIONS": False, + "APP_REDIRECT_URI": REDIRECT_LINK, + 'OIDC_CLIENT_SECRETS': ROOT_FILE_PTH + '/client_secrets.json', + 'OIDC_ID_TOKEN_COOKIE_SECURE': True, # Only set false in development setups... + 'OIDC_REQUIRE_VERIFIED_EMAIL': False, + 'OIDC_USER_INFO_ENABLED': True, + 'OIDC_VALID_ISSUERS': [ + 'http://www.ssoapps.com/auth/realms/apps', + 'https://www.ssoapps.com/auth/realms/apps' + ], + 'OIDC_TOKEN_TYPE_HINT': 'access_token' + }) + + +login_manager = LoginManager(app) +bcrypt = Bcrypt(app) +oidc = OpenIDConnect(app) +def oidc_loggedin(): + return oidc.user_loggedin +app.jinja_env.globals['oidc_loggedin'] = oidc_loggedin +app.jinja_env.globals['TITLE'] = APP_NAME + -# For csrf and some other stuff... -app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days = 7) -app.config['SECRET_KEY'] = secrets.token_hex(32) -login_manager = LoginManager(app) -bcrypt = Bcrypt(app) # Settings data -THIS_FILE_PTH = os.path.dirname(os.path.realpath(__file__)) -CONFIG_FILE = THIS_FILE_PTH + "/config.json" def retrieveSettings(): returnData = [] @@ -39,7 +68,7 @@ config = retrieveSettings() from .forms import LoginForm, RegisterForm from .models import db, Favorites, Settings, User -from webfm import routes -with app.app_context(): - db.create_all() +db.init_app(app) +with app.app_context(): db.create_all() +from webfm import routes diff --git a/webfm/client_secrets.json b/webfm/client_secrets.json new file mode 100644 index 0000000..e277903 --- /dev/null +++ b/webfm/client_secrets.json @@ -0,0 +1,15 @@ +{ + "web": { + "auth_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/auth", + "client_id": "apps", + "issuer": "https://www.ssoapps.com/auth/realms/apps", + "client_secret": "[Add your secret key here]", + "redirect_uris": [ + "http://www.webfm.com/home", + "https://www.webfm.com/home" + ], + "userinfo_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/userinfo", + "token_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/token", + "token_introspection_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/token/introspect" + } +} diff --git a/webfm/routes/pages/Login.py b/webfm/routes/pages/Login.py index 2ae699d..0d63433 100644 --- a/webfm/routes/pages/Login.py +++ b/webfm/routes/pages/Login.py @@ -10,7 +10,6 @@ from ...utils import MessageHandler # Get simple message processor msgHandler = MessageHandler() -TITLE = app.config['TITLE'] @app.route('/login', methods=['GET', 'POST']) def login(): @@ -28,7 +27,7 @@ def login(): flash("Username or password incorrect! Please try again...", "danger") - return render_template('login.html', title=TITLE, form=_form) + return render_template('login.html', form = _form) @app.route('/logout', methods=['GET', 'POST']) diff --git a/webfm/routes/pages/Register.py b/webfm/routes/pages/Register.py index a7e90d7..d68c1d1 100644 --- a/webfm/routes/pages/Register.py +++ b/webfm/routes/pages/Register.py @@ -10,7 +10,6 @@ from ...utils import MessageHandler # Get simple message processor msgHandler = MessageHandler() -TITLE = app.config['TITLE'] @app.route('/register', methods=['GET', 'POST']) def register(): @@ -27,5 +26,4 @@ def register(): return redirect("/login") return render_template('register.html', - title=TITLE, - form=_form) + form = _form) diff --git a/webfm/static/css/main.css b/webfm/static/css/main.css index 0580881..bf0b145 100644 --- a/webfm/static/css/main.css +++ b/webfm/static/css/main.css @@ -22,12 +22,11 @@ #file-grid { display: grid; - grid-template-columns: repeat(auto-fit, minmax(18em, 1fr)); + grid-template-columns: repeat(auto-fit, minmax(14em, 1fr)); grid-column-gap: 1em; grid-row-gap: 1em; - margin: 5em auto; + margin: 2em auto; width: 85%; - padding: 2em; overflow-y: auto; max-height: 25em; } @@ -35,12 +34,33 @@ #path { max-width: inherit; } #faves-list > li { width: 100%; } +#video-container { + width: 30em; + position: relative; +} + +#video-viewer { + width: inherit; + height: inherit; + vertical-align: top; +} + +#video-controls { + position: absolute; + left: 0; + right: 0; + bottom: 0.5em; + background-color: rgba(0, 0, 0, 0.64); + width: inherit; + margin: 0 auto; +} + /* CLASSES */ .scroller { - scrollbar-color: #00000084 #ffffff64; - scrollbar-width: thin; + scrollbar-color: #00000084 #ffffff64; + scrollbar-width: thin; } .dir-style, .video-style, .file-style { diff --git a/webfm/static/css/overrides.css b/webfm/static/css/overrides.css index 15e59a9..019d26f 100644 --- a/webfm/static/css/overrides.css +++ b/webfm/static/css/overrides.css @@ -1,3 +1,14 @@ +#video-container::-webkit-media-controls { + display:none !important; +} + +#video-container::-webkit-media-controls-enclosure { + display:none !important; +} + + + + .modal-content { background-color: #32383e74; border-color: #f8940674; diff --git a/webfm/static/js/ajax.js b/webfm/static/js/ajax.js index 050db5d..d2a46d0 100644 --- a/webfm/static/js/ajax.js +++ b/webfm/static/js/ajax.js @@ -30,12 +30,7 @@ const doAjax = (actionPath, data, action) => { xhttp.onreadystatechange = function() { if (this.readyState === 4 && this.status === 200) { if (this.responseText != null) { // this.responseXML if getting XML data - if (xhttp.responseURL.includes("/register") || - xhttp.responseURL.includes("/login")) { - window.location.href = xhttp.responseURL; - } else { - postAjaxController(JSON.parse(this.responseText), action); - } + postAjaxController(JSON.parse(this.responseText), action); } else { let type = "danger" let msg = "No content returned. Check the target path."; diff --git a/webfm/static/js/events.js b/webfm/static/js/events.js index 7e2fd95..59fec97 100644 --- a/webfm/static/js/events.js +++ b/webfm/static/js/events.js @@ -1,7 +1,6 @@ -// let eventSource = new EventSource( formatURL("stream") ); -// eventSource.onmessage = function(e) { -// console.log(e.data); -// }; +let fullScreenState = 0; +let shouldPlay = null; +let clicktapwait = 200; document.body.onload = (eve) => { @@ -23,6 +22,100 @@ 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) { searchPage(); diff --git a/webfm/static/js/favorites.js b/webfm/static/js/favorites.js index b4af23b..d733ef5 100644 --- a/webfm/static/js/favorites.js +++ b/webfm/static/js/favorites.js @@ -15,4 +15,7 @@ const manageFavorites = (elm) => { const loadFave = (id) => { loadFavoriteLink(id); + document.getElementById("favorites-modal") + .getElementsByClassName("modal-footer")[0] + .children[0].click() } diff --git a/webfm/templates/error.html b/webfm/templates/error.html index a6aa5ac..2ecab7d 100644 --- a/webfm/templates/error.html +++ b/webfm/templates/error.html @@ -1,7 +1,5 @@ {% extends "layout.html" %} {% block content %} -
-

{{title}}

-

{{message}}

-
+

{{title}}

+

{{message}}

{% endblock content %} diff --git a/webfm/templates/index.html b/webfm/templates/index.html index f16738e..6f711fe 100644 --- a/webfm/templates/index.html +++ b/webfm/templates/index.html @@ -2,26 +2,14 @@ {% block body_header_additional %} - {% endblock body_header_additional%} - -{% with messages = get_flashed_messages(with_categories=true) %} - {% if messages %} -
- {% for category, message in messages %} -
  • {{ message }}
  • - {% endfor %} -
    - {% endif %} -{% endwith %} + {% block body_content %} -