fix: logging
This commit is contained in:
parent
495f33aa68
commit
d2952c3ac0
27
app.py
27
app.py
@ -35,6 +35,7 @@ import helperfunctions as hf
|
|||||||
import search_db_analyzer as sdb
|
import search_db_analyzer as sdb
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import openpyxl
|
import openpyxl
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
app_config = auth.return_app_config()
|
app_config = auth.return_app_config()
|
||||||
BASE_DIR = os.path.realpath(app_config['BASE_DIR'])
|
BASE_DIR = os.path.realpath(app_config['BASE_DIR'])
|
||||||
@ -44,6 +45,27 @@ cache_image = diskcache.Cache('./filecache_image', size_limit= app_config['filec
|
|||||||
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)
|
||||||
cache_other = diskcache.Cache('./filecache_other', size_limit= app_config['filecache_size_limit_other'] * 1024**3)
|
cache_other = diskcache.Cache('./filecache_other', size_limit= app_config['filecache_size_limit_other'] * 1024**3)
|
||||||
|
|
||||||
|
_logged_request_ids = OrderedDict()
|
||||||
|
_logged_request_ids_lock = threading.Lock()
|
||||||
|
_LOGGED_REQUEST_IDS_MAX = 2048
|
||||||
|
|
||||||
|
|
||||||
|
def _is_duplicate_request(req_id: str) -> bool:
|
||||||
|
if not req_id:
|
||||||
|
return False
|
||||||
|
with _logged_request_ids_lock:
|
||||||
|
return req_id in _logged_request_ids
|
||||||
|
|
||||||
|
|
||||||
|
def _mark_request_logged(req_id: str):
|
||||||
|
if not req_id:
|
||||||
|
return
|
||||||
|
with _logged_request_ids_lock:
|
||||||
|
_logged_request_ids[req_id] = None
|
||||||
|
_logged_request_ids.move_to_end(req_id)
|
||||||
|
if len(_logged_request_ids) > _LOGGED_REQUEST_IDS_MAX:
|
||||||
|
_logged_request_ids.popitem(last=False)
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
|
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1)
|
||||||
|
|
||||||
@ -782,6 +804,7 @@ def serve_file(subpath):
|
|||||||
ip_address = request.remote_addr
|
ip_address = request.remote_addr
|
||||||
user_agent = request.headers.get('User-Agent')
|
user_agent = request.headers.get('User-Agent')
|
||||||
range_header = request.headers.get('Range', '')
|
range_header = request.headers.get('Range', '')
|
||||||
|
req_id = request.args.get('req') or request.headers.get('X-Request-Id')
|
||||||
|
|
||||||
def is_range_prefetch(header, ua):
|
def is_range_prefetch(header, ua):
|
||||||
"""
|
"""
|
||||||
@ -886,6 +909,7 @@ def serve_file(subpath):
|
|||||||
response.headers['Cache-Control'] = 'public, max-age=86400'
|
response.headers['Cache-Control'] = 'public, max-age=86400'
|
||||||
|
|
||||||
if do_log and not small:
|
if do_log and not small:
|
||||||
|
if not _is_duplicate_request(req_id):
|
||||||
a.log_file_access(
|
a.log_file_access(
|
||||||
cache_key,
|
cache_key,
|
||||||
os.path.getsize(file_path),
|
os.path.getsize(file_path),
|
||||||
@ -896,6 +920,7 @@ def serve_file(subpath):
|
|||||||
cached_hit,
|
cached_hit,
|
||||||
request.method
|
request.method
|
||||||
)
|
)
|
||||||
|
_mark_request_logged(req_id)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# 5) Non-image branch: check if cached, otherwise create partial cache file
|
# 5) Non-image branch: check if cached, otherwise create partial cache file
|
||||||
@ -1041,6 +1066,7 @@ def serve_file(subpath):
|
|||||||
|
|
||||||
# 7) Logging
|
# 7) Logging
|
||||||
if do_log:
|
if do_log:
|
||||||
|
if not _is_duplicate_request(req_id):
|
||||||
a.log_file_access(
|
a.log_file_access(
|
||||||
subpath,
|
subpath,
|
||||||
filesize,
|
filesize,
|
||||||
@ -1051,6 +1077,7 @@ def serve_file(subpath):
|
|||||||
cached_hit,
|
cached_hit,
|
||||||
request.method
|
request.method
|
||||||
)
|
)
|
||||||
|
_mark_request_logged(req_id)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -263,6 +263,9 @@ function preload_audio() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TRACK_CLICK_DEBOUNCE_MS = 3000;
|
||||||
|
let lastTrackClick = { url: null, ts: 0 };
|
||||||
|
|
||||||
// Attach event listeners for directory, breadcrumb, file, and transcript links.
|
// Attach event listeners for directory, breadcrumb, file, and transcript links.
|
||||||
function attachEventListeners() {
|
function attachEventListeners() {
|
||||||
// Directory link clicks.
|
// Directory link clicks.
|
||||||
@ -295,20 +298,33 @@ document.querySelectorAll('.play-file').forEach(link => {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const { fileType, url: relUrl, index } = this.dataset;
|
const { fileType, url: relUrl, index } = this.dataset;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
if (fileType === 'music') {
|
||||||
|
// If this is the same track already loaded, ignore to avoid extra GETs and unselects.
|
||||||
|
if (player.currentRelUrl === relUrl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the class from all file items.
|
// Remove the class from all file items.
|
||||||
document.querySelectorAll('.file-item').forEach(item => {
|
document.querySelectorAll('.file-item').forEach(item => {
|
||||||
item.classList.remove('currently-playing');
|
item.classList.remove('currently-playing');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (fileType === 'music') {
|
// Debounce repeated clicks on the same track to avoid extra GETs.
|
||||||
|
if (lastTrackClick.url === relUrl && now - lastTrackClick.ts < TRACK_CLICK_DEBOUNCE_MS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastTrackClick = { url: relUrl, ts: now };
|
||||||
|
|
||||||
// Update the current music index.
|
// Update the current music index.
|
||||||
currentMusicIndex = index !== undefined ? parseInt(index) : -1;
|
currentMusicIndex = index !== undefined ? parseInt(index) : -1;
|
||||||
|
|
||||||
// Mark the clicked item as currently playing.
|
// Mark the clicked item as currently playing.
|
||||||
this.closest('.file-item').classList.add('currently-playing');
|
this.closest('.file-item').classList.add('currently-playing');
|
||||||
|
|
||||||
player.loadTrack(relUrl);
|
const reqId = crypto.randomUUID ? crypto.randomUUID() : (Date.now().toString(36) + Math.random().toString(36).slice(2));
|
||||||
|
player.loadTrack(relUrl, reqId);
|
||||||
|
|
||||||
// Delay preloading to avoid blocking playback.
|
// Delay preloading to avoid blocking playback.
|
||||||
setTimeout(preload_audio, 1000);
|
setTimeout(preload_audio, 1000);
|
||||||
@ -318,7 +334,9 @@ document.querySelectorAll('.play-file').forEach(link => {
|
|||||||
openGalleryModal(relUrl);
|
openGalleryModal(relUrl);
|
||||||
} else {
|
} else {
|
||||||
// serve like a download
|
// serve like a download
|
||||||
window.location.href = `/media/${relUrl}`;
|
const reqId = crypto.randomUUID ? crypto.randomUUID() : (Date.now().toString(36) + Math.random().toString(36).slice(2));
|
||||||
|
const urlWithReq = `/media/${relUrl}${relUrl.includes('?') ? '&' : '?'}req=${encodeURIComponent(reqId)}`;
|
||||||
|
window.location.href = urlWithReq;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -168,7 +168,11 @@ class SimpleAudioPlayer {
|
|||||||
document.body.removeChild(a);
|
document.body.removeChild(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadTrack(relUrl) {
|
async loadTrack(relUrl, reqId) {
|
||||||
|
this.currentRelUrl = relUrl;
|
||||||
|
const requestId = reqId || (crypto.randomUUID ? crypto.randomUUID() : (Date.now().toString(36) + Math.random().toString(36).slice(2)));
|
||||||
|
const urlWithReq = `/media/${relUrl}${relUrl.includes('?') ? '&' : '?'}req=${encodeURIComponent(requestId)}`;
|
||||||
|
|
||||||
this.audio.pause();
|
this.audio.pause();
|
||||||
this.container.style.display = 'block';
|
this.container.style.display = 'block';
|
||||||
this.nowInfo.textContent = 'Loading…';
|
this.nowInfo.textContent = 'Loading…';
|
||||||
@ -177,13 +181,13 @@ class SimpleAudioPlayer {
|
|||||||
this.abortCtrl = new AbortController();
|
this.abortCtrl = new AbortController();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const head = await fetch(`/media/${relUrl}`, {
|
const head = await fetch(urlWithReq, {
|
||||||
method: 'HEAD',
|
method: 'HEAD',
|
||||||
signal: this.abortCtrl.signal
|
signal: this.abortCtrl.signal
|
||||||
});
|
});
|
||||||
if (!head.ok) throw new Error(`Status ${head.status}`);
|
if (!head.ok) throw new Error(`Status ${head.status}`);
|
||||||
|
|
||||||
this.audio.src = `/media/${relUrl}`;
|
this.audio.src = urlWithReq;
|
||||||
await this.audio.play();
|
await this.audio.play();
|
||||||
|
|
||||||
// Full breadcrumb
|
// Full breadcrumb
|
||||||
@ -265,4 +269,3 @@ class SimpleAudioPlayer {
|
|||||||
|
|
||||||
// Initialize instance
|
// Initialize instance
|
||||||
const player = new SimpleAudioPlayer();
|
const player = new SimpleAudioPlayer();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user