Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ef1259bb4 | |||
4b3782d671 | |||
f5d2f3dd4f | |||
d8724eaf5a | |||
fddcc3a266 | |||
353acf7ae6 |
@ -3,6 +3,7 @@ certifi==2022.12.7
|
|||||||
charset-normalizer==3.0.1
|
charset-normalizer==3.0.1
|
||||||
click==7.1.2
|
click==7.1.2
|
||||||
dnspython==1.16.0
|
dnspython==1.16.0
|
||||||
|
ecdsa==0.18.0
|
||||||
email-validator==1.1.2
|
email-validator==1.1.2
|
||||||
eventlet==0.30.1
|
eventlet==0.30.1
|
||||||
Flask==1.1.2
|
Flask==1.1.2
|
||||||
@ -26,6 +27,7 @@ pyasn1-modules==0.2.8
|
|||||||
pycairo==1.23.0
|
pycairo==1.23.0
|
||||||
PyGObject==3.42.2
|
PyGObject==3.42.2
|
||||||
pyparsing==2.4.7
|
pyparsing==2.4.7
|
||||||
|
pywebpush==1.14.0
|
||||||
pyxdg==0.28
|
pyxdg==0.28
|
||||||
requests==2.28.2
|
requests==2.28.2
|
||||||
rsa==4.7
|
rsa==4.7
|
||||||
|
@ -4,6 +4,7 @@ import builtins
|
|||||||
import threading
|
import threading
|
||||||
import re
|
import re
|
||||||
import secrets
|
import secrets
|
||||||
|
import subprocess
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import session
|
from flask import session
|
||||||
@ -11,8 +12,12 @@ from flask import session
|
|||||||
# Application imports
|
# Application imports
|
||||||
from core import app
|
from core import app
|
||||||
from core.utils import Logger
|
from core.utils import Logger
|
||||||
|
from core.utils import MessageHandler # Get simple message processor
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltinsException(Exception):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
# NOTE: Threads WILL NOT die with parent's destruction.
|
# NOTE: Threads WILL NOT die with parent's destruction.
|
||||||
def threaded_wrapper(fn):
|
def threaded_wrapper(fn):
|
||||||
@ -41,22 +46,76 @@ def _get_file_size(file):
|
|||||||
|
|
||||||
# NOTE: Just reminding myself we can add to builtins two different ways...
|
# NOTE: Just reminding myself we can add to builtins two different ways...
|
||||||
# __builtins__.update({"event_system": Builtins()})
|
# __builtins__.update({"event_system": Builtins()})
|
||||||
builtins.app_name = "WebFM"
|
builtins.app_name = "WebFM"
|
||||||
builtins.threaded = threaded_wrapper
|
builtins.threaded = threaded_wrapper
|
||||||
builtins.daemon_threaded = daemon_threaded_wrapper
|
builtins.daemon_threaded = daemon_threaded_wrapper
|
||||||
builtins.sizeof_fmt = sizeof_fmt_def
|
builtins.sizeof_fmt = sizeof_fmt_def
|
||||||
builtins.get_file_size = _get_file_size
|
builtins.get_file_size = _get_file_size
|
||||||
builtins.ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
builtins.ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
||||||
builtins.BG_IMGS_PATH = ROOT_FILE_PTH + "/static/imgs/backgrounds/"
|
builtins.BG_IMGS_PATH = ROOT_FILE_PTH + "/static/imgs/backgrounds/"
|
||||||
builtins.BG_FILE_TYPE = (".webm", ".mp4", ".gif", ".jpg", ".png", ".webp")
|
builtins.BG_FILE_TYPE = (".webm", ".mp4", ".gif", ".jpg", ".png", ".webp")
|
||||||
builtins.valid_fname_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]{4,20}")
|
builtins.valid_fname_pat = re.compile(r"[a-z0-9A-Z-_\[\]\(\)\| ]{4,20}")
|
||||||
builtins.logger = Logger().get_logger()
|
builtins.logger = Logger().get_logger()
|
||||||
|
builtins.json_message = MessageHandler()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE: Need threads defined before instantiating
|
||||||
|
|
||||||
|
def _start_rtsp_and_ntfy_server():
|
||||||
|
PATH = f"{ROOT_FILE_PTH}/utils"
|
||||||
|
RTSP_PATH = f"{PATH}/rtsp-server"
|
||||||
|
NTFY_PATH = f"{PATH}/ntfy"
|
||||||
|
|
||||||
|
RAMFS = "/dev/shm/webfm"
|
||||||
|
SYMLINK = app.config['REMUX_FOLDER']
|
||||||
|
|
||||||
|
if not os.path.exists(RTSP_PATH) or not os.path.exists(f"{RTSP_PATH}/rtsp-simple-server"):
|
||||||
|
msg = f"\n\nAlert: Reference --> https://github.com/aler9/rtsp-simple-server/releases" + \
|
||||||
|
f"\nPlease insure {RTSP_PATH} exists and rtsp-simple-server binary is there.\n\n"
|
||||||
|
raise BuiltinsException(msg)
|
||||||
|
|
||||||
|
if not os.path.exists(NTFY_PATH) or not os.path.exists(f"{NTFY_PATH}/ntfy"):
|
||||||
|
msg = f"\n\nAlert: Reference --> https://ntfy.sh/" + \
|
||||||
|
f"\nPlease insure {NTFY_PATH} exists and ntfy binary is there.\n\n"
|
||||||
|
raise BuiltinsException(msg)
|
||||||
|
|
||||||
|
if not os.path.exists(RAMFS):
|
||||||
|
os.mkdir(RAMFS)
|
||||||
|
|
||||||
|
if not os.path.exists(SYMLINK):
|
||||||
|
os.symlink(RAMFS, SYMLINK)
|
||||||
|
|
||||||
|
@daemon_threaded
|
||||||
|
def _start_rtsp_server_threaded():
|
||||||
|
os.chdir(RTSP_PATH)
|
||||||
|
command = ["./rtsp-simple-server", "./rtsp-simple-server.yml"]
|
||||||
|
process = subprocess.Popen(command)
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
@daemon_threaded
|
||||||
|
def _start_ntfy_server_threaded():
|
||||||
|
os.chdir(NTFY_PATH)
|
||||||
|
command = ["./ntfy", "serve", "--behind-proxy", "--listen-http", ":7777"]
|
||||||
|
process = subprocess.Popen(command)
|
||||||
|
process.wait()
|
||||||
|
|
||||||
|
|
||||||
|
_start_ntfy_server_threaded()
|
||||||
|
_start_rtsp_server_threaded()
|
||||||
|
|
||||||
|
|
||||||
|
_start_rtsp_and_ntfy_server()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# NOTE: Need threads defined befor instantiating
|
|
||||||
from core.utils.shellfm.windows.controller import WindowController # Get file manager controller
|
from core.utils.shellfm.windows.controller import WindowController # Get file manager controller
|
||||||
window_controllers = {}
|
window_controllers = {}
|
||||||
|
processes = {}
|
||||||
|
|
||||||
|
def _get_sse_id():
|
||||||
|
return session["win_controller_id"]
|
||||||
|
|
||||||
def _get_view():
|
def _get_view():
|
||||||
controller = None
|
controller = None
|
||||||
try:
|
try:
|
||||||
@ -84,11 +143,59 @@ def _get_view():
|
|||||||
view.logger = logger
|
view.logger = logger
|
||||||
|
|
||||||
session['win_controller_id'] = id
|
session['win_controller_id'] = id
|
||||||
window_controllers.update( {id: controller } )
|
window_controllers.update( {id: controller} )
|
||||||
controller = window_controllers[ session["win_controller_id"] ].get_window_by_index(0).get_tab_by_index(0)
|
controller = window_controllers[ session["win_controller_id"] ].get_window_by_index(0).get_tab_by_index(0)
|
||||||
|
|
||||||
return controller
|
return controller
|
||||||
|
|
||||||
|
|
||||||
|
def _get_stream(video_path=None, stream_target=None):
|
||||||
|
process = None
|
||||||
|
try:
|
||||||
|
window = window_controllers[ session["win_controller_id"] ].get_window_by_index(0)
|
||||||
|
tab = window.get_tab_by_index(0)
|
||||||
|
id = f"{window.get_id()}{tab.get_id()}"
|
||||||
|
process = processes[id]
|
||||||
|
except Exception as e:
|
||||||
|
if video_path and stream_target:
|
||||||
|
# NOTE: Yes, technically we should check if cuda is supported.
|
||||||
|
# Yes, the process probably should give us info we can process when failure occures.
|
||||||
|
command = [
|
||||||
|
"ffmpeg", "-nostdin", "-fflags", "+genpts", "-hwaccel", "cuda",
|
||||||
|
"-stream_loop", "-1", "-i", video_path, "-strict", "experimental",
|
||||||
|
"-vcodec", "copy", "-acodec", "copy", "-f", "rtsp",
|
||||||
|
"-rtsp_transport", "tcp", stream_target
|
||||||
|
]
|
||||||
|
|
||||||
builtins.get_view = _get_view
|
proc = subprocess.Popen(command, shell=False, stdin=None, stdout=None, stderr=None)
|
||||||
|
window = window_controllers[ session["win_controller_id"] ].get_window_by_index(0)
|
||||||
|
tab = window.get_tab_by_index(0)
|
||||||
|
id = f"{window.get_id()}{tab.get_id()}"
|
||||||
|
|
||||||
|
processes.update( {id: proc} )
|
||||||
|
process = processes[id]
|
||||||
|
|
||||||
|
return process
|
||||||
|
|
||||||
|
def _kill_stream(process):
|
||||||
|
try:
|
||||||
|
if process.poll() == None:
|
||||||
|
process.terminate()
|
||||||
|
while process.poll() == None:
|
||||||
|
...
|
||||||
|
|
||||||
|
window = window_controllers[ session["win_controller_id"] ].get_window_by_index(0)
|
||||||
|
tab = window.get_tab_by_index(0)
|
||||||
|
id = f"{window.get_id()}{tab.get_id()}"
|
||||||
|
del processes[id]
|
||||||
|
except Exception as e:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
builtins.get_view = _get_view
|
||||||
|
builtins.get_sse_id = _get_sse_id
|
||||||
|
builtins.get_stream = _get_stream
|
||||||
|
builtins.kill_stream = _kill_stream
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import Flask
|
from flask import Flask
|
||||||
@ -6,7 +7,10 @@ from flask import Flask
|
|||||||
from flask_oidc import OpenIDConnect
|
from flask_oidc import OpenIDConnect
|
||||||
# Flask Login Path
|
# Flask Login Path
|
||||||
from flask_bcrypt import Bcrypt
|
from flask_bcrypt import Bcrypt
|
||||||
from flask_login import current_user, login_user, logout_user, LoginManager
|
from flask_login import current_user
|
||||||
|
from flask_login import login_user
|
||||||
|
from flask_login import logout_user
|
||||||
|
from flask_login import LoginManager
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.config.from_object("core.config.ProductionConfig")
|
app.config.from_object("core.config.ProductionConfig")
|
||||||
@ -36,10 +40,15 @@ app.jinja_env.globals['oidc_isAdmin'] = oidc_isAdmin
|
|||||||
app.jinja_env.globals['TITLE'] = app.config["TITLE"]
|
app.jinja_env.globals['TITLE'] = app.config["TITLE"]
|
||||||
|
|
||||||
|
|
||||||
from core.models import db, User, Favorites
|
|
||||||
|
from core.models import db
|
||||||
|
from core.models import User
|
||||||
|
from core.models import Favorites
|
||||||
|
|
||||||
db.init_app(app)
|
db.init_app(app)
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
||||||
from core.forms import RegisterForm, LoginForm
|
from core.forms import RegisterForm
|
||||||
|
from core.forms import LoginForm
|
||||||
from core import routes
|
from core import routes
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
# System import
|
# System import
|
||||||
import os, secrets
|
import os
|
||||||
|
import secrets
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
|
|
||||||
# Apoplication imports
|
# Apoplication imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Configs
|
# Configs
|
||||||
APP_NAME = 'WebFM'
|
APP_NAME = 'WebFM'
|
||||||
ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
ROOT_FILE_PTH = os.path.dirname(os.path.realpath(__file__))
|
||||||
@ -43,9 +43,9 @@ class Config(object):
|
|||||||
|
|
||||||
# We are overiding some of the the shellmen view settings with these to make it all work with flask.
|
# 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.
|
# These are passed along to the shellmen view from the Routes file upon the window controller creation.
|
||||||
ABS_THUMBS_PTH = f"{STATIC_FPTH}/imgs/thumbnails" # Used for thumbnail generation
|
ABS_THUMBS_PTH = f"{STATIC_FPTH}/imgs/thumbnails" # Used for thumbnail generation
|
||||||
REMUX_FOLDER = f"{STATIC_FPTH}/remuxs" # Remuxed files folder
|
REMUX_FOLDER = f"{STATIC_FPTH}/remuxs" # Remuxed files folder
|
||||||
FFMPG_THUMBNLR = f"{STATIC_FPTH}/ffmpegthumbnailer" # Thumbnail generator binary
|
FFMPG_THUMBNLR = f"{STATIC_FPTH}/ffmpegthumbnailer" # Thumbnail generator binary
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
from flask_wtf import FlaskForm
|
from flask_wtf import FlaskForm
|
||||||
from wtforms import StringField, PasswordField, SubmitField
|
|
||||||
from wtforms.validators import DataRequired, Length, Email, EqualTo, ValidationError
|
from wtforms import StringField
|
||||||
|
from wtforms import PasswordField
|
||||||
|
from wtforms import SubmitField
|
||||||
|
|
||||||
|
from wtforms.validators import DataRequired
|
||||||
|
from wtforms.validators import Length
|
||||||
|
from wtforms.validators import Email
|
||||||
|
from wtforms.validators import EqualTo
|
||||||
|
from wtforms.validators import ValidationError
|
||||||
|
|
||||||
from core import User
|
from core import User
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class RegisterForm(FlaskForm):
|
class RegisterForm(FlaskForm):
|
||||||
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
|
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=24)])
|
||||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
# System imports
|
# System imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
from flask_login import UserMixin
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from . import app, login_manager
|
from . import app
|
||||||
from flask_login import UserMixin
|
from . import login_manager
|
||||||
|
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
@ -9,7 +9,6 @@ from flask_uploads import ALL
|
|||||||
from flask_uploads import configure_uploads
|
from flask_uploads import configure_uploads
|
||||||
from flask_uploads import UploadSet
|
from flask_uploads import UploadSet
|
||||||
|
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
# Get from __init__
|
# Get from __init__
|
||||||
from core import app
|
from core import app
|
||||||
@ -17,10 +16,6 @@ from core import db
|
|||||||
from core import Favorites
|
from core import Favorites
|
||||||
from core import oidc
|
from core import oidc
|
||||||
|
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
|
||||||
|
|
||||||
json_message = MessageHandler()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/delete/<_hash>', methods=['GET', 'POST'])
|
@app.route('/api/delete/<_hash>', methods=['GET', 'POST'])
|
||||||
@ -46,6 +41,8 @@ def delete_item(_hash = None):
|
|||||||
msg = "[Error] Unable to delete the file/folder...."
|
msg = "[Error] Unable to delete the file/folder...."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/create/<_type>', methods=['GET', 'POST'])
|
@app.route('/api/create/<_type>', methods=['GET', 'POST'])
|
||||||
@ -82,9 +79,9 @@ def create_item(_type = None):
|
|||||||
|
|
||||||
msg = "[Success] created the file/dir..."
|
msg = "[Success] created the file/dir..."
|
||||||
return json_message.create("success", msg)
|
return json_message.create("success", msg)
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/upload', methods=['GET', 'POST'])
|
@app.route('/api/upload', methods=['GET', 'POST'])
|
||||||
@ -114,6 +111,6 @@ def upload():
|
|||||||
|
|
||||||
msg = "[Success] Uploaded file(s)..."
|
msg = "[Success] Uploaded file(s)..."
|
||||||
return json_message.create("success", msg)
|
return json_message.create("success", msg)
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
@ -7,15 +7,11 @@ from flask import request
|
|||||||
from core import app
|
from core import app
|
||||||
from core import db
|
from core import db
|
||||||
from core import Favorites # Get from __init__
|
from core import Favorites # Get from __init__
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
|
||||||
|
|
||||||
|
|
||||||
json_message = MessageHandler()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/list-favorites', methods=['GET', 'POST'])
|
@app.route('/api/list-favorites', methods=['GET', 'POST'])
|
||||||
def listFavorites():
|
def list_favorites():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
list = db.session.query(Favorites).all()
|
list = db.session.query(Favorites).all()
|
||||||
faves = []
|
faves = []
|
||||||
@ -23,12 +19,12 @@ def listFavorites():
|
|||||||
faves.append([fave.link, fave.id])
|
faves.append([fave.link, fave.id])
|
||||||
|
|
||||||
return json_message.faves_list(faves)
|
return json_message.faves_list(faves)
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
@app.route('/api/load-favorite/<_id>', methods=['GET', 'POST'])
|
@app.route('/api/load-favorite/<_id>', methods=['GET', 'POST'])
|
||||||
def loadFavorite(_id):
|
def load_favorite(_id):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
try:
|
try:
|
||||||
ID = int(_id)
|
ID = int(_id)
|
||||||
@ -40,13 +36,13 @@ def loadFavorite(_id):
|
|||||||
print(repr(e))
|
print(repr(e))
|
||||||
msg = "Incorrect Favorites ID..."
|
msg = "Incorrect Favorites ID..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/manage-favorites/<_action>', methods=['GET', 'POST'])
|
@app.route('/api/manage-favorites/<_action>', methods=['GET', 'POST'])
|
||||||
def manageFavorites(_action):
|
def manage_favorites(_action):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
ACTION = _action.strip()
|
ACTION = _action.strip()
|
||||||
view = get_view()
|
view = get_view()
|
||||||
@ -66,6 +62,6 @@ def manageFavorites(_action):
|
|||||||
|
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return json_message.create("success", msg)
|
return json_message.create("success", msg)
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
@ -6,21 +6,19 @@ import shutil
|
|||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
# Get from __init__
|
# Get from __init__
|
||||||
from core import app
|
from core import app
|
||||||
|
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
|
||||||
from core.utils.tmdbscraper import scraper # Get media art scraper
|
from core.utils.tmdbscraper import scraper # Get media art scraper
|
||||||
|
|
||||||
|
|
||||||
json_message = MessageHandler()
|
|
||||||
tmdb = scraper.get_tmdb_scraper()
|
tmdb = scraper.get_tmdb_scraper()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/get-background-poster-trailer', methods=['GET', 'POST'])
|
@app.route('/api/get-background-poster-trailer', methods=['GET', 'POST'])
|
||||||
def getPosterTrailer():
|
def get_poster_trailer():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
info = {}
|
info = {}
|
||||||
view = get_view()
|
view = get_view()
|
||||||
@ -71,6 +69,8 @@ def getPosterTrailer():
|
|||||||
|
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
@app.route('/backgrounds', methods=['GET', 'POST'])
|
@app.route('/backgrounds', methods=['GET', 'POST'])
|
||||||
def backgrounds():
|
def backgrounds():
|
||||||
@ -83,10 +83,10 @@ def backgrounds():
|
|||||||
return json_message.backgrounds(files)
|
return json_message.backgrounds(files)
|
||||||
|
|
||||||
@app.route('/api/get-thumbnails', methods=['GET', 'POST'])
|
@app.route('/api/get-thumbnails', methods=['GET', 'POST'])
|
||||||
def getThumbnails():
|
def get_thumbnails():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
view = get_view()
|
view = get_view()
|
||||||
return json_message.thumbnails( view.get_video_icons() )
|
return json_message.thumbnails( view.get_video_icons() )
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
msg = "Can't manage the request type..."
|
||||||
return json_message.create("danger", msg)
|
return json_message.create("danger", msg)
|
||||||
|
@ -1,42 +1,49 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
import os
|
import os
|
||||||
|
import requests
|
||||||
|
import uuid
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
from flask import make_response
|
||||||
from flask import redirect
|
from flask import redirect
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
|
from flask import session
|
||||||
from flask import send_from_directory
|
from flask import send_from_directory
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
# Get from __init__
|
# Get from __init__
|
||||||
from core import app
|
from core import app
|
||||||
from core import db
|
from core import db
|
||||||
from core import Favorites
|
from core import Favorites
|
||||||
from core import oidc
|
from core import oidc
|
||||||
|
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
json_message = MessageHandler()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/', methods=['GET', 'POST'])
|
@app.route('/', methods=['GET', 'POST'])
|
||||||
def home():
|
def home():
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
view = get_view()
|
view = get_view()
|
||||||
|
sse_id = get_sse_id()
|
||||||
_dot_dots = view.get_dot_dots()
|
_dot_dots = view.get_dot_dots()
|
||||||
_current_directory = view.get_current_directory()
|
_current_directory = view.get_current_directory()
|
||||||
return render_template('pages/index.html', current_directory = _current_directory, dot_dots = _dot_dots)
|
|
||||||
|
response = make_response(
|
||||||
|
render_template(
|
||||||
|
'pages/index.html',
|
||||||
|
current_directory = _current_directory,
|
||||||
|
dot_dots = _dot_dots
|
||||||
|
)
|
||||||
|
)
|
||||||
|
response.set_cookie('sse_id', sse_id, secure=True, httponly = False)
|
||||||
|
return response
|
||||||
|
|
||||||
return render_template('error.html', title = 'Error!',
|
return render_template('error.html', title = 'Error!',
|
||||||
message = 'Must use GET request type...')
|
message = 'Must use GET request type...')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/list-files/<_hash>', methods=['GET', 'POST'])
|
@app.route('/api/list-files/<_hash>', methods=['GET', 'POST'])
|
||||||
def listFiles(_hash = None):
|
def list_files(_hash = None):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
view = get_view()
|
view = get_view()
|
||||||
dot_dots = view.get_dot_dots()
|
dot_dots = view.get_dot_dots()
|
||||||
@ -70,14 +77,13 @@ def listFiles(_hash = None):
|
|||||||
in_fave = "true" if fave else "false"
|
in_fave = "true" if fave else "false"
|
||||||
files.update({'in_fave': in_fave})
|
files.update({'in_fave': in_fave})
|
||||||
return files
|
return files
|
||||||
else:
|
|
||||||
msg = "Can't manage the request type..."
|
|
||||||
return json_message.create("danger", msg)
|
|
||||||
|
|
||||||
|
msg = "Can't manage the request type..."
|
||||||
|
return json_message.create("danger", msg)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/file-manager-action/<_type>/<_hash>', methods=['GET', 'POST'])
|
@app.route('/api/file-manager-action/<_type>/<_hash>', methods=['GET', 'POST'])
|
||||||
def fileManagerAction(_type, _hash = None):
|
def file_manager_action(_type, _hash = None):
|
||||||
view = get_view()
|
view = get_view()
|
||||||
|
|
||||||
if _type == "reset-path" and _hash == "None":
|
if _type == "reset-path" and _hash == "None":
|
||||||
@ -93,19 +99,16 @@ def fileManagerAction(_type, _hash = None):
|
|||||||
if _type == "files":
|
if _type == "files":
|
||||||
logger.debug(f"Downloading:\n\tDirectory: {folder}\n\tFile: {file}")
|
logger.debug(f"Downloading:\n\tDirectory: {folder}\n\tFile: {file}")
|
||||||
return send_from_directory(directory=folder, filename=file)
|
return send_from_directory(directory=folder, filename=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.remux_video(_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 json_message.create("success", msg)
|
|
||||||
|
|
||||||
if _type == "remux":
|
if _type == "remux":
|
||||||
stream_target = view.remux_video(_hash, fpath)
|
remux_video(get_sse_id(), _hash, fpath, view)
|
||||||
|
msg = "Remuxing: Remux process has started..."
|
||||||
|
return json_message.create("success", msg)
|
||||||
|
|
||||||
|
if _type == "stream":
|
||||||
|
setup_stream(get_sse_id(), _hash, fpath)
|
||||||
|
msg = "Streaming: Streaming process is being setup..."
|
||||||
|
return json_message.create("success", msg)
|
||||||
|
|
||||||
|
|
||||||
# NOTE: Positionally protecting actions further down that are privlidged
|
# NOTE: Positionally protecting actions further down that are privlidged
|
||||||
@ -123,3 +126,63 @@ def fileManagerAction(_type, _hash = None):
|
|||||||
msg = "Opened media..."
|
msg = "Opened media..."
|
||||||
view.open_file_locally(fpath)
|
view.open_file_locally(fpath)
|
||||||
return json_message.create("success", msg)
|
return json_message.create("success", msg)
|
||||||
|
|
||||||
|
|
||||||
|
@daemon_threaded
|
||||||
|
def remux_video(sse_id, hash, path, view):
|
||||||
|
link = f"https://www.webfm.com/sse/{sse_id}"
|
||||||
|
body = '{"path":"static/remuxs/' + hash + '.mp4"}'
|
||||||
|
|
||||||
|
# good_result = view.remux_video(hash, path)
|
||||||
|
good_result = view.handbrake_remux_video(hash, path)
|
||||||
|
if not good_result:
|
||||||
|
body = json_message.create("warning", "Remuxing: Remux failed...")
|
||||||
|
|
||||||
|
requests.post(link, data=body, timeout=10)
|
||||||
|
|
||||||
|
|
||||||
|
def setup_stream(sse_id, hash, path):
|
||||||
|
link = f"https://www.webfm.com/sse/{sse_id}"
|
||||||
|
_sub_uuid = uuid.uuid4().hex
|
||||||
|
_video_path = path
|
||||||
|
_stub = f"{hash}{_sub_uuid}"
|
||||||
|
_rtsp_path = f"rtsp://127.0.0.1:8554/{_stub}"
|
||||||
|
_webrtc_path = f"http://www.{app_name.lower()}.com:8889/{_stub}/"
|
||||||
|
_stream_target = _rtsp_path
|
||||||
|
|
||||||
|
process = get_stream()
|
||||||
|
if process:
|
||||||
|
if not kill_stream(process):
|
||||||
|
msg = "Couldn't stop an existing stream!"
|
||||||
|
body = json_message.create("danger", msg)
|
||||||
|
requests.post(link, data=body, timeout=10)
|
||||||
|
return
|
||||||
|
|
||||||
|
stream = get_stream(_video_path, _stream_target)
|
||||||
|
if stream.poll():
|
||||||
|
msg = "Streaming: Setting up stream failed! Please try again..."
|
||||||
|
body = json_message.create("danger", msg)
|
||||||
|
requests.post(link, data=body, timeout=10)
|
||||||
|
return
|
||||||
|
|
||||||
|
_stream_target = _webrtc_path
|
||||||
|
body = '{"stream":"' + _stream_target + '"}'
|
||||||
|
requests.post(link, data=body, timeout=10)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/api/stop-current-stream', methods=['GET', 'POST'])
|
||||||
|
def stop_current_stream():
|
||||||
|
type = "success"
|
||||||
|
msg = "Stopped found stream process..."
|
||||||
|
process = get_stream()
|
||||||
|
|
||||||
|
if process:
|
||||||
|
if not kill_stream(process):
|
||||||
|
type = "danger"
|
||||||
|
msg = "Couldn't stop an existing stream!"
|
||||||
|
else:
|
||||||
|
type = "warning"
|
||||||
|
msg = "No stream process found. Nothing to stop..."
|
||||||
|
|
||||||
|
return json_message.create(type, msg)
|
||||||
|
@ -1,15 +1,24 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import request, render_template, flash, redirect, url_for
|
from flask import request
|
||||||
from flask_login import current_user, login_user, logout_user
|
from flask import render_template
|
||||||
|
from flask import flash
|
||||||
|
from flask import redirect
|
||||||
|
from flask import url_for
|
||||||
|
|
||||||
|
from flask_login import current_user
|
||||||
|
from flask_login import login_user
|
||||||
|
from flask_login import logout_user
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from core import app, bcrypt, db, User, LoginForm
|
from core import app
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
from core import bcrypt
|
||||||
|
from core import db
|
||||||
|
from core import User
|
||||||
|
from core import LoginForm
|
||||||
|
|
||||||
|
|
||||||
msgHandler = MessageHandler()
|
|
||||||
|
|
||||||
@app.route('/app-login', methods=['GET', 'POST'])
|
@app.route('/app-login', methods=['GET', 'POST'])
|
||||||
def app_login():
|
def app_login():
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import request, render_template, url_for, redirect, flash
|
from flask import render_template
|
||||||
|
from flask import url_for
|
||||||
|
from flask import redirect
|
||||||
|
from flask import flash
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from core import app, bcrypt, db, current_user, RegisterForm # Get from __init__
|
# Get from __init__
|
||||||
|
from core import app
|
||||||
|
from core import bcrypt
|
||||||
|
from core import db
|
||||||
|
from core import current_user
|
||||||
|
from core import RegisterForm
|
||||||
from core.models import User
|
from core.models import User
|
||||||
from core.utils import MessageHandler # Get simple message processor
|
|
||||||
|
|
||||||
|
|
||||||
msgHandler = MessageHandler()
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/app-register', methods=['GET', 'POST'])
|
@app.route('/app-register', methods=['GET', 'POST'])
|
||||||
def app_register():
|
def app_register():
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import request, redirect, flash
|
from flask import request
|
||||||
|
from flask import redirect
|
||||||
|
from flask import flash
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from ... import app, oidc
|
from ... import app
|
||||||
|
from ... import oidc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/oidc-login', methods=['GET', 'POST'])
|
@app.route('/oidc-login', methods=['GET', 'POST'])
|
||||||
@oidc.require_login
|
@oidc.require_login
|
||||||
def oidc_login():
|
def oidc_login():
|
||||||
print(request)
|
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
# Python imports
|
# Python imports
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
from flask import request, render_template, url_for, redirect, flash
|
from flask import request
|
||||||
|
from flask import render_template
|
||||||
|
from flask import url_for
|
||||||
|
from flask import redirect
|
||||||
|
from flask import flash
|
||||||
|
|
||||||
# App imports
|
# App imports
|
||||||
from ... import app, oidc, db # Get from __init__
|
# Get from __init__
|
||||||
from ...utils import MessageHandler # Get simple message processor
|
from ... import app
|
||||||
|
from ... import oidc
|
||||||
|
from ... import db
|
||||||
|
|
||||||
|
|
||||||
msgHandler = MessageHandler()
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/oidc-register', methods=['GET', 'POST'])
|
@app.route('/oidc-register', methods=['GET', 'POST'])
|
||||||
def oidc_register():
|
def oidc_register():
|
||||||
|
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 870 B |
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 711 B After Width: | Height: | Size: 711 B |
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 316 B After Width: | Height: | Size: 316 B |
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 401 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 352 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 444 B |
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 362 B After Width: | Height: | Size: 362 B |
Before Width: | Height: | Size: 445 B After Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 582 B After Width: | Height: | Size: 582 B |
Before Width: | Height: | Size: 373 B After Width: | Height: | Size: 373 B |
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 322 B After Width: | Height: | Size: 322 B |
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 316 B After Width: | Height: | Size: 316 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 446 B |
Before Width: | Height: | Size: 312 B After Width: | Height: | Size: 312 B |
Before Width: | Height: | Size: 769 B After Width: | Height: | Size: 769 B |
Before Width: | Height: | Size: 977 B After Width: | Height: | Size: 977 B |
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 369 B |
Before Width: | Height: | Size: 323 B After Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 372 B After Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 446 B After Width: | Height: | Size: 446 B |
Before Width: | Height: | Size: 284 B After Width: | Height: | Size: 284 B |
Before Width: | Height: | Size: 324 B After Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 442 B |
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 463 B After Width: | Height: | Size: 463 B |
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 462 B |
Before Width: | Height: | Size: 499 B After Width: | Height: | Size: 499 B |
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 498 B |
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 730 B |
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
Before Width: | Height: | Size: 358 B After Width: | Height: | Size: 358 B |