Converted to python flask #1
|
@ -0,0 +1,143 @@
|
||||||
|
*.db
|
||||||
|
*.pyc
|
||||||
|
app.pid
|
||||||
|
|
||||||
|
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
cover/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
.pybuilder/
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
# For a library or package, you might want to ignore these files since the code is
|
||||||
|
# intended to run in multiple environments; otherwise, check them in:
|
||||||
|
# .python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# pytype static type analyzer
|
||||||
|
.pytype/
|
||||||
|
|
||||||
|
# Cython debug symbols
|
||||||
|
cython_debug/
|
Before Width: | Height: | Size: 386 KiB |
BIN
Images/000.jpg
Before Width: | Height: | Size: 210 KiB |
BIN
Images/pic1.png
Before Width: | Height: | Size: 1.4 MiB |
BIN
Images/pic2.png
Before Width: | Height: | Size: 2.0 MiB |
BIN
Images/pic3.png
Before Width: | Height: | Size: 1.8 MiB |
BIN
Images/pic4.png
Before Width: | Height: | Size: 2.1 MiB |
BIN
Images/pic5.png
Before Width: | Height: | Size: 2.0 MiB |
BIN
Images/pic6.png
Before Width: | Height: | Size: 2.4 MiB |
BIN
Music/000.jpg
Before Width: | Height: | Size: 1019 KiB |
34
README.md
|
@ -2,22 +2,17 @@
|
||||||
WebFM is a media and file viewer aspiring to become a full fledged file manager in the browser.
|
WebFM is a media and file viewer aspiring to become a full fledged file manager in the browser.
|
||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
1. Install php7, php-sqlite3, and ffmpeg on the system this will be on.
|
1. Install python, sqlite3, and ffmpeg on the system this will be on.
|
||||||
2. Use php -S 0.0.0.0:yourDesiredPort
|
3. Use ufw or gufw to open the port on your computer to the local network.
|
||||||
3. Use ufw or gufw to open the port on your computer to the network.
|
4. Use hosts file (or other methods) to redirect webfm.com and ssoapps.com to local app.
|
||||||
4. Place files or start uploading some to the folders.
|
5. Update client_secrets.json > 'client_secret' field with your Keycloak key. (Current one is local to me and not public)
|
||||||
5. Double click thumbnails and container outlines to open files.
|
6. Place files or start uploading some to the folders.
|
||||||
6. Double click the text name to change the file's or folder's name and press enter to set it.
|
7. Place an image such as a jpg, png, or gif labeled "000.itsExtension" in a directory and the viewer will use it as the background image for that folder/directory.
|
||||||
7. Right-click to get context menu options.
|
7. Password protect folder based on core/utils/shellfm/windows/Settings.py file settings.
|
||||||
8. Place an image such as a jpg, png, or gif labeled "000.itsExtension" in a directory then the viewer will use it as the background image for that folder/directory.
|
8. Save paths to favorites list for quick access.
|
||||||
9. Password protect folder based on resources/php/config.php file setting.
|
|
||||||
10. Save paths to favorites list for quick access.
|
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
1. The provided folders except "resources" are optional. You can add and remove them as you please.
|
n/a
|
||||||
2. The media and image pane can be moved by dragging from the transparentish bar that has the close button and other controls.
|
|
||||||
3. Edit the resources/php/config.php file and put your own programs there.
|
|
||||||
4. Edit your php.ini file "upload_max_filesize" and "post_max_size" to be higher to upload larger files.
|
|
||||||
|
|
||||||
# TO-DO
|
# TO-DO
|
||||||
1. Allow for move and copy.
|
1. Allow for move and copy.
|
||||||
|
@ -25,9 +20,8 @@ Notes:
|
||||||
|
|
||||||
|
|
||||||
# Images
|
# Images
|
||||||
![1 Home](Images/pic1.png)
|
![1 Videos List](images/pic1.png)
|
||||||
![2 Images Listed](Images/pic2.png)
|
![2 Video Playing](images/pic2.png)
|
||||||
![3 Videos Listed](Images/pic3.png)
|
![3 Images List](images/pic3.png)
|
||||||
![4 Image Open](Images/pic4.png)
|
![4 Context menu](images/pic4.png)
|
||||||
![5 Image Open And Video Playing](Images/pic5.png)
|
![5 Settings Pane With Upload And Create Functionality](images/pic5.png)
|
||||||
![6 Alternate Background](Images/pic6.png)
|
|
BIN
Videos/000.jpg
Before Width: | Height: | Size: 1.9 MiB |
|
@ -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 $@;
|
|
@ -1 +0,0 @@
|
||||||
LOL...Not really!
|
|
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.5 MiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 390 KiB |
After Width: | Height: | Size: 316 KiB |
120
index.html
|
@ -1,120 +0,0 @@
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta content="" charset="utf-8"/>
|
|
||||||
<title>Web File Manager</title>
|
|
||||||
<link type="text/css" rel="stylesheet" href="resources/css/base.css"/>
|
|
||||||
<link type="text/css" rel="stylesheet" href="resources/css/main.css"/>
|
|
||||||
<link rel="shortcut icon" type="image/png" href="favicon.png"/>
|
|
||||||
</head>
|
|
||||||
<body onload="onloadSetBG(); getDir('/')" contextmenu="menu">
|
|
||||||
<!-- Background -->
|
|
||||||
<img id="bg" />
|
|
||||||
|
|
||||||
<video id="video" src="" controls >
|
|
||||||
</video>
|
|
||||||
|
|
||||||
<!-- Controls -->
|
|
||||||
<!-- Create the menu -->
|
|
||||||
<menu type="context" id="menu">
|
|
||||||
<menuitem label="Home Directory" onclick="clearDirCookie()"></menuitem>
|
|
||||||
<menuitem label="Show Server Messages" onclick="tgglElmView('serverMsgView')"></menuitem>
|
|
||||||
<menuitem label="Clear Upload List" onclick="clearDlList()"></menuitem>
|
|
||||||
<menuitem label="Download" onclick="downloadItem()"></menuitem>
|
|
||||||
<menuitem label="Delete" onclick="deleteItem()"></menuitem>
|
|
||||||
</menu>
|
|
||||||
|
|
||||||
<!-- Uploader -->
|
|
||||||
<h2 id="controls">
|
|
||||||
<button type="button" title="Other Options" onclick="tgglElmView('popOutControls')">⚙</button>
|
|
||||||
<button type="button" title="Refresh" onclick="getDir('./')">↻</button>
|
|
||||||
<button type="button" title="Back" onclick="getDir('../')">⇐</button>
|
|
||||||
<input type="text" placeholder="Search..." onkeyup="searchPage(this)" name="" value="">
|
|
||||||
<button type="button" onclick="clearSearch()" title="Clears search..." >Clear Search</button>
|
|
||||||
<button onclick="getFavesList(); tgglElmView('favesList')">Faves List ↕</button>
|
|
||||||
<button type="button" onclick="lockFolders()" title="Lock unlocked folders..." >Lock Unlocked Folders</button>
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
<button type="button" id="faves" onclick="faveManager(this)" title="Add/Delete from favorites..." >☆</button>
|
|
||||||
Path:<span id="path"></span>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div id="popOutControls" style="display:none;">
|
|
||||||
<center>
|
|
||||||
<form>
|
|
||||||
<input class="ulFile" type="file" title="files To Upload" name="filesToUpload[]" data-multiple-caption="{count} files selected" multiple />
|
|
||||||
<input type="button" onclick="uploadFiles()" name="UploadFiles" title="Upload File(s)" value="Upload File(s)" />
|
|
||||||
<input type="reset" title="Clear" id="CLEARBTTN" value="Clear" style="display:none;">
|
|
||||||
<input type="text" id="DIRPATHUL" name="DIRPATHUL" value="">
|
|
||||||
</form>
|
|
||||||
<br/>
|
|
||||||
<input type="text" id="NewItem" value=""/>
|
|
||||||
<input type="button" value="New Dir" onclick="createItem('dir')"/>
|
|
||||||
<input type="button" value="New File" onclick="createItem('file')"/>
|
|
||||||
<input type="button" value="Show Server Messages" onclick="tgglElmView('serverMsgView')"/>
|
|
||||||
<br/>
|
|
||||||
<input id="MergeType" type="checkbox" onchange="getDir('./')" />
|
|
||||||
<label for="MergeType">Show seassons in same list.</label>
|
|
||||||
</center>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Dynamic content targets -->
|
|
||||||
<ul id="favesList" style="display: none;"> </ul>
|
|
||||||
<ul id="dynUl"></ul>
|
|
||||||
|
|
||||||
<!-- Uploader processor -->
|
|
||||||
<div id="serverMsgView" style="display:none;"> </div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Templates -->
|
|
||||||
<template id="dirTemplate">
|
|
||||||
<li class="dirStyle" tabindex="1">
|
|
||||||
<img id="dirID" class="systemIcon" src="" />
|
|
||||||
<input id="titleID" class="dirTitle" type="text" value="" readonly="true" />
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
<template id="vidTemplate">
|
|
||||||
<li id="movieID" class="movieStyle" tabindex="1" style="background-image: url('')">
|
|
||||||
<span class="popOutBttnInner" title="Open In Local Program">∽</span>
|
|
||||||
<input id="titleID" class="movieTitle" type="text" value="" readonly="true" />
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
<template id="imgTemplate">
|
|
||||||
<img id="imageID" class="iconImg" src="" alt="">
|
|
||||||
</template>
|
|
||||||
<template id="filTemplate">
|
|
||||||
<li class="fileStyle">
|
|
||||||
<img id="fileID" class="systemIcon" src="" />
|
|
||||||
<input id="titleID" class="fileTitle" type="text" value="" readonly="true" />
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
if (window.self !== window.top) {
|
|
||||||
setTimeout(function () {
|
|
||||||
let elm = document.getElementById("bg");
|
|
||||||
elm.parentElement.removeChild(elm);
|
|
||||||
|
|
||||||
// Stylesheet for iframe views
|
|
||||||
var link = document.createElement("link");
|
|
||||||
link.href = "resources/css/iframe.css";
|
|
||||||
link.type = "text/css";
|
|
||||||
link.rel = "stylesheet";
|
|
||||||
document.getElementsByTagName("head")[0].appendChild(link);
|
|
||||||
}, 500);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/javascript" src="resources/js/favorites.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/passwordFieldInsert.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/cookieHandler.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/jsonParser.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/ajax.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/uiActions.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/filesystemActions.js" charset="utf-8"></script>
|
|
||||||
<script type="text/javascript" src="resources/js/uiEvents.js" charset="utf-8"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
click==7.1.2
|
||||||
|
dnspython==2.1.0
|
||||||
|
eventlet==0.30.1
|
||||||
|
email-validator==1.1.2
|
||||||
|
Flask==1.1.2
|
||||||
|
Flask-Login==0.5.0
|
||||||
|
flask-oidc==1.4.0
|
||||||
|
Flask-Bcrypt==0.7.1
|
||||||
|
Flask-SQLAlchemy==2.4.4
|
||||||
|
Flask-WTF==0.14.3
|
||||||
|
greenlet==1.0.0
|
||||||
|
gunicorn==20.0.4
|
||||||
|
httplib2==0.19.0
|
||||||
|
itsdangerous==1.1.0
|
||||||
|
Jinja2==2.11.3
|
||||||
|
MarkupSafe==1.1.1
|
||||||
|
oauth2client==4.1.3
|
||||||
|
pyasn1==0.4.8
|
||||||
|
pyasn1-modules==0.2.8
|
||||||
|
pyparsing==2.4.7
|
||||||
|
rsa==4.7
|
||||||
|
six==1.15.0
|
||||||
|
SQLAlchemy==1.3.23
|
||||||
|
Werkzeug==1.0.1
|
||||||
|
WTForms==2.3.3
|
|
@ -1,8 +0,0 @@
|
||||||
html {
|
|
||||||
margin: 0em;
|
|
||||||
padding: 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol, ul, li {
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
#controls, #fullPathHeader, #dynDiv,
|
|
||||||
.errorStyling, .dirStyle, .movieStyle, .fileStyle {
|
|
||||||
background-color: rgba(0,0,0,0.2);
|
|
||||||
}
|
|
|
@ -1,304 +0,0 @@
|
||||||
/* IDs */
|
|
||||||
|
|
||||||
#DIRPATHUL {
|
|
||||||
display: none;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#video,
|
|
||||||
#bg {
|
|
||||||
position: fixed;
|
|
||||||
top: 0%;
|
|
||||||
left: 0%;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: -999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#video,
|
|
||||||
#bg img {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
z-index: -999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#video {
|
|
||||||
position: fixed;
|
|
||||||
display: none;
|
|
||||||
background-color: rgba(0, 0, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls, #dynUl,
|
|
||||||
.errorStyling, .dirStyle, .movieStyle, .fileStyle {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: auto;
|
|
||||||
overflow: auto;
|
|
||||||
padding-bottom: 0.5em;
|
|
||||||
color: #ffffff;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.2em;
|
|
||||||
background-color: rgba(0,0,0,0.64);
|
|
||||||
}
|
|
||||||
|
|
||||||
#favesList {
|
|
||||||
border-style: solid;
|
|
||||||
border-color: rgba(0, 0, 0, 0.5);
|
|
||||||
border-width: 0.2em;
|
|
||||||
background-color: rgba(7, 150, 159, 0.8);
|
|
||||||
position: fixed;
|
|
||||||
font-size: 2em;
|
|
||||||
overflow-x: auto;
|
|
||||||
overflow-y: scroll;
|
|
||||||
padding: 1.5em;
|
|
||||||
max-height: 632px;
|
|
||||||
color: #ffffff;
|
|
||||||
z-index: 888;
|
|
||||||
}
|
|
||||||
|
|
||||||
#favesList > li:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: rgba(92, 199, 35, 0.8);
|
|
||||||
padding-left: 1em;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#controls {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 999;
|
|
||||||
top: 0em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#dynUl {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(18em, 1fr));
|
|
||||||
grid-column-gap: 1em;
|
|
||||||
grid-row-gap: 1em;
|
|
||||||
margin: 5em auto;
|
|
||||||
width: 85%;
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#imgView, #imgArea, #fileView {
|
|
||||||
width: 800px;
|
|
||||||
height: 600px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#imgView, #fileView {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0em;
|
|
||||||
z-index: 100;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: rgb(114,184,199);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#fileView {
|
|
||||||
display: block;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#fileViewInner {
|
|
||||||
position: sticky;
|
|
||||||
display: inline;
|
|
||||||
width: 100%;
|
|
||||||
height: 500px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#imgArea {
|
|
||||||
width: 800px;
|
|
||||||
height: 600px;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
#imgView {
|
|
||||||
overflow: hidden;
|
|
||||||
left: 15em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#NewItem {
|
|
||||||
background-color: #ffffff;
|
|
||||||
color: #000000;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#popOutControls {
|
|
||||||
position: fixed;
|
|
||||||
top: 15%;
|
|
||||||
width: 99%;
|
|
||||||
height: 15em;
|
|
||||||
padding-top: 6em;
|
|
||||||
opacity: 0.94;
|
|
||||||
background: radial-gradient(circle,#3f3f3f,#000000);
|
|
||||||
color: #ffffff;
|
|
||||||
text-align: center;
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#serverMsgView {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 0em;
|
|
||||||
height: 5em;
|
|
||||||
overflow-y: scroll;
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgba(0,0,0,0.64);
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchField {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#searchField:focus {
|
|
||||||
height: 2em;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: thin;
|
|
||||||
border-color: rgba(55, 204, 209, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Classes */
|
|
||||||
.imgViewImg {
|
|
||||||
width: inherit;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.dirStyle { background-color: rgba(0, 0, 0, 0.56); }
|
|
||||||
.movieStyle, .fileStyle { background-color: rgba(101, 101, 101, 0.56); }
|
|
||||||
|
|
||||||
.movieStyle {
|
|
||||||
min-height: 6.5em;
|
|
||||||
overflow: hidden;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: 100% 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.videoInputField {
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 5.5em;
|
|
||||||
background-color: rgba(0, 0, 0, 0.64);
|
|
||||||
color: rgb(255, 255, 255);
|
|
||||||
text-align: center;
|
|
||||||
border-top: 1px solid rgb(255, 255, 255);
|
|
||||||
border-bottom: 1px solid rgb(255, 255, 255);
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dirStyle:hover, .movieStyle:hover, .fileStyle:hover {
|
|
||||||
background-color: rgba(0, 141, 166, 0.56);
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0px 0px 15px rgb(114,184,199);
|
|
||||||
border-radius: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dirStyle:focus, .movieStyle:focus, .fileStyle:focus {
|
|
||||||
background-color: rgba(0, 139, 35, 0.76);
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0px 0px 25px rgb(114, 199, 120);
|
|
||||||
border-radius: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dirTitle, .fileTitle, .movieTitle {
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
border-style: none;
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dirTitle, .fileTitle {
|
|
||||||
width: auto;
|
|
||||||
background-color: #00000000;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.movieTitle {
|
|
||||||
width: 18em;
|
|
||||||
background-color: #ffffff00;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thumbnail {
|
|
||||||
width: 12em;
|
|
||||||
height: 6.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.systemIcon {
|
|
||||||
width: 2em;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.iconImg {
|
|
||||||
width: 18em;
|
|
||||||
height: 12em;
|
|
||||||
margin: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popOutBttn, .closeBttn {
|
|
||||||
float: right;
|
|
||||||
z-index: 2;
|
|
||||||
width: 4em;
|
|
||||||
height: 4em;
|
|
||||||
text-align: center;
|
|
||||||
vertical-align: middle;
|
|
||||||
line-height: 4em; /* the same as your div height */
|
|
||||||
background-color: rgba(0,0,0, 0.85);
|
|
||||||
color: rgb(255,255,255);
|
|
||||||
border-style:solid;
|
|
||||||
border-color: rgb(255,255,255);
|
|
||||||
}
|
|
||||||
|
|
||||||
.popOutBttnInner {
|
|
||||||
float: right;
|
|
||||||
z-index: 2;
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
text-align: center;
|
|
||||||
background-color: rgba(0,0,0, 0.85);
|
|
||||||
color: rgb(255,255,255);
|
|
||||||
border-style:solid;
|
|
||||||
border-color: rgb(255,255,255);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.completionBar {
|
|
||||||
float:left;
|
|
||||||
clear:left;
|
|
||||||
height: 0.1em;
|
|
||||||
background-color: rgba(25, 125, 10, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Hover events */
|
|
||||||
.dirTitle:hover,
|
|
||||||
.iconImg:hover,
|
|
||||||
.closeBttn:hover,
|
|
||||||
.popOutBttnInner:hover,
|
|
||||||
.popOutBttn:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popOutBttnInner:hover,
|
|
||||||
.popOutBttn:hover,
|
|
||||||
.closeBttn:hover {
|
|
||||||
background-color: rgba(255,255,255, 0.85);
|
|
||||||
color: #000000;
|
|
||||||
border-color: #000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Messages coloring */
|
|
||||||
.error, .warnning, .success {
|
|
||||||
float: left;
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.error { color: rgb(255, 0, 0); }
|
|
||||||
.warning { color: rgb(255, 168, 0); }
|
|
||||||
.success { color: rgb(136, 204, 39); }
|
|
Before Width: | Height: | Size: 7.4 KiB |
|
@ -1 +0,0 @@
|
||||||
Place Holder File
|
|
|
@ -1,54 +0,0 @@
|
||||||
// SSE events if supported
|
|
||||||
if(typeof(EventSource) !== "undefined") {
|
|
||||||
let source = new EventSource("resources/php/sse.php");
|
|
||||||
source.onmessage = (event) => {
|
|
||||||
if (event.data === "updateListing") {
|
|
||||||
getDir("./");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
console.log("SSE Not Supported In Browser...");
|
|
||||||
}
|
|
||||||
|
|
||||||
const getFavesList = () => {
|
|
||||||
doAjax("resources/php/dbController.php", "getTabs=true");
|
|
||||||
}
|
|
||||||
|
|
||||||
const doAjax = async (actionPath, data) => {
|
|
||||||
let xhttp = new XMLHttpRequest();
|
|
||||||
|
|
||||||
xhttp.onreadystatechange = function() {
|
|
||||||
if (this.readyState === 4 && this.status === 200) {
|
|
||||||
// Send the returned data to further process
|
|
||||||
if (this.responseText != null) {
|
|
||||||
handleJSONReturnData(JSON.parse(this.responseText));
|
|
||||||
} else {
|
|
||||||
document.getElementById('dynUl').innerHTML =
|
|
||||||
"<p class=\"error\" style=\"width:100%;text-align:center;\"> "
|
|
||||||
+ "No content returned. Check the folder path.</p>";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhttp.open("POST", actionPath, true);
|
|
||||||
xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
|
||||||
xhttp.overrideMimeType('application/json'); // Force return to be JSON
|
|
||||||
xhttp.send(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileUploader = (data) => {
|
|
||||||
let xhttp = new XMLHttpRequest();
|
|
||||||
|
|
||||||
xhttp.onreadystatechange = function() {
|
|
||||||
if (this.readyState === 4 && this.status === 200) {
|
|
||||||
// Send the returned data to further process
|
|
||||||
if (this.responseXML != null) {
|
|
||||||
handleXMLReturnData(this.responseXML);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhttp.open("POST", "resources/php/filesystemActions.php", true);
|
|
||||||
xhttp.overrideMimeType('application/xml'); // Force return to be XML
|
|
||||||
xhttp.send(data);
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
const getCookie = (cname) => {
|
|
||||||
let decodedCookie = decodeURIComponent(document.cookie);
|
|
||||||
let name = cname + "=";
|
|
||||||
let ca = decodedCookie.split(';');
|
|
||||||
for(let i = 0; i <ca.length; i++) {
|
|
||||||
let c = ca[i];
|
|
||||||
while (c.charAt(0) == ' ') {
|
|
||||||
c = c.substring(1);
|
|
||||||
}
|
|
||||||
if (c.indexOf(name) == 0) {
|
|
||||||
return c.substring(name.length, c.length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
const faveManager = (elm) => {
|
|
||||||
let path = document.getElementById("path").innerHTML;
|
|
||||||
let data = "";
|
|
||||||
|
|
||||||
if (elm.style.backgroundColor != "") {
|
|
||||||
elm.style.backgroundColor = "";
|
|
||||||
elm.style.color = "";
|
|
||||||
data = "deleteLink=true";
|
|
||||||
} else {
|
|
||||||
elm.style.backgroundColor = "rgb(255, 255, 255)";
|
|
||||||
elm.style.color = "rgb(0, 0, 0)";
|
|
||||||
data = "deleteLink=false";
|
|
||||||
}
|
|
||||||
|
|
||||||
data += "&linkPath=" + path;
|
|
||||||
doAjax("resources/php/dbController.php", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basically resetting path nodes and setting them up
|
|
||||||
// to the new path and just doing a refresh
|
|
||||||
const loadFave = (elm) => {
|
|
||||||
let path = elm.getAttribute("name");
|
|
||||||
let parts = path.split("/");
|
|
||||||
let size = parts.length;
|
|
||||||
pathNodes = [];
|
|
||||||
|
|
||||||
pathNodes.push(parts[0] + "/");
|
|
||||||
for (let i = 1; i < size - 1; i++) {
|
|
||||||
pathNodes.push(parts[i] + "/");
|
|
||||||
}
|
|
||||||
pathNodes.push(parts[size - 1]);
|
|
||||||
|
|
||||||
getDir("./");
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
let binary = null;
|
|
||||||
let pathNodes = [];
|
|
||||||
|
|
||||||
const lockFolders = () => {
|
|
||||||
const data = "lockFolders=true";
|
|
||||||
doAjax("resources/php/lockedFolders.php", data);
|
|
||||||
getDir("./");
|
|
||||||
}
|
|
||||||
|
|
||||||
const getDir = (query) => {
|
|
||||||
document.getElementById("controls").style.opacity = "1";
|
|
||||||
document.getElementById("dynUl").style.display = "grid";
|
|
||||||
document.getElementById("video").src = "#";
|
|
||||||
document.getElementById("video").style.display = "none";
|
|
||||||
|
|
||||||
let formUlPth = document.getElementById("DIRPATHUL");
|
|
||||||
let mergeType = document.getElementById("MergeType");
|
|
||||||
let passwd = undefined;
|
|
||||||
let data = "";
|
|
||||||
let cookies = "";
|
|
||||||
let dirCookie = "";
|
|
||||||
|
|
||||||
// push or pop to path list
|
|
||||||
if (query === "/") {
|
|
||||||
// Process path from cookie and set to array/list
|
|
||||||
dirCookie = getCookie("dirQuery");
|
|
||||||
if (dirCookie != "" && dirCookie != "./") {
|
|
||||||
dirCookie = dirCookie.split("/");
|
|
||||||
dirCookie.pop(); // account for ending empty slot
|
|
||||||
|
|
||||||
let size = dirCookie.length;
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
pathNodes.push(dirCookie[i] + "/");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pathNodes = [];
|
|
||||||
pathNodes.push("." + query);
|
|
||||||
}
|
|
||||||
} else if (query === "../") {
|
|
||||||
// Only remove while not in root
|
|
||||||
if (pathNodes.length > 1) {
|
|
||||||
pathNodes.pop();
|
|
||||||
}
|
|
||||||
} else if (query === "./") {
|
|
||||||
// Do nothing since re-scanning dir
|
|
||||||
} else {
|
|
||||||
pathNodes.push(query); // Add path
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create path from array of items
|
|
||||||
for (pathNode of pathNodes) { data += pathNode; }
|
|
||||||
|
|
||||||
try {
|
|
||||||
passwd = document.getElementById("PASSWD").value;
|
|
||||||
} catch (e) {
|
|
||||||
passwd = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup upload path for form and make a cookie for persistence during browser session....
|
|
||||||
formUlPth.value = data;
|
|
||||||
data = "dirQuery=" + encodeURIComponent(data);
|
|
||||||
document.cookie = data + "; expires=Sun, 31 Dec 2034 12:00:00 UTC";
|
|
||||||
data +="&mergeType=" + mergeType.checked
|
|
||||||
+ "&passwd=" + passwd;
|
|
||||||
|
|
||||||
doAjax("resources/php/getDirList.php", data);
|
|
||||||
}
|
|
||||||
|
|
||||||
const uploadFiles = async () => {
|
|
||||||
let toUpload = document.getElementsByName("filesToUpload[]")[0];
|
|
||||||
let path = document.getElementById("path").innerHTML;
|
|
||||||
let reader = new FileReader();
|
|
||||||
let data = new FormData();
|
|
||||||
let size = toUpload.files.length;
|
|
||||||
|
|
||||||
data.append("UploadFiles", "trut");
|
|
||||||
data.append("DIRPATHUL", path);
|
|
||||||
|
|
||||||
// Add files
|
|
||||||
if (size > 0) {
|
|
||||||
for (let i = 0; i < size; i++) {
|
|
||||||
data.append("filesToUpload[]", toUpload.files[i]);
|
|
||||||
}
|
|
||||||
fileUploader(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createItem = (type) => {
|
|
||||||
let path = document.getElementById("path").innerHTML;
|
|
||||||
let newItem = document.getElementById("NewItem");
|
|
||||||
let fullPth = path + newItem.value;
|
|
||||||
newItem.value = "";
|
|
||||||
fullPth = encodeURIComponent(fullPth);
|
|
||||||
|
|
||||||
doAjax("resources/php/filesystemActions.php",
|
|
||||||
"createItem=true&item=" + fullPth + "&type=" + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
const deleteItem = () => {
|
|
||||||
let path = document.getElementById("path").innerHTML;
|
|
||||||
// Clicked yes to delete and there is an item
|
|
||||||
if (itemObj != undefined && itemObj != null) {
|
|
||||||
let fullPth = path + itemObj;
|
|
||||||
fullPth = encodeURIComponent(fullPth);
|
|
||||||
let answer = confirm("Are you sure you want to delete: " + fullPth);
|
|
||||||
if (answer == true) {
|
|
||||||
doAjax("resources/php/filesystemActions.php",
|
|
||||||
"deleteItem=true&item=" + fullPth);
|
|
||||||
|
|
||||||
console.log("Deleted: " + fullPth);
|
|
||||||
itemObj = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const renameItem = (obj) => {
|
|
||||||
let path = encodeURIComponent(document.getElementById("path").innerHTML);
|
|
||||||
let oldName = encodeURIComponent(formerFileName);
|
|
||||||
let newName = encodeURIComponent(obj.value);
|
|
||||||
let formData = "renameItem=true&oldName=" + oldName + "&newName=" + newName + "&path=" + path;
|
|
||||||
|
|
||||||
console.log("Old name: " + oldName);
|
|
||||||
console.log("New name: " + newName);
|
|
||||||
|
|
||||||
doAjax("resources/php/filesystemActions.php",
|
|
||||||
formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
const openInLocalProg = (media) => {
|
|
||||||
doAjax("resources/php/filesystemActions.php",
|
|
||||||
"media=" + media);
|
|
||||||
}
|
|
|
@ -1,167 +0,0 @@
|
||||||
const insertArea = document.getElementById('dynUl');
|
|
||||||
|
|
||||||
|
|
||||||
const handleJSONReturnData = (data) => {
|
|
||||||
if (data.message) {
|
|
||||||
if (data.message.type == "locked") {
|
|
||||||
createPassField();
|
|
||||||
} else {
|
|
||||||
const text = document.createTextNode(data.message.text)
|
|
||||||
document.getElementById("serverMsgView").appendChild(text);
|
|
||||||
}
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.list) {
|
|
||||||
updateHTMLDirList(data);
|
|
||||||
} else if (data.FAVES_LIST) {
|
|
||||||
generateFavesList(data.FAVES_LIST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const generateFavesList = (data) => {
|
|
||||||
let listView = document.getElementById("favesList");
|
|
||||||
listView.innerHTML = "";
|
|
||||||
|
|
||||||
data.forEach(fave => {
|
|
||||||
let liTag = document.createElement("LI");
|
|
||||||
let parts = (fave.includes("/")) ? fave.split("/") : fave.split("\\");
|
|
||||||
let txtNode = document.createTextNode(parts[parts.length - 2]);
|
|
||||||
|
|
||||||
liTag.setAttribute("name", fave);
|
|
||||||
liTag.setAttribute("title", fave);
|
|
||||||
liTag.setAttribute("onclick", "loadFave(this)");
|
|
||||||
liTag.appendChild(txtNode);
|
|
||||||
listView.appendChild(liTag);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateHTMLDirList = async (data) => {
|
|
||||||
var dirTemplate = document.querySelector('#dirTemplate');
|
|
||||||
var vidTemplate = document.querySelector('#vidTemplate');
|
|
||||||
var imgTemplate = document.querySelector('#imgTemplate');
|
|
||||||
var filTemplate = document.querySelector('#filTemplate');
|
|
||||||
let dirPath = data.PATH_HEAD;
|
|
||||||
let isInFaves = data.IN_FAVE;
|
|
||||||
let dirs = (data.list.dirs) ? data.list.dirs : [];
|
|
||||||
let videos = (data.list.vids) ? data.list.vids : [];
|
|
||||||
let images = (data.list.imgs) ? data.list.imgs : [];
|
|
||||||
let files = (data.list.files) ? data.list.files : [];
|
|
||||||
let i = 0;
|
|
||||||
let size = 0;
|
|
||||||
|
|
||||||
document.getElementById("path").innerHTML = dirPath;
|
|
||||||
insertArea.innerHTML = "";
|
|
||||||
|
|
||||||
// Setup background if there is a 000.* in selection
|
|
||||||
let bgImgPth = images[0] ? images[0].image : "";
|
|
||||||
if (bgImgPth.match(/000\.(jpg|png|gif)\b/) != null) {
|
|
||||||
updateBG(dirPath + bgImgPth);
|
|
||||||
} else {
|
|
||||||
updateBG("resources/images/backgrounds/000.jpg");
|
|
||||||
}
|
|
||||||
|
|
||||||
// determin whether to style faves or not
|
|
||||||
let elm = document.getElementById("faves");
|
|
||||||
if (isInFaves == "true") {
|
|
||||||
elm.style.backgroundColor = "rgb(255, 255, 255)";
|
|
||||||
elm.style.color = "rgb(0, 0, 0)";
|
|
||||||
} else {
|
|
||||||
elm.style.backgroundColor = "";
|
|
||||||
elm.style.color = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert dirs
|
|
||||||
let dirClone = document.importNode(dirTemplate.content, true);
|
|
||||||
let dirImg = "resources/images/icons/folder.png";
|
|
||||||
let dir = null;
|
|
||||||
size = dirs.length;
|
|
||||||
for (; i < size; i++) {
|
|
||||||
dir = dirs[i].dir;
|
|
||||||
const clone = dirClone.cloneNode(true);
|
|
||||||
createElmBlock(clone, dirImg, dir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert videos
|
|
||||||
let vidClone = document.importNode(vidTemplate.content, true);
|
|
||||||
let thumbnail = "";
|
|
||||||
let title = "";
|
|
||||||
size = videos.length;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
title = videos[i].video.title;
|
|
||||||
thumbnail = videos[i].video.thumbnail;
|
|
||||||
const clone = vidClone.cloneNode(true);
|
|
||||||
createElmBlock(clone, thumbnail, title, true, dirPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert images
|
|
||||||
let imgClone = document.importNode(imgTemplate.content, true);
|
|
||||||
thumbnail = "";
|
|
||||||
size = images.length;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
thumbnail = images[i].image;
|
|
||||||
if (thumbnail.match(/000\.(jpg|png|gif)\b/) == null &&
|
|
||||||
!thumbnail.includes("favicon.png")) {
|
|
||||||
const clone = imgClone.cloneNode(true);
|
|
||||||
let imgTag = clone.firstElementChild;
|
|
||||||
imgTag.src = dirPath + '/' + thumbnail;
|
|
||||||
imgTag.alt = thumbnail;
|
|
||||||
insertArea.appendChild(clone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert files
|
|
||||||
let fileClone = document.importNode(filTemplate.content, true);
|
|
||||||
size = files.length;
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
const clone = fileClone.cloneNode(true);
|
|
||||||
let fileName = files[i].file;
|
|
||||||
createElmBlock(clone, setFileIconType(fileName), fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const createElmBlock = (elm, imgSrc, fileName, isVideo = null, path = null) => {
|
|
||||||
contnrTag = elm.firstElementChild;
|
|
||||||
let imgTag = null;
|
|
||||||
let inputTag = elm.querySelector("input");
|
|
||||||
|
|
||||||
if (isVideo) {
|
|
||||||
contnrTag.style = "background-image: url('/resources/images/thumbnails/" + imgSrc + "')";
|
|
||||||
inputTag.className = "videoInputField";
|
|
||||||
let fullMedia = path + fileName;
|
|
||||||
elm.querySelector("span").addEventListener("click", function (eve) {
|
|
||||||
openInLocalProg(fullMedia);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
imgTag = elm.querySelector("img");
|
|
||||||
imgTag.src = imgSrc;
|
|
||||||
imgTag.alt = fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
contnrTag.title = fileName;
|
|
||||||
inputTag.value = fileName;
|
|
||||||
inputTag.addEventListener("focusout", function (eve) {
|
|
||||||
disableEdits(eve.target);
|
|
||||||
});
|
|
||||||
insertArea.appendChild(elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
const setFileIconType = (fileName) => {
|
|
||||||
if (fileName.match(/\.(doc|docx|xls|xlsx|rtf)\b/) != null) {
|
|
||||||
return "resources/images/icons/doc.png";
|
|
||||||
} else if (fileName.match(/\.(7z|7zip|zip|tar.gz|tar.xz|gz|rar|jar)\b/) != null) {
|
|
||||||
return "resources/images/icons/arc.png";
|
|
||||||
} else if (fileName.match(/\.(pdf)\b/) != null) {
|
|
||||||
return "resources/images/icons/pdf.png";
|
|
||||||
} else if (fileName.match(/\.(html)\b/) != null) {
|
|
||||||
return "resources/images/icons/html.png";
|
|
||||||
} else if (fileName.match(/\.(txt|conf)\b/) != null) {
|
|
||||||
return "resources/images/icons/text.png";
|
|
||||||
} else if (fileName.match(/\.(iso|img)\b/) != null) {
|
|
||||||
return "resources/images/icons/img.png";
|
|
||||||
} else if (fileName.match(/\.(sh|batch|exe)\b/) != null) {
|
|
||||||
return "resources/images/icons/scrip.png";
|
|
||||||
} else {
|
|
||||||
return "resources/images/icons/bin.png";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
const createPassField = () => {
|
|
||||||
let passField = document.createElement("INPUT");
|
|
||||||
let submitBttn = document.createElement("BUTTON");
|
|
||||||
passField.id = "PASSWD";
|
|
||||||
passField.type = "password";
|
|
||||||
passField.placeholder = "Password...";
|
|
||||||
submitBttn.innerHTML = "Submit";
|
|
||||||
insertArea.innerHTML = "";
|
|
||||||
|
|
||||||
passField.onkeyup = (eve) => {
|
|
||||||
if (eve.key == "Enter") {
|
|
||||||
getDir("./");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
submitBttn.onclick = () => {
|
|
||||||
getDir("./");
|
|
||||||
};
|
|
||||||
|
|
||||||
insertArea.appendChild(passField);
|
|
||||||
insertArea.appendChild(submitBttn);
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
let formerFileName = "";
|
|
||||||
|
|
||||||
const tgglElmView = (id) => {
|
|
||||||
let elm = document.getElementById(id);
|
|
||||||
if (elm.style.display == "none") {
|
|
||||||
elm.style.display = "block";
|
|
||||||
} else {
|
|
||||||
elm.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchPage = (elm) => {
|
|
||||||
let query = elm.value.toLowerCase();
|
|
||||||
let list = document.getElementById("dynUl").querySelectorAll("[title]");
|
|
||||||
let size = list.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
if (!list[i].title.toLowerCase().includes(query)) {
|
|
||||||
list[i].style.display = "none";
|
|
||||||
} else {
|
|
||||||
list[i].style.display = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearSearch = () => {
|
|
||||||
let list = document.getElementById("dynUl").querySelectorAll("[title]");
|
|
||||||
let size = list.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
list[i].style.display = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const enableEdit = (obj) => {
|
|
||||||
obj.style.backgroundColor = "#ffffffff";
|
|
||||||
obj.style.color = '#000000ff';
|
|
||||||
obj.readOnly = '';
|
|
||||||
formerFileName = obj.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
const disableEdits = (elm) => {
|
|
||||||
elm.style.backgroundColor = "";
|
|
||||||
elm.style.color = '';
|
|
||||||
elm.value = formerFileName;
|
|
||||||
elm.readOnly = "true";
|
|
||||||
}
|
|
||||||
|
|
||||||
const showMedia = async (mediaLoc, type) => {
|
|
||||||
let path = document.getElementById("path").innerHTML;
|
|
||||||
let tempRef = mediaLoc.toLowerCase();
|
|
||||||
let fullMedia = path + mediaLoc;
|
|
||||||
|
|
||||||
if (type === "video") {
|
|
||||||
setupVideo(type, fullMedia, tempRef);
|
|
||||||
} else {
|
|
||||||
createFloatingPane(type, fullMedia);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setupVideo = async (type, fullMedia, tempRef) => {
|
|
||||||
try {
|
|
||||||
let video = document.getElementById("video");
|
|
||||||
video.autoplay = true;
|
|
||||||
video.poster = "resources/images/loading.gif";
|
|
||||||
|
|
||||||
if ((/\.(mkv|avi|flv|mov|m4v|mpg|wmv|mpeg|mp4|mp3|webm|flac|ogg|pdf)$/i).test(tempRef)) {
|
|
||||||
if ((/\.(mkv|avi|wmv)$/i).test(tempRef)) {
|
|
||||||
const params = "remuxVideo=true&mediaPth=" + fullMedia;
|
|
||||||
let response = await fetch("resources/php/filesystemActions.php",
|
|
||||||
{method: "POST", body: new URLSearchParams(params)});
|
|
||||||
let xml = new window.DOMParser().parseFromString(await response.text(), "text/xml");
|
|
||||||
|
|
||||||
if (xml.getElementsByTagName("REMUX_PATH")[0]) {
|
|
||||||
fullMedia = xml.getElementsByTagName("REMUX_PATH")[0].innerHTML;
|
|
||||||
} else {
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
} else if ((/\.(avi|flv|mov|m4v|mpg|wmv)$/i).test(tempRef)) {
|
|
||||||
openInLocalProg(fullMedia);
|
|
||||||
return ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is questionable in usage since it loads the full video
|
|
||||||
// before showing; but, seeking doesn't work otherwise...
|
|
||||||
let response = await fetch(fullMedia, {method: "GET"});
|
|
||||||
var vidSrc = URL.createObjectURL(await response.blob()); // IE10+
|
|
||||||
video.src = vidSrc;
|
|
||||||
|
|
||||||
document.getElementById("controls").style.opacity = "0";
|
|
||||||
document.getElementById("video").style.display = "block";
|
|
||||||
document.getElementById("dynUl").style.display = "none";
|
|
||||||
} catch (e) {
|
|
||||||
document.getElementById("controls").style.opacity = "1";
|
|
||||||
document.getElementById("dynUl").style.display = "grid";
|
|
||||||
document.getElementById("video").src = "#";
|
|
||||||
document.getElementById("video").style.display = "none";
|
|
||||||
console.log(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const createFloatingPane = (type, fullMedia) => {
|
|
||||||
let iframe = document.createElement("IFRAME");
|
|
||||||
let outterDiv = document.createElement("DIV");
|
|
||||||
let popOutDiv = document.createElement("DIV");
|
|
||||||
let closeDiv = document.createElement("DIV");
|
|
||||||
let toLocDiv = document.createElement("DIV");
|
|
||||||
let imgDiv = document.createElement("DIV");
|
|
||||||
let aTag = document.createElement("A");
|
|
||||||
let imgTag = document.createElement("IMG");
|
|
||||||
let closeText = document.createTextNode("X");
|
|
||||||
|
|
||||||
closeDiv.className = "closeBttn";
|
|
||||||
closeDiv.title = "Close";
|
|
||||||
closeDiv.setAttribute("onclick", "closeContainer(this)");
|
|
||||||
closeDiv.appendChild(closeText);
|
|
||||||
|
|
||||||
aTag.title = "New Tab";
|
|
||||||
aTag.target = "_blank";
|
|
||||||
aTag.href = fullMedia;
|
|
||||||
|
|
||||||
popOutDiv.className = "popOutBttn";
|
|
||||||
popOutDiv.innerHTML = "↗";
|
|
||||||
aTag.appendChild(popOutDiv);
|
|
||||||
|
|
||||||
toLocDiv.title = "Open In Local Program";
|
|
||||||
toLocDiv.className = "popOutBttn";
|
|
||||||
toLocDiv.innerHTML = "∽";
|
|
||||||
toLocDiv.setAttribute("onclick", "openInLocalProg('" + fullMedia + "')");
|
|
||||||
|
|
||||||
imgDiv.id = "imgArea";
|
|
||||||
imgTag.className = "imgViewImg";
|
|
||||||
imgTag.src = fullMedia;
|
|
||||||
imgDiv.appendChild(imgTag);
|
|
||||||
|
|
||||||
iframe.id = "fileViewInner";
|
|
||||||
iframe.src = fullMedia;
|
|
||||||
|
|
||||||
outterDiv.appendChild(closeDiv);
|
|
||||||
outterDiv.appendChild(aTag);
|
|
||||||
outterDiv.appendChild(toLocDiv);
|
|
||||||
|
|
||||||
if (type === "image") {
|
|
||||||
outterDiv.id = "imgView";
|
|
||||||
outterDiv.appendChild(imgDiv);
|
|
||||||
} else {
|
|
||||||
outterDiv.id = "fileView";
|
|
||||||
outterDiv.appendChild(iframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.body.appendChild(outterDiv);
|
|
||||||
dragContainer(outterDiv); // Set for dragging events
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeContainer = (elm) => {
|
|
||||||
elm.parentElement.parentElement.removeChild(elm.parentElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearDirCookie = () => {
|
|
||||||
let expireDate = "Thu, 01 Jan 1970 00:00:00 UTC";
|
|
||||||
document.cookie = "dirQuery=; expires=" + expireDate;
|
|
||||||
getDir("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
const downloadItem = () => {
|
|
||||||
let partialPath = document.getElementById("path").innerHTML;
|
|
||||||
let brTag = document.createElement("BR");
|
|
||||||
let aTag = document.createElement("A");
|
|
||||||
let text = document.createTextNode(itemObj);
|
|
||||||
let fullPath = partialPath + itemObj;
|
|
||||||
aTag.setAttribute("href", fullPath);
|
|
||||||
aTag.setAttribute("target", "_blank");
|
|
||||||
aTag.setAttribute("id", itemObj);
|
|
||||||
aTag.append(text);
|
|
||||||
|
|
||||||
document.getElementById("serverMsgView").append(aTag, brTag);
|
|
||||||
aTag.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
const clearDlList = () => { document.getElementById("CLEARBTTN").click(); }
|
|
||||||
const onloadSetBG = () => { updateBG("resources/images/backgrounds/000.jpg"); }
|
|
||||||
|
|
||||||
const updateBG = (bgImg) => {
|
|
||||||
try {
|
|
||||||
document.getElementById("bg").src = bgImg;
|
|
||||||
} catch (e) { }
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
let itemObj = undefined;
|
|
||||||
let interval = undefined;
|
|
||||||
let cursorX;
|
|
||||||
let cursorY;
|
|
||||||
|
|
||||||
document.getElementById("controls").onmouseover = (eve) => {
|
|
||||||
let source = document.getElementById("video").src;
|
|
||||||
let target = eve.target
|
|
||||||
|
|
||||||
if (interval)
|
|
||||||
clearInterval(interval);
|
|
||||||
|
|
||||||
if (source !== "#") {
|
|
||||||
eve.target.style.opacity = "1";
|
|
||||||
document.getElementById("dynUl").style.display = "grid";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("video").onmouseover = (eve) => {
|
|
||||||
interval = setInterval(function () {
|
|
||||||
elementMouseIsOver = document.elementFromPoint(cursorX, cursorY);
|
|
||||||
if (elementMouseIsOver.tagName == "BODY" ||
|
|
||||||
elementMouseIsOver.id == "video") {
|
|
||||||
let controls = document.getElementById("controls");
|
|
||||||
controls.style.opacity = "0";
|
|
||||||
document.getElementById("dynUl").style.display = "none";
|
|
||||||
clearInterval(interval);
|
|
||||||
}
|
|
||||||
}, 2500);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For context menu to have element
|
|
||||||
document.onclick = (event) => {
|
|
||||||
let obj = event.target;
|
|
||||||
let callingID = obj.id;
|
|
||||||
let classNM = obj.className;
|
|
||||||
|
|
||||||
// right-click detect
|
|
||||||
if (event.which == 3) {
|
|
||||||
if (callingID == "imageID") {
|
|
||||||
setSelectedItem(obj.alt);
|
|
||||||
} else if (callingID == "dirID" || callingID == "fileID" ||
|
|
||||||
callingID == "movieID") {
|
|
||||||
let node = obj.parentNode;
|
|
||||||
setSelectedItem(node.children[1].value);
|
|
||||||
} else if (classNM == "fileStyle" || classNM == "dirStyle" ||
|
|
||||||
classNM == "movieStyle") {
|
|
||||||
setSelectedItem(obj.children[1].value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Actions for content
|
|
||||||
document.ondblclick = (event) => {
|
|
||||||
let obj = event.target;
|
|
||||||
let callingID = obj.id;
|
|
||||||
let classNM = obj.className;
|
|
||||||
|
|
||||||
// Left click detect
|
|
||||||
if (event.which == 1) {
|
|
||||||
// If clicking on container
|
|
||||||
if (classNM === "fileStyle" || classNM === "movieStyle" ||
|
|
||||||
classNM === "dirStyle") {
|
|
||||||
if (classNM === "dirStyle") {
|
|
||||||
getDir(obj.children[1].value);
|
|
||||||
} else if (classNM === "movieStyle") {
|
|
||||||
showMedia(obj.title, "video");
|
|
||||||
} else {
|
|
||||||
showMedia(obj.children[1].value, "file");
|
|
||||||
}
|
|
||||||
} else if (callingID === "dirID") { // If clicking on dir icon
|
|
||||||
let node = obj.parentNode;
|
|
||||||
getDir(node.children[1].value);
|
|
||||||
} else if (callingID === "movieID") { // If clicking on movie thumbnail
|
|
||||||
let node = obj.parentNode;
|
|
||||||
showMedia(node.children[1].value, "video");
|
|
||||||
} else if (callingID === "imageID") { // If clicking on image
|
|
||||||
showMedia(obj.alt, "image");
|
|
||||||
} else if (callingID === "titleID") { // If clicking on text title
|
|
||||||
enableEdit(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mainly for rename event
|
|
||||||
document.onkeydown = (event) => {
|
|
||||||
let obj = event.target;
|
|
||||||
let callingID = event.target.id;
|
|
||||||
let keyCodeVal = event.keyCode;
|
|
||||||
|
|
||||||
// If keycode == Enter
|
|
||||||
if (keyCodeVal == 13) {
|
|
||||||
if (callingID == "titleID") {
|
|
||||||
renameItem(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setSelectedItem = (item) => { itemObj = item; }
|
|
||||||
|
|
||||||
// Drage event for the poped out image and media container
|
|
||||||
const dragContainer = (elmnt) => {
|
|
||||||
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
|
|
||||||
elmnt.onmousedown = dragMouseDown;
|
|
||||||
|
|
||||||
function dragMouseDown(e) {
|
|
||||||
e = e || window.event;
|
|
||||||
pauseEvent(e);
|
|
||||||
// get the mouse cursor position at startup:
|
|
||||||
pos3 = e.clientX;
|
|
||||||
pos4 = e.clientY;
|
|
||||||
document.onmouseup = closeDragElement;
|
|
||||||
// call a function whenever the cursor moves:
|
|
||||||
document.onmousemove = elementDrag;
|
|
||||||
}
|
|
||||||
|
|
||||||
function elementDrag(e) {
|
|
||||||
e = e || window.event;
|
|
||||||
pauseEvent(e);
|
|
||||||
// calculate the new cursor position:
|
|
||||||
pos1 = pos3 - e.clientX;
|
|
||||||
pos2 = pos4 - e.clientY;
|
|
||||||
pos3 = e.clientX;
|
|
||||||
pos4 = e.clientY;
|
|
||||||
// set the element's new position:
|
|
||||||
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
|
|
||||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDragElement(e) {
|
|
||||||
// stop moving when mouse button is released:
|
|
||||||
document.onmouseup = null;
|
|
||||||
document.onmousemove = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pauseEvent(e) {
|
|
||||||
if(e.stopPropagation) e.stopPropagation();
|
|
||||||
if(e.preventDefault) e.preventDefault();
|
|
||||||
|
|
||||||
e.cancelBubble=true;
|
|
||||||
e.returnValue=false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Mouse position detection for control show/hide setup
|
|
||||||
document.onmousemove = function(e){
|
|
||||||
cursorX = e.pageX;
|
|
||||||
cursorY = e.pageY;
|
|
||||||
}
|
|
||||||
|
|
||||||
setInterval(checkCursor, 2000);
|
|
||||||
function checkCursor() {
|
|
||||||
return "";
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<?php
|
|
||||||
$MEDIAPLAYER = "mpv ";
|
|
||||||
$MPLAYER_WH = " -xy 1600 -geometry 50%:50% ";
|
|
||||||
$MUSICPLAYER = "/opt/deadbeef/bin/deadbeef";
|
|
||||||
$IMGVIEWER = "mirage";
|
|
||||||
$OFFICEPROG = "libreoffice";
|
|
||||||
$PDFVIEWER = "evince";
|
|
||||||
$TEXTVIEWER = "leafpad";
|
|
||||||
$FILEMANAGER = "spacefm";
|
|
||||||
$LOCKPASSWORD = "1234";
|
|
||||||
$TMPFOLDERSIZE = 8000; // tmp folder size check for cleanup if above 8GB used.
|
|
||||||
// NOTE: Split folders with ::::
|
|
||||||
$LOCKEDFOLDERS = "./dirLockCheck/";
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,10 +0,0 @@
|
||||||
<?php
|
|
||||||
include_once 'serverMessenger.php';
|
|
||||||
|
|
||||||
chdir("../../");
|
|
||||||
$db = new SQLite3('resources/db/webfm.db');
|
|
||||||
if($db === false){
|
|
||||||
$message = "Server: [Error] --> Database connection failed!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
}
|
|
||||||
?>
|
|
|
@ -1,56 +0,0 @@
|
||||||
<?php
|
|
||||||
include_once 'connection.php';
|
|
||||||
include_once 'serverMessenger.php';
|
|
||||||
|
|
||||||
function getTabLinks() {
|
|
||||||
GLOBAL $db;
|
|
||||||
|
|
||||||
$res = $db->query('Select * FROM faves');
|
|
||||||
$GeneratedJSON = array('FAVES_LIST' => array());
|
|
||||||
while ($row = $res->fetchArray(SQLITE3_ASSOC)) {
|
|
||||||
$GeneratedJSON['FAVES_LIST'][] = $row['link'];
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode($GeneratedJSON);
|
|
||||||
}
|
|
||||||
|
|
||||||
function manageLink($ACTION, $PATH) {
|
|
||||||
GLOBAL $db;
|
|
||||||
$ACTION_TYPE = "";
|
|
||||||
|
|
||||||
// If action isn't true then we add else we delete or exit.
|
|
||||||
if ($ACTION == "false") {
|
|
||||||
$stmt = $db->prepare('INSERT INTO faves VALUES(:link)');
|
|
||||||
$ACTION_TYPE = "added to";
|
|
||||||
} elseif ($ACTION == "true") {
|
|
||||||
$stmt = $db->prepare('DELETE FROM faves WHERE link = :link');
|
|
||||||
$ACTION_TYPE = "deleted from";
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Action for adding or deleting isn't set properly!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt->bindValue(":link", $PATH, SQLITE3_TEXT);
|
|
||||||
$stmt->execute();
|
|
||||||
$stmt->close();
|
|
||||||
|
|
||||||
$message = "Server: [Success] --> Fave link: " .
|
|
||||||
$PATH . " " . $ACTION_TYPE . " the database!";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Determin action
|
|
||||||
chdir("../../");
|
|
||||||
if (isset($_POST['getTabs'])) {
|
|
||||||
getTabLinks();
|
|
||||||
} elseif (isset($_POST['deleteLink'],
|
|
||||||
$_POST['linkPath'])) {
|
|
||||||
manageLink($_POST['deleteLink'], $_POST['linkPath']);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Illegal Access Method!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,199 +0,0 @@
|
||||||
<?php
|
|
||||||
session_start();
|
|
||||||
include_once 'serverMessenger.php';
|
|
||||||
|
|
||||||
// Create file or folder
|
|
||||||
function createItem($FILE, $TYPE) {
|
|
||||||
$FILE = trim($FILE);
|
|
||||||
$FILE = preg_replace('/\.*$/','',$FILE); // removing dot . after file extension
|
|
||||||
|
|
||||||
if ($TYPE === "dir"){
|
|
||||||
mkdir($FILE, 0755);
|
|
||||||
} else if ($TYPE === "file") {
|
|
||||||
$myfile = fopen($FILE, "w");
|
|
||||||
fclose($myfile);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Failed to create folder or file!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = "Server: [Success] --> The file " . $FILE . " has been created.";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
$_SESSION["refreshState"] = "updateListing";
|
|
||||||
}
|
|
||||||
|
|
||||||
// File or folder delition
|
|
||||||
function deleteItem($FILE) {
|
|
||||||
if (filetype($FILE) == "dir"){
|
|
||||||
//GLOB_MARK adds a slash to directories returned
|
|
||||||
$files = glob($FILE . '*', GLOB_MARK);
|
|
||||||
foreach ($files as $file) {
|
|
||||||
deleteItem($file);
|
|
||||||
}
|
|
||||||
rmdir($FILE);
|
|
||||||
} else if (filetype($FILE) == "file") {
|
|
||||||
unlink($FILE);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Failed to delete item! Not a folder or file!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = "Server: [Success] --> The file(s) has/have been deleted.";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
$_SESSION["refreshState"] = "updateListing";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename file or folder
|
|
||||||
function renameItem($OLDFILE, $NEWNAME, $PATH) {
|
|
||||||
rename($PATH . $OLDFILE, $PATH . $NEWNAME);
|
|
||||||
$message = "Server: [Success] --> The file " . $OLDFILE . " has been renamed to " . $NEWNAME . " side.";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
$_SESSION["refreshState"] = "updateListing";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uploader
|
|
||||||
function uploadFiles($targetDir) {
|
|
||||||
$numberOfFiles = count($_FILES['filesToUpload']['name']);
|
|
||||||
|
|
||||||
if ($numberOfFiles === 0) {
|
|
||||||
$message = "Server: [Error] --> No files were uploaded!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$type = "";
|
|
||||||
$message = "";
|
|
||||||
for ($i=0; $i < $numberOfFiles; $i++) {
|
|
||||||
$uploadOk = 1;
|
|
||||||
$fileName = $_FILES['filesToUpload']['name'][$i];
|
|
||||||
$fileTmpName = $_FILES['filesToUpload']['tmp_name'][$i];
|
|
||||||
|
|
||||||
// Check if file already exists
|
|
||||||
$targetFile = $targetDir . $fileName;
|
|
||||||
if (file_exists($targetFile)) {
|
|
||||||
if (filetype($targetFile) == "file") {
|
|
||||||
unlink($targetFile);
|
|
||||||
$message = "Server: [Warning] --> This file already exists. Overwriting it.";
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Warning] --> This file might be a directory. Or, no files were submitted for uploading.";
|
|
||||||
$uploadOk = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check file size
|
|
||||||
$fileSize = $_FILES['filesToUpload']['size'][$i];
|
|
||||||
if ($fileSize > 500000000000) {
|
|
||||||
$message = "Server: [Warning] --> This file is too large.";
|
|
||||||
$uploadOk = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow certain file formats
|
|
||||||
// $ext = pathinfo($targetFile,PATHINFO_EXTENSION);
|
|
||||||
// if(!preg_match('/^.*\.(rar|iso|img|tar|zip|7z|7zip|jpg|jpeg|png|gif|mpeg|mov|flv|avi|mp4|webm|mpg|mkv|m4a|mp3|ogg|docx|doc|odt|txt|pdf|)$/i', strtolower($ext))) {
|
|
||||||
// $message = "Server: [Warning] --> This file type is not allowed.";
|
|
||||||
// $uploadOk = 0;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if everything is ok, try to upload file
|
|
||||||
if ($uploadOk !== 0) {
|
|
||||||
if (move_uploaded_file($fileTmpName, $targetFile)) {
|
|
||||||
$type = "success";
|
|
||||||
$message = "Server: [Success] --> The file " . $fileName . " has been uploaded.";
|
|
||||||
$_SESSION["refreshState"] = "updateListing";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$type = "error";
|
|
||||||
$message .= "\nServer: [Error] --> Your file " . $fileName . " was not uploaded.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
serverMessage($type, $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local program file access
|
|
||||||
function openFile($FILE) {
|
|
||||||
include 'config.php';
|
|
||||||
$EXTNSN = strtolower(pathinfo($FILE, PATHINFO_EXTENSION));
|
|
||||||
|
|
||||||
if (preg_match('(mkv|avi|flv|mov|m4v|mpg|wmv|mpeg|mp4|webm)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($MEDIAPLAYER . "\"" . $FILE . "\" > /dev/null &");
|
|
||||||
} else if (preg_match('(png|jpg|jpeg|gif)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($IMGVIEWER . ' "' . $FILE . '" > /dev/null &');
|
|
||||||
} else if (preg_match('(psf|mp3|ogg|flac)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($MUSICPLAYER . ' "' . $FILE . '" > /dev/null &');
|
|
||||||
} else if (preg_match('(odt|doc|docx|rtf)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($OFFICEPROG . ' "' . $FILE . '" > /dev/null &');
|
|
||||||
} else if (preg_match('(txt)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($TEXTVIEWER . ' "' . $FILE . '" > /dev/null &');
|
|
||||||
} else if (preg_match('(pdf)', $EXTNSN) === 1) {
|
|
||||||
shell_exec($PDFVIEWER . ' "' . $FILE . '" > /dev/null &');
|
|
||||||
}
|
|
||||||
|
|
||||||
$message = "Server: [Success] --> The file " . $FILE . " has been opened server side.";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
function remuxVideo($FILE) {
|
|
||||||
$FILE = trim($FILE);
|
|
||||||
$PTH = "resources/tmp/";
|
|
||||||
$HASHED_NAME = hash('sha256', $FILE) . '.mp4';
|
|
||||||
$EXTNSN = strtolower(pathinfo($FILE, PATHINFO_EXTENSION));
|
|
||||||
|
|
||||||
|
|
||||||
if (!file_exists($PTH . $HASHED_NAME)) {
|
|
||||||
$io = popen('/usr/bin/du -sm ' . $PTH, 'r');
|
|
||||||
$size = fgets($io, 4096);
|
|
||||||
$size = (int) substr($size, 0, strpos ( $size, "\t" ));
|
|
||||||
pclose ($io);
|
|
||||||
|
|
||||||
include 'config.php';
|
|
||||||
if ($size > $TMPFOLDERSIZE) {
|
|
||||||
$files = glob($PTH . '*');
|
|
||||||
foreach($files as $file){
|
|
||||||
if(is_file($file))
|
|
||||||
unlink($file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preg_match('(mkv)', $EXTNSN) === 1)
|
|
||||||
$COMMAND = 'ffmpeg -i "' . $FILE . '" -hide_banner -movflags +faststart -codec copy -strict -2 ' . $PTH . $HASHED_NAME;
|
|
||||||
if (preg_match('(avi)', $EXTNSN) === 1)
|
|
||||||
$COMMAND = 'ffmpeg -i "' . $FILE . '" -hide_banner -movflags +faststart -c:v libx264 -crf 21 -c:a aac -b:a 192k -ac 2 ' . $PTH . $HASHED_NAME;
|
|
||||||
if (preg_match('(wmv)', $EXTNSN) === 1)
|
|
||||||
$COMMAND = 'ffmpeg -i "' . $FILE . '" -hide_banner -movflags +faststart -c:v libx264 -crf 23 -c:a aac -strict -2 -q:a 100 ' . $PTH . $HASHED_NAME;
|
|
||||||
|
|
||||||
shell_exec($COMMAND . " 2> resources/vdata.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
$GeneratedXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
|
||||||
$GeneratedXML .= "<REMUX_PATH>" . $PTH . $HASHED_NAME ."</REMUX_PATH>";
|
|
||||||
echo $GeneratedXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
chdir("../../");
|
|
||||||
if (isset($_POST["remuxVideo"], $_POST["mediaPth"])) {
|
|
||||||
remuxVideo($_POST["mediaPth"]);
|
|
||||||
} else if (isset($_POST["createItem"],
|
|
||||||
$_POST["item"],
|
|
||||||
$_POST["type"])) {
|
|
||||||
createItem($_POST["item"], $_POST["type"]);
|
|
||||||
} else if (isset($_POST["deleteItem"], $_POST["item"])) {
|
|
||||||
deleteItem($_POST["item"]);
|
|
||||||
} else if (isset($_POST["renameItem"],
|
|
||||||
$_POST["oldName"],
|
|
||||||
$_POST["newName"],
|
|
||||||
$_POST["path"])) {
|
|
||||||
renameItem($_POST["oldName"], $_POST["newName"], $_POST["path"]);
|
|
||||||
} else if(isset($_POST["UploadFiles"], $_POST["DIRPATHUL"])) {
|
|
||||||
uploadFiles($_POST["DIRPATHUL"]);
|
|
||||||
} else if (isset($_POST["media"])) {
|
|
||||||
openFile($_POST["media"]);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Incorrect access attempt!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,108 +0,0 @@
|
||||||
<?php
|
|
||||||
session_start();
|
|
||||||
include_once 'serverMessenger.php';
|
|
||||||
|
|
||||||
// Start of retrieving dir data
|
|
||||||
function startListing($NEWPATH, $MERGESEASSONS, $PASSWD) {
|
|
||||||
if (filetype($NEWPATH) == "dir") {
|
|
||||||
include_once 'lockedFolders.php';
|
|
||||||
|
|
||||||
if (checkForLock($NEWPATH, $PASSWD) == false) {
|
|
||||||
$subPath = ""; // This is used for season scanning as a means of properly getting
|
|
||||||
// the video src.... It's left blank when not in a sub dir
|
|
||||||
|
|
||||||
$GeneratedJSON = array('PATH_HEAD' => $NEWPATH,
|
|
||||||
'IN_FAVE' => isInDBCheck($NEWPATH),
|
|
||||||
'list' => array()
|
|
||||||
);
|
|
||||||
|
|
||||||
listDir($GeneratedJSON, $NEWPATH, $MERGESEASSONS, $subPath);
|
|
||||||
echo json_encode($GeneratedJSON);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Folder is locked.";
|
|
||||||
serverMessage("locked", $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function listDir(&$GeneratedJSON, &$NEWPATH, &$MERGESEASSONS, &$subPath) {
|
|
||||||
if ($MERGESEASSONS !== "true") {
|
|
||||||
$files = array_diff(scandir($NEWPATH), array('..', '.', 'resources'));
|
|
||||||
foreach ($files as $fileName) {
|
|
||||||
$fullPath = $NEWPATH . '/' . $fileName;
|
|
||||||
// error_log($fullPath, 4);
|
|
||||||
processItem($GeneratedJSON, $fullPath, $fileName, $subPath);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$files = array_diff(scandir($NEWPATH), array('..', '.', 'resources'));
|
|
||||||
foreach ($files as $fileName) {
|
|
||||||
$fullPath = $NEWPATH . $fileName;
|
|
||||||
// error_log($fullPath, 4);
|
|
||||||
if (filetype($fullPath) == "dir" && strpos(strtolower($fileName),
|
|
||||||
'season') !== false) {
|
|
||||||
$fileName .= "/";
|
|
||||||
listDir($GeneratedJSON, $fullPath, $MERGESEASSONS, $fileName);
|
|
||||||
} else {
|
|
||||||
processItem($GeneratedJSON, $fullPath, $fileName, $subPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assign JSON Markup based on file type
|
|
||||||
function processItem(&$GeneratedJSON, &$fullPath, &$fileName, $subPath) {
|
|
||||||
if (preg_match('/^.*\.(mkv|avi|flv|mov|m4v|mpg|wmv|mpeg|mp4|webm)$/i', strtolower($fileName))) {
|
|
||||||
$NAMEHASH = hash('sha256', $fileName);
|
|
||||||
if (!file_exists('resources/images/thumbnails/' . $NAMEHASH . '.jpg')) {
|
|
||||||
shell_exec('resources/ffmpegthumbnailer -t 65% -s 320 -c jpg '
|
|
||||||
. '-i "' . $subPath . $fullPath . '" '
|
|
||||||
. '-o resources/images/thumbnails/' . $NAMEHASH . '.jpg'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$GeneratedJSON['list']['vids'][] = array('video' =>
|
|
||||||
array('title' => $subPath . $fileName,
|
|
||||||
'thumbnail' => $NAMEHASH . '.jpg'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
} elseif (preg_match('/^.*\.(png|jpg|gif|jpeg)$/i', strtolower($fileName))) {
|
|
||||||
$GeneratedJSON['list']['imgs'][] = array('image' => $subPath . $fileName);
|
|
||||||
} elseif (filetype($fullPath) == "dir") {
|
|
||||||
$GeneratedJSON['list']['dirs'][] = array('dir' => $fileName . "/");
|
|
||||||
} else {
|
|
||||||
$GeneratedJSON['list']['files'][] = array('file' => $subPath . $fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isInDBCheck($PATH) {
|
|
||||||
$db = new SQLite3('resources/db/webfm.db');
|
|
||||||
|
|
||||||
if($db === false){
|
|
||||||
$message = "Server: [Error] --> Database connection failed!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
die("ERROR: Could not connect to db.");
|
|
||||||
}
|
|
||||||
|
|
||||||
$stmt = $db->prepare('SELECT 1 FROM faves WHERE link = :link');
|
|
||||||
$stmt->bindValue(":link", $PATH, SQLITE3_TEXT);
|
|
||||||
$result = $stmt->execute() ;
|
|
||||||
$row = $result->fetchArray() ;
|
|
||||||
|
|
||||||
if ($row > 0) {
|
|
||||||
return "true";
|
|
||||||
} else {
|
|
||||||
return "false";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Determin action
|
|
||||||
chdir("../../");
|
|
||||||
if (isset($_POST['dirQuery'])) {
|
|
||||||
startListing(trim($_POST['dirQuery']), $_POST['mergeType'], $_POST['passwd']);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Error] --> Illegal Access Method!";
|
|
||||||
serverMessage("error", $message);
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?php
|
|
||||||
// Check if sub folder is in locked folder
|
|
||||||
function checkForLock($NEWPATH, $PASSWD) {
|
|
||||||
include 'config.php';
|
|
||||||
|
|
||||||
$LOCKS = explode("::::", $LOCKEDFOLDERS);
|
|
||||||
$size = sizeof($LOCKS);
|
|
||||||
|
|
||||||
if (isset($_SESSION["unlockState"]) && $_SESSION["unlockState"] == true) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for ($i = 0; $i < $size; $i++) {
|
|
||||||
if (strpos($NEWPATH, $LOCKS[$i]) !== false) {
|
|
||||||
if ($PASSWD === $LOCKPASSWORD) {
|
|
||||||
$_SESSION["unlockState"] = true;
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function lockFolders() {
|
|
||||||
session_start();
|
|
||||||
include 'serverMessenger.php';
|
|
||||||
|
|
||||||
if (isset($_SESSION["unlockState"]) && $_SESSION["unlockState"] == true) {
|
|
||||||
$_SESSION["unlockState"] = false;
|
|
||||||
$message = "Server: [Success] --> Folders unlocked!";
|
|
||||||
serverMessage("success", $message);
|
|
||||||
} else {
|
|
||||||
$message = "Server: [Warning] --> Folders aren't unlocked!"
|
|
||||||
. "\n" . $_SESSION["unlockState"];
|
|
||||||
serverMessage("warning", $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isset($_POST['lockFolders'])) {
|
|
||||||
lockFolders();
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
|
@ -1,12 +0,0 @@
|
||||||
<?php
|
|
||||||
function serverMessage($TYPE, $MESSAGE) {
|
|
||||||
$GeneratedJSON = array( 'message' =>
|
|
||||||
array(
|
|
||||||
'type' => $TYPE,
|
|
||||||
'text' => $MESSAGE
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
echo json_encode($GeneratedJSON);
|
|
||||||
}
|
|
||||||
?>
|
|
|
@ -1,16 +0,0 @@
|
||||||
<?php
|
|
||||||
// Start the session
|
|
||||||
session_start();
|
|
||||||
include_once 'config.php';
|
|
||||||
|
|
||||||
if (!isset($_SESSION["refreshState"])) {
|
|
||||||
$_SESSION["refreshState"] = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: text/event-stream');
|
|
||||||
header('Cache-Control: no-cache');
|
|
||||||
echo "data:" . $_SESSION["refreshState"] . "\n\n";
|
|
||||||
|
|
||||||
$_SESSION["refreshState"] = "none";
|
|
||||||
flush();
|
|
||||||
?>
|
|
|
@ -1 +0,0 @@
|
||||||
Place Holder....
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import Flask
|
||||||
|
#OIDC Login path
|
||||||
|
from flask_oidc import OpenIDConnect
|
||||||
|
# Flask Login Path
|
||||||
|
from flask_bcrypt import Bcrypt
|
||||||
|
from flask_login import current_user, login_user, logout_user, LoginManager
|
||||||
|
|
||||||
|
|
||||||
|
# Apoplication imports
|
||||||
|
from core.utils import Logger
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object("core.config.ProductionConfig")
|
||||||
|
# app.config.from_object("core.config.DevelopmentConfig")
|
||||||
|
|
||||||
|
oidc = OpenIDConnect(app)
|
||||||
|
login_manager = LoginManager(app)
|
||||||
|
bcrypt = Bcrypt(app)
|
||||||
|
logger = Logger().get_logger()
|
||||||
|
|
||||||
|
def oidc_loggedin():
|
||||||
|
return oidc.user_loggedin
|
||||||
|
|
||||||
|
def oidc_isAdmin():
|
||||||
|
if oidc_loggedin():
|
||||||
|
isAdmin = oidc.user_getfield("isAdmin")
|
||||||
|
if isAdmin == "yes" :
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
app.jinja_env.globals['oidc_loggedin'] = oidc_loggedin
|
||||||
|
app.jinja_env.globals['oidc_isAdmin'] = oidc_isAdmin
|
||||||
|
app.jinja_env.globals['TITLE'] = app.config["TITLE"]
|
||||||
|
|
||||||
|
|
||||||
|
from core.models import db, User, Favorites
|
||||||
|
db.init_app(app)
|
||||||
|
with app.app_context():
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
from core.forms import RegisterForm, LoginForm
|
||||||
|
from core import routes
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"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": "9028c2ac-d6e0-4d96-86bd-02624b91695d",
|
||||||
|
"redirect_uris": [
|
||||||
|
"https%3A%2F%2Fwww.webfm.com%2F"
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
# System import
|
||||||
|
import os, secrets
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
|
||||||
|
# Apoplication imports
|
||||||
|
|
||||||
|
|
||||||
|
# Configs
|
||||||
|
APP_NAME = 'WebFM'
|
||||||
|
ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
TITLE = APP_NAME
|
||||||
|
DEBUG = False
|
||||||
|
TESTING = False
|
||||||
|
THREADED = True
|
||||||
|
SECRET_KEY = "2A#GQafbREoblgMSQYomZSxbaPE6dt#"
|
||||||
|
# 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
|
||||||
|
|
||||||
|
LOGIN_PATH = "OIDC" # Value can be OIDC or FLASK_LOGIN
|
||||||
|
OIDC_TOKEN_TYPE_HINT = 'access_token'
|
||||||
|
APP_REDIRECT_URI = "https%3A%2F%2Fwww.webfm.com%2F" # This path is submitted as the redirect URI in certain code flows
|
||||||
|
OIDC_CLIENT_SECRETS = ROOT_FILE_PTH + '/client_secrets.json'
|
||||||
|
OIDC_ID_TOKEN_COOKIE_SECURE = True
|
||||||
|
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'
|
||||||
|
]
|
||||||
|
|
||||||
|
STATIC_FPTH = ROOT_FILE_PTH + "/static"
|
||||||
|
REL_THUMBS_PTH = "static/imgs/thumbnails" # Used for flask thumbnail return
|
||||||
|
|
||||||
|
# We are overiding some of the the shellmen view settings with these to make it all work with flask.
|
||||||
|
# These are passed along to the shellmen view from the Routes file upon the window controller creation.
|
||||||
|
ABS_THUMBS_PTH = STATIC_FPTH + "/imgs/thumbnails" # Used for thumbnail generation
|
||||||
|
REMUX_FOLDER = STATIC_FPTH + "/remuxs" # Remuxed files folder
|
||||||
|
FFMPG_THUMBNLR = STATIC_FPTH + "/ffmpegthumbnailer" # Thumbnail generator binary
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ProductionConfig(Config):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class DevelopmentConfig(Config):
|
||||||
|
DEBUG = True
|
||||||
|
USE_RELOADER = True
|
||||||
|
OIDC_ID_TOKEN_COOKIE_SECURE = False
|
||||||
|
OIDC_REQUIRE_VERIFIED_EMAIL = False
|
||||||
|
|
||||||
|
|
||||||
|
class TestingConfig(Config):
|
||||||
|
TESTING = True
|
|
@ -0,0 +1,24 @@
|
||||||
|
from flask_wtf import FlaskForm
|
||||||
|
from wtforms import StringField, PasswordField, SubmitField
|
||||||
|
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
|
||||||
|
from core import User
|
||||||
|
|
||||||
|
|
||||||
|
class RegisterForm(FlaskForm):
|
||||||
|
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
|
||||||
|
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||||
|
password = PasswordField('Password', validators=[DataRequired(), Length(min=8)])
|
||||||
|
confirm_password = PasswordField('Confirm Password',
|
||||||
|
validators=[DataRequired(), EqualTo('password', message="Passwords must match!")])
|
||||||
|
submit = SubmitField("Sign Up")
|
||||||
|
|
||||||
|
def validate_username(self, username):
|
||||||
|
user = User.query.filter_by(username=username.data).first()
|
||||||
|
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")
|
|
@ -0,0 +1,41 @@
|
||||||
|
# System imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from . import app, login_manager
|
||||||
|
from flask_login import UserMixin
|
||||||
|
|
||||||
|
|
||||||
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
|
||||||
|
@login_manager.user_loader
|
||||||
|
def load_user(user_id):
|
||||||
|
return User.query.get(int(user_id))
|
||||||
|
|
||||||
|
|
||||||
|
class User(db.Model, UserMixin):
|
||||||
|
username = db.Column(db.String, unique=True, nullable=False)
|
||||||
|
email = db.Column(db.String, 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}']"
|
||||||
|
|
||||||
|
class Favorites(db.Model):
|
||||||
|
link = db.Column(db.String, nullable=False, unique=True)
|
||||||
|
id = db.Column(db.Integer, nullable=False, primary_key=True, unique=True, autoincrement=True)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"['{self.link}', '{self.id}']"
|
||||||
|
|
||||||
|
class Settings(db.Model):
|
||||||
|
key = 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)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"['{self.key}', '{self.value}', '{self.id}']"
|
|
@ -0,0 +1,279 @@
|
||||||
|
# Python imports
|
||||||
|
import os, json, secrets, re, shutil
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import request, session, render_template, send_from_directory, redirect
|
||||||
|
from flask_uploads import UploadSet, configure_uploads, ALL
|
||||||
|
from flask_login import current_user
|
||||||
|
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from core import app, logger, oidc, db, Favorites # Get from __init__
|
||||||
|
from core.utils import MessageHandler # Get simple message processor
|
||||||
|
from core.utils.shellfm import WindowController # Get file manager controller
|
||||||
|
|
||||||
|
|
||||||
|
msgHandler = MessageHandler()
|
||||||
|
window_controllers = {}
|
||||||
|
# valid_fname_pat = re.compile(r"/^[a-zA-Z0-9-_\[\]\(\)| ]+$/")
|
||||||
|
valid_fname_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]{4,20}")
|
||||||
|
|
||||||
|
|
||||||
|
def get_window_controller():
|
||||||
|
controller = None
|
||||||
|
try:
|
||||||
|
controller = window_controllers[ session["win_controller_id"] ]
|
||||||
|
except Exception as e:
|
||||||
|
id = secrets.token_hex(16)
|
||||||
|
controller = WindowController()
|
||||||
|
view = controller.get_window(1).get_view(0)
|
||||||
|
view.ABS_THUMBS_PTH = app.config['ABS_THUMBS_PTH']
|
||||||
|
view.REMUX_FOLDER = app.config['REMUX_FOLDER']
|
||||||
|
view.FFMPG_THUMBNLR = app.config['FFMPG_THUMBNLR']
|
||||||
|
view.logger = logger
|
||||||
|
|
||||||
|
session['win_controller_id'] = id
|
||||||
|
window_controllers.update( {id: controller } )
|
||||||
|
controller = window_controllers[ session["win_controller_id"] ]
|
||||||
|
|
||||||
|
return controller
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/', methods=['GET', 'POST'])
|
||||||
|
def home():
|
||||||
|
if request.method == 'GET':
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
_dot_dots = view.get_dot_dots()
|
||||||
|
_current_directory = view.get_current_directory()
|
||||||
|
return render_template('pages/index.html', current_directory = _current_directory, dot_dots = _dot_dots)
|
||||||
|
|
||||||
|
return render_template('error.html', title = 'Error!',
|
||||||
|
message = 'Must use GET request type...')
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/list-files/<_hash>', methods=['GET', 'POST'])
|
||||||
|
def listFiles(_hash = None):
|
||||||
|
if request.method == 'POST':
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
dot_dots = view.get_dot_dots()
|
||||||
|
|
||||||
|
if dot_dots[0][1] == _hash: # Refresh
|
||||||
|
view.load_directory()
|
||||||
|
elif dot_dots[1][1] == _hash: # Pop from dir
|
||||||
|
view.pop_from_path()
|
||||||
|
|
||||||
|
msg = "Log in with an Admin privlidged user to view the requested path!"
|
||||||
|
is_locked = view.is_folder_locked(_hash)
|
||||||
|
if is_locked and not oidc.user_loggedin:
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
elif is_locked and oidc.user_loggedin:
|
||||||
|
isAdmin = oidc.user_getfield("isAdmin")
|
||||||
|
if isAdmin != "yes" :
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
if dot_dots[0][1] != _hash and dot_dots[1][1] != _hash:
|
||||||
|
path = view.get_path_part_from_hash(_hash)
|
||||||
|
view.push_to_path(path)
|
||||||
|
|
||||||
|
error_msg = view.get_error_message()
|
||||||
|
if error_msg != None:
|
||||||
|
view.unset_error_message()
|
||||||
|
return msgHandler.createMessageJSON("danger", error_msg)
|
||||||
|
|
||||||
|
|
||||||
|
sub_path = view.get_current_sub_path()
|
||||||
|
files = view.get_files_formatted()
|
||||||
|
fave = db.session.query(Favorites).filter_by(link = sub_path).first()
|
||||||
|
in_fave = "true" if fave else "false"
|
||||||
|
files.update({'in_fave': in_fave})
|
||||||
|
return files
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
@app.route('/api/file-manager-action/<_type>/<_hash>', methods=['GET', 'POST'])
|
||||||
|
def fileManagerAction(_type, _hash = None):
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
|
||||||
|
if _type == "reset-path" and _hash == "None":
|
||||||
|
view.set_to_home()
|
||||||
|
msg = "Returning to home directory..."
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
|
||||||
|
folder = view.get_current_directory()
|
||||||
|
file = view.get_path_part_from_hash(_hash)
|
||||||
|
fpath = os.path.join(folder, file)
|
||||||
|
logger.debug(fpath)
|
||||||
|
|
||||||
|
if _type == "files":
|
||||||
|
return send_from_directory(folder, file)
|
||||||
|
if _type == "remux":
|
||||||
|
# NOTE: Need to actually implimint a websocket to communicate back to client that remux has completed.
|
||||||
|
# As is, the remux thread hangs until completion and client tries waiting until server reaches connection timeout.
|
||||||
|
# I.E....this is stupid but for now works better than nothing
|
||||||
|
good_result = view.remuxVideo(_hash, fpath)
|
||||||
|
if good_result:
|
||||||
|
return '{"path":"static/remuxs/' + _hash + '.mp4"}'
|
||||||
|
else:
|
||||||
|
msg = "Remuxing: Remux failed or took too long; please, refresh the page and try again..."
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
if _type == "run-locally":
|
||||||
|
msg = "Opened media..."
|
||||||
|
view.openFilelocally(fpath)
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE: Positionally protecting actions further down that are privlidged
|
||||||
|
# Be aware of ordering!
|
||||||
|
msg = "Log in with an Admin privlidged user to do this action!"
|
||||||
|
if not oidc.user_loggedin:
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
elif oidc.user_loggedin:
|
||||||
|
isAdmin = oidc.user_getfield("isAdmin")
|
||||||
|
if isAdmin != "yes" :
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
if _type == "delete":
|
||||||
|
try:
|
||||||
|
msg = f"[Success] Deleted the file/folder -->: {file} !"
|
||||||
|
if os.path.isfile(fpath):
|
||||||
|
os.unlink(fpath)
|
||||||
|
else:
|
||||||
|
shutil.rmtree(fpath)
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
except Exception as e:
|
||||||
|
msg = "[Error] Unable to delete the file/folder...."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/list-favorites', methods=['GET', 'POST'])
|
||||||
|
def listFavorites():
|
||||||
|
if request.method == 'POST':
|
||||||
|
list = db.session.query(Favorites).all()
|
||||||
|
faves = []
|
||||||
|
for fave in list:
|
||||||
|
faves.append([fave.link, fave.id])
|
||||||
|
|
||||||
|
return '{"faves_list":' + json.dumps(faves) + '}'
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
@app.route('/api/load-favorite/<_id>', methods=['GET', 'POST'])
|
||||||
|
def loadFavorite(_id):
|
||||||
|
if request.method == 'POST':
|
||||||
|
try:
|
||||||
|
ID = int(_id)
|
||||||
|
fave = db.session.query(Favorites).filter_by(id = ID).first()
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
view.set_path_with_sub_path(fave.link)
|
||||||
|
return '{"refresh": "true"}'
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
msg = "Incorrect Favorites ID..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/manage-favorites/<_action>', methods=['GET', 'POST'])
|
||||||
|
def manageFavorites(_action):
|
||||||
|
if request.method == 'POST':
|
||||||
|
ACTION = _action.strip()
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
sub_path = view.get_current_sub_path()
|
||||||
|
|
||||||
|
if ACTION == "add":
|
||||||
|
fave = Favorites(link = sub_path)
|
||||||
|
db.session.add(fave)
|
||||||
|
msg = "Added to Favorites successfully..."
|
||||||
|
elif ACTION == "delete":
|
||||||
|
fave = db.session.query(Favorites).filter_by(link = sub_path).first()
|
||||||
|
db.session.delete(fave)
|
||||||
|
msg = "Deleted from Favorites successfully..."
|
||||||
|
else:
|
||||||
|
msg = "Couldn't handle action for favorites item..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
db.session.commit()
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/create/<_type>', methods=['GET', 'POST'])
|
||||||
|
def create_item(_type = None):
|
||||||
|
if request.method == 'POST':
|
||||||
|
msg = "Log in with an Admin privlidged user to upload files!"
|
||||||
|
if not oidc.user_loggedin:
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
elif oidc.user_loggedin:
|
||||||
|
isAdmin = oidc.user_getfield("isAdmin")
|
||||||
|
if isAdmin != "yes" :
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
TYPE = _type.strip()
|
||||||
|
FNAME = str(request.values['fname']).strip()
|
||||||
|
|
||||||
|
if not re.fullmatch(valid_fname_pat, FNAME):
|
||||||
|
msg = "A new item name can only contain alphanumeric, -, _, |, [], (), or spaces and must be minimum of 4 and max of 20 characters..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
folder = view.get_current_directory()
|
||||||
|
new_item = folder + '/' + FNAME
|
||||||
|
|
||||||
|
try:
|
||||||
|
if TYPE == "dir":
|
||||||
|
os.mkdir(new_item)
|
||||||
|
elif TYPE == "file":
|
||||||
|
open(new_item + ".txt", 'a').close()
|
||||||
|
else:
|
||||||
|
msg = "Couldn't handle action type for api create..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
msg = "Couldn't create file/folder. An unexpected error occured..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
msg = "[Success] created the file/dir..."
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/upload', methods=['GET', 'POST'])
|
||||||
|
def upload():
|
||||||
|
if request.method == 'POST' and len(request.files) > 0:
|
||||||
|
msg = "Log in with an Admin privlidged user to upload files!"
|
||||||
|
if not oidc.user_loggedin:
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
elif oidc.user_loggedin:
|
||||||
|
isAdmin = oidc.user_getfield("isAdmin")
|
||||||
|
if isAdmin != "yes" :
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
|
folder = view.get_current_directory()
|
||||||
|
UPLOADS_PTH = folder + '/'
|
||||||
|
files = UploadSet('files', ALL, default_dest=lambda x: UPLOADS_PTH)
|
||||||
|
configure_uploads(app, files)
|
||||||
|
|
||||||
|
for file in request.files:
|
||||||
|
try:
|
||||||
|
files.save(request.files[file])
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
msg = "[Error] Failed to upload some or all of the file(s)..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
||||||
|
|
||||||
|
msg = "[Success] Uploaded file(s)..."
|
||||||
|
return msgHandler.createMessageJSON("success", msg)
|
||||||
|
else:
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return msgHandler.createMessageJSON("danger", msg)
|
|
@ -0,0 +1,6 @@
|
||||||
|
from . import Routes
|
||||||
|
from .pages import Flask_Login
|
||||||
|
from .pages import Flask_Register
|
||||||
|
from .pages import OIDC_Login
|
||||||
|
from .pages import OIDC_Register
|
||||||
|
from .pages import LoginManager
|
|
@ -0,0 +1,37 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import request, render_template, flash, redirect, url_for
|
||||||
|
from flask_login import current_user, login_user, logout_user
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from core import app, bcrypt, db, User, LoginForm
|
||||||
|
from core.utils import MessageHandler # Get simple message processor
|
||||||
|
|
||||||
|
|
||||||
|
msgHandler = MessageHandler()
|
||||||
|
|
||||||
|
@app.route('/app-login', methods=['GET', 'POST'])
|
||||||
|
def app_login():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for("home"))
|
||||||
|
|
||||||
|
_form = LoginForm()
|
||||||
|
if _form.validate_on_submit():
|
||||||
|
user = db.session.query(User).filter(User.username == _form.username.data).first()
|
||||||
|
|
||||||
|
if user and bcrypt.check_password_hash(user.password, _form.password.data):
|
||||||
|
login_user(user, remember=False)
|
||||||
|
flash("Logged in successfully!", "success")
|
||||||
|
return redirect(url_for("home"))
|
||||||
|
|
||||||
|
flash("Username or password incorrect! Please try again...", "danger")
|
||||||
|
|
||||||
|
return render_template('pages/login.html', form = _form)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/app-logout')
|
||||||
|
def app_logout():
|
||||||
|
logout_user()
|
||||||
|
flash("Logged out successfully!", "success")
|
||||||
|
return redirect(url_for("home"))
|
|
@ -0,0 +1,30 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import request, render_template, url_for, redirect, flash
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from core import app, bcrypt, db, current_user, RegisterForm # Get from __init__
|
||||||
|
from core.models import User
|
||||||
|
from core.utils import MessageHandler # Get simple message processor
|
||||||
|
|
||||||
|
|
||||||
|
msgHandler = MessageHandler()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/app-register', methods=['GET', 'POST'])
|
||||||
|
def app_register():
|
||||||
|
if current_user.is_authenticated:
|
||||||
|
return redirect(url_for("home"))
|
||||||
|
|
||||||
|
_form = RegisterForm()
|
||||||
|
if _form.validate_on_submit():
|
||||||
|
hashed_password = bcrypt.generate_password_hash(_form.password.data).decode("utf-8")
|
||||||
|
user = User(username = _form.username.data, email = _form.email.data, password = hashed_password)
|
||||||
|
db.session.add(user)
|
||||||
|
db.session.commit()
|
||||||
|
flash("Account created successfully!", "success")
|
||||||
|
return redirect(url_for("login"))
|
||||||
|
|
||||||
|
return render_template('pages/register.html',
|
||||||
|
form = _form)
|
|
@ -0,0 +1,43 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import redirect, url_for, flash
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from core import app
|
||||||
|
|
||||||
|
|
||||||
|
ROUTE = app.config['LOGIN_PATH']
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/login', methods=['GET', 'POST'])
|
||||||
|
def login():
|
||||||
|
if ROUTE == "OIDC":
|
||||||
|
return redirect(url_for("oidc_login"))
|
||||||
|
if ROUTE == "FLASK_LOGIN":
|
||||||
|
return redirect(url_for("app_login"))
|
||||||
|
|
||||||
|
flash("No Login Path Accessable! Please contact an Administrator!", "danger")
|
||||||
|
return redirect(url_for("home"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/logout')
|
||||||
|
def logout():
|
||||||
|
if ROUTE == "OIDC":
|
||||||
|
return redirect(url_for("oidc_logout"))
|
||||||
|
if ROUTE == "FLASK_LOGIN":
|
||||||
|
return redirect(url_for("app_logout"))
|
||||||
|
|
||||||
|
flash("No Logout Path Accessable! Please contact an Administrator!", "danger")
|
||||||
|
return redirect(url_for("home"))
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/register', methods=['GET', 'POST'])
|
||||||
|
def register():
|
||||||
|
if ROUTE == "OIDC":
|
||||||
|
return redirect(url_for("oidc_register"))
|
||||||
|
if ROUTE == "FLASK_LOGIN":
|
||||||
|
return redirect(url_for("app_register"))
|
||||||
|
|
||||||
|
flash("No Register Path Accessable! Please contact an Administrator!", "danger")
|
||||||
|
return redirect(url_for("home"))
|
|
@ -0,0 +1,27 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import request, redirect, flash
|
||||||
|
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from ... import app, oidc
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/oidc-login', methods=['GET', 'POST'])
|
||||||
|
@oidc.require_login
|
||||||
|
def oidc_login():
|
||||||
|
print(request)
|
||||||
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/oidc-logout', methods=['GET', 'POST'])
|
||||||
|
@oidc.require_login
|
||||||
|
def oidc_logout():
|
||||||
|
oidc.logout()
|
||||||
|
flash("Logged out successfully!", "success")
|
||||||
|
# NOTE: Need to redirect to logout on OIDC server to end session there too.
|
||||||
|
# If not, we can hit login url again and get same token until it expires.
|
||||||
|
return redirect( oidc.client_secrets.get('issuer')
|
||||||
|
+ '/protocol/openid-connect/logout?redirect_uri='
|
||||||
|
+ app.config['APP_REDIRECT_URI'])
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
from flask import request, render_template, url_for, redirect, flash
|
||||||
|
|
||||||
|
# App imports
|
||||||
|
from ... import app, oidc, db # Get from __init__
|
||||||
|
from ...utils import MessageHandler # Get simple message processor
|
||||||
|
|
||||||
|
|
||||||
|
msgHandler = MessageHandler()
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/oidc-register', methods=['GET', 'POST'])
|
||||||
|
def oidc_register():
|
||||||
|
if oidc.user_loggedin:
|
||||||
|
return redirect("/home")
|
||||||
|
|
||||||
|
_form = RegisterForm()
|
||||||
|
if _form.validate_on_submit():
|
||||||
|
# TODO: Create...
|
||||||
|
# NOTE: Do a requests api here maybe??
|
||||||
|
|
||||||
|
# hashed_password = bcrypt.generate_password_hash(_form.password.data).decode("utf-8")
|
||||||
|
# user = User(username=_form.username.data, password=hashed_password)
|
||||||
|
# db.session.add(user)
|
||||||
|
# db.session.commit()
|
||||||
|
flash("Account created successfully!", "success")
|
||||||
|
return redirect("/login")
|
||||||
|
|
||||||
|
return render_template('pages/register.html', form = _form)
|
|
@ -0,0 +1,50 @@
|
||||||
|
.menu {
|
||||||
|
width: 165px;
|
||||||
|
z-index: 999;
|
||||||
|
box-shadow: 0 4px 5px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
background-color: rgba(0, 0, 0, 0.64);
|
||||||
|
position: fixed;
|
||||||
|
display: none;
|
||||||
|
transition: 0.2s display ease-in;
|
||||||
|
}
|
||||||
|
.menu .menu-options {
|
||||||
|
list-style: none;
|
||||||
|
padding: 10px 0;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.menu .menu-options .menu-option {
|
||||||
|
font-weight: 500;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 10px 40px 10px 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu .menu-options .menu-option:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.64);
|
||||||
|
color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: grey;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
button .next {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
button[disabled="false"]:hover .next {
|
||||||
|
color: red;
|
||||||
|
animation: move 0.5s;
|
||||||
|
animation-iteration-count: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes move {
|
||||||
|
from {
|
||||||
|
transform: translate(0%);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate(-40%);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: transform(0%);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
body,
|
||||||
|
.container-fluid, .row, .col,
|
||||||
|
.error-styling, .dir-style, .movie-style, .file-style {
|
||||||
|
background-color: rgba(0,0,0,0.0);
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
#bg {
|
||||||
|
position: fixed;
|
||||||
|
top: 0%;
|
||||||
|
left: 0%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -999;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bg img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#master-container {
|
||||||
|
height: 90vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#video-controls {
|
||||||
|
position: relative;
|
||||||
|
bottom: 2.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* CLASSES */
|
||||||
|
.scroller {
|
||||||
|
scrollbar-color: #00000084 #ffffff64;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noselect {
|
||||||
|
-webkit-touch-callout: none; /* iOS Safari */
|
||||||
|
-webkit-user-select: none; /* Safari */
|
||||||
|
-khtml-user-select: none; /* Konqueror HTML */
|
||||||
|
-moz-user-select: none; /* Old versions of Firefox */
|
||||||
|
-ms-user-select: none; /* Internet Explorer/Edge */
|
||||||
|
user-select: none; /* Non-prefixed version, currently
|
||||||
|
supported by Chrome, Edge, Opera and Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.card-title-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.volume-control-positioner {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 3.5em;
|
||||||
|
right: 2.5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-style {
|
||||||
|
width: 2em;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewer {
|
||||||
|
max-width: 55em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Other message text colors */
|
||||||
|
.errorTxt { color: rgb(170, 18, 18); }
|
||||||
|
.warningTxt { color: rgb(255, 168, 0); }
|
||||||
|
.successTxt { color: rgb(136, 204, 39); }
|
|
@ -0,0 +1,81 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: Dosis;
|
||||||
|
src: url("/static/css/fonts/dosis/Dosis-Regular.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-Medium.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-Light.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-ExtraLight.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-Bold.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-ExtraBold.ttf"),
|
||||||
|
url("/static/css/fonts/dosis/Dosis-SemiBold.ttf"),
|
||||||
|
url("/static/css/fonts/Dosis-VariableFont_wght.ttf");
|
||||||
|
font-style: normal;
|
||||||
|
font-display: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Dosis;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul, li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Vertical slider */
|
||||||
|
input[type=range][orient=vertical] {
|
||||||
|
writing-mode: bt-lr; /* IE */
|
||||||
|
-webkit-appearance: slider-vertical; /* WebKit */
|
||||||
|
width: 8px;
|
||||||
|
height: 175px;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="col-"] {
|
||||||
|
background-clip: padding-box;
|
||||||
|
border: 10px solid transparent;
|
||||||
|
margin: 0em !important;
|
||||||
|
padding: 0em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sticky-top,
|
||||||
|
.card {
|
||||||
|
background-color: rgba(50, 56, 62, 0.84);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
min-height: 326px;
|
||||||
|
font-size: x-large;
|
||||||
|
vertical-align: middle !important;
|
||||||
|
align-items: center;
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-img, .card-img-top {
|
||||||
|
max-height: 285px !important;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-group-item {
|
||||||
|
color: rgba(255, 255, 255, 1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-as-badge {
|
||||||
|
border-radius: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
Delete this...
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 680 KiB |
Before Width: | Height: | Size: 216 KiB After Width: | Height: | Size: 216 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |