Bedienoberfläche für Webradio
ulrich
2018-02-20 e15bc00949694f5b27585c200abc234761325f6f
Merge branch 'master' of https://uhilger.de/gitblit/r/web/radio-ui
6 files modified
5 files added
455 ■■■■■ changed files
README.md 170 ●●●● patch | view | raw | blame | history
app.css 2 ●●● patch | view | raw | blame | history
app.js 61 ●●●●● patch | view | raw | blame | history
beispiel.md 45 ●●●●● patch | view | raw | blame | history
data/tpl/abspieler.tpl 2 ●●● patch | view | raw | blame | history
data/tpl/dlg-abspieler-edit-form.tpl 57 ●●●● patch | view | raw | blame | history
data/tpl/dlg-abspieler-loeschen.tpl 13 ●●●●● patch | view | raw | blame | history
data/tpl/dlg-sender-edit.tpl 4 ●●● patch | view | raw | blame | history
data/tpl/dlg-sender-loeschen.tpl 13 ●●●●● patch | view | raw | blame | history
pirc.md 45 ●●●●● patch | view | raw | blame | history
radiostreams.md 43 ●●●●● patch | view | raw | blame | history
README.md
@@ -2,69 +2,27 @@
Eine Bedienoberfläche für Webradio
## Prototyp
## Funktionen
Diese Anwendung ist zur Zeit im Bau. Der aktuelle Prototyp zum Stand des Codes in diesem Repository ist hier zu sehen: [Link zum Prototyp](/data/ulrich/test/radio-ui).
## Vorgesehene Funktionen
Das radio-ui zeigt eine Übersicht von Radiosendern. Antippen eines Senders in der Übersicht spielt den Sender ab.
Das radio-ui zeigt eine Übersicht von Radiosendern. Antippen eines Senders in der Übersicht spielt den [Livestream](/gitblit/doc/web!radio-ui.git/master/radiostreams.md) des Senders ab.
Radiosender können hinzugefügt, geändert und gelöscht werden. Ein Suchfeld ermöglicht das Einschränken der Übersicht auf bestimmte Sender.
Das Abspiel-Ziel ist konfigurierbar: Ein Radionsender kann entweder auf dem Gerät abgespielt werden, auf dem das radio-ui im Browser läuft oder auf einem anderen Gerät wie z.B. einem Raspberry Pi.
Das Abspiel-Ziel ist konfigurierbar: Ein Radionsender kann entweder auf dem Gerät abgespielt werden, auf dem das radio-ui im Browser läuft oder auf einem anderen Gerät wie z.B. einem [Raspberry Pi](/gitblit/doc/web!radio-ui.git/master/pirc.md).
Zum Abspielen auf einem Raspberry Pi ist die Nutzung der Anwendung [pirc](/gitblit/docs/pirc.git) vorgesehen, die zum Spielen von Audiostreams den [omxplayer](https://elinux.org/Omxplayer) mit einer unter [Tomcat](https://de.wikipedia.org/wiki/Apache_Tomcat) laufenden Fernbedienung kombiniert, die per HTTP gesteuert werden kann.
## Protoyp, Demo
## Beispielcharakter
Das radio-ui als einzelne Webanwendung hat prototypischen Charakter, es kann für allerlei Webradio-Anwendungen die wiederverwendbare Grundlage bilden.
Neben dem praktischen Nutzen veranschaulicht das radio-ui verschiedene Aspekte des Baus von Webanwendungen:
Als reinem Client-Teil solcher Anwendungen fehlt dem radio-ui ein zentraler Anwendungskern mit Funktionen zum Speichern individueller Einstellungen an einem zentralen Ort. Die Trennung von Client und Server ist bewußt so gewählt, um einen gleichartigen Client-Teil für verschiedene Implementierungen auf der Serverseite zu ermöglichen.
+ app-layout
+ Vorlagen
+ app-menu
+ CRUD-Muster (Create, Read, Update, Delete)
Der aktuelle Stand des Codes in diesem Repository kann hier ausprobiert werden: [Link zur Demo](/data/ulrich/test/radio-ui).
Wie in der Anwendung radio-ui die obigen Themen umgesetzt sind, ist nachfolgend kurz betrachtet.
### app-layout
Das radio-ui verwendet das [app-layout](/gitblit/docs/web!app-layout.git), das mit Hilfe von HTML und CSS die Grundlage einer für Webanwendungen geeigneten Bedienoberfläche schafft.
### Nutzung von Vorlagen
Die Datei `index.html` definiert Bereiche einer HTML-Seite als `div`-Elemente, die während der Ausführung des Programmes dynamisch mit wechselnden Inhalten gefüllt werden.
Inhalte werden dabei mit Hilfe von [Mustache](https://github.com/janl/mustache.js) aus einer Vorlage und einer Inhaltsbeschreibung in [JSON](https://de.wikipedia.org/wiki/JavaScript_Object_Notation) zu [HTML](https://de.wikipedia.org/wiki/Hypertext_Markup_Language) zusammengesetzt.
Durch die Nutzung von Vorlagen lassen sich dynamische und statische Inhalte sowie deren Gestaltung und Struktur optimal und frei von Redundanzen zusammenführen.
### app-menu
Das [app-menu](/gitblit/docs/web!app-menu.git) setzt auf die Nutzung von Vorlagen auf und fügt dem radio-ui ein Menü zur Bedienung der Anwendung hinzu. Es ist zudem eingebettet in die Funktion des app-layout. Das radio-ui zeigt so den Einsatz des app-menu und mithin das Zusammenspiel von Vorlagen, app-layout und Menü am praktischen Beispiel.
### CRUD-Muster
CRUD (Create, Read, Update, Delete) ist ein häufig vorkommendes Nutzungsmuster von Anwendungen, Daten werden erzeugt, gelesen, bearbeitet und gelöscht. Bei Webanwendungen zerfällt es in einen Teil, der auf dem Server ausgeführt wird und einen, der im Browser abläuft (Bedienoberfläche).
Allein bezogen auf den Umgang mit den Daten auf der Serverseite ist das CRUD-Muster schnell umgesetzt. Eine Datenstruktur wird erzeugt, gelesen, gespeichert und gelöscht. Eine Bedienoberfläche zur Ausführung dieser Operationen erfordert allerdings mehr als nur den Anstoß der jeweiligen Operation.
Beim radio-ui wird beispielsweise mit den Daten der Radiosender auf diese Weise umgegangen. Die folgende Tabelle veranschaulicht die benötigten Funktionen.
| Operation        | Bedienoberfläche (radio-ui)           | Server  |
| ------------- |-------------| -----|
| Create      | Funktion zum Auslösen der Erstellung eines neuen Senders, Dialog zur Eingabe der Daten, Funktion zum Senden der neuen Daten  | Speichern eines neuen Senders |
| Read      | Funktion zum Abruf der Senderliste, Lesen der Senderliste, Darstellen der Liste als Kacheln      |   Ausgeben einer Liste von Sendern |
| Update | Funktion zum Auslösen der Änderung an einem Sender, Funktion zur Auswahl eines Senders aus einer Liste, Darstellen der Daten des gewählten Senders in einem Dialog zum Bearbeiten, Funktion zum Senden der Änderungen    |    Speichern von Änderungen an einem bestehenden Sender |
| Delete | Funktion zum Auslösen der Löschfunktion, Funktion zur Auswahl eines Senders oder mehrerer Sender aus einer Liste, Funktion zum Senden einer Liste zu löschender Sender, Funktion zur Absicherung gegenüber versehentlichem Löschen    |    Löschen eines Senders oder mehrerer Sender |
Die Tabelle läßt ahnen, dass der größere Aufwand zur Herstellung eines CRUD-Musters auf die Bedienoberfläche entfällt.
Mit seinen Menüfunktionen und der Art, wie mit Daten als Liste und als einzelnem Datensatz umgegangen wird sowie der Kombination dieser Funktionen mit der Verwendung von Vorlagen zeigt das radio-ui einen generischen Lösungsansatz, der sich für die Wiederverwendung in anderen Anwendungen eignet und dabei wenige Abhängigkeiten erfordert.
Code und Demo des radio-ui [veranschaulichen](/gitblit/doc/web!radio-ui.git/master/beispiel.md) zusätzlich zum praktischen Nutzen als Webradiofernbedienung verschiedene Aspekte des Baus von Webanwendungen.
## Abhängigkeiten
Zur Verwendung des radio-ui sind die folgenden Komponenten erforderlich
Neben dem Code in diesem Repository sind zur Nutzung des radio-ui die folgenden Komponenten erforderlich
+ [jQuery](http://jquery.com/)
+ [Mustache](https://github.com/janl/mustache.js)
@@ -79,89 +37,57 @@
<script src="../jslib/app-menu/app-menu.js"></script>
````
Sollen einzelne Komponenten von einem anderen Ort wie beispielsweise einem Content Delivery Network (CDN) eingebunden werden, müssen nur die obigen Einträge entsprechend angepasst werden.
Sollen einzelne Komponenten von einem anderen Ort, beispielsweise aus einem Content Delivery Network (CDN) eingebunden werden, müssen diese Einträge angepasst werden.
## Kombination von pirc und radio-ui
### Zeichensätze
Zur Verwendung des radio-ui mit [pirc](/gitblit/docs/pirc.git) kann die Anwendung radio-ui direkt auf einen Raspberry Pi installiert werden, beispielsweise ähnlich wie pirc als Webanwendung für Tomcat. Stattdessen kann radio-ui auch von einer anderen Maschine aus die pirc-Instanz auf einen Raspberry Pi aufrufen.
### Abspielen auf dem Raspberry Pi
Kommandos an [pirc](/gitblit/docs/pirc.git) werden via HTTP an die betreffende Maschine gesendet und bestehen aus einem Klassennamen `c`, einem Methodennamen `m` und einem Parameter `p`. Ein Kommando setzt sich wie folgt zusammen
1. `http://raspi:8080/` - URL der Maschine
1. `pirc/` - Name des Kontext, unter dem die Anwendung pirc läuft
1. `sys/rpc` - Service-Endpunkt der pirc-API
1. `c=de.uhilger.pirc.App` - Name der Klasse von pirc, die die Abspielmethode enthält
1. `m=abspielen` - Name der Methode zum Abspielen
1. `p=Sender-URL` - der Parameter mit dem URL zum Audiostream des Webradiosenders
Zum Aufruf des Kommandos mit dem radio-ui kann es weitgehend unverändert bleiben. Nur der Teil 6. mit dem URL des Senders muss veränderlich gestaltet sein.
#### Beispiel Abspielen
Ist die Fernbedienung pirc auf einem Raspberry Pi installiert, lautet das Kommando zum Abspielen des Webradiosenders radiobob (vgl. Senderliste weiter unten) wie folgt
Neben den obigen Komponenten werden zudem die Zeichensätze `Amethysta`, `Oswald` und `Roboto Condensed` verwendet. Sie können von Google Fonts heruntergeladen werden und sind über das Stylesheet `app.css` von folgenden Orten auf dem Server eingebunden:
````
http://raspi:8080/pirc/sys/rpc?c=de.uhilger.pirc.App&m=abspielen&p=http://bob.hoerradar.de/radiobob-live-mp3-hq&p=
/lib/fonts/Amethysta/Amethysta-Regular.ttf
/lib/fonts/Oswald/Oswald-Regular.ttf
/lib/fonts/Oswald/Oswald-Bold.ttf
/lib/fonts/Roboto_Condensed/RobotoCondensed-Regular.ttf
/lib/fonts/Roboto_Condensed/RobotoCondensed-Bold.ttf
````
Das obige Kommando geht davon aus, dass der betreffende Raspberry Pi unter dem Namen `raspi` auf Port `8080` über `HTTP` erreichbar ist und dass auf dem Pi die Anwendung pirc unter dem Kontextnamen `pirc` installiert wurde. Es bewirkt, dass auf dem betreffenden Raspberry Pi eine Instanz des omxplayer gestartet wird und diese fortlaufend den Webradio-Stream unter der angegebenen Adresse abspielt.
### Bilder
#### Beispiel Stoppen
Zu jedem Sender wird an der Bedienoberfläche des radio-ui ein Piktogramm angezeigt. In der Demo des radio-ui ist hierfür der Ordner `bilder` vorgesehen. Prinzipiell kann aber jeder Ablageort für Bilder verwendet werden. Jedem Sender ist ein URL zu einem Bild über die Datei `sender.json` zugeordnet. Der URL für ein Bild kann zur Laufzeit über die Funktion `Sender ändern` geändert werden.
Zum Stoppen des zur Zeit abgespielten Webradios dient das folgende Kommando
## Installation
Zur Verwendung des radio-ui muss dessen Code mit den Komponenen kombiniert werden, die vom radio-ui benötigt werden.
1. Code aus diesem Repository herunterladen
1. Die unter Abhängigkeiten oben angegebenen Komponenten herunterladen
1. Aus den heruntergeladenen Teilen eine Ordnerstruktur bilden
````
http://raspi:8080/sys/rpc?c=de.uhilger.pirc.App&m=kommando&p=q
radio-ui/
  hier der Inhalt aus diesem Repository
jslib/
  jquery-1.11.1/
    jquery-1.11.1.min.js
  mustache/
    mustache.min.js
  app-menu/
    hier der Inhalt aus dem app-menu-Repository
lib/
  fonts/
    Amethysta/
      Amethysta-Regular.ttf
    Oswald/
      Oswald-Regular.ttf
      Oswald-Bold.ttf
    Roboto_Condensed/
      RobotoCondensed-Regular.ttf
      RobotoCondensed-Bold-ttf
bilder/
  hier Bilder nach Wahl
````
Mit dem obigen Aufruf wird das Kommando `q` an den laufenden Prozess des omxplayer gesendet. Das bewirkt, dass der omxplayer das Abspielen stoppt und der laufende omxplayer-Prozess endet.
## Radiostreams
Nachfolgend die Adressen einiger Radiostreams
### hr3
[Livestream-Übersicht](http://www.hr3.de/service/hr3-online-hoeren,webradio-100.html)
128 kbit http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/128/stream.mp3
48 kbit http://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/48/stream.mp3
### hr info
[Livestream-Übersicht](http://www.hr-inforadio.de/livestream/index.html)
128 kBit/s http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/128/stream.mp3
48 kBit/s http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/48/stream.mp3
### radiobob
[Livestream-Übersicht](http://www.radiobob.de/radiobob/empfang/livestream)
MP3: http://bob.hoerradar.de/radiobob-live-mp3-hq
Mobile Nutzung: http://bob.hoerradar.de/aac-radiobob
#### Test der Bandbreite
Spielt man den URL 'hq' von Radiobob im Browser zeigt der Netzwerkmonitor von Linux eine Netznutzung von 24-32 kbit/s. Das ergibt die folgende Betrachtung:
+ 32    kBit/s
+ 115.20.000    Bit/Std (kBit x 3600 x 1000)
+ 13,74    MB pro Stunde (Bit : 8 : 1.024 : 1.024)
### FFH
[Livestream-Übersicht](https://www.ffh.de/musik/webradios/stream-adressen.html)
128kbps http://mp3.ffh.de/radioffh/hqlivestream.mp3
48kbps http://mp3.ffh.de/radioffh/livestream.aac
Die obige Ordnerstruktur wird auf einem HTTP-Server wie z.B. [Tomcat](https://de.wikipedia.org/wiki/Apache_Tomcat) oder [lighttpd](https://de.wikipedia.org/wiki/Lighttpd) hinterlegt und kann dann mit einem Browser aufgerufen werden.
## Noch zu erledigen
app.css
@@ -290,7 +290,7 @@
  padding-right: 0.2em;
}
.abspieler-auswahl {
.abspieler-auswahl, .abspieler-form-auswahl {
  width: 70%;
  margin-left: 0.4em;
}
app.js
@@ -5,11 +5,13 @@
var TPL_DLG_INFO = 'dlg-info';
var TPL_DLG_SENDER_NEU = 'dlg-sender-neu';
var TPL_DLG_SENDER_EDIT = 'dlg-sender-edit';
var TPL_DLG_SENDER_DEL = 'dlg-sender-del';
var TPL_SENDER_EDIT_FORM = 'sender-edit-form';
var TPL_SENDER_KACHEL = 'sender-kachel';
var TPL_ABSPIELER = 'abspieler';
var TPL_DLG_ABSPIELER_NEU = 'dlg-abspieler-neu';
var TPL_DLG_ABSPIELER_EDIT_FORM = 'dlg-abspieler-edit-form';
var TPL_DLG_ABSPIELER_DEL = 'dlg-abspieler-del';
var TPL_ABSPIELER_EINTRAG = 'abspieler-eintrag';
var templateCache = {}; // mustache templates
var prefsRendered = false;
@@ -37,11 +39,13 @@
  app_get_template('data/tpl/sender.tpl', TPL_SENDER);
  app_get_template('data/tpl/dlg-sender-neu.tpl', TPL_DLG_SENDER_NEU);
  app_get_template('data/tpl/dlg-sender-edit.tpl', TPL_DLG_SENDER_EDIT);
  app_get_template('data/tpl/dlg-sender-loeschen.tpl', TPL_DLG_SENDER_DEL);
  app_get_template('data/tpl/dlg-sender-edit-form.tpl', TPL_SENDER_EDIT_FORM);
  app_get_template('data/tpl/kachel.tpl', TPL_SENDER_KACHEL);
  app_get_template('data/tpl/abspieler.tpl', TPL_ABSPIELER);
  app_get_template('data/tpl/dlg-abspieler-neu.tpl', TPL_DLG_ABSPIELER_NEU);
  app_get_template('data/tpl/abspieler-eintrag.tpl', TPL_ABSPIELER_EINTRAG);
  app_get_template('data/tpl/dlg-abspieler-loeschen.tpl', TPL_DLG_ABSPIELER_DEL);
  app_get_template('data/tpl/dlg-abspieler-edit-form.tpl', TPL_DLG_ABSPIELER_EDIT_FORM);
  // Klicks auf das Hamburger-Menü-Icon an eine Funktion leiten
@@ -79,6 +83,7 @@
  $(".hamburger").toggleClass("is-active"); // hamburger-icon umschalten
  app_menu_toggle(); // menue oeffnen/schliessen
}
/* Abspieler und abspielen */
function app_get_abspiel_ziel() {
@@ -86,7 +91,8 @@
  var atyp = opt.attr("atyp");
  var aname = opt.text();
  var aurl = opt.attr("aurl");
  return new Abspieler(-1, aname, aurl, atyp, "", "selected");
  var zustand = opt.attr("standardzustand");
  return new Abspieler(-1, aname, aurl, atyp, "", zustand);
}
/*
@@ -137,6 +143,10 @@
  $(".abspieler-auswahl").append(html);
}
function app_abspieler_entfernen(abspieler) {
  $(".abspieler-auswahl :selected").remove();
}
/* Senderliste */
function app_kachel_anpassen(sender) {
@@ -151,6 +161,10 @@
  $("#sender").append(html);
  var kachel = $( "div[sid='" + sender.id + "']" );
  kachel.on('click', app_kachel_klick);
}
function app_kachel_entfernen(sender) {
  $( "div[sid='" + sender.id + "']" ).remove();
}
function app_kachel_klick() {
@@ -176,6 +190,19 @@
        });
        break;
      case "3":
        app_dialog_zeigen(templateCache[TPL_DLG_SENDER_DEL], s);
        /*
        $(".dlg-behaelter").html(
          Mustache.render(templateCache[TPL_DLG_SENDER_DEL], s)
        );
        */
        $('#sender-loeschen').on('click', function() {
          $('#sender-loeschen').off('click');
          app_kachel_entfernen(s);
          app_dialog_schliessen();
          app_meldung_mit_timeout('Loeschen gewaehlt ' + s.name, 1500);
        });
        //app_menue_umschalten();
        break;
      default:
        app_meldung_mit_timeout(
@@ -217,12 +244,20 @@
}
function app_sender_loeschen() {
  app_meldung_mit_timeout('Nicht implementiert: Sender loeschen.', 1500);
  senderKlickModus = "3"; // loeschen
  app_dialog_laden_und_zeigen(templateCache[TPL_DLG_SENDER_EDIT], '');
  app_menue_umschalten();
}
function app_abspieler_loeschen() {
  app_meldung_mit_timeout('Nicht implementiert: Abspieler loeschen.', 1500);
  var abspieler = app_get_abspiel_ziel();
  app_dialog_zeigen(templateCache[TPL_DLG_ABSPIELER_DEL], abspieler);
  $('#abspieler-loeschen').on('click', function() {
    $('#abspieler-loeschen').off('click');
    app_abspieler_entfernen(abspieler);
    app_dialog_schliessen();
    app_meldung_mit_timeout('Loeschen gewaehlt ' + abspieler.name, 1500);
  });
  app_menue_umschalten();
}
function app_neuer_abspieler() {
@@ -236,15 +271,29 @@
  app_menue_umschalten();
}
function app_abspieler_bearbeiten() {
  var abspieler = '';
  var abspieler = app_get_abspiel_ziel();
  app_dialog_zeigen(templateCache[TPL_DLG_ABSPIELER_EDIT_FORM], abspieler);
  //app_dialog_laden_und_zeigen(templateCache[TPL_DLG_ABSPIELER_EDIT_FORM], '');
  $("#abspieler-typ").val(abspieler.typ);
  $("#abspieler-zustand").val(abspieler.zustand);
  $('#abspieler-speichern').on('click', function() {
    $('#abspieler-speichern').off('click');
    // Aenderungen auf die Bedienoberflaeche uebernehmen
    var abspieler = app_abspieler_dialog_lesen();
    if(abspieler.zustand === 'selected') {
      $(".abspieler-auswahl").children().attr("standardzustand", "");
    }
    var opt = $(".abspieler-auswahl :selected");
    opt.attr("atyp", abspieler.typ);
    opt.attr("aurl", abspieler.url);
    opt.attr("standardzustand", abspieler.zustand);
    opt.text(abspieler.name);
    /*
      hier eine Funktion zum Speichern der Aenderungen
      hier fehlt noch eine Funktion zum Speichern
      der Aenderungen
    */
    app_dialog_schliessen();
    app_meldung_mit_timeout('Speichern gewaehlt', 1500);
  });
beispiel.md
New file
@@ -0,0 +1,45 @@
# App-Vorlage
Das [radio-ui](README.md) ist in verschiedener Hinsicht eine Vorlage für Webanwendungen.
+ Es veranschaulicht die Nutzung des app-layout
+ Es zeigt, wie Vorlagen in einer Webapp zur Vereinfachung eingesetzt werden können
+ Es nutzt das app-menu und zeigt damit, wie es für eine Steuerung von WEbapps eingesetzt wird
+ Es implementiert den Client-Teil eines CRUD-Musters (Create, Read, Update, Delete)
Die oben aufgezählten Teile sind nachfolgend erläutert.
## app-layout
Das radio-ui verwendet das [app-layout](/gitblit/docs/web!app-layout.git), das mit Hilfe von HTML und CSS die Grundlage einer für Webanwendungen geeigneten Bedienoberfläche schafft.
## Nutzung von Vorlagen
Die Datei `index.html` definiert Bereiche einer HTML-Seite als `div`-Elemente, die während der Ausführung des Programmes dynamisch mit wechselnden Inhalten gefüllt werden.
Inhalte werden dabei mit Hilfe von [Mustache](https://github.com/janl/mustache.js) aus einer Vorlage und einer Inhaltsbeschreibung in [JSON](https://de.wikipedia.org/wiki/JavaScript_Object_Notation) zu [HTML](https://de.wikipedia.org/wiki/Hypertext_Markup_Language) zusammengesetzt.
Durch die Nutzung von Vorlagen lassen sich dynamische und statische Inhalte sowie deren Gestaltung und Struktur optimal und frei von Redundanzen zusammenführen.
## app-menu
Das [app-menu](/gitblit/docs/web!app-menu.git) setzt auf die Nutzung von Vorlagen auf und fügt dem radio-ui ein Menü zur Bedienung der Anwendung hinzu. Es ist zudem eingebettet in die Funktion des app-layout. Das radio-ui zeigt so den Einsatz des app-menu und mithin das Zusammenspiel von Vorlagen, app-layout und Menü am praktischen Beispiel.
## CRUD-Muster
CRUD (Create, Read, Update, Delete) ist ein häufig vorkommendes Nutzungsmuster von Anwendungen, Daten werden erzeugt, gelesen, bearbeitet und gelöscht. Bei Webanwendungen zerfällt es in einen Teil, der auf dem Server ausgeführt wird und einen, der im Browser abläuft (Bedienoberfläche).
Allein bezogen auf den Umgang mit den Daten auf der Serverseite ist das CRUD-Muster schnell umgesetzt. Eine Datenstruktur wird erzeugt, gelesen, gespeichert und gelöscht. Eine Bedienoberfläche zur Ausführung dieser Operationen erfordert allerdings mehr als nur den Anstoß der jeweiligen Operation.
Beim radio-ui wird beispielsweise mit den Daten der Radiosender auf diese Weise umgegangen. Die folgende Tabelle veranschaulicht die benötigten Funktionen.
| Operation        | Bedienoberfläche (radio-ui)           | Server  |
| ------------- |-------------| -----|
| Create      | Funktion zum Auslösen der Erstellung eines neuen Senders, Dialog zur Eingabe der Daten, Funktion zum Senden der neuen Daten  | Speichern eines neuen Senders |
| Read      | Funktion zum Abruf der Senderliste, Lesen der Senderliste, Darstellen der Liste als Kacheln      |   Ausgeben einer Liste von Sendern |
| Update | Funktion zum Auslösen der Änderung an einem Sender, Funktion zur Auswahl eines Senders aus einer Liste, Darstellen der Daten des gewählten Senders in einem Dialog zum Bearbeiten, Funktion zum Senden der Änderungen    |    Speichern von Änderungen an einem bestehenden Sender |
| Delete | Funktion zum Auslösen der Löschfunktion, Funktion zur Auswahl eines Senders oder mehrerer Sender aus einer Liste, Funktion zum Senden einer Liste zu löschender Sender, Funktion zur Absicherung gegenüber versehentlichem Löschen    |    Löschen eines Senders oder mehrerer Sender |
Die Tabelle läßt ahnen, dass der größere Aufwand zur Herstellung eines CRUD-Musters auf die Bedienoberfläche entfällt.
Mit seinen Menüfunktionen und der Art, wie mit Daten als Liste und als einzelnem Datensatz umgegangen wird sowie der Kombination dieser Funktionen mit der Verwendung von Vorlagen zeigt das radio-ui einen generischen Lösungsansatz, der sich für die Wiederverwendung in anderen Anwendungen eignet und dabei wenige Abhängigkeiten erfordert.
data/tpl/abspieler.tpl
@@ -2,7 +2,7 @@
<select name="abspieler" size="1" class="abspieler-auswahl">
  {{#abspielerliste}}
    {{#inhalt}}
    <option {{abspielerzustand}} atyp="{{abspielertyp}}" aurl="{{abspielerurl}}">{{abspielername}}</option>
    <option {{abspielerzustand}} standardzustand="{{abspielerzustand}}" atyp="{{abspielertyp}}" aurl="{{abspielerurl}}">{{abspielername}}</option>
    {{/inhalt}}
  {{/abspielerliste}}
</select>
data/tpl/dlg-abspieler-edit-form.tpl
@@ -1,27 +1,32 @@
<div class="dlg-abspieler-titel">Abspieler bearbeiten</div>
<form>
  <input value="{{id}}" id="abspieler-id" name="abspieler-id" type="hidden"
      class="abspieler-eingabe"></br>
  <label class="inline-label">Name:</label>
  <input value="{{name}}" id="abspieler-name" name="abspieler-name" placeholder="Name"
      type="text" class="abspieler-eingabe"></br>
  <label class="inline-label">Bild:</label>
  <input value="{{logo}}" id="abspieler-bild" name="abspieler-bild" placeholder="Bild"
      type="text" class="abspieler-eingabe"></br>
  <label class="inline-label">URL:</label>
  <input value="{{url}}" id="abspieler-url"  name="abspieler-url" placeholder="URL"
      type="text" class="abspieler-eingabe"></br>
  <label class="inline-label">Typ:</label>
  <select id="abspieler-typ" size="1" class="abspieler-auswahl">
    <option value="lokal">lokal</option>
    <option value="pirc">pirc</option>
  </select></br>
  <label class="inline-label">Zustand:</label>
  <select id="abspieler-zustand" size="1" class="abspieler-auswahl">
    <option value="">nicht ausgew&auml;hlt</option>
    <option value="selected">ausgew&auml;hlt</option>
  </select></br>
  <div class="form-button-footer">
    <button type="button" id="abspieler-speichern">Speichern</button>
<div class="dlg-sender-edit">
  <span class="close-btn pointer-cursor">&#10006;</span>
  <div class="dlg-behaelter">
    <div class="dlg-abspieler-titel">Abspieler bearbeiten</div>
    <form>
      <input value="{{id}}" id="abspieler-id" name="abspieler-id" type="hidden"
          class="abspieler-eingabe"></br>
      <label class="inline-label">Name:</label>
      <input value="{{name}}" id="abspieler-name" name="abspieler-name" placeholder="Name"
          type="text" class="abspieler-eingabe"></br>
      <!-- <label class="inline-label">Bild:</label> -->
      <input value="{{logo}}" id="abspieler-bild" name="abspieler-bild" placeholder="Bild"
          type="text" class="abspieler-eingabe" type="hidden"></br>
      <label class="inline-label">URL:</label>
      <input value="{{url}}" id="abspieler-url"  name="abspieler-url" placeholder="URL"
          type="text" class="abspieler-eingabe"></br>
      <label class="inline-label">Typ:</label>
      <select id="abspieler-typ" size="1" class="abspieler-form-auswahl">
        <option value="lokal">lokal</option>
        <option value="pirc">pirc</option>
      </select></br>
      <label class="inline-label">Zustand:</label>
      <select id="abspieler-zustand" size="1" class="abspieler-form-auswahl">
        <option value="">nicht ausgew&auml;hlt</option>
        <option value="selected">ausgew&auml;hlt</option>
      </select></br>
      <div class="form-button-footer">
        <button type="button" id="abspieler-speichern">Speichern</button>
      </div>
    </form>
  </div>
</form>
</div>
data/tpl/dlg-abspieler-loeschen.tpl
New file
@@ -0,0 +1,13 @@
<div class="nachricht">
  <span class="close-btn pointer-cursor">&#10006;</span>
  <div class="dlg-behaelter">
    <div class="dlg-info-app-info">
      Wollen Sie den Abspieler <br/>
      <b><i>{{name}}</i></b><br/>
      wirklich l&ouml;schen?
    </div>
    <div class="form-button-footer">
      <button type="button" id="abspieler-loeschen">L&ouml;schen</button>
    </div>
  </div>
</div>
data/tpl/dlg-sender-edit.tpl
@@ -1,6 +1,8 @@
<div class="dlg-sender-edit">
  <span class="close-btn pointer-cursor">&#10006;</span>
  <div class="dlg-behaelter">
    <div class="dlg-sender-text">Sender zum Bearbeiten antippen...</div>
    <div class="dlg-sender-text">
      Sender zum Bearbeiten oder L&ouml;schen antippen...
    </div>
  </div>
</div>
data/tpl/dlg-sender-loeschen.tpl
New file
@@ -0,0 +1,13 @@
<div class="nachricht">
  <span class="close-btn pointer-cursor">&#10006;</span>
  <div class="dlg-behaelter">
    <div class="dlg-info-app-info">
      Wollen Sie den Sender<br/>
      <b><i>{{name}}</i></b><br/>
      wirklich l&ouml;schen?
    </div>
    <div class="form-button-footer">
      <button type="button" id="sender-loeschen">L&ouml;schen</button>
    </div>
  </div>
</div>
pirc.md
New file
@@ -0,0 +1,45 @@
# Radio abspielen mit dem Raspberry Pi
Das [radio-ui](README.md) kann verwendet werden, um den Livestream eines Radiosenders von einem Raspberry Pi wiedergeben zu lassen. Hierzu wird auf dem betreffenden Raspberry Pi die Anwendung [pirc](/gitblit/docs/pirc.git) genutzt. Pirc kombiniert zum Spielen von Audiostreams den [omxplayer](https://elinux.org/Omxplayer) mit einer auf [Tomcat](https://de.wikipedia.org/wiki/Apache_Tomcat) laufenden Fernbedienung, die per HTTP gesteuert werden kann.
Auf dieser Seite ist beschrieben, wie pirc aus dem radio-ui heraus genutzt und mithin das Abspielen von Webradio auf dem Raspberry Pi bewerkstelligt werden kann.
## Kombination von pirc und radio-ui
Zur Verwendung des radio-ui mit [pirc](/gitblit/docs/pirc.git) kann die Anwendung radio-ui direkt auf einen Raspberry Pi installiert werden, beispielsweise ähnlich wie pirc als Webanwendung für Tomcat. Stattdessen kann radio-ui auch von einer anderen Maschine aus die pirc-Instanz auf einen Raspberry Pi aufrufen.
In beiden Fällen sendet das radio-ui Kommandos via HTTP an pirc wie nachfolgend beschrieben.
## Kommandos an den Raspberry Pi
Wird [pirc](/gitblit/docs/pirc.git) auf dem Raspberry Pi ausgeführt, können Kommandos via HTTP an die betreffende Maschine gesendet werden. Sie bestehen aus einem Klassennamen `c`, einem Methodennamen `m` und Parametern `p`. Ein Kommando setzt sich wie folgt zusammen
1. `http://raspi:8080/` - URL der Maschine
1. `pirc/` - Name des Kontext, unter dem die Anwendung pirc läuft
1. `sys/rpc` - Service-Endpunkt der pirc-API
1. `c=de.uhilger.pirc.App` - Name der Klasse von pirc, die die Abspielmethode enthält
1. `m=abspielen` - Name der Methode zum Abspielen
1. `p=Sender-URL` - der Parameter mit dem URL zum Audiostream des Webradiosenders
1. `p=` - optionaler Token zur Authentisierung (kann hier leer bleiben)
Das obige Beispiel geht davon aus, dass der betreffende Raspberry Pi unter dem Namen `raspi` auf Port `8080` über `HTTP` erreichbar ist und dass auf dem Pi die Anwendung pirc unter dem Kontextnamen `pirc` installiert wurde. Zum Aufruf mit dem radio-ui kann das obige Kommando weitgehend unverändert bleiben. Nur der Teil 6. mit dem URL des Senders muss veränderlich gestaltet sein.
### Abspielen
Das Kommando zum Abspielen des Livestreams des Radiosenders radiobob (vgl. [Senderliste](radiostreams.md)) lautet z.B. wie folgt
````
http://raspi:8080/pirc/sys/rpc?c=de.uhilger.pirc.App&m=abspielen&p=http://bob.hoerradar.de/radiobob-live-mp3-hq&p=
````
Es bewirkt, dass auf dem betreffenden Raspberry Pi eine Instanz des [omxplayer](https://elinux.org/Omxplayer) gestartet wird und diese fortlaufend den Webradio-Stream unter der angegebenen Adresse abspielt.
### Stoppen
Zum Stoppen des zur Zeit abgespielten Webradios dient das folgende Kommando
````
http://raspi:8080/sys/rpc?c=de.uhilger.pirc.App&m=kommando&p=q
````
Mit dem obigen Aufruf wird das Kommando `q` an den auf dem Raspberry Pi laufenden Abspielprozess gesendet. Das bewirkt, dass der im Abspielprozess laufende [omxplayer](https://elinux.org/Omxplayer) das Abspielen stoppt und der Prozess endet.
radiostreams.md
New file
@@ -0,0 +1,43 @@
# Radiostreams
Nachfolgend die Adressen einiger Radiostreams, die vom [radio-ui](README.md) verwendet werden können.
## hr3
[Livestream-Übersicht](http://www.hr3.de/service/hr3-online-hoeren,webradio-100.html)
128 kbit http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/128/stream.mp3
48 kbit http://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/48/stream.mp3
## hr info
[Livestream-Übersicht](http://www.hr-inforadio.de/livestream/index.html)
128 kBit/s http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/128/stream.mp3
48 kBit/s http://hr-hrinfo-live.cast.addradio.de/hr/hrinfo/live/mp3/48/stream.mp3
## radiobob
[Livestream-Übersicht](http://www.radiobob.de/radiobob/empfang/livestream)
MP3: http://bob.hoerradar.de/radiobob-live-mp3-hq
Mobile Nutzung: http://bob.hoerradar.de/aac-radiobob
### Test der Bandbreite
Spielt man den URL 'hq' von Radiobob im Browser zeigt der Netzwerkmonitor von Linux eine Netznutzung von 24-32 kbit/s. Das ergibt die folgende Betrachtung:
+ 32    kBit/s
+ 115.20.000    Bit/Std (kBit x 3600 x 1000)
+ 13,74    MB pro Stunde (Bit : 8 : 1.024 : 1.024)
## FFH
[Livestream-Übersicht](https://www.ffh.de/musik/webradios/stream-adressen.html)
128kbps http://mp3.ffh.de/radioffh/hqlivestream.mp3
48kbps http://mp3.ffh.de/radioffh/livestream.aac