const imageExtensions = ['gif','jpg','jpeg','png', 'webp']; const videoExtensions =['mpg', 'mp2', 'mpeg', 'mpe', 'mpv', 'mp4']; const audioExtensions =['mp3', 'ogg', 'wav', 'flac']; const mappings = new Map(JSON.parse(localStorage.getItem('mappings')) || []); let statusLine = document.getElementById('status'); // store for when done with sorting TODO display let splash = document.getElementById('current-file').innerHTML; let history = []; // // SERVER COMMUNICATION // /** * Only show the server response text if its a 500 internal */ function showServerError(fname, status, text) { if (status == 500) { message = `in ${fname}: server returned ${status}: '${text}'`; } else { message = `in ${fname}: server returned ${status}`; } statusLine.textContent = message; console.error(message); } /** * get the path in which the images are located and can be loaded from, by appending to them to the stagingPath */ let stagingPath = ""; async function setStagingPath() { const response = await fetch("imgsort.php?action=getStagingPath"); if (response.ok) { stagingPath = await response.text(); } else { showServerError("setStagingPath", response.status, text); } } /** * list of files to be processed */ let fileList = []; async function setFileList() { const response = await fetch("imgsort.php?action=getFileList"); const text = await response.text(); // console.log(text); if (response.ok) { fileList = JSON.parse(text); // fileList.sort(); } else { } } // // RENDERING // /* * Create button for each mapping */ function renderMoveButtons() { const buttons = document.getElementById('move-buttons'); buttons.innerHTML = ''; mappings.forEach((directory, key) => { const removeButton = document.createElement('button'); removeButton.innerHTML = `${key} ${directory}`; removeButton.onclick = function() { moveFile(directory); }; removeButton.class = "move-button"; buttons.appendChild(removeButton); }); } function renderFileList() { const fileListDiv = document.getElementById('file-list'); fileListDiv.innerHTML = ''; fileList.forEach(file => { const p = document.createElement('p'); classes = "file-list-item path"; if (file === currentFile) { classes += " selected-file-list-item"; } p.setAttribute("class", classes) p.innerHTML = file; fileListDiv.appendChild(p); }); } let currentFile = ""; let currentFileIdx = null; function createMediaFileElement(file, autoplay=false) { const fileExt = file.split('.').pop(); if (imageExtensions.includes(fileExt)) { // if image let img = document.createElement("img"); img.setAttribute('src', stagingPath + file) return img; } else if (videoExtensions.includes(fileExt)) { // if video let vid = document.createElement("video"); if (autoplay) vid.setAttribute('autoplay', true); vid.setAttribute('controls', true); src = document.createElement("source"); src.setAttribute("src", stagingPath + file); src.setAttribute("type", `video/${fileExt}`); vid.appendChild(src); return vid; } else if (audioExtensions.includes(fileExt)) { // if audio let aud = document.createElement("audio"); if (autoplay) aud.setAttribute('autoplay', true); aud.setAttribute('controls', true); src = document.createElement("source"); src.setAttribute("src", stagingPath + file); src.setAttribute("type", `audio/${fileExt}`); aud.appendChild(src); return aud; } else { // if none of the above let p = document.createElement("p"); p.innerHTML = 'No preview available'; return p; } } function renderCurrentFile() { // const currentFileNameDiv = document.getElementById('current-file-name'); // if (!currentFile) { // currentFileNameDiv.innerHTML = "No files in staging"; // } // else { // currentFileNameDiv.innerHTML = currentFile; // } const currentFileDiv = document.getElementById('current-file'); currentFileDiv.innerHTML = ""; if (currentFile) { let element = createMediaFileElement(currentFile, true); currentFileDiv.appendChild(element); } else { currentFileDiv.innerHTML = splash; } } // load media tag of the next file in hidden div, without autoplay function preloadNextFile() { const nextFile = fileList[currentFileIdx+1]; if (!nextFile) { return } const preloadFileDiv = document.getElementById('preload-file'); preloadFileDiv.innerHTML = ""; let element = createMediaFileElement(nextFile, false); preloadFileDiv.appendChild(element); console.log("Preloaded " + nextFile); } // // LOGIC // // set the currentFile variable according to currentFileIdx function setCurrentFile() { // check configuration if (mappings.size == 0) { statusLine.textContent = "No mappings configured - Click 'Configure' first"; return; } // if none set and there are files if (currentFileIdx == null && fileList.length > 0) { currentFileIdx = 0; } // else if (currentFileIdx < fileList.length) { // } else if (currentFileIdx >= fileList.length) { currentFileIdx = fileList.length - 1; } // if index is valid if (typeof(currentFileIdx) == 'number' && currentFileIdx >= 0 && currentFileIdx < fileList.length) { currentFile = fileList[currentFileIdx]; } else { currentFileIdx = null; currentFile = ""; statusLine.textContent = "No more files to sort"; } renderCurrentFile(); renderFileList(); } async function moveFile(directory) { if (!currentFile) { statusLine.innerHTML = "No file to process!"; return } const response = await fetch(`imgsort.php?action=moveFile&file=${escape(currentFile)}&dest=${directory}`); const text = await response.text(); // console.log(text); if (response.ok) { statusLine.textContent = `Moved '${currentFile}' to '${directory}'`; history.push([currentFile, directory]); // remove file from list fileList.splice(currentFileIdx, 1); // set next file setCurrentFile(); preloadNextFile(); } else { showServerError("moveFile", response.status, text); } } async function undo() { if (!history.length > 0) { statusLine.textContent = "Nothing to undo" return; } const [file, directory] = history.pop(); const response = await fetch(`imgsort.php?action=undoFile&file=${escape(file)}&dest=${directory}`); const text = await response.text(); // console.log(text); if (response.ok) { statusLine.innerHTML = `Undo: move '${file}' to '${directory}'`; await setFileList() setCurrentFile(); } else { showServerError("undo", response.status, text); } } function skip() { currentFileIdx++; setCurrentFile(); } async function initialize() { await setStagingPath(); await setFileList(); renderMoveButtons(); renderFileList(); // setCurrentFile(); preloadNextFile(); statusLine.textContent = "Loaded"; } // load existing mappings on page load window.onload = function() { initialize(); }; // handle keyboard document.onkeypress = function(e) { e = e || window.event; let keydebug = document.getElementById("keydebug"); if (keydebug) { keydebug.innerHTML = e.key; } if (e.key == "u") { undo(); } else if (e.key == "s") { skip(); } else if (mappings.has(e.key)) { moveFile(mappings.get(e.key)); } }