mirror of
https://github.com/Benzauber/convert-commander.git
synced 2025-12-20 09:49:31 -06:00
Multiple File Converting
This commit is contained in:
203
index.py
203
index.py
@@ -7,6 +7,8 @@ from flask_cors import CORS
|
||||
import shutil
|
||||
from threading import Timer
|
||||
import json
|
||||
import uuid
|
||||
from zip_creator import create_zip_file, cleanup_convert_folder
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app, resources={r"/*": {"origins": "*"}})
|
||||
@@ -16,7 +18,8 @@ app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
|
||||
|
||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||
|
||||
|
||||
# Global variables to store multiple files and their info
|
||||
uploaded_files = {} # {session_id: [{'filename': str, 'filepath': str, 'original_name': str}]}
|
||||
global_filetest = None
|
||||
folder_path_1 = 'uploads'
|
||||
folder_path_2 = 'convert'
|
||||
@@ -24,31 +27,60 @@ folder_path_2 = 'convert'
|
||||
with open('static/data/formats.json', 'r') as f:
|
||||
data = json.load(f)
|
||||
|
||||
|
||||
pandoc_formats = data['pandocGruppe']
|
||||
libreoffice_formats = data['tabelleGruppe'] + data['persentGruppe']
|
||||
ffmpeg_formats = data['videoGruppe'] + data['audioGruppe'] + data['imageGruppe']
|
||||
|
||||
|
||||
def delete_files_in_folder(folder_path):
|
||||
# Check if the folder exists
|
||||
if os.path.exists(folder_path):
|
||||
# Iterate through all files and subfolders in the folder
|
||||
for filename in os.listdir(folder_path):
|
||||
file_path = os.path.join(folder_path, filename)
|
||||
try:
|
||||
# Check if it is a file or a folder
|
||||
if os.path.isfile(file_path) or os.path.islink(file_path):
|
||||
os.unlink(file_path) # Delete file or symbolic link
|
||||
os.unlink(file_path)
|
||||
elif os.path.isdir(file_path):
|
||||
shutil.rmtree(file_path) # Delete folder and its content
|
||||
shutil.rmtree(file_path)
|
||||
except Exception as e:
|
||||
print(f'Error deleting {file_path}. Reason: {e}')
|
||||
else:
|
||||
print(f'Folder {folder_path} does not exist')
|
||||
|
||||
def download_file(filepath, global_filetest):
|
||||
filename = os.path.splitext(os.path.basename(filepath))[0]
|
||||
def convert_file(filepath, target_format):
|
||||
"""Convert a single file based on its target format"""
|
||||
try:
|
||||
if target_format in libreoffice_formats:
|
||||
print(f"Converting with Libreoffice: {filepath}")
|
||||
libre.start(filepath, target_format)
|
||||
elif target_format in pandoc_formats:
|
||||
print(f"Converting with Pandoc: {filepath}")
|
||||
pandoc.start(filepath, target_format)
|
||||
elif target_format in ffmpeg_formats:
|
||||
print(f"Converting with Ffmpeg: {filepath}")
|
||||
ffmpeg.start(filepath, target_format)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Error converting {filepath}: {e}")
|
||||
return False
|
||||
|
||||
def convert_multiple_files(file_list, target_format):
|
||||
"""Convert multiple files sequentially"""
|
||||
converted_count = 0
|
||||
for file_info in file_list:
|
||||
filepath = file_info['filepath']
|
||||
if convert_file(filepath, target_format):
|
||||
converted_count += 1
|
||||
else:
|
||||
print(f"Failed to convert: {filepath}")
|
||||
return converted_count
|
||||
|
||||
def download_file(original_filename, global_filetest):
|
||||
# Use the original filename without the UUID prefix
|
||||
if original_filename.count('_') >= 4: # UUID format: uuid_originalname
|
||||
clean_filename = '_'.join(original_filename.split('_')[1:])
|
||||
else:
|
||||
clean_filename = original_filename
|
||||
|
||||
filename = os.path.splitext(clean_filename)[0]
|
||||
filethepath = f'convert/{filename}.{global_filetest}'
|
||||
try:
|
||||
print(f"Ready for download: {filethepath}")
|
||||
@@ -62,47 +94,97 @@ def delete_files_after_delay():
|
||||
|
||||
@app.route('/', methods=['GET', 'POST'])
|
||||
def index():
|
||||
global global_filetest
|
||||
global global_filetest, uploaded_files
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'file' not in request.files:
|
||||
return redirect(url_for('index', status='No file selected'))
|
||||
file = request.files['file']
|
||||
session_id = request.form.get('session_id', str(uuid.uuid4()))
|
||||
|
||||
if file.filename == '':
|
||||
return redirect(url_for('index', status='No file selected'))
|
||||
|
||||
if file and global_filetest is not None:
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
|
||||
file.save(filepath)
|
||||
|
||||
if global_filetest in libreoffice_formats:
|
||||
print("Libreoffice")
|
||||
libre.start(filepath, global_filetest)
|
||||
elif global_filetest in pandoc_formats:
|
||||
print("Pandoc")
|
||||
pandoc.start(filepath, global_filetest)
|
||||
elif global_filetest in ffmpeg_formats:
|
||||
print("Ffmpeg")
|
||||
ffmpeg.start(filepath, global_filetest)
|
||||
|
||||
response = redirect(url_for('download', filename=file.filename))
|
||||
|
||||
Timer(5, delete_files_after_delay).start()
|
||||
|
||||
if 'files' in request.files:
|
||||
# Multiple file upload
|
||||
files = request.files.getlist('files')
|
||||
if not files or all(f.filename == '' for f in files):
|
||||
return redirect(url_for('index', status='No files selected'))
|
||||
|
||||
if global_filetest is None:
|
||||
return redirect(url_for('index', status='Please select target format first'))
|
||||
|
||||
# Initialize session if not exists
|
||||
if session_id not in uploaded_files:
|
||||
uploaded_files[session_id] = []
|
||||
|
||||
# Save all files
|
||||
for file in files:
|
||||
if file and file.filename != '':
|
||||
# Create unique filename to avoid conflicts
|
||||
unique_filename = f"{uuid.uuid4()}_{file.filename}"
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
|
||||
file.save(filepath)
|
||||
|
||||
uploaded_files[session_id].append({
|
||||
'filename': unique_filename,
|
||||
'filepath': filepath,
|
||||
'original_name': file.filename
|
||||
})
|
||||
|
||||
# Convert all files
|
||||
file_count = len(uploaded_files[session_id])
|
||||
converted_count = convert_multiple_files(uploaded_files[session_id], global_filetest)
|
||||
|
||||
if file_count > 1:
|
||||
# Create ZIP file for multiple files
|
||||
zip_path = create_zip_file('convert')
|
||||
if zip_path:
|
||||
response = redirect(url_for('download_zip', session_id=session_id))
|
||||
else:
|
||||
response = redirect(url_for('index', status='Error creating ZIP file'))
|
||||
else:
|
||||
# Single file - direct download
|
||||
file_info = uploaded_files[session_id][0]
|
||||
response = redirect(url_for('download', filename=file_info['filename'])) # Use the unique filename
|
||||
|
||||
# Clean up after delay
|
||||
Timer(10, delete_files_after_delay).start()
|
||||
|
||||
# Clear session files
|
||||
if session_id in uploaded_files:
|
||||
del uploaded_files[session_id]
|
||||
|
||||
return response
|
||||
|
||||
|
||||
elif file:
|
||||
return redirect(url_for('index', status='File uploaded, but file type not selected'))
|
||||
elif 'file' in request.files:
|
||||
# Single file upload (legacy support)
|
||||
file = request.files['file']
|
||||
|
||||
if file.filename == '':
|
||||
return redirect(url_for('index', status='No file selected'))
|
||||
|
||||
if file and global_filetest is not None:
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
|
||||
file.save(filepath)
|
||||
|
||||
if convert_file(filepath, global_filetest):
|
||||
response = redirect(url_for('download', filename=file.filename))
|
||||
Timer(5, delete_files_after_delay).start()
|
||||
return response
|
||||
else:
|
||||
return redirect(url_for('index', status='Conversion failed'))
|
||||
elif file:
|
||||
return redirect(url_for('index', status='File uploaded, but file type not selected'))
|
||||
|
||||
return render_template('index.html', status=request.args.get('status'))
|
||||
|
||||
@app.route('/download/<filename>', methods=['GET'])
|
||||
def download(filename):
|
||||
global global_filetest
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
return download_file(filepath, global_filetest)
|
||||
|
||||
return download_file(filename, global_filetest)
|
||||
|
||||
@app.route('/download_zip/<session_id>', methods=['GET'])
|
||||
def download_zip(session_id):
|
||||
zip_path = os.path.join('convert', 'converted_files.zip')
|
||||
try:
|
||||
return send_file(zip_path, as_attachment=True, download_name='converted_files.zip')
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
||||
@app.route('/empfange_daten', methods=['POST'])
|
||||
def empfange_daten():
|
||||
@@ -110,8 +192,43 @@ def empfange_daten():
|
||||
daten = request.json['daten']
|
||||
global_filetest = daten
|
||||
print(f"Received data: {daten}")
|
||||
return jsonify({"status": "successfully received", "message": "Please upload files now"})
|
||||
|
||||
return jsonify({"status": "successfully received", "message": "Please upload a file now"})
|
||||
@app.route('/get_uploaded_files/<session_id>', methods=['GET'])
|
||||
def get_uploaded_files(session_id):
|
||||
if session_id in uploaded_files:
|
||||
return jsonify({
|
||||
'files': [{'original_name': f['original_name'], 'filename': f['filename']}
|
||||
for f in uploaded_files[session_id]]
|
||||
})
|
||||
return jsonify({'files': []})
|
||||
|
||||
@app.route('/remove_file', methods=['POST'])
|
||||
def remove_file():
|
||||
global uploaded_files
|
||||
session_id = request.json.get('session_id')
|
||||
filename = request.json.get('filename')
|
||||
|
||||
if session_id in uploaded_files:
|
||||
# Find and remove the file
|
||||
uploaded_files[session_id] = [
|
||||
f for f in uploaded_files[session_id]
|
||||
if f['filename'] != filename
|
||||
]
|
||||
|
||||
# Delete physical file
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
if os.path.exists(filepath):
|
||||
try:
|
||||
os.unlink(filepath)
|
||||
except Exception as e:
|
||||
print(f"Error deleting file: {e}")
|
||||
|
||||
# Clean up empty session
|
||||
if not uploaded_files[session_id]:
|
||||
del uploaded_files[session_id]
|
||||
|
||||
return jsonify({"status": "success"})
|
||||
|
||||
@app.route('/docs')
|
||||
def doc():
|
||||
@@ -122,4 +239,4 @@ def get_gruppen():
|
||||
return send_from_directory("static/data", "formats.json")
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True, host="0.0.0.0")
|
||||
app.run(debug=True, host="0.0.0.0")
|
||||
334
static/script.js
334
static/script.js
@@ -3,6 +3,8 @@ var value = "";
|
||||
var valuename = "";
|
||||
var globalfileExtension = "";
|
||||
var same = false;
|
||||
var selectedFiles = [];
|
||||
var sessionId = generateSessionId();
|
||||
|
||||
var elementsPandoc = document.getElementsByClassName("pandoc");
|
||||
var elementsExel = document.getElementsByClassName("exel");
|
||||
@@ -11,8 +13,6 @@ var elementsVideo = document.getElementsByClassName("video");
|
||||
var elementsAudio = document.getElementsByClassName("audio");
|
||||
var elementsImage = document.getElementsByClassName("image");
|
||||
|
||||
// var textGuppe = [".docx", ".txt", ".odt", ".html", ".htm", ".doc", ".epub"];
|
||||
// Oben: global definieren
|
||||
var videoGruppe = [];
|
||||
var audioGruppe = [];
|
||||
var imageGruppe = [];
|
||||
@@ -21,6 +21,12 @@ var persentGruppe = [];
|
||||
var pandocGruppe = [];
|
||||
var convertFile = [];
|
||||
|
||||
function generateSessionId() {
|
||||
return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
document.getElementById('sessionId').value = sessionId;
|
||||
|
||||
fetch("/static/data/formats.json")
|
||||
.then(res => {
|
||||
if (!res.ok) throw new Error("Fehler beim Laden der JSON-Datei");
|
||||
@@ -37,19 +43,19 @@ fetch("/static/data/formats.json")
|
||||
pandocGruppe = addDot(data.pandocGruppe);
|
||||
convertFile = addDot(data.convertFile);
|
||||
|
||||
console.log("Video-Formate:", videoGruppe);
|
||||
console.log("Formats loaded successfully");
|
||||
})
|
||||
.catch(err => console.error(err));
|
||||
|
||||
|
||||
const dropOverlay = document.getElementById('dropOverlay');
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
let dragCounter = 0;
|
||||
|
||||
// Drag and Drop
|
||||
// Drag and Drop functions
|
||||
function showOverlay() {
|
||||
dropOverlay.style.display = 'flex';
|
||||
}
|
||||
|
||||
function hideOverlay() {
|
||||
dropOverlay.style.display = 'none';
|
||||
}
|
||||
@@ -88,37 +94,20 @@ dropOverlay.addEventListener('drop', (e) => {
|
||||
dt.items.add(files[i]);
|
||||
}
|
||||
fileInput.files = dt.files;
|
||||
|
||||
if (fileInput.files.length > 0) {
|
||||
const file = fileInput.files[0];
|
||||
const fileName = file.name;
|
||||
const fileExtension = '.' + fileName.split('.').pop().toLowerCase();
|
||||
globalfileExtension = fileExtension;
|
||||
|
||||
updateFileName();
|
||||
overfeed();
|
||||
flexElemente();
|
||||
meineFunktion(fileExtension);
|
||||
}
|
||||
|
||||
handleFileSelection();
|
||||
e.dataTransfer.clearData();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
function filterFunction(dropdownClass) {
|
||||
const input = document.querySelector(`.${dropdownClass} .suche`);
|
||||
const filter = input.value.toLowerCase();
|
||||
const pElements = document.querySelectorAll(`.${dropdownClass} p`);
|
||||
|
||||
// Make all p-elements visible again first
|
||||
pElements.forEach(function (item) {
|
||||
item.style.display = "flex";
|
||||
});
|
||||
|
||||
// Then filter only the elements that match the search query
|
||||
pElements.forEach(function (item) {
|
||||
const textValue = item.textContent.toLowerCase();
|
||||
if (textValue.indexOf(filter) == -1) {
|
||||
@@ -128,7 +117,6 @@ function filterFunction(dropdownClass) {
|
||||
}
|
||||
});
|
||||
|
||||
// Execute 'meineFunktion' only if the search field is empty
|
||||
if (elementsDown2.length > 0 && window.getComputedStyle(elementsDown2[0]).display === "flex" && input.value.trim() === "") {
|
||||
console.log(globalfileExtension)
|
||||
meineFunktion(globalfileExtension);
|
||||
@@ -140,10 +128,7 @@ function setFileFunction(name, filename) {
|
||||
valuename = filename;
|
||||
console.log(value, valuename);
|
||||
|
||||
if (
|
||||
elementsDown2.length > 0 &&
|
||||
window.getComputedStyle(elementsDown2[0]).display === "flex"
|
||||
) {
|
||||
if (elementsDown2.length > 0 && window.getComputedStyle(elementsDown2[0]).display === "flex") {
|
||||
var dropbtn2 = document.getElementsByClassName("dropbtn2");
|
||||
if (dropbtn2.length > 0) {
|
||||
dropbtn2[0].innerHTML = valuename;
|
||||
@@ -153,31 +138,144 @@ function setFileFunction(name, filename) {
|
||||
return [value, valuename];
|
||||
}
|
||||
|
||||
document.getElementById('fileInput').addEventListener('change', function (event) {
|
||||
const file = event.target.files[0];
|
||||
|
||||
if (file) {
|
||||
const fileName = file.name;
|
||||
const fileExtension = '.' + fileName.split('.').pop();
|
||||
|
||||
console.log(`Dateiendung: ${fileExtension}`);
|
||||
globalfileExtension = fileExtension
|
||||
function handleFileSelection() {
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const fileLabel = document.getElementById('fileLabel');
|
||||
|
||||
if (fileInput.files.length > 0) {
|
||||
selectedFiles = Array.from(fileInput.files);
|
||||
|
||||
// Update label text
|
||||
if (selectedFiles.length === 1) {
|
||||
fileLabel.textContent = selectedFiles[0].name;
|
||||
} else {
|
||||
fileLabel.textContent = `${selectedFiles.length} files selected`;
|
||||
}
|
||||
|
||||
// Validate all files and get extensions
|
||||
let allValid = true;
|
||||
let extensions = new Set();
|
||||
let firstValidExtension = "";
|
||||
|
||||
selectedFiles.forEach(file => {
|
||||
const fileName = file.name;
|
||||
const fileExtension = '.' + fileName.split('.').pop().toLowerCase();
|
||||
extensions.add(fileExtension);
|
||||
|
||||
if (!convertFile.includes(fileExtension)) {
|
||||
allValid = false;
|
||||
} else if (firstValidExtension === "") {
|
||||
firstValidExtension = fileExtension;
|
||||
}
|
||||
});
|
||||
|
||||
if (!allValid) {
|
||||
errorMessage("Invalidfile");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if all files have the same extension (same group compatibility)
|
||||
if (extensions.size > 1) {
|
||||
// Multiple different extensions - check if they're all in the same conversion group
|
||||
let groups = [videoGruppe, audioGruppe, imageGruppe, tabelleGruppe, persentGruppe, pandocGruppe];
|
||||
let fileGroups = new Set();
|
||||
|
||||
extensions.forEach(ext => {
|
||||
let group = groups.findIndex(g => g.includes(ext));
|
||||
if (group !== -1) {
|
||||
fileGroups.add(group);
|
||||
}
|
||||
});
|
||||
|
||||
if (fileGroups.size > 1) {
|
||||
errorMessage("mixedtypes");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Use first extension for group detection
|
||||
globalfileExtension = firstValidExtension;
|
||||
|
||||
// Show file list
|
||||
updateFileList();
|
||||
overfeed();
|
||||
flexElemente();
|
||||
meineFunktion(fileExtension);
|
||||
console.log('Keine Datei ausgewählt.');
|
||||
meineFunktion(globalfileExtension);
|
||||
errorMessage("none");
|
||||
} else {
|
||||
fileLabel.textContent = 'Select Files';
|
||||
document.getElementById('fileListContainer').style.display = 'none';
|
||||
errorMessage("none");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateFileList() {
|
||||
const fileListContainer = document.getElementById('fileListContainer');
|
||||
const fileList = document.getElementById('fileList');
|
||||
|
||||
if (selectedFiles.length === 0) {
|
||||
fileListContainer.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
fileListContainer.style.display = 'block';
|
||||
fileList.innerHTML = '';
|
||||
|
||||
selectedFiles.forEach((file, index) => {
|
||||
const fileItem = document.createElement('div');
|
||||
fileItem.className = 'file-item';
|
||||
|
||||
fileItem.innerHTML = `
|
||||
<span class="file-name">${file.name}</span>
|
||||
<button class="delete-btn" onclick="removeFile(${index})" title="Remove file">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 6h18"></path>
|
||||
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path>
|
||||
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
|
||||
<line x1="10" y1="11" x2="10" y2="17"></line>
|
||||
<line x1="14" y1="11" x2="14" y2="17"></line>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
|
||||
fileList.appendChild(fileItem);
|
||||
});
|
||||
}
|
||||
|
||||
function removeFile(index) {
|
||||
selectedFiles.splice(index, 1);
|
||||
|
||||
// Update file input
|
||||
const dt = new DataTransfer();
|
||||
selectedFiles.forEach(file => {
|
||||
dt.items.add(file);
|
||||
});
|
||||
fileInput.files = dt.files;
|
||||
|
||||
// Update display
|
||||
const fileLabel = document.getElementById('fileLabel');
|
||||
if (selectedFiles.length === 0) {
|
||||
fileLabel.textContent = 'Select Files';
|
||||
document.getElementById('fileListContainer').style.display = 'none';
|
||||
} else if (selectedFiles.length === 1) {
|
||||
fileLabel.textContent = selectedFiles[0].name;
|
||||
} else {
|
||||
fileLabel.textContent = `${selectedFiles.length} files selected`;
|
||||
}
|
||||
|
||||
updateFileList();
|
||||
overfeed();
|
||||
}
|
||||
|
||||
document.getElementById('fileInput').addEventListener('change', handleFileSelection);
|
||||
|
||||
function flexElemente() {
|
||||
// Function to apply the style to all elements of a collection
|
||||
function setDisplayFlex(elements) {
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
elements[i].style.display = "flex";
|
||||
}
|
||||
}
|
||||
|
||||
// Stil anwenden
|
||||
setDisplayFlex(elementsExel);
|
||||
setDisplayFlex(elementsPPT);
|
||||
setDisplayFlex(elementsVideo);
|
||||
@@ -186,9 +284,7 @@ function flexElemente() {
|
||||
setDisplayFlex(elementsPandoc);
|
||||
}
|
||||
|
||||
|
||||
function meineFunktion(name) {
|
||||
|
||||
if (pandocGruppe.includes(name)) {
|
||||
for (var i = 0; i < elementsExel.length; i++) {
|
||||
elementsExel[i].style.display = "none";
|
||||
@@ -247,9 +343,6 @@ function meineFunktion(name) {
|
||||
for (var i = 0; i < elementsPPT.length; i++) {
|
||||
elementsPPT[i].style.display = "none";
|
||||
}
|
||||
// for (var i = 0; i < elementsAudio.length; i++) {
|
||||
// elementsAudio[i].style.display = "none";
|
||||
// }
|
||||
for (var i = 0; i < elementsImage.length; i++) {
|
||||
elementsImage[i].style.display = "none";
|
||||
}
|
||||
@@ -288,10 +381,8 @@ function meineFunktion(name) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function sendData() {
|
||||
if (same == true) {
|
||||
|
||||
if (same == true && selectedFiles.length > 0) {
|
||||
fetch('/empfange_daten', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -307,16 +398,18 @@ function sendData() {
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Success:', data);
|
||||
document.querySelector('form').submit();
|
||||
document.getElementById('uploadForm').submit();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
|
||||
} else{
|
||||
} else if (selectedFiles.length === 0) {
|
||||
errorMessage("nofiles");
|
||||
} else {
|
||||
errorMessage("nottype");
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll('.dropdown2').forEach(dropdown => {
|
||||
dropdown.addEventListener('mouseenter', () => {
|
||||
const dropdownContent = dropdown.querySelector('.dropdown-content2');
|
||||
@@ -331,78 +424,93 @@ document.querySelectorAll('.dropdown2').forEach(dropdown => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function updateFileName() {
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
const fileLabel = document.getElementById('fileLabel');
|
||||
// This function is now replaced by handleFileSelection
|
||||
// Kept for compatibility
|
||||
handleFileSelection();
|
||||
}
|
||||
|
||||
function errorMessage(element) {
|
||||
const errorElement = document.getElementById('error');
|
||||
|
||||
if (fileInput.files.length > 0) {
|
||||
const fileName = fileInput.files[0].name;
|
||||
const fileExtension = '.' + fileName.split('.').pop().toLowerCase();
|
||||
if (convertFile.includes(fileExtension)) {
|
||||
errorMessage("none");
|
||||
fileLabel.textContent = fileName;
|
||||
} else {
|
||||
// Error: Invalid file format
|
||||
fileLabel.textContent = 'Datei auswählen';
|
||||
errorMessage("Invalidfile");
|
||||
}
|
||||
} else {
|
||||
// No file selected
|
||||
fileLabel.textContent = 'Datei auswählen';
|
||||
errorMessage("none");
|
||||
if (element == "Invalidfile") {
|
||||
errorElement.innerHTML = 'Invalid file format. More details: <a href="/docs" target="_blank">Docs</a>';
|
||||
} else if (element == "notsame") {
|
||||
errorElement.innerHTML = 'Cannot be converted to the selected format.';
|
||||
} else if (element == "nottype") {
|
||||
errorElement.innerHTML = 'No target format selected';
|
||||
} else if (element == "nofiles") {
|
||||
errorElement.innerHTML = 'No files selected';
|
||||
} else if (element == "mixedtypes") {
|
||||
errorElement.innerHTML = 'All files must be of the same type (e.g., all images, all documents, etc.)';
|
||||
} else if (element == "none") {
|
||||
errorElement.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
function errorMessage(elemt) {
|
||||
const errorElement = document.getElementById('error');
|
||||
|
||||
if (elemt == "Invalidfile") {
|
||||
errorElement.innerHTML = 'Invalid file format. More details: <a href="/docs" target="_blank">Docs</a>';
|
||||
} else {
|
||||
if (elemt == "notsame") {
|
||||
errorElement.innerHTML = 'Cannot be converted to the selected format.';
|
||||
} else {
|
||||
if (elemt == "nottype") {
|
||||
errorElement.innerHTML = 'No file or type selected';
|
||||
} else {
|
||||
if (elemt == "none") {
|
||||
errorElement.innerHTML = '';
|
||||
function overfeed() {
|
||||
if (valuename !== "" && selectedFiles.length > 0) {
|
||||
let groups = [videoGruppe, audioGruppe, imageGruppe, tabelleGruppe, persentGruppe, pandocGruppe];
|
||||
let targetFormat = "." + valuename;
|
||||
let allCompatible = true;
|
||||
|
||||
// Check if all selected files are compatible with the target format
|
||||
selectedFiles.forEach(file => {
|
||||
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
||||
|
||||
let sourceGroup = groups.find(group => group.includes(fileExtension));
|
||||
let targetGroup = groups.find(group => group.includes(targetFormat));
|
||||
|
||||
if (!sourceGroup || !targetGroup || sourceGroup !== targetGroup) {
|
||||
allCompatible = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Also check if all files are in the same group (no mixing different types)
|
||||
if (allCompatible && selectedFiles.length > 1) {
|
||||
let fileGroups = new Set();
|
||||
selectedFiles.forEach(file => {
|
||||
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
||||
let groupIndex = groups.findIndex(group => group.includes(fileExtension));
|
||||
if (groupIndex !== -1) {
|
||||
fileGroups.add(groupIndex);
|
||||
}
|
||||
});
|
||||
|
||||
if (fileGroups.size > 1) {
|
||||
allCompatible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function overfeed() {
|
||||
if (valuename !== "") {
|
||||
let groups = [videoGruppe, audioGruppe, imageGruppe, tabelleGruppe, persentGruppe, pandocGruppe];
|
||||
|
||||
let var1 = "." + valuename;
|
||||
|
||||
let var1Group = groups.filter(group => group.includes(globalfileExtension));
|
||||
let var2Group = groups.filter(group => group.includes(var1));
|
||||
|
||||
// Check if var1 or globalfileExtension are invalid
|
||||
if (var1 === "" || globalfileExtension === "") {
|
||||
console.log("Error: One of the variables is empty.");
|
||||
errorMessage("notsame");
|
||||
same = false;
|
||||
return; // Exit the function early if there's an error
|
||||
}
|
||||
|
||||
if (var1Group.length > 0 && var2Group.length > 0 && var1Group[0] === var2Group[0]) {
|
||||
console.log("The variables are in the same group");
|
||||
console.log(var1, globalfileExtension);
|
||||
|
||||
if (allCompatible) {
|
||||
console.log("All files are compatible with target format");
|
||||
errorMessage("none");
|
||||
same = true;
|
||||
} else {
|
||||
console.log("The variables are in different groups.");
|
||||
console.log(var1, globalfileExtension);
|
||||
errorMessage("notsame");
|
||||
console.log("Some files are not compatible with target format or files are of different types");
|
||||
if (selectedFiles.length > 1) {
|
||||
// Check if it's a mixed types issue
|
||||
let groups = [videoGruppe, audioGruppe, imageGruppe, tabelleGruppe, persentGruppe, pandocGruppe];
|
||||
let fileGroups = new Set();
|
||||
selectedFiles.forEach(file => {
|
||||
const fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
||||
let groupIndex = groups.findIndex(group => group.includes(fileExtension));
|
||||
if (groupIndex !== -1) {
|
||||
fileGroups.add(groupIndex);
|
||||
}
|
||||
});
|
||||
|
||||
if (fileGroups.size > 1) {
|
||||
errorMessage("mixedtypes");
|
||||
} else {
|
||||
errorMessage("notsame");
|
||||
}
|
||||
} else {
|
||||
errorMessage("notsame");
|
||||
}
|
||||
same = false;
|
||||
|
||||
}
|
||||
} else {
|
||||
same = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -22,7 +22,6 @@ h1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
border-bottom: 1px solid #333;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
@@ -32,7 +31,6 @@ h1 {
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
font-size: 20px;
|
||||
/* Einheitliche Schriftgröße */
|
||||
}
|
||||
|
||||
.logo {
|
||||
@@ -61,7 +59,7 @@ h1 {
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none; /* Standardmäßig versteckt */
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
@@ -69,6 +67,7 @@ h1 {
|
||||
z-index: 1000;
|
||||
transition: background-color 0.3s, border-color 0.3s;
|
||||
}
|
||||
|
||||
.drop-overlay label {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
@@ -78,14 +77,17 @@ h1 {
|
||||
cursor: pointer;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-overlay label:hover {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.drop-overlay.highlight {
|
||||
border-color: #333;
|
||||
background-color: rgba(240, 240, 240, 0.95);
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba(51, 51, 51, 0.7);
|
||||
@@ -97,7 +99,8 @@ h1 {
|
||||
box-shadow: 0 0 0 0 rgba(51, 51, 51, 0);
|
||||
}
|
||||
}
|
||||
/* Datei-Input ausblenden */
|
||||
|
||||
/* File input hidden */
|
||||
#fileInput {
|
||||
display: none;
|
||||
}
|
||||
@@ -220,10 +223,6 @@ h1 {
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
#fileInput {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.suche {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
@@ -243,6 +242,75 @@ h1 {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/* File List Styles */
|
||||
.file-list-container {
|
||||
margin-top: 30px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.file-list-container h3 {
|
||||
color: #94EBEB;
|
||||
margin-bottom: 15px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.file-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background-color: #2A2A2A;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #3A3A3A;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background-color: #333333;
|
||||
border-color: #94EBEB;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
color: #FFFFFF;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ff4444;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
background-color: rgba(255, 68, 68, 0.1);
|
||||
color: #ff6666;
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.delete-btn svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.buttons:hover {
|
||||
transform: translateY(-2px);
|
||||
@@ -251,14 +319,12 @@ h1 {
|
||||
.dropdown2:hover .dropbtn2 {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
body {
|
||||
width: 95%;
|
||||
margin: 0 auto;
|
||||
|
||||
}
|
||||
|
||||
.main {
|
||||
@@ -304,9 +370,19 @@ h1 {
|
||||
|
||||
.dropdown2:hover .dropdown-content2 {
|
||||
overflow-y: auto;
|
||||
|
||||
}
|
||||
|
||||
.file-list-container {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 415px) {
|
||||
|
||||
@@ -23,25 +23,23 @@
|
||||
|
||||
<div class="button-container">
|
||||
<div class="button-wrapper">
|
||||
<form action="/" method="post" enctype="multipart/form-data">
|
||||
<label class="buttons" for="fileInput" id="fileLabel">Select File</label>
|
||||
<input type="file" name="file" id="fileInput" required onchange="updateFileName()">
|
||||
</div>
|
||||
<div id="dropOverlay" class="drop-overlay">
|
||||
<form action="/" method="post" enctype="multipart/form-data">
|
||||
<label for="fileInput" id="fileLabel">
|
||||
New File
|
||||
</label>
|
||||
<input type="file" name="file" id="fileInput" required onchange="updateFileName()">
|
||||
<form action="/" method="post" enctype="multipart/form-data" id="uploadForm">
|
||||
<input type="hidden" name="session_id" id="sessionId" value="">
|
||||
<label class="buttons" for="fileInput" id="fileLabel">Select Files</label>
|
||||
<input type="file" name="files" id="fileInput" multiple required onchange="handleFileSelection()">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="dropOverlay" class="drop-overlay">
|
||||
<label for="fileInput" id="fileLabel">
|
||||
Drop Files Here
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="button-wrapper dropdown2" onmouseover="meineFunktion()">
|
||||
<div class="buttons dropbtn2" onclick="event.preventDefault(); meineFunktion()" id="file">File Type
|
||||
</div>
|
||||
<div class="buttons dropbtn2" onclick="event.preventDefault(); meineFunktion()" id="file">File Type</div>
|
||||
<div class="dropdown-content2">
|
||||
<input class="suche" type="text" onkeyup="filterFunction('dropdown-content2')"
|
||||
placeholder="Search...">
|
||||
<input class="suche" type="text" onkeyup="filterFunction('dropdown-content2')" placeholder="Search...">
|
||||
<p class="ppt" onclick="setFileFunction('ppt', 'pptx')">pptx</p>
|
||||
<p class="ppt" onclick="setFileFunction('ppt', 'ppt')">ppt</p>
|
||||
<p class="ppt" onclick="setFileFunction('ppt', 'odp')">odp</p>
|
||||
@@ -112,16 +110,23 @@
|
||||
<p class="image" onclick="setFileFunction('image', 'bmp')">bmp</p>
|
||||
<p class="image" onclick="setFileFunction('image', 'tiff')">tiff</p>
|
||||
<p class="image" onclick="setFileFunction('image', 'webp')">webp</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="button-wrapper">
|
||||
<input class="buttons" type="button" value="Upload" id="submitButton" onclick="sendData()">
|
||||
<input class="buttons" type="button" value="Upload & Convert" id="submitButton" onclick="sendData()">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- File List Container -->
|
||||
<div id="fileListContainer" class="file-list-container" style="display: none;">
|
||||
<h3>Selected Files:</h3>
|
||||
<div id="fileList" class="file-list"></div>
|
||||
</div>
|
||||
|
||||
<h1 id="error"></h1>
|
||||
</div>
|
||||
|
||||
<p id="upload-status">
|
||||
{% if status %}
|
||||
{{ status }}
|
||||
|
||||
Reference in New Issue
Block a user