Compare commits
18 Commits
c27377cd60
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 69e7e66823 | |||
| 39917b7351 | |||
| 13d9cc9dc9 | |||
| db5a88972b | |||
| 98eb031c1c | |||
| 68a044a679 | |||
| ab84dea518 | |||
| 25617cb3c3 | |||
| 10b143193b | |||
| f9fca8c044 | |||
| 8298a4bae5 | |||
| 18a64279fd | |||
| 4629e12f67 | |||
|
|
0bdb09b23c | ||
| 763d360be6 | |||
|
|
f3f9979a0e | ||
|
|
bd93caa375 | ||
|
|
a48abc3b53 |
15
.dockerignore
Normal file
15
.dockerignore
Normal file
@@ -0,0 +1,15 @@
|
||||
.idea
|
||||
__pycache__
|
||||
.git
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
*.md
|
||||
db.json
|
||||
users.json
|
||||
test.py
|
||||
update_db.py
|
||||
logs
|
||||
*.log
|
||||
.vscode
|
||||
uploads/
|
||||
instructions.txt
|
||||
10
Dockerfile
Normal file
10
Dockerfile
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM python:3.9.5
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
COPY . .
|
||||
COPY container/* .
|
||||
RUN mkdir -p /app/uploads
|
||||
EXPOSE 3133
|
||||
|
||||
CMD ["python", "app.py"]
|
||||
60
app.py
60
app.py
@@ -5,16 +5,20 @@ from flask import (
|
||||
request,
|
||||
url_for,
|
||||
send_from_directory,
|
||||
flash
|
||||
flash,
|
||||
jsonify
|
||||
)
|
||||
from utils import redirect, dbload, dbsave, udbload, udbsave
|
||||
from werkzeug.exceptions import RequestEntityTooLarge
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.middleware.proxy_fix import ProxyFix
|
||||
|
||||
|
||||
import os
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
import requests
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
@@ -24,6 +28,7 @@ app = Flask('adrive', static_folder='static', template_folder='templates')
|
||||
app.config['UPLOAD_DIRECTORY'] = 'uploads/'
|
||||
app.config['MAX_CONTENT_LENGTH'] = 1000000 * 1024 * 1024
|
||||
app.config['SECRET_KEY'] = str(random.randint(99999, 9999999))
|
||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1)
|
||||
|
||||
# Redirect logs to the file 'logs'
|
||||
handler = logging.handlers.RotatingFileHandler('logs', maxBytes=1024 * 1024)
|
||||
@@ -32,6 +37,57 @@ logging.getLogger('werkzeug').addHandler(handler)
|
||||
app.logger.setLevel(logging.WARNING)
|
||||
app.logger.addHandler(handler)
|
||||
|
||||
@app.route('/get-location')
|
||||
def get_location():
|
||||
# Since you said /check-ip shows the correct IP, we use it directly
|
||||
user_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||
|
||||
# Clean the IP if it's a list
|
||||
if user_ip and ',' in user_ip:
|
||||
user_ip = user_ip.split(',')[0].strip()
|
||||
|
||||
try:
|
||||
# 1. We MUST send a User-Agent header or the API will block the request
|
||||
headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/120.0.0.0'
|
||||
}
|
||||
|
||||
# 2. Use ip-api.com (it's the most 'forgiving' for free testing)
|
||||
response = requests.get(
|
||||
f'http://ip-api.com/json/{user_ip}',
|
||||
headers=headers,
|
||||
timeout=5
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
|
||||
if data.get('status') == 'success':
|
||||
return jsonify({
|
||||
"status": "success",
|
||||
"city": data.get('city'),
|
||||
"country": data.get('country')
|
||||
})
|
||||
else:
|
||||
# This helps you debug: what did the API actually say?
|
||||
print(f"API Error Message: {data.get('message')}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"Python Request Failed: {e}")
|
||||
|
||||
return jsonify({"status": "fail", "city": "Unknown", "country": "Location"})
|
||||
|
||||
@app.route('/check-ip')
|
||||
def check_ip():
|
||||
return {
|
||||
"remote_addr": request.remote_addr,
|
||||
"x_forwarded_for": request.headers.get('X-Forwarded-For'),
|
||||
"actual_ip_used": request.headers.get('X-Forwarded-For', request.remote_addr)
|
||||
}
|
||||
|
||||
@app.route('/ping')
|
||||
def ping():
|
||||
return jsonify({"status": "ok"})
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return redirect(url_for('upload'))
|
||||
@@ -330,4 +386,4 @@ def download(code):
|
||||
flash('Invalid code! Check if you typed the correct code, and for one-time codes, make sure nobody else entered the code before you did.', 'error')
|
||||
return redirect(url_for('upload'))
|
||||
|
||||
app.run(debug=True, port=3133)
|
||||
app.run(debug=True, port=3133, host='0.0.0.0')
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
Flask
|
||||
requests
|
||||
werkzeug
|
||||
@@ -1,17 +1,4 @@
|
||||
if (localStorage.getItem("loaded")) {
|
||||
document.getElementById("mirrorLogo").className = "fa-solid fa-circle-dot fa-2xs";
|
||||
document.getElementById("mirrorText").textContent = "drive.fybe.dev";
|
||||
document.getElementById("mirrorLogo").style.color = "#47cc00";
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
document.getElementById("mirrorLogo").style.color = "#47cc00";
|
||||
document.getElementById("mirrorText").textContent = "drive.fybe.dev";
|
||||
setTimeout(() => {
|
||||
document.getElementById("mirrorLogo").className = "fa-solid fa-circle-dot fa-2xs";
|
||||
localStorage.setItem("loaded", true);
|
||||
}, 3000);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('uploadForm');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
:root {
|
||||
--black: #000000;
|
||||
--almost-black: #080708;
|
||||
--almostBlack: #888888;
|
||||
--blue: #3772FF;
|
||||
--blue-light: #3787ff;
|
||||
--red: #DF2935;
|
||||
@@ -19,9 +19,8 @@ body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
color: var(--white);
|
||||
background: var(--black);
|
||||
background-image: linear-gradient(to bottom right, var(--almost-black), var(--black));
|
||||
color: var(--black);
|
||||
background: var(--white);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
@@ -37,14 +36,16 @@ body,html {
|
||||
align-items: flex-start;
|
||||
width: 80%;
|
||||
border: 1px solid rgb(40, 40, 40);
|
||||
border-radius: 8px;
|
||||
padding-bottom: 40px;
|
||||
padding: 50px;
|
||||
color: var(--black) !important;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 15px 0 0 15px;
|
||||
width: 100%;
|
||||
color: var(--light);
|
||||
color: var(--black);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -167,57 +168,16 @@ button[type='button']:hover,
|
||||
.dashboard-container {
|
||||
padding: 15px 15px 15px 15px;
|
||||
width: 100%;
|
||||
color: var(--light);
|
||||
color: var(--black);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
/* Table Styling */
|
||||
|
||||
/* Bootstrap-Friendly Table Design */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 20px 0;
|
||||
background: rgba(20, 20, 20, 0.8);
|
||||
border: 1px solid rgb(60, 60, 60);
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
font-size: 16px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
table th {
|
||||
background: linear-gradient(to bottom, rgb(50, 50, 50), rgb(40, 40, 40));
|
||||
padding: 14px 16px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
color: var(--white);
|
||||
border-bottom: 2px solid rgb(80, 80, 80);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid rgb(40, 40, 40);
|
||||
color: var(--light);
|
||||
}
|
||||
|
||||
table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
table tr:hover {
|
||||
background: rgba(55, 114, 255, 0.08);
|
||||
}
|
||||
|
||||
table a {
|
||||
color: var(--blue);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
table a:hover {
|
||||
color: var(--blue-light);
|
||||
text-decoration: underline;
|
||||
table tr td {
|
||||
font-weight: light;
|
||||
}
|
||||
|
||||
/* Styled select for forms */
|
||||
@@ -279,6 +239,7 @@ select.fancy-select::-ms-expand {
|
||||
.quota-block {
|
||||
margin: 8px 0 18px;
|
||||
flex: 0 0 auto;
|
||||
color: var(--almostBlack) !important;
|
||||
}
|
||||
.quota-donut {
|
||||
position: relative;
|
||||
@@ -293,7 +254,8 @@ select.fancy-select::-ms-expand {
|
||||
height: 100%;
|
||||
}
|
||||
.donut-ring {
|
||||
stroke: rgba(255,255,255,0.06);
|
||||
stroke: rgba(9, 9, 9, 0.1);
|
||||
/* fill: black; */
|
||||
stroke-linecap: round;
|
||||
vector-effect: non-scaling-stroke;
|
||||
shape-rendering: geometricPrecision;
|
||||
@@ -315,7 +277,7 @@ select.fancy-select::-ms-expand {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
pointer-events: none;
|
||||
color: var(--white);
|
||||
color: var(--almostBlack);
|
||||
}
|
||||
.quota-percent {
|
||||
font-size: 18px;
|
||||
@@ -325,7 +287,7 @@ select.fancy-select::-ms-expand {
|
||||
.quota-number {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
color: var(--light);
|
||||
color: var(--almostBlack);
|
||||
}
|
||||
.quota-label {
|
||||
font-size: 11px;
|
||||
|
||||
@@ -6,18 +6,31 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ADrive Share</title>
|
||||
<script src="https://kit.fontawesome.com/972393379b.js" crossorigin="anonymous"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
<li class="{{ category }}"><strong>{{ message }}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
{% if category == 'message' %}
|
||||
{% set category = 'primary' %}
|
||||
{% endif %}
|
||||
{% if category == 'error' %}
|
||||
{% set category = 'danger' %}
|
||||
{% endif %}
|
||||
{% if category == 'info' %}
|
||||
{% set category = 'info' %}
|
||||
{% endif %}
|
||||
{% if category == 'warning' %}
|
||||
{% set category = 'warning' %}
|
||||
{% endif %}
|
||||
<li class="alert alert-{{ category }}">{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<div class="dashboard-container">
|
||||
@@ -64,7 +77,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Code</th>
|
||||
@@ -85,9 +98,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if file.reusable %}
|
||||
<a href="/delete/{{ file.code }}" style="color: red;">Delete</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -7,17 +7,30 @@
|
||||
<title>ADrive Share</title>
|
||||
<script src="https://kit.fontawesome.com/972393379b.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
<li class="{{ category }}"><strong>{{ message }}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
{% if category == 'message' %}
|
||||
{% set category = 'primary' %}
|
||||
{% endif %}
|
||||
{% if category == 'error' %}
|
||||
{% set category = 'danger' %}
|
||||
{% endif %}
|
||||
{% if category == 'info' %}
|
||||
{% set category = 'info' %}
|
||||
{% endif %}
|
||||
{% if category == 'warning' %}
|
||||
{% set category = 'warning' %}
|
||||
{% endif %}
|
||||
<li class="alert alert-{{ category }}">{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -27,8 +40,8 @@
|
||||
Enter your credentials to access your dashboard and manage your files.
|
||||
</p>
|
||||
<form id="loginForm" action="/login" method="post">
|
||||
Username: <input type="text" name="username" id="username" placeholder="📋" required aria-required>
|
||||
Passphrase: <input type="password" name="password" id="password" placeholder="🗝️" aria-required>
|
||||
Username: <input type="text" class="form-control" name="username" id="username" placeholder="📋" required aria-required>
|
||||
Passphrase: <input type="password" class="form-control" name="password" id="password" placeholder="🗝️" aria-required>
|
||||
<input type="submit" value="Sign In" id="uploadBtn">
|
||||
</form>
|
||||
|
||||
@@ -70,5 +83,8 @@
|
||||
</script>
|
||||
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
||||
crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -7,17 +7,30 @@
|
||||
<title>ADrive Share</title>
|
||||
<script src="https://kit.fontawesome.com/972393379b.js" crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app">
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
{% if messages %}
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
<li class="{{ category }}"><strong>{{ message }}</strong></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul class="flashes">
|
||||
{% for category, message in messages %}
|
||||
<!-- category: message, error, info, warning -->
|
||||
{% if category == 'message' %}
|
||||
{% set category = 'primary' %}
|
||||
{% endif %}
|
||||
{% if category == 'error' %}
|
||||
{% set category = 'danger' %}
|
||||
{% endif %}
|
||||
{% if category == 'info' %}
|
||||
{% set category = 'info' %}
|
||||
{% endif %}
|
||||
{% if category == 'warning' %}
|
||||
{% set category = 'warning' %}
|
||||
{% endif %}
|
||||
<li class="alert alert-{{ category }}">{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
@@ -27,8 +40,8 @@
|
||||
With an account, you can manage up to 3GB in one dashboard. If you use up your limit, you can delete to free up space or upload files without the ability to manage them.
|
||||
</p>
|
||||
<form id="loginForm" action="/register" method="post">
|
||||
Username: <input type="text" name="username" id="username" placeholder="📋" required aria-required>
|
||||
Passphrase: <input type="password" name="password" id="password" placeholder="🗝️" aria-required>
|
||||
Username: <input type="text" class="form-control" name="username" id="username" placeholder="📋" required aria-required>
|
||||
Passphrase: <input type="password" class="form-control" name="password" id="password" placeholder="🗝️" aria-required>
|
||||
Managable Storage Quota: <select name="quota_files" id="quota_files" class="fancy-select" disabled aria-disabled>
|
||||
<option value="3GB">3GB</option>
|
||||
</select>
|
||||
@@ -72,5 +85,8 @@
|
||||
</script>
|
||||
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
||||
crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -41,18 +41,18 @@
|
||||
{% if loggedIn %}
|
||||
<h1>ADrive File Sharing <span class="badge text-bg-primary">{{ username }}</span></h1>
|
||||
{% else %}
|
||||
<h1>ADrive File Sharing <span class="badge text-bg-primary">Guest</span></h1>
|
||||
<h1>ADrive File Sharing <span class="badge text-bg-danger">Guest</span></h1>
|
||||
{% endif %}
|
||||
<span style="font-size: 20px;">
|
||||
<i class="fa-solid fa-server fa-xs"
|
||||
<!-- <span style="font-size: 20px;">
|
||||
<i class="fa-solid fa-wifi fa-xs"
|
||||
style="line-height: 25px; font-size: 15px; display: inline-block;"></i>
|
||||
<span id="mirrorText">Finding Nearby Mirror</span> <i
|
||||
<span id="mirrorText">Ping: <span id="ping-value">CONNECTING</span>ms</span> <i
|
||||
class="fa-solid fa-circle-dot fa-beat-fade fa-2xs" style="color: #ff9500;" id="mirrorLogo"></i>
|
||||
</span>
|
||||
<span style="font-size: 20px;">
|
||||
<i class="fa-solid fa-server fa-xs"
|
||||
</span> -->
|
||||
<span style="font-size: 20px; padding-bottom: 7px;">
|
||||
<i class="fa-solid fa-location fa-xs"
|
||||
style="line-height: 25px; font-size: 15px; display: inline-block;"></i>
|
||||
Location Not Found <i class="fa-solid fa-circle-dot fa-2xs" style="color: #c10101;"></i>
|
||||
<span id="location-display" class="loading">Locating...</span> <i class="fa-solid fa-circle-dot fa-2xs" id="mirrorLogo" style="color: #c10101;"></i> <span class="badge text-bg-primary" id="ping-badge"><span id="ping-status"></span> <span id="ping-value">..</span>ms</span></span>
|
||||
</span>
|
||||
<input type="file" name="file" id="fileUpload" class="form-control" required aria-required>
|
||||
<input type="hidden" id="quotaGB" value="{{ quota_gb }}">
|
||||
@@ -63,7 +63,7 @@
|
||||
<div id="uploadProgressText" style="display:none;font-size:13px;margin-top:4px">0%</div>
|
||||
<div class="input-group mb-3">
|
||||
<div class="input-group-text">
|
||||
<input class="form-check-input mt-0" type="checkbox" value="" name="reusable"
|
||||
<input class="form-check-input mt-0" type="checkbox" value="" id="reusableCheck" name="reusable"
|
||||
aria-label="Checkbox for following text input" style="border: 1px solid rgb(106, 106, 106);">
|
||||
<label for="reusable" style="margin-left: 6px; margin-bottom: 0;">Reusable
|
||||
Link</label>
|
||||
@@ -74,7 +74,7 @@
|
||||
</form>
|
||||
|
||||
<form>
|
||||
<input type="text" id="codeInput">
|
||||
<input type="text" class="form-control" id="codeInput">
|
||||
<button type="button" value="Download" class="btn btn-primary" onclick="downloadClick()">Download</button>
|
||||
</form>
|
||||
{% if not loggedIn %}
|
||||
@@ -83,7 +83,7 @@
|
||||
<a href="/register" class="sign-in-button"
|
||||
style="text-decoration: none; background: rgb(32, 0, 139)">Register</a><br><br>
|
||||
<p style="color: gray; font-size: 11px; text-align: center;">Signing in is not required. You can at any time
|
||||
register and sign in to manage your existing codes for free. You can manage up to 1GB of files.</p>
|
||||
register and sign in to manage your existing codes for free. You can manage up to 3GB of files.</p>
|
||||
{% else %}
|
||||
<a href="/dashboard" class="sign-in-button" style="text-decoration: none; background: blue">View
|
||||
Dashboard</a>
|
||||
@@ -177,6 +177,76 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
function measurePing() {
|
||||
const start = Date.now();
|
||||
|
||||
fetch('/ping')
|
||||
.then(() => {
|
||||
const end = Date.now();
|
||||
const latency = end - start;
|
||||
document.getElementById('ping-value').innerText = latency;
|
||||
if (latency > 200) {
|
||||
document.getElementById('ping-status').innerText = "BAD";
|
||||
document.getElementById('ping-badge').className = "badge text-bg-danger";
|
||||
} else if (latency > 100) {
|
||||
document.getElementById('ping-status').innerText = "GOOD";
|
||||
document.getElementById('ping-badge').className = "badge text-bg-success";
|
||||
} else if (latency <= 100) {
|
||||
document.getElementById('ping-status').innerText = "BEST";
|
||||
document.getElementById('ping-badge').className = "badge text-bg-primary";
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
document.getElementById('ping-value').innerText = "Error";
|
||||
});
|
||||
}
|
||||
|
||||
document.getElementById("fileUpload").disabled = true;
|
||||
document.getElementById("uploadBtn").disabled = true;
|
||||
document.getElementById("codeInput").disabled = true;
|
||||
document.getElementById("reusableCheck").disabled = true;
|
||||
// Measure ping immediately on load
|
||||
setTimeout(() => {
|
||||
document.getElementById("mirrorLogo").classList.remove("fa-beat-fade");
|
||||
document.getElementById("mirrorLogo").style.color = "green";
|
||||
measurePing();
|
||||
document.getElementById("fileUpload").disabled = false;
|
||||
document.getElementById("codeInput").disabled = false;
|
||||
document.getElementById("uploadBtn").disabled = false;
|
||||
document.getElementById("reusableCheck").disabled = false;
|
||||
|
||||
|
||||
}, 1000);
|
||||
|
||||
|
||||
setInterval(() => {
|
||||
measurePing();
|
||||
}, 1000); // Update every 30 seconds
|
||||
</script>
|
||||
<script>
|
||||
async function loadLocation() {
|
||||
try {
|
||||
// This calls the API from the USER'S browser.
|
||||
// The API will see the User's Real IP directly.
|
||||
const response = await fetch('https://ipapi.co/json/');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.city && data.country_name) {
|
||||
document.getElementById('location-display').innerText =
|
||||
`${data.city}, ${data.country_name}`;
|
||||
document.getElementById('location-display').classList.remove('loading');
|
||||
} else {
|
||||
throw new Error("Missing data");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Location Error:", err);
|
||||
document.getElementById('location-display').innerText = "Unknown Location";
|
||||
}
|
||||
}
|
||||
loadLocation();
|
||||
</script>
|
||||
|
||||
<script src="{{ url_for('static', filename='script.js') }}"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"
|
||||
|
||||
Reference in New Issue
Block a user