Merge pull request 'Change site to Light Mode for now' (#6) from lightmode into main
All checks were successful
Flask Run Test / Flask-Run-Test (push) Successful in 13s

Reviewed-on: #6
This commit was merged in pull request #6.
This commit is contained in:
2026-01-12 11:49:15 +09:00
7 changed files with 146 additions and 84 deletions

View File

@@ -12,3 +12,4 @@ logs
*.log *.log
.vscode .vscode
uploads/ uploads/
instructions.txt

46
app.py
View File

@@ -5,16 +5,20 @@ from flask import (
request, request,
url_for, url_for,
send_from_directory, send_from_directory,
flash flash,
jsonify
) )
from utils import redirect, dbload, dbsave, udbload, udbsave from utils import redirect, dbload, dbsave, udbload, udbsave
from werkzeug.exceptions import RequestEntityTooLarge from werkzeug.exceptions import RequestEntityTooLarge
from werkzeug.utils import secure_filename from werkzeug.utils import secure_filename
from werkzeug.middleware.proxy_fix import ProxyFix
import os import os
import random import random
import threading import threading
import time import time
import requests
import logging import logging
import logging.handlers import logging.handlers
@@ -24,6 +28,7 @@ app = Flask('adrive', static_folder='static', template_folder='templates')
app.config['UPLOAD_DIRECTORY'] = 'uploads/' app.config['UPLOAD_DIRECTORY'] = 'uploads/'
app.config['MAX_CONTENT_LENGTH'] = 1000000 * 1024 * 1024 app.config['MAX_CONTENT_LENGTH'] = 1000000 * 1024 * 1024
app.config['SECRET_KEY'] = str(random.randint(99999, 9999999)) 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' # Redirect logs to the file 'logs'
handler = logging.handlers.RotatingFileHandler('logs', maxBytes=1024 * 1024) handler = logging.handlers.RotatingFileHandler('logs', maxBytes=1024 * 1024)
@@ -32,6 +37,45 @@ logging.getLogger('werkzeug').addHandler(handler)
app.logger.setLevel(logging.WARNING) app.logger.setLevel(logging.WARNING)
app.logger.addHandler(handler) app.logger.addHandler(handler)
@app.route('/get-location')
def get_location():
# 1. Try to get the forwarded IP first (for Docker/Production)
user_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
# 2. If it's a list (e.g. "1.2.3.4, 172.17.0.1"), take the first one
if user_ip and ',' in user_ip:
user_ip = user_ip.split(',')[0].strip()
# 3. Clean up any weird local addresses
if user_ip in ['127.0.0.1', 'localhost', '::1'] or user_ip.startswith('172.'):
# Fallback for testing only
return jsonify({"status": "success", "city": "Seoul", "country": "South Korea", "isp": "Test ISP"})
try:
# Use HTTPS to be safer
response = requests.get(f'https://ipapi.co/{user_ip}/json/', timeout=5)
data = response.json()
return jsonify({
"status": "success",
"city": data.get('city', 'Unknown'),
"country": data.get('country_name', 'Unknown'),
"isp": data.get('org', 'Unknown ISP')
})
except Exception as e:
return jsonify({"status": "fail", "error": str(e)}), 500
@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('/') @app.route('/')
def index(): def index():
return redirect(url_for('upload')) return redirect(url_for('upload'))

View File

@@ -1 +1,3 @@
Flask Flask
requests
werkzeug

View File

@@ -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() { document.addEventListener('DOMContentLoaded', function() {
const form = document.getElementById('uploadForm'); const form = document.getElementById('uploadForm');

View File

@@ -1,6 +1,6 @@
:root { :root {
--black: #000000; --black: #000000;
--almost-black: #080708; --almostBlack: #888888;
--blue: #3772FF; --blue: #3772FF;
--blue-light: #3787ff; --blue-light: #3787ff;
--red: #DF2935; --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-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
font-size: 22px; font-size: 22px;
line-height: 1.5; line-height: 1.5;
color: var(--white); color: var(--black);
background: var(--black); background: var(--white);
background-image: linear-gradient(to bottom right, var(--almost-black), var(--black));
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
@@ -37,14 +36,16 @@ body,html {
align-items: flex-start; align-items: flex-start;
width: 80%; width: 80%;
border: 1px solid rgb(40, 40, 40); border: 1px solid rgb(40, 40, 40);
border-radius: 8px;
padding-bottom: 40px; padding-bottom: 40px;
padding: 50px; padding: 50px;
color: var(--black) !important;
} }
.form-section { .form-section {
padding: 15px 0 0 15px; padding: 15px 0 0 15px;
width: 100%; width: 100%;
color: var(--light); color: var(--black);
flex-shrink: 0; flex-shrink: 0;
} }
@@ -167,57 +168,16 @@ button[type='button']:hover,
.dashboard-container { .dashboard-container {
padding: 15px 15px 15px 15px; padding: 15px 15px 15px 15px;
width: 100%; width: 100%;
color: var(--light); color: var(--black);
flex-shrink: 0; flex-shrink: 0;
} }
/* Table Styling */
/* Bootstrap-Friendly Table Design */
table { table {
width: 100%; font-size: 15px;
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;
} }
table tr td {
table th { font-weight: light;
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;
} }
/* Styled select for forms */ /* Styled select for forms */
@@ -279,6 +239,7 @@ select.fancy-select::-ms-expand {
.quota-block { .quota-block {
margin: 8px 0 18px; margin: 8px 0 18px;
flex: 0 0 auto; flex: 0 0 auto;
color: var(--almostBlack) !important;
} }
.quota-donut { .quota-donut {
position: relative; position: relative;
@@ -293,7 +254,8 @@ select.fancy-select::-ms-expand {
height: 100%; height: 100%;
} }
.donut-ring { .donut-ring {
stroke: rgba(255,255,255,0.06); stroke: rgba(9, 9, 9, 0.1);
/* fill: black; */
stroke-linecap: round; stroke-linecap: round;
vector-effect: non-scaling-stroke; vector-effect: non-scaling-stroke;
shape-rendering: geometricPrecision; shape-rendering: geometricPrecision;
@@ -315,7 +277,7 @@ select.fancy-select::-ms-expand {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
pointer-events: none; pointer-events: none;
color: var(--white); color: var(--almostBlack);
} }
.quota-percent { .quota-percent {
font-size: 18px; font-size: 18px;
@@ -325,7 +287,7 @@ select.fancy-select::-ms-expand {
.quota-number { .quota-number {
font-size: 12px; font-size: 12px;
font-weight: 700; font-weight: 700;
color: var(--light); color: var(--almostBlack);
} }
.quota-label { .quota-label {
font-size: 11px; font-size: 11px;

View File

@@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ADrive Share</title> <title>ADrive Share</title>
<script src="https://kit.fontawesome.com/972393379b.js" crossorigin="anonymous"></script> <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') }}"> <link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head> </head>
<body> <body>
@@ -76,7 +77,7 @@
</div> </div>
</div> </div>
</div> </div>
<table> <table class="table table-striped">
<tr> <tr>
<th>Filename</th> <th>Filename</th>
<th>Code</th> <th>Code</th>
@@ -97,9 +98,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
{% if file.reusable %}
<a href="/delete/{{ file.code }}" style="color: red;">Delete</a> <a href="/delete/{{ file.code }}" style="color: red;">Delete</a>
{% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@@ -41,18 +41,18 @@
{% if loggedIn %} {% if loggedIn %}
<h1>ADrive File Sharing <span class="badge text-bg-primary">{{ username }}</span></h1> <h1>ADrive File Sharing <span class="badge text-bg-primary">{{ username }}</span></h1>
{% else %} {% 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 %} {% endif %}
<span style="font-size: 20px;"> <!-- <span style="font-size: 20px;">
<i class="fa-solid fa-server fa-xs" <i class="fa-solid fa-wifi fa-xs"
style="line-height: 25px; font-size: 15px; display: inline-block;"></i> 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> class="fa-solid fa-circle-dot fa-beat-fade fa-2xs" style="color: #ff9500;" id="mirrorLogo"></i>
</span> </span> -->
<span style="font-size: 20px;"> <span style="font-size: 20px; padding-bottom: 7px;">
<i class="fa-solid fa-server fa-xs" <i class="fa-solid fa-location fa-xs"
style="line-height: 25px; font-size: 15px; display: inline-block;"></i> 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> </span>
<input type="file" name="file" id="fileUpload" class="form-control" required aria-required> <input type="file" name="file" id="fileUpload" class="form-control" required aria-required>
<input type="hidden" id="quotaGB" value="{{ quota_gb }}"> <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 id="uploadProgressText" style="display:none;font-size:13px;margin-top:4px">0%</div>
<div class="input-group mb-3"> <div class="input-group mb-3">
<div class="input-group-text"> <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);"> 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 <label for="reusable" style="margin-left: 6px; margin-bottom: 0;">Reusable
Link</label> Link</label>
@@ -177,6 +177,73 @@
})(); })();
</script> </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 {
const response = await fetch('/get-location');
const data = await response.json();
if (data.status === 'success') {
document.getElementById('location-display').innerHTML =
`${data.city}, ${data.country} <small>(${data.isp})</small>`;
document.getElementById('location-display').classList.remove('loading');
} else {
throw new Error();
}
} catch (err) {
document.getElementById('location-display').innerText = "Unknown Location";
}
}
loadLocation();
</script>
<script src="{{ url_for('static', filename='script.js') }}"></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" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"
integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI" integrity="sha384-FKyoEForCGlyvwx9Hj09JcYn3nv7wiPVlz7YYwJrWVcXK/BmnVDxM+D2scQbITxI"