Merge pull request 'Dateien nach „/“ hochladen' (#1) from simonpipe-html-version into main

Reviewed-on: https://codeberg.org/simonpipe/Radioplayer-with-Presets/pulls/1
This commit is contained in:
Simon Pipe 2024-12-22 11:16:11 +00:00
commit 2b95185b63
2 changed files with 140 additions and 85 deletions

58
index.html Normal file
View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Radioplayer mit Presets</title>
<link rel="stylesheet" href="style.css">
<link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon-16x16.png">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<script defer src="https://stats.thepipes.ch/script.js" data-website-id="9d65de5b-b789-424e-ac4c-fe51477b8eb6"></script>
</head>
<body>
<div class="header">
<div class="titel">
<img src="/img/icon.png" alt="Radioplayer" height="35" width="35">
<h1>Radioplayer</h1>
</div>
<div class="current-station">
<span id="aktueller-sender">Aktueller Sender: <span id="current-station-name">Kein Sender ausgewählt</span></span>
<button class="stop-button">Stop</button>
</div>
</div>
<div class="preset-container" id="preset-container">
</div>
<div class="new-preset-container">
<input type="text" id="new-preset-name" placeholder="Sendername">
<input type="text" id="new-preset-url" placeholder="Stream-URL">
<button id="add-new-preset">Neuen Sender hinzufügen</button>
</div>
<div class="button-container">
<button id="export-button" class="export-button">Presets exportieren</button>
<button id="import-button" class="import-button">Presets importieren</button>
</div>
<div class="preset-set">
Ein Set an Presets findest du <a href="#" id="load-presets-link">hier</a>.
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
<script src="script.js"></script>
</body>
<footer>
<div class="footer">
&copy; 2024-<span id="current-year"></span>&nbsp;<img src="/img/favicon-16x16.png" alt="Radioplayer" height="14" width="14">&nbsp;<span id="server-name"></span>&nbsp;//&nbsp;View on&nbsp;<a target="_blank" href="https://codeberg.org/simonpipe/Radioplayer-with-Presets">&nbsp;<img src="/img/codeberg_16px.ico" alt="Codeberg" height="12" width="12"> Codeberg</a>.
</div>
</footer>
</html>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Aktuelles Jahr einfügen
const currentYear = new Date().getFullYear();
document.getElementById('current-year').textContent = currentYear;
// Server-Name einfügen
const serverName = window.location.hostname;
document.getElementById('server-name').textContent = serverName;
});
</script>

165
script.js
View file

@ -1,47 +1,64 @@
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function () {
// === Abschnitt: Globale Variablen ===
const presetContainer = document.getElementById('preset-container');
const addNewPresetButton = document.getElementById('add-new-preset');
const newPresetNameInput = document.getElementById('new-preset-name');
const newPresetUrlInput = document.getElementById('new-preset-url');
let currentPlayingItem = null; // Variable zum Speichern des aktuell spielenden Elements
const exportButton = document.getElementById('export-button');
const importButton = document.getElementById('import-button');
const loadPresetsLink = document.getElementById('load-presets-link'); // Der neue Link zum Laden der Presets-Datei
exportButton.addEventListener('click', exportPresets);
importButton.addEventListener('click', importPresets);
loadPresetsLink.addEventListener('click', loadPresetsFromFile); // Event für den Link
const loadPresetsLink = document.getElementById('load-presets-link');
const stopButton = document.querySelector('.stop-button');
const currentStationName = document.getElementById('current-station-name');
let currentPlayingItem = null; // Speichert das aktuell spielende Element
// === Abschnitt: Initialisierung ===
initializeFooter();
initializeEventListeners();
loadExistingPresets();
setupSortable();
new Sortable(presetContainer, {
animation: 250,
ghostClass: 'ghost',
handle: '.move-button', // Nur das Verschieben-Symbol erlaubt das Verschieben
onEnd: () => {
savePresetOrder();
// === Funktion: Footer dynamisch aktualisieren ===
function initializeFooter() {
const currentYear = new Date().getFullYear();
const currentYearElement = document.getElementById('current-year');
if (currentYearElement) {
currentYearElement.textContent = currentYear;
}
});
addNewPresetButton.addEventListener('click', () => {
const presetName = newPresetNameInput.value.trim();
const presetUrl = newPresetUrlInput.value.trim();
if (presetName && presetUrl) {
addNewPreset(presetName, presetUrl);
savePresetToLocalStorage(presetName, presetUrl);
newPresetNameInput.value = '';
newPresetUrlInput.value = '';
} else {
alert("Bitte geben Sie einen Namen und eine URL ein.");
const serverName = window.location.hostname;
const serverNameElement = document.getElementById('server-name');
if (serverNameElement) {
serverNameElement.textContent = serverName;
}
});
}
// === Abschnitt: Event-Listener ===
function initializeEventListeners() {
exportButton.addEventListener('click', exportPresets);
importButton.addEventListener('click', importPresets);
loadPresetsLink.addEventListener('click', loadPresetsFromFile);
addNewPresetButton.addEventListener('click', () => {
const presetName = newPresetNameInput.value.trim();
const presetUrl = newPresetUrlInput.value.trim();
if (presetName && presetUrl) {
addNewPreset(presetName, presetUrl);
savePresetToLocalStorage(presetName, presetUrl);
newPresetNameInput.value = '';
newPresetUrlInput.value = '';
} else {
alert("Bitte geben Sie einen Namen und eine URL ein.");
}
});
stopButton.addEventListener('click', stopPlayback);
}
// === Funktion: Preset-Handling ===
function loadExistingPresets() {
const presets = JSON.parse(localStorage.getItem('presets')) || [];
presets.forEach(preset => {
addNewPreset(preset.name, preset.url);
});
presets.forEach(preset => addNewPreset(preset.name, preset.url));
}
function addNewPreset(name, url) {
@ -52,15 +69,9 @@ document.addEventListener('DOMContentLoaded', function() {
presetItem.innerHTML = `
<h3>${name}</h3>
<div class="button-container">
<button class="move-button">
<i class="fas fa-arrows-alt"></i> <!-- Verschieben-Symbol -->
</button>
<button class="edit-button">
<i class="fas fa-edit"></i> <!-- Stift-Symbol für Bearbeiten -->
</button>
<button class="delete-button">
<i class="fas fa-trash-alt"></i> <!-- Papierkorb-Symbol für Löschen -->
</button>
<button class="move-button"><i class="fas fa-arrows-alt"></i></button>
<button class="edit-button"><i class="fas fa-edit"></i></button>
<button class="delete-button"><i class="fas fa-trash-alt"></i></button>
</div>
`;
@ -74,17 +85,7 @@ document.addEventListener('DOMContentLoaded', function() {
deletePreset(presetItem);
});
presetItem.querySelector('.move-button').addEventListener('click', (event) => {
event.stopPropagation(); // Verhindert, dass das Verschieben-Symbol das gesamte Preset aktiviert
});
presetItem.addEventListener('click', (event) => {
if (event.target !== presetItem.querySelector('.edit-button') &&
event.target !== presetItem.querySelector('.delete-button') &&
event.target !== presetItem.querySelector('.move-button')) {
playStream(url, presetItem);
}
});
presetItem.addEventListener('click', () => playStream(url, presetItem));
presetContainer.appendChild(presetItem);
}
@ -122,6 +123,7 @@ document.addEventListener('DOMContentLoaded', function() {
localStorage.setItem('presets', JSON.stringify(presets));
}
// === Funktion: Audio-Handling ===
function playStream(url, item) {
if (currentPlayingItem) {
const currentAudio = currentPlayingItem.querySelector('audio');
@ -136,16 +138,28 @@ document.addEventListener('DOMContentLoaded', function() {
audioElement.autoplay = true;
audioElement.loop = true;
audioElement.volume = 0.5;
audioElement.onerror = function() {
alert('Fehler beim Laden des Streams: ' + url);
};
audioElement.onerror = () => alert('Fehler beim Laden des Streams: ' + url);
item.appendChild(audioElement);
item.classList.add('playing');
currentPlayingItem = item;
currentStationName.textContent = item.querySelector('h3').textContent;
}
function stopPlayback() {
if (currentPlayingItem) {
const audioElement = currentPlayingItem.querySelector('audio');
if (audioElement) {
audioElement.pause();
audioElement.currentTime = 0;
currentPlayingItem.classList.remove('playing');
currentPlayingItem = null;
currentStationName.textContent = 'Kein Sender ausgewählt.';
}
}
}
// === Funktion: Preset-Import und -Export ===
function exportPresets() {
const presets = JSON.parse(localStorage.getItem('presets')) || [];
const json = JSON.stringify(presets, null, 2);
@ -173,25 +187,15 @@ document.addEventListener('DOMContentLoaded', function() {
try {
const importedPresets = JSON.parse(e.target.result);
if (Array.isArray(importedPresets)) {
// Speichere die importierten Presets im Local Storage
localStorage.setItem('presets', JSON.stringify(importedPresets));
// Leere den Preset-Container und lade die neuen Presets
presetContainer.innerHTML = '';
importedPresets.forEach(preset => {
if (preset.name && preset.url) { // Prüfe, ob die Presets gültig sind
addNewPreset(preset.name, preset.url);
} else {
console.warn("Ungültiger Preset-Eintrag übersprungen:", preset);
}
});
importedPresets.forEach(preset => addNewPreset(preset.name, preset.url));
alert("Presets erfolgreich importiert.");
} else {
throw new Error("Das importierte Format ist ungültig. Es wird ein Array erwartet.");
throw new Error("Ungültiges Format.");
}
} catch (error) {
alert("Fehler beim Importieren der Presets: " + error.message);
alert("Fehler beim Importieren: " + error.message);
}
};
reader.readAsText(file);
@ -200,21 +204,6 @@ document.addEventListener('DOMContentLoaded', function() {
input.click();
}
const stopButton = document.querySelector('.stop-button');
const progressBar = document.getElementById('progress-bar');
const currentStationName = document.getElementById('current-station-name');
stopButton.addEventListener('click', () => {
if (currentPlayingItem) {
const audioElement = currentPlayingItem.querySelector('audio');
audioElement.pause();
audioElement.currentTime = 0;
currentPlayingItem.classList.remove('playing');
currentPlayingItem = null;
currentStationName.textContent = 'Kein Sender ausgewählt.';
}
});
function loadPresetsFromFile(event) {
event.preventDefault();
@ -231,8 +220,16 @@ document.addEventListener('DOMContentLoaded', function() {
data.forEach(preset => addNewPreset(preset.name, preset.url));
alert('Presets erfolgreich geladen.');
})
.catch(error => {
alert('Fehler beim Laden der Presets: ' + error.message);
});
.catch(error => alert('Fehler: ' + error.message));
}
// === Funktion: Sortierbare Presets ===
function setupSortable() {
new Sortable(presetContainer, {
animation: 250,
ghostClass: 'ghost',
handle: '.move-button',
onEnd: savePresetOrder
});
}
});