From 929228226e08e352769810f729f0e9644a781bec Mon Sep 17 00:00:00 2001 From: undisclosed Date: Sun, 08 Jan 2023 13:35:06 +0000 Subject: [PATCH] Calypso neu gebaut auf Nutzung von mpv, alte Fassung entfernt --- src/de/uhilger/calypso/neu/MeldeThread.java | 10 /dev/null | 72 ------ src/de/uhilger/calypso/neu/ProzessLauscher.java | 3 src/de/uhilger/calypso/neu/actor/PlayActor.java | 87 +++++++ src/de/uhilger/calypso/neu/http/Server.java | 69 +++++ src/de/uhilger/calypso/neu/http/ApiHandler.java | 146 ++++++++++++ src/de/uhilger/calypso/neu/AppProperties.java | 15 - src/de/uhilger/calypso/neu/Rueckmelder.java | 46 +++ src/de/uhilger/calypso/neu/App.java | 19 + src/de/uhilger/calypso/neu/http/HttpApi.java | 97 ++++++++ src/de/uhilger/calypso/neu/actor/StopServerActor.java | 53 ++++ src/de/uhilger/calypso/neu/actor/ShellActor.java | 73 ++++++ 12 files changed, 599 insertions(+), 91 deletions(-) diff --git a/src/de/uhilger/calypso/App.java b/src/de/uhilger/calypso/App.java deleted file mode 100644 index 3b17088..0000000 --- a/src/de/uhilger/calypso/App.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - Calypso - Media Player Remote Control via HTTP for Raspberry Pi - Copyright (C) 2021-2023 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso; - -import de.uhilger.calypso.handler.MPVPlayer; -import de.uhilger.calypso.handler.MPlayer; -import de.uhilger.calypso.handler.OMXPlayer; -import de.uhilger.calypso.handler.Player; -import de.uhilger.calypso.handler.VLCPlayer; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Hauptklasse von Calypso - * - * Aufruf mit<br> - * java -jar calypso.jar port=9000 ctx="/calypso"<br> - * java -jar calypso.jar nfs-prefix="/media/mc" port=9000<br> - * java -Djava.util.logging.config.file=logging.properties -jar ..<br> - * - * Der Parameter nfs-prefix bewirkt, dass beim Abspielen relative Pfade - * mit diesem Praefix verbunden werden und setzt voraus, dass auf der - * Maschine ein NFS-Mount ueber /etc/fstab eingerichtet ist.<br> - * <br> - * Anmerkung anlaesslich der Aenderung auf VLC (2.1.2023):<br> - * Mit Calypso wurde erstmals jdk.httpserver anstelle von Tomcat - * einsetzt. Es war in diesem Punkt noch ein Laborversuch und sollte - * unter Wiederverwendung der wesentlichen Teile bei Gelegenheit - * neu gebaut werden. - * - * @author Ulrich Hilger - * @version 0.2 vom 2.1.2023, 0.1 vom 20.03.2021 als Nachfolger von Pirc (02.2013-03.2021) - */ -public class App { - - private static final Logger logger = Logger.getLogger(App.class.getName()); - - public static final String IP_PORT = "port"; - public static final String IP_WWW_DATA = "www-data"; - public static final String IP_NFS_PREFIX = "nfs-prefix"; - public static final String IP_PLAYER = "player"; - public static final String VLC_PLAYER = "vlc"; - public static final String OMX_PLAYER = "omx"; - public static final String M_PLAYER = "mpl"; - public static final String MPV_PLAYER = "mpv"; - public static final String OMX_WD = "omx.wd"; - public static final String CTX = "ctx"; - public static final String CONF_PATH = "conf"; - - public static final String DEFAULT_CTX = "/calypso"; - - private static HashMap initParams; - private static Process playerproc; - private static Player player; - - /** - * @param args the command line arguments - */ - public static void main(String[] args) { - Logger.getLogger(App.class.getName()).log(Level.INFO, new File(".").getAbsolutePath()); - initParams = new HashMap(); - for(String arg: args) { - String[] argParts = arg.split("="); - initParams.put(argParts[0], argParts[1]); - } - - String playerType = getInitParameter(IP_PLAYER); - switch(playerType) { - case MPV_PLAYER: - player = new MPVPlayer(); - break; - case M_PLAYER: - player = new MPlayer(); - break; - case VLC_PLAYER: - player = new VLCPlayer(); - break; - case OMX_PLAYER: - player = new OMXPlayer(); - break; - } - Server server = new Server(Integer.parseInt(getInitParameter(IP_PORT))); - server.setPath(getInitParameter(CONF_PATH)); - String ctx = getInitParameter(CTX); - if(ctx != null && ctx.length() > 0) { - server.setContextName(ctx); - } else { - server.setContextName(DEFAULT_CTX); - } - try { - server.start(playerType); - } catch (IOException ex) { - Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex); - } - } - - public static void stop() { - System.exit(0); - } - - public static String getInitParameter(String pname) { - String param = null; - Object o = initParams.get(pname); - if(o != null) { - param = o.toString(); - } - return param; - } - - public static Process getPlayerProcess() { - return playerproc; - } - - public static void setPlayerProcess(Process p) { - playerproc = p; - } - - public static Player getPlayer() { - return player; - } - - public static void setPlayer(Player pl) { - player = pl; - } - - - -} diff --git a/src/de/uhilger/calypso/Betrachter.java b/src/de/uhilger/calypso/Betrachter.java deleted file mode 100644 index 3890072..0000000 --- a/src/de/uhilger/calypso/Betrachter.java +++ /dev/null @@ -1,143 +0,0 @@ -package de.uhilger.calypso; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.net.URL; -import java.util.logging.Level; -import java.util.logging.Logger; -import javax.imageio.ImageIO; -import org.tw.pi.framebuffer.FrameBuffer; - -/** - * Klasse zum Betrachten von Fotografien auf dem Fernseher - * mit dem Raspberry Pi - * - * Diese Klasse verwendet die Klasse JavaFrameBuffer - * von Thomas Welsch, die die Ausgabe direkt in den - * FrameBuffer des Raspberry Pi erlaubt. - * - * Der JavaFrameBuffer ist mit Calypso - * enthalten und erfordert, dass beim Start die native - * Programmbibliothek namens 'libFrameBuffer.so' eingebunden wird, die im Verteilpaket - * von Calypso enthalten ist. Zum Einbinden der nativen Biliothek genuegt die - * Angabe von -Djava.library.path=/pfad/zum/lib-ordner im Startskript von - * Calypso. - * - * Durch die Verwendung des Framebuffer kann das Betrachten von - * Bildern auf dem Fernseher erfolgen ohne, dass auf dem Raspberry Pi - * eine grafische Bedienoberflaeche wie z.B. das X Windowing System, - * XBMC oder OpenELEC, usw. laufen muss. Es genuegt Java - * im 'headless mode', was zudem die Bedienbarkeit aus der Ferne via - * HTTP hinzufuegt. - * - * @author Ulrich Hilger, https://uhilger.de - * @author Published under the terms and conditions of - * the <a href="http://www.gnu.org/licenses/agpl-3.0" target="_blank">GNU Affero General Public License</a> - * - * @version 2 vom 11. Februar 2022, Version 1 war vom 15.1.2014 - */ -public class Betrachter { - - public static final long serialVersionUID = 42L; - - private static final Logger logger = Logger.getLogger(Betrachter.class.getName()); - - public static final String P_FBDEV = "fbdev"; - public static final String STANDARD_FBDEV = "/dev/fb0"; - - public static final String P_URL = "u"; - public static final String P_X = "x"; - public static final String P_Y = "y"; - public static final String P_WIDTH = "w"; - public static final String P_HEIGHT = "h"; - - //public static final String PATH_ZEIGEN = "/zeigen"; - //public static final String PATH_LOESCHEN = "/loeschen"; - - private FrameBuffer jfb; - private BufferedImage img; - private Graphics2D g; - - public void init(String devName) { - String device = devName; - if(device == null) { - device = STANDARD_FBDEV; - } - jfb = new FrameBuffer(device, false); - img = jfb.getScreen(); - g = img.createGraphics(); - } - - public void close() { - jfb.close(); - } - - public void jfbHelloWorld() { - g.setColor(Color.RED); - g.drawString("Hello World !", 50, 50); - jfb.updateScreen(); - } - - /** - * Anzeigen eines Bildes mit Hilfe des JavaFrameBuffers - * - * Diese Methode laedt ein Bild via HTTP oder HTTPS und - * schreibt es in den Framebuffer zur Anzeige - * - * @param urlStr Adresse des Bildes, das angezeigt werden soll - * @param x waagerechte Koordinate der gewuenschten Position der linken oberen Ecke des Bildes - * @param y senkrechte Koordinate der gewuenschten Position der linken oberen Ecke des Bildes - * @param w Breite in Bildpunkten, in der das Bild angezeigt werden soll - * @param h Hoehe in Bildpunkten, in der das Bild angezeigt werden soll - */ - public String jfbBildZeigen(String urlStr, int x, int y, int w, int h) { - String antwort = "jfbBildZeigen hat nicht geklappt"; - BufferedImage webimg = null; - try { - /* - vgl. http://java.kompf.de/java2d.html - */ - //System.setProperty("sun.java2d.opengl","true"); - URL url = new URL(urlStr); - webimg = ImageIO.read(url); - g.drawImage(webimg, x, y, w, h, null); - jfb.updateScreen(); - antwort = urlStr + " geladen"; - } catch (Exception e) { - antwort = e.getMessage(); - } - return antwort; - } - - /** - * Leeren des FrameBuffers - * - * Hier wird einfach ein Linux-Prozess eroeffnet, der das - * Kommando dd if=/dev/zero of=/dev/fb0 ausfuehrt und - * den Framebuffer mit Nullwerten fuellt - */ - public String fbLeeren(String deviceName) { - String antwort = "fbLeeren hat nicht geklappt"; - try { - String cmd = "dd if=/dev/zero of=" + deviceName; - Process leeren = Runtime.getRuntime().exec(cmd); - /*MeldeThread t = new MeldeThread(); - t.setProcess(leeren); - t.lauscherHinzufuegen(new ProzessLauscherImpl() { - @Override - public void prozessBeendet() { - // etwas tun, wenn fertig... - } - }); - t.start();*/ - antwort = "Prozess gestartet"; - } catch(Exception ex) { - logger.log(Level.FINE, ex.getMessage(), ex); - } - return antwort; - } - - - -} diff --git a/src/de/uhilger/calypso/OMXLogLeser.java b/src/de/uhilger/calypso/OMXLogLeser.java deleted file mode 100644 index 8450481..0000000 --- a/src/de/uhilger/calypso/OMXLogLeser.java +++ /dev/null @@ -1,165 +0,0 @@ -package de.uhilger.calypso; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class OMXLogLeser { - - private static final Logger logger = Logger.getLogger(OMXLogLeser.class.getName()); - - public static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); - - private static final long MILLIS = (long) 1000; - - private static final long MINSEC = (long) 60; - - - public String logDirLesen(File logDir) throws IOException, FileNotFoundException, ParseException { - Blocks blocks = new Blocks(); - File[] files = logDir.listFiles(); - for(File file : files) { - lesen(file, blocks); - } - return blocks.getTimeString(); - } - - /** - * - * <p>Die Spieldauer laut OMX-Log ergibt sich aus dem Zeitstempel des - * letzten Eintrags abzueglich des Zeitstempels des - * ersten Eintrags abzueglich der Pausen</p> - * - * <p>Eine Pause ist der Zeitraum vom Zeitstempel eines Eintrags mit - * <code>Keyboard: character p (0x70)</code> bis zum Zeitstempel des - * nächsten Eintrags mit <code>Keyboard: character p</code></p> - * - * - * @param logfile - * @param blocks - * @return die Spieldauer als String im Format H:MM:SS - * @throws FileNotFoundException - * @throws IOException - * @throws ParseException - */ - public void lesen(File logfile, Blocks blocks) throws FileNotFoundException, IOException, ParseException { - boolean inPause = false; - logger.info("Starting to parse log.."); - Date parseStart = new Date(); - long lineCount = 0; - InputStream is = new FileInputStream(logfile); - BufferedReader r = new BufferedReader(new InputStreamReader(is)); - String firstLine = r.readLine(); - ++lineCount; - String lastLine = ""; - String line = r.readLine(); - //Blocks blocks = new Blocks(); - Block currentBlock = new Block(); - while(line != null) { - ++lineCount; - if(currentBlock.getStart() == null) { - currentBlock.setStart(line.substring(0, 8)); - } - if(line.contains("Keyboard: character p")) { - if(inPause) { - currentBlock.setStart(line.substring(0, 8)); - } else { - currentBlock.setEnd(line.substring(0, 8)); - blocks.add(currentBlock); - currentBlock = new Block(); - } - inPause = !inPause; - } - lastLine = line; - line = r.readLine(); - } - currentBlock.setEnd(lastLine.substring(0, 8)); - blocks.add(currentBlock); - Date parseEnd = new Date(); - long timeMillis = parseEnd.getTime() - parseStart.getTime(); - long timeSeconds = timeMillis / MILLIS; - long secMillis = timeSeconds * MILLIS; - long restMillis = timeMillis - secMillis; - logger.log(Level.INFO, - "{0} lines parsed in {1} seconds and {2} milliseconds.", - new Object[]{lineCount, timeSeconds, restMillis}); - //return blocks.getTimeString(); - } - - class Block { - private String start = null; - private String end = null; - - public long getDuration() throws ParseException { - Date startDate = sdf.parse(start); - Date endDate = sdf.parse(end); - return endDate.getTime() - startDate.getTime(); - } - - public String getStart() { - return start; - } - - public void setStart(String start) { - //logger.log(Level.FINER, "Start: ''{0}''", start); - this.start = start; - } - - public String getEnd() { - return end; - } - - public void setEnd(String end) { - //logger.log(Level.FINER, "End: ''{0}''", end); - this.end = end; - } - - - } - - class Blocks { - - private final List<Block> blocks = new ArrayList(); - - public void add(Block block) { - blocks.add(block); - } - - public long getDuration() throws ParseException { - long duration = (long) 0; - Iterator<Block> i = blocks.iterator(); - while(i.hasNext()) { - Block b = i.next(); - duration += b.getDuration(); - } - return duration; - } - - public String getTimeString() throws ParseException { - long diff = getDuration(); - long h = diff / MILLIS / MINSEC / MINSEC; - long hmillis = h * MINSEC * MINSEC * MILLIS; - long m = (diff - hmillis) / MILLIS / MINSEC; - long mmillis = m * MINSEC * MILLIS; - long s = (diff - hmillis - mmillis) / MILLIS; - //logger.log(Level.FINER, "{0}:{1}:{2}", new Object[]{h, m, s}); - return h + ":" + m + ":" + s; - } - } -} diff --git a/src/de/uhilger/calypso/Server.java b/src/de/uhilger/calypso/Server.java deleted file mode 100644 index 9948ece..0000000 --- a/src/de/uhilger/calypso/Server.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - Calypso - Media Player Remote Control via HTTP for Raspberry Pi - Copyright (C) 2021-2023 Ulrich Hilger - - 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/>. -*/ -package de.uhilger.calypso; - -import com.sun.net.httpserver.HttpServer; -import de.uhilger.calypso.handler.BasePlayer; -import de.uhilger.calypso.handler.CmdHandler; -import de.uhilger.calypso.handler.DBusHandler; -import de.uhilger.calypso.handler.FileHandler; -import de.uhilger.calypso.handler.LogHandler; -import de.uhilger.calypso.handler.MPVKillHandler; -import de.uhilger.calypso.handler.MPVPlayHandler; -import de.uhilger.calypso.handler.MPVPlayer; -import de.uhilger.calypso.handler.MPVSeekHandler; -import de.uhilger.calypso.handler.MPlayHandler; -import de.uhilger.calypso.handler.MPlayer; -import de.uhilger.calypso.handler.OMXPlayer; -import de.uhilger.calypso.handler.PingHandler; -import de.uhilger.calypso.handler.PlayHandler; -import de.uhilger.calypso.handler.PlayOnHandler; -import de.uhilger.calypso.handler.SeekHandler; -import de.uhilger.calypso.handler.SocketHandler; -import de.uhilger.calypso.handler.StopServerHandler; -import de.uhilger.calypso.handler.VLCKillHandler; -import de.uhilger.calypso.handler.VLCPlayer; -import de.uhilger.calypso.handler.VLCSeekHandler; -import java.io.File; -import java.io.IOException; -import java.util.logging.Logger; -import java.net.InetSocketAddress; -import java.util.concurrent.Executors; -import java.util.logging.Level; - -/** - * Die Klasse Server implementiert die HTTP-Schnittstelle zum - * Mediaplayer. Es wird ein Player-Prozesss fuer das Abspielen - * eines Titels gestartet. Mit Stopp oder Ende des Titels endet - * auch der Abspielprozess.<br> - * <br> - * zum Abspielen:<br> - * /calypso/play?title=http://ein.titel.mp3&r=http://rueckmelde.url<br> - * <br> - * waehrend des Abspielens:<br> - * /calypso/pause<br> - * /calypso/seek?pos=[sekunden]<br> - * /calypso/stop<br> - * <br> - * sonstige Funktionen:<br> - * /calypso/ping<br> - * /calypso/server/stop<br> - * <br> - * verworfene Funktionen<br> - * /calypso/vol-inc<br> - * /calypso/vol-dec<br> - * Die Lautstaerke wird in aller Regel am Geraet geregelt, an das der - * Zuspieler (der Raspi) angeschlossen ist. Eine Regelung ueber den - * Zuspieler ist daher eher selten erforderlich. - * - * @author Ulrich Hilger - */ -public class Server { - - private static final Logger logger = Logger.getLogger(Server.class.getName()); - - private int port; - - private String contextName; - - private String path; - - public Server(int port) { - this.port = port; - } - - public void setPort(int port) { - this.port = port; - } - - public void setPath(String path) { - this.path = path; - } - - /** - * - * @param contextName e.g. '/calypso' or '/cal' - */ - public void setContextName(String contextName) { - this.contextName = contextName; - } - - public void start(String playerType) throws IOException { - logger.log(Level.INFO, "Server starting on port {0}", port); - - HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); - - if (playerType.equals(App.OMX_PLAYER)) { - server.createContext(contextName + "/play", new PlayHandler(BasePlayer.F_PLAY)); - server.createContext(contextName + "/seek", new SeekHandler(OMXPlayer.F_SEEK)); - server.createContext(contextName + "/stop", new CmdHandler(OMXPlayer.CMD_STOP)); - server.createContext(contextName + "/pause", new CmdHandler(OMXPlayer.CMD_PAUSE_RESUME)); - server.createContext(contextName + "/vol-inc", new CmdHandler(OMXPlayer.CMD_INC_VOL)); - server.createContext(contextName + "/vol-dec", new CmdHandler(OMXPlayer.CMD_DEC_VOL)); - server.createContext(contextName + "/info", new CmdHandler(OMXPlayer.CMD_TOGGLE_INFO)); - server.createContext(contextName + "/log", new LogHandler()); - server.createContext(contextName + "/playon", new PlayOnHandler(OMXPlayer.F_PLAY_ON)); - } else if (playerType.equals(App.VLC_PLAYER)) { - server.createContext(contextName + "/play", new PlayHandler(BasePlayer.F_PLAY)); - server.createContext(contextName + "/pause", new DBusHandler(VLCPlayer.CMD_PAUSE_RESUME)); - //server.createContext(contextName + "/pause", new CmdHandler("pause")); - //server.createContext(contextName + "/seek", new DBusHandler(VLCPlayer.CMD_SEEK)); - server.createContext(contextName + "/seek", new VLCSeekHandler(VLCPlayer.CMD_SEEK)); - server.createContext(contextName + "/stop", new VLCKillHandler()); - } else if (playerType.equals(App.M_PLAYER)) { - server.createContext(contextName + "/play", new MPlayHandler()); - server.createContext(contextName + "/pause", new CmdHandler(MPlayer.CMD_PAUSE_RESUME)); - server.createContext(contextName + "/stop", new CmdHandler(MPlayer.CMD_STOP)); - } else if (playerType.equals(App.MPV_PLAYER)) { - server.createContext(contextName + "/play", new MPVPlayHandler()); - server.createContext(contextName + "/pause", new SocketHandler(path + MPVPlayer.CMD_PAUSE_RESUME)); - server.createContext(contextName + "/seek", new MPVSeekHandler(path + MPVPlayer.CMD_SEEK)); - server.createContext(contextName + "/stop", new MPVKillHandler()); - } - server.createContext(contextName + "/ui", new FileHandler(App.getInitParameter(App.IP_WWW_DATA))); - server.createContext(contextName + "/ping", new PingHandler(BasePlayer.F_PING)); - server.createContext(contextName + "/server/stop", new StopServerHandler()); - //server.setExecutor(null); // creates a default executor - server.setExecutor(Executors.newFixedThreadPool(20)); - server.start(); - } - -} diff --git a/src/de/uhilger/calypso/handler/AbstractHandler.java b/src/de/uhilger/calypso/handler/AbstractHandler.java deleted file mode 100644 index a46d368..0000000 --- a/src/de/uhilger/calypso/handler/AbstractHandler.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public abstract class AbstractHandler implements HttpHandler { - - private static final Logger logger = Logger.getLogger(AbstractHandler.class.getName()); - - protected String cmd; - protected Map map; - - @Override - public void handle(HttpExchange t) throws IOException { - logger.log(Level.FINE, "RequestURI: {0}", t.getRequestURI().toString()); - StringBuilder params = buildParams(t); - String antwort = process(t, params.toString()); - sendResponse(t, cmd, antwort); - } - - protected abstract String process(HttpExchange t, String params); - - protected StringBuilder buildParams(HttpExchange t) { - map = getQueryMap(t); - StringBuilder params = new StringBuilder(); - return params; - } - - protected void sendResponse(HttpExchange t, String cmd, String antwort) throws IOException { - String response = getResponseString(map, cmd, antwort); - t.sendResponseHeaders(200, response.length()); - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); - } - - public void setCmd(String cmd) { - this.cmd = cmd; - } - - public String getCmd(String cmd) { - return this.cmd; - } - - /* --- --- */ - - /* - Den Query-Teil einer URL in die Parameter zerlegen - - Die Zerlegung erfolgt mit String.split nach - & und dann nach = - */ - protected Map getQueryMap(HttpExchange t) { - HashMap map = new HashMap(); - String query = t.getRequestURI().getQuery(); - if(query != null && query.length() > 0) { - String qParts[] = query.split("&"); - for(String qPart : qParts) { - logger.finer("qPart: " + qPart); - String pParts[] = qPart.split("="); - map.put(pParts[0], pParts[1]); - logger.finer("pParts[0]: " + pParts[0] + ", pParts[1]: " + pParts[1]); - } - } - return map; - } - - protected String getResponseString(Map map, String cmd, String antwort) { - Set keys = map.keySet(); - StringBuilder buf = new StringBuilder(); - buf.append(cmd); - buf.append(System.lineSeparator()); - keys.forEach((Object key) -> { - buf.append("key: "); - buf.append(key); - buf.append(System.lineSeparator()); - buf.append("value: "); - buf.append(map.get(key)); - buf.append(System.lineSeparator()); - //logger.log(Level.FINE, "key {0} value {1}", new Object[]{key, map.get(key)}); - }); - buf.append(antwort); - return buf.toString(); - } - -} diff --git a/src/de/uhilger/calypso/handler/BasePlayer.java b/src/de/uhilger/calypso/handler/BasePlayer.java deleted file mode 100644 index 19576a4..0000000 --- a/src/de/uhilger/calypso/handler/BasePlayer.java +++ /dev/null @@ -1,115 +0,0 @@ -package de.uhilger.calypso.handler; - -import de.uhilger.calypso.App; -import static de.uhilger.calypso.handler.OMXPlayer.CMD_STOP; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulli - */ -public abstract class BasePlayer implements Player { - - private static final Logger logger = Logger.getLogger(BasePlayer.class.getName()); - - public static final String F_PLAY = "play"; - public static final String F_PING = "ping"; - - - @Override - public void prozessBeendet(String meldeUrlStr) { - logger.log(Level.INFO, - "Abspielen beendet, sende Meldung an {0}.", - new Object[]{meldeUrlStr}); - try { - HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection(); - conn.setRequestMethod("GET"); - conn.connect(); - int status = conn.getResponseCode(); - logger.log(Level.INFO, - "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", - new Object[]{meldeUrlStr, status}); - /* - fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht - oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen, - dass der Player noch spielt. Damit in einem solchen Fall der Zeiger - auf den Abspielprozess nicht verloren geht, wird der Zeiger nicht - auf null gesetzt. - */ - //App.setPlayerProcess(null); - } catch(IOException ex) { - logger.log(Level.INFO, ex.getMessage(), ex); - } - } - - @Override - public String tilgen() { - logger.log(Level.INFO,"Player tilgen."); - String antwort; // = null; - try { - Process o = App.getPlayerProcess(); - if(o == null) { - antwort = "Es ist kein Player zum Beenden vorhanden."; - //App.setPlayerProcess(null); - } else { - kommando(CMD_STOP); // setzt den Prozess der App auf null - antwort = "Player gestoppt."; - } - } - catch(Exception ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - public String getParam(Map map, String key) { - Object o = map.get(key); - if(o != null) { - return o.toString(); - } else { - return null; - } - } - - /** - * Dem laufenden Abspielprozess ein Kommando uebermitteln - * @param k das Kommando laut - * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a> - * @return die Antwort des Servers - */ - @Override - public String kommando(String k) { - String antwort; // = null; - try { - //Object o = t.getAttribute(App.PI_PLAYER); - Process o = App.getPlayerProcess(); - if(o == null) { - //App.setPlayerProcess(null); - //servletContext.removeAttribute(PI_PLAYER); - //t.setAttribute(App.PI_PLAYER, null); - antwort = "Es wird nichts abgespielt dem ein Kommando gesendet werden kann."; - } else { - Process player_process = o; - OutputStream os = player_process.getOutputStream(); - Writer out = new BufferedWriter(new OutputStreamWriter(os)); - out.write(k); - out.flush(); - antwort = "Kommando '" + k + "' ausgefuehrt."; - } - } - catch(IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - -} diff --git a/src/de/uhilger/calypso/handler/CmdHandler.java b/src/de/uhilger/calypso/handler/CmdHandler.java deleted file mode 100644 index a8abc29..0000000 --- a/src/de/uhilger/calypso/handler/CmdHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class CmdHandler extends AbstractHandler { - - private static final Logger logger = Logger.getLogger(CmdHandler.class.getName()); - - public CmdHandler(String cmd) { - this.cmd = cmd; - } - - protected String process(HttpExchange t, String params) { - String antwort = App.getPlayer().kommando(cmd); - logger.log(Level.FINE, antwort); - return antwort; - } - -} diff --git a/src/de/uhilger/calypso/handler/DBusHandler.java b/src/de/uhilger/calypso/handler/DBusHandler.java deleted file mode 100644 index 0f6be4d..0000000 --- a/src/de/uhilger/calypso/handler/DBusHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Obwohl ein laufendes VLC-Programm mit Tastaturbefehlen gesteuert - * werden kann, funktioniert es nicht, dem Prozess einen Tastaturbefehl - * wie z.B. S fuer Stopp ueber process.getOutputStream zu 'schreiben', - * moeglicherweise, weil auf dem Raspberry Pi das VLC als Kommando- - * zeilenprogramm ohne UI laeuft. Im Augenblick gelingt nur die Steuerung - * ueber dbus. Hier muss noch geprueft werden, ob das auch mit Windows und - * Mac OS klappt, was aber fuer einen Einsatz auf dem Raspberry Pi - * nebensaechlich ist. - * - * Die Steuerung von VLC via dbus wiederum folgt dem Standard mpris - * (Media Player Remote Interfacing Specification) von freedesktop.org, - * der von zahlreichen Mediaplayern unterstuetzt wird. - * - * @author Ulrich Hilger - */ -public class DBusHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(DBusHandler.class.getName()); - - public DBusHandler(String cmd) { - super(cmd); - } - - @Override - protected String process(HttpExchange t, String params) { - String antwort;// = null; - try { - StringBuilder kommando = new StringBuilder(); - kommando.append(VLCPlayer.DBUS_PREFIX); - kommando.append(cmd); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - antwort = "Kommando ausgefuehrt: " + kommando; - } catch (IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } -} diff --git a/src/de/uhilger/calypso/handler/FileHandler.java b/src/de/uhilger/calypso/handler/FileHandler.java deleted file mode 100644 index caaf149..0000000 --- a/src/de/uhilger/calypso/handler/FileHandler.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class FileHandler implements HttpHandler { - - private static final Logger logger = Logger.getLogger(FileHandler.class.getName()); - - private final String basePath; - - public FileHandler(String basePath) { - this.basePath = basePath; - } - - @Override - public void handle(HttpExchange t) throws IOException { - String ctxPath = t.getHttpContext().getPath(); - String uriPath = t.getRequestURI().getPath(); - String fName = uriPath.substring(ctxPath.length()); - if(fName.endsWith("/")) { - fName += "index.html"; - } - OutputStream os = t.getResponseBody(); - File file = new File(basePath, fName); - if(file.exists()) { - t.sendResponseHeaders(200, file.length()); - InputStream in = new FileInputStream(file); - int b = in.read(); - while(b > -1) { - os.write(b); - b = in.read(); - } - in.close(); - } else { - String response = fName + " not found."; - byte[] bytes = response.getBytes(StandardCharsets.UTF_8); - t.sendResponseHeaders(404, bytes.length); - os.write(bytes); - } - os.flush(); - os.close(); - } - -} diff --git a/src/de/uhilger/calypso/handler/LogHandler.java b/src/de/uhilger/calypso/handler/LogHandler.java deleted file mode 100644 index f22421c..0000000 --- a/src/de/uhilger/calypso/handler/LogHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.OMXLogLeser; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; -import java.text.ParseException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class LogHandler extends AbstractHandler { - - private static final Logger logger = Logger.getLogger(LogHandler.class.getName()); - - @Override - public void handle(HttpExchange t) throws IOException { - logger.log(Level.FINE, "RequestURI: {0}", t.getRequestURI().toString()); - StringBuilder params = buildParams(t); - String antwort = process(t, params.toString()); - sendResponse(t, cmd, antwort); - } - - @Override - protected void sendResponse(HttpExchange t, String cmd, String antwort) throws IOException { - t.sendResponseHeaders(200, antwort.length()); - OutputStream os = t.getResponseBody(); - os.write(antwort.getBytes()); - os.close(); - } - - - @Override - protected String process(HttpExchange t, String params) { - /* - OMXLogLeser leser = new OMXLogLeser(); - String lines = "Log nicht lesbar."; - try { - logger.info(new File(".").getAbsolutePath()); - lines = leser.lesen(new File("omxplayer.log")); - } catch (IOException ex) { - Logger.getLogger(LogHandler.class.getName()).log(Level.SEVERE, null, ex); - } catch (ParseException ex) { - Logger.getLogger(LogHandler.class.getName()).log(Level.SEVERE, null, ex); - } - */ - return ""; - } - -} diff --git a/src/de/uhilger/calypso/handler/MPVKillHandler.java b/src/de/uhilger/calypso/handler/MPVKillHandler.java deleted file mode 100644 index f3240f0..0000000 --- a/src/de/uhilger/calypso/handler/MPVKillHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; - -/** - * - * @author Ulrich Hilger - */ -public class MPVKillHandler extends AbstractHandler { - - @Override - protected String process(HttpExchange t, String params) { - Process p = App.getPlayerProcess(); - p.destroy(); - App.setPlayerProcess(null); - String antwort = "Player-Prozess beendet."; - return antwort; - } - -} diff --git a/src/de/uhilger/calypso/handler/MPVPlayHandler.java b/src/de/uhilger/calypso/handler/MPVPlayHandler.java deleted file mode 100644 index 52e84a1..0000000 --- a/src/de/uhilger/calypso/handler/MPVPlayHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Ulrich Hilger - */ -public class MPVPlayHandler extends AbstractHandler { - - private static final Logger logger = Logger.getLogger(MPVPlayHandler.class.getName()); - - @Override - protected String process(HttpExchange t, String params) { - Player player = App.getPlayer(); - String antwort = player.abspielen( - player.getParam(map, "titel"), params, player.getParam(map, "r"), "1"); - logger.log(Level.FINE, antwort); - return antwort; - } - - - -} diff --git a/src/de/uhilger/calypso/handler/MPVPlayer.java b/src/de/uhilger/calypso/handler/MPVPlayer.java deleted file mode 100644 index fc169dd..0000000 --- a/src/de/uhilger/calypso/handler/MPVPlayer.java +++ /dev/null @@ -1,123 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import de.uhilger.calypso.MeldeThread; -import java.io.IOException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class MPVPlayer extends BasePlayer implements Player { - - private static final Logger logger = Logger.getLogger(MPVPlayer.class.getName()); - - /* -echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket -{"data":190.482000,"error":"success"} - -echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket - - { "command": ["set_property", "pause", true] } - { "error": "success" } - -{"command": ["cycle", "pause"]} - - */ - public static final String SOCK_PREFIX = ""; - public static final String CMD_PAUSE_RESUME = "pause"; - public static final String CMD_SEEK = "seek"; - - @Override - public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) { - String antwort;// = null; - try { - //Object o = t.getAttribute(App.PI_PLAYER); - Process o = App.getPlayerProcess(); - if(o != null) { - tilgen(); - } - StringBuilder kommando = new StringBuilder("mpv --input-ipc-server=/tmp/mpvsocket --no-terminal "); - - /* - mpv versucht Musikstuecke mit Album-Bildern in den Metadaten als Video - abzuspielen und bricht ab. - (diese Einstellung muss noch parametriert und erweitert werden) - */ - if(urlStr.contains(".mp3")) { - kommando.append("--vo=null "); - } - /* - if(parameter != null) { - kommando.append(parameter); - kommando.append(BLANK); - } - */ - if(urlStr.startsWith("http")) { - kommando.append(urlStr.replace(" ", "%20")); - kommando.append("?t="); - kommando.append(token); - } else { - /* - //url z.B.: Filme/H/HEAT_D2.m4v - - hier muss noch der Pfad hinzugefuegt werden, unter - dem auf dem raspi die Datenquelle via NFS eingebunden ist, - z.B. /media/mc/ - dieser Teil des Pfades muss in pirc als Init-Parameter oder - etwas aehnliches hinterlegt sein, weil es lokal zum jeweils - verwendeten raspi gehoert - - */ - - String pfad = App.getInitParameter("nfs-prefix"); - kommando.append(pfad); - - kommando.append(urlStr); - } - //kommando.append(" vlc://quit"); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - if(meldeUrlStr != null) { - MeldeThread mt = new MeldeThread(); - mt.setProcess(player_process); - mt.lauscherHinzufuegen(this); - mt.setMeldeUrl(meldeUrlStr); - mt.start(); - } - //servletContext.setAttribute(App.PI_PLAYER, player_process); - //t.setAttribute(App.PI_PLAYER, player_process); - App.setPlayerProcess(player_process); - //Runtime.getRuntime().exec("killall dbus-daemon"); - antwort = "Abspielen gestartet, url: " + urlStr; - } - catch(IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - - /* - public String kommando(String k) { - if(k.equalsIgnoreCase(VLCPlayer.CMD_STOP)) { - Process p = App.getPlayerProcess(); - p.destroy(); - App.setPlayerProcess(null); - } - String antwort = "Kommando '" + k + "' ausgefuehrt."; - return antwort; - } -*/ - - @Override - public StringBuilder buildParams(HttpExchange t, Map m) { - return new StringBuilder(); - } - - -} diff --git a/src/de/uhilger/calypso/handler/MPVSeekHandler.java b/src/de/uhilger/calypso/handler/MPVSeekHandler.java deleted file mode 100644 index 097c6d4..0000000 --- a/src/de/uhilger/calypso/handler/MPVSeekHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * http://server:9090/calypso/seek?pos=30 (30 Sekunden vor) oder pos=-30 (zurueck) - * - * echo '{"command": ["seek", '30']}' | socat - /tmp/mpvsocket - * echo '{"command": ["seek", '-30']}' | socat - /tmp/mpvsocket - * - * in einem Shell Skript - * echo '{"command": ["seek", '$1']}' | socat - /tmp/mpvsocket - * - * - * @author Ulrich Hilger - */ -public class MPVSeekHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(MPVSeekHandler.class.getName()); - - public MPVSeekHandler(String cmd) { - super(cmd); - } - - @Override - protected String process(HttpExchange t, String params) { - String antwort;// = null; - try { - StringBuilder kommando = new StringBuilder(); - //kommando.append(VLCPlayer.DBUS_PREFIX); - kommando.append(cmd); - kommando.append(params); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - antwort = "Kommando ausgefuehrt: " + kommando; - } catch (IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - @Override - protected StringBuilder buildParams(HttpExchange t) { - Player player = App.getPlayer(); - StringBuilder params = super.buildParams(t); - - if (player instanceof MPVPlayer) { - String pos = player.getParam(map, "pos"); - if (!pos.isEmpty()) { - params.append(" "); - params.append(pos); - } - } - - logger.log(Level.FINER, "params: " + params.toString()); - return params; - } -} diff --git a/src/de/uhilger/calypso/handler/MPlayHandler.java b/src/de/uhilger/calypso/handler/MPlayHandler.java deleted file mode 100644 index 7ccb685..0000000 --- a/src/de/uhilger/calypso/handler/MPlayHandler.java +++ /dev/null @@ -1,27 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Ulrich Hilger - */ -public class MPlayHandler extends AbstractHandler { - - private static final Logger logger = Logger.getLogger(MPlayHandler.class.getName()); - - @Override - protected String process(HttpExchange t, String params) { - Player player = App.getPlayer(); - String antwort = player.abspielen( - player.getParam(map, "titel"), params, player.getParam(map, "r"), "1"); - logger.log(Level.FINE, antwort); - return antwort; - } - - - -} diff --git a/src/de/uhilger/calypso/handler/MPlayer.java b/src/de/uhilger/calypso/handler/MPlayer.java deleted file mode 100644 index 6539233..0000000 --- a/src/de/uhilger/calypso/handler/MPlayer.java +++ /dev/null @@ -1,88 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import de.uhilger.calypso.MeldeThread; -import java.io.IOException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Ulrich Hilger - */ -public class MPlayer extends BasePlayer { - - private static final Logger logger = Logger.getLogger(MPlayer.class.getName()); - - public static final String CMD_STOP = "q"; - public static final String CMD_PAUSE_RESUME = "p"; - - @Override - public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) { - String antwort;// = null; - try { - //Object o = t.getAttribute(App.PI_PLAYER); - Process o = App.getPlayerProcess(); - if(o != null) { - tilgen(); - } - StringBuilder kommando = new StringBuilder("mplayer -cache 2048 -cache-min 80 -really-quiet -framedrop "); - /* - if(parameter != null) { - kommando.append(parameter); - kommando.append(BLANK); - } - */ - if(urlStr.startsWith("http")) { - kommando.append(urlStr.replace(" ", "%20")); - //kommando.append("?t="); - //kommando.append(token); - } else { - /* - //url z.B.: Filme/H/HEAT_D2.m4v - - hier muss noch der Pfad hinzugefuegt werden, unter - dem auf dem raspi die Datenquelle via NFS eingebunden ist, - z.B. /media/mc/ - dieser Teil des Pfades muss in pirc als Init-Parameter oder - etwas aehnliches hinterlegt sein, weil es lokal zum jeweils - verwendeten raspi gehoert - - */ - - String pfad = App.getInitParameter("nfs-prefix"); - kommando.append(pfad); - - kommando.append(urlStr); - } - //kommando.append(" vlc://quit"); - //kommando.append(" >>/dev/null 2>&1"); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - if(meldeUrlStr != null) { - MeldeThread mt = new MeldeThread(); - mt.setProcess(player_process); - mt.lauscherHinzufuegen(this); - mt.setMeldeUrl(meldeUrlStr); - mt.start(); - } - //servletContext.setAttribute(App.PI_PLAYER, player_process); - //t.setAttribute(App.PI_PLAYER, player_process); - App.setPlayerProcess(player_process); - //Runtime.getRuntime().exec("killall dbus-daemon"); - antwort = "Abspielen gestartet, url: " + urlStr; - } - catch(IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - @Override - public StringBuilder buildParams(HttpExchange t, Map m) { - return new StringBuilder(); - } - -} diff --git a/src/de/uhilger/calypso/handler/OMXPlayer.java b/src/de/uhilger/calypso/handler/OMXPlayer.java deleted file mode 100644 index f012ad9..0000000 --- a/src/de/uhilger/calypso/handler/OMXPlayer.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import de.uhilger.calypso.MeldeThread; -import de.uhilger.calypso.ProzessLauscher; -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Methoden zur Ausfuehrung des Programmes omxplayer des Raspberry Pi - * sowie zum Senden von Kommandos an eine laufende Instanz des - * omxplayer. - * - * Die Klasse OMXPlayer stellt als abstrakte Basisklasse ihre Methoden - * den Handler-Klassen zur Verfuegung. - * - * @author ulrich - */ -public class OMXPlayer extends BasePlayer implements Player , ProzessLauscher { - - private static final Logger logger = Logger.getLogger(OMXPlayer.class.getName()); - - public static final String NAME = "omxplayer"; - - public static final String BLANK = " "; - public static final String CMD_TOGGLE_INFO = "z"; - public static final String CMD_DEC_SPEED = "1"; - public static final String CMD_DEC_VOL = "-"; - public static final String CMD_INC_SPEED = "2"; - public static final String CMD_INC_VOL = "="; // oder "+"; - public static final String CMD_NEXT_AUDIO = "k"; - public static final String CMD_NEXT_CHAPTER = "o"; - public static final String CMD_NEXT_SUB = "m"; - public static final String CMD_PAUSE_RESUME = "p"; - public static final String CMD_PREV_AUDIO = "j"; - public static final String CMD_PREV_CHAPTER = "i"; - public static final String CMD_PREV_SUB = "n"; - public static final String CMD_STOP = "q"; - public static final String CMD_TOGGLE_SUB = "s"; - public static final String F_PLAY_ON = "playon"; - public static final String F_SEEK = "seek"; - public static final String OPT_HDMI_AUDIO = "-o%20hdmi"; - public static final String OPT_LOCAL_AUDIO = "-o%20local"; - public static final String PFEIL_HERAUF = "5b41"; - public static final String PFEIL_HERUNTER = "5b42"; - public static final String PFEIL_LINKS = "5b44"; - public static final String PFEIL_RECHTS = "5b43"; - public static final String SP_RUECK_30 = "rueck30"; - public static final String SP_RUECK_600 = "rueck600"; - public static final String SP_VOR_30 = "rueck30"; - public static final String SP_VOR_600 = "vor600"; - - @Override - public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) { - String antwort;// = null; - try { - Process o = App.getPlayerProcess(); - if(o != null) { - tilgen(); - } - List<String> kommando = new ArrayList(); - kommando.add(NAME); - kommando.addAll(Arrays.asList(parameter.split(BLANK))); - if(urlStr.startsWith("http")) { - kommando.add(urlStr.replace(" ", "%20")); - } else { - kommando.add(App.getInitParameter("nfs-prefix") + urlStr); - } - logger.log(Level.FINE, "parameter: {0}", parameter); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - ProcessBuilder pb = new ProcessBuilder(kommando); - pb.directory(new File(System.getProperty("omx.wd"))); - Process player_process = pb.start(); - if(meldeUrlStr != null) { - MeldeThread mt = new MeldeThread(); - mt.setProcess(player_process); - mt.lauscherHinzufuegen(this); - mt.setMeldeUrl(meldeUrlStr); - mt.start(); - } - App.setPlayerProcess(player_process); - antwort = "Abspielen gestartet, url: " + urlStr; - } - catch(IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - @Override - public StringBuilder buildParams(HttpExchange t, Map map) { - StringBuilder params = new StringBuilder(); - params.append("-o "); - params.append(getParam(map, "o")); - params.append(" --threshold "); - params.append(getParam(map, "th")); - params.append(" --timeout "); - params.append(getParam(map, "ti")); - String log = getParam(map, "log"); - if (log != null && log.equalsIgnoreCase("true")) { - params.append(" --genlog"); - } - return params; - } - - - /** - * Einen eventuell laufenden Abspielprozess beenden und den - * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen - Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch - eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr - aktuell ist. - * - * Mit der Methode tilgen kann man eine solche Referenz - entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung - weiterer Kommandos. - * - * @return die Antwort des Servers - */ - /* - @Override - public String tilgen() { - String antwort; // = null; - try { - Process o = App.getPlayerProcess(); - if(o == null) { - antwort = "Es ist kein Player zum Beenden vorhanden."; - //App.setPlayerProcess(null); - } else { - kommando(CMD_STOP); // setzt den Prozess der App auf null - antwort = "Player gestoppt."; - } - } - catch(Exception ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - */ - - /* ------ Implementierung ProzessLauscher ----------------- */ - - /* - @Override - public void prozessBeendet(String meldeUrlStr) { - try { - HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection(); - conn.setRequestMethod("GET"); - conn.connect(); - int status = conn.getResponseCode(); - logger.log(Level.INFO, - "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", - new Object[]{meldeUrlStr, status}); - /* - fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht - oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen, - dass der Player noch spielt. Damit in einem solchen Fall der Zeiger - auf den Abspielprozess nicht verloren geht, wird der Zeiger nicht - auf null gesetzt. - */ - //App.setPlayerProcess(null); - /* - } catch(IOException ex) { - logger.log(Level.INFO, ex.getMessage(), ex); - } - } - */ -} diff --git a/src/de/uhilger/calypso/handler/PingHandler.java b/src/de/uhilger/calypso/handler/PingHandler.java deleted file mode 100644 index 5ecd735..0000000 --- a/src/de/uhilger/calypso/handler/PingHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import java.io.IOException; -import java.io.OutputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class PingHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(PingHandler.class.getName()); - - public PingHandler(String cmd) { - super(cmd); - } - - protected String process(HttpExchange t, String params) { - logger.log(Level.FINE, cmd); - return cmd; - } - - protected void sendResponse(HttpExchange t, String cmd, String antwort) throws IOException { - t.sendResponseHeaders(200, antwort.length()); - OutputStream os = t.getResponseBody(); - os.write(antwort.getBytes()); - os.close(); - } - -} diff --git a/src/de/uhilger/calypso/handler/PlayHandler.java b/src/de/uhilger/calypso/handler/PlayHandler.java deleted file mode 100644 index 7b09208..0000000 --- a/src/de/uhilger/calypso/handler/PlayHandler.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. - */ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Play - * - * rpi4-az:9090/avd/play?titel=/Filme/S/sound_city.m4v&th=60&ti=60&o=local - * - * OMXPlayer.abspielenMitParameternUndRueckmeldung( String urlStr, String - * parameter, String meldeUrlStr, String token) - * - * Parameter des Aufrufs play als query (th threshold, ti timeout) - * - * ?titel=/Filme/S/sound_city.m4v &ti=60 &th=60 &o=local|hdmi|both - * &r=http://uhilger.de/mc/api/usw - * - * r muss ganz wegbleiben, wenn keine Rueckmeldung gewuescht ist - * - * @author ulrich - */ -public class PlayHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(PlayHandler.class.getName()); - - public PlayHandler(String cmd) { - super(cmd); - } - - - @Override - protected StringBuilder buildParams(HttpExchange t) { - StringBuilder params = super.buildParams(t); - params.append(App.getPlayer().buildParams(t, map)); - return params; - } - - - /* - protected StringBuilder buildParams(HttpExchange t) { - StringBuilder params = super.buildParams(t); - params.append("-o "); - params.append(getParam(map, "o")); - params.append(" --threshold "); - params.append(getParam(map, "th")); - params.append(" --timeout "); - params.append(getParam(map, "ti")); - String log = getParam(map, "log"); - if (log != null && log.equalsIgnoreCase("true")) { - params.append(" --genlog"); - } - return params; - } - */ - - @Override - protected String process(HttpExchange t, String params) { - if (cmd.equalsIgnoreCase(BasePlayer.F_PLAY)) { - try { - //FileUtils.deleteDirectory(new File(System.getProperty("omx.wd"), "omx-logs")); - FileSystem fs = FileSystems.getDefault(); - Path path = fs.getPath(System.getProperty("omx.wd"), "omx-logs"); - if(path.toFile().exists()) { - deleteDirectory(path); - } - //Files.delete(path); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - } - Player player = App.getPlayer(); - String antwort = player.abspielen( - player.getParam(map, "titel"), params, player.getParam(map, "r"), "1"); - logger.log(Level.FINE, antwort); - return antwort; - } - - protected void deleteDirectory(Path start) throws IOException { - Files.walkFileTree(start, new SimpleFileVisitor<Path>() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException e) - throws IOException { - if (e == null) { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } else { - // directory iteration failed - throw e; - } - } - }); - } - -} diff --git a/src/de/uhilger/calypso/handler/PlayOnHandler.java b/src/de/uhilger/calypso/handler/PlayOnHandler.java deleted file mode 100644 index 957677e..0000000 --- a/src/de/uhilger/calypso/handler/PlayOnHandler.java +++ /dev/null @@ -1,87 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import de.uhilger.calypso.OMXLogLeser; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.file.FileSystem; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * z.B. - * http://rpi4-az:9090/avd/playon?th=1&ti=240&o=local&log=true&titel=http://amd-srv:9090/srv/Filme/C/casino_royale.m4v - * - * @author ulrich - */ -public class PlayOnHandler extends PlayHandler { - - private static final Logger logger = Logger.getLogger(PlayOnHandler.class.getName()); - - public static final String LOG_DIR = "omx-logs"; - public static final String LOG_EXT = "log"; - public static final String DASH = "-"; - public static final String DOT = "."; - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); - - public PlayOnHandler(String cmd) { - super(cmd); - } - - /* - 1. buildParams - 2. process - */ - @Override - protected StringBuilder buildParams(HttpExchange t) { - File logDir = logSichern(); - StringBuilder params = super.buildParams(t); - params.append(" --pos "); - try { - params.append(dauerBestimmen(logDir)); - } catch (IOException | ParseException ex) { - logger.log(Level.SEVERE, null, ex); - } - return params; - } - - private File logSichern() { - String wd = System.getProperty(App.OMX_WD); - File zielOrdner = new File(wd, LOG_DIR); - try { - // omxplayer.log umbenennen - FileSystem fs = FileSystems.getDefault(); - Path logDatei = fs.getPath(wd, OMXPlayer.NAME + DOT + LOG_EXT); - Date now = new Date(); - String neuerName = OMXPlayer.NAME + DASH + sdf.format(now) + DOT + LOG_EXT; - Files.move(logDatei, logDatei.resolveSibling(neuerName)); - - // Unterverzeichnis ggf. erzeugen - zielOrdner.mkdirs(); - - // omxplayer-datum.log verschieben - Path quellDatei = fs.getPath(wd, neuerName); - Path zielPfad = fs.getPath(wd, LOG_DIR); - Files.move(quellDatei, zielPfad.resolve(quellDatei.getFileName()), REPLACE_EXISTING); - } catch (IOException ex) { - logger.log(Level.SEVERE, null, ex); - } - return zielOrdner; - } - - private String dauerBestimmen(File logDir) throws IOException, FileNotFoundException, ParseException { - OMXLogLeser leser = new OMXLogLeser(); - return leser.logDirLesen(logDir); - } - -} diff --git a/src/de/uhilger/calypso/handler/Player.java b/src/de/uhilger/calypso/handler/Player.java deleted file mode 100644 index 9808bcb..0000000 --- a/src/de/uhilger/calypso/handler/Player.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.ProzessLauscher; -import java.util.Map; - -/** - * - * @author ulrich - */ -public interface Player extends ProzessLauscher { - - /** - * Einen Prozess zum Abspielen mit dem omxplayer starten - * @param urlStr URL der Quelle, die abgespielt werden soll - * @param token - * @return Antwort des Servers - */ - /* - public String abspielen(String urlStr, String token) { - return abspielenMitParametern(urlStr, null, token); - } - */ - /* - public String abspielenMitRueckmeldung(String urlStr, String meldeUrlStr, String token) { - return abspielenMitParameternUndRueckmeldung(urlStr, null, meldeUrlStr, token); - } - */ - /** - * Einen Prozess zum Abspielen mit dem omxplayer starten - * und Parameter uebergeben.Moegliche Parameter fuer das Abspielen mit dem omxplayer - beschreibt die Seite - <a href="https://github.com/huceke/omxplayer/blob/master/README.md"target="_blank">Aufstellung der Parameter</a>.Die Zeichenkette parameter enthaelt Eintraege wie z.B. - * App.OPT_LOCAL_AUDIO oder App.OPT_HDMI_AUDIO. - Mehrere Parameter werden mit App.BLANK getrennt. - * @param urlStr der URL der Quelle, die abgespielt werden soll - * @param parameter die Parameter, die vom omxplayer angewendet werden sollen - * @param token - * @return Antwort des Servers - */ - /* - public String abspielenMitParametern(String urlStr, String parameter, String token) { - return abspielenMitParameternUndRueckmeldung(urlStr, parameter, null, token); - } - */ - String abspielen(String urlStr, String parameter, String meldeUrlStr, String token); - - /** - * Dem laufenden Abspielprozess ein Kommando uebermitteln - * @param k das Kommando laut - * <a href="https://github.com/huceke/omxplayer/blob/master/README.md" target="_blank">Liste der Kommandos</a> - * @return die Antwort des Servers - */ - String kommando(String k); - - StringBuilder buildParams(HttpExchange t, Map m); - - String getParam(Map map, String key); - - /* ------ Implementierung ProzessLauscher ----------------- */ - void prozessBeendet(String meldeUrlStr); - - /** - * Einen eventuell laufenden Abspielprozess beenden und den - * Servlet-Kontext bereinigen.Diese Methode kann auch verwendet werden, wenn es beim normalen - Abspielen zu Fehlern kommt und womoeglich der Servlet-Kontext noch - eine Referenz zu einem Abspielprozess enthaelt, die nicht mehr - aktuell ist. - * - * Mit der Methode tilgen kann man eine solche Referenz - entfernen und gibt so das Objekt wieder frei fuer die Ausfuehrung - weiterer Kommandos. - * - * @return die Antwort des Servers - */ - String tilgen(); - -} diff --git a/src/de/uhilger/calypso/handler/SeekHandler.java b/src/de/uhilger/calypso/handler/SeekHandler.java deleted file mode 100644 index 9d3c255..0000000 --- a/src/de/uhilger/calypso/handler/SeekHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class SeekHandler extends PlayHandler { - - private static final Logger logger = Logger.getLogger(SeekHandler.class.getName()); - - public SeekHandler(String cmd) { - super(cmd); - } - - @Override - protected String process(HttpExchange t, String params) { - Player player = App.getPlayer(); - String antwort = player.abspielen( - player.getParam(map, "titel"), params, player.getParam(map, "r"), "1"); - logger.log(Level.FINE, antwort); - return antwort; - } - - /* - start "C:Program FilesVLCvlc.exe" rel="nofollow" "D:MoviesThe Italian Job.avi" --start-time 12 --stop-time 20 - - You simply have to use the command line as given above, with the file paths and the time changed as needed. - The numbers 12 and 20 in the command line indicate 12 seconds and 20 seconds respectively. - - - --global-key-play-pause=<string> - Play/Pause - Select the hotkey to use to swap paused state. - */ - protected StringBuilder buildParams(HttpExchange t) { - Player player = App.getPlayer(); - StringBuilder params = super.buildParams(t); - if(player instanceof OMXPlayer) { - params.append(" --pos "); - params.append(player.getParam(map, "pos")); - } - return params; - } - -} diff --git a/src/de/uhilger/calypso/handler/SocketHandler.java b/src/de/uhilger/calypso/handler/SocketHandler.java deleted file mode 100644 index 8fce603..0000000 --- a/src/de/uhilger/calypso/handler/SocketHandler.java +++ /dev/null @@ -1,46 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Hier muss noch die Implementierung mit Unix Domain Sockets folgen, - * sobald Java 16 fuer 64-bit Raspberry Pi 4 erhaeltlich ist. - * - * Bis dahin wird hier (dirty trick) ein Shell Skript aufgerufen, - * das mit Hilfe des Tools socat das Kommando ausfuehrt. socat muss - * dafuer auf dem Raspberry Pi installiert sein. - * - * Kommandos - * - * pause: echo '{"command": ["cycle", "pause"]}' | socat - /tmp/mpvsocket - * seek: echo '{"command": ["seek", '30']}' | socat - /tmp/mpvsocket - * - * @author Ulrich Hilger - */ -public class SocketHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(SocketHandler.class.getName()); - - public SocketHandler(String cmd) { - super(cmd); - } - - @Override - protected String process(HttpExchange t, String params) { - String antwort;// = null; - try { - StringBuilder kommando = new StringBuilder(); - kommando.append(MPVPlayer.SOCK_PREFIX); - kommando.append(cmd); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - antwort = "Kommando ausgefuehrt: " + kommando; - } catch (IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } -} diff --git a/src/de/uhilger/calypso/handler/StopServerHandler.java b/src/de/uhilger/calypso/handler/StopServerHandler.java deleted file mode 100644 index 1bf848b..0000000 --- a/src/de/uhilger/calypso/handler/StopServerHandler.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - AV-Direktor - Control OMXPlayer on Raspberry Pi via HTTP - Copyright (C) 2021 Ulrich Hilger - - 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/>. -*/ - -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; -import de.uhilger.calypso.App; -import java.io.IOException; -import java.io.OutputStream; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class StopServerHandler extends OMXPlayer implements HttpHandler { - - @Override - public void handle(HttpExchange exchange) throws IOException { - Logger.getLogger(StopServerHandler.class.getName()).info(exchange.getRequestURI().toString()); - this.kommando(CMD_STOP); - String response = "Server stopped"; - exchange.sendResponseHeaders(200, response.length()); - OutputStream os = exchange.getResponseBody(); - os.write(response.getBytes()); - os.flush(); - os.close(); - Logger.getLogger(StopServerHandler.class.getName()).info("stopping app."); - App.stop(); - //exchange.getHttpContext().getServer().stop(5); - } - - -} diff --git a/src/de/uhilger/calypso/handler/VLCKillHandler.java b/src/de/uhilger/calypso/handler/VLCKillHandler.java deleted file mode 100644 index 34325f1..0000000 --- a/src/de/uhilger/calypso/handler/VLCKillHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license - * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template - */ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; - -/** - * - * @author ulli - */ -public class VLCKillHandler extends AbstractHandler { - - @Override - protected String process(HttpExchange t, String params) { - Process p = App.getPlayerProcess(); - p.destroy(); - App.setPlayerProcess(null); - String antwort = "Player-Prozess beendet."; - return antwort; - } - -} diff --git a/src/de/uhilger/calypso/handler/VLCPlayer.java b/src/de/uhilger/calypso/handler/VLCPlayer.java deleted file mode 100644 index c2c1aba..0000000 --- a/src/de/uhilger/calypso/handler/VLCPlayer.java +++ /dev/null @@ -1,104 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import de.uhilger.calypso.MeldeThread; -import java.io.IOException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author ulrich - */ -public class VLCPlayer extends BasePlayer implements Player { - - private static final Logger logger = Logger.getLogger(VLCPlayer.class.getName()); - - public static final String CMD_STOP = "s"; - public static final String DBUS_PREFIX = "dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player."; - public static final String CMD_PAUSE_RESUME = "PlayPause"; - public static final String CMD_SEEK = "Seek"; - public static final String CMD_VOLUME = "Volume"; - - @Override - public String abspielen(String urlStr, String parameter, String meldeUrlStr, String token) { - String antwort;// = null; - try { - //Object o = t.getAttribute(App.PI_PLAYER); - Process o = App.getPlayerProcess(); - if(o != null) { - tilgen(); - } - StringBuilder kommando = new StringBuilder("vlc --fullscreen "); - /* - if(parameter != null) { - kommando.append(parameter); - kommando.append(BLANK); - } - */ - if(urlStr.startsWith("http")) { - kommando.append(urlStr.replace(" ", "%20")); - kommando.append("?t="); - kommando.append(token); - } else { - /* - //url z.B.: Filme/H/HEAT_D2.m4v - - hier muss noch der Pfad hinzugefuegt werden, unter - dem auf dem raspi die Datenquelle via NFS eingebunden ist, - z.B. /media/mc/ - dieser Teil des Pfades muss in pirc als Init-Parameter oder - etwas aehnliches hinterlegt sein, weil es lokal zum jeweils - verwendeten raspi gehoert - - */ - - String pfad = App.getInitParameter("nfs-prefix"); - kommando.append(pfad); - - kommando.append(urlStr); - } - kommando.append(" vlc://quit"); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - if(meldeUrlStr != null) { - MeldeThread mt = new MeldeThread(); - mt.setProcess(player_process); - mt.lauscherHinzufuegen(this); - mt.setMeldeUrl(meldeUrlStr); - mt.start(); - } - //servletContext.setAttribute(App.PI_PLAYER, player_process); - //t.setAttribute(App.PI_PLAYER, player_process); - App.setPlayerProcess(player_process); - //Runtime.getRuntime().exec("killall dbus-daemon"); - antwort = "Abspielen gestartet, url: " + urlStr; - } - catch(IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - - /* - public String kommando(String k) { - if(k.equalsIgnoreCase(VLCPlayer.CMD_STOP)) { - Process p = App.getPlayerProcess(); - p.destroy(); - App.setPlayerProcess(null); - } - String antwort = "Kommando '" + k + "' ausgefuehrt."; - return antwort; - } -*/ - - @Override - public StringBuilder buildParams(HttpExchange t, Map m) { - return new StringBuilder(); - } - - -} diff --git a/src/de/uhilger/calypso/handler/VLCSeekHandler.java b/src/de/uhilger/calypso/handler/VLCSeekHandler.java deleted file mode 100644 index 8da3a3a..0000000 --- a/src/de/uhilger/calypso/handler/VLCSeekHandler.java +++ /dev/null @@ -1,58 +0,0 @@ -package de.uhilger.calypso.handler; - -import com.sun.net.httpserver.HttpExchange; -import de.uhilger.calypso.App; -import java.io.IOException; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * dbus-send --type=method_call --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 - * org.mpris.MediaPlayer2.Player.Seek int64:-5000000 - * - * @author Ulrich Hilger - */ -public class VLCSeekHandler extends CmdHandler { - - private static final Logger logger = Logger.getLogger(VLCSeekHandler.class.getName()); - - public VLCSeekHandler(String cmd) { - super(cmd); - } - - @Override - protected String process(HttpExchange t, String params) { - String antwort;// = null; - try { - StringBuilder kommando = new StringBuilder(); - kommando.append(VLCPlayer.DBUS_PREFIX); - kommando.append(cmd); - kommando.append(params); - logger.log(Level.FINE, "kommando: {0}", kommando.toString()); - Process player_process = Runtime.getRuntime().exec(kommando.toString()); - antwort = "Kommando ausgefuehrt: " + kommando; - } catch (IOException ex) { - antwort = "Fehler: " + ex.getMessage(); - } - return antwort; - } - - @Override - protected StringBuilder buildParams(HttpExchange t) { - Player player = App.getPlayer(); - StringBuilder params = super.buildParams(t); - - if (player instanceof VLCPlayer) { - String pos = player.getParam(map, "pos"); - if (!pos.isEmpty()) { - params.append(" "); - params.append("int64:"); - params.append(pos); - params.append("000000"); // Mikrosekunden - } - } - - logger.log(Level.FINER, "params: " + params.toString()); - return params; - } -} diff --git a/src/de/uhilger/calypso/neu/App.java b/src/de/uhilger/calypso/neu/App.java index 603f4ea..602707f 100644 --- a/src/de/uhilger/calypso/neu/App.java +++ b/src/de/uhilger/calypso/neu/App.java @@ -1,5 +1,24 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + package de.uhilger.calypso.neu; +import de.uhilger.calypso.neu.http.Server; import java.util.HashMap; /** diff --git a/src/de/uhilger/calypso/neu/AppProperties.java b/src/de/uhilger/calypso/neu/AppProperties.java index f80c4b8..aea7da8 100644 --- a/src/de/uhilger/calypso/neu/AppProperties.java +++ b/src/de/uhilger/calypso/neu/AppProperties.java @@ -59,20 +59,8 @@ Logger.getLogger(AppProperties.class.getName()).log(Level.INFO, fName); InputStream in = null; try { - // Einstellungen aus Datei lesen - //AppProperties einst = new AppProperties(); File einstellungenDatei = new File(fName); in = new FileInputStream(einstellungenDatei); - - //BufferedReader br = new BufferedReader(new InputStreamReader(in)); - //String line = br.readLine(); - //while(line != null) { - // System.out.println(line); - // line = br.readLine(); - //} - //br.close(); - - load(in); in.close(); } catch (FileNotFoundException ex) { @@ -86,8 +74,5 @@ Logger.getLogger(AppProperties.class.getName()).log(Level.SEVERE, null, ex); } } - - } - } diff --git a/src/de/uhilger/calypso/MeldeThread.java b/src/de/uhilger/calypso/neu/MeldeThread.java similarity index 92% rename from src/de/uhilger/calypso/MeldeThread.java rename to src/de/uhilger/calypso/neu/MeldeThread.java index 7d03fb5..a8ea023 100644 --- a/src/de/uhilger/calypso/MeldeThread.java +++ b/src/de/uhilger/calypso/neu/MeldeThread.java @@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package de.uhilger.calypso; +package de.uhilger.calypso.neu; import java.util.logging.Logger; import java.util.logging.Level; @@ -45,11 +45,17 @@ this.meldeUrlStr = meldeUrlStr; } + /** + * ausfuehren des Threads + */ + @Override public void run() { try { exitValue = omxplayer.waitFor(); prozessBeendetMelden(); - } catch(Exception ex) { + lauscher.clear(); + lauscher = null; + } catch(InterruptedException ex) { logger.log(Level.FINE, ex.getMessage(), ex); } finally { aufraeumen(); diff --git a/src/de/uhilger/calypso/ProzessLauscher.java b/src/de/uhilger/calypso/neu/ProzessLauscher.java similarity index 96% rename from src/de/uhilger/calypso/ProzessLauscher.java rename to src/de/uhilger/calypso/neu/ProzessLauscher.java index 0fdb5d2..6adff11 100644 --- a/src/de/uhilger/calypso/ProzessLauscher.java +++ b/src/de/uhilger/calypso/neu/ProzessLauscher.java @@ -16,8 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package de.uhilger.calypso; - +package de.uhilger.calypso.neu; public interface ProzessLauscher { diff --git a/src/de/uhilger/calypso/neu/Rueckmelder.java b/src/de/uhilger/calypso/neu/Rueckmelder.java new file mode 100644 index 0000000..1680653 --- /dev/null +++ b/src/de/uhilger/calypso/neu/Rueckmelder.java @@ -0,0 +1,46 @@ +package de.uhilger.calypso.neu; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Ulrich Hilger + */ +public class Rueckmelder implements ProzessLauscher { + + + + @Override + public void prozessBeendet(String meldeUrlStr) { + Logger logger = Logger.getLogger(de.uhilger.calypso.neu.http.ApiHandler.class.getName()); + logger.log(Level.INFO, + "Abspielen beendet, sende Meldung an {0}.", + new Object[]{meldeUrlStr}); + try { + HttpURLConnection conn = (HttpURLConnection) new URL(meldeUrlStr).openConnection(); + conn.setRequestMethod("GET"); + conn.connect(); + int status = conn.getResponseCode(); + logger.log(Level.INFO, + "Abspielen beendet, Meldung an {0} mit Statuscode {1} gesendet.", + new Object[]{meldeUrlStr, status}); + /* + fuer den Fall, dass ein Stopp-Signal den Player nicht erreicht + oder dort nicht funktioniert, gibt es keine Moeglichkeit festzustellen, + dass der Player noch spielt. Damit in einem solchen Fall der Zeiger + auf den Abspielprozess nicht verloren geht, wird der Zeiger nicht + auf null gesetzt. + */ + //App.setPlayerProcess(null); + } catch (IOException ex) { + logger.log(Level.INFO, ex.getMessage(), ex); + } + } + + + +} diff --git a/src/de/uhilger/calypso/neu/Server.java b/src/de/uhilger/calypso/neu/Server.java deleted file mode 100644 index db467ba..0000000 --- a/src/de/uhilger/calypso/neu/Server.java +++ /dev/null @@ -1,35 +0,0 @@ -package de.uhilger.calypso.neu; - -import java.io.File; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * - * @author Ulrich Hilger - */ -public class Server { - - private static final Logger logger = Logger.getLogger(de.uhilger.calypso.Server.class.getName()); - - public static final String CONF = "conf"; - public static final String PORT = "port"; - public static final String SKRIPTE = "skripte"; - - public static final String EQUAL = "="; - - private AppProperties einst; - - public void start(AppProperties einst) { - logger.log(Level.INFO, "Server startet auf Port {0}", einst.getString(PORT)); - this.einst = einst; - String skripte = einst.getString(SKRIPTE); - File playSkript = new File(skripte, "play"); - if(playSkript.exists()) { - logger.log(Level.INFO, "Skripte gefunden in {0}", playSkript.getParentFile().getAbsolutePath()); - } else { - logger.log(Level.INFO, "Skripte nicht gefunden, Ordner laut Einstellungen: {0}", skripte); - } - } - -} diff --git a/src/de/uhilger/calypso/neu/actor/PlayActor.java b/src/de/uhilger/calypso/neu/actor/PlayActor.java new file mode 100644 index 0000000..d8a7a67 --- /dev/null +++ b/src/de/uhilger/calypso/neu/actor/PlayActor.java @@ -0,0 +1,87 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + +package de.uhilger.calypso.neu.actor; + +import de.uhilger.calypso.neu.MeldeThread; +import de.uhilger.calypso.neu.Rueckmelder; +import de.uhilger.calypso.neu.http.Server; +import java.io.IOException; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Der PlayActor loest das Abspielen eines Titels aus. + * + * Das koennte auch als Shell-Skript geschehen, aber abhaengig + * vom verwendeten Abspielprogramm benoetigt man das Prozessobjekt + * des laufenden Abspielprozesses im Verlauf des Abspielens noch, um + * weitere Kommandos zu senden. + * + * Beim Abspieler mpv werden Kommandos allerdings ueber Unix Domain + * Sockets gesendet, hierfuer waere also das Objekt des laufenden + * Abspielprozesses nicht noetig. Man benoetigt es aber auch um + * festzustellen, ob der Abspielprozess beendet ist. + * + * @author Ulrich Hilger + */ +public class PlayActor { + + public Process run(Map parameter) { + String meldeUrlStr = null; + Object o = parameter.get("r"); + if (o instanceof String) { + meldeUrlStr = (String) o; + } + + StringBuilder kommando = new StringBuilder(); + o = parameter.get("titel"); + if (o instanceof String) { + String titel = (String) o; + if (titel.toLowerCase().endsWith(".mp3")) { + kommando.append("mpv --input-ipc-server=/tmp/mpvsocket --no-terminal --vo=null "); + } else { + kommando.append("mpv --input-ipc-server=/tmp/mpvsocket --no-terminal "); + } + kommando.append(Server.BLANK); + kommando.append(titel); + Logger.getLogger(PlayActor.class.getName()).log(Level.FINE, kommando.toString()); + Process player_process; + try { + player_process = Runtime.getRuntime().exec(kommando.toString()); + if (meldeUrlStr != null) { + MeldeThread mt = new MeldeThread(); + mt.setProcess(player_process); + mt.lauscherHinzufuegen(new Rueckmelder()); + mt.setMeldeUrl(meldeUrlStr); + mt.start(); + } + return player_process; + } catch (IOException ex) { + Logger logger = Logger.getLogger(PlayActor.class.getName()); + logger.log(Level.SEVERE, ex.getLocalizedMessage(), ex); + ex.printStackTrace(); + return null; + } + } else { + Logger.getLogger(PlayActor.class.getName()).log(Level.INFO, "Titel fehlt"); + return null; + } + } +} diff --git a/src/de/uhilger/calypso/neu/actor/ShellActor.java b/src/de/uhilger/calypso/neu/actor/ShellActor.java new file mode 100644 index 0000000..c912c51 --- /dev/null +++ b/src/de/uhilger/calypso/neu/actor/ShellActor.java @@ -0,0 +1,73 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + +package de.uhilger.calypso.neu.actor; + +import de.uhilger.calypso.neu.http.Server; +import java.io.File; +import java.io.IOException; + +/** + * + * Der mpv Abspieler erhaelt Kommandos waehrend des Abspielens + * ueber Unix Domain Sockets. Da diese erst mit Java 16 untersuetzt + * werden und Java 16 fuer den Raspberry Pi noch nicht erhaeltlich + * ist, werden diese Kommandos als Shell-Skript unter Verwendung + * des Linux-Programms socat gesendet. + * + * Der Shell Actor fuehrt Skripte aus. Wenn ein Kommando Parameter + * erfordert, werden diese aus dem Query-Teil des HTTP-Aufrufes + * entnommen. + * + * + * @author Ulrich Hilger + */ +public class ShellActor { + + /** + * Ein Skript auf der Kommandozeile ausfuehren + * + * @param skriptDir das Verzeichnis, in dem das Skript liegt + * @param kommando der Name des Skript + * @throws IOException + */ + //public void run(String skriptDir, String kommando) throws IOException { + // File skriptFile = new File(skriptDir, kommando); + // Process p = Runtime.getRuntime().exec(skriptFile.getAbsolutePath()); + //} + + /** + * + * @param skriptDir das Verzeichnis, in dem das Skript liegt + * @param kommando der Name des Skript + * @param params die Parameter des Shell-Kommandos, null, wenn keine + * @throws IOException + */ + public void run(String skriptDir, String kommando, String... params) throws IOException { + StringBuilder sb = new StringBuilder(); + File skriptFile = new File(skriptDir, kommando); + sb.append(skriptFile.getAbsolutePath()); + if(params instanceof String[]) { + for (String param : params) { + sb.append(Server.BLANK); + sb.append(param); + } + } + Process p = Runtime.getRuntime().exec(sb.toString()); + } +} diff --git a/src/de/uhilger/calypso/neu/actor/StopServerActor.java b/src/de/uhilger/calypso/neu/actor/StopServerActor.java new file mode 100644 index 0000000..c73c6c0 --- /dev/null +++ b/src/de/uhilger/calypso/neu/actor/StopServerActor.java @@ -0,0 +1,53 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + +package de.uhilger.calypso.neu.actor; + +import com.sun.net.httpserver.HttpContext; +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Logger; + +/** + * Ein HTTP-Handler zum Stoppen der Anwendung + * + * @author Ulrich Hilger + */ +public class StopServerActor { + + public void run(HttpContext thisContext) { + Logger.getLogger(StopServerActor.class.getName()).info("Server wird gestoppt.."); + thisContext.getServer().stop(1); // diesen Server stoppen + Timer timer = new Timer(); + timer.schedule(new AppStopper(), 1500); // die App auch beenden + } + + /** + * Die Klasse AppStopper ermöglicht das asnychrone bzw. + * zeitgesteuerte Stoppen der Anwendung. + */ + class AppStopper extends TimerTask { + + @Override + public void run() { + Logger.getLogger(StopServerActor.class.getName()).info("Calypso beendet."); + System.exit(0); + } + } + +} diff --git a/src/de/uhilger/calypso/neu/http/ApiHandler.java b/src/de/uhilger/calypso/neu/http/ApiHandler.java new file mode 100644 index 0000000..e803df6 --- /dev/null +++ b/src/de/uhilger/calypso/neu/http/ApiHandler.java @@ -0,0 +1,146 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + +package de.uhilger.calypso.neu.http; + +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import de.uhilger.calypso.neu.actor.PlayActor; +import de.uhilger.calypso.neu.actor.ShellActor; +import de.uhilger.calypso.neu.actor.StopServerActor; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Der ApiHandler ist die proprietaer fuer Calypso vorgesehene + * Weise, HTTP-Anfragen zu verarbeiten. + * + * Der ApiHandler ist ein HttpHandler, der vom Server ueber die + * gesamte Laufzeit des Programmes hinweg gehalten wird. Deswegen + * beschraenkt sich der Programmcode des ApiHandlers auf die + * Verteilung der Kommandos auf Aktoren. Die Aktoren werden je nach + * Bedarf instanziiert und enthalten zusammengenommen den Code + * des Anwendungskerns. + * + * @author Ulrich Hilger + */ +public class ApiHandler extends HttpApi { + + public static final int PLAYERCMD = 2; + public static final int SERVERCMD = 3; + public static final String PLAY = "play"; + public static final String PAUSE = "pause"; + public static final String SEEK = "seek"; + public static final String STOP = "stop"; + public static final String SERVER = "server"; + public static final String PING = "ping"; + + public static final String PLAYER = "player-proc"; + + /** + * Die HTTP-Anfrage ausführen + * + * WICHTIG: Die HTTP-Parameter aus dem Query-Teil muessen in + * der Reihenfolge sein, die vom Shell-Skript erwartet wird. + * + * @param elems die Elemente des URI-Pfads + * @param parameter die Parameter des Query-Teils der URI + * @param exchange das Objekt mit Infos zum HTTP-Aufruf + * @return die Antwort, die gesendet werden soll + */ + @Override + protected String process(String[] elems, Map parameter, HttpExchange exchange) { + String antwort; + Object o; + + switch (elems[PLAYERCMD]) { + case PLAY: + PlayActor a = new PlayActor(); + o = a.run(parameter); + if (o instanceof Process) { + exchange.getHttpContext().getAttributes().put(PLAYER, o); + antwort = "Abspielprozess gestartet."; + } else { + // kein Prozess, es ist etwas schief gelaufen + antwort = "Abspielen konnte nicht gestartet werden."; + } + break; + + case PAUSE: + case SEEK: + ShellActor pa = new ShellActor(); + try { + pa.run(getSkriptDir(exchange), elems[PLAYERCMD], toShellParams(parameter)); + antwort = elems[PLAYERCMD] + " ausgefuehrt"; + } catch (IOException ex) { + Logger.getLogger(ApiHandler.class.getName()).log(Level.SEVERE, null, ex); + antwort = "Fehler bei der Ausfuehrung von " + elems[PLAYERCMD]; + } + break; + + case STOP: + o = exchange.getHttpContext().getAttributes().get(PLAYER); + if(o instanceof Process) { + Process p = (Process) o; + p.destroy(); + antwort = "Player gestoppt."; + } else { + antwort = "Es wurde kein Player-Prozess zum Stoppen gefunden."; + } + break; + + case SERVER: + if(elems[SERVERCMD].equals(STOP)) { + new StopServerActor().run(exchange.getHttpContext()); + antwort = "Calypso: Der Server wird angehalten und die App beendet."; + } else { + antwort = elems[SERVERCMD] + " ist ein unbekanntes Serverkommando"; + } + break; + + case PING: + antwort = elems[PLAYERCMD]; + break; + + default: + antwort = "Kommando " + elems[PLAYERCMD] + " unbekannt"; + break; + } + + return antwort; + } + + private String[] toShellParams(Map parameter) { + Collection<String> c = parameter.values(); + return c.toArray(String[]::new); + } + + private String getSkriptDir(HttpExchange exchange) { + HttpContext context = exchange.getHttpContext(); + Object o = context.getAttributes().get(Server.SKRIPT_DIR); + if (o instanceof String) { + return (String) o; + } else { + // kein Skript-Dir + return ""; + } + } +} diff --git a/src/de/uhilger/calypso/neu/http/HttpApi.java b/src/de/uhilger/calypso/neu/http/HttpApi.java new file mode 100644 index 0000000..ed87d17 --- /dev/null +++ b/src/de/uhilger/calypso/neu/http/HttpApi.java @@ -0,0 +1,97 @@ +package de.uhilger.calypso.neu.http; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Die Klasse HttpApi verwendet die von der Klasse HttpExchange + * gelieferten Elemente einer HTTP-Anfrage und leitet sie an + * die abstrakte Methode process, wo Subklassen das jeweilige + * Kommando aus der HTTP-Anfrage ausfuehren können. + * + * @author Ulrich Hilger + */ +public abstract class HttpApi implements HttpHandler { + + public static final String AMP = "&"; + public static final String SLASH = "/"; + + @Override + public void handle(HttpExchange exchange) throws IOException { + String path = exchange.getRequestURI().getPath(); + String[] elems = path.split(SLASH); + Map params = getQueryMap(exchange); + String antwort = process(elems, params, exchange); + antwortSenden(exchange, params, path, antwort); + } + + /** + * Eine HTTP-Anfrage ausführen + * + * @param elems die Elemente des URI-Pfads + * @param parameter die Parameter des Query-Teils der URI + * @return die Antwort, die gesendet werden soll + */ + protected abstract String process(String[] elems, Map parameter, HttpExchange exchange); + + /* + Den Query-Teil einer URL in die Parameter zerlegen + + Die Zerlegung erfolgt mit String.split nach + & und dann nach = + */ + protected Map getQueryMap(HttpExchange t) { + HashMap map = new HashMap(); + String query = t.getRequestURI().getQuery(); + if(query != null && query.length() > 0) { + String qParts[] = query.split("&"); + for(String qPart : qParts) { + Logger logger = Logger.getLogger(de.uhilger.calypso.neu.http.HttpApi.class.getName()); + logger.log(Level.FINER, "qPart: {0}", qPart); + String pParts[] = qPart.split("="); + map.put(pParts[0], pParts[1]); + logger.log(Level.FINER, "pParts[0]: {0} pParts[1]: {1}", new Object[]{pParts[0], pParts[1]}); + } + } + return map; + } + + protected void antwortSenden(HttpExchange exchange, Map params, String cmd, String antwort) throws IOException { + String httpResponseStr = getResponseString(params, cmd, antwort); + sendResponse(exchange, httpResponseStr); + } + + protected String getResponseString(Map map, String cmd, String antwort) { + Set keys = map.keySet(); + StringBuilder buf = new StringBuilder(); + buf.append(cmd); + buf.append(System.lineSeparator()); + keys.forEach((Object key) -> { + buf.append("key: "); + buf.append(key); + buf.append(System.lineSeparator()); + buf.append("value: "); + buf.append(map.get(key)); + buf.append(System.lineSeparator()); + //logger.log(Level.FINE, "key {0} value {1}", new Object[]{key, map.get(key)}); + }); + buf.append(antwort); + return buf.toString(); + } + + protected void sendResponse(HttpExchange t, String response) throws IOException { + t.sendResponseHeaders(200, response.length()); + OutputStream os = t.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + + +} diff --git a/src/de/uhilger/calypso/neu/http/Server.java b/src/de/uhilger/calypso/neu/http/Server.java new file mode 100644 index 0000000..168d3c9 --- /dev/null +++ b/src/de/uhilger/calypso/neu/http/Server.java @@ -0,0 +1,69 @@ +/* + Calypso - Media Player Remote Control via HTTP for Raspberry Pi + Copyright (C) 2021-2023 Ulrich Hilger + + 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/>. +*/ + +package de.uhilger.calypso.neu.http; + +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpServer; +import de.uhilger.calypso.neu.AppProperties; +import java.io.File; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.util.concurrent.Executors; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author Ulrich Hilger + */ +public class Server { + + //private static final Logger logger = Logger.getLogger(de.uhilger.calypso.Server.class.getName()); + + public static final String CONF = "conf"; + public static final String PORT = "port"; + public static final String SKRIPTE = "skripte"; + public static final String CTX = "ctx"; + public static final String EQUAL = "="; + public static final String BLANK = " "; + public static final String SKRIPT_DIR = "skript-dir"; + + + public void start(AppProperties einst) { + Logger logger = Logger.getLogger(de.uhilger.calypso.neu.http.Server.class.getName()); + logger.log(Level.INFO, "Server startet auf Port {0}", einst.getString(PORT)); + String skripte = einst.getString(SKRIPTE); + File skript = new File(skripte, "pause"); + if(skript.exists()) { + logger.log(Level.INFO, "Skripte gefunden in {0}", skript.getParentFile().getAbsolutePath()); + } else { + logger.log(Level.INFO, "Skripte nicht gefunden, Ordner laut Einstellungen: {0}", skripte); + } + try { + HttpServer server = HttpServer.create(new InetSocketAddress(einst.getInt(PORT)), 0); + String ctx = einst.getString(CTX); + HttpContext context = server.createContext(ctx, new ApiHandler()); + context.getAttributes().put(SKRIPT_DIR, einst.getString(SKRIPTE)); + server.setExecutor(Executors.newFixedThreadPool(20)); + server.start(); + } catch (IOException ex) { + logger.log(Level.SEVERE, null, ex); + } + } +} diff --git a/src/logging.properties b/src/logging.properties deleted file mode 100644 index aa7cc61..0000000 --- a/src/logging.properties +++ /dev/null @@ -1,72 +0,0 @@ -############################################################ -# Default Logging Configuration File -# -# You can use a different file by specifying a filename -# with the java.util.logging.config.file system property. -# For example java -Djava.util.logging.config.file=myfile -############################################################ - -############################################################ -# Global properties -############################################################ - -# "handlers" specifies a comma separated list of log Handler -# classes. These handlers will be installed during VM startup. -# Note that these classes must be on the system classpath. -# By default we only configure a ConsoleHandler, which will only -# show messages at the INFO and above levels. -# handlers= java.util.logging.ConsoleHandler - -# To also add the FileHandler, use the following line instead. -# handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler - -# Default global logging level. -# This specifies which kinds of events are logged across -# all loggers. For any given facility this global level -# can be overriden by a facility specific level -# Note that the ConsoleHandler also has a separate level -# setting to limit messages printed to the console. -# .level= FINE -.level = OFF - -############################################################ -# Handler specific properties. -# Describes specific configuration info for Handlers. -############################################################ - -# default file output is in user's home directory. -java.util.logging.FileHandler.pattern = %h/java%u.log -# java.util.logging.FileHandler.pattern = /media/extmirror/tomcat747/logs/tv_%u.log -# java.util.logging.FileHandler.pattern = ${catalina.base}/logs/file-cms_%u.log -# java.util.logging.FileHandler.limit = 50000 -# java.util.logging.FileHandler.count = 1 -# java.util.logging.FileHandler.count = 2 -# java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter -java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter -# java.util.logging.FileHandler.level = FINER - -# Limit the message that are printed on the console to INFO and above. -# java.util.logging.ConsoleHandler.level = INFO -# java.util.logging.ConsoleHandler.level = FINER -# java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter - -# Example to customize the SimpleFormatter output format -# to print one-line log message like this: -# <level>: <log message> [<date/time>] -# -# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n - -############################################################ -# Facility specific properties. -# Provides extra control for each logger. -############################################################ - -# For example, set the com.xyz.foo logger to only log SEVERE -# messages: -# com.xyz.foo.level = SEVERE -# de.uhilger.filecms.handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler -# de.uhilger.filecms.level = FINEST -# de.uhilger.wbx.handlers = java.util.logging.ConsoleHandler -# de.uhilger.wbx.level = FINEST -de.uhilger.avdirektor.handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler -de.uhilger.avdirektor.level = FINEST \ No newline at end of file -- Gitblit v1.9.3