192 lines
8.7 KiB
HTML
Raw Permalink Normal View History

2025-07-15 11:43:28 +01:00
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
2025-07-18 13:20:44 +01:00
<meta name="viewport" content="width=device-width, initial-scale=1.0">
2025-07-15 11:43:28 +01:00
<title>{% block title %}KTVManager{% endblock %}</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="icon" type="image/png" href="{{ url_for('static', filename='favicon-96x96.png') }}" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="{{ url_for('static', filename='favicon.svg') }}" />
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" />
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='apple-touch-icon.png') }}" />
<meta name="apple-mobile-web-app-title" content="kTvManager" />
<link rel="manifest" href="{{ url_for('static', filename='site.webmanifest') }}?v={{ version }}" />
2025-07-18 13:47:26 +01:00
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}?v={{ version }}" />
2025-07-15 11:43:28 +01:00
{% block head_content %}{% endblock %}
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="/">KTVManager</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/accounts">Accounts</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/urls">URLs</a>
</li>
</ul>
</div>
</nav>
{% block sub_nav %}{% endblock %}
<!-- Main Content -->
<main class="container mt-5">
{% block content %}{% endblock %}
</main>
<footer class="bg-dark text-white text-center py-3 mt-5">
2025-07-19 08:56:13 +01:00
<p>Version: <a href="{{ url_for('config') }}" style="color: inherit; text-decoration: none;">{{ version }}</a></p>
2025-07-15 11:43:28 +01:00
</footer>
2025-07-18 17:33:26 +01:00
<input type="hidden" id="is-logged-in" value="{{ 'true' if session.get('logged_in') else 'false' }}">
2025-07-15 15:13:16 +01:00
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
2025-07-15 11:43:28 +01:00
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
{% block scripts %}{% endblock %}
2025-07-17 10:32:06 +01:00
<script>
2025-07-17 15:41:16 +01:00
if ('serviceWorker' in navigator && 'PushManager' in window) {
2025-07-18 17:33:26 +01:00
const isLoggedIn = document.getElementById('is-logged-in').value === 'true';
2025-07-17 17:08:11 +01:00
navigator.serviceWorker.register('{{ url_for("static", filename="service-worker.js") }}').then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
2025-07-18 17:36:25 +01:00
const enableNotificationsBtn = document.getElementById('enable-notifications-btn');
function setupNotificationButton() {
registration.pushManager.getSubscription().then(function(subscription) {
if (enableNotificationsBtn) {
if (subscription) {
enableNotificationsBtn.style.display = 'none';
} else {
enableNotificationsBtn.style.display = 'block';
enableNotificationsBtn.addEventListener('click', function() {
askPermission(registration);
});
}
}
});
}
if (enableNotificationsBtn) {
setupNotificationButton();
2025-07-17 18:13:10 +01:00
}
2025-07-17 17:08:11 +01:00
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
2025-07-19 11:56:17 +01:00
const forceResubscribeBtn = document.getElementById('force-resubscribe-btn');
if (forceResubscribeBtn) {
forceResubscribeBtn.addEventListener('click', function() {
navigator.serviceWorker.ready.then(function(registration) {
registration.pushManager.getSubscription().then(function(subscription) {
if (subscription) {
subscription.unsubscribe().then(function(successful) {
if (successful) {
console.log('Unsubscribed successfully.');
askPermission(registration);
} else {
console.log('Unsubscribe failed.');
}
});
} else {
askPermission(registration);
}
});
});
});
}
2025-07-17 15:41:16 +01:00
}
function askPermission(registration) {
Notification.requestPermission().then(function(result) {
if (result === 'granted') {
subscribeUser(registration);
}
});
}
function subscribeUser(registration) {
2025-07-17 16:50:08 +01:00
fetch('/vapid-public-key')
.then(response => {
if (!response.ok) {
2025-07-18 17:19:14 +01:00
return response.text().then(text => {
console.error('Failed to fetch VAPID public key. Server response:', text);
throw new Error('Failed to fetch VAPID public key. See server response in logs.');
});
2025-07-17 16:50:08 +01:00
}
return response.json();
})
2025-07-17 16:22:56 +01:00
.then(data => {
2025-07-17 17:19:21 +01:00
console.log('Received VAPID public key:', data.public_key);
2025-07-17 16:22:56 +01:00
const applicationServerKey = urlB64ToUint8Array(data.public_key);
registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
}).then(function(subscription) {
console.log('User is subscribed.');
saveSubscription(subscription);
}).catch(function(err) {
console.log('Failed to subscribe the user: ', err);
});
2025-07-17 16:43:07 +01:00
}).catch(function(err) {
2025-07-17 16:50:08 +01:00
console.error('Error during subscription process:', err);
2025-07-17 16:22:56 +01:00
});
2025-07-17 15:41:16 +01:00
}
function saveSubscription(subscription) {
2025-07-18 16:58:42 +01:00
console.log('Attempting to save subscription...');
2025-07-17 16:50:08 +01:00
fetch('/save-subscription', {
2025-07-17 15:41:16 +01:00
method: 'POST',
headers: {
2025-07-18 16:58:42 +01:00
'Content-Type': 'application/json'
2025-07-17 15:41:16 +01:00
},
body: JSON.stringify(subscription)
2025-07-18 16:58:42 +01:00
})
.then(response => {
if (response.ok) {
console.log('Subscription saved successfully.');
2025-07-18 17:36:25 +01:00
const enableNotificationsBtn = document.getElementById('enable-notifications-btn');
if (enableNotificationsBtn) {
enableNotificationsBtn.style.display = 'none';
}
2025-07-18 16:58:42 +01:00
return response.json();
} else {
console.error('Failed to save subscription. Status:', response.status);
response.text().then(text => console.error('Server response:', text));
throw new Error('Failed to save subscription.');
}
})
.then(data => {
console.log('Server response on save:', data);
})
.catch(err => {
console.error('Error during saveSubscription fetch:', err);
2025-07-17 15:41:16 +01:00
});
}
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
2025-07-17 10:32:06 +01:00
}
</script>
2025-07-15 11:43:28 +01:00
</body>
</html>