From 22c437e8edbe7ee045ff91825abd95f3e18b1dcd Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 13 Jun 2022 21:51:51 -0500 Subject: [PATCH] addedd rtsp streamer inferastructure, applied fstrings, updated method names to align with standards in project --- src/core/config.py | 10 +- src/core/routes/Routes.py | 86 +++--- src/core/utils/MessageHandler.py | 2 +- .../utils/shellfm/windows/WindowController.py | 12 +- src/core/utils/shellfm/windows/view/View.py | 2 +- .../shellfm/windows/view/utils/Launcher.py | 25 +- .../shellfm/windows/view/utils/Settings.py | 22 +- .../windows/view/utils/rtsp-simple-server | Bin 0 -> 20226064 bytes .../windows/view/utils/rtsp-simple-server.yml | 281 ++++++++++++++++++ 9 files changed, 367 insertions(+), 73 deletions(-) create mode 100755 src/core/utils/shellfm/windows/view/utils/rtsp-simple-server create mode 100644 src/core/utils/shellfm/windows/view/utils/rtsp-simple-server.yml diff --git a/src/core/config.py b/src/core/config.py index 7f2472e..acd6569 100644 --- a/src/core/config.py +++ b/src/core/config.py @@ -29,7 +29,7 @@ class Config(object): 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_CLIENT_SECRETS = f'{ROOT_FILE_PTH}/client_secrets.json' OIDC_ID_TOKEN_COOKIE_SECURE = True OIDC_REQUIRE_VERIFIED_EMAIL = False OIDC_USER_INFO_ENABLED = True @@ -38,14 +38,14 @@ class Config(object): 'https://www.ssoapps.com/auth/realms/apps' ] - STATIC_FPTH = ROOT_FILE_PTH + "/static" + STATIC_FPTH = f"{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 + ABS_THUMBS_PTH = f"{STATIC_FPTH}/imgs/thumbnails" # Used for thumbnail generation + REMUX_FOLDER = f"{STATIC_FPTH}/remuxs" # Remuxed files folder + FFMPG_THUMBNLR = f"{STATIC_FPTH}/ffmpegthumbnailer" # Thumbnail generator binary diff --git a/src/core/routes/Routes.py b/src/core/routes/Routes.py index 61e3f25..ad9e526 100644 --- a/src/core/routes/Routes.py +++ b/src/core/routes/Routes.py @@ -67,11 +67,11 @@ def listFiles(_hash = None): 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) + return msgHandler.create_JSON_message("danger", msg) elif is_locked and oidc.user_loggedin: isAdmin = oidc.user_getfield("isAdmin") if isAdmin != "yes" : - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) if dot_dots[0][1] != _hash and dot_dots[1][1] != _hash: path = view.get_path_part_from_hash(_hash) @@ -80,7 +80,7 @@ def listFiles(_hash = None): error_msg = view.get_error_message() if error_msg != None: view.unset_error_message() - return msgHandler.createMessageJSON("danger", error_msg) + return msgHandler.create_JSON_message("danger", error_msg) sub_path = view.get_current_sub_path() @@ -92,7 +92,7 @@ def listFiles(_hash = None): date = current_directory[startIndex:endIndex] video_data = tmdb.search(title, date) background_url = video_data[0]["backdrop_path"] - background_pth = view.get_current_directory() + "/" + "000.jpg" + background_pth = f"{view.get_current_directory()}/000.jpg" if not os.path.isfile(background_pth): r = requests.get(background_url, stream = True) @@ -116,20 +116,17 @@ def listFiles(_hash = None): return files else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/get-posters', methods=['GET', 'POST']) def getPosters(): if request.method == 'POST': view = get_window_controller().get_window(1).get_view(0) videos = view.get_videos() - - print(videos) - # tmdb.search("Matrix") return videos else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/file-manager-action/<_type>/<_hash>', methods=['GET', 'POST']) def fileManagerAction(_type, _hash = None): @@ -138,7 +135,7 @@ def fileManagerAction(_type, _hash = None): if _type == "reset-path" and _hash == "None": view.set_to_home() msg = "Returning to home directory..." - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) folder = view.get_current_directory() file = view.get_path_part_from_hash(_hash) @@ -146,34 +143,39 @@ def fileManagerAction(_type, _hash = None): logger.debug(fpath) if _type == "files": - return send_from_directory(folder, file) + logger.debug(f"Downloading:\n\tDirectory: {folder}\n\tFile: {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.remuxVideo(_hash, fpath) + 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 msgHandler.createMessageJSON("success", msg) - if _type == "run-locally": - msg = "Opened media..." - view.openFilelocally(fpath) - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) + + if _type == "remux": + stream_target = view.remux_video(_hash, fpath) # 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) + return msgHandler.create_JSON_message("danger", msg) elif oidc.user_loggedin: isAdmin = oidc.user_getfield("isAdmin") if isAdmin != "yes" : - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) + if _type == "run-locally": + msg = "Opened media..." + view.open_file_locally(fpath) + return msgHandler.create_JSON_message("success", msg) + if _type == "delete": try: msg = f"[Success] Deleted the file/folder -->: {file} !" @@ -181,10 +183,10 @@ def fileManagerAction(_type, _hash = None): os.unlink(fpath) else: shutil.rmtree(fpath) - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) except Exception as e: msg = "[Error] Unable to delete the file/folder...." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/list-favorites', methods=['GET', 'POST']) @@ -198,7 +200,7 @@ def listFavorites(): return '{"faves_list":' + json.dumps(faves) + '}' else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/load-favorite/<_id>', methods=['GET', 'POST']) def loadFavorite(_id): @@ -212,10 +214,10 @@ def loadFavorite(_id): except Exception as e: print(repr(e)) msg = "Incorrect Favorites ID..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/manage-favorites/<_action>', methods=['GET', 'POST']) @@ -235,13 +237,13 @@ def manageFavorites(_action): msg = "Deleted from Favorites successfully..." else: msg = "Couldn't handle action for favorites item..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) db.session.commit() - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/api/create/<_type>', methods=['GET', 'POST']) @@ -249,42 +251,42 @@ 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) + return msgHandler.create_JSON_message("danger", msg) elif oidc.user_loggedin: isAdmin = oidc.user_getfield("isAdmin") if isAdmin != "yes" : - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("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) + return msgHandler.create_JSON_message("danger", msg) view = get_window_controller().get_window(1).get_view(0) folder = view.get_current_directory() - new_item = folder + '/' + FNAME + new_item = f"{folder}/{FNAME}" try: if TYPE == "dir": os.mkdir(new_item) elif TYPE == "file": - open(new_item + ".txt", 'a').close() + open(f"{new_item}.txt", 'a').close() else: msg = "Couldn't handle action type for api create..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) except Exception as e: print(repr(e)) msg = "Couldn't create file/folder. An unexpected error occured..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) msg = "[Success] created the file/dir..." - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) @app.route('/upload', methods=['GET', 'POST']) @@ -292,15 +294,15 @@ 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) + return msgHandler.create_JSON_message("danger", msg) elif oidc.user_loggedin: isAdmin = oidc.user_getfield("isAdmin") if isAdmin != "yes" : - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) view = get_window_controller().get_window(1).get_view(0) folder = view.get_current_directory() - UPLOADS_PTH = folder + '/' + UPLOADS_PTH = f'{folder}/' files = UploadSet('files', ALL, default_dest=lambda x: UPLOADS_PTH) configure_uploads(app, files) @@ -310,10 +312,10 @@ def upload(): except Exception as e: print(repr(e)) msg = "[Error] Failed to upload some or all of the file(s)..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) msg = "[Success] Uploaded file(s)..." - return msgHandler.createMessageJSON("success", msg) + return msgHandler.create_JSON_message("success", msg) else: msg = "Can't manage the request type..." - return msgHandler.createMessageJSON("danger", msg) + return msgHandler.create_JSON_message("danger", msg) diff --git a/src/core/utils/MessageHandler.py b/src/core/utils/MessageHandler.py index f6538f2..9bf6368 100644 --- a/src/core/utils/MessageHandler.py +++ b/src/core/utils/MessageHandler.py @@ -10,5 +10,5 @@ class MessageHandler: print("MessageHandler initialized...") - def createMessageJSON(self, type, text): + def create_JSON_message(self, type, text): return '{"message": { "type": "' + type + '", "text": "' + text + '" } }' diff --git a/src/core/utils/shellfm/windows/WindowController.py b/src/core/utils/shellfm/windows/WindowController.py index 30cc30d..4c81aa0 100644 --- a/src/core/utils/shellfm/windows/WindowController.py +++ b/src/core/utils/shellfm/windows/WindowController.py @@ -11,7 +11,7 @@ class WindowController: if window.id == win_id: return window - raise("No Window by ID {} found!".format(win_id)) + raise(f"No Window by ID {win_id} found!") def get_windows(self): return self.windows @@ -19,7 +19,7 @@ class WindowController: def add_window(self): window = Window() window.id = len(self.windows) + 1 - window.name = "window_" + str(window.id) + window.name = f"window_{window.id}" window.create_view() self.windows.append(window) @@ -48,10 +48,10 @@ class WindowController: def list_windows(self): for window in self.windows: print("\n[ Window ]") - print("ID: " + str(window.id)) - print("Name: " + window.name) - print("Nickname: " + window.nickname) - print("View Count: " + str( len(window.views) )) + print("ID: {window.id}") + print("Name: {window.name}") + print("Nickname: {window.nickname}") + print("View Count: {len(window.views)}") def list_views_from_window(self, win_id): diff --git a/src/core/utils/shellfm/windows/view/View.py b/src/core/utils/shellfm/windows/view/View.py index 70a97d4..1f1001a 100644 --- a/src/core/utils/shellfm/windows/view/View.py +++ b/src/core/utils/shellfm/windows/view/View.py @@ -157,7 +157,7 @@ class View(Settings, Launcher, Path): if not os.path.exists(hashImgPth) : fullPath = join(current_directory, video[0]) self.logger.debug(f"Hash Path: {hashImgPth}\nFile Path: {fullPath}") - self.generateVideoThumbnail(fullPath, hashImgPth) + self.generate_video_thumbnail(fullPath, hashImgPth) return videos_set diff --git a/src/core/utils/shellfm/windows/view/utils/Launcher.py b/src/core/utils/shellfm/windows/view/utils/Launcher.py index 6e3dcac..cc09d61 100644 --- a/src/core/utils/shellfm/windows/view/utils/Launcher.py +++ b/src/core/utils/shellfm/windows/view/utils/Launcher.py @@ -9,7 +9,7 @@ import os, subprocess, threading class Launcher: - def openFilelocally(self, file): + def open_file_locally(self, file): lowerName = file.lower() command = [] @@ -38,14 +38,25 @@ class Launcher: subprocess.Popen(command, start_new_session=True, stdout=DEVNULL, stderr=DEVNULL, close_fds=True) - def remuxVideo(self, hash, file): - remux_vid_pth = self.REMUX_FOLDER + "/" + hash + ".mp4" + def create_stream(self, hash, file): + # ffmpeg -re -stream_loop -1 -i "