diff --git a/static/app.js b/static/app.js
index 963abe7..e799d60 100644
--- a/static/app.js
+++ b/static/app.js
@@ -53,6 +53,12 @@ const uploadStatusText = document.getElementById('upload-status-text');
const uploadsList = document.getElementById('uploads-list');
const emptyUploadsMsg = document.getElementById('empty-uploads-msg');
const uploadsCountBadge = document.getElementById('uploads-count');
+const btnOpenAllUploads = document.getElementById('btn-open-all-uploads');
+const btnAllUploadsCount = document.getElementById('btn-all-uploads-count');
+const uploadsModal = document.getElementById('uploads-modal');
+const btnCloseUploads = document.getElementById('btn-close-uploads');
+const modalUploadsList = document.getElementById('modal-uploads-list');
+const emptyModalUploadsMsg = document.getElementById('empty-modal-uploads-msg');
const historyList = document.getElementById('history-list');
const emptyHistoryMsg = document.getElementById('empty-history-msg');
const historyCountBadge = document.getElementById('history-count');
@@ -170,6 +176,15 @@ function bindEvents() {
});
}
+ // Uploads Modal Events
+ if (btnOpenAllUploads) btnOpenAllUploads.addEventListener('click', openUploadsModal);
+ if (btnCloseUploads) btnCloseUploads.addEventListener('click', closeUploadsModal);
+ if (uploadsModal) {
+ uploadsModal.addEventListener('click', (e) => {
+ if (e.target === uploadsModal) closeUploadsModal();
+ });
+ }
+
// Upload Events
if (btnSelectFile && fileInput) {
btnSelectFile.addEventListener('click', () => fileInput.click());
@@ -848,20 +863,33 @@ async function fetchUploads() {
}
}
-// Render Uploaded Files
-function renderUploads(files) {
- if (!uploadsList) return;
- const items = uploadsList.querySelectorAll('.queue-item');
+let allUploadedFiles = [];
+
+// Open Uploads Modal
+function openUploadsModal() {
+ if (uploadsModal) {
+ uploadsModal.style.display = 'flex';
+ renderModalUploads(allUploadedFiles);
+ }
+}
+
+// Close Uploads Modal
+function closeUploadsModal() {
+ if (uploadsModal) uploadsModal.style.display = 'none';
+}
+
+// Render Modal Uploads (All files)
+function renderModalUploads(files) {
+ if (!modalUploadsList) return;
+ const items = modalUploadsList.querySelectorAll('.queue-item');
items.forEach(el => el.remove());
if (!files || files.length === 0) {
- emptyUploadsMsg.style.display = 'flex';
- uploadsCountBadge.textContent = '0 plików';
+ if (emptyModalUploadsMsg) emptyModalUploadsMsg.style.display = 'flex';
return;
}
- emptyUploadsMsg.style.display = 'none';
- uploadsCountBadge.textContent = `${files.length} ${files.length === 1 ? 'plik' : files.length < 5 ? 'pliki' : 'plików'}`;
+ if (emptyModalUploadsMsg) emptyModalUploadsMsg.style.display = 'none';
files.forEach(file => {
const li = document.createElement('li');
@@ -877,7 +905,55 @@ function renderUploads(files) {
+
+
+ `;
+ modalUploadsList.appendChild(li);
+ });
+ lucide.createIcons();
+}
+
+// Render Uploaded Files (Top 10 most recent on dashboard panel)
+function renderUploads(files) {
+ allUploadedFiles = files || [];
+ if (btnAllUploadsCount) btnAllUploadsCount.textContent = allUploadedFiles.length;
+
+ if (!uploadsList) return;
+ const items = uploadsList.querySelectorAll('.queue-item');
+ items.forEach(el => el.remove());
+
+ if (!files || files.length === 0) {
+ emptyUploadsMsg.style.display = 'flex';
+ uploadsCountBadge.textContent = '0 plików';
+ if (modalUploadsList) renderModalUploads([]);
+ return;
+ }
+
+ emptyUploadsMsg.style.display = 'none';
+ uploadsCountBadge.textContent = `${files.length} ${files.length === 1 ? 'plik' : files.length < 5 ? 'pliki' : 'plików'}`;
+
+ // Take only top 10 most recently used/uploaded
+ const top10 = files.slice(0, 10);
+
+ top10.forEach(file => {
+ const li = document.createElement('li');
+ li.className = 'queue-item';
+
+ const safeFilename = file.filename.replace(/'/g, "\\'");
+
+ li.innerHTML = `
+
+
+
${file.filename}
+
${file.size_mb} MB
+
+
+
@@ -173,6 +173,9 @@
+
@@ -234,6 +237,25 @@
+
+
+
+
+
+
Pełna lista plików zapisanych w serwerowej bazie danych (posortowana od ostatnio używanych / przesłanych).
+
+
+
+
+
diff --git a/static/style.css b/static/style.css
index bee5e63..06eaca4 100644
--- a/static/style.css
+++ b/static/style.css
@@ -988,7 +988,7 @@ body {
background: rgba(255, 255, 255, 0.02);
}
-#btn-close-settings {
+#btn-close-settings, #btn-close-uploads {
width: 42px;
height: 42px;
background: rgba(255, 255, 255, 0.12);
@@ -1002,7 +1002,7 @@ body {
cursor: pointer;
}
-#btn-close-settings:hover {
+#btn-close-settings:hover, #btn-close-uploads:hover {
background: rgba(239, 68, 68, 0.25);
border-color: rgba(239, 68, 68, 0.6);
color: #ff6b6b;
diff --git a/web.py b/web.py
index b68e6cc..338dd94 100644
--- a/web.py
+++ b/web.py
@@ -510,14 +510,17 @@ async def get_uploads():
uploads_dir = "uploads"
os.makedirs(uploads_dir, exist_ok=True)
files = []
- for f in sorted(os.listdir(uploads_dir)):
+ for f in os.listdir(uploads_dir):
filepath = os.path.join(uploads_dir, f)
if os.path.isfile(filepath) and not f.startswith("."):
size_mb = round(os.path.getsize(filepath) / (1024 * 1024), 2)
+ mtime = os.path.getmtime(filepath)
files.append({
"filename": f,
- "size_mb": size_mb
+ "size_mb": size_mb,
+ "mtime": mtime
})
+ files.sort(key=lambda x: x["mtime"], reverse=True)
return {"files": files}
@app.post("/api/upload")
@@ -567,6 +570,7 @@ async def api_play_file(req: PlayFileRequest):
raise HTTPException(status_code=404, detail="Plik nie istnieje na serwerze")
try:
+ os.utime(filepath, None)
player = await YTDLSource.from_file(filepath, loop=bot.loop)
res = await music_cog.enqueue_track(guild_id, player, from_web=True)
await broadcast_status()