implement sharing in gui
This commit is contained in:
parent
77b9221320
commit
fef89666df
55
app.py
55
app.py
@ -25,6 +25,9 @@ import analytics as a
|
|||||||
with open("app_config.json", 'r') as file:
|
with open("app_config.json", 'r') as file:
|
||||||
app_config = json.load(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_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_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)
|
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()
|
content = f.read()
|
||||||
return content, 200, {'Content-Type': 'text/markdown; charset=utf-8'}
|
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():
|
def query_recent_connections():
|
||||||
global clients_connected, background_thread_running
|
global clients_connected, background_thread_running
|
||||||
background_thread_running = True
|
background_thread_running = True
|
||||||
@ -476,9 +525,13 @@ def handle_request_initial_data():
|
|||||||
def index(path):
|
def index(path):
|
||||||
title_short = app_config.get('TITLE_SHORT', 'Default Title')
|
title_short = app_config.get('TITLE_SHORT', 'Default Title')
|
||||||
title_long = app_config.get('TITLE_LONG' , 'Default Title')
|
title_long = app_config.get('TITLE_LONG' , 'Default Title')
|
||||||
|
if 'admin' in session:
|
||||||
|
admin_enabled = session['admin']
|
||||||
|
|
||||||
return render_template("app.html",
|
return render_template("app.html",
|
||||||
title_short=title_short,
|
title_short=title_short,
|
||||||
title_long=title_long
|
title_long=title_long,
|
||||||
|
admin_enabled=admin_enabled,
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
9
auth.py
9
auth.py
@ -99,6 +99,15 @@ def require_secret(f):
|
|||||||
for folder_info in token_item['folders']:
|
for folder_info in token_item['folders']:
|
||||||
session['folders'][folder_info['foldername']] = folder_info['folderpath']
|
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
|
# 6) If we have folders, proceed; otherwise show index
|
||||||
if session['folders']:
|
if session['folders']:
|
||||||
# assume since visitor has a valid secret, they are ok with annonymous tracking
|
# assume since visitor has a valid secret, they are ok with annonymous tracking
|
||||||
|
|||||||
@ -10,6 +10,7 @@ html, body {
|
|||||||
body {
|
body {
|
||||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||||
padding-top: 70px; /* Adjust to your header height */
|
padding-top: 70px; /* Adjust to your header height */
|
||||||
|
overflow-x: hidden; /* Prevent horizontal scroll */
|
||||||
}
|
}
|
||||||
/* Header styles */
|
/* Header styles */
|
||||||
.site-header {
|
.site-header {
|
||||||
@ -17,7 +18,7 @@ body {
|
|||||||
color: var(--header-text-color);
|
color: var(--header-text-color);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
width: 94%;
|
width: 100%;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -138,6 +139,16 @@ a.show-transcript:hover {
|
|||||||
color: rgb(113, 146, 167);
|
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 {
|
.currently-playing {
|
||||||
background-color: var(--selected-background);
|
background-color: var(--selected-background);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,19 +74,26 @@ function renderContent(data) {
|
|||||||
});
|
});
|
||||||
contentHTML += '</div>';
|
contentHTML += '</div>';
|
||||||
} else {
|
} else {
|
||||||
|
share_link = '';
|
||||||
// Render directories normally
|
// Render directories normally
|
||||||
if (data.directories.length > 0) {
|
if (data.directories.length > 0) {
|
||||||
const areAllShort = data.directories.every(dir => dir.name.length <= 15) && data.files.length === 0;
|
const areAllShort = data.directories.every(dir => dir.name.length <= 15) && data.files.length === 0;
|
||||||
if (areAllShort && data.breadcrumbs.length !== 1) {
|
if (areAllShort && data.breadcrumbs.length !== 1) {
|
||||||
contentHTML += '<div class="directories-grid">';
|
contentHTML += '<div class="directories-grid">';
|
||||||
data.directories.forEach(dir => {
|
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>';
|
contentHTML += '</div>';
|
||||||
} else {
|
} else {
|
||||||
contentHTML += '<ul>';
|
contentHTML += '<ul>';
|
||||||
data.directories.forEach(dir => {
|
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) {
|
if (data.breadcrumbs.length === 1) {
|
||||||
contentHTML += `<li class="link-item" onclick="window.location.href='/search'">🔎 <a href="/search" class="link-link">Suche</a></li>`;
|
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}"` : '';
|
const indexAttr = file.file_type === 'music' ? ` data-index="${currentMusicFiles.length - 1}"` : '';
|
||||||
contentHTML += `<li class="file-item">
|
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>`;
|
<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">📄</a>`;
|
contentHTML += `<a href="#" class="show-transcript" data-url="${file.transcript_url}" title="Show Transcript">📄</a>`;
|
||||||
}
|
}
|
||||||
contentHTML += `</li>`;
|
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.
|
// Modal close logic for transcript modal.
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
<link rel="stylesheet" href="{{ url_for('static', filename='gallery.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='gallery.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='audioplayer.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='audioplayer.css') }}">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
|
<script> const admin_enabled = {{ admin_enabled | tojson | safe }}; </script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class="site-header">
|
<header class="site-header">
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
<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">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='theme.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='theme.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='app.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>
|
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -20,7 +21,7 @@
|
|||||||
</header>
|
</header>
|
||||||
|
|
||||||
<div class="container">
|
<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>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user