file manager and config updates, css changes, etc
This commit is contained in:
parent
840ffc8255
commit
f6f7cfda58
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,5 @@
|
|||||||
*.db
|
*.db
|
||||||
*.pyc
|
*.pyc
|
||||||
client_secrets.json
|
|
||||||
webfm_config.json
|
|
||||||
app.pid
|
app.pid
|
||||||
|
|
||||||
|
|
||||||
|
12
README.md
12
README.md
@ -3,11 +3,13 @@ WebFM is a media and file viewer aspiring to become a full fledged file manager
|
|||||||
|
|
||||||
# Usage
|
# Usage
|
||||||
1. Install python, sqlite3, and ffmpeg on the system this will be on.
|
1. Install python, sqlite3, and ffmpeg on the system this will be on.
|
||||||
3. Use ufw or gufw to open the port on your computer to the network.
|
3. Use ufw or gufw to open the port on your computer to the local network.
|
||||||
4. Place files or start uploading some to the folders.
|
4. Use hosts file (or other methods) to redirect webfm.com and ssoapps.com to local app.
|
||||||
5. 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.
|
5. Update client_secrets.json > 'client_secret' field with your Keycloak key. (Current one is local to me and not public)
|
||||||
9. Password protect folder based on core/webfm_config.json file settings.
|
6. Place files or start uploading some to the folders.
|
||||||
10. Save paths to favorites list for quick access.
|
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. Password protect folder based on core/utils/shellfm/windows/webfm_config.json file settings.
|
||||||
|
8. Save paths to favorites list for quick access.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
n/a
|
n/a
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
"auth_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/auth",
|
"auth_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/auth",
|
||||||
"client_id": "apps",
|
"client_id": "apps",
|
||||||
"issuer": "https://www.ssoapps.com/auth/realms/apps",
|
"issuer": "https://www.ssoapps.com/auth/realms/apps",
|
||||||
"client_secret": "[Add your secret key here]",
|
"client_secret": "ce6fdb7d-fdcb-46ea-bc80-b5df9649d50b",
|
||||||
"redirect_uris": [
|
"redirect_uris": [
|
||||||
"http://www.webfm.com/home",
|
"https://www.webfm.com/home",
|
||||||
"https://www.webfm.com/home"
|
"http://www.webfm.com/home"
|
||||||
],
|
],
|
||||||
"userinfo_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/userinfo",
|
"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_uri": "https://www.ssoapps.com/auth/realms/apps/protocol/openid-connect/token",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# System import
|
# System import
|
||||||
import os, secrets, json
|
import os, secrets
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
@ -12,19 +12,9 @@ from datetime import timedelta
|
|||||||
APP_NAME = 'WebFM'
|
APP_NAME = 'WebFM'
|
||||||
# Configs
|
# Configs
|
||||||
ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
||||||
CONFIG_FILE = ROOT_FILE_PTH + "/webfm_config.json"
|
|
||||||
# This path is submitted as the redirect URI in certain code flows.
|
# This path is submitted as the redirect URI in certain code flows.
|
||||||
REDIRECT_LINK = "https%3A%2F%2Fwww.webfm.com%2F"
|
REDIRECT_LINK = "https%3A%2F%2Fwww.webfm.com%2F"
|
||||||
|
|
||||||
# Settings data
|
|
||||||
def retrieveSettings():
|
|
||||||
returnData = []
|
|
||||||
with open(CONFIG_FILE) as infile:
|
|
||||||
try:
|
|
||||||
return json.load(infile)
|
|
||||||
except Exception as e:
|
|
||||||
print(repr(e))
|
|
||||||
return ['', 'mplayer', 'xdg-open']
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -50,10 +40,14 @@ class Config(object):
|
|||||||
'https://localhost:443/auth/realms/apps'
|
'https://localhost:443/auth/realms/apps'
|
||||||
]
|
]
|
||||||
|
|
||||||
WEBFM_CONFIG = retrieveSettings()
|
|
||||||
STATIC_FPTH = ROOT_FILE_PTH + "/static"
|
STATIC_FPTH = ROOT_FILE_PTH + "/static"
|
||||||
REMUX_FOLDER = STATIC_FPTH + "/remuxs"
|
REMUX_FOLDER = STATIC_FPTH + "/remuxs" # Remuxed files folder
|
||||||
FFMPG_THUMBNLR = STATIC_FPTH + "/ffmpegthumbnailer"
|
FFMPG_THUMBNLR = STATIC_FPTH + "/ffmpegthumbnailer" # Thumbnail generator binary
|
||||||
|
|
||||||
|
ABS_THUMBS_PTH = STATIC_FPTH + "/imgs/thumbnails" # Used for thumbnail generation
|
||||||
|
REL_THUMBS_PTH = "static/imgs/thumbnails" # Used for flask thumbnail return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ProductionConfig(Config):
|
class ProductionConfig(Config):
|
||||||
|
@ -30,7 +30,7 @@ def home():
|
|||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
view = get_window_controller().get_window(1).get_view(0)
|
view = get_window_controller().get_window(1).get_view(0)
|
||||||
_path = view.get_path()
|
_path = view.get_path()
|
||||||
_files = view.get_files()
|
_files = view.get_files_formatted()
|
||||||
return render_template('pages/index.html', path=_path, files=_files)
|
return render_template('pages/index.html', path=_path, files=_files)
|
||||||
|
|
||||||
return render_template('error.html',
|
return render_template('error.html',
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: -999;
|
z-index: -999;
|
||||||
|
object-fit: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
#bg img {
|
#bg img {
|
||||||
@ -19,7 +20,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#master-container {
|
#master-container {
|
||||||
height: 85vh;
|
height: 90vh;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
@ -47,9 +48,9 @@
|
|||||||
|
|
||||||
|
|
||||||
.dir-style, .video-style, .image-style, .file-style {
|
.dir-style, .video-style, .image-style, .file-style {
|
||||||
height: auto;
|
/* max-width: 24vw; */
|
||||||
width: 24vw;
|
/* height: auto;
|
||||||
position: relative;
|
position: relative; */
|
||||||
max-width: 20em;
|
max-width: 20em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<div class="input-group input-group-sm justify-content-center">
|
<div class="input-group input-group-sm justify-content-center">
|
||||||
<button title="Other Options..." class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#options-modal">⚙</button>
|
<button title="Other Options..." class="btn btn-secondary btn-sm" data-toggle="modal" data-target="#options-modal">⚙</button>
|
||||||
<button title="Refresh..." id="refresh-btn" class="btn btn-sm btn-secondary" hash="{{files[0][1]}}">↻</button>
|
<button title="Refresh..." id="refresh-btn" class="btn btn-sm btn-secondary" hash="{{files['files'][0][1]}}">↻</button>
|
||||||
<button title="Back..." id="back-btn" class="btn btn-sm btn-secondary" hash="{{files[1][1]}}">⇐</button>
|
<button title="Back..." id="back-btn" class="btn btn-sm btn-secondary" hash="{{files['files'][1][1]}}">⇐</button>
|
||||||
|
|
||||||
<input id="search-files-field" type="text" class="form-control" aria-label="Search..." placeholder="Search..." style="max-width: 260px">
|
<input id="search-files-field" type="text" class="form-control" aria-label="Search..." placeholder="Search..." style="max-width: 260px">
|
||||||
<div class="input-group-prepend">
|
<div class="input-group-prepend">
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
{% block body_content_additional %}
|
{% block body_content_additional %}
|
||||||
<div id="files" class="row">
|
<div id="files" class="row">
|
||||||
{% for file in files %}
|
{% for file in files['files'] %}
|
||||||
<div class="col-sm-12 col-md-6 col-lg-4">
|
<div class="col-sm-12 col-md-6 col-lg-4">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">{{file[0]}}</div>
|
<div class="card-header">{{file[0]}}</div>
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
class Filters:
|
|
||||||
fvideos = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
|
|
||||||
foffice = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm', '.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf')
|
|
||||||
fimages = ('.png', '.jpg', '.jpeg', '.gif', '.ico', '.tga')
|
|
||||||
ftext = ('.txt', '.text', '.sh', '.cfg', '.conf')
|
|
||||||
fmusic = ('.psf', '.mp3', '.ogg', '.flac', '.m4a')
|
|
||||||
fpdf = ('.pdf')
|
|
||||||
|
|
||||||
subpath = "/LazyShare/Synced Backup/222_Photos/Backgrounds/HD-Wallpapers"
|
|
@ -1,29 +1,39 @@
|
|||||||
|
# System import
|
||||||
|
import os, subprocess, threading
|
||||||
|
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
|
||||||
|
# Apoplication imports
|
||||||
|
|
||||||
|
|
||||||
class Launcher:
|
class Launcher:
|
||||||
def openFilelocally(self, file):
|
def openFilelocally(self, file):
|
||||||
lowerName = file.lower()
|
lowerName = file.lower()
|
||||||
command = []
|
command = []
|
||||||
|
|
||||||
if lowerName.endswith(self.VEXTENSION):
|
if lowerName.endswith(self.fvideos):
|
||||||
player = config["settings"]["media_app"]
|
player = self.fm_config["settings"]["media_app"]
|
||||||
options = config["settings"]["mplayer_options"].split()
|
options = self.fm_config["settings"]["mplayer_options"].split()
|
||||||
command = [player]
|
command = [player]
|
||||||
|
|
||||||
if "mplayer" in player:
|
if "mplayer" in player:
|
||||||
command += options
|
command += options
|
||||||
|
|
||||||
command += [file]
|
command += [file]
|
||||||
elif lowerName.endswith(self.IEXTENSION):
|
elif lowerName.endswith(self.fimages):
|
||||||
command = [config["settings"]["image_app"], file]
|
command = [self.fm_config["settings"]["image_app"], file]
|
||||||
elif lowerName.endswith(self.MEXTENSION):
|
elif lowerName.endswith(self.fmusic):
|
||||||
command = [config["settings"]["music_app"], file]
|
command = [self.fm_config["settings"]["music_app"], file]
|
||||||
elif lowerName.endswith(self.OEXTENSION):
|
elif lowerName.endswith(self.foffice):
|
||||||
command = [config["settings"]["office_app"], file]
|
command = [self.fm_config["settings"]["office_app"], file]
|
||||||
elif lowerName.endswith(self.TEXTENSION):
|
elif lowerName.endswith(self.ftext):
|
||||||
command = [config["settings"]["text_app"], file]
|
command = [self.fm_config["settings"]["text_app"], file]
|
||||||
elif lowerName.endswith(self.PEXTENSION):
|
elif lowerName.endswith(self.fpdf):
|
||||||
command = [config["settings"]["pdf_app"], file]
|
command = [self.fm_config["settings"]["pdf_app"], file]
|
||||||
else:
|
else:
|
||||||
command = [config["settings"]["file_manager_app"], file]
|
command = [self.fm_config["settings"]["file_manager_app"], file]
|
||||||
|
|
||||||
self.logging.debug(command)
|
self.logging.debug(command)
|
||||||
DEVNULL = open(os.devnull, 'w')
|
DEVNULL = open(os.devnull, 'w')
|
||||||
@ -32,25 +42,10 @@ class Launcher:
|
|||||||
|
|
||||||
def remuxVideo(self, hash, file):
|
def remuxVideo(self, hash, file):
|
||||||
remux_vid_pth = self.REMUX_FOLDER + "/" + hash + ".mp4"
|
remux_vid_pth = self.REMUX_FOLDER + "/" + hash + ".mp4"
|
||||||
message = '{"path":"static/remuxs/' + hash + '.mp4"}'
|
|
||||||
|
|
||||||
self.logging.debug(remux_vid_pth)
|
self.logging.debug(remux_vid_pth)
|
||||||
self.logging.debug(message)
|
|
||||||
|
|
||||||
if not os.path.isfile(remux_vid_pth):
|
if not os.path.isfile(remux_vid_pth):
|
||||||
limit = config["settings"]["remux_folder_max_disk_usage"]
|
self.check_remux_space()
|
||||||
try:
|
|
||||||
limit = int(limit)
|
|
||||||
except Exception as e:
|
|
||||||
self.logging.debug(e)
|
|
||||||
return
|
|
||||||
|
|
||||||
usage = self.getRemuxFolderUsage(self.REMUX_FOLDER)
|
|
||||||
if usage > limit:
|
|
||||||
files = os.listdir(self.REMUX_FOLDER)
|
|
||||||
for file in files:
|
|
||||||
fp = os.path.join(self.REMUX_FOLDER, file)
|
|
||||||
os.unlink(fp)
|
|
||||||
|
|
||||||
command = ["ffmpeg", "-i", file, "-hide_banner", "-movflags", "+faststart"]
|
command = ["ffmpeg", "-i", file, "-hide_banner", "-movflags", "+faststart"]
|
||||||
if file.endswith("mkv"):
|
if file.endswith("mkv"):
|
||||||
@ -67,11 +62,11 @@ class Launcher:
|
|||||||
proc = subprocess.Popen(command)
|
proc = subprocess.Popen(command)
|
||||||
proc.wait()
|
proc.wait()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
message = '{"message": {"type": "danger", "text":"' + str( repr(e) ) + '"}}'
|
|
||||||
self.logging.debug(message)
|
self.logging.debug(message)
|
||||||
self.logging.debug(e)
|
self.logging.debug(e)
|
||||||
|
return False
|
||||||
|
|
||||||
return message
|
return True
|
||||||
|
|
||||||
|
|
||||||
def generateVideoThumbnail(self, fullPath, hashImgPth):
|
def generateVideoThumbnail(self, fullPath, hashImgPth):
|
||||||
@ -81,13 +76,29 @@ class Launcher:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logging.debug(repr(e))
|
self.logging.debug(repr(e))
|
||||||
|
|
||||||
|
|
||||||
|
def check_remux_space(self):
|
||||||
|
limit = self.fm_config["settings"]["remux_folder_max_disk_usage"]
|
||||||
|
try:
|
||||||
|
limit = int(limit)
|
||||||
|
except Exception as e:
|
||||||
|
self.logging.debug(e)
|
||||||
|
return
|
||||||
|
|
||||||
|
usage = self.getRemuxFolderUsage(self.REMUX_FOLDER)
|
||||||
|
if usage > limit:
|
||||||
|
files = os.listdir(self.REMUX_FOLDER)
|
||||||
|
for file in files:
|
||||||
|
fp = os.path.join(self.REMUX_FOLDER, file)
|
||||||
|
os.unlink(fp)
|
||||||
|
|
||||||
|
|
||||||
def getRemuxFolderUsage(self, start_path = "."):
|
def getRemuxFolderUsage(self, start_path = "."):
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for dirpath, dirnames, filenames in os.walk(start_path):
|
for dirpath, dirnames, filenames in os.walk(start_path):
|
||||||
for f in filenames:
|
for f in filenames:
|
||||||
fp = os.path.join(dirpath, f)
|
fp = os.path.join(dirpath, f)
|
||||||
# skip if it is symbolic link
|
if not os.path.islink(fp): # Skip if it is symbolic link
|
||||||
if not os.path.islink(fp):
|
|
||||||
total_size += os.path.getsize(fp)
|
total_size += os.path.getsize(fp)
|
||||||
|
|
||||||
return total_size
|
return total_size
|
||||||
|
26
src/core/utils/shellfm/windows/Settings.py
Normal file
26
src/core/utils/shellfm/windows/Settings.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# System import
|
||||||
|
import json
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
|
||||||
|
# Apoplication imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Settings:
|
||||||
|
ABS_THUMBS_PTH = None # Used for thumbnail generation and is set by passing in
|
||||||
|
REMUX_FOLDER = None # Used for Remuxed files and is set by passing in
|
||||||
|
FFMPG_THUMBNLR = None # Used for thumbnail generator binary and is set by passing in
|
||||||
|
|
||||||
|
CONFIG_FILE = path.dirname(__file__) + '/webfm_config.json'
|
||||||
|
subpath = "/LazyShare" # modify 'home' folder path
|
||||||
|
|
||||||
|
fvideos = ('.mkv', '.avi', '.flv', '.mov', '.m4v', '.mpg', '.wmv', '.mpeg', '.mp4', '.webm')
|
||||||
|
foffice = ('.doc', '.docx', '.xls', '.xlsx', '.xlt', '.xltx', '.xlm', '.ppt', 'pptx', '.pps', '.ppsx', '.odt', '.rtf')
|
||||||
|
fimages = ('.png', '.jpg', '.jpeg', '.gif', '.ico', '.tga')
|
||||||
|
ftext = ('.txt', '.text', '.sh', '.cfg', '.conf')
|
||||||
|
fmusic = ('.psf', '.mp3', '.ogg', '.flac', '.m4a')
|
||||||
|
fpdf = ('.pdf')
|
@ -8,10 +8,10 @@ from os.path import isdir, isfile, join
|
|||||||
|
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from . import Path, Filters, Launcher
|
from . import Path, Settings, Launcher
|
||||||
|
|
||||||
|
|
||||||
class View(Filters, Path, Launcher):
|
class View(Settings, Launcher, Path):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.hideHiddenFiles = True
|
self.hideHiddenFiles = True
|
||||||
self.files = []
|
self.files = []
|
||||||
@ -20,8 +20,20 @@ class View(Filters, Path, Launcher):
|
|||||||
self.images = []
|
self.images = []
|
||||||
self.desktop = []
|
self.desktop = []
|
||||||
self.ungrouped = []
|
self.ungrouped = []
|
||||||
|
self.fm_config = self.getFileManagerSettings()
|
||||||
self.set_to_home()
|
self.set_to_home()
|
||||||
|
|
||||||
|
|
||||||
|
# Settings data
|
||||||
|
def getFileManagerSettings(self):
|
||||||
|
returnData = []
|
||||||
|
with open(self.CONFIG_FILE) as infile:
|
||||||
|
try:
|
||||||
|
return json.load(infile)
|
||||||
|
except Exception as e:
|
||||||
|
print(repr(e))
|
||||||
|
return ['', 'mplayer', 'xdg-open']
|
||||||
|
|
||||||
def load_directory(self):
|
def load_directory(self):
|
||||||
path = self.get_path()
|
path = self.get_path()
|
||||||
self.dirs = ['.', '..']
|
self.dirs = ['.', '..']
|
||||||
@ -78,6 +90,16 @@ class View(Filters, Path, Launcher):
|
|||||||
return file[0]
|
return file[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_files_formatted(self):
|
||||||
|
return {
|
||||||
|
'files': self.hashSet(self.files),
|
||||||
|
'dirs': self.hashSet(self.dirs),
|
||||||
|
'videos': self.hashSet(self.vids),
|
||||||
|
'images': self.hashSet(self.images),
|
||||||
|
'desktops': self.hashSet(self.desktop),
|
||||||
|
'ungrouped': self.hashSet(self.ungrouped)
|
||||||
|
}
|
||||||
|
|
||||||
def get_files(self):
|
def get_files(self):
|
||||||
return self.hashSet(self.files)
|
return self.hashSet(self.files)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
from .Settings import Settings
|
||||||
from .Launcher import Launcher
|
from .Launcher import Launcher
|
||||||
from .Filters import Filters
|
|
||||||
from .Path import Path
|
from .Path import Path
|
||||||
from .View import View
|
from .View import View
|
||||||
from .Window import Window
|
from .Window import Window
|
||||||
|
@ -8,10 +8,9 @@
|
|||||||
"pdf_app": "evince",
|
"pdf_app": "evince",
|
||||||
"text_app": "leafpad",
|
"text_app": "leafpad",
|
||||||
"file_manager_app": "spacefm",
|
"file_manager_app": "spacefm",
|
||||||
"locked_folder_password": "toor",
|
|
||||||
"do_refresh": "no",
|
"do_refresh": "no",
|
||||||
"remux_folder_max_disk_usage": "8589934592",
|
"remux_folder_max_disk_usage": "8589934592",
|
||||||
"locked_folders": "venv::::flasks",
|
"locked_folders": "Synced Backup::::venv::::flasks",
|
||||||
"folders_locked": "true"
|
"folders_locked": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user