Added handbreak cli conversion, fixed background loading, cleanup

This commit is contained in:
itdominator 2023-06-07 20:59:42 -05:00
parent f5d2f3dd4f
commit 4b3782d671
7 changed files with 58 additions and 36 deletions

View File

@ -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. # Yes, the process probably should give us info we can process when failure occures.
command = [ command = [
"ffmpeg", "-nostdin", "-fflags", "+genpts", "-hwaccel", "cuda", "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", "-vcodec", "copy", "-acodec", "copy", "-f", "rtsp",
"-rtsp_transport", "tcp", stream_target "-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) proc = subprocess.Popen(command, shell=False, stdin=None, stdout=None, stderr=None)
window = window_controllers[ session["win_controller_id"] ].get_window_by_index(0) window = window_controllers[ session["win_controller_id"] ].get_window_by_index(0)
tab = window.get_tab_by_index(0) tab = window.get_tab_by_index(0)

View File

@ -1,6 +1,5 @@
# Python imports # Python imports
import os import os
import subprocess
# Lib imports # Lib imports
from flask import Flask from flask import Flask

View File

@ -133,25 +133,22 @@ def remux_video(sse_id, hash, path, view):
link = f"https://www.webfm.com/sse/{sse_id}" link = f"https://www.webfm.com/sse/{sse_id}"
body = '{"path":"static/remuxs/' + hash + '.mp4"}' 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: if not good_result:
body = json_message.create("warning", "Remuxing: Remux failed...") body = json_message.create("warning", "Remuxing: Remux failed...")
requests.post(link, data=body, timeout=10) requests.post(link, data=body, timeout=10)
# @daemon_threaded
def setup_stream(sse_id, hash, path): def setup_stream(sse_id, hash, path):
link = f"https://www.webfm.com/sse/{sse_id}" link = f"https://www.webfm.com/sse/{sse_id}"
_sub_uuid = uuid.uuid4().hex _sub_uuid = uuid.uuid4().hex
_video_path = path _video_path = path
_stub = f"{hash}{_sub_uuid}" _stub = f"{hash}{_sub_uuid}"
_rtsp_path = f"rtsp://www.{app_name.lower()}.com:8554/{_stub}" _rtsp_path = f"rtsp://127.0.0.1:8554/{_stub}"
_rtmp_path = f"rtmp://www.{app_name.lower()}.com:1935/{_stub}"
_hls_path = f"http://www.{app_name.lower()}.com:8888/{_stub}/"
_webrtc_path = f"http://www.{app_name.lower()}.com:8889/{_stub}/" _webrtc_path = f"http://www.{app_name.lower()}.com:8889/{_stub}/"
_stream_target = _rtsp_path _stream_target = _rtsp_path
body = '{"stream":"' + _stream_target + '"}'
process = get_stream() process = get_stream()
if process: if process:
@ -168,6 +165,8 @@ def setup_stream(sse_id, hash, path):
requests.post(link, data=body, timeout=10) requests.post(link, data=body, timeout=10)
return return
_stream_target = _webrtc_path
body = '{"stream":"' + _stream_target + '"}'
requests.post(link, data=body, timeout=10) requests.post(link, data=body, timeout=10)

View File

@ -19,6 +19,7 @@ eventSource.onmessage = (eve) => {
try { try {
const data = JSON.parse(eve.data); const data = JSON.parse(eve.data);
const sse_msg = JSON.parse(data.message); const sse_msg = JSON.parse(data.message);
if (sse_msg.hasOwnProperty('path') || sse_msg.hasOwnProperty('stream')) { if (sse_msg.hasOwnProperty('path') || sse_msg.hasOwnProperty('stream')) {
const target = (sse_msg.path) ? sse_msg.path : sse_msg.stream; const target = (sse_msg.path) ? sse_msg.path : sse_msg.stream;
handleMedia(target); handleMedia(target);

View File

@ -70,22 +70,21 @@ const closeFile = async () => {
} }
const showFile = async (title, hash, extension, type, target=null) => { const showFile = async (title, hash, extension, type, target=null) => {
document.getElementById("selectedFile").innerText = title;
document.getElementById("image-viewer").style.display = "none"; document.getElementById("image-viewer").style.display = "none";
document.getElementById("text-viewer").style.display = "none"; document.getElementById("text-viewer").style.display = "none";
document.getElementById("pdf-viewer").style.display = "none"; document.getElementById("pdf-viewer").style.display = "none";
document.getElementById("video_container").style.display = "none"; document.getElementById("video_container").style.display = "none";
document.getElementById("trailerPlayer").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. // FIXME: Yes, a wasted call every time there is no stream.
await fetchData("api/stop-current-stream"); await fetchData("api/stop-current-stream");
if (type === "video" || type === "stream") { if (type === "video" || type === "stream") {
isStream = (type === "stream") ? true : false; isStream = (type === "stream") ? true : false;
target = (type === "stream") ? "stream" : "remux"; action = (type === "stream") ? "stream" : "remux";
setupVideo(hash, extension, isStream, target); setupVideo(hash, extension, isStream, action);
setSelectedActiveMedia(target); setSelectedActiveMedia(target);
} else if (type === "trailer") { } else if (type === "trailer") {
launchTrailer(hash); launchTrailer(hash);
@ -103,7 +102,7 @@ const launchTrailer = (link) => {
modal.show(); modal.show();
} }
const setupVideo = async (hash, extension, isStream, target="remux") => { const setupVideo = async (hash, extension, isStream, action="remux") => {
document.getElementById("video_container").style.display = ""; document.getElementById("video_container").style.display = "";
video_path = `api/file-manager-action/files/${hash}`; video_path = `api/file-manager-action/files/${hash}`;
@ -120,7 +119,7 @@ const setupVideo = async (hash, extension, isStream, target="remux") => {
return; 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); displayMessage(data.message.text, data.message.type, 5);
} catch (e) { } catch (e) {
video.style.display = "none"; video.style.display = "none";
@ -236,8 +235,10 @@ const loadBackgroundPoster = () => {
} }
if (data.poster !== null) { if (data.poster !== null) {
background_image = "api/file-manager-action/files/000.jpg?d=" + Date.now(); getSHA256Hash("000.jpg").then((_hash) => {
updateBackground(background_image, false); 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);
};

View File

@ -100,7 +100,7 @@ authMethods: [basic, digest]
# RTMP parameters # RTMP parameters
# Disable support for the RTMP protocol. # 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". # Address of the RTMP listener. This is needed only when encryption is "no" or "optional".
rtmpAddress: :1935 rtmpAddress: :1935
# Encrypt connections with TLS (RTMPS). # Encrypt connections with TLS (RTMPS).
@ -120,12 +120,12 @@ rtmpServerCert: server.crt
# HLS parameters # HLS parameters
# Disable support for the HLS protocol. # Disable support for the HLS protocol.
hlsDisable: no hlsDisable: yes
# Address of the HLS listener. # Address of the HLS listener.
hlsAddress: :8888 hlsAddress: :8888
# Enable TLS/HTTPS on the HLS server. # Enable TLS/HTTPS on the HLS server.
# This is required for Low-Latency HLS. # This is required for Low-Latency HLS.
hlsEncryption: yes hlsEncryption: no
# Path to the server key. This is needed only when encryption is yes. # Path to the server key. This is needed only when encryption is yes.
# This can be generated with: # This can be generated with:
# openssl genrsa -out server.key 2048 # openssl genrsa -out server.key 2048
@ -135,22 +135,22 @@ hlsServerKey: server.key
hlsServerCert: server.crt hlsServerCert: server.crt
# By default, HLS is generated only when requested by a user. # 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. # 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: # Variant of the HLS protocol to use. Available options are:
# * mpegts - uses MPEG-TS segments, for maximum compatibility. # * mpegts - uses MPEG-TS segments, for maximum compatibility.
# * fmp4 - uses fragmented MP4 segments, more efficient. # * fmp4 - uses fragmented MP4 segments, more efficient.
# * lowLatency - uses Low-Latency HLS. # * lowLatency - uses Low-Latency HLS.
hlsVariant: lowLatency hlsVariant: mpegts
# Number of HLS segments to keep on the server. # Number of HLS segments to keep on the server.
# Segments allow to seek through the stream. # Segments allow to seek through the stream.
# Their number doesn't influence latency. # Their number doesn't influence latency.
hlsSegmentCount: 7 hlsSegmentCount: 24
# Minimum duration of each segment. # Minimum duration of each segment.
# A player usually puts 3 segments in a buffer before reproducing the stream. # 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, # 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 # since the server changes the duration in order to include at least one IDR frame
# in each segment. # in each segment.
hlsSegmentDuration: 1s hlsSegmentDuration: 5s
# Minimum duration of each part. # Minimum duration of each part.
# A player usually puts 3 parts in a buffer before reproducing the stream. # A player usually puts 3 parts in a buffer before reproducing the stream.
# Parts are used in Low-Latency HLS in place of segments. # 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. # 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 # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # will be taken from the X-Forwarded-For header.
hlsTrustedProxies: [] hlsTrustedProxies: [0.0.0.0]
############################################### ###############################################
# WebRTC parameters # WebRTC parameters
# Disable support for the WebRTC protocol. # Disable support for the WebRTC protocol.
webrtcDisable: yes webrtcDisable: no
# Address of the WebRTC listener. # Address of the WebRTC listener.
webrtcAddress: :8889 webrtcAddress: :8889
# Enable TLS/HTTPS on the WebRTC server. # Enable TLS/HTTPS on the WebRTC server.
@ -190,7 +190,7 @@ webrtcAllowOrigin: '*'
# List of IPs or CIDRs of proxies placed before the WebRTC server. # 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 # If the server receives a request from one of these entries, IP in logs
# will be taken from the X-Forwarded-For header. # 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. # List of ICE servers, in format type:user:pass:host:port or type:host:port.
# type can be "stun", "turn" or "turns". # type can be "stun", "turn" or "turns".
# STUN servers are used to get the public IP of both server and clients. # 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] 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. # 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. # 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. # Address of a ICE UDP listener in format host:port.
# If filled, ICE traffic will come through a single UDP 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. # allowing the deployment of the server inside a container or behind a NAT.

View File

@ -8,6 +8,9 @@ import shlex
# Apoplication imports # Apoplication imports
class ShellFMLauncherException(Exception):
...
class Launcher: class Launcher:
@ -76,7 +79,24 @@ class Launcher:
try: try:
proc = subprocess.Popen(command) proc = subprocess.Popen(command)
proc.wait() 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) self.logger.debug(e)
return False return False
@ -86,7 +106,7 @@ class Launcher:
limit = self.remux_folder_max_disk_usage limit = self.remux_folder_max_disk_usage
try: try:
limit = int(limit) limit = int(limit)
except Exception as e: except ShellFMLauncherException as e:
self.logger.debug(e) self.logger.debug(e)
return return