2026-04-19 20:41:37 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
AZA Empfang - Schlanke Desktop-Huelle fuer die Empfangs-Weboberflaeche.
|
2026-04-21 10:05:37 +02:00
|
|
|
|
|
|
|
|
Standard: Laedt die Empfang-URL direkt im Fenster (kein iframe) — zuverlaessig
|
|
|
|
|
mit Edge WebView2 unter Windows.
|
|
|
|
|
|
|
|
|
|
Optional: Umgebungsvariable AZA_EMPFANG_IFRAME=1 aktiviert die alte iframe-Huelle
|
|
|
|
|
(Toolbar in HTML); dazu sollte der Server frame-embedding erlauben.
|
2026-04-19 20:41:37 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import ssl
|
|
|
|
|
import sys
|
|
|
|
|
import threading
|
|
|
|
|
import webbrowser
|
|
|
|
|
|
|
|
|
|
_APP_TITLE = "AZA Empfang"
|
|
|
|
|
_MIN_SIZE = (380, 500)
|
|
|
|
|
_DEFAULT_W, _DEFAULT_H = 480, 820
|
|
|
|
|
|
|
|
|
|
_PUBLIC_EMPFANG_URL = "https://empfang.aza-medwork.ch"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _data_dir():
|
|
|
|
|
if getattr(sys, "frozen", False):
|
|
|
|
|
return sys._MEIPASS
|
|
|
|
|
return os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _user_dir():
|
|
|
|
|
if getattr(sys, "frozen", False):
|
|
|
|
|
return os.path.dirname(sys.executable)
|
|
|
|
|
return os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _empfang_url():
|
|
|
|
|
try:
|
|
|
|
|
p = os.path.join(_data_dir(), "backend_url.txt")
|
|
|
|
|
with open(p, "r", encoding="utf-8") as f:
|
|
|
|
|
return f.read().strip().rstrip("/") + "/empfang/"
|
|
|
|
|
except Exception:
|
|
|
|
|
return _PUBLIC_EMPFANG_URL + "/empfang/"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_SETTINGS_FILE = os.path.join(_user_dir(), "empfang_app_settings.json")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _load_settings() -> dict:
|
|
|
|
|
defaults = {"width": _DEFAULT_W, "height": _DEFAULT_H,
|
|
|
|
|
"x": None, "y": None, "on_top": False}
|
|
|
|
|
try:
|
|
|
|
|
with open(_SETTINGS_FILE, "r", encoding="utf-8") as f:
|
|
|
|
|
return {**defaults, **json.load(f)}
|
|
|
|
|
except Exception:
|
|
|
|
|
return defaults
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _save_settings(s: dict):
|
|
|
|
|
try:
|
|
|
|
|
with open(_SETTINGS_FILE, "w", encoding="utf-8") as f:
|
|
|
|
|
json.dump(s, f, indent=2)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class _Api:
|
|
|
|
|
def __init__(self, window, on_top: bool, url: str):
|
|
|
|
|
self._w = window
|
|
|
|
|
self._on_top = on_top
|
|
|
|
|
self._url = url
|
|
|
|
|
self._pin_lock = threading.Lock()
|
|
|
|
|
|
|
|
|
|
def check_url(self):
|
|
|
|
|
"""Diagnostic connectivity check (GET with SSL fallback)."""
|
|
|
|
|
from urllib.request import urlopen, Request
|
|
|
|
|
for verify in (True, False):
|
|
|
|
|
try:
|
|
|
|
|
ctx = ssl.create_default_context() if verify else ssl._create_unverified_context()
|
|
|
|
|
req = Request(self._url)
|
|
|
|
|
with urlopen(req, timeout=10, context=ctx) as r:
|
|
|
|
|
r.read(512)
|
|
|
|
|
return {"ok": True, "url": self._url, "error": ""}
|
|
|
|
|
except ssl.SSLError:
|
|
|
|
|
if verify:
|
|
|
|
|
continue
|
|
|
|
|
return {"ok": False, "url": self._url,
|
|
|
|
|
"error": "SSL/TLS-Zertifikatsfehler. Bitte IT kontaktieren."}
|
|
|
|
|
except Exception as e:
|
|
|
|
|
if verify:
|
|
|
|
|
continue
|
|
|
|
|
return {"ok": False, "url": self._url, "error": str(e)}
|
|
|
|
|
return {"ok": False, "url": self._url,
|
|
|
|
|
"error": "Server nicht erreichbar. Bitte Netzwerk pruefen."}
|
|
|
|
|
|
|
|
|
|
def open_in_browser(self):
|
2026-04-21 10:05:37 +02:00
|
|
|
"""Öffnet dieselbe Ziel-URL wie im Fenster (lokal oder Produktion)."""
|
|
|
|
|
webbrowser.open(self._url)
|
2026-04-19 20:41:37 +02:00
|
|
|
|
|
|
|
|
def toggle_on_top(self):
|
|
|
|
|
if not self._pin_lock.acquire(blocking=False):
|
|
|
|
|
return self._on_top
|
|
|
|
|
try:
|
|
|
|
|
self._on_top = not self._on_top
|
|
|
|
|
new_val = self._on_top
|
|
|
|
|
finally:
|
|
|
|
|
self._pin_lock.release()
|
|
|
|
|
|
|
|
|
|
def _apply():
|
|
|
|
|
try:
|
|
|
|
|
self._w.on_top = new_val
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
threading.Thread(target=_apply, daemon=True).start()
|
|
|
|
|
return new_val
|
|
|
|
|
|
|
|
|
|
def get_on_top(self):
|
|
|
|
|
return self._on_top
|
|
|
|
|
|
|
|
|
|
def get_version(self):
|
|
|
|
|
try:
|
|
|
|
|
sys.path.insert(0, _data_dir())
|
|
|
|
|
from _build_info import BUILD_TIME, GIT_COMMIT
|
|
|
|
|
return f"Build: {BUILD_TIME} ({GIT_COMMIT})"
|
|
|
|
|
except Exception:
|
|
|
|
|
return "Entwicklungsversion"
|
|
|
|
|
|
|
|
|
|
def get_url(self):
|
|
|
|
|
return self._url
|
|
|
|
|
|
|
|
|
|
def get_public_url(self):
|
|
|
|
|
return _PUBLIC_EMPFANG_URL
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_SHELL_HTML = r'''<!DOCTYPE html>
|
|
|
|
|
<html lang="de">
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
<style>
|
|
|
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
|
|
|
html,body{height:100%;overflow:hidden}
|
|
|
|
|
body{font-family:'Segoe UI',system-ui,sans-serif;background:#f0f4f8}
|
|
|
|
|
#toolbar{
|
|
|
|
|
height:34px;
|
|
|
|
|
background:linear-gradient(135deg,#5B8DB3,#3a6d93);
|
|
|
|
|
display:flex;align-items:center;justify-content:space-between;
|
|
|
|
|
padding:0 10px;box-shadow:0 1px 4px rgba(0,0,0,.15);
|
|
|
|
|
position:relative;z-index:20;
|
|
|
|
|
}
|
|
|
|
|
.tb-l,.tb-r{display:flex;align-items:center;gap:6px}
|
|
|
|
|
.tb-title{color:#fff;font-size:12px;font-weight:600;letter-spacing:.3px}
|
|
|
|
|
.tb-btn{
|
|
|
|
|
background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);
|
|
|
|
|
color:#fff;border-radius:4px;padding:3px 9px;font-size:11px;
|
|
|
|
|
cursor:pointer;transition:all .15s;font-family:inherit;white-space:nowrap;
|
|
|
|
|
}
|
|
|
|
|
.tb-btn:hover{background:rgba(255,255,255,.2)}
|
|
|
|
|
.tb-btn.on{background:rgba(255,255,255,.35);border-color:rgba(255,255,255,.6);font-weight:600}
|
|
|
|
|
.tb-btn.busy{opacity:.5;pointer-events:none}
|
|
|
|
|
#content{position:absolute;top:34px;left:0;right:0;bottom:0}
|
|
|
|
|
#frame{width:100%;height:100%;border:none;display:none}
|
|
|
|
|
#loading{
|
|
|
|
|
position:absolute;top:0;left:0;right:0;bottom:0;
|
|
|
|
|
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
|
|
|
|
background:#f0f4f8;z-index:10;
|
|
|
|
|
}
|
|
|
|
|
.spin{width:34px;height:34px;border:3px solid #dde8f0;border-top-color:#5B8DB3;
|
|
|
|
|
border-radius:50%;animation:sp .8s linear infinite;margin-bottom:16px}
|
|
|
|
|
@keyframes sp{to{transform:rotate(360deg)}}
|
|
|
|
|
.ld-t{color:#5B8DB3;font-size:13px;font-weight:500}
|
|
|
|
|
.ld-s{color:#8aa8bc;font-size:11px;margin-top:5px}
|
|
|
|
|
#error{
|
|
|
|
|
position:absolute;top:0;left:0;right:0;bottom:0;
|
|
|
|
|
display:none;flex-direction:column;align-items:center;justify-content:center;
|
|
|
|
|
background:#f0f4f8;padding:30px;text-align:center;z-index:10;
|
|
|
|
|
}
|
|
|
|
|
.er-i{font-size:44px;margin-bottom:14px;opacity:.65}
|
|
|
|
|
.er-h{font-size:15px;font-weight:600;color:#1a4d6d;margin-bottom:6px}
|
|
|
|
|
.er-m{font-size:12px;color:#6a8a9a;margin-bottom:20px;line-height:1.6}
|
|
|
|
|
.er-b{display:flex;gap:8px}
|
|
|
|
|
.er-btn{background:#5B8DB3;color:#fff;border:none;border-radius:6px;
|
|
|
|
|
padding:8px 18px;font-size:12px;cursor:pointer;font-weight:500;font-family:inherit}
|
|
|
|
|
.er-btn:hover{background:#4A7A9E}
|
|
|
|
|
.er-btn.s{background:#dde8f0;color:#1a4d6d}
|
|
|
|
|
.er-btn.s:hover{background:#ccd8e0}
|
|
|
|
|
</style>
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div id="toolbar">
|
|
|
|
|
<div class="tb-l"><span class="tb-title">AZA Empfang</span></div>
|
|
|
|
|
<div class="tb-r">
|
|
|
|
|
<button class="tb-btn" onclick="doReload()" title="Seite neu laden">↻ Laden</button>
|
|
|
|
|
<button class="tb-btn" onclick="doOpen()" title="Im Browser oeffnen">↗ Browser</button>
|
|
|
|
|
<button class="tb-btn" id="bp" onclick="doPin()" title="Immer im Vordergrund">📌</button>
|
|
|
|
|
<button class="tb-btn" onclick="doInfo()" title="Version / Info">ℹ</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="content">
|
|
|
|
|
<div id="loading">
|
|
|
|
|
<div class="spin"></div>
|
|
|
|
|
<div class="ld-t">Empfang wird geladen</div>
|
|
|
|
|
<div class="ld-s">Verbindung wird hergestellt…</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="error">
|
|
|
|
|
<div class="er-i">⚠️</div>
|
|
|
|
|
<div class="er-h">Empfang nicht erreichbar</div>
|
|
|
|
|
<div class="er-m" id="erMsg">Die Empfangsseite konnte nicht geladen werden.</div>
|
|
|
|
|
<div class="er-b">
|
|
|
|
|
<button class="er-btn" onclick="doReload()">↻ Neu laden</button>
|
|
|
|
|
<button class="er-btn s" onclick="doOpen()">↗ Im Browser oeffnen</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<iframe id="frame" src="about:blank"></iframe>
|
|
|
|
|
</div>
|
|
|
|
|
<script>
|
|
|
|
|
var RDY=false, URL='';
|
|
|
|
|
window.addEventListener('pywebviewready',function(){
|
|
|
|
|
RDY=true;
|
|
|
|
|
pywebview.api.get_url().then(function(u){URL=u;boot()});
|
|
|
|
|
pinInit();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
function view(id){
|
|
|
|
|
['loading','error','frame'].forEach(function(k){
|
|
|
|
|
var e=document.getElementById(k);
|
|
|
|
|
e.style.display=(k===id)?(k==='frame'?'block':'flex'):'none';
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function boot(){
|
|
|
|
|
view('loading');
|
|
|
|
|
var f=document.getElementById('frame');
|
|
|
|
|
var done=false;
|
|
|
|
|
f.onload=function(){
|
|
|
|
|
if(!done&&f.src!=='about:blank'){done=true;view('frame')}
|
|
|
|
|
};
|
2026-04-20 14:38:16 +02:00
|
|
|
var cacheBust = '?_t=' + Date.now();
|
|
|
|
|
f.src=URL + (URL.indexOf('?')>=0 ? '&_t=' : '?_t=') + Date.now();
|
2026-04-19 20:41:37 +02:00
|
|
|
setTimeout(function(){
|
|
|
|
|
if(!done){diagnose()}
|
|
|
|
|
},12000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function diagnose(){
|
|
|
|
|
try{
|
|
|
|
|
var r=await pywebview.api.check_url();
|
|
|
|
|
if(r&&r.ok){
|
|
|
|
|
view('frame');
|
|
|
|
|
}else{
|
|
|
|
|
document.getElementById('erMsg').innerHTML=
|
|
|
|
|
(r&&r.error?r.error:'Server nicht erreichbar.')+'<br><br><small>URL: '+(r&&r.url||'')+'</small>';
|
|
|
|
|
view('error');
|
|
|
|
|
}
|
|
|
|
|
}catch(e){view('error')}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function doReload(){
|
|
|
|
|
view('loading');
|
|
|
|
|
var f=document.getElementById('frame');
|
|
|
|
|
var done=false;
|
|
|
|
|
f.onload=function(){
|
|
|
|
|
if(!done&&f.src!=='about:blank'){done=true;view('frame')}
|
|
|
|
|
};
|
|
|
|
|
f.src='about:blank';
|
2026-04-20 14:38:16 +02:00
|
|
|
setTimeout(function(){f.src=URL + (URL.indexOf('?')>=0 ? '&_t=' : '?_t=') + Date.now()},100);
|
2026-04-19 20:41:37 +02:00
|
|
|
setTimeout(function(){if(!done)diagnose()},12000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function doOpen(){if(RDY)pywebview.api.open_in_browser()}
|
|
|
|
|
|
|
|
|
|
var pinBusy=false;
|
|
|
|
|
async function doPin(){
|
|
|
|
|
if(!RDY||pinBusy)return;
|
|
|
|
|
var b=document.getElementById('bp');
|
|
|
|
|
pinBusy=true;
|
|
|
|
|
b.classList.add('busy');
|
|
|
|
|
try{
|
|
|
|
|
var v=await pywebview.api.toggle_on_top();
|
|
|
|
|
pinUI(v);
|
|
|
|
|
}catch(e){}
|
|
|
|
|
setTimeout(function(){pinBusy=false;b.classList.remove('busy')},300);
|
|
|
|
|
}
|
|
|
|
|
async function pinInit(){
|
|
|
|
|
try{var v=await pywebview.api.get_on_top();pinUI(v)}catch(e){}
|
|
|
|
|
}
|
|
|
|
|
function pinUI(on){
|
|
|
|
|
var b=document.getElementById('bp');
|
|
|
|
|
if(on){b.classList.add('on');b.textContent='\uD83D\uDCCC An';b.title='Immer im Vordergrund (aktiv)'}
|
|
|
|
|
else {b.classList.remove('on');b.textContent='\uD83D\uDCCC';b.title='Immer im Vordergrund'}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function doInfo(){
|
|
|
|
|
if(!RDY)return;
|
|
|
|
|
var v=await pywebview.api.get_version();
|
|
|
|
|
alert('AZA Empfang\n\n'+v+'\n'+URL);
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>'''
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
try:
|
|
|
|
|
import webview
|
|
|
|
|
except ImportError:
|
|
|
|
|
print("FEHLER: pywebview ist nicht installiert.")
|
|
|
|
|
print("Bitte ausfuehren: pip install pywebview")
|
|
|
|
|
sys.exit(1)
|
2026-04-21 10:05:37 +02:00
|
|
|
try:
|
|
|
|
|
from webview.menu import Menu, MenuAction, MenuSeparator
|
|
|
|
|
except ImportError:
|
|
|
|
|
Menu = None # type: ignore
|
|
|
|
|
MenuAction = None # type: ignore
|
|
|
|
|
MenuSeparator = None # type: ignore
|
2026-04-19 20:41:37 +02:00
|
|
|
|
|
|
|
|
settings = _load_settings()
|
|
|
|
|
url = _empfang_url()
|
2026-04-21 10:05:37 +02:00
|
|
|
# iframe-Huelle (alt): nur setzen wenn noetig: AZA_EMPFANG_IFRAME=1
|
|
|
|
|
use_iframe_shell = os.environ.get("AZA_EMPFANG_IFRAME", "").strip() == "1"
|
2026-04-19 20:41:37 +02:00
|
|
|
|
|
|
|
|
w = max(_MIN_SIZE[0], min(1920, settings.get("width") or _DEFAULT_W))
|
|
|
|
|
h = max(_MIN_SIZE[1], min(1200, settings.get("height") or _DEFAULT_H))
|
|
|
|
|
x = settings.get("x")
|
|
|
|
|
y = settings.get("y")
|
|
|
|
|
if isinstance(x, (int, float)) and isinstance(y, (int, float)):
|
|
|
|
|
if x < -200 or y < -200 or x > 3800 or y > 2200:
|
|
|
|
|
x, y = None, None
|
|
|
|
|
else:
|
|
|
|
|
x, y = None, None
|
|
|
|
|
|
2026-04-21 10:05:37 +02:00
|
|
|
on_top = bool(settings.get("on_top", False))
|
|
|
|
|
|
|
|
|
|
if use_iframe_shell:
|
|
|
|
|
window = webview.create_window(
|
|
|
|
|
_APP_TITLE,
|
|
|
|
|
html=_SHELL_HTML,
|
|
|
|
|
width=w,
|
|
|
|
|
height=h,
|
|
|
|
|
x=x,
|
|
|
|
|
y=y,
|
|
|
|
|
min_size=_MIN_SIZE,
|
|
|
|
|
on_top=on_top,
|
|
|
|
|
text_select=True,
|
|
|
|
|
background_color="#f0f4f8",
|
|
|
|
|
)
|
|
|
|
|
api = _Api(window, on_top, url)
|
|
|
|
|
window.expose(
|
|
|
|
|
api.check_url,
|
|
|
|
|
api.open_in_browser,
|
|
|
|
|
api.toggle_on_top,
|
|
|
|
|
api.get_on_top,
|
|
|
|
|
api.get_version,
|
|
|
|
|
api.get_url,
|
|
|
|
|
api.get_public_url,
|
|
|
|
|
)
|
|
|
|
|
else:
|
|
|
|
|
window = webview.create_window(
|
|
|
|
|
_APP_TITLE,
|
|
|
|
|
url=url,
|
|
|
|
|
width=w,
|
|
|
|
|
height=h,
|
|
|
|
|
x=x,
|
|
|
|
|
y=y,
|
|
|
|
|
min_size=_MIN_SIZE,
|
|
|
|
|
on_top=on_top,
|
|
|
|
|
text_select=True,
|
|
|
|
|
background_color="#f0f4f8",
|
|
|
|
|
)
|
|
|
|
|
api = _Api(window, on_top, url)
|
|
|
|
|
|
|
|
|
|
def _reload():
|
|
|
|
|
try:
|
|
|
|
|
window.evaluate_js("window.location.reload()")
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
print(f"[AZA Empfang] Neu laden: {exc}")
|
|
|
|
|
|
|
|
|
|
def _info_box():
|
|
|
|
|
try:
|
|
|
|
|
msg = f"{api.get_version()}\n\n{api._url}"
|
|
|
|
|
try:
|
|
|
|
|
import ctypes
|
|
|
|
|
|
|
|
|
|
ctypes.windll.user32.MessageBoxW(0, msg, _APP_TITLE, 0)
|
|
|
|
|
except Exception:
|
|
|
|
|
print(msg)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def _toggle_pin_menu():
|
|
|
|
|
api.toggle_on_top()
|
|
|
|
|
|
|
|
|
|
menu = None
|
|
|
|
|
if Menu is not None:
|
|
|
|
|
menu = [
|
|
|
|
|
Menu(
|
|
|
|
|
"Empfang",
|
|
|
|
|
[
|
|
|
|
|
MenuAction("Neu laden", _reload),
|
|
|
|
|
MenuAction("Im Browser \u00f6ffnen", api.open_in_browser),
|
|
|
|
|
MenuAction("Immer im Vordergrund", _toggle_pin_menu),
|
|
|
|
|
MenuSeparator(),
|
|
|
|
|
MenuAction("Version / Info", _info_box),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
]
|
2026-04-19 20:41:37 +02:00
|
|
|
|
|
|
|
|
def _on_closing():
|
|
|
|
|
try:
|
|
|
|
|
_save_settings({
|
2026-04-21 10:05:37 +02:00
|
|
|
"x": window.x,
|
|
|
|
|
"y": window.y,
|
|
|
|
|
"width": window.width,
|
|
|
|
|
"height": window.height,
|
2026-04-19 20:41:37 +02:00
|
|
|
"on_top": api._on_top,
|
|
|
|
|
})
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
window.events.closing += _on_closing
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
try:
|
2026-04-21 10:05:37 +02:00
|
|
|
if use_iframe_shell:
|
|
|
|
|
webview.start()
|
|
|
|
|
elif menu:
|
|
|
|
|
try:
|
|
|
|
|
webview.start(menu=menu)
|
|
|
|
|
except TypeError:
|
|
|
|
|
webview.start()
|
|
|
|
|
else:
|
|
|
|
|
webview.start()
|
2026-04-19 20:41:37 +02:00
|
|
|
except Exception as e:
|
|
|
|
|
print(f"[AZA Empfang] Fehler: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
try:
|
|
|
|
|
import ctypes
|
|
|
|
|
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
|
|
|
|
|
"ch.aza-medwork.empfang.v2")
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
try:
|
|
|
|
|
main()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(f"[AZA Empfang] Kritischer Fehler: {e}")
|
|
|
|
|
import traceback
|
|
|
|
|
traceback.print_exc()
|