Merge branch 'development' of gitea.centx.de:lelo/bethaus-app into development

This commit is contained in:
lelo 2025-06-08 19:25:43 +02:00
commit d13b0f92c3
4 changed files with 72 additions and 31 deletions

27
app.py
View File

@ -24,6 +24,7 @@ import auth
import analytics as a import analytics as a
import folder_secret_config_editor as fsce import folder_secret_config_editor as fsce
import helperfunctions as hf import helperfunctions as hf
import fnmatch
app_config = auth.return_app_config() app_config = auth.return_app_config()
BASE_DIR = os.path.realpath(app_config['BASE_DIR']) BASE_DIR = os.path.realpath(app_config['BASE_DIR'])
@ -136,7 +137,7 @@ def list_directory_contents(directory, subpath):
music_exts = ('.mp3',) music_exts = ('.mp3',)
image_exts = ('.jpg', '.jpeg', '.png', '.gif', '.bmp') image_exts = ('.jpg', '.jpeg', '.png', '.gif', '.bmp')
blocked_filenames = ['Thumbs.db'] blocked_filenames = ['Thumbs.db', '*.mrk']
try: try:
with os.scandir(directory) as it: with os.scandir(directory) as it:
@ -146,12 +147,12 @@ def list_directory_contents(directory, subpath):
if entry.name.startswith('.'): if entry.name.startswith('.'):
continue continue
# Skip blocked_filenames # Skip blocked_filenames using fnmatch for wildcards
if entry.name in blocked_filenames: if any(fnmatch.fnmatch(entry.name, pattern) for pattern in blocked_filenames):
continue continue
if entry.is_dir(follow_symlinks=False): if entry.is_dir(follow_symlinks=False):
if entry.name in ["Transkription", "@eaDir"]: if entry.name in ["Transkription", "@eaDir", ".ai"]:
continue continue
rel_path = os.path.join(subpath, entry.name) if subpath else entry.name rel_path = os.path.join(subpath, entry.name) if subpath else entry.name
@ -238,6 +239,7 @@ def custom_logo(filename):
response.headers['Cache-Control'] = 'public, max-age=86400' response.headers['Cache-Control'] = 'public, max-age=86400'
return response return response
@app.route('/sw.js') @app.route('/sw.js')
def serve_sw(): def serve_sw():
return send_from_directory(os.path.join(app.root_path, 'static'), 'sw.js', mimetype='application/javascript') return send_from_directory(os.path.join(app.root_path, 'static'), 'sw.js', mimetype='application/javascript')
@ -472,16 +474,29 @@ def serve_file(subpath):
filesize = os.path.getsize(file_path) filesize = os.path.getsize(file_path)
filename = os.path.basename(full_path) filename = os.path.basename(full_path)
if as_attachment:
download_name = filename
mimetype = 'application/octet-stream'
else:
download_name = None
mimetype = mime
# Single send_file call with proper attachment handling # Single send_file call with proper attachment handling
response = send_file( response = send_file(
file_path, file_path,
mimetype=mime, mimetype=mimetype,
conditional=True, conditional=True,
as_attachment=as_attachment, as_attachment=as_attachment,
download_name=filename if as_attachment else None download_name=filename if as_attachment else None
) )
if not as_attachment:
if as_attachment:
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['Content-Disposition'] = 'attachment'
else:
response.headers['Content-Disposition'] = 'inline' response.headers['Content-Disposition'] = 'inline'
response.headers['Cache-Control'] = 'public, max-age=86400' response.headers['Cache-Control'] = 'public, max-age=86400'
# 7) Logging # 7) Logging

View File

@ -54,8 +54,10 @@ def extract_date_from_string(string_with_date):
def extract_structure_from_string(input_string): def extract_structure_from_string(input_string):
# extract category and titel from filename # extract category and titel from filename
filename_ext = os.path.splitext(input_string)[0] filepathname_ext = os.path.splitext(input_string)[0] # remove file extension
filename_ext = os.path.basename(filepathname_ext) # get only the filename
left_side, right_side = filename_ext.split('-', 1) if '-' in filename_ext else (filename_ext, None) left_side, right_side = filename_ext.split('-', 1) if '-' in filename_ext else (filename_ext, None)
try: try:
int(left_side.strip()) int(left_side.strip())
# first part is only a number # first part is only a number
@ -65,9 +67,9 @@ def extract_structure_from_string(input_string):
# first part not a number # first part not a number
pass pass
if 'predig' in left_side.lower(): if 'predig' in left_side.lower() or 'thema' in left_side.lower():
category = 'Predigt' category = 'Predigt'
elif 'wort' in left_side.lower() or 'einladung' in left_side.lower() or 'begrüßung' in left_side.lower() or 'ansprache' in left_side.lower() or 'einleitung' in left_side.lower(): elif 'wort' in left_side.lower() or 'einladung' in left_side.lower() or 'begrüßung' in left_side.lower() or 'ansprache' in left_side.lower() or 'einleitung' in left_side.lower() or 'aufruf zum' in left_side.lower() or 'zuruf zum' in left_side.lower():
category = 'Vorwort' category = 'Vorwort'
elif 'kinderchor' in left_side.lower(): elif 'kinderchor' in left_side.lower():
category = 'Kinderchor' category = 'Kinderchor'

View File

@ -1,30 +1,56 @@
const cacheName = 'gottesdienste-v1.11'; const VERSION = '1.19';
const CACHE_NAME = `gottesdienste-v${VERSION}`;
const assets = [ const assets = [
'/', '/',
'/static/app.css', `/static/app.css?v=${VERSION}`,
'/static/app.js', `/static/app.js?v=${VERSION}`,
'/static/gallery.css', `/static/gallery.css?v=${VERSION}`,
'/static/gallery.js', `/static/gallery.js?v=${VERSION}`,
'/static/audioplayer.css', `/static/audioplayer.css?v=${VERSION}`,
'/static/audioplayer.js', `/static/audioplayer.js?v=${VERSION}`,
'/icon/logo-192x192.png', '/icon/logo-192x192.png',
'/icon/logo-300x300.png',
'/icon/logo-512x512.png', '/icon/logo-512x512.png',
'/custom_logo/logoB.png', '/custom_logo/logoB.png',
'/custom_logo/logoW.png' '/custom_logo/logoW.png'
]; ];
self.addEventListener('install', e => { self.addEventListener('install', evt => {
e.waitUntil( self.skipWaiting();
caches.open(cacheName).then(cache => { evt.waitUntil(
return cache.addAll(assets); caches.open(CACHE_NAME)
.then(cache => cache.addAll(assets))
);
});
self.addEventListener('activate', evt => {
self.clients.claim();
evt.waitUntil(
caches.keys().then(keys =>
Promise.all(
keys
.filter(k => k !== CACHE_NAME)
.map(k => caches.delete(k))
)
)
.then(() => {
// Reload to use new files
return self.clients.matchAll({ type: 'window' })
.then(clients =>
clients.forEach(client => client.navigate(client.url))
);
}) })
); );
}); });
self.addEventListener('fetch', e => { self.addEventListener('fetch', evt => {
e.respondWith( if (evt.request.mode === 'navigate') {
caches.match(e.request).then(response => { evt.respondWith(
return response || fetch(e.request); fetch(evt.request).catch(() => caches.match('/app.html'))
}) );
return;
}
evt.respondWith(
caches.match(evt.request).then(cached => cached || fetch(evt.request))
); );
}); });

View File

@ -8,7 +8,7 @@
<meta property="og:title" content="{{ title_long }}" /> <meta property="og:title" content="{{ title_long }}" />
<meta property="og:description" content="... uns aber, die wir gerettet werden, ist es eine Gotteskraft." /> <meta property="og:description" content="... uns aber, die wir gerettet werden, ist es eine Gotteskraft." />
<meta property="og:image" content="/icon/logo-200x200.png" /> <meta property="og:image" content="/icon/logo-192x192.png" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="description" content="... uns aber, die wir gerettet werden, ist es eine Gotteskraft."> <meta name="description" content="... uns aber, die wir gerettet werden, ist es eine Gotteskraft.">
@ -23,7 +23,7 @@
<meta name="theme-color" content="#000"> <meta name="theme-color" content="#000">
<!-- Apple-specific tags --> <!-- Apple-specific tags -->
<link rel="touch-icon" href="{{ url_for('static', filename='icons/icon-192x192.png') }}"> <link rel="touch-icon" href="/icon/logo-192x192.png">
<meta name="mobile-web-app-capable" content="yes"> <meta name="mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-status-bar-style" content="default"> <meta name="mobile-web-app-status-bar-style" content="default">
<meta name="mobile-web-app-title" content="Gottesdienste"> <meta name="mobile-web-app-title" content="Gottesdienste">
@ -253,8 +253,6 @@
if ('serviceWorker' in navigator) { if ('serviceWorker' in navigator) {
window.addEventListener('load', () => { window.addEventListener('load', () => {
navigator.serviceWorker.register('{{ url_for("static", filename="sw.js") }}') navigator.serviceWorker.register('{{ url_for("static", filename="sw.js") }}')
.then(reg => console.log('Service worker registered.', reg))
.catch(err => console.error('Service worker not registered.', err));
}); });
} }
</script> </script>