Implements update notifications by fetching the latest version from a remote source. Displays a warning message on the home and setup pages if the current version is outdated. The update check is performed on application startup.
236 lines
5.7 KiB
HTML
236 lines
5.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>qBittorrent Setup</title>
|
|
<style>
|
|
body {
|
|
background: #121212;
|
|
font-family: 'Segoe UI', sans-serif;
|
|
color: #eee;
|
|
margin: 0;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
height: 100vh;
|
|
}
|
|
|
|
.card {
|
|
background: #1e1e1e;
|
|
padding: 2rem 2.5rem;
|
|
border-radius: 10px;
|
|
box-shadow: 0 0 25px rgba(0, 0, 0, 0.6);
|
|
max-width: 420px;
|
|
width: 100%;
|
|
}
|
|
|
|
h2 {
|
|
margin-top: 0;
|
|
font-weight: 500;
|
|
color: #ffffff;
|
|
text-align: center;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
margin-top: 1.2rem;
|
|
font-size: 0.9rem;
|
|
color: #bbb;
|
|
}
|
|
|
|
input {
|
|
width: 100%;
|
|
padding: 0.55rem;
|
|
margin-top: 0.3rem;
|
|
background: #2c2c2c;
|
|
color: #eee;
|
|
border: 1px solid #444;
|
|
border-radius: 5px;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
button {
|
|
padding: 0.6rem 1.2rem;
|
|
border: none;
|
|
background: #00bcd4;
|
|
color: #000;
|
|
font-weight: bold;
|
|
border-radius: 5px;
|
|
cursor: pointer;
|
|
font-size: 0.95rem;
|
|
transition: background 0.2s ease;
|
|
margin-top: 1.5rem;
|
|
}
|
|
|
|
button:hover {
|
|
background: #0097a7;
|
|
}
|
|
|
|
button:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.button-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.spinner {
|
|
border: 3px solid #eee;
|
|
border-top: 3px solid transparent;
|
|
border-radius: 50%;
|
|
width: 16px;
|
|
height: 16px;
|
|
animation: spin 0.8s linear infinite;
|
|
display: inline-block;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
@keyframes spin {
|
|
to { transform: rotate(360deg); }
|
|
}
|
|
|
|
.result-box {
|
|
margin-top: 1rem;
|
|
padding: 1rem;
|
|
background: #252525;
|
|
border-radius: 8px;
|
|
border: 1px solid #444;
|
|
display: none;
|
|
}
|
|
|
|
.success .checkmark {
|
|
color: #00e676;
|
|
font-size: 1.6rem;
|
|
margin-right: 10px;
|
|
transform: scale(0);
|
|
animation: pop 0.4s forwards;
|
|
}
|
|
|
|
.error .checkmark {
|
|
color: #ff1744;
|
|
font-size: 1.6rem;
|
|
margin-right: 10px;
|
|
transform: scale(0);
|
|
animation: pop 0.4s forwards;
|
|
}
|
|
|
|
@keyframes pop {
|
|
to { transform: scale(1); }
|
|
}
|
|
|
|
.info {
|
|
margin-top: 0.4rem;
|
|
color: #ccc;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.warning {
|
|
background: #2a1b1b;
|
|
color: #ff6f61;
|
|
padding: 0.75rem 1rem;
|
|
margin-top: 1rem;
|
|
border-left: 4px solid #ff6f61;
|
|
border-radius: 6px;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.warning strong {
|
|
color: #ffab91;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="card">
|
|
<h2>qBittorrent Setup</h2>
|
|
{% if outdated %}
|
|
<div class="warning">
|
|
<strong>Outdated:</strong> You are running version <b>{{ current_version }}</b>. The latest is <b>{{ latest_version }}</b>.
|
|
</div>
|
|
{% endif %}
|
|
<form method="POST">
|
|
<label>Web UI URL:</label>
|
|
<input name="url" required value="http://192.168.0.236:8080/">
|
|
|
|
<label>Username:</label>
|
|
<input name="username" required value="admin">
|
|
|
|
<label>Password:</label>
|
|
<input name="password" type="password" required value="123456">
|
|
|
|
<div class="button-row">
|
|
<button type="submit">Save & Start</button>
|
|
<button id="testBtn" type="button" onclick="testConnection()">Test</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="result-box" id="test-result-box">
|
|
<span class="checkmark">✔</span>
|
|
<span id="test-message"></span>
|
|
<div class="info" id="test-info"></div>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
<script>
|
|
|
|
function testConnection() {
|
|
const url = document.querySelector('input[name="url"]').value;
|
|
const username = document.querySelector('input[name="username"]').value;
|
|
const password = document.querySelector('input[name="password"]').value;
|
|
|
|
const box = document.getElementById('test-result-box');
|
|
const msg = document.getElementById('test-message');
|
|
const info = document.getElementById('test-info');
|
|
const checkmark = document.querySelector('.checkmark');
|
|
const testBtn = document.getElementById('testBtn');
|
|
const outdated = document.getElementById('outdated-warning');
|
|
const currVer = document.getElementById('current-version');
|
|
const latestVer = document.getElementById('latest-version');
|
|
|
|
testBtn.disabled = true;
|
|
testBtn.innerHTML = '<span class="spinner"></span>';
|
|
|
|
box.style.display = 'block';
|
|
box.className = 'result-box';
|
|
msg.innerText = '';
|
|
checkmark.textContent = '';
|
|
info.innerText = '';
|
|
outdated.style.display = 'none';
|
|
|
|
fetch('/test-connection', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ url, username, password })
|
|
}).then(res => res.json()).then(data => {
|
|
testBtn.disabled = false;
|
|
testBtn.innerText = 'Test';
|
|
|
|
if (data.success) {
|
|
box.className = 'result-box success';
|
|
checkmark.textContent = '✔';
|
|
msg.innerText = 'Connected successfully!';
|
|
info.innerHTML = `Version: <b>${data.version}</b><br>Port: <b>${new URL(url).port || '8080'}</b>`;
|
|
|
|
} else {
|
|
box.className = 'result-box error';
|
|
checkmark.textContent = '✖';
|
|
msg.innerText = 'Connection failed.';
|
|
info.innerText = `Error: ${data.error}`;
|
|
}
|
|
}).catch(err => {
|
|
testBtn.disabled = false;
|
|
testBtn.innerText = 'Test';
|
|
box.className = 'result-box error';
|
|
checkmark.textContent = '✖';
|
|
msg.innerText = 'Connection failed.';
|
|
info.innerText = `Error: ${err}`;
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|