Compare commits
No commits in common. "8db6107dfa7a1f93496dde352de08aba2c2b27ce" and "bb058bb98965ff09e01a619ba5ee0929c8dea444" have entirely different histories.
8db6107dfa
...
bb058bb989
11 changed files with 70 additions and 281 deletions
|
|
@ -8,7 +8,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
try:
|
try:
|
||||||
asyncio.run(obj_server.start_server())
|
asyncio.run(obj_server.start_server())
|
||||||
except KeyboardInterrupt:
|
except asyncio.exceptions.CancelledError:
|
||||||
logging.warning("Server wurde manuell beendet")
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.critical(f"Global error: {e}")
|
logging.critical(f"Global error: {e}")
|
||||||
|
|
@ -2,7 +2,7 @@ log_file: "server.log"
|
||||||
log_level: DEBUG
|
log_level: DEBUG
|
||||||
log_rotation: time
|
log_rotation: time
|
||||||
path_file: "media_path.yaml"
|
path_file: "media_path.yaml"
|
||||||
server_ip: "0.0.0.0"
|
server_ip: "127.0.0.1"
|
||||||
server_port: 8000
|
server_port: 8000
|
||||||
task_max: 1
|
task_max: 1
|
||||||
autostart: true
|
autostart: true
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class Convert:
|
||||||
"""Startet die Videokonvertierung asynchron."""
|
"""Startet die Videokonvertierung asynchron."""
|
||||||
|
|
||||||
obj_process = Process(self.obj_websocket)
|
obj_process = Process(self.obj_websocket)
|
||||||
obj_stat = Stat()
|
obj_stat = Stat(obj)
|
||||||
|
|
||||||
obj.convert_start = time.time()
|
obj.convert_start = time.time()
|
||||||
command = self.convert_cmd(obj)
|
command = self.convert_cmd(obj)
|
||||||
|
|
@ -79,7 +79,7 @@ class Convert:
|
||||||
self.active_process.discard(obj)
|
self.active_process.discard(obj)
|
||||||
self.active_tasks.discard(obj)
|
self.active_tasks.discard(obj)
|
||||||
self.obj_path.save_paths()
|
self.obj_path.save_paths()
|
||||||
obj_stat.save_stat(obj)
|
obj_stat.save_stat()
|
||||||
|
|
||||||
obj.convert_end = time.time()
|
obj.convert_end = time.time()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,3 +112,38 @@ class Process:
|
||||||
"bitrate": self.bitrate,
|
"bitrate": self.bitrate,
|
||||||
"speed": self.speed
|
"speed": self.speed
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def size_convert(source: str, target, unit: str, size=0):
|
||||||
|
list_unit: list = []
|
||||||
|
|
||||||
|
if unit == "storage":
|
||||||
|
list_unit = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"]
|
||||||
|
elif unit == "data_rate":
|
||||||
|
list_unit = ["bps", "Kbps", "Mbps", "Gbps", "Tbps", "Pbps"]
|
||||||
|
elif unit == "binary_data_rate":
|
||||||
|
list_unit = ["b/s", "Kib/s", "Mib/s", "Gib/s", "Tib/s", "Pib/s"]
|
||||||
|
|
||||||
|
factor = 1024 # Binäre Umrechnung
|
||||||
|
|
||||||
|
if source not in list_unit:
|
||||||
|
raise ValueError("Ungültige Quell-Einheit!")
|
||||||
|
|
||||||
|
source_index = list_unit.index(source)
|
||||||
|
|
||||||
|
if target:
|
||||||
|
if target not in list_unit:
|
||||||
|
raise ValueError("Ungültige Ziel-Einheit!")
|
||||||
|
target_index = list_unit.index(target)
|
||||||
|
|
||||||
|
if source_index < target_index:
|
||||||
|
return size / (factor ** (target_index - source_index)), target
|
||||||
|
else:
|
||||||
|
return size * (factor ** (source_index - target_index)), target
|
||||||
|
|
||||||
|
# Automatische Umrechnung
|
||||||
|
while size >= 1000 and source_index < len(list_unit) - 1:
|
||||||
|
size /= factor
|
||||||
|
source_index += 1
|
||||||
|
|
||||||
|
return [round(size,1), list_unit[source_index]]
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,13 @@ class Media:
|
||||||
self.source_file: str = path
|
self.source_file: str = path
|
||||||
self.source_file_name: str = os.path.basename(self.source_file)
|
self.source_file_name: str = os.path.basename(self.source_file)
|
||||||
self.source_duration: int = self.time_in_sec(streams_video[0]["tags"].get("DURATION" or "duration", "00:00:00"))
|
self.source_duration: int = self.time_in_sec(streams_video[0]["tags"].get("DURATION" or "duration", "00:00:00"))
|
||||||
self.source_size: list = self.size_convert("B", None, "storage", int(streams_format[0].get("size")))
|
self.source_size: int = 0
|
||||||
self.source_frame_rate: int = self.frame_rate(streams_video)
|
self.source_frame_rate: int = self.frame_rate(streams_video)
|
||||||
self.source_frames_total: int = self.source_frame_rate * self.source_duration
|
self.source_frames_total: int = self.source_frame_rate * self.source_duration
|
||||||
self.source_time: int = 0
|
self.source_time: int = 0
|
||||||
|
|
||||||
# target
|
# target
|
||||||
self.target_file: str = f"{path.rsplit(".", 1)[0]}.webm"
|
self.target_file: str = f"{path.rsplit(".", 1)[0]}.webm"
|
||||||
self.target_file_name: str = os.path.basename(self.target_file)
|
|
||||||
self.target_size: int = 0
|
self.target_size: int = 0
|
||||||
|
|
||||||
# process
|
# process
|
||||||
|
|
@ -86,7 +85,6 @@ class Media:
|
||||||
def to_dict_stat(self):
|
def to_dict_stat(self):
|
||||||
return {self.id: {
|
return {self.id: {
|
||||||
# source
|
# source
|
||||||
"source_file_name": self.source_file_name,
|
|
||||||
"source_file": self.source_file,
|
"source_file": self.source_file,
|
||||||
"source_duration": self.source_duration,
|
"source_duration": self.source_duration,
|
||||||
"source_size": self.source_size,
|
"source_size": self.source_size,
|
||||||
|
|
@ -95,7 +93,6 @@ class Media:
|
||||||
"source_time": self.source_time,
|
"source_time": self.source_time,
|
||||||
|
|
||||||
# target
|
# target
|
||||||
"target_file_name": self.target_file_name,
|
|
||||||
"target_file": self.target_file,
|
"target_file": self.target_file,
|
||||||
"target_size": self.target_size,
|
"target_size": self.target_size,
|
||||||
|
|
||||||
|
|
@ -173,38 +170,3 @@ class Media:
|
||||||
return int(h * 3600 + m * 60 + s) # Alles in Sekunden umrechnen
|
return int(h * 3600 + m * 60 + s) # Alles in Sekunden umrechnen
|
||||||
|
|
||||||
raise ValueError(f"Ungültiges Zeitformat: {time_str}")
|
raise ValueError(f"Ungültiges Zeitformat: {time_str}")
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def size_convert(source: str, target, unit: str, size=0):
|
|
||||||
list_unit: list = []
|
|
||||||
|
|
||||||
if unit == "storage":
|
|
||||||
list_unit = ["B", "KiB", "MiB", "GiB", "TiB", "PiB"]
|
|
||||||
elif unit == "data_rate":
|
|
||||||
list_unit = ["bps", "Kbps", "Mbps", "Gbps", "Tbps", "Pbps"]
|
|
||||||
elif unit == "binary_data_rate":
|
|
||||||
list_unit = ["b/s", "Kib/s", "Mib/s", "Gib/s", "Tib/s", "Pib/s"]
|
|
||||||
|
|
||||||
factor = 1024 # Binäre Umrechnung
|
|
||||||
|
|
||||||
if source not in list_unit:
|
|
||||||
raise ValueError("Ungültige Quell-Einheit!")
|
|
||||||
|
|
||||||
source_index = list_unit.index(source)
|
|
||||||
|
|
||||||
if target:
|
|
||||||
if target not in list_unit:
|
|
||||||
raise ValueError("Ungültige Ziel-Einheit!")
|
|
||||||
target_index = list_unit.index(target)
|
|
||||||
|
|
||||||
if source_index < target_index:
|
|
||||||
return size / (factor ** (target_index - source_index)), target
|
|
||||||
else:
|
|
||||||
return size * (factor ** (source_index - target_index)), target
|
|
||||||
|
|
||||||
# Automatische Umrechnung
|
|
||||||
while size >= 1000 and source_index < len(list_unit) - 1:
|
|
||||||
size /= factor
|
|
||||||
source_index += 1
|
|
||||||
|
|
||||||
return [round(size, 1), list_unit[source_index]]
|
|
||||||
|
|
@ -2,29 +2,25 @@ import yaml
|
||||||
import os
|
import os
|
||||||
|
|
||||||
class Stat:
|
class Stat:
|
||||||
def __init__(self):
|
def __init__(self, obj):
|
||||||
self.path = "app/cfg/statistic.yaml"
|
self.obj = obj
|
||||||
|
|
||||||
def save_stat(self, obj):
|
def save_stat(self):
|
||||||
|
pfad = "app/cfg/statistic.yaml"
|
||||||
|
|
||||||
daten = self.read_stat()
|
# Bestehende Daten laden
|
||||||
|
if os.path.exists(pfad):
|
||||||
|
with open(pfad, "r", encoding="utf8") as file:
|
||||||
|
daten = yaml.safe_load(file) or {}
|
||||||
|
else:
|
||||||
|
daten = {}
|
||||||
|
|
||||||
# Videosammlung initialisieren, falls nötig
|
# Videosammlung initialisieren, falls nötig
|
||||||
daten.setdefault("videos", {})
|
daten.setdefault("videos", {})
|
||||||
|
|
||||||
# Neuen Eintrag hinzufügen
|
# Neuen Eintrag hinzufügen
|
||||||
daten["videos"].update(obj.to_dict_stat())
|
daten["videos"].update(self.obj.to_dict_stat())
|
||||||
|
|
||||||
# Datei mit aktualisierten Daten speichern
|
# Datei mit aktualisierten Daten speichern
|
||||||
with open(self.path, "w", encoding="utf8") as file:
|
with open(pfad, "w", encoding="utf8") as file:
|
||||||
yaml.dump(daten, file, default_flow_style=False, indent=4, allow_unicode=True)
|
yaml.dump(daten, file, default_flow_style=False, indent=4, allow_unicode=True)
|
||||||
|
|
||||||
def read_stat(self):
|
|
||||||
# Bestehende Daten laden
|
|
||||||
if os.path.exists(self.path):
|
|
||||||
with open(self.path, "r", encoding="utf8") as file:
|
|
||||||
daten = yaml.safe_load(file) or {}
|
|
||||||
else:
|
|
||||||
daten = {}
|
|
||||||
|
|
||||||
return daten
|
|
||||||
|
|
@ -4,14 +4,12 @@ import websockets
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from asyncio import CancelledError
|
|
||||||
from websockets import InvalidUpgrade, ConnectionClosed, ConnectionClosedError
|
from websockets import InvalidUpgrade, ConnectionClosed, ConnectionClosedError
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
|
|
||||||
from app.class_settings import Settings
|
from app.class_settings import Settings
|
||||||
from app.class_file_path import Path
|
from app.class_file_path import Path
|
||||||
from app.class_file_convert import Convert
|
from app.class_file_convert import Convert
|
||||||
from app.class_media_file_stat import Stat
|
|
||||||
|
|
||||||
var_convert_active = False
|
var_convert_active = False
|
||||||
|
|
||||||
|
|
@ -58,14 +56,14 @@ class Server:
|
||||||
elif data.get("data_message"):
|
elif data.get("data_message"):
|
||||||
logging.info(f"Server hat Empfangen: {data.get('data_message')}")
|
logging.info(f"Server hat Empfangen: {data.get('data_message')}")
|
||||||
|
|
||||||
except (ConnectionClosedError, ConnectionClosed):
|
except (ConnectionClosedError, InvalidUpgrade):
|
||||||
logging.warning("Client Verbindung geschlossen")
|
pass
|
||||||
except InvalidUpgrade:
|
except json.JSONDecodeError as e:
|
||||||
logging.warning("Ungültiger Websocket Upgrade versuch")
|
logging.error(f"JSON Fehler: {e}")
|
||||||
except Exception as e:
|
except ConnectionClosed:
|
||||||
logging.error(f"Unerwarteter Fehler {e}")
|
logging.error("Server sagt: Client getrennt")
|
||||||
finally:
|
finally:
|
||||||
self.clients.discard(websocket)
|
self.clients.remove(websocket)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def set_var_convert_active(value: bool):
|
def set_var_convert_active(value: bool):
|
||||||
|
|
@ -89,17 +87,11 @@ class Server:
|
||||||
port = self.yaml.get("server_port", 8000)
|
port = self.yaml.get("server_port", 8000)
|
||||||
return web.json_response({"server_ip": ip, "server_port": port})
|
return web.json_response({"server_ip": ip, "server_port": port})
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def handle_stat(request):
|
|
||||||
obj_stat = Stat()
|
|
||||||
return web.json_response(obj_stat.read_stat())
|
|
||||||
|
|
||||||
async def server_http(self):
|
async def server_http(self):
|
||||||
app = web.Application()
|
app = web.Application()
|
||||||
app.router.add_get("/", self.handle_index)
|
app.router.add_get("/", self.handle_index)
|
||||||
app.router.add_get("/api/ip", self.handle_ip)
|
app.router.add_get("/api/ip", self.handle_ip)
|
||||||
app.router.add_get("/api/stats", self.handle_stat)
|
app.router.add_static("/client", path="./client", name="client")
|
||||||
app.router.add_static("/client/", path="./client", name="client")
|
|
||||||
runner = web.AppRunner(app)
|
runner = web.AppRunner(app)
|
||||||
await runner.setup()
|
await runner.setup()
|
||||||
site = web.TCPSite(runner, "0.0.0.0", 8080)
|
site = web.TCPSite(runner, "0.0.0.0", 8080)
|
||||||
|
|
@ -109,12 +101,7 @@ class Server:
|
||||||
# Start Server -----------------------------------------------------------------------------------------------------
|
# Start Server -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
async def start_server(self):
|
async def start_server(self):
|
||||||
try:
|
|
||||||
await asyncio.gather(
|
await asyncio.gather(
|
||||||
self.server_websocket(),
|
self.server_websocket(),
|
||||||
self.server_http()
|
self.server_http()
|
||||||
)
|
)
|
||||||
except CancelledError:
|
|
||||||
logging.warning("Server wurde durch Keyboard Interrupt gestoppt.")
|
|
||||||
except Exception as e:
|
|
||||||
logging.error(f"Unerwarteter Fehler beim Starten des Servers {e}")
|
|
||||||
|
|
|
||||||
50
client/client.js
Executable file → Normal file
50
client/client.js
Executable file → Normal file
|
|
@ -6,11 +6,6 @@ async function getServerConfig() {
|
||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getMediaStat() {
|
|
||||||
const response = await fetch('/api/stats');
|
|
||||||
return await response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
getServerConfig()
|
getServerConfig()
|
||||||
.then(data => {
|
.then(data => {
|
||||||
const websocketIp = data.server_ip;
|
const websocketIp = data.server_ip;
|
||||||
|
|
@ -37,48 +32,3 @@ getServerConfig()
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error fetching settings:', error);
|
console.error('Error fetching settings:', error);
|
||||||
});
|
});
|
||||||
|
|
||||||
getMediaStat()
|
|
||||||
.then(data => {
|
|
||||||
console.log("Antwort von /api/stats:", data); // Debug-Ausgabe
|
|
||||||
|
|
||||||
if (!data || typeof data !== 'object' || !data.videos || typeof data.videos !== 'object') {
|
|
||||||
throw new Error("Ungültiges Antwortformat oder fehlende 'videos'-Eigenschaft");
|
|
||||||
}
|
|
||||||
|
|
||||||
const stat_Container = document.getElementById('stat');
|
|
||||||
|
|
||||||
Object.keys(data.videos).forEach(key => {
|
|
||||||
const video = data.videos[key];
|
|
||||||
const card = document.createElement('div');
|
|
||||||
card.className = 'video-card';
|
|
||||||
card.id = key
|
|
||||||
|
|
||||||
card.innerHTML = `
|
|
||||||
<h3 title="${video.source_file}">${video.source_file_name}</h3>
|
|
||||||
<div class="actions">
|
|
||||||
<button>Löschen</button>
|
|
||||||
</div>
|
|
||||||
<div class="tooltip">
|
|
||||||
Quelle: ${video.source_file}<br>
|
|
||||||
Dauer: ${video.source_duration}<br>
|
|
||||||
Größe: ${video.source_size}<br>
|
|
||||||
FPS: ${video.source_frame_rate}<br>
|
|
||||||
Frames: ${video.source_frames_total}<br>
|
|
||||||
Start: ${video.process_start}<br>
|
|
||||||
Ende: ${video.process_end}<br>
|
|
||||||
Status: ${video.status}<br>
|
|
||||||
Zeit: ${video.process_time}<br>
|
|
||||||
Größe (Ziel): ${video.target_size}<br>
|
|
||||||
FPS (aktuell): ${video.stat_fps}<br>
|
|
||||||
Bitrate: ${video.stat_bitrate}<br>
|
|
||||||
Speed: ${video.stat_speed}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
stat_Container.appendChild(card)
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Fehler beim Abrufen der Medienstatistik:', error);
|
|
||||||
});
|
|
||||||
27
client/index.html
Executable file → Normal file
27
client/index.html
Executable file → Normal file
|
|
@ -3,35 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Websocket Client</title>
|
<title>Websocket Client</title>
|
||||||
<link rel="stylesheet" href="/client/index_style.css">
|
|
||||||
<link rel="icon" href="/client/icons/favicon.ico" type="image/x-icon">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- === Menü === -->
|
|
||||||
<header>
|
|
||||||
<h1>Video Konvertierung</h1>
|
|
||||||
<nav>
|
|
||||||
<button onclick="alert('Statistiken bald verfügbar')">Statistiken</button>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<!-- === Aktive Konvertierungen === -->
|
|
||||||
<section id="active-conversions">
|
|
||||||
<h2>Aktive Konvertierungen</h2>
|
|
||||||
<!-- Wird dynamisch mit JS gefüllt -->
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- === Warteschleife === -->
|
|
||||||
<section id="queue">
|
|
||||||
<h2>Warteschleife</h2>
|
|
||||||
<!-- Wird dynamisch mit JS gefüllt -->
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<!-- === Statistikbereich === -->
|
|
||||||
<section id="stat">
|
|
||||||
<h2>Allgemeine Statistiken</h2>
|
|
||||||
<p>Hier könnten Diagramme, Durchschnittswerte etc. angezeigt werden.</p>
|
|
||||||
</section>
|
|
||||||
<script src="/client/client.js"></script>
|
<script src="/client/client.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
/* === Allgemeines Design === */
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #121212;
|
|
||||||
color: #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #90caf9;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Menü oben === */
|
|
||||||
header {
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
padding: 1rem;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
border-bottom: 1px solid #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav button {
|
|
||||||
background-color: #333;
|
|
||||||
color: #fff;
|
|
||||||
border: none;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav button:hover {
|
|
||||||
background-color: #444;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Bereich: Aktive Konvertierungen === */
|
|
||||||
#active-conversions {
|
|
||||||
padding: 1rem;
|
|
||||||
border-bottom: 1px solid #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#active-conversions h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-card {
|
|
||||||
background-color: #1f1f1f;
|
|
||||||
padding: 1rem;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
border-radius: 8px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-card h3 {
|
|
||||||
margin: 0 0 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-card .actions button {
|
|
||||||
background-color: #444;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
padding: 0.4rem 0.8rem;
|
|
||||||
margin-right: 0.5rem;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-card .actions button:hover {
|
|
||||||
background-color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
position: absolute;
|
|
||||||
background-color: #333;
|
|
||||||
color: #eee;
|
|
||||||
padding: 0.5rem;
|
|
||||||
border-radius: 6px;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
display: none;
|
|
||||||
width: max-content;
|
|
||||||
max-width: 300px;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.video-card:hover .tooltip {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Bereich: Warteschleife === */
|
|
||||||
#queue {
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
#queue h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Statistik-Bereich === */
|
|
||||||
#statistics {
|
|
||||||
padding: 1rem;
|
|
||||||
border-top: 1px solid #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
#statistics h2 {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
SERVER="ws://192.168.155.110:8000/"
|
SERVER="ws://localhost:8000/"
|
||||||
|
|
||||||
for FILE in "$@"; do
|
for FILE in "$@"; do
|
||||||
JSON=$(printf '{"data_path": "%s"}' "$FILE")
|
JSON=$(printf '{"data_path: "%s"}' "$FILE")
|
||||||
echo "$JSON" | websocat "$SERVER"
|
echo "$JSON" | websocat "$SERVER"
|
||||||
|
|
||||||
done
|
done
|
||||||
Loading…
Reference in a new issue