Added handbreak cli conversion, fixed background loading, cleanup
This commit is contained in:
parent
f5d2f3dd4f
commit
4b3782d671
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
};
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user