Persoenliche Mediazentrale
ulrich
2024-11-22 4d16fb3576e60a2a5da6f7bfe396a555010dfa79
commit | author | age
8d7d35 1 /*
94b1c2 2   Tango - Personal Media Center
8d7d35 3   Copyright (C) 2021  Ulrich Hilger
U 4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU Affero General Public License as
7   published by the Free Software Foundation, either version 3 of the
8   License, or (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU Affero General Public License for more details.
14
15   You should have received a copy of the GNU Affero General Public License
16   along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
94b1c2 18 package de.uhilger.tango.api;
8d7d35 19
e60cff 20 import com.google.gson.Gson;
43d323 21 import com.sun.net.httpserver.Headers;
8d7d35 22 import com.sun.net.httpserver.HttpExchange;
7f4414 23 import de.uhilger.tango.PlaylistListener;
94b1c2 24 import de.uhilger.tango.Server;
U 25 import de.uhilger.tango.entity.Abspielliste;
26 import de.uhilger.tango.entity.Entity;
27 import de.uhilger.tango.entity.Titel;
28 import de.uhilger.tango.store.FileStorage;
8d7d35 29 import java.io.IOException;
7f4414 30 import java.util.ArrayList;
U 31 import java.util.Iterator;
1bf4f6 32 import java.util.List;
e60cff 33 import java.util.logging.Logger;
8d7d35 34
U 35 /**
36  * Der ListHandler bearbeitet HTTP-Anfragen zu Abspiellisten
37  * 
03b95f 38  * GET /tango/api/alist/[pl-name]          die Titel-Objekte der Liste [pl-name] liefern
U 39  * GET /tango/api/alist/[pl-name]/m3u      eine einfache Playlist im M3U-Format ausgeben
40  * GET /tango/api/alist/[pl-name]/[nr]     den Titel mit der Nummer [nr] abrufen
a6081c 41  * 
03b95f 42  * PUT /tango/api/alist/[pl-name]          den Titel im Body anfuegen an die Liste [pl-name]
U 43  * PUT /tango/api/alist/[pl-name]/[nr]     an der Position nr der Liste [pl-name] den Titel im Body einfuegen
44  * PUT /tango/api/alist/[pl-name]/[nrVon]/[nrNach]   den Titel von seiner aktuellen Position an eine 
1bf4f6 45  *                                                 andere Position der Liste [pl-name] verschieben
03b95f 46  * DELETE /tango/api/alist/[pl-name]/[nr]  den Titel an der Position [nr] aus der Liste [pl-name] entfernen  
U 47  * DELETE /tango/api/alist/[pl-name]/alle  alle Titel aus der Liste [pl-name] entfernen  
792b21 48  * 
U 49  * TODO (2.1.2023):
50  * - Liste ab Titel spielen
51  * - Ganzes Album der Liste hinzufuegen
8d7d35 52  *
U 53  * @author Ulrich Hilger
54  * @version 1, 8.4.2021
55  */
56 public class ListHandler extends AbstractHandler {
e60cff 57   
U 58   private static final Logger logger = Logger.getLogger(ListHandler.class.getName());
095119 59   
U 60   public static final String ALLE_TITEL = "alle";
f70acb 61   
U 62   private String conf;
63   
7f4414 64   private List<PlaylistListener> listeners;
U 65   
f70acb 66   public ListHandler(String conf) {
U 67     this.conf = conf;
7f4414 68     listeners = new ArrayList();
f70acb 69   }
8d7d35 70
U 71   @Override
72   protected String get(HttpExchange e) {
e60cff 73     String path = e.getRequestURI().toString();
0e9cd3 74     String[] elems = path.split(Server.SLASH);
43d323 75     if(elems.length > 5) {
U 76       if(elems[5].endsWith("m3u")) {
77         Headers headers = e.getResponseHeaders();
78         headers.add("Content-Type", "application/m3u");
79         return getM3u(e, elems[4]);
80       } else {
a6081c 81         try {
U 82           int index = Integer.parseInt(elems[5]);
83           return getTitel(elems[4], index);
84         } catch(NumberFormatException ex) {
85           return "ungueltig";
86         }
43d323 87       }
U 88     } else {
89       String plname = elems[elems.length - 1];
90       FileStorage fs = new FileStorage(conf);
91       String json = fs.readJson(FileStorage.ST_ABSPIELLISTE, plname);
92       return embedInCustomType(json, FileStorage.ST_ABSPIELLISTE);
93     }
94   }
95   
96   private String getM3u(HttpExchange e, String plname) {
97     StringBuilder sb = new StringBuilder();
98     FileStorage fs = new FileStorage(conf);    
99     Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
100     if (entity instanceof Abspielliste) {
101       Abspielliste liste = (Abspielliste) entity;
102       List<Titel> titelListe = liste.getTitel();
103       
104       for(Titel titel : titelListe) {
03b95f 105         String server = getEinstellung(fs, 
U 106                 getResString(MediaSteuerung.RB_HOST), MediaSteuerung.DEFAULT_HOST);
107         sb.append(server);
43d323 108         sb.append(titel.getKatalogUrl());
U 109         sb.append(titel.getPfad());
110         sb.append(titel.getName());
03b95f 111         sb.append(Server.NEWLINE);
43d323 112       }
U 113     }
114     return sb.toString();
8d7d35 115   }
U 116
117   @Override
118   protected String put(HttpExchange e) throws IOException {
e60cff 119     String path = e.getRequestURI().toString();
0e9cd3 120     String[] elems = path.split(Server.SLASH);
e60cff 121     String response = "ListHandler.put: ungueltiger URL";
U 122     switch(elems.length) {
8e2578 123       case 5: // ohne nr am Ende
e60cff 124         response = addTitel(e, elems[4]);
U 125         break;
126         
127       case 6:
1bf4f6 128         response = insertTitel(e, elems[4], Integer.parseInt(elems[5]));
e60cff 129         break;
1bf4f6 130         
U 131       case 7:
132         response = moveTitel(e, elems[4], Integer.parseInt(elems[5]), Integer.parseInt(elems[6]));
133         break;
134     }
135     return response;
136   }
137   
a6081c 138   private String getTitel(String plname, int index) {
U 139     FileStorage fs = new FileStorage(conf);
140     Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
141     String response = "eom";
142     if(entity instanceof Abspielliste) {
143       Abspielliste aliste = (Abspielliste) entity;
144       //String titelJson = bodyLesen(e);
145       List<Titel> titelListe = aliste.getTitel();
146       if(index < titelListe.size()) {
147         Titel titel = aliste.getTitel().get(index);
148         Gson gson = new Gson();
149         response = gson.toJson(titel);
150       }
151     }
152     return response;    
153   }
154   
1bf4f6 155   /**
U 156    * Den Titel im Body von seiner aktuellen Position an die angegebene 
157    * Position setzen. Der Titel an der angegebenen Position rueckt nach 
158    * unten.
159    * 
160    * Annahme: Die Abspielliste enthaelt keine Titel mehrfach.
161    * 
162    * @param e
163    * @param plname
164    * @param zielPos
165    * @return
166    * @throws IOException 
167    */
168   private String moveTitel(HttpExchange e, String plname, int pos, int zielPos) throws IOException {
169     FileStorage fs = new FileStorage(conf);
170     Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
171     String response = "Titel konnte nicht verschoben werden.";
172     if(entity instanceof Abspielliste) {
173       if(pos < zielPos) {
174         --zielPos;
175       }
176       Abspielliste aliste = (Abspielliste) entity;
177       List<Titel> liste = aliste.getTitel();
178       Titel t = liste.get(pos);
179       liste.remove(pos);
180       liste.add(zielPos, t);
181       fs.write(aliste, true);
182       response = "Titel " + t.getName() + " der Liste " + aliste.getName() + 
183               " an Position " + zielPos + " verschoben.";
184     }
185     return response;
186   }
187   
188   /**
189    * Den Titel im Body an Position anPos einfuegen. Der Titel an anPos 
190    * rueckt nach unten.
191    * 
192    * @param e
193    * @param plname
194    * @param anPos
195    * @return
196    * @throws IOException 
197    */
198   private String insertTitel(HttpExchange e, String plname, int anPos) throws IOException {
199     FileStorage fs = new FileStorage(conf);
200     Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
201     String response = "Titel konnte nicht hinzugefuegt werden.";
202     if(entity instanceof Abspielliste) {
203       Abspielliste aliste = (Abspielliste) entity;
204       String titelJson = bodyLesen(e);
205       Gson gson = new Gson();
206       Object o = gson.fromJson(titelJson, fs.typeFromName(Titel.class.getSimpleName()).getType());
207       if(o instanceof Titel) {
208         Titel titel = (Titel) o;
209         aliste.putTitel(titel, anPos);
210         fs.write(aliste, true);
211         response = "Titel " + titel.getName() + " der Liste " + aliste.getName() + 
212                 " an Position " + anPos + " hinzugefuegt.";
213       }
e60cff 214     }
U 215     return response;
216   }
217   
218   private String addTitel(HttpExchange e, String plname) throws IOException {
f70acb 219     FileStorage fs = new FileStorage(conf);
e60cff 220     Entity entity = fs.read(FileStorage.ST_ABSPIELLISTE, plname);
U 221     String response = "Titel konnte nicht hinzugefuegt werden.";
222     if(entity instanceof Abspielliste) {
223       Abspielliste aliste = (Abspielliste) entity;
224       String titelJson = bodyLesen(e);
225       Gson gson = new Gson();
226       Object o = gson.fromJson(titelJson, fs.typeFromName(Titel.class.getSimpleName()).getType());
227       if(o instanceof Titel) {
228         Titel titel = (Titel) o;
229         aliste.addTitel(titel);
230         fs.write(aliste, true);
231         response = "Titel " + titel.getName() + " der Liste " + aliste.getName() + " hinzugefuegt.";
232       }
233     }
234     return response;
8d7d35 235   }
U 236
172013 237   // DELETE /mz/api/alist/[pl-name]/[nr]  den Titel an der Position [nr] aus der Liste [pl-name] entfernen  
8d7d35 238   @Override
U 239   protected boolean delete(HttpExchange e) {
172013 240     String path = e.getRequestURI().toString();
U 241     String[] elems = path.split(Server.SLASH);
5f7e0b 242     String listName = elems[elems.length - 2];
f70acb 243     FileStorage fs = new FileStorage(conf);
172013 244     Entity entity = fs.read(Abspielliste.class.getSimpleName(), listName);
U 245     if(entity instanceof Abspielliste) {
246       Abspielliste liste = (Abspielliste) entity;
095119 247       String titelStr = elems[elems.length-1];
U 248       if(titelStr.equalsIgnoreCase(ALLE_TITEL)) {
249         liste.getTitel().clear();
250       } else {
7f4414 251         int idx = Integer.parseInt(elems[elems.length-1]);
U 252         liste.getTitel().remove(idx);
253         sendRemovalInfo(liste.getName(), idx);
095119 254       }
172013 255       fs.write(liste, true);
U 256       return true;
257     } else {
258       return false;
259     }
8d7d35 260   }
U 261   
7f4414 262   private void sendRemovalInfo(String listName, int titleIndex) {
U 263     Iterator<PlaylistListener> i = listeners.iterator();
264     while(i.hasNext()) {
265       PlaylistListener l = i.next();
266       l.titleRemoved(listName, titleIndex);
267     }
268   }
269   
270   public void addPlaylistListener(PlaylistListener listener) {
271     this.listeners.add(listener);
272   }
273   
274   public void removePlaylistListener(PlaylistListener listener) {
275     this.listeners.remove(listener);
276   }
8d7d35 277 }