diff --git a/index.js b/index.js
new file mode 100644
index 0000000..8e9d501
--- /dev/null
+++ b/index.js
@@ -0,0 +1,271 @@
+// Public Domain
+
+document.addEventListener('DOMContentLoaded', function () {
+ const presetContainer = document.getElementById('preset-container');
+ 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');
+ const openSleepTimerModalButton = document.getElementById('open-sleep-timer-modal');
+ const sleepTimerModal = document.getElementById('sleep-timer-modal');
+ const closeSleepTimerModalButton = document.getElementById('close-sleep-timer-modal');
+ const offSleepTimerModalButton = document.getElementById('off-sleep-timer-modal');
+ let currentSound = null;
+ let presets = [];
+ let sleepTimerTimeout = null;
+ let sleepTimerEndTime = null;
+
+ initializeFooter();
+ loadPresets();
+ initializeEventListeners();
+
+ function initializeFooter() {
+ const currentYear = new Date().getFullYear();
+ document.getElementById('current-year').textContent = currentYear;
+ document.getElementById('server-name').textContent = window.location.hostname;
+ }
+
+ function updateTitle(stationName) {
+ document.title = stationName ? `${stationName} - Radioplayer mit Presets` : "Radioplayer mit Presets";
+ }
+
+ function initializeEventListeners() {
+ stopButton.addEventListener('click', stopPlayback);
+ editPresetsButton.addEventListener('click', openModal);
+ }
+
+ async function loadPresets() {
+ presets = JSON.parse(localStorage.getItem('presets')) || [];
+ if (presets.length === 0) {
+ try {
+ 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();
+ }
+
+ function displayPresets(presets) {
+ presetContainer.innerHTML = '';
+ presets.forEach(preset => addNewPreset(preset.name, preset.url));
+ }
+
+ function addNewPreset(name, url) {
+ const presetItem = document.createElement('div');
+ presetItem.classList.add('preset-item');
+ presetItem.dataset.streamUrl = url;
+ presetItem.innerHTML = `
${name}
`;
+ presetItem.addEventListener('click', () => playStream(url, presetItem));
+ presetContainer.appendChild(presetItem);
+ }
+
+ function renderPresets() {
+ tableBody.innerHTML = '';
+ presets.forEach((preset, index) => {
+ const row = document.createElement('tr');
+ row.setAttribute('data-index', index);
+ row.innerHTML = `
+ ☰ |
+ |
+ |
+ |
+ `;
+ tableBody.appendChild(row);
+ });
+ }
+
+ openSleepTimerModalButton.addEventListener('click', function () {
+ sleepTimerModal.classList.remove('hidden');
+ sleepTimerModal.style.display = 'block';
+ updateOffButtonVisibility();
+ });
+
+ closeSleepTimerModalButton.addEventListener('click', function () {
+ sleepTimerModal.classList.add('hidden');
+ sleepTimerModal.style.display = 'none';
+ });
+
+ offSleepTimerModalButton.addEventListener('click', function () {
+ clearSleepTimer();
+ sleepTimerModal.classList.add('hidden');
+ sleepTimerModal.style.display = 'none';
+ });
+
+ document.querySelectorAll('.time-option').forEach(button => {
+ button.addEventListener('click', function () {
+ const timeInMilliseconds = button.getAttribute('data-time');
+ startSleepTimer(parseInt(timeInMilliseconds));
+ sleepTimerModal.classList.add('hidden');
+ sleepTimerModal.style.display = 'none';
+ });
+ });
+
+ function startSleepTimer(duration) {
+ if (sleepTimerTimeout) {
+ clearTimeout(sleepTimerTimeout);
+ }
+ sleepTimerEndTime = Date.now() + duration;
+ sleepTimerTimeout = setTimeout(() => {
+ stopPlayback();
+ updateSleepTimerButton();
+ updateOffButtonVisibility();
+ }, duration);
+ updateSleepTimerButton();
+ updateOffButtonVisibility();
+ }
+
+ function clearSleepTimer() {
+ if (sleepTimerTimeout) {
+ clearTimeout(sleepTimerTimeout);
+ sleepTimerTimeout = null;
+ sleepTimerEndTime = null;
+ openSleepTimerModalButton.textContent = 'Sleep Timer';
+ updateOffButtonVisibility();
+ }
+ }
+
+ function updateSleepTimerButton() {
+ if (sleepTimerEndTime) {
+ const remainingTime = Math.max(0, Math.ceil((sleepTimerEndTime - Date.now()) / 60000));
+ openSleepTimerModalButton.innerHTML = ` ${remainingTime} Minuten`;
+ if (remainingTime > 0) {
+ setTimeout(updateSleepTimerButton, 60000); // Update every minute
+ } else {
+ openSleepTimerModalButton.textContent = 'Sleep Timer';
+ sleepTimerEndTime = null;
+ updateOffButtonVisibility();
+ }
+ }
+ }
+
+ function updateOffButtonVisibility() {
+ if (sleepTimerTimeout) {
+ offSleepTimerModalButton.style.display = 'inline-block';
+ } else {
+ offSleepTimerModalButton.style.display = 'none';
+ }
+ }
+
+ function playStream(url, item) {
+ 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 (currentSound) {
+ currentSound.stop();
+ currentSound = null;
+ }
+ }
+
+ function openModal() {
+ presetModal.classList.remove('hidden');
+ presetModal.style.display = 'block';
+ renderPresets();
+ }
+
+ window.closeModal = function() {
+ presetModal.classList.add('hidden');
+ presetModal.style.display = 'none';
+ }
+
+ 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 = 'radio_presets.json';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ URL.revokeObjectURL(url);
+ }
+
+ window.importPreset = function() {
+ const input = document.createElement('input');
+ input.type = 'file';
+ input.accept = 'application/json';
+ input.onchange = function(event) {
+ const file = event.target.files[0];
+ if (file) {
+ const reader = new FileReader();
+ reader.onload = function(e) {
+ try {
+ const importedPresets = JSON.parse(e.target.result);
+ presets = importedPresets;
+ localStorage.setItem('presets', JSON.stringify(presets));
+ renderPresets();
+ displayPresets(presets);
+ location.reload();
+ } catch (error) {
+ alert('Fehler beim Importieren der Presets: Ungültige Datei.');
+ }
+ };
+ reader.readAsText(file);
+ }
+ };
+ input.click();
+ }
+});