/*
|
Aufzeichnungsplaner
|
Copyright (C) 2020 Ulrich Hilger, https://uhilger.de
|
|
This program is free software: you can redistribute it and/or modify
|
it under the terms of the GNU Affero General Public License as published by
|
the Free Software Foundation, either version 3 of the License, or
|
(at your option) any later version.
|
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU Affero General Public License for more details.
|
|
You should have received a copy of the GNU Affero General Public License
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
*/
|
|
function App() {
|
var self = this;
|
var wochentag;
|
var mone;
|
var channels;
|
var outPath;
|
var senderliste;
|
|
/**
|
* Den Aufnahmeplaner initialisieren
|
*/
|
this.init = function () {
|
self.wochentag = ['Sonntag','Montag','Dienstag','Mittwoch',
|
'Donnerstag','Freitag','Samstag' ];
|
|
// Monatskuerzel in englisch fuer den 'at'-Befehl
|
self.mone = ['jan', 'feb', 'mar', 'apr', 'may', 'jun',
|
'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];
|
|
self.senderliste = new Array();
|
/*
|
* die folgenden Konstanten koennten auch ueber eine Konfigurationsdatei
|
* oder eine API vom Server bereitgestellt werden
|
*/
|
self.channels = "/media/extssd/mc/channels.conf";
|
self.outPath = "/opt/tv/";
|
|
self.channelsLesen();
|
|
// Bedienelemente an Programmlogik binden
|
var elem = self.elementAnbinden("startdatum");
|
elem.valueAsDate = new Date();
|
self.elementAnbinden("bez");
|
self.elementAnbinden("startzeit");
|
self.elementAnbinden("dauer");
|
self.elementAnbinden("sender");
|
|
/*
|
* initial die Einstellungen einsammeln und
|
* an der Bedienoberflaeche zeigen
|
*/
|
//self.collectSettings();
|
};
|
|
/**
|
* Ein Element aus dem Document Object Model (DOM) an das Eingabe-Ereignis
|
* (oninput) binden um auf diese Weise dessen geaenderten Inhalt in die
|
* Ausgabe des Infotextes zu uebernehmen
|
*
|
* @param {type} ename name des anzubindenden Elements
|
* @returns {elem|Element} das angebundene Element
|
*/
|
this.elementAnbinden = function(ename) {
|
elem = document.getElementById(ename);
|
elem.oninput = self.collectSettings;
|
return elem;
|
};
|
|
/*
|
* collectSettings nimmt die aktuellen Einstellungen aus den Eingabeelementen
|
* und bildet eine Textausgabe aller aktuell eingegebenen Parameter
|
* sowie das Kommando fuer gnutv und gibt diese in den Elementen
|
* 'info' und 'cmd' aus.
|
*/
|
this.collectSettings = function() {
|
// das Startdatum bestimmen und in den Infotext uebernehmen
|
var start = self.getStart();
|
var infotext = "<br>Start: " + self.wochentag[start.getDay()] + ", "
|
+ self.datumZuDatumText(start)
|
+ ", " + self.zeitZuText(start, ":") + " Uhr";
|
|
// den Endezeitpunkt bestimmen und in den Infotext uebernehmen
|
var ende = self.getEnde();
|
var endzeit = self.wochentag[ende.getDay()] + ", "
|
+ self.datumZuDatumText(ende) + ", "
|
+ self.zeitZuText(ende, ":");
|
infotext = infotext + "<br>Ende: " + endzeit + " Uhr";
|
|
// die Dauer in Sekunden sowie in Minuten bestimmen und dem Infotext anfuegen
|
var dauerSekunden = document.getElementById("dauer").value;
|
infotext = infotext + "<br>Dauer: " + dauerSekunden / 60 + " Minuten"
|
+ " (" + dauerSekunden + " Sekunden)";
|
|
/*
|
* Die eingegebene Bezeichnung fuer die Aufnahme bestimmen und um
|
* Startdatum, -zeit und Sender ergaenzen und das Ganze in den Infotext
|
* uebernehmen
|
* Es wird '.ts' fuer 'transport stream' angefuegt, wenn keine
|
* Dateierweiterung in der Bezeichnung angegeben ist. Bei DVB wird der
|
* Inhalt ueblicherweise als 'transport stream' bezeichnet.
|
*/
|
var bez = document.getElementById("bez").value;
|
var dotpos = bez.indexOf(".");
|
var fname = self.outPath;
|
var senderElem = document.getElementById("sender");
|
var sender = senderElem.options[senderElem.selectedIndex].text;
|
|
var streamData = self.senderliste[senderElem.selectedIndex];
|
var streamElems = streamData.split("|");
|
var streamFreq = streamElems[1];
|
|
|
if(dotpos > -1) {
|
fname = fname + bez.substring(0, dotpos) + "-" + self.fts(start) + "-"
|
+ sender + bez.substring(dotpos);
|
} else {
|
fname = fname + bez + "-" + self.fts(start) + "-" + sender + ".mp4";
|
}
|
infotext = infotext + "<br>" + fname;
|
|
// den Infotext im DOM-Element 'info' anzeigen
|
document.getElementById("info").innerHTML = infotext;
|
|
/*
|
* im DOM-Element 'cmd' wird der Befehl zusammengstellt und angezeigt
|
* wie er fuer die Programmierung einer Aufzeichnung mit Hilfe von
|
* gnutv und at benoetigt wird.
|
*
|
* Beispiel:
|
* echo "gnutv -channels /media/extssd/mc/channels.conf
|
* -out file /home/fred/work/test-2020-02-01-1050-arteHD.ts
|
* -timeout 300 arteHD" | at 1050 feb 01
|
*
|
* echo "ffmpeg -i https://artesimulcast.akamaized.net/hls/live/2030993/artelive_de/index.m3u8
|
* -t 10800 -acodec copy -vcodec copy
|
* /home/ulli/tv/triangle-of-sadness-2024-11-17-2005-arte-HD.mp4" | at 2005 nov 17
|
*
|
*
|
*/
|
/*document.getElementById("cmd").innerHTML = 'echo "gnutv -channels '
|
+ self.channels + ' -out file '
|
+ fname + ' -timeout ' + dauerSekunden + ' ' + sender
|
+ '" | at ' + self.zeitZuText(start) + ' '
|
+ self.mone[start.getMonth()] + ' ' + start.getDate();*/
|
document.getElementById("cmd").innerHTML = 'echo "ffmpeg -i '
|
+ streamFreq + ' -t ' + dauerSekunden +
|
' -acodec copy -vcodec copy ' + fname + '" | at ' + self.zeitZuText(start) + ' '
|
+ self.mone[start.getMonth()] + ' ' + start.getDate();
|
|
/*
|
+ ' -out file '
|
+ fname + ' -timeout ' + dauerSekunden + ' ' + sender
|
+ '" | at ' + self.zeitZuText(start) + ' '
|
+ self.mone[start.getMonth()] + ' ' + start.getDate();
|
*/
|
};
|
|
/*
|
* getEnde fuegt dem Startzeitpunkt aus getStart() die Dauer hinzu
|
* und bildet so den Endzeitpunkt, der als Datumsobjekt zurueckgegeben wird
|
*/
|
this.getEnde = function() {
|
var endeZeitpunkt = self.getStart();
|
endeZeitpunkt.setMilliseconds(endeZeitpunkt.getMilliseconds()
|
+ (document.getElementById("dauer").value * 1000));
|
return endeZeitpunkt;
|
};
|
|
/*
|
* getStart setzt aus dem Datumseingabefeld und dem Schieberegler fuer die
|
* Startzeit den Startzeitpunkt zusammen und gibt diesen als Datumsobjekt
|
* zurueck
|
*
|
* Wenn das Datumseingabefeld kein Datum enthaelt, wird das heutige Datum
|
* mit der Zeit des Schiebereglers kombiniert.
|
*/
|
this.getStart = function() {
|
var startdatum = document.getElementById("startdatum").valueAsDate;
|
startdatum.setHours(0);
|
startdatum.setMilliseconds(startdatum.getMilliseconds()
|
+ (document.getElementById("startzeit").value * 1000));
|
return startdatum;
|
};
|
|
/*
|
* Die Sender aus der Datei channels.conf lesen und in eine
|
* HTML-Auswahlliste ueberfuehren
|
*/
|
this.channelsLesen = function() {
|
var url = 'channels.conf';
|
self.http_get(url, function (antwort) {
|
var zeilen = antwort.split("\n");
|
zeilen.sort();
|
self.senderliste = zeilen;
|
var senderAuswahl = document.getElementById("sender");
|
var sender;
|
var zElems;
|
for(var i = 0; i < zeilen.length; i++) {
|
zElems = zeilen[i].split("|");
|
sender = document.createElement("option");
|
sender.textContent = zElems[0];
|
sender.value = zElems[1];
|
senderAuswahl.appendChild(sender);
|
}
|
});
|
};
|
|
/**
|
* Die Funktion http_get ruft einen Inhalt ueber HTTP GET ab
|
*
|
* @param {type} url der aufzurufende URL
|
* @param {type} process die Funktion, der die Antwort uebergeben
|
* werden soll
|
*/
|
this.http_get = function (url, process) {
|
var xmlhttp = new XMLHttpRequest();
|
xmlhttp.onreadystatechange = function() {
|
if (this.readyState == 4 && this.status == 200) {
|
process(this.responseText);
|
}
|
};
|
xmlhttp.open("GET", url, true);
|
xmlhttp.send();
|
};
|
|
/* -----------------------------------------------------------------------
|
* Nachfolgend einige Hilfsfunktionen zur Umwandlung von Datum-Objekten
|
* zu Text.
|
*
|
* Solche Funktionen gibt es auch fertig in Bibliotheken wie
|
* z.B. Moment.js. Hier werden allerdings nur wenige solche
|
* Funktionen benoetigt so dass sich die zusaetzliche
|
* Abhaengigkeit nicht lohnt, die mit der Verwendung der Bibliothek
|
* entstuende.
|
* ---------------------------------------------------------------------- */
|
|
/*
|
* Aus einem Datums-Objekt einen Text im Format JJJJ-MM-TT machen
|
*/
|
this.datumZuText = function(datum) {
|
var tag = self.textZweistellig(datum.getDate());
|
var monat = self.textZweistellig(datum.getMonth() + 1);
|
var jahr = datum.getFullYear();
|
return jahr + "-" + monat + "-" + tag;
|
};
|
|
/*
|
* Aus einem Datums-Objekt einen Text im Format TT.MM.JJJJ machen
|
*/
|
this.datumZuDatumText = function(datum) {
|
var tag = self.textZweistellig(datum.getDate());
|
var monat = self.textZweistellig(datum.getMonth() + 1);
|
var jahr = datum.getFullYear();
|
return tag + "." + monat + "." + jahr;
|
};
|
|
/*
|
* Aus einem Datums-Objekt einen Text im Format SS:MM machen
|
*
|
* Das Trennzeichen, z.B. ":" kann im Parameter trennzeichen
|
* uebergeben werden. trennzeichen darf auch leer bleiben.
|
*/
|
this.zeitZuText = function(datum, trennzeichen) {
|
var std = self.textZweistellig(datum.getHours());
|
var min = self.textZweistellig(datum.getMinutes());
|
if(trennzeichen) {
|
return std + trennzeichen + min;
|
} else {
|
return std + "" + min;
|
}
|
};
|
|
/*
|
* Aus einer Zahl einen Text machen und dabei einstellige
|
* Werte mit einer Null auffuellen
|
*/
|
this.textZweistellig = function(zahl) {
|
if(zahl < 10) {
|
return "0" + zahl;
|
} else {
|
return zahl;
|
}
|
};
|
|
/**
|
* Aus einem Datum den Textausdruck JJJJ-MM-TT-hhmm machen
|
* (fts: file name timestamp)
|
*
|
* @param {type} datum das Datumsobjekt aus dem der Text gemacht werden soll
|
* @returns {String} der Text im Format JJJJ-MM-TT-hhmm
|
*/
|
this.fts = function(datum) {
|
return self.datumZuText(datum) + "-" + self.zeitZuText(datum);
|
};
|
}
|