diff --git a/src/core/__builtins__.py b/src/core/__builtins__.py index f6c101f..86cfa8f 100644 --- a/src/core/__builtins__.py +++ b/src/core/__builtins__.py @@ -162,18 +162,11 @@ def _get_stream(video_path=None, stream_target=None): # Yes, the process probably should give us info we can process when failure occures. command = [ "ffmpeg", "-nostdin", "-fflags", "+genpts", "-hwaccel", "cuda", - # --preset ultrafast --threads 1 - "-stream_loop", "1", "-i", video_path, "-strict", "experimental", + "-stream_loop", "-1", "-i", video_path, "-strict", "experimental", "-vcodec", "copy", "-acodec", "copy", "-f", "rtsp", "-rtsp_transport", "tcp", stream_target ] - # command = [ - # "ffmpeg", "-nostdin", "-fflags", "+genpts", "-i", video_path, - # "-strict", "experimental", "-f", - # "rtsp", "-rtsp_transport", "udp", stream_target - # ] - 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) diff --git a/src/core/__init__.py b/src/core/__init__.py index aacb05e..87e133a 100644 --- a/src/core/__init__.py +++ b/src/core/__init__.py @@ -1,6 +1,5 @@ # Python imports import os -import subprocess # Lib imports from flask import Flask diff --git a/src/core/routes/Routes.py b/src/core/routes/Routes.py index 23b2526..eac711d 100644 --- a/src/core/routes/Routes.py +++ b/src/core/routes/Routes.py @@ -133,25 +133,22 @@ 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.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) -# @daemon_threaded 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://www.{app_name.lower()}.com:8554/{_stub}" - _rtmp_path = f"rtmp://www.{app_name.lower()}.com:1935/{_stub}" - _hls_path = f"http://www.{app_name.lower()}.com:8888/{_stub}/" + _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 - body = '{"stream":"' + _stream_target + '"}' process = get_stream() if process: @@ -168,6 +165,8 @@ def setup_stream(sse_id, hash, path): requests.post(link, data=body, timeout=10) return + _stream_target = _webrtc_path + body = '{"stream":"' + _stream_target + '"}' requests.post(link, data=body, timeout=10) diff --git a/src/core/static/js/webfm/sse.js b/src/core/static/js/webfm/sse.js index 63ad838..8e1a0ce 100644 --- a/src/core/static/js/webfm/sse.js +++ b/src/core/static/js/webfm/sse.js @@ -19,6 +19,7 @@ eventSource.onmessage = (eve) => { try { const data = JSON.parse(eve.data); const sse_msg = JSON.parse(data.message); + if (sse_msg.hasOwnProperty('path') || sse_msg.hasOwnProperty('stream')) { const target = (sse_msg.path) ? sse_msg.path : sse_msg.stream; handleMedia(target); diff --git a/src/core/static/js/webfm/ui-logic.js b/src/core/static/js/webfm/ui-logic.js index 7e84401..aa5873e 100644 --- a/src/core/static/js/webfm/ui-logic.js +++ b/src/core/static/js/webfm/ui-logic.js @@ -70,22 +70,21 @@ const closeFile = async () => { } const showFile = async (title, hash, extension, type, target=null) => { + document.getElementById("selectedFile").innerText = title; document.getElementById("image-viewer").style.display = "none"; document.getElementById("text-viewer").style.display = "none"; document.getElementById("pdf-viewer").style.display = "none"; document.getElementById("video_container").style.display = "none"; document.getElementById("trailerPlayer").style.display = "none"; - let titleElm = document.getElementById("selectedFile"); - titleElm.innerText = title; // FIXME: Yes, a wasted call every time there is no stream. await fetchData("api/stop-current-stream"); if (type === "video" || type === "stream") { isStream = (type === "stream") ? true : false; - target = (type === "stream") ? "stream" : "remux"; - setupVideo(hash, extension, isStream, target); + action = (type === "stream") ? "stream" : "remux"; + setupVideo(hash, extension, isStream, action); setSelectedActiveMedia(target); } else if (type === "trailer") { launchTrailer(hash); @@ -103,7 +102,7 @@ const launchTrailer = (link) => { modal.show(); } -const setupVideo = async (hash, extension, isStream, target="remux") => { +const setupVideo = async (hash, extension, isStream, action="remux") => { document.getElementById("video_container").style.display = ""; video_path = `api/file-manager-action/files/${hash}`; @@ -120,7 +119,7 @@ const setupVideo = async (hash, extension, isStream, target="remux") => { return; } - const data = await fetchData(`api/file-manager-action/${target}/${hash}`); + const data = await fetchData(`api/file-manager-action/${action}/${hash}`); displayMessage(data.message.text, data.message.type, 5); } catch (e) { video.style.display = "none"; @@ -236,8 +235,10 @@ const loadBackgroundPoster = () => { } if (data.poster !== null) { - background_image = "api/file-manager-action/files/000.jpg?d=" + Date.now(); - updateBackground(background_image, false); + getSHA256Hash("000.jpg").then((_hash) => { + background_image = "api/file-manager-action/files/" + _hash + "?d=" + Date.now(); + updateBackground(background_image, false); + }) } } }); @@ -377,3 +378,12 @@ const clearCache = () => { } } } + +const getSHA256Hash = async (input) => { + const textAsBuffer = new TextEncoder().encode(input); + const hashBuffer = await window.crypto.subtle.digest("SHA-256", textAsBuffer); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const hash = hashArray.map((item) => item.toString(16).padStart(2, "0")).join(""); + + return hash.substring(0, 18); +}; diff --git a/src/core/utils/rtsp-server/rtsp-simple-server.yml b/src/core/utils/rtsp-server/rtsp-simple-server.yml index 49f79f7..e8b2d21 100644 --- a/src/core/utils/rtsp-server/rtsp-simple-server.yml +++ b/src/core/utils/rtsp-server/rtsp-simple-server.yml @@ -100,7 +100,7 @@ authMethods: [basic, digest] # RTMP parameters # Disable support for the RTMP protocol. -rtmpDisable: no +rtmpDisable: yes # Address of the RTMP listener. This is needed only when encryption is "no" or "optional". rtmpAddress: :1935 # Encrypt connections with TLS (RTMPS). @@ -120,12 +120,12 @@ rtmpServerCert: server.crt # HLS parameters # Disable support for the HLS protocol. -hlsDisable: no +hlsDisable: yes # Address of the HLS listener. hlsAddress: :8888 # Enable TLS/HTTPS on the HLS server. # This is required for Low-Latency HLS. -hlsEncryption: yes +hlsEncryption: no # Path to the server key. This is needed only when encryption is yes. # This can be generated with: # openssl genrsa -out server.key 2048 @@ -135,22 +135,22 @@ hlsServerKey: server.key hlsServerCert: server.crt # By default, HLS is generated only when requested by a user. # This option allows to generate it always, avoiding the delay between request and generation. -hlsAlwaysRemux: yes +hlsAlwaysRemux: no # Variant of the HLS protocol to use. Available options are: # * mpegts - uses MPEG-TS segments, for maximum compatibility. # * fmp4 - uses fragmented MP4 segments, more efficient. # * lowLatency - uses Low-Latency HLS. -hlsVariant: lowLatency +hlsVariant: mpegts # Number of HLS segments to keep on the server. # Segments allow to seek through the stream. # Their number doesn't influence latency. -hlsSegmentCount: 7 +hlsSegmentCount: 24 # Minimum duration of each segment. # A player usually puts 3 segments in a buffer before reproducing the stream. # The final segment duration is also influenced by the interval between IDR frames, # since the server changes the duration in order to include at least one IDR frame # in each segment. -hlsSegmentDuration: 1s +hlsSegmentDuration: 5s # Minimum duration of each part. # A player usually puts 3 parts in a buffer before reproducing the stream. # Parts are used in Low-Latency HLS in place of segments. @@ -166,13 +166,13 @@ hlsAllowOrigin: '*' # List of IPs or CIDRs of proxies placed before the HLS server. # If the server receives a request from one of these entries, IP in logs # will be taken from the X-Forwarded-For header. -hlsTrustedProxies: [] +hlsTrustedProxies: [0.0.0.0] ############################################### # WebRTC parameters # Disable support for the WebRTC protocol. -webrtcDisable: yes +webrtcDisable: no # Address of the WebRTC listener. webrtcAddress: :8889 # Enable TLS/HTTPS on the WebRTC server. @@ -190,7 +190,7 @@ webrtcAllowOrigin: '*' # List of IPs or CIDRs of proxies placed before the WebRTC server. # If the server receives a request from one of these entries, IP in logs # will be taken from the X-Forwarded-For header. -webrtcTrustedProxies: [] +webrtcTrustedProxies: [0.0.0.0, 127.0.0.1] # List of ICE servers, in format type:user:pass:host:port or type:host:port. # type can be "stun", "turn" or "turns". # STUN servers are used to get the public IP of both server and clients. @@ -200,7 +200,7 @@ webrtcTrustedProxies: [] webrtcICEServers: [stun:stun.l.google.com:19302, stun:stun.services.mozilla.com] # List of public IP addresses that are to be used as a host. # This is used typically for servers that are behind 1:1 D-NAT. -webrtcICEHostNAT1To1IPs: [] +webrtcICEHostNAT1To1IPs: [0.0.0.0] # Address of a ICE UDP listener in format host:port. # If filled, ICE traffic will come through a single UDP port, # allowing the deployment of the server inside a container or behind a NAT. diff --git a/src/core/utils/shellfm/windows/tabs/utils/launcher.py b/src/core/utils/shellfm/windows/tabs/utils/launcher.py index 1781218..9ff4755 100644 --- a/src/core/utils/shellfm/windows/tabs/utils/launcher.py +++ b/src/core/utils/shellfm/windows/tabs/utils/launcher.py @@ -8,6 +8,9 @@ import shlex # Apoplication imports +class ShellFMLauncherException(Exception): + ... + class Launcher: @@ -76,7 +79,24 @@ class Launcher: try: proc = subprocess.Popen(command) proc.wait() - except Exception as e: + except ShellFMLauncherException as e: + self.logger.debug(e) + return False + + return True + + def handbrake_remux_video(self, hash, file): + remux_vid_pth = f"{self.REMUX_FOLDER}/{hash}.mp4" + self.logger.debug(remux_vid_pth) + + if not os.path.isfile(remux_vid_pth): + self.check_remux_space() + + command = ["HandBrakeCLI", "-i", file, "-e", "nvenc_h264", "-f", "av_mp4", "-O", "-o", remux_vid_pth] + try: + proc = subprocess.Popen(command) + proc.wait() + except ShellFMLauncherException as e: self.logger.debug(e) return False @@ -86,7 +106,7 @@ class Launcher: limit = self.remux_folder_max_disk_usage try: limit = int(limit) - except Exception as e: + except ShellFMLauncherException as e: self.logger.debug(e) return