implement sharing in gui

This commit is contained in:
lelo 2025-05-01 19:04:18 +02:00
parent 77b9221320
commit fef89666df
6 changed files with 114 additions and 6 deletions

55
app.py
View File

@ -25,6 +25,9 @@ import analytics as a
with open("app_config.json", 'r') as file:
app_config = json.load(file)
with open('folder_permission_config.json') as file:
folder_config = json.load(file)
cache_audio = diskcache.Cache('./filecache_audio', size_limit= app_config['filecache_size_limit_audio'] * 1024**3)
cache_image = diskcache.Cache('./filecache_image', size_limit= app_config['filecache_size_limit_image'] * 1024**3)
cache_video = diskcache.Cache('./filecache_video', size_limit= app_config['filecache_size_limit_video'] * 1024**3)
@ -407,6 +410,52 @@ def get_transcript(subpath):
content = f.read()
return content, 200, {'Content-Type': 'text/markdown; charset=utf-8'}
@app.route("/create_share/<path:subpath>")
@auth.require_secret
def create_share(subpath):
scheme = request.scheme # current scheme (http or https)
if 'admin ' not in session and not session.get('admin'):
return "Unauthorized", 403
paths = {}
for item in folder_config:
for folder in item['folders']:
paths[folder['foldername']] = folder['folderpath']
# use folder config file and ignore validity to get full path
root, *relative_parts = subpath.split('/')
base_path = paths[root]
full_path = os.path.join(base_path, *relative_parts)
foldername = relative_parts[-1]
validity_date = (datetime.now() + timedelta(days=90)).strftime('%d.%m.%Y')
data = {
"validity": validity_date,
"folders": [
{
"foldername": foldername,
"folderpath": full_path
}
]
}
print (data)
token = auth.generate_secret_key_compressed(data)
content = f"""Ordner:\\
{foldername}\\
\\
Gültig bis:\\
{validity_date}\\
\\
Link:\\
`{scheme}://{request.host}?token={token}`"""
return content, 200, {'Content-Type': 'text/markdown; charset=utf-8'}
def query_recent_connections():
global clients_connected, background_thread_running
background_thread_running = True
@ -476,9 +525,13 @@ def handle_request_initial_data():
def index(path):
title_short = app_config.get('TITLE_SHORT', 'Default Title')
title_long = app_config.get('TITLE_LONG' , 'Default Title')
if 'admin' in session:
admin_enabled = session['admin']
return render_template("app.html",
title_short=title_short,
title_long=title_long
title_long=title_long,
admin_enabled=admin_enabled,
)
if __name__ == '__main__':

View File

@ -99,6 +99,15 @@ def require_secret(f):
for folder_info in token_item['folders']:
session['folders'][folder_info['foldername']] = folder_info['folderpath']
args_admin = request.args.get('admin', None)
config_admin = app_config.get('ADMIN_KEY', None)
if args_admin and config_admin:
if args_admin == config_admin:
session['admin'] = True
else:
session['admin'] = False
# 6) If we have folders, proceed; otherwise show index
if session['folders']:
# assume since visitor has a valid secret, they are ok with annonymous tracking

View File

@ -10,6 +10,7 @@ html, body {
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
padding-top: 70px; /* Adjust to your header height */
overflow-x: hidden; /* Prevent horizontal scroll */
}
/* Header styles */
.site-header {
@ -17,7 +18,7 @@ body {
color: var(--header-text-color);
position: fixed;
top: 0;
width: 94%;
width: 100%;
z-index: 1000;
display: flex;
align-items: center;
@ -138,6 +139,16 @@ a.show-transcript:hover {
color: rgb(113, 146, 167);
}
a.create-share {
text-decoration: none;
color: var(--main-text-color);
font-size: 20px;
margin-left: 10px;
}
a.create-share:hover {
color: rgb(113, 146, 167);
}
.currently-playing {
background-color: var(--selected-background);
}

View File

@ -74,19 +74,26 @@ function renderContent(data) {
});
contentHTML += '</div>';
} else {
share_link = '';
// Render directories normally
if (data.directories.length > 0) {
const areAllShort = data.directories.every(dir => dir.name.length <= 15) && data.files.length === 0;
if (areAllShort && data.breadcrumbs.length !== 1) {
contentHTML += '<div class="directories-grid">';
data.directories.forEach(dir => {
contentHTML += `<div class="directory-item">📁 <a href="#" class="directory-link" data-path="${dir.path}">${dir.name}</a></div>`;
if (admin_enabled && data.breadcrumbs.length != 1) {
share_link = `<a href="#" class="create-share" data-url="${dir.path}">🌐</a>`;
}
contentHTML += `<div class="directory-item">📁 <a href="#" class="directory-link" data-path="${dir.path}">${dir.name}</a>${share_link}</div>`;
});
contentHTML += '</div>';
} else {
contentHTML += '<ul>';
data.directories.forEach(dir => {
contentHTML += `<li class="directory-item">📁 <a href="#" class="directory-link" data-path="${dir.path}">${dir.name}</a></li>`;
if (admin_enabled && data.breadcrumbs.length != 1) {
share_link = `<a href="#" class="create-share" data-url="${dir.path}">🌐</a>`;
}
contentHTML += `<li class="directory-item">📁 <a href="#" class="directory-link" data-path="${dir.path}">${dir.name}</a>${share_link}</li>`;
});
if (data.breadcrumbs.length === 1) {
contentHTML += `<li class="link-item" onclick="window.location.href='/search'">🔎 <a href="/search" class="link-link">Suche</a></li>`;
@ -110,7 +117,7 @@ function renderContent(data) {
const indexAttr = file.file_type === 'music' ? ` data-index="${currentMusicFiles.length - 1}"` : '';
contentHTML += `<li class="file-item">
<a href="#" class="play-file"${indexAttr} data-url="${file.path}" data-file-type="${file.file_type}">${symbol} ${file.name.replace('.mp3', '')}</a>`;
if (file.has_transcript) {
if (file.has_transcript && admin_enabled) {
contentHTML += `<a href="#" class="show-transcript" data-url="${file.transcript_url}" title="Show Transcript">&#128196;</a>`;
}
contentHTML += `</li>`;
@ -362,6 +369,32 @@ document.querySelectorAll('.play-file').forEach(link => {
});
});
});
// create share icon clicks.
document.querySelectorAll('.create-share').forEach(link => {
link.addEventListener('click', function (event) {
event.preventDefault();
const url = '/create_share/' + this.getAttribute('data-url');
console.log(url);
fetch(url)
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then(data => {
console.log(data);
document.getElementById('transcriptContent').innerHTML = marked.parse(data);
document.getElementById('transcriptModal').style.display = 'block';
})
.catch(error => {
console.error('Error creating share:', error);
document.getElementById('transcriptContent').innerHTML = "<p>You can't share this.</p>";
document.getElementById('transcriptModal').style.display = 'block';
});
});
});
}
// Modal close logic for transcript modal.

View File

@ -32,6 +32,7 @@
<link rel="stylesheet" href="{{ url_for('static', filename='gallery.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='audioplayer.css') }}">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script> const admin_enabled = {{ admin_enabled | tojson | safe }}; </script>
</head>
<body>
<header class="site-header">

View File

@ -11,6 +11,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="{{ url_for('static', filename='theme.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='app.css') }}">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
</head>
<body>
@ -20,7 +21,7 @@
</header>
<div class="container">
<div id="content">Du hast keine Links die noch gültig sind.<br>Bitte den Freigabelink erneut anklicken.</div>
<div class="alert alert-warning">Du hast keine Links die noch gültig sind.<br>Bitte den Freigabelink erneut anklicken.</div>
</div>
</body>
</html>