Start meines kleinen Projekts
Der Player läuft. Presets lassen sich erstellen, verschieben, bearbeiten und löschen. Ebenfalls gibt es bereits eine Funktion für Export und Import. Einige Sender sind bereits angelegt.
This commit is contained in:
parent
b0a195f3cd
commit
e9615937db
3 changed files with 326 additions and 0 deletions
36
index.php
Normal file
36
index.php
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?php
|
||||||
|
$senderIstAusgewaehlt = false;
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Internetradio Presets</title>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Internetradio Presets</h1>
|
||||||
|
<div class="current-station">
|
||||||
|
<span id="aktueller-sender">Aktueller Sender: <span id="current-station-name">
|
||||||
|
<?php
|
||||||
|
if ($senderIstAusgewaehlt) {
|
||||||
|
echo "Aktueller Sender: " . $senderName;
|
||||||
|
} else {
|
||||||
|
echo "Kein Sender ausgewählt";
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</span> </span>
|
||||||
|
<button class="stop-button">Stop</button>
|
||||||
|
</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>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.14.0/Sortable.min.js"></script>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
215
script.js
Normal file
215
script.js
Normal file
|
|
@ -0,0 +1,215 @@
|
||||||
|
const presets = [
|
||||||
|
{ name: "Radio SRF 1 AG/SO", url: "https://stream.srg-ssr.ch/regi_ag_so/aacp_96.m3u" },
|
||||||
|
{ name: "Radio SRF 2 Kultur", url: "https://stream.srg-ssr.ch/drs2/aacp_96.m3u" },
|
||||||
|
{ name: "Radio SRF 3", url: "https://stream.srg-ssr.ch/drs3/aacp_96.m3u" },
|
||||||
|
{ name: "Radio SRF 4 News", url: "https://stream.srg-ssr.ch/drs4news/aacp_96.m3u" },
|
||||||
|
{ name: "Radio SRF Virus", url: "https://stream.srg-ssr.ch/drsvirus/aacp_96.m3u" },
|
||||||
|
{ name: "Radio SRF Musikwelle", url: "https://stream.srg-ssr.ch/drsmw/aacp_96.m3u" },
|
||||||
|
{ name: "Radio Swiss Pop", url: "https://stream.srg-ssr.ch/rsp/aacp_96.m3u" },
|
||||||
|
{ name: "Radio Swiss Jazz", url: "https://stream.srg-ssr.ch/rsj/aacp_96.m3u" },
|
||||||
|
{ name: "Radio Swiss Classic", url: "https://stream.srg-ssr.ch/rsc_de/aacp_96.m3u" },
|
||||||
|
];
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
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.createElement('button');
|
||||||
|
exportButton.textContent = 'Presets exportieren';
|
||||||
|
exportButton.addEventListener('click', exportPresets);
|
||||||
|
document.body.appendChild(exportButton);
|
||||||
|
|
||||||
|
const importButton = document.createElement('button');
|
||||||
|
importButton.textContent = 'Presets importieren';
|
||||||
|
importButton.addEventListener('click', importPresets);
|
||||||
|
document.body.appendChild(importButton);
|
||||||
|
|
||||||
|
presets.forEach(preset => {
|
||||||
|
addNewPreset(preset.name, preset.url);
|
||||||
|
});
|
||||||
|
|
||||||
|
loadExistingPresets();
|
||||||
|
|
||||||
|
new Sortable(presetContainer, {
|
||||||
|
animation: 150,
|
||||||
|
ghostClass: 'ghost',
|
||||||
|
onEnd: () => {
|
||||||
|
savePresetOrder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function loadExistingPresets() {
|
||||||
|
const presets = JSON.parse(localStorage.getItem('presets')) || [];
|
||||||
|
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 = `
|
||||||
|
<h3>${name}</h3>
|
||||||
|
<div class="button-container">
|
||||||
|
<button class="edit-button">Bearbeiten</button>
|
||||||
|
<button class="delete-button">Löschen</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.addEventListener('click', (event) => {
|
||||||
|
if (event.target !== presetItem.querySelector('.edit-button') && event.target !== presetItem.querySelector('.delete-button')) {
|
||||||
|
playStream(url, presetItem); // Übergabe des 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 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));
|
||||||
|
}
|
||||||
|
|
||||||
|
function playStream(url, item) {
|
||||||
|
// Stoppe den aktuell laufenden Stream (falls vorhanden)
|
||||||
|
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 = function() {
|
||||||
|
alert('Fehler beim Laden des Streams: ' + url);
|
||||||
|
};
|
||||||
|
item.appendChild(audioElement); // Füge das Audio-Element zum Preset-Item hinzu
|
||||||
|
item.classList.add('playing');
|
||||||
|
|
||||||
|
currentPlayingItem = item; // Aktualisiere das aktuell spielende Element
|
||||||
|
currentStationName.textContent = item.querySelector('h3').textContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportPresets() {
|
||||||
|
const presets = JSON.parse(localStorage.getItem('presets')) || [];
|
||||||
|
const json = JSON.stringify(presets, null, 2);
|
||||||
|
|
||||||
|
const blob = new Blob([json], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'webradio_presets.json';
|
||||||
|
a.click();
|
||||||
|
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function importPresets() {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = '.json';
|
||||||
|
input.onchange = (event) => {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (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 {
|
||||||
|
alert("Ungültiges Dateiformat. Bitte eine JSON-Datei importieren.");
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
alert("Fehler beim Importieren der Presets: " + error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
const stopButton = document.querySelector('.stop-button');
|
||||||
|
const progressBar = document.getElementById('progress-bar');
|
||||||
|
const currentStationName = document.getElementById('current-station-name');
|
||||||
|
|
||||||
|
stopButton.addEventListener('click', () => {
|
||||||
|
// Stoppe den aktuellen Stream und setze currentPlayingItem zurück
|
||||||
|
if (currentPlayingItem) {
|
||||||
|
const audioElement = currentPlayingItem.querySelector('audio');
|
||||||
|
audioElement.pause();
|
||||||
|
audioElement.currentTime = 0;
|
||||||
|
currentPlayingItem.classList.remove('playing');
|
||||||
|
currentPlayingItem = null;
|
||||||
|
currentStationName.textContent = 'Kein Sender ausgewählt.';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
75
style.css
Normal file
75
style.css
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
grid-gap: 20px;
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-item {
|
||||||
|
background-color: #f1f1f1;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-item:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-item h3 {
|
||||||
|
margin: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preset-item button {
|
||||||
|
margin-left: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-preset-container {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.current-station {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#aktueller-sender {
|
||||||
|
background-color: #FFFF00;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-button {
|
||||||
|
background-color: #ff9999;
|
||||||
|
color: #fff; /* Weißer Text auf rotem Hintergrund */
|
||||||
|
font-weight: bold;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 4px 2px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stop-button:hover {
|
||||||
|
background-color: #ff4d4d; /* Dunklerer Farbton beim Hovern */
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue