From 89e41699fee6789130e20837831509bcacc9b1ff Mon Sep 17 00:00:00 2001
From: ulrich
Date: Mon, 24 Mar 2025 19:13:08 +0000
Subject: [PATCH] Beruecksichtigung eines gleichnamigen Untertitel-Files
---
src/de/uhilger/tango/api/MediaSteuerung.java | 235 +++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 198 insertions(+), 37 deletions(-)
diff --git a/src/de/uhilger/tango/api/MediaSteuerung.java b/src/de/uhilger/tango/api/MediaSteuerung.java
index 37e0d9e..09fa750 100644
--- a/src/de/uhilger/tango/api/MediaSteuerung.java
+++ b/src/de/uhilger/tango/api/MediaSteuerung.java
@@ -19,8 +19,10 @@
import com.google.gson.Gson;
import com.sun.net.httpserver.HttpExchange;
-import de.uhilger.tango.App;
+import de.uhilger.tango.PlaylistListener;
import de.uhilger.tango.Server;
+import static de.uhilger.tango.api.ListFileHandler.RB_VIDEOEXTS;
+import de.uhilger.tango.entity.Ablageort;
import de.uhilger.tango.entity.Abspielvorgang;
import de.uhilger.tango.entity.Abspieler;
import de.uhilger.tango.entity.Abspielliste;
@@ -30,11 +32,16 @@
import de.uhilger.tango.entity.Titel;
import de.uhilger.tango.store.FileStorage;
import de.uhilger.tango.store.Storage;
+import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -44,47 +51,74 @@
* Abspielgeraet.
*
* HTTP GET /mz/api/strg/abspieler/play/liste/[name]
+ * HTTP GET /mz/api/strg/abspieler/next
* HTTP GET /mz/api/strg/abspieler/ende
*
* HTTP POST /mz/api/strg/abspieler/play/titel mit dem Titel im Body
* HTTP POST /mz/api/strg/abspieler/play/stream mit dem Livestream im Body (nur Name gefuellt)
+ *
+ * DEPRECATED: HTTP POST /mz/api/strg/abspieler/weiter/titel mit dem Titel im Body
*
* HTTP GET /mz/api/strg/abspieler/pause
* HTTP GET /mz/api/strg/abspieler/stop
- * HTTP GET /mz/api/strg/abspieler/weiter
+ * HTTP GET /mz/api/strg/abspieler/seek/[sekunden]
*
* Faustregel: Anzahl Elemente eines URL plus 1 ist die Anzahl der Elemente des
* Ergebnisses von String.split.
*
+ * Mit der Funktion ende liefert die MediaSteuerung die Moeglichkeit, Titel aus
+ * einer Abspielliste gesteuert von Tango abzuspielen. Die Nutzung der Funktion wird
+ * ausgeloest vom Aufruf an abspieler/play/liste/[name]. Tango erwartet dann von einem
+ * Abspieler die Rueckmeldung, dass dieser den zuletzt von Tango an den
+ * Abspieler zum Abspielen uebermittelten Titel zuende abgespielt hat. Tango
+ * uebergibt dem Abspieler dann den naechsten Titel, bis die Abspielliste zuende ist.
+ *
+ * Diese Form unterscheidet sich vom Abspielen einer Abspielliste als einzelner
+ * Stream, wie es vom StreamHandler realisiert wird.
*
* @author Ulrich Hilger
* @version 1, 9.4.2021
*/
-public class MediaSteuerung extends AbstractHandler {
+public class MediaSteuerung extends AbstractHandler implements PlaylistListener {
private static final Logger logger = Logger.getLogger(MediaSteuerung.class.getName());
public static final String PL_CMD_PLAY = "play";
+ public static final String PL_CMD_SEEK = "seek";
public static final String PL_DEFAULT_PARAMS = "?titel=";
public static final String PL_PARAM_RUECK = "&r=";
- public static final String PL_API_STRG = "/api/strg/";
+ public static final String PL_API_STRG = "api/strg/";
public static final String PL_CMD_ENDE = "ende";
public static final String PL_CMD_STOP = "stop";
+ public static final String PL_CMD_VOLDN = "voldn";
+ public static final String PL_CMD_VOLUP = "volup";
public static final String PL_CMD_PAUSE = "pause";
- public static final String PL_CMD_PLAYON = "playon";
+ public static final String PL_CMD_PLAYON = "weiter";
+ public static final String PL_CMD_NEXT = "next";
public static final String PL_CMD_CALYPSO_STOP = "stop";
+ public static final String PL_CMD_CALYPSO_VOL_INC = "vol-inc";
+ public static final String PL_CMD_CALYPSO_VOL_DEC = "vol-dec";
public static final String PL_CMD_CALYPSO_PAUSE = "pause";
public static final String PL_CMD_CALYPSO_PLAYON = "playon";
public static final String DEFAULT_HOST = "http://localhost:9090";
+ public static final String RB_HOST = "host";
+ public static final String RB_PLAYERPARAMS = "playerparams";
+
private final Map spielt = new HashMap();
+
+ private final String conf;
+
+ public MediaSteuerung(String conf) {
+ this.conf = conf;
+ }
@Override
protected String get(HttpExchange e) {
String response;
String path = e.getRequestURI().toString();
String[] elems = path.split(Server.SLASH);
- FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
+ FileStorage fs = new FileStorage(conf);
logger.fine(path);
// Faustregel: Anzahl Elemente eines URL plus 1 ist die Anzahl der Elemente des
@@ -96,10 +130,25 @@
} else if(elems[5].equalsIgnoreCase(PL_CMD_STOP)) {
spielt.remove(elems[4]);
response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_STOP);
+ } else if(elems[5].equalsIgnoreCase(PL_CMD_VOLDN)) {
+ response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_VOL_DEC);
+ } else if(elems[5].equalsIgnoreCase(PL_CMD_VOLUP)) {
+ response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_VOL_INC);
} else if(elems[5].equalsIgnoreCase(PL_CMD_PAUSE)) {
response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_PAUSE);
- } else if(elems[5].equalsIgnoreCase(PL_CMD_PLAYON)) {
- response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_PLAYON);
+ //} else if(elems[5].equalsIgnoreCase(PL_CMD_PLAYON)) {
+ // response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_PLAYON);
+ } else if(elems[5].equalsIgnoreCase(PL_CMD_NEXT)) {
+ response = kommandoSenden(fs, elems[4], PL_CMD_CALYPSO_STOP);
+ //response = naechsterTitel(fs, elems[4]);
+ } else {
+ response = meldung("Ungueltiges Kommando: " + elems[5], AbstractHandler.RTC_NOT_FOUND);
+ }
+ break;
+ case 7:
+ if (elems[5].equalsIgnoreCase(PL_CMD_SEEK)) {
+ // /calypso/seek?pos=[sekunden]
+ response = kommandoSenden(fs, elems[4], "seek?pos=" + elems[6]);
} else {
response = meldung("Ungueltiges Kommando: " + elems[5], AbstractHandler.RTC_NOT_FOUND);
}
@@ -117,8 +166,26 @@
@Override
protected String post(HttpExchange e) {
String response;
+ String abspielerKmd = PL_CMD_PLAY;
+ String path = e.getRequestURI().toString();
+ String[] elems = path.split(Server.SLASH);
+ logger.info("POST elem 0: " + elems[0]);
+ logger.info("POST elem 1: " + elems[1]);
+ logger.info("POST elem 2: " + elems[2]);
+ logger.info("POST elem 3: " + elems[3]);
+ logger.info("POST elem 4: " + elems[4]);
+ logger.info("POST cmd: " + elems[5]);
+ // PLAYON ist deprecated
+ //if(elems[5].equalsIgnoreCase(PL_CMD_PLAYON)) {
+ // abspielerKmd = PL_CMD_CALYPSO_PLAYON;
+ //} else if(elems[5].equalsIgnoreCase(PL_CMD_PLAY)){
+ // abspielerKmd = PL_CMD_PLAY;
+ //}
+ if(elems[5].equalsIgnoreCase(PL_CMD_PLAY)){
+ abspielerKmd = PL_CMD_PLAY;
+ }
try {
- return urlAbspielen(e);
+ return urlAbspielen(e, abspielerKmd);
} catch (IOException ex) {
logger.log(Level.SEVERE, null, ex);
return meldung(ex.getLocalizedMessage(), 404);
@@ -126,31 +193,36 @@
}
// titel.katalogUrl + titel.pfad + titel.name
- private String urlAbspielen(HttpExchange e) throws IOException {
+ private String urlAbspielen(HttpExchange e, String abspielerKmd) throws IOException {
String path = e.getRequestURI().toString();
String[] elems = path.split(Server.SLASH);
- FileStorage fs = new FileStorage(App.getInitParameter(App.getRs(App.RB_AP_CONF)));
- if(elems[5].equalsIgnoreCase("titel")) {
+ FileStorage fs = new FileStorage(conf);
+ if(elems[6].equalsIgnoreCase("titel")) {
String titelJson = bodyLesen(e);
+ logger.finest("Titel aus Body: " + titelJson);
Gson gson = new Gson();
Object o = gson.fromJson(titelJson, fs.typeFromName(Titel.class.getSimpleName()).getType());
if(o instanceof Titel) {
Titel titel = (Titel) o;
+ logger.finest("Katalog-URL: " + titel.getKatalogUrl());
+ logger.finest("Titel-Pfad: " + titel.getPfad());
String titelUrl = titel.getKatalogUrl() + titel.getPfad() + titel.getName();
+ logger.finest("Titel-URL: " + titelUrl);
+
Entity entity = fs.read(FileStorage.ST_ABSPIELER, elems[4]);
if (entity instanceof Abspieler) {
Abspieler abspieler = (Abspieler) entity;
- String server = getEinstellung(fs, App.getRs(App.RB_HOST), DEFAULT_HOST);
- String signal = abspielKommando(fs, abspieler, server, titelUrl).toString();
+ String server = getEinstellung(fs, getResString(RB_HOST), DEFAULT_HOST);
+ String signal = abspielKommando(fs, abspieler, server, e.getHttpContext().getPath(), titel.getKatalogUrl(), titelUrl, abspielerKmd).toString();
abspielerKommandoSenden(signal);
- return signal + "gesendet.";
+ return signal + " gesendet.";
} else {
return meldung("Ungueltiger Abspieler.", 404);
}
} else {
return meldung("Ungueltiger Titel.", 404);
}
- } else if(elems[5].equalsIgnoreCase("stream")) {
+ } else if(elems[6].equalsIgnoreCase("stream")) {
String streamJson = bodyLesen(e);
Gson gson = new Gson();
Object o = gson.fromJson(streamJson, fs.typeFromName(Livestream.class.getSimpleName()).getType());
@@ -162,9 +234,9 @@
if (entity instanceof Abspieler) {
Abspieler abspieler = (Abspieler) entity;
String server = "";
- String signal = abspielKommando(fs, abspieler, server, stream.getUrl()).toString();
+ String signal = abspielKommando(fs, abspieler, server, "", "", stream.getUrl(), PL_CMD_PLAY).toString();
abspielerKommandoSenden(signal);
- return signal + "gesendet.";
+ return signal + " gesendet.";
} else {
return meldung("Ungueltiger Abspieler.", 404);
}
@@ -179,6 +251,7 @@
}
}
+
private String kommandoSenden(Storage s, String aName, String kommando) {
Entity entity = s.read(FileStorage.ST_ABSPIELER, aName);
if (entity instanceof Abspieler) {
@@ -187,12 +260,15 @@
kmd.append(abspieler.getUrl());
kmd.append(kommando);
String signal = kmd.toString();
+ //String server = getEinstellung(s, App.getRs(App.RB_HOST), DEFAULT_HOST);
+ //String signal = abspielKommando(s, abspieler, server, stream.getUrl(), PL_CMD_PLAY).toString();
abspielerKommandoSenden(signal);
return signal + " gesendet.";
} else {
return meldung("Abspielliste nicht gefunden.", AbstractHandler.RTC_NOT_FOUND);
}
}
+
private String ersterTitel(Storage s, String aName, String lName) {
String response;
@@ -272,7 +348,7 @@
vorgang.setTitelNr(titelNr);
spielt.put(abspieler.getName(), vorgang);
- String server = getEinstellung(s, App.getRs(App.RB_HOST), DEFAULT_HOST);
+ String server = getEinstellung(s, getResString(RB_HOST), DEFAULT_HOST);
/*
@@ -285,9 +361,12 @@
kmd.append(server);
kmd.append(titelUrl);
*/
- StringBuilder kmd = abspielKommando(s, abspieler, server, titelUrl);
+ StringBuilder kmd = abspielKommando(s, abspieler, server, "", "", titelUrl, PL_CMD_PLAY);
kmd.append(PL_PARAM_RUECK);
kmd.append(server);
+ if(!server.endsWith(Server.SLASH)) {
+ kmd.append(Server.SLASH);
+ }
kmd.append(PL_API_STRG);
kmd.append(abspieler.getName());
kmd.append("/ende");
@@ -295,35 +374,95 @@
return kmd.toString();
}
- private StringBuilder abspielKommando(Storage s, Abspieler abspieler, String server, String titelUrl) {
-
+ private StringBuilder abspielKommando(Storage s, Abspieler abspieler, String server, String ctx, String katalogUrl, String titelUrl, String abspielKmd) {
+ logger.finest("Server: " + server);
// Kommando an den Abspieler zusammenbauen
StringBuilder kmd = new StringBuilder();
kmd.append(abspieler.getUrl());
- kmd.append(PL_CMD_PLAY);
+ //kmd.append(PL_CMD_PLAY);
+ kmd.append(abspielKmd);
// Parameter fuer den Abspieler holen
- kmd.append(getEinstellung(s, App.getRs(App.RB_PLAYERPARAMS), PL_DEFAULT_PARAMS));
+ kmd.append(getEinstellung(s, getResString(RB_PLAYERPARAMS), PL_DEFAULT_PARAMS));
kmd.append(server);
kmd.append(titelUrl);
+
+ /*
+ Wenn eine Untertiteldatei gleichen Names vorliegt, wird
+ diese beim Abspielen aktiviert. Soll also kein Untertitel
+ erscheinen, darf keine Untertiteldatei beigelegt werden,
+ deren Name so lautet wie der abzuspielende Titel.
+
+ Beispiel: Titel mein-video.mp4 und eine Datei mein-video.srt aktiviert
+ die Unteritel-Datei. Lautet der Name der Untertiteldatei
+ stattdessen mein-video.de-de.forced.srt werden Untertitel
+ nicht aktiviert
+
+ */
+ if(isVideo(s, titelUrl)) {
+ if(hasSub((FileStorage) s, ctx, katalogUrl, titelUrl)) {
+ logger.info(titelUrl + " has subFile");
+ kmd.append("&sub=on");
+ }
+ }
+
return kmd;
}
- private String getEinstellung(Storage s, String key, String standardWert) {
- Entity entity = s.read(Einstellung.class.getSimpleName(), key);
- if (entity instanceof Einstellung) {
- Einstellung einstellung = (Einstellung) entity;
- Object o = einstellung.getValue();
- if(o instanceof String) {
- return o.toString();
- } else {
- return standardWert;
- }
- } else {
- return standardWert;
- }
+ private boolean hasSub(FileStorage s, String ctx, String katalogUrl, String titelUrl) {
+ //String titel = titelUrl.substring(0, titelUrl.lastIndexOf("."));
+ String titel = titelUrl.substring(katalogUrl.length());
+ logger.finest(titel);
+ String pfad = ablageortFromKatalog(s, ctx, katalogUrl);
+ File titelFile = new File(pfad, titel);
+ File parentFile = titelFile.getParentFile();
+ File subFile = new File(parentFile, titelFile.getName().substring(0, titelFile.getName().lastIndexOf(".")) + ".srt");
+ logger.finest("subFile abs path: " + subFile.getAbsolutePath());
+ boolean doesExist = subFile.exists();
+ logger.finest("subFile exist? " + doesExist);
+ return doesExist;
}
+ private boolean isVideo(Storage s, String titelUrl) {
+ String werte = getEinstellung(s, getResString(RB_VIDEOEXTS), "mp4");
+ String[] exts = werte.split(",");
+ for(String ext : exts) {
+ //extMap.put(ext, typ);
+ if(titelUrl.toLowerCase().endsWith(ext.toLowerCase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private String ablageortFromKatalog(Storage s, String ctx, String katalogUrl) {
+ String ort = "";
+ logger.finest("start");
+ String typ = Ablageort.class.getSimpleName();
+ logger.finest("typ: " + typ);
+ //FileStorage store = new FileStorage(conf);
+ FileStorage store = (FileStorage) s;
+ List<String> orte = store.list(typ);
+ Iterator<String> i = orte.iterator();
+ while(i.hasNext()) {
+ String ortName = i.next();
+ logger.finest("ortname: " + ortName);
+ Entity e = store.read(typ, ortName);
+ if(e instanceof Ablageort) {
+ Ablageort ablageort = (Ablageort) e;
+ logger.log(Level.FINE, "Ablageort {0}{1}", new Object[]{ctx, ablageort.getUrl()});
+ logger.fine(ablageort.getOrt());
+ if(ablageort.getUrl().endsWith(katalogUrl)) {
+ logger.finest("MATCH for " + katalogUrl + " Pfad " + ablageort.getOrt());
+ ort = ablageort.getOrt();
+ }
+ //server.createContext(ctx + ablageort.getUrl(),
+ //new ListFileHandler(new File(ablageort.getOrt()).getAbsolutePath(), conf));
+ }
+ }
+ return ort;
+ }
+
private void abspielerKommandoSenden(String kommando) {
/*
TODO hier evtl. mit mehreren Versuchen ausgleichen,
@@ -346,4 +485,26 @@
setReturnCode(code);
return text;
}
+
+ /* ------- PlaylistListener implementation ------ */
+
+ @Override
+ public void titleRemoved(String listName, int titleIndex) {
+ Set keys = spielt.keySet();
+ Iterator<String> keyIterator = keys.iterator();
+ boolean found = false;
+ while(keyIterator.hasNext() && !found) {
+ String abspielerName = keyIterator.next();
+ Abspielvorgang av = (Abspielvorgang) spielt.get(abspielerName);
+ if(av.getListe().equals(listName)) {
+ found = true;
+ int tnr = av.getTitelNr();
+ if(tnr > titleIndex) {
+ av.setTitelNr(--tnr);
+ logger.info("Abspieler " + abspielerName + " Liste " + av.getListe() + " titelnr jetzt " + tnr);
+ spielt.put(abspielerName, av);
+ }
+ }
+ }
+ }
}
--
Gitblit v1.9.3