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:
commit
2b95185b63
2 changed files with 140 additions and 85 deletions
58
index.html
Normal file
58
index.html
Normal 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">
|
||||
© 2024-<span id="current-year"></span> <img src="/img/favicon-16x16.png" alt="Radioplayer" height="14" width="14"> <span id="server-name"></span> // View on <a target="_blank" href="https://codeberg.org/simonpipe/Radioplayer-with-Presets"> <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>
|
||||
167
script.js
167
script.js
|
|
@ -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);
|
||||
|
|
@ -160,7 +174,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
|
||||
function importPresets() {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
|
|
@ -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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue