Persoenliche Mediazentrale
undisclosed
2023-01-23 03b95f100b605458e5bf2995e955882d9aa51868
commit | author | age
b379f5 1 function Mediazentrale() {
cfa858 2   var self = this;
U 3   var appMenu;
4   var cache; // mustache templates
86bbf7 5   var ortPfad;
U 6   var mediaPfad;
1c3232 7   //var katUrl;
U 8   //var selTitel;
78d707 9   var katName;
f9dd4f 10   var playingIndex;
U 11   var audioCtx;
12   var playState; // 'pause' oder 'play' oder 'stop'
13   var audioElem;
a6081c 14   var playingList;
f45e20 15
U 16   this.init = function () {
17     self.mediaPfad = '/';
18     self.ortPfad = '/';
19     self.cache = new Array();
20     self.appMenu = new AppMenu();
21     self.appMenu.init(
22             "data/menu/",
23             "hauptmenue.json",
78d707 24             "data/tpl/app-menu.txt",
f45e20 25             ".west",
0866ae 26             "6em");
f45e20 27
U 28     document.querySelector('.hamburger').addEventListener('click', function (e) {
29       self.menue_umschalten();
30     });
31     
32     self.addEvtListener('#mi-katalog', 'click', self.media_liste);
33     self.addEvtListener('#mi-orte', 'click', self.ablageort_liste);
34     self.addEvtListener('#mi-prefs', 'click', self.prefs_liste);
35     self.addEvtListener('#mi-player', 'click', self.abspieler_liste);
8d7d35 36     self.addEvtListener('#mi-listen', 'click', self.abspielliste_liste);
U 37     self.addEvtListener('#mi-list', 'click', self.titel_liste);
d027b5 38     self.addEvtListener('#mi-live', 'click', self.livestream_liste);
3929b0 39     self.addEvtListener('#mi-devices', 'click', self.geraet_liste);
a27c68 40     self.addEvtListener('#mi-switch', 'click', self.geraet_schalt_liste);
f45e20 41     
U 42     self.fusszeile_umschalten();
43     self.seitenleiste_umschalten();
f9dd4f 44     self.dialog_unten_zeigen();    
f45e20 45   };
1c3232 46     
8d7d35 47   /* ---------------- Entitaets-Listen ----------------- */
d027b5 48   
U 49   this.livestream_selection = function() {
50     document.querySelector('.breadcrumb-behaelter').textContent = '';
51     document.querySelector('.bereich-name').textContent = 'Livestream-Auswahl'; 
960359 52     self.http_get('api/store/Livestream/liste/', function(responseText) {
2af7d6 53       self.html_erzeugen("data/tpl/livestream_liste.txt", JSON.parse(responseText), function (html) {
d027b5 54         document.querySelector(".zentraler-inhalt").innerHTML = html;
U 55         self.addEvtListener('.entity-eintrag', 'click', function (event) {
56           var t = event.target;
57           self.removeClassMulti('selected');
58           t.classList.add('selected');          
59         });
60       });
61     });
62   };
8d7d35 63
86bbf7 64   // auf der obersten Ebene werden die Kataloge angezeigt,
U 65   // darunter der Inhalt des aktuellen Pfades
66   this.media_liste = function() {
78d707 67     self.reset_top_buttons(); 
095119 68     //console.log("ortPfad: " + self.ortPfad + ", mediaPfad: " + self.mediaPfad);
78d707 69     document.querySelector('.bereich-name').textContent = '';    
86bbf7 70     if(self.ortPfad === '/') {
78d707 71       var bb = document.querySelector('.breadcrumb-behaelter');
U 72       bb.textContent = "Kataloge";
86bbf7 73       // Kataloge listen
960359 74       self.http_get('api/store/Ablageort/liste/', function (responseText) {
8d7d35 75         //document.querySelector('#top-up-btn').removeEventListener('click', self.media_liste_herauf);
2af7d6 76         self.html_erzeugen("data/tpl/katalog_root_liste.txt", JSON.parse(responseText), function (html) {
86bbf7 77           document.querySelector(".zentraler-inhalt").innerHTML = html;
U 78           self.addEvtListener('.entity-eintrag', 'click', function (event) {
79             var t = event.target;
78d707 80             self.katName = t.textContent;
d027b5 81             if(self.katName !== "Livestreams") {
960359 82               self.http_get('api/store/Ablageort/' + t.textContent, function(responseText) {
d027b5 83                 var ablageort = JSON.parse(responseText);
U 84                 self.ortPfad = ablageort.url;
85                 self.media_liste();
86               });
87             } else {
88               self.livestream_selection();
89             }
86bbf7 90           });
U 91         });
92       });
93     } else {
78d707 94       var bb = document.querySelector('.breadcrumb-behaelter');
U 95       var brPfad = self.katName + self.mediaPfad;
96       var breadcrumbs = brPfad.split('/');
97       var brLinks = "";
98       var brLinkPfad = "";
99       for(var index = 0; index < breadcrumbs.length; index++) {
100         // <a class="breadcrumb-link" href="#">breadcrumbs[index]</a>
101         if(index === 0) {
275b21 102           brLinkPfad = '';
78d707 103         } else {
U 104           brLinkPfad = brLinkPfad + '/' + breadcrumbs[index];
105         }
106         brLinks = brLinks + "<a brlink='" + brLinkPfad + "' class='breadcrumb-link' href='#'>" + breadcrumbs[index] + "</a>";
107         //console.log('   breadcrumbs[' + index + ']: ' + breadcrumbs[index]);
108       }
109       bb.innerHTML = brLinks;
110       self.addEvtListener('.breadcrumb-link', 'click', function(event) {
095119 111         //console.log(event.target.attributes.brlink.nodeValue);
78d707 112         var neuerPfad = event.target.attributes.brlink.nodeValue;
U 113         self.mediaPfad = neuerPfad;
114         self.media_liste();
115       });
3deb92 116       //var url = '/tango' + self.ortPfad + self.mediaPfad;
U 117       var url = '.' + self.ortPfad + self.mediaPfad;
3271f1 118       if(!url.endsWith('/')) {
U 119         url = url + '/';
120       }
121       self.http_get(url, function(responseText) {
2af7d6 122         self.html_erzeugen("data/tpl/katalog_inhalt_liste.txt", JSON.parse(responseText), function (html) {
86bbf7 123           document.querySelector(".zentraler-inhalt").innerHTML = html;
U 124           self.addEvtListener('.entity-eintrag', 'click', function (event) {
125             var t = event.target;
3271f1 126             var tx = t.textContent;
86bbf7 127             if(t.classList.contains("entity-typ-folder")) {
3271f1 128               if(self.mediaPfad.endsWith('/')) {
U 129                 self.mediaPfad = self.mediaPfad + tx;                
130               } else {
131                 self.mediaPfad = self.mediaPfad + '/' + tx;
132               }
86bbf7 133               self.media_liste();
U 134             } else {
37eadf 135               if(t.classList.contains('selected')) {
78d707 136                 t.classList.add('added-to-playlist');
095119 137                 self.titelDazu();
37eadf 138               } else {
U 139                 self.removeClassMulti('selected');
140                 t.classList.add('selected');
141               }
e60cff 142               //self.selTitel = new Titel(t.textContent, self.ortPfad);       
86bbf7 143             }
U 144           });
8d7d35 145           self.addEvtListener('#top-up-btn', 'click', function(event) {
86bbf7 146             if(self.mediaPfad === '/') {
U 147               self.ortPfad = '/';              
148             } else {
149               var pos = self.mediaPfad.lastIndexOf('/');
3271f1 150               var parent;
U 151               if(pos > 1) {
152                 parent = self.mediaPfad.substring(0, pos);
153               } else {
154                 parent = '/';
155               }
86bbf7 156               self.mediaPfad = parent;
U 157             }
158             self.media_liste();
8d7d35 159           });
86bbf7 160         });
U 161       });
162     }
e60cff 163   };
245ac1 164   
39ebae 165   this.ein_aus_btn = function() {
U 166     self.addEvtListener('#ein-aus-btn', 'click', function (event) {
167       var geraetName = event.target.attributes.gname.nodeValue;
168       var nameElem = event.target.parentNode.querySelector('.schalt-geraet-name');
169       if(nameElem.classList.contains('schalt-geraet-true')) {
170         // ausschalten
960359 171         self.http_get('api/gstrg/geraet/' + geraetName + "/aus", function(responseText) {
39ebae 172           // console.log(responseText);
U 173           self.geraet_schalt_liste();
174         });
175       } else {
176         // einschalten            
960359 177         self.http_get('api/gstrg/geraet/' + geraetName + "/ein", function(responseText) {
39ebae 178           // console.log(responseText);
U 179           self.geraet_schalt_liste();
180         });
181       }
182     });
183   };
184   
3e5a56 185   this.geraet_schalt_liste = function() {
39ebae 186     /*self.entitaet_liste('Geräte schalten','../api/store/Geraet/listealles/', 
U 187       "data/tpl/geraet_schalt_liste.txt", '../api/store/Geraet/', 
188       "self.form_geraet_status", function(responseText) {*/
960359 189     self.entitaet_liste('Geräte schalten','api/store/Geraet/listealles/', 
U 190       "data/tpl/geraet_schalt_liste.txt", 'api/store/Geraet/', 
39ebae 191       "", function(responseText) {
U 192         //var geraet = JSON.parse(responseText);
193         //self.geraet_status_form(geraet);
194       }, self.ein_aus_btn);      
3e5a56 195   };
U 196   
3929b0 197   this.geraet_liste = function() {
960359 198     self.entitaet_liste('Geräte','api/store/Geraet/liste/', 
U 199       "data/tpl/geraet_liste.txt", 'api/store/Geraet/', 
3929b0 200       "self.geraet_form", function(responseText) {
U 201         var geraet = JSON.parse(responseText);
202         self.geraet_form(geraet);
203       });
204   };
205
a43e1a 206   this.ablageort_liste = function() {
960359 207     self.entitaet_liste('Kataloge','api/store/Ablageort/liste/', 
U 208       "data/tpl/ablageort_liste.txt", 'api/store/Ablageort/', 
e44ed0 209       "self.ablageort_form", function(responseText) {
U 210         var ablageort = JSON.parse(responseText);
211         self.ablageort_form(ablageort);
212       });
cf6509 213   };
U 214
215   this.prefs_liste = function() {
960359 216     self.entitaet_liste('Einstellungen','api/store/Einstellung/liste/', 
U 217       "data/tpl/einstellung_liste.txt", 'api/store/Einstellung/', 
e44ed0 218       "self.prefs_form", function(responseText) {
U 219         var einstellung = JSON.parse(responseText);
220         self.prefs_form(einstellung);
221       });
cf6509 222   };
U 223
3d4bca 224   this.abspieler_liste = function() {
960359 225     self.entitaet_liste('Abspieler','api/store/Abspieler/liste/', 
U 226       "data/tpl/abspieler_liste.txt", 'api/store/Abspieler/', 
e44ed0 227       "self.abspieler_form", function(responseText) {
U 228         var abspieler = JSON.parse(responseText);
229         self.abspieler_form(abspieler);
230       });
8d7d35 231   };
U 232   
d027b5 233   this.livestream_liste = function() {
960359 234     self.entitaet_liste('Livestreams','api/store/Livestream/liste/', 
U 235       "data/tpl/livestream_liste.txt", 'api/store/Livestream/', 
d027b5 236       "self.livestream_form", function(responseText) {
U 237         var livestream = JSON.parse(responseText);
238         self.livestream_form(livestream);
239       });
240   };
241   
8d7d35 242   this.abspielliste_liste = function() {
960359 243     self.entitaet_liste('Abspielliste','api/store/Abspielliste/liste/', 
U 244       "data/tpl/abspielliste_liste.txt", 'api/store/Abspielliste/', 
e44ed0 245       "self.abspielliste_form", function(responseText) {
095119 246         //console.log("responseTest: '" + responseText + "'");
e44ed0 247         var abspielliste = JSON.parse(responseText);
U 248         self.abspielliste_form(abspielliste);
249       });
8d7d35 250   };
U 251   
c7030d 252   /* -------------------- Entitaets-Formulare ------------------ */  
8d7d35 253   
U 254   this.abspielliste_form = function(al) {
50e53e 255     self.entitaet_form('Abspielliste', al, al.name,
960359 256       "data/tpl/form_abspielliste.txt", 'api/store/Abspielliste/',
960317 257       '#abspielliste-name', 'name', function(event) {
095119 258           if(event !== undefined) {
U 259             event.preventDefault();
260           }
c7030d 261           self.abspielliste_auswahl_fuellen();
U 262           self.abspielliste_liste();
263     });
3d4bca 264   };
71def1 265   
3d4bca 266   this.abspieler_form = function(pl) {
50e53e 267     self.entitaet_form('Abspieler', pl, pl.key,
960359 268       "data/tpl/form_abspieler.txt", 'api/store/Abspieler/',
960317 269       '#abspieler-name', 'name', function() { 
c7030d 270           self.abspieler_auswahl_fuellen();
U 271           self.abspieler_liste();
d027b5 272     });
U 273   };
274
275   this.livestream_form = function(ls) {
276     self.entitaet_form('Livestream', ls, ls.name,
960359 277       "data/tpl/form_livestream.txt", 'api/store/Livestream/',
960317 278       '#livestream-name', 'name', function() { 
d027b5 279           self.livestream_liste();
3929b0 280     });
U 281   };
282
283   this.geraet_form = function(ge) {
284     self.entitaet_form('Gerät', ge, ge.name,
960359 285       "data/tpl/form_geraet.txt", 'api/store/Geraet/',
960317 286       '#geraet-name', 'name', function() { 
3929b0 287           self.geraet_liste();
3e5a56 288     });
U 289   };
290
291   this.geraet_status_form = function(ge) {
292     self.entitaet_form('Gerät', ge, ge.name,
960359 293       "data/tpl/form_geraet_status.txt", 'api/store/Geraet/',
960317 294       '#geraet-name', 'name', function() { 
3e5a56 295           self.geraet_schalt_liste();
c7030d 296     });
71def1 297   };
U 298
cf6509 299   this.prefs_form = function(k) {
78d707 300     self.entitaet_form('Einstellung', k, k.key,
960359 301       "data/tpl/form_einstellung.txt", 'api/store/Einstellung/',
960317 302       '#einstellung-key', 'key', function() { 
c7030d 303           self.prefs_liste();
U 304     });
a43e1a 305   };
cfa858 306
90f5d4 307   /* 
U 308    * Ablageort-Formular anzeigen
309    * 
310    * {"name":"Katalog 2","ort":"/home/ulrich/Videos","url":"/media/kat2"}: 
311    * 
312    * @param {type} ablageort  der Ablageort, der bearbeitet werden soll, leer fuer neuen Ort
313    * @returns {undefined} kein Rueckgabewert
314    */
315   this.ablageort_form = function(ort) {
78d707 316     self.entitaet_form('Katalog', ort, ort.name,
960359 317       "data/tpl/form_ablageort.txt", 'api/store/Ablageort/',
a48ca3 318       '#ablageort-name', 'name', function() { 
c7030d 319         self.ablageort_liste();
U 320     });
b379f5 321   };
48f8f9 322   
748b6f 323   /* ------------------------------- UI-Dynamik ----------------------- */
48f8f9 324   
748b6f 325   self.reset_top_buttons = function() {
2af7d6 326     self.html_erzeugen("data/tpl/top_btns.txt", '', function (html) {
748b6f 327       document.querySelector(".top-btns").innerHTML = html;
U 328     });
329   };
330   
331   this.abspieler_auswahl_fuellen = function() {
960359 332     self.http_get('api/store/Abspieler/liste/', function (responseText) {
2af7d6 333       self.html_erzeugen("data/tpl/abs_sel.txt", JSON.parse(responseText), function (html) {
748b6f 334         document.querySelector(".abs-sel").innerHTML = html;
U 335       });    
336     });
337   };
338
339   this.abspielliste_auswahl_fuellen = function() {
960359 340     self.http_get('api/store/Abspielliste/', function (responseText) {
2af7d6 341       self.html_erzeugen("data/tpl/pl_sel.txt", JSON.parse(responseText), function (html) {
748b6f 342         document.querySelector(".pl-sel").innerHTML = html;
b56bb3 343         self.addEvtListener('#playlist', 'change', function() {
U 344           self.titel_liste();
345         });
748b6f 346       });    
U 347     });
348   };
349   
350   /* Unterer Einblendbereich */
351   
352   this.dialog_unten_zeigen = function() {
2af7d6 353     self.html_erzeugen("data/tpl/ctrl.txt", "", function (html) {
748b6f 354       var dlg = document.querySelector(".dialog-unten");
a07e7e 355       //dlg.style.height = '10em';
748b6f 356       dlg.innerHTML = html;
U 357       self.abspieler_auswahl_fuellen();
358       self.abspielliste_auswahl_fuellen();
095119 359       self.addEvtListener('#dazu-btn', 'click', self.titelDazu);
b56bb3 360       self.addEvtListener('#play-btn', 'click', self.play);
9e14ef 361       self.addEvtListener('#stop-btn', 'click', function() {
U 362         self.kommando('stop');
363       });
364       self.addEvtListener('#pause-btn', 'click', function() {
365         self.kommando('pause');
366       });
c6fdc4 367       self.addEvtListener('#weiter-btn', 'click', self.weiter);
fe0cf7 368
U 369       self.addEvtListener('#hier-btn', 'click', self.hier_spielen);
9e14ef 370       
U 371 /*
372     <button class="ctrl-btn ctrl-item" id="hier-btn" title="hier spielen"><i class="icon-tablet"></i></button>
373  */      
374       
095119 375       self.addEvtListener('#weg-btn', 'click', self.titelWeg);
U 376       self.addEvtListener('#leeren-btn', 'click', self.alleTitelEntfernen);
f6ea0c 377       
U 378       self.addEvtListener('#media-btn', 'click', self.media_liste);
379       self.addEvtListener('#plst-btn', 'click', self.titel_liste);
938b6b 380       self.addEvtListener('#live-btn', 'click', self.livestream_selection);
f6ea0c 381       self.addEvtListener('#switch-btn', 'click', self.geraet_schalt_liste);
392dc9 382
U 383       self.addEvtListener('#voldn-btn', 'click', function() {
384         self.kommando('voldn');
385       });
386       self.addEvtListener('#volup-btn', 'click', function() {
387         self.kommando('volup');
388       });
389       
748b6f 390       self.media_liste();
U 391     });
392   };
393   
394   /* Titel einer Abspielliste */
395   
396   this.titel_liste = function() {
397     self.reset_top_buttons();
398     var plname = document.querySelector('#playlist').value;
78d707 399     document.querySelector('.bereich-name').textContent = 'Abspielliste ' + plname;
U 400     var bb = document.querySelector('.breadcrumb-behaelter');
401     bb.textContent = "";
960359 402     self.http_get('api/alist/' + plname, function (responseText) {
2af7d6 403       self.html_erzeugen("data/tpl/titel_liste.txt", JSON.parse(responseText), function (html) {
748b6f 404         document.querySelector(".zentraler-inhalt").innerHTML = html;
U 405         self.addEvtListener('.entity-eintrag', 'click', function (event) {
406           var t = event.target;
407           self.removeClassMulti('selected');
408           t.classList.add('selected');
409         });
1bf4f6 410         self.addEvtListener('.entity-eintrag', 'dragstart', function (e) {
U 411           //console.log("drag started");          
412           e.dataTransfer.setData('text/plain', e.target.textContent);
413           setTimeout(() => {
414                   e.target.classList.add('hide');
415                   e.target.classList.add('drag-elem');
416           }, 0);          
417         });
418         self.addEvtListener('.entity-eintrag', 'dragenter', function (e) {
419           e.preventDefault();
420           //console.log("drag enter");
421           e.target.classList.add('drag-over');
422         });
423         self.addEvtListener('.entity-eintrag', 'dragover', function (e) {
424           e.preventDefault();
425           //console.log("drag over");
426           e.target.classList.add('drag-over');
427         });
428         self.addEvtListener('.entity-eintrag', 'dragleave', function (e) {
429           //console.log("drag leave");
430           e.target.classList.remove('drag-over');
431         });
432         self.addEvtListener('.entity-eintrag', 'drop', function (e) {     
433           e.preventDefault();
434           //console.log("drop");
435           //console.log("index: " + self.getIndexBySelector('drag-over'));
436           const pos = self.getIndexBySelector('drag-elem');
437           const zielPos = self.getIndexBySelector('drag-over');
438           const titeltext = e.dataTransfer.getData('text/plain');
439           const draggable = document.querySelector(".drag-elem");
440           draggable.classList.remove("drag-elem");
441           e.target.classList.remove('drag-over');
442           var plname = document.querySelector('#playlist').value;
443           self.http_put('api/alist/' + plname + "/" + pos + "/" + zielPos, '', function(responseText) {
444             //self.meldung_mit_timeout(responseText, 1500);
445           });
446           ulElem = draggable.parentElement;
447           ulElem.removeChild(draggable);          
448           e.target.insertAdjacentElement('beforebegin', draggable);
449           draggable.classList.remove('hide');
450         });             
748b6f 451       });
U 452     });
453   };  
454   
b56bb3 455   /* ------------- Media-Steuerung ------------------------- */
U 456   
457   this.play = function() {
658c14 458     var bereichName = document.querySelector('.bereich-name').textContent;
U 459     if(bereichName === '') {
4f2589 460       var titel = self.titelErmitteln(document.querySelector(".selected"));
1c5fa4 461       var playername = document.querySelector('#abspieler').value;
658c14 462       console.log('plname: ' + playername + ' url: ' + titel.katalogUrl + titel.pfad + titel.name);
960359 463       self.http_post('api/strg/' + playername + '/play/titel', JSON.stringify(titel), function(responseText) {
658c14 464         self.meldung_mit_timeout(responseText, 1500);
d027b5 465       });   
U 466     } else if(bereichName === 'Livestream-Auswahl') {
467       var streamName = document.querySelector(".selected").textContent;
468       var playername = document.querySelector('#abspieler').value;
469       var stream = new Livestream(streamName, '-');
960359 470       self.http_post('api/strg/' + playername + '/play/stream', JSON.stringify(stream), function(responseText) {
d027b5 471         self.meldung_mit_timeout(responseText, 1500);
U 472       });   
658c14 473     } else {
U 474       var abs = document.querySelector('#abspieler').value;
475       var lst = document.querySelector('#playlist').value;
476       console.log(
477         "play playlist.value: " + document.querySelector('#playlist').value + 
478         ", abspieler.value: " + document.querySelector('#abspieler').value);
960359 479       self.http_get('api/strg/' + abs + '/play/liste/' + lst, function(responseText) {
658c14 480         self.meldung_mit_timeout(responseText, 1500);
U 481       });
482     }
095119 483   };
U 484   
c6fdc4 485   this.weiter = function() {
U 486     var bereichName = document.querySelector('.bereich-name').textContent;
487     if(bereichName === '') {
488       var titel = self.titelErmitteln(document.querySelector(".selected"));
489       var playername = document.querySelector('#abspieler').value;
490       console.log('plname: ' + playername + ' url: ' + titel.katalogUrl + titel.pfad + titel.name);
960359 491       self.http_post('api/strg/' + playername + '/weiter/titel', JSON.stringify(titel), function(responseText) {
c6fdc4 492         self.meldung_mit_timeout(responseText, 1500);
U 493       });   
494     }
495   };
496   
9e14ef 497   this.kommando = function(kommando) {
f9dd4f 498     console.log(kommando);
U 499     if(self.playingIndex > -1) {
500       if(kommando === 'stop') {
501         self.audioElem.pause();
502         self.audioElem.currentTime = 0;
503         self.audioElem.removeEventListener("ended", self.nextTrack);
504         self.playingIndex = -1;
505         self.playState = 'stop';
506       } else if(kommando === 'pause') {
507         if(self.playState === 'pause') {
508           self.playState = 'play';
509           self.audioElem.play();
510         } else if(self.playState === 'play') {
511           self.playState = 'pause';
512           self.audioElem.pause();
513         }
514       } else if(kommando === 'play') {
515         if(self.playingIndex < 0) {
516           self.nextTrack();
517         } else {
518           self.audioElem.play();
519         }
520         self.playState = 'play';
3866a7 521       }
f9dd4f 522     } else {
U 523       var abs = document.querySelector('#abspieler').value;
524       self.http_get('api/strg/' + abs + '/' + kommando, function(responseText) {
525         if(kommando !== 'volup' && kommando !== 'voldn') {
526           self.meldung_mit_timeout(responseText, 1500);
527         }
528       });
529     }
9e14ef 530   };
fe0cf7 531   
U 532   this.hier_spielen = function() {
533     var url;
534     // den Host noch vom Server abrufen und den nachfolgenden Code ersetzen
883f91 535     var host = 'http://' + window.location.host + '/tango';
fe0cf7 536     console.log('host: ' + host);
U 537     var bereichName = document.querySelector('.bereich-name').textContent;
538     if(bereichName === '') {
539       var titel = self.titelErmitteln(document.querySelector(".selected"));
540       //var playername = document.querySelector('#abspieler').value;
541       console.log(' url: ' + titel.katalogUrl + titel.pfad + titel.name);
542       //self.http_post('../api/strg/' + playername + '/titel', JSON.stringify(titel), function(responseText) {
543       //  self.meldung_mit_timeout(responseText, 1500);
544       //}); 
545       url = host + titel.katalogUrl + titel.pfad + titel.name;
546       window.open(url);
547     } else if(bereichName === 'Livestream-Auswahl') {
548       var streamName = document.querySelector(".selected").textContent;
549       // hier den Stream-URL abrufen
550       //GET /mz/api/store/[typname]/[name]
960359 551       self.http_get('api/store/Livestream/' + streamName, function(responseText) {
fe0cf7 552         var stream = JSON.parse(responseText);        
U 553         url = stream.url;
554         window.open(url);
555       });
556     } else {
557       var lst = document.querySelector('#playlist').value;
558       console.log(
559         "play playlist.value: " + document.querySelector('#playlist').value + 
560         ", abspieler.value: " + document.querySelector('#abspieler').value);
f9dd4f 561       self.playingIndex = -1;
U 562       self.nextTrack();
fe0cf7 563     }
U 564   };  
792b21 565   
f9dd4f 566   this.nextTrack = function() {
a6081c 567     /*
U 568       
569       {
570         "katalogUrl":"/media",
571         "pfad":"/Musik/M/Bruno-Mars/",
572         "name":"04-Uptown-Funk.mp3",
573         "interpret":"Mark Ronson feat Bruno Mars",
574         "titelAnzName":"Uptown Funk",
575         "album":"Uptown Special Explicit"
576       }
f9dd4f 577     
a6081c 578      */
U 579     //const plname = document.querySelector('#playlist').value;
f9dd4f 580     if(self.playingIndex > -1) {
U 581       self.audioElem.removeEventListener("ended", self.nextTrack);
a6081c 582     } else {
U 583       self.playingList = document.querySelector('#playlist').value;
f9dd4f 584     }
U 585     self.playingIndex++;
a6081c 586     const url = 'api/alist/' + self.playingList + "/" + self.playingIndex;
U 587     self.http_get(url, function(responseText){
588       if(responseText === 'eom') {
589         // ende
590         self.audioElem.removeEventListener("ended", self.nextTrack);
591         self.playingIndex = -1;
592         self.playState = 'stop';
593       } else {
594         const titel = JSON.parse(responseText);
595         console.log("titel: " + titel.name);
596         const titelUrl = self.getTitelFromJSONObj(titel);
597         //const titelElem = new Audio(titel);        
598         self.audioElem = new Audio(titelUrl);
599         self.audioElem.addEventListener("ended", self.nextTrack);
600         self.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
601         const track = self.audioCtx.createMediaElementSource(self.audioElem);
602         track.connect(self.audioCtx.destination);
603         self.audioElem.play();
604         self.playState = 'play';        
605       }
606     });
f9dd4f 607   };
U 608   
a6081c 609   this.getTitelFromJSONObj = function(titelObj) {
f9dd4f 610     //const audioElements = document.querySelectorAll('.entity-eintrag');
U 611     const host = 'http://' + window.location.host + '/tango';
a6081c 612     const titel = host + titelObj.katalogUrl + titelObj.pfad + titelObj.name;
f9dd4f 613     return titel;
U 614   };
615   
792b21 616   this.gehe_zu_dialog_zeigen = function () {
U 617     self.dialog_laden_und_zeigen('data/tpl/gehe-zu.txt', '', function(){
618       const form = document.querySelector('form');      
619       form.addEventListener('submit', function(event) {
620         // hier gehe zu realisieren
621         event.preventDefault();
622         const data = new FormData(event.target);
623         const value = Object.fromEntries(data.entries());
624         var daten = JSON.stringify(value);
625         console.log('gehe zu mit ' + daten);
626         var sekunden = (value['std'] * 3600) + (value['min'] * 60) + (value['sek'] * 1);
627         if(value['richtung'] === 'zurueck') {
628           sekunden *= -1;
629         }
630         console.log('sekunden: ' + sekunden);
631         self.dialog_schliessen();
632         // HTTP GET /mz/api/strg/abspieler/seek/[sekunden]
633         self.kommando('seek/' + sekunden);
634       });
635       self.addEvtListener('#cancel-btn', 'click', function(event) {
636         self.dialog_schliessen();
637       });
638       self.menue_umschalten();    
639     });
640   };
9e14ef 641     
095119 642   /* ------------- Verwaltungsfunktionen Abspielliste -------------------- */
U 643   
644   self.alleTitelEntfernen = function() {
645     var plname = document.querySelector('#playlist').value;
960359 646     self.http_delete('api/alist/' + plname + '/alle', '', function(responseText) {
095119 647       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
U 648       //self.meldung_mit_timeout(responseText, 1500);
649       self.titel_liste();
650     });
651   };
652   
1bf4f6 653   /*
U 654    * {
655    *  "katalogUrl":"/media",
656    *  "pfad":"/Musik/B/Bay-City-Rollers/Original-Album-Classics/3/",
657    *  "name":"3-37-Love-Is.mp3",
658    *  "interpret":"Bay City Rollers",
659    *  "titelAnzName":"Love Is",
660    *  "album":"Original Album Classics"
661    * }
662    * @returns {undefined}
663    */
095119 664   this.titelDazu = function() {
4f2589 665     var titel = self.titelErmitteln(document.querySelector(".selected"));
095119 666     //var titelName = elem.textContent;
4f2589 667     /*
095119 668     var titelName = elem.attributes.dateiName.nodeValue;
U 669     var album = elem.attributes.album.nodeValue;
670     var interpret = elem.attributes.interpret.nodeValue;
671     var anzName = elem.attributes.titelAnzName.nodeValue;
672     var titel;
673     if(self.mediaPfad.endsWith('/')) {
674       titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
675     } else {
676       titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
677     }
4f2589 678     */
095119 679     var plname = document.querySelector('#playlist').value;
960359 680     self.http_put('api/alist/' + plname, JSON.stringify(titel), function(responseText) {
095119 681       //self.meldung_mit_timeout(responseText, 1500);
U 682     });
683   };  
684   
685   this.titelWeg = function() {
1bf4f6 686     //var elem = document.querySelector(".selected");
U 687     //var parentElem = elem.parentNode;
095119 688     //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
1bf4f6 689     //var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
095119 690     //console.log("liElems.anz: " + liElems.length);
1bf4f6 691     //var gefunden = false;
U 692     //for(var i = 0; i < liElems.length && !gefunden; i++) {
095119 693       //console.log(liElems.item(i).textContent);
1bf4f6 694       //if(liElems.item(i).classList.contains("selected")) {
U 695         //gefunden = true;
696         //var index = i;
095119 697         //console.log(elem.textContent + ' hat Index ' + i);
1bf4f6 698       //}
U 699     //}
700     
701     const index = self.getIndexBySelector("selected");
095119 702     // /mz/api/alist/[pl-name]/[nr] 
U 703     var plname = document.querySelector('#playlist').value;
960359 704     self.http_delete('api/alist/' + plname + '/' + index,'', function(responseText) {
095119 705       // DELETE    http://localhost:9090/mz/api/alist/liste1/0
U 706       //self.meldung_mit_timeout(responseText, 1500);
707       self.titel_liste();
708     });
709     
b56bb3 710   };
U 711   
1bf4f6 712   this.getIndexBySelector = function(selector) {
U 713     var qSel = '.' + selector;
714     var elem = document.querySelector(qSel);
715     var parentElem = elem.parentNode;
716     //console.log("elem: " + elem.nodeName + ", parent: " + parentElem.nodeName + ", len: " + parentElem.childNodes.length);
717     var liElems = parentElem.getElementsByTagName(elem.nodeName); // nur die LI Elemente
718     //console.log("liElems.anz: " + liElems.length);
719     var gefunden = false;
720     var index = -1;
721     for(var i = 0; i < liElems.length && !gefunden; i++) {
722       //console.log(liElems.item(i).textContent);
723       if(liElems.item(i).classList.contains(selector)) {
724         gefunden = true;
725         index = i;
726         //console.log(elem.textContent + ' hat Index ' + i);
727       }
728     }
729     return index;
730   };
731   
748b6f 732   /* ------------- Helfer fuer Entitaets-Formulare ----------------------- */
14638b 733   
U 734   /*
735    * url: '../api/store/Ablageort/liste/'
78d707 736    * tpl: "data/tpl/ablageort_liste.txt"
14638b 737    * storeUrl: '../api/store/Ablageort/'
U 738    * formFunc: "self.ablageort_form"
739    * cb: etwas wie
740    *   function(responseText){
741    *     var ablageort = JSON.parse(responseText);
742    *     self.ablageort_form(ablageort);
743    *   });
39ebae 744    */  
849ee2 745   this.entitaet_liste = function(bname, listUrl, tpl, storeUrl, formFunc, cb, customListCode) {
14638b 746     self.reset_top_buttons();
50e53e 747     document.querySelector('.bereich-name').textContent = bname;
78d707 748     var bb = document.querySelector('.breadcrumb-behaelter');
U 749     bb.textContent = "";
14638b 750     self.http_get(listUrl, function (responseText) {
2af7d6 751       self.html_erzeugen(tpl, JSON.parse(responseText), function (html) {
14638b 752         document.querySelector(".zentraler-inhalt").innerHTML = html;
U 753         self.addEvtListener('.entity-eintrag', 'click', function (event) {
754           var t = event.target;
755           self.http_get(storeUrl + t.textContent, cb);
756         });
757         //self.addEvtListener('#neu-btn', 'click', function (event) {
758         self.addEvtListener('#top-neu-btn', 'click', function(event) {
759           eval(formFunc + "(this)");
849ee2 760         });                
U 761         if(typeof(customListCode) !== 'function') {
762           // ..
763         } else {
764           customListCode();
765         }        
14638b 766       });
U 767     });
768   };  
748b6f 769       
48f8f9 770   /*
c7030d 771    * dat: gefuelltes Datenobjekt bei Aenderung
U 772    * key: der alte schluesselbegriff bei Aenderung (z.B. al.name)
78d707 773    * tpl: "data/tpl/form_abspielliste.txt"
c7030d 774    * url: '../api/store/Abspielliste/'
U 775    * selector: '#abspielliste-name'
776    * cbOk: etwas wie
777    *    function() {
778    *       self.abspielliste_auswahl_fuellen();
779    *       self.abspielliste_liste();
780    *     });
781    * delSelector: '#abspielliste-name'
782    * cbDel: etwas wie
783    *    function() {
784    *       self.abspielliste_auswahl_fuellen();
785    *       self.abspielliste_liste();
786    *     });
787    */
788
960317 789   this.entitaet_form = function(bname, dat, key, tpl, url, selector, keyname, cb) {
50e53e 790     document.querySelector('.bereich-name').textContent = bname;
2af7d6 791     self.html_erzeugen(tpl, dat, function (html) {
c7030d 792       document.querySelector(".zentraler-inhalt").innerHTML = html;
U 793       const form = document.querySelector('form');      
794       form.addEventListener('submit', function(event) {
960317 795         self.handle_submit(event, key, url, selector, keyname, cb);
c7030d 796       });
U 797       self.addEvtListener('#cancel-btn', 'click', cb);
798       self.addEvtListener('#loeschen-btn', 'click', function(event) {
799         event.preventDefault();
800         self.handle_del_btn(selector, url, cb);
801       });
802     });
803   };
804   
805   /*
48f8f9 806    * existingKey: wenn die Entitaet existiert und geandert werden soll
U 807    *                 leer, wenn neue Entitaet 
808    */
960317 809   this.handle_submit = function(event, existingKey, putUrl, keySelector, keyname, cb) {
48f8f9 810     event.preventDefault();
U 811     const data = new FormData(event.target);
812     const value = Object.fromEntries(data.entries());
813     var formkey = document.querySelector(keySelector).value;
960317 814     formkey = formkey.replace(' ', '');
U 815     formkey = formkey.replace(/[\W]+/g, '');
816     value[keyname] = formkey;
817     var daten = JSON.stringify(value);
48f8f9 818     if(typeof existingKey === "undefined" ||  existingKey.length < 1) {
U 819       // neu
820       self.http_put(putUrl + formkey, daten, function (responseText) {
821         if(typeof(cb) !== 'function') {
822           // ..
823         } else {
824           cb();
825         }
826       });
827     } else {
828       // aendern
829       self.http_put(putUrl + existingKey, daten, function (responseText) {
830         if(typeof(cb) !== 'function') {
831           // ..
832         } else {
833           cb();
834         }
835       });
836     }
837   };
838   
839   this.handle_del_btn = function(selectorKey, delUrl, cb) {
840     var pkey = document.querySelector(selectorKey).value;
841     var dlgdata = {"del-elem": pkey};
78d707 842     self.dialog_laden_und_zeigen('data/tpl/dlg-loeschen.txt', dlgdata, function() {
48f8f9 843       self.addEvtListener('#nein-btn', 'click', self.dialog_schliessen);
U 844       self.addEvtListener('#ja-btn', 'click', function(event) {
095119 845         //console.log("loeschen geklickt.");
48f8f9 846         self.http_delete(delUrl + pkey, '', function (responseText) {
U 847           self.dialog_schliessen();
848           if(typeof(cb) !== 'function') {
849             // ..
850           } else {
851             cb();
852           }
853         });
854       });
855     });    
856   };  
748b6f 857   
U 858   /* ------------------ sonstige Helfer ----------------------- */
859       
7c22a2 860   this.addEvtListener = function(selector, eventName, func) {
U 861     document.querySelectorAll(selector).forEach(elem => { elem.addEventListener(eventName, func); });
862   };
863   
864   this.removeClassMulti = function(selector) {
865     document.querySelectorAll('.' + selector).forEach(elem => { elem.classList.remove(selector); });
866   };
4f2589 867   
U 868   self.titelErmitteln = function(elem) {
869     var titelName = elem.attributes.dateiName.nodeValue;
870     var album = elem.attributes.album.nodeValue;
871     var interpret = elem.attributes.interpret.nodeValue;
872     var anzName = elem.attributes.titelAnzName.nodeValue;
873     var titel;
874     if(self.mediaPfad.endsWith('/')) {
875       titel = new Titel(titelName, self.mediaPfad, self.ortPfad, interpret, anzName, album);
876     } else {
877       titel = new Titel(titelName, self.mediaPfad + '/', self.ortPfad, interpret, anzName, album);
878     }
879     return titel;
880   };
7c22a2 881
f45e20 882   /* --------------------- asynchroner HTTP Client ----------------- */
faab2d 883   
f074f6 884   this.http_get = function (u, cb) {
b379f5 885     self.http_call('GET', u, null, cb);
U 886   };
f074f6 887
U 888   this.http_post = function (u, data, cb) {
b379f5 889     self.http_call('POST', u, data, cb);
U 890   };
891
90f5d4 892   this.http_put = function (u, data, cb) {
U 893     self.http_call('PUT', u, data, cb);
894   };
895   
5b7356 896   this.http_delete = function (u, data, cb) {
5f7e0b 897     // console.log("delete " + u);
5b7356 898     self.http_call('DELETE', u, data, cb);
U 899   };
900   
ea73fa 901   this.http_call = function (method, callurl, data, scallback) {
b379f5 902     var xhr = new XMLHttpRequest();
f074f6 903     xhr.onreadystatechange = function () {
b379f5 904       if (this.readyState === 4 && this.status === 200) {
U 905         scallback(this.responseText);
906       }
907     };
ea73fa 908     xhr.open(method, callurl);
f074f6 909     if (method === 'GET') {
b379f5 910       xhr.send();
2597cd 911     } else if (method === 'POST' || method === 'PUT' || method === 'DELETE') {
b379f5 912       xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
U 913       xhr.send(data);
914     }
915   };
8239d1 916   
f45e20 917   /* ------------------------ aus App-Vorlage -------------------  */
cfa858 918
f074f6 919   this.menue_umschalten = function () {
cfa858 920     var ham = document.querySelector(".hamburger");
U 921     ham.classList.toggle("is-active"); // hamburger-icon umschalten
922     self.appMenu.toggle(); // menue oeffnen/schliessen
923   };
924
f074f6 925   this.info_dialog_zeigen = function () {
78d707 926     self.dialog_laden_und_zeigen('data/tpl/dlg-info.txt', '');
cfa858 927     self.menue_umschalten();
U 928   };
929
f074f6 930   this.seitenleiste_umschalten = function () {
cfa858 931     var ostDiv = document.querySelector('.ost');
f074f6 932     if (ostDiv.classList.contains('ost-open')) {
cfa858 933       ostDiv.classList.remove('ost-open');
f074f6 934       ostDiv.style.flexBasis = '0em';
cfa858 935     } else {
f074f6 936       ostDiv.classList.add('ost-open');
U 937       ostDiv.style.flexBasis = '6em';
cfa858 938     }
U 939     self.menue_umschalten();
940   };
941
f074f6 942   this.fusszeile_umschalten = function () {
cfa858 943     var suedDiv = document.querySelector('.sued');
f074f6 944     if (suedDiv.classList.contains('sued-open')) {
cfa858 945       suedDiv.classList.remove('sued-open');
f074f6 946       suedDiv.style.height = '0';
cfa858 947     } else {
U 948       suedDiv.classList.add('sued-open');
f074f6 949       suedDiv.style.height = '1.5em';
cfa858 950     }
U 951     self.menue_umschalten();
952   };
953
f074f6 954   this.menu_message = function (msg) {
cfa858 955     self.meldung_mit_timeout(msg, 1500);
U 956     var suedDiv = document.querySelector('.sued');
f074f6 957     if (suedDiv.classList.contains('sued-open')) {
cfa858 958     } else {
U 959       suedDiv.classList.add('sued-open');
f074f6 960       suedDiv.style.height = '1.5em';
cfa858 961     }
U 962     self.menue_umschalten();
963   };
964
f074f6 965   this.message_1 = function () {
cfa858 966     self.menu_message('Eine Mitteilung.');
U 967   };
968
f074f6 969   this.message_2 = function () {
cfa858 970     self.menu_message('Was wir schon immer sagen wollten.');
U 971   };
972
f074f6 973   this.message_3 = function (text) {
cfa858 974     self.menu_message(text);
U 975   };
976
f074f6 977   this.meldung_mit_timeout = function (meldung, timeout) {
cfa858 978     var s = document.querySelector('.sued');
a43e1a 979     s.classList.add('sued-open');
U 980     s.style.height = '1.5em';
cfa858 981     s.textContent = meldung;
f074f6 982     setTimeout(function () {
cfa858 983       s.textContent = 'Bereit.';
f074f6 984       setTimeout(function () {
cfa858 985         var suedDiv = document.querySelector('.sued');
f074f6 986         if (suedDiv.classList.contains('sued-open')) {
U 987           suedDiv.classList.remove('sued-open');
988           suedDiv.style.height = '0';
cfa858 989         }
U 990       }, 500);
991     }, timeout);
992   };
8239d1 993   
f45e20 994   /* --------------------- Dialog-Funktionen ------------------------ */
cfa858 995
U 996   /*
f074f6 997    Einen Dialog aus Vorlagen erzeugen
U 998    
999    vurl - URL zur Dialogvorlage
1000    msgTpl - URL mit einer Vorlage eines Mitteilungstextes (optional)
1001    */
5b7356 1002   this.dialog_laden_und_zeigen = function (vurl, msgTpl, cb) {
U 1003     var vorlage = self.cache[vurl];
1004     if(vorlage === undefined) {
1005       self.http_get(vurl, function(antwort) {
1006         self.cache[vurl] = antwort;
1007         self.dialog_zeigen(vurl, msgTpl, cb);
f074f6 1008       });
cfa858 1009     } else {
5b7356 1010       self.dialog_zeigen(vurl, msgTpl, cb);
cfa858 1011     }
U 1012   };
1013
5b7356 1014   this.dialog_zeigen = function (vurl, inhalt, cb) {
U 1015     var dlg = document.querySelector(".dialog");
2597cd 1016     self.html_erzeugen(vurl, inhalt, function (html) {
U 1017       dlg.style.height = '7em';
1018       dlg.innerHTML = html;
1019       document.querySelector('.close-btn').addEventListener('click', self.dialog_schliessen);
1020       if(typeof(cb) !== 'function') {
1021         // ..
1022       } else {
1023         cb();
1024       }
1025     });
5b7356 1026   };
2597cd 1027   
f45e20 1028   this.dialog_schliessen = function () {
cfa858 1029     document.querySelector('.close-btn').removeEventListener('click', self.dialog_schliessen);
U 1030     var dlg = document.querySelector('.dialog');
1031     dlg.style.height = '0';
1032     dlg.innerHTML = '';
1033   };
1034
f45e20 1035   /* ---------------------   Vorlagen   ---------------------- */
cfa858 1036
U 1037   /*
f074f6 1038    Das HTML erzeugen, das entsteht, wenn eine Vorlage mit Inhalt
U 1039    gefüllt wird
1040    
1041    Das Füllen erfolgt asynchron, d.h. der Programmlauf geht nach dem
1042    Aufruf weiter ohne auf das Laden und Füllen der Vorlage zu warten.
1043    Das fertige HTML wird der Callback-Funktion übergeben
1044    sobald die Vorlage geladen und gefüllt ist, unabhängig davon, wo der
1045    Programmlauf zu diesem Zeitpunkt mittlerweile ist.
1046    
1047    vurl - URL zur Vorlagendatei
1048    inhalt - die JSON-Struktur, deren Inhalt in die
1049    Vorlage gefüllt werden soll
1050    cb - Callback-Funktion, die gerufen wird, wenn die Vorlage gefüllt ist.
1051    Dieser Callback-Funktion wird das fertige HTML übergeben
1052    */
1053   this.html_erzeugen = function (vurl, inhalt, cb) {
cfa858 1054     var vorlage = self.cache[vurl];
f074f6 1055     if (vorlage === undefined) {
cfa858 1056       self.vorlage_laden_und_fuellen(vurl, inhalt, cb);
U 1057     } else {
1058       self.vorlage_fuellen(vurl, inhalt, cb);
1059     }
1060   };
1061
f074f6 1062   this.vorlage_fuellen = function (vurl, inhalt, cb) {
cfa858 1063     cb(Mustache.render(self.cache[vurl], inhalt));
U 1064   };
1065
1066   /*
f074f6 1067    Eine Vorlage vom Server in den lokalen Speicher laden
U 1068    vurl - der URL unter dem die Vorlage zu finden ist
1069    inhalt - die JSON-Struktur, deren Inhalt in die
1070    Vorlage gefüllt werden soll
1071    cb - callback: Diese Funktion wird gerufen, wenn die Vorlage mit dem
1072    Inhalt gefüllt ist
1073    */
1074   this.vorlage_laden_und_fuellen = function (vurl, inhalt, cb) {
cfa858 1075     var xmlhttp = new XMLHttpRequest();
f074f6 1076     xmlhttp.onreadystatechange = function () {
cfa858 1077       if (this.readyState == 4 && this.status == 200) {
U 1078         self.cache[vurl] = this.responseText;
1079         self.vorlage_fuellen(vurl, inhalt, cb);
1080       }
1081     };
1082     xmlhttp.open("GET", vurl, true);
1083     xmlhttp.send();
1084   };
1085
1086
1087 }
1088
f45e20 1089 /* ----------- Objekte ---------------- */
U 1090
1091 function Ablageort(n, o, u) {
1092   this.name = n;
1093   this.ort = o;
1094   this.url = u;
1095 }
1096
1097 function Einstellung(k, v) {
1098   this.key = k;
1099   this.value = v;
1100 }
1101
1102 function Abspieler(n, u) {
1103   this.name = n;
1104   this.url = u;
8d7d35 1105 }
U 1106
d027b5 1107 function Livestream(n, u) {
U 1108   this.name = n;
1109   this.url = u;
1110 }
1111
8d7d35 1112 function Abspielliste(n) {
U 1113   this.name = n;
e60cff 1114 }
U 1115
245ac1 1116 function Titel(n, p, u, i, t, a) {
e60cff 1117   this.katalogUrl = u;
2bdd78 1118   this.pfad = p;
e60cff 1119   this.name = n;
245ac1 1120   this.interpret = i;
U 1121   this.titelAnzName = t;
1122   this.album  = a;
3929b0 1123 }
U 1124
a29f5c 1125 function Geraet(n, e, a, s, st) {
3929b0 1126   this.name = n;
U 1127   this.einUrl = e;
1128   this.ausUrl = a;
1129   this.statusUrl = s;
a29f5c 1130   this.status = st;
d6b78c 1131 }