script.js aktualisiert

Neuer Modus um die Presets zu bearbeiten
This commit is contained in:
simonpipe 2025-04-02 13:59:47 +00:00
parent 65d63a9a6a
commit d86e682db5

336
script.js
View file

@ -1,107 +1,51 @@
document.addEventListener('DOMContentLoaded', function () {
// === Abschnitt: Globale Variablen ===
const presetContainer = document.getElementById('preset-container');
const newPresetForm = document.getElementById('new-preset-form');
const newPresetNameInput = document.getElementById('new-preset-name');
const newPresetUrlInput = document.getElementById('new-preset-url');
const exportButton = document.getElementById('export-button');
const importButton = document.getElementById('import-button');
const loadPresetsLink = document.getElementById('load-presets-link');
const stopButton = document.querySelector('.stop-button');
const currentStationName = document.getElementById('current-station-name');
const presetModal = document.getElementById('preset-modal');
const tableBody = document.querySelector('#sortable-tbody');
const editPresetsButton = document.getElementById('edit-presets-button');
let currentPlayingItem = null; // Speichert das aktuell spielende Element
let currentSound = null;
let presets = [];
// === Abschnitt: Initialisierung ===
initializeFooter();
loadPresets();
initializeEventListeners();
loadExistingPresets();
setupSortable();
// === Funktion: Footer dynamisch aktualisieren ===
function initializeFooter() {
const currentYear = new Date().getFullYear();
const currentYearElement = document.getElementById('current-year');
if (currentYearElement) {
currentYearElement.textContent = currentYear;
document.getElementById('current-year').textContent = currentYear;
document.getElementById('server-name').textContent = window.location.hostname;
}
const serverName = window.location.hostname;
const serverNameElement = document.getElementById('server-name');
if (serverNameElement) {
serverNameElement.textContent = serverName;
}
}
// === Funktion: Titel dynamisch ändern ===
function updateTitle(stationName) {
if (stationName) {
document.title = `${stationName} - Radioplayer mit Presets`;
} else {
document.title = "Radioplayer mit Presets";
}
document.title = stationName ? `${stationName} - Radioplayer mit Presets` : "Radioplayer mit Presets";
}
// === Abschnitt: Event-Listener ===
function initializeEventListeners() {
newPresetForm.addEventListener('submit', (event) => {
event.preventDefault(); // Verhindert die Standardaktion (Seiten-Reload)
const presetName = newPresetNameInput.value.trim();
const presetUrl = newPresetUrlInput.value.trim();
if (!presetName || !presetUrl) {
alert("Bitte geben Sie einen Namen und eine URL ein.");
return;
}
if (!isValidHttpUrl(presetUrl)) {
alert("Bitte geben Sie eine gültige HTTP- oder HTTPS-URL ein.");
return;
}
addNewPreset(presetName, presetUrl);
savePresetToLocalStorage(presetName, presetUrl);
newPresetNameInput.value = '';
newPresetUrlInput.value = '';
});
exportButton.addEventListener('click', exportPresets);
importButton.addEventListener('click', importPresets);
loadPresetsLink.addEventListener('click', loadPresetsFromFile);
stopButton.addEventListener('click', stopPlayback);
// Event-Listener für den "Presets bearbeiten"-Button
editPresetsButton.addEventListener('click', () => {
toggleEditMode();
const isPressed = editPresetsButton.getAttribute('aria-pressed') === 'true';
editPresetsButton.setAttribute('aria-pressed', !isPressed);
});
editPresetsButton.addEventListener('click', openModal);
}
// === Funktion: URL-Validierung ===
function isValidHttpUrl(url) {
async function loadPresets() {
presets = JSON.parse(localStorage.getItem('presets')) || [];
if (presets.length === 0) {
try {
const parsedUrl = new URL(url);
return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:";
} catch (e) {
return false;
const response = await fetch('webradio_presets.json');
if (!response.ok) throw new Error('Datei konnte nicht geladen werden');
presets = await response.json();
localStorage.setItem('presets', JSON.stringify(presets));
} catch (error) {
alert('Fehler beim Laden der Presets: ' + error.message);
}
}
displayPresets(presets);
renderPresets();
initSortable();
}
// Funktion zum Ein- und Ausblenden der Bearbeitungsbuttons
function toggleEditMode() {
const presetItems = document.querySelectorAll('.preset-item');
presetItems.forEach(item => {
const buttons = item.querySelectorAll('.edit-button, .delete-button, .move-button');
buttons.forEach(button => button.classList.toggle('hidden'));
});
}
// === Funktion: Preset-Handling ===
function loadExistingPresets() {
const presets = JSON.parse(localStorage.getItem('presets')) || [];
function displayPresets(presets) {
presetContainer.innerHTML = '';
presets.forEach(preset => addNewPreset(preset.name, preset.url));
}
@ -109,177 +53,139 @@ document.addEventListener('DOMContentLoaded', function () {
const presetItem = document.createElement('div');
presetItem.classList.add('preset-item');
presetItem.dataset.streamUrl = url;
presetItem.innerHTML = `
<h3>${name}</h3>
<div class="button-container">
<button class="move-button hidden" aria-label="Verschieben" title="Verschieben"><i class="fas fa-arrows-alt" style="color:grey"></i></button>
<button class="edit-button hidden" aria-label="Bearbeiten" title="Bearbeiten"><i class="fas fa-edit" style="color:grey"></i></button>
<button class="delete-button hidden" aria-label="Löschen" title="Löschen"><i class="fas fa-trash-alt" style="color:grey"></i></button>
</div>
`;
presetItem.querySelector('.edit-button').addEventListener('click', (event) => {
event.stopPropagation();
editPreset(presetItem, name, url);
});
presetItem.querySelector('.delete-button').addEventListener('click', (event) => {
event.stopPropagation();
deletePreset(presetItem);
});
presetItem.innerHTML = `<h3>${name}</h3>`;
presetItem.addEventListener('click', () => playStream(url, presetItem));
presetContainer.appendChild(presetItem);
}
function editPreset(item, currentName, currentUrl) {
const newName = prompt("Neuer Name:", currentName);
const newUrl = prompt("Neue URL:", currentUrl);
if (newName !== null && newUrl !== null) {
item.querySelector('h3').textContent = newName;
item.dataset.streamUrl = newUrl;
savePresetOrder();
}
function renderPresets() {
tableBody.innerHTML = '';
presets.forEach((preset, index) => {
const row = document.createElement('tr');
row.setAttribute('data-index', index);
row.innerHTML = `
<td class="drag-handle"></td>
<td><input type="text" value="${preset.name}" onchange="changeName(${index}, this.value)"></td>
<td><input type="text" value="${preset.url}" onchange="changeURL(${index}, this.value)"></td>
<td><button class="delete-btn" onclick="deletePreset(${index})"><i class="fas fa-trash-alt" style="color:grey"></i></button></td>
`;
tableBody.appendChild(row);
});
}
function deletePreset(item) {
if (confirm("Möchten Sie diesen Sender wirklich löschen?")) {
presetContainer.removeChild(item);
savePresetOrder();
}
}
function savePresetToLocalStorage(name, url) {
const presets = JSON.parse(localStorage.getItem('presets')) || [];
presets.push({ name, url });
localStorage.setItem('presets', JSON.stringify(presets));
}
function savePresetOrder() {
const presetItems = Array.from(presetContainer.children);
const presets = presetItems.map(item => ({
name: item.querySelector('h3').textContent,
url: item.dataset.streamUrl
}));
localStorage.setItem('presets', JSON.stringify(presets));
}
// === Funktion: Audio-Handling ===
function playStream(url, item) {
if (currentPlayingItem) {
const currentAudio = currentPlayingItem.querySelector('audio');
if (currentAudio) {
currentAudio.pause();
currentAudio.remove();
}
currentPlayingItem.classList.remove('playing');
}
const audioElement = new Audio(url);
audioElement.autoplay = true;
audioElement.loop = true;
audioElement.volume = 0.5;
audioElement.onerror = () => alert('Fehler beim Laden des Streams: ' + url);
item.appendChild(audioElement);
item.classList.add('playing');
currentPlayingItem = item;
currentStationName.textContent = 'Es läuft: ' + item.querySelector('h3').textContent;
stopButton.classList.remove('hidden'); // Stopp-Button einblenden
stopPlayback();
currentSound = new Howl({
src: [url],
html5: true,
volume: 0.5,
onplay: () => {
stopButton.classList.remove('hidden');
updateTitle(item.querySelector('h3').textContent);
currentStationName.textContent = 'Es läuft: ' + item.querySelector('h3').textContent;
},
onstop: () => {
stopButton.classList.add('hidden');
currentStationName.textContent = 'Wähle einen Sender aus';
updateTitle('');
}
});
currentSound.play();
}
function stopPlayback() {
if (currentPlayingItem) {
const audioElement = currentPlayingItem.querySelector('audio');
if (audioElement) {
audioElement.pause();
audioElement.currentTime = 0;
currentPlayingItem.classList.remove('playing');
currentPlayingItem = null;
currentStationName.textContent = 'Wähle einen Sender aus';
if (currentSound) {
currentSound.stop();
currentSound = null;
}
}
stopButton.classList.add('hidden'); // Stopp-Button ausblenden
updateTitle('');
function openModal() {
presetModal.classList.remove('hidden');
presetModal.style.display = 'block';
renderPresets();
}
// === Funktion: Preset-Import und -Export ===
function exportPresets() {
const presets = JSON.parse(localStorage.getItem('presets')) || [];
const json = JSON.stringify(presets, null, 2);
window.closeModal = function() {
presetModal.classList.add('hidden');
presetModal.style.display = 'none';
}
const blob = new Blob([json], { type: 'application/json' });
window.addPreset = function() {
presets.push({ name: 'Neuer Sender', url: '' });
renderPresets();
}
window.changeName = function(index, newName) {
presets[index].name = newName;
}
window.changeURL = function(index, newURL) {
presets[index].url = newURL;
}
window.deletePreset = function(index) {
presets.splice(index, 1);
renderPresets();
}
window.saveAndClose = function() {
savePresets();
closeModal();
location.reload();
}
function savePresets() {
localStorage.setItem('presets', JSON.stringify(presets));
}
function initSortable() {
const sortable = new Sortable(tableBody, {
handle: '.drag-handle',
animation: 150,
onEnd: function (evt) {
const newOrder = Array.from(tableBody.children).map(row => parseInt(row.getAttribute('data-index')));
presets = newOrder.map(index => presets[index]);
}
});
}
window.exportPreset = function() {
const presetsJSON = JSON.stringify(presets, null, 2);
const blob = new Blob([presetsJSON], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'webradio_presets.json';
a.download = 'radio_presets.json';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function importPresets() {
window.importPreset = function() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.addEventListener('change', (event) => {
input.accept = 'application/json';
input.onchange = function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
reader.onload = function(e) {
try {
const importedPresets = JSON.parse(e.target.result);
if (Array.isArray(importedPresets)) {
localStorage.setItem('presets', JSON.stringify(importedPresets));
presetContainer.innerHTML = '';
importedPresets.forEach(preset => addNewPreset(preset.name, preset.url));
alert("Presets erfolgreich importiert.");
} else {
throw new Error("Ungültiges Format.");
}
presets = importedPresets;
localStorage.setItem('presets', JSON.stringify(presets));
renderPresets();
displayPresets(presets);
location.reload();
} catch (error) {
alert("Fehler beim Importieren: " + error.message);
alert('Fehler beim Importieren der Presets: Ungültige Datei.');
}
};
reader.readAsText(file);
}
});
};
input.click();
}
function loadPresetsFromFile(event) {
event.preventDefault();
fetch('/webradio_presets.json')
.then(response => {
if (!response.ok) {
throw new Error('Datei konnte nicht geladen werden');
}
return response.json();
})
.then(data => {
localStorage.setItem('presets', JSON.stringify(data));
presetContainer.innerHTML = '';
data.forEach(preset => addNewPreset(preset.name, preset.url));
alert('Presets erfolgreich geladen.');
})
.catch(error => alert('Fehler: ' + error.message));
}
// === Funktion: Sortierbare Presets ===
function setupSortable() {
new Sortable(presetContainer, {
animation: 250,
ghostClass: 'ghost',
handle: '.move-button',
onEnd: savePresetOrder
});
}
});