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