Multiple File Converting

This commit is contained in:
Benzauber
2025-08-09 14:02:43 +00:00
parent 48a6e6b760
commit b8701313e6
4 changed files with 490 additions and 184 deletions

203
index.py
View File

@@ -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")

View File

@@ -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;
}
};
}

View File

@@ -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) {

View File

@@ -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 }}