AstraOS Ver. 1.23:
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
Fix: - ETS2 Download Timeout gefixt
This commit is contained in:
parent
fd977fcc01
commit
ea64ca0dcd
|
|
@ -8,12 +8,17 @@
|
||||||
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">ETS2 DLCs</h2>
|
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">ETS2 DLCs</h2>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
<div class="text-sm text-gray-400">
|
||||||
|
Große DLC-Pakete werden im Hintergrund als ZIP vorbereitet. Der Download steht erst bereit, wenn der Status <span class="text-white font-semibold">Bereit</span> ist.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
<div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden {% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
||||||
<table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}">
|
<table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}">
|
||||||
<thead class="bg-black/20">
|
<thead class="bg-black/20">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Name</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Name</th>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">DLC Datum</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">DLC Datum</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Status</th>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Erstellt von</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Erstellt von</th>
|
||||||
<th class="px-6 py-3 text-right text-xs font-medium text-gray-300 uppercase tracking-wider">Aktionen</th>
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-300 uppercase tracking-wider">Aktionen</th>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
@ -23,12 +28,26 @@
|
||||||
<tr class="transition {% if maintenance_active %}hover:bg-yellow-500/5{% else %}hover:bg-purple-500/5{% endif %}">
|
<tr class="transition {% if maintenance_active %}hover:bg-yellow-500/5{% else %}hover:bg-purple-500/5{% endif %}">
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-white">{{ package.name }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-white">{{ package.name }}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">{{ package.dlc_date_display }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">{{ package.dlc_date_display }}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">
|
||||||
|
<span class="px-2 py-1 rounded-full text-xs font-semibold
|
||||||
|
{% if package.archive_status == 'ready' %}bg-green-500/20 text-green-300
|
||||||
|
{% elif package.archive_status == 'building' or package.archive_status == 'pending' %}bg-yellow-500/20 text-yellow-300
|
||||||
|
{% else %}bg-red-500/20 text-red-300{% endif %}">
|
||||||
|
{{ package.archive_status_display }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">{{ package.created_by or 'N/A' }}</td>
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-300">{{ package.created_by or 'N/A' }}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-right">
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-right">
|
||||||
<div class="flex items-center justify-end gap-2">
|
<div class="flex items-center justify-end gap-2">
|
||||||
|
{% if package.download_ready %}
|
||||||
<a href="{{ url_for('download_ets2_dlc_package', package_id=package._id) }}" class="px-3 py-2 text-sm font-semibold rounded-lg transition text-white {% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">
|
<a href="{{ url_for('download_ets2_dlc_package', package_id=package._id) }}" class="px-3 py-2 text-sm font-semibold rounded-lg transition text-white {% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">
|
||||||
Download
|
Download
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<span class="px-3 py-2 text-sm font-semibold rounded-lg bg-gray-700 text-gray-300 cursor-not-allowed">
|
||||||
|
Download in Vorbereitung
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
{% if can_manage_ets2_dlcs %}
|
{% if can_manage_ets2_dlcs %}
|
||||||
<form action="{{ url_for('delete_ets2_dlc_package', package_id=package._id) }}" method="POST" onsubmit="return confirm('Möchtest du dieses DLC-Paket wirklich löschen?');">
|
<form action="{{ url_for('delete_ets2_dlc_package', package_id=package._id) }}" method="POST" onsubmit="return confirm('Möchtest du dieses DLC-Paket wirklich löschen?');">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
||||||
|
|
@ -42,7 +61,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
{% else %}
|
{% else %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="5" class="px-6 py-8 text-center text-gray-400">Noch keine DLC-Pakete vorhanden.</td>
|
<td colspan="6" class="px-6 py-8 text-center text-gray-400">Noch keine DLC-Pakete vorhanden.</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ from datetime import timedelta, datetime
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
import paramiko
|
import paramiko
|
||||||
from flask import jsonify, send_file, after_this_request
|
from flask import jsonify, send_file
|
||||||
import logging
|
import logging
|
||||||
from flask_socketio import SocketIO, emit, join_room, leave_room
|
from flask_socketio import SocketIO, emit, join_room, leave_room
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
@ -18,7 +18,6 @@ import ipaddress
|
||||||
import socket
|
import socket
|
||||||
import ssl
|
import ssl
|
||||||
import zipfile
|
import zipfile
|
||||||
import tempfile
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
async_mode = "eventlet"
|
async_mode = "eventlet"
|
||||||
|
|
@ -38,7 +37,11 @@ except Exception as e:
|
||||||
os.makedirs(BOT_UPLOAD_FOLDER, exist_ok=True)
|
os.makedirs(BOT_UPLOAD_FOLDER, exist_ok=True)
|
||||||
print(f"WARNUNG: Konnte '/opt/astraos/Discord_Bots' nicht erstellen ({e}), benutze lokalen Ordner: {BOT_UPLOAD_FOLDER}")
|
print(f"WARNUNG: Konnte '/opt/astraos/Discord_Bots' nicht erstellen ({e}), benutze lokalen Ordner: {BOT_UPLOAD_FOLDER}")
|
||||||
app.config['BOT_UPLOAD_FOLDER'] = BOT_UPLOAD_FOLDER
|
app.config['BOT_UPLOAD_FOLDER'] = BOT_UPLOAD_FOLDER
|
||||||
|
ETS2_DLC_ARCHIVE_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ets2_dlc_archives')
|
||||||
|
os.makedirs(ETS2_DLC_ARCHIVE_FOLDER, exist_ok=True)
|
||||||
running_bots = {}
|
running_bots = {}
|
||||||
|
ets2_dlc_build_locks = {}
|
||||||
|
ets2_dlc_build_locks_guard = threading.Lock()
|
||||||
class SuppressServerLoadFilter(logging.Filter):
|
class SuppressServerLoadFilter(logging.Filter):
|
||||||
def filter(self, record):
|
def filter(self, record):
|
||||||
msg = record.getMessage()
|
msg = record.getMessage()
|
||||||
|
|
@ -275,6 +278,156 @@ def add_log(action, details=None):
|
||||||
}
|
}
|
||||||
logs_collection.insert_one(log_entry)
|
logs_collection.insert_one(log_entry)
|
||||||
|
|
||||||
|
def _ets2_archive_filename(package_id: str, package_name: str):
|
||||||
|
safe_name = secure_filename(package_name or 'ets2_dlc_package') or 'ets2_dlc_package'
|
||||||
|
return f'{package_id}_{safe_name}.zip'
|
||||||
|
|
||||||
|
|
||||||
|
def _ets2_archive_path(package_id: str, package_name: str):
|
||||||
|
return os.path.join(ETS2_DLC_ARCHIVE_FOLDER, _ets2_archive_filename(package_id, package_name))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_ets2_build_lock(package_id: str):
|
||||||
|
with ets2_dlc_build_locks_guard:
|
||||||
|
lock = ets2_dlc_build_locks.get(package_id)
|
||||||
|
if lock is None:
|
||||||
|
lock = threading.Lock()
|
||||||
|
ets2_dlc_build_locks[package_id] = lock
|
||||||
|
return lock
|
||||||
|
|
||||||
|
|
||||||
|
def _set_ets2_archive_state(package_id: str, **fields):
|
||||||
|
if ets2_dlcs_collection is None:
|
||||||
|
return
|
||||||
|
ets2_dlcs_collection.update_one({'_id': ObjectId(package_id)}, {'$set': fields})
|
||||||
|
|
||||||
|
|
||||||
|
def _build_ets2_archive(package_id: str):
|
||||||
|
if ets2_dlcs_collection is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
package = ets2_dlcs_collection.find_one({'_id': ObjectId(package_id)})
|
||||||
|
if not package:
|
||||||
|
return
|
||||||
|
|
||||||
|
folder_path = package.get('folder_path')
|
||||||
|
if not folder_path or not os.path.isdir(folder_path):
|
||||||
|
_set_ets2_archive_state(
|
||||||
|
package_id,
|
||||||
|
archive_status='error',
|
||||||
|
archive_error='Ordnerpfad ist nicht mehr verfügbar.',
|
||||||
|
archive_generated_at=None,
|
||||||
|
archive_path=None
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
archive_path = _ets2_archive_path(package_id, package.get('name', 'ets2_dlc_package'))
|
||||||
|
temp_archive_path = f'{archive_path}.tmp'
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.exists(temp_archive_path):
|
||||||
|
try:
|
||||||
|
os.remove(temp_archive_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
_set_ets2_archive_state(
|
||||||
|
package_id,
|
||||||
|
archive_status='building',
|
||||||
|
archive_error=None,
|
||||||
|
archive_path=archive_path,
|
||||||
|
archive_generated_at=None
|
||||||
|
)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(temp_archive_path, 'w', compression=zipfile.ZIP_STORED, allowZip64=True) as zipf:
|
||||||
|
has_content = False
|
||||||
|
for root, _, files in os.walk(folder_path):
|
||||||
|
for filename in files:
|
||||||
|
file_path = os.path.join(root, filename)
|
||||||
|
arcname = os.path.relpath(file_path, folder_path)
|
||||||
|
zipf.write(file_path, arcname, compress_type=zipfile.ZIP_STORED)
|
||||||
|
has_content = True
|
||||||
|
|
||||||
|
if not has_content:
|
||||||
|
zipf.writestr('EMPTY_PACKAGE.txt', 'Dieses DLC-Paket enthaelt aktuell keine Dateien.')
|
||||||
|
|
||||||
|
os.replace(temp_archive_path, archive_path)
|
||||||
|
_set_ets2_archive_state(
|
||||||
|
package_id,
|
||||||
|
archive_status='ready',
|
||||||
|
archive_error=None,
|
||||||
|
archive_path=archive_path,
|
||||||
|
archive_generated_at=datetime.utcnow()
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
if os.path.exists(temp_archive_path):
|
||||||
|
os.remove(temp_archive_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
_set_ets2_archive_state(
|
||||||
|
package_id,
|
||||||
|
archive_status='error',
|
||||||
|
archive_error=str(e),
|
||||||
|
archive_generated_at=None,
|
||||||
|
archive_path=archive_path
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _schedule_ets2_archive_build(package_id: str):
|
||||||
|
lock = _get_ets2_build_lock(package_id)
|
||||||
|
if not lock.acquire(blocking=False):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def runner():
|
||||||
|
try:
|
||||||
|
_build_ets2_archive(package_id)
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
lock.release()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
with ets2_dlc_build_locks_guard:
|
||||||
|
ets2_dlc_build_locks.pop(package_id, None)
|
||||||
|
|
||||||
|
thread = threading.Thread(target=runner, daemon=True)
|
||||||
|
thread.start()
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _format_ets2_dlcs_for_view(packages):
|
||||||
|
for package in packages:
|
||||||
|
dlc_date = package.get('dlc_date')
|
||||||
|
try:
|
||||||
|
package['dlc_date_display'] = datetime.strptime(dlc_date, '%Y-%m-%d').strftime('%d.%m.%Y') if dlc_date else 'N/A'
|
||||||
|
except ValueError:
|
||||||
|
package['dlc_date_display'] = str(dlc_date) if dlc_date else 'N/A'
|
||||||
|
|
||||||
|
package_id = str(package['_id'])
|
||||||
|
archive_path = package.get('archive_path') or _ets2_archive_path(package_id, package.get('name', 'ets2_dlc_package'))
|
||||||
|
archive_ready = package.get('archive_status') == 'ready' and os.path.isfile(archive_path)
|
||||||
|
folder_path = package.get('folder_path')
|
||||||
|
|
||||||
|
if not archive_ready and folder_path and os.path.isdir(folder_path):
|
||||||
|
package.setdefault('archive_status', 'pending')
|
||||||
|
package['download_ready'] = False
|
||||||
|
package['archive_status_display'] = 'Wird erstellt'
|
||||||
|
package['archive_path'] = archive_path
|
||||||
|
_schedule_ets2_archive_build(package_id)
|
||||||
|
elif archive_ready:
|
||||||
|
package['download_ready'] = True
|
||||||
|
package['archive_status_display'] = 'Bereit'
|
||||||
|
package['archive_path'] = archive_path
|
||||||
|
else:
|
||||||
|
package['download_ready'] = False
|
||||||
|
package['archive_status_display'] = 'Fehler'
|
||||||
|
package['archive_path'] = archive_path
|
||||||
|
|
||||||
|
if package.get('archive_status') == 'error' and package.get('archive_error'):
|
||||||
|
package['archive_status_display'] = f"Fehler: {package.get('archive_error')}"
|
||||||
|
|
||||||
|
return packages
|
||||||
|
|
||||||
def get_user_permissions(user_id):
|
def get_user_permissions(user_id):
|
||||||
user = accounts_collection.find_one({'_id': ObjectId(user_id)})
|
user = accounts_collection.find_one({'_id': ObjectId(user_id)})
|
||||||
if not user or 'role_id' not in user:
|
if not user or 'role_id' not in user:
|
||||||
|
|
@ -997,13 +1150,7 @@ def ets2_dlcs():
|
||||||
flash("Datenbankverbindung nicht verfügbar.", "danger")
|
flash("Datenbankverbindung nicht verfügbar.", "danger")
|
||||||
return redirect(url_for('dashboard'))
|
return redirect(url_for('dashboard'))
|
||||||
|
|
||||||
packages = list(ets2_dlcs_collection.find().sort('created_at', -1))
|
packages = _format_ets2_dlcs_for_view(list(ets2_dlcs_collection.find().sort('created_at', -1)))
|
||||||
for package in packages:
|
|
||||||
dlc_date = package.get('dlc_date')
|
|
||||||
try:
|
|
||||||
package['dlc_date_display'] = datetime.strptime(dlc_date, '%Y-%m-%d').strftime('%d.%m.%Y') if dlc_date else 'N/A'
|
|
||||||
except ValueError:
|
|
||||||
package['dlc_date_display'] = str(dlc_date) if dlc_date else 'N/A'
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'ets2_dlcs.html',
|
'ets2_dlcs.html',
|
||||||
active_page='ets2_dlcs',
|
active_page='ets2_dlcs',
|
||||||
|
|
@ -1043,15 +1190,20 @@ def create_ets2_dlc_package():
|
||||||
flash("Ein DLC-Paket mit diesem Namen existiert bereits.", "danger")
|
flash("Ein DLC-Paket mit diesem Namen existiert bereits.", "danger")
|
||||||
return redirect(url_for('ets2_dlcs'))
|
return redirect(url_for('ets2_dlcs'))
|
||||||
|
|
||||||
ets2_dlcs_collection.insert_one({
|
package_id = ets2_dlcs_collection.insert_one({
|
||||||
'name': package_name,
|
'name': package_name,
|
||||||
'folder_path': folder_path,
|
'folder_path': folder_path,
|
||||||
'dlc_date': dlc_date,
|
'dlc_date': dlc_date,
|
||||||
'created_by': session.get('username'),
|
'created_by': session.get('username'),
|
||||||
'created_at': datetime.utcnow()
|
'created_at': datetime.utcnow(),
|
||||||
})
|
'archive_status': 'pending',
|
||||||
|
'archive_path': None,
|
||||||
|
'archive_generated_at': None,
|
||||||
|
'archive_error': None
|
||||||
|
}).inserted_id
|
||||||
add_log("ETS2 DLC-Paket erstellt", f"Name: {package_name}, Pfad: {folder_path}")
|
add_log("ETS2 DLC-Paket erstellt", f"Name: {package_name}, Pfad: {folder_path}")
|
||||||
flash("DLC-Paket wurde erfolgreich erstellt.", "success")
|
_schedule_ets2_archive_build(str(package_id))
|
||||||
|
flash("DLC-Paket wurde erstellt. Das Archiv wird im Hintergrund vorbereitet.", "success")
|
||||||
return redirect(url_for('ets2_dlcs'))
|
return redirect(url_for('ets2_dlcs'))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1074,6 +1226,13 @@ def delete_ets2_dlc_package(package_id):
|
||||||
flash("DLC-Paket nicht gefunden.", "danger")
|
flash("DLC-Paket nicht gefunden.", "danger")
|
||||||
return redirect(url_for('ets2_dlcs'))
|
return redirect(url_for('ets2_dlcs'))
|
||||||
|
|
||||||
|
archive_path = package.get('archive_path') or _ets2_archive_path(package_id, package.get('name', 'ets2_dlc_package'))
|
||||||
|
if package.get('archive_status') == 'ready' and os.path.isfile(archive_path):
|
||||||
|
try:
|
||||||
|
os.remove(archive_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
ets2_dlcs_collection.delete_one({'_id': package_object_id})
|
ets2_dlcs_collection.delete_one({'_id': package_object_id})
|
||||||
add_log("ETS2 DLC-Paket gelöscht", f"Name: {package.get('name', 'N/A')}")
|
add_log("ETS2 DLC-Paket gelöscht", f"Name: {package.get('name', 'N/A')}")
|
||||||
flash("DLC-Paket wurde gelöscht.", "success")
|
flash("DLC-Paket wurde gelöscht.", "success")
|
||||||
|
|
@ -1099,46 +1258,18 @@ def download_ets2_dlc_package(package_id):
|
||||||
flash("DLC-Paket nicht gefunden.", "danger")
|
flash("DLC-Paket nicht gefunden.", "danger")
|
||||||
return redirect(url_for('ets2_dlcs'))
|
return redirect(url_for('ets2_dlcs'))
|
||||||
|
|
||||||
folder_path = package.get('folder_path')
|
archive_path = package.get('archive_path') or _ets2_archive_path(package_id, package.get('name', 'ets2_dlc_package'))
|
||||||
if not folder_path or not os.path.isdir(folder_path):
|
if package.get('archive_status') != 'ready' or not os.path.isfile(archive_path):
|
||||||
flash("Der gespeicherte Ordnerpfad ist ungültig oder nicht mehr vorhanden.", "danger")
|
if package.get('folder_path') and os.path.isdir(package.get('folder_path')):
|
||||||
|
_schedule_ets2_archive_build(package_id)
|
||||||
|
flash("Das DLC-Archiv wird noch erstellt. Bitte in ein paar Augenblicken erneut versuchen.", "info")
|
||||||
|
else:
|
||||||
|
flash("Das gespeicherte Archiv ist nicht verfügbar.", "danger")
|
||||||
return redirect(url_for('ets2_dlcs'))
|
return redirect(url_for('ets2_dlcs'))
|
||||||
|
|
||||||
temp_zip = tempfile.NamedTemporaryFile(delete=False, suffix='.zip')
|
|
||||||
temp_zip_path = temp_zip.name
|
|
||||||
temp_zip.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
with zipfile.ZipFile(temp_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
|
||||||
has_content = False
|
|
||||||
for root, _, files in os.walk(folder_path):
|
|
||||||
for filename in files:
|
|
||||||
has_content = True
|
|
||||||
file_path = os.path.join(root, filename)
|
|
||||||
arcname = os.path.relpath(file_path, folder_path)
|
|
||||||
zipf.write(file_path, arcname)
|
|
||||||
|
|
||||||
if not has_content:
|
|
||||||
zipf.writestr('EMPTY_PACKAGE.txt', 'Dieses DLC-Paket enthaelt aktuell keine Dateien.')
|
|
||||||
except Exception as e:
|
|
||||||
try:
|
|
||||||
os.remove(temp_zip_path)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
flash(f"Fehler beim Erstellen des Downloads: {e}", "danger")
|
|
||||||
return redirect(url_for('ets2_dlcs'))
|
|
||||||
|
|
||||||
@after_this_request
|
|
||||||
def cleanup_temp_file(response):
|
|
||||||
try:
|
|
||||||
os.remove(temp_zip_path)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return response
|
|
||||||
|
|
||||||
safe_name = secure_filename(package.get('name', 'ets2_dlc_package')) or 'ets2_dlc_package'
|
safe_name = secure_filename(package.get('name', 'ets2_dlc_package')) or 'ets2_dlc_package'
|
||||||
add_log("ETS2 DLC-Paket heruntergeladen", f"Name: {package.get('name', 'N/A')}")
|
add_log("ETS2 DLC-Paket heruntergeladen", f"Name: {package.get('name', 'N/A')}")
|
||||||
return send_file(temp_zip_path, as_attachment=True, download_name=f"{safe_name}.zip")
|
return send_file(archive_path, as_attachment=True, download_name=f"{safe_name}.zip", conditional=True)
|
||||||
|
|
||||||
def stream_bot_output(bot_id, process):
|
def stream_bot_output(bot_id, process):
|
||||||
def stream_to_socket(pipe, log_type):
|
def stream_to_socket(pipe, log_type):
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue