View Javadoc

1   package org.rpi.playlist;
2   
3   import java.io.StringReader;
4   import java.io.StringWriter;
5   import java.util.Vector;
6   
7   import javax.xml.parsers.DocumentBuilder;
8   import javax.xml.parsers.DocumentBuilderFactory;
9   import javax.xml.transform.Transformer;
10  import javax.xml.transform.TransformerFactory;
11  import javax.xml.transform.dom.DOMSource;
12  import javax.xml.transform.stream.StreamResult;
13  import javax.xml.xpath.XPath;
14  import javax.xml.xpath.XPathFactory;
15  
16  import org.apache.log4j.Logger;
17  import org.w3c.dom.Document;
18  import org.w3c.dom.NamedNodeMap;
19  import org.w3c.dom.Node;
20  import org.w3c.dom.NodeList;
21  import org.xml.sax.InputSource;
22  
23  public class CustomTrack {
24  
25      private static final Logger LOG = Logger.getLogger(CustomTrack.class);
26  
27      private static final String ENTRY_START = "<Entry>";
28      private static final String ENTRY_END = "</Entry>";
29      private static final String ID_START = "<Id>";
30      private static final String ID_END = "</Id>";
31      private static final String URI_START = "<Uri>";
32      private static final String URI_END = "</Uri>";
33      private static final String META_START = "<Metadata>";
34      private static final String META_END = "</Metadata>";
35  
36      private String uri = "";
37  
38      private String title = "";
39      private String album = "";
40      private StringBuffer artist = new StringBuffer();
41      private StringBuffer performer = new StringBuffer();
42      private StringBuffer composer = new StringBuffer();
43      private StringBuffer conductor = new StringBuffer();
44      private String disc_number = "";
45      private String full_text = "";
46      private String date = "";
47      private boolean icy_reverse = false;
48      private String albumArtUri = "";
49  
50      private String metadata;
51  
52      private int id;
53      private String metatext = "";
54      private long time = -99;
55      private String full_details;
56  
57      public CustomTrack(String uri, String metadata, int id) {
58          // long startTime = System.nanoTime();
59          setUri(uri);
60          setMetadata(metadata);
61          setId(id);
62          full_text = getXmlString();
63          if (!metadata.equalsIgnoreCase("")) {
64              getTrackDetails();
65              setFullDetails();
66          }
67          // long endTime = System.nanoTime();
68          // long duration = endTime - startTime;
69          // LOG.warn("Time to Add CustomTrack: " + duration);
70      }
71  
72      public String getUniqueId() {
73          return "PL:" + id;
74      }
75  
76      private String getXmlString() {
77          StringBuilder sb = new StringBuilder();
78          sb.append(ENTRY_START);
79          sb.append(ID_START);
80          sb.append(getId());
81          sb.append(ID_END);
82          sb.append(URI_START);
83          sb.append(protectSpecialCharacters(getUri()));
84          sb.append(URI_END);
85          sb.append(META_START);
86          sb.append(protectSpecialCharacters(getMetadata()));
87          sb.append(META_END);
88          sb.append(ENTRY_END);
89          return sb.toString();
90      }
91  
92      public String getFullText() {
93          return full_text;
94      }
95  
96      public String getUri() {
97          return uri;
98      }
99  
100     private void setUri(String uri) {
101         this.uri = uri;
102     }
103 
104     public String getMetadata() {
105         return metadata;
106     }
107 
108     public String getMetaClean() {
109         return protectSpecialCharacters(getMetadata());
110     }
111 
112     private void setMetadata(String metadata) {
113         this.metadata = metadata;
114     }
115 
116     public int getId() {
117         return id;
118     }
119 
120     private void setId(int id) {
121         this.id = id;
122     }
123 
124     public String tidyMetaData() {
125 
126         try {
127             Vector<Node> removeNodes = new Vector<Node>();
128             StringBuilder temp = new StringBuilder();
129             // DocumentBuilderFactory factory =
130             // DocumentBuilderFactory.newInstance();
131             // DocumentBuilder builder = factory.newDocumentBuilder();
132             // InputSource insrc = new InputSource(new StringReader(Metadata));
133             // Document doc = builder.parse(insrc);
134             Document doc = getDocument();
135             Node node = doc.getFirstChild();
136             Node item = node.getFirstChild();
137             NodeList childs = item.getChildNodes();
138             temp.append("<item>");
139             for (int i = 0; i < childs.getLength(); i++) {
140                 Node n = childs.item(i);
141                 boolean remove = true;
142                 if (n.getNodeName() == "dc:title") {
143                     remove = false;
144                 }
145                 else if (n.getNodeName() == "upnp:album") {
146                     remove = false;
147                 }
148                 else if (n.getNodeName() == "upnp:artist") {
149                     NamedNodeMap map = n.getAttributes();
150                     Node role = map.getNamedItem("role");
151                     String role_type = role.getTextContent();
152                     if (role.getTextContent().equalsIgnoreCase("AlbumArtist")) {
153                         remove = false;
154                     }
155                     if (role.getTextContent().equalsIgnoreCase("Performer")) {
156                         // remove =false;
157                     }
158 
159                 }
160                 else if (n.getNodeName() == "upnp:class") {
161                     remove = false;
162                 }
163                 else if (n.getNodeName() == "upnp:albumArtURI") {
164                     remove = false;
165                 }
166 
167                 if (remove) {
168                     removeNodes.add(n);
169                 }
170             }
171             for (Node n : removeNodes) {
172                 item.removeChild(n);
173             }
174             Transformer transformer = TransformerFactory.newInstance().newTransformer();
175             StreamResult result = new StreamResult(new StringWriter());
176             DOMSource source = new DOMSource(doc);
177             transformer.transform(source, result);
178             return result.getWriter().toString();
179         } catch (Exception e) {
180             LOG.error("Erorr TidyMetaData", e);
181         }
182 
183         return "";
184     }
185 
186     public String updateTrack(String title, String artist) {
187         try {
188             String full_title = title + " - " + artist;
189             full_title = tidyUpString(full_title);
190             Document doc = getDocument();
191             Node node = doc.getFirstChild();
192             Node item = node.getFirstChild();
193             NodeList childs = item.getChildNodes();
194             for (int i = 0; i < childs.getLength(); i++) {
195                 Node n = childs.item(i);
196                 if (n.getNodeName() == "dc:title") {
197                     n.setTextContent(full_title);
198                     LOG.info("ICY INFO Replacing dc:title: " + full_title);
199                     break;
200                 }
201             }
202             Transformer transformer = TransformerFactory.newInstance().newTransformer();
203             StreamResult result = new StreamResult(new StringWriter());
204             DOMSource source = new DOMSource(doc);
205             transformer.transform(source, result);
206             metatext = result.getWriter().toString();
207             return metatext;
208         } catch (Exception e) {
209             LOG.error("Error Creating XML Doc", e);
210         }
211         return null;
212     }
213 
214     private String tidyUpString(String s) throws Exception {
215         String string = "";
216         if (s.equals(s.toUpperCase())) {
217             // s = s.toLowerCase();
218             String[] splits = s.split(" ");
219             for (String word : splits) {
220                 try {
221                     word = word.replace(word.substring(1), word.substring(1).toLowerCase());
222                 } catch (Exception e) {
223                     LOG.debug("Error with Word: " + word);
224                 }
225                 string += word + " ";
226             }
227 
228         }
229         if (string.equals("")) {
230             return s;
231         }
232         return string.trim();
233     }
234 
235     private String protectSpecialCharacters(String originalUnprotectedString) {
236         // String test = StringEscapeUtils.escapeXml(originalUnprotectedString);
237         if (originalUnprotectedString == null) {
238             return null;
239         }
240         boolean anyCharactersProtected = false;
241 
242         StringBuffer stringBuffer = new StringBuffer();
243         for (int i = 0; i < originalUnprotectedString.length(); i++) {
244             char ch = originalUnprotectedString.charAt(i);
245 
246             boolean controlCharacter = ch < 32;
247             boolean unicodeButNotAscii = ch > 126;
248             boolean characterWithSpecialMeaningInXML = ch == '<' || ch == '&' || ch == '>';
249 
250             if (characterWithSpecialMeaningInXML || unicodeButNotAscii || controlCharacter) {
251                 stringBuffer.append("&#" + (int) ch + ";");
252                 anyCharactersProtected = true;
253             } else {
254                 stringBuffer.append(ch);
255             }
256         }
257         if (anyCharactersProtected == false) {
258             return originalUnprotectedString;
259         }
260         return stringBuffer.toString();
261     }
262 
263     @Override
264     public String toString() {
265         String res = "Track Id: " + id + " + URI: " + uri + "  MetaData:\r\n " + getMetadata();
266         return res;
267     }
268 
269     private Document getDocument() {
270         try {
271             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
272             DocumentBuilder builder = factory.newDocumentBuilder();
273             InputSource insrc = new InputSource(new StringReader(metadata));
274             return builder.parse(insrc);
275         } catch (Exception e) {
276 
277         }
278         return null;
279     }
280 
281     /**
282      * Using XPath Queries, which are slower
283      */
284     public void getTrackDetailsNew() {
285         try {
286             Document doc = getDocument();
287             String ex_title = "DIDL-Lite/item/title";
288             XPath xPath = XPathFactory.newInstance().newXPath();
289             String title = xPath.compile(ex_title).evaluate(doc);
290             setTitle(title);
291             String exAlbum = "DIDL-Lite/item/album";
292             String album = xPath.compile(exAlbum).evaluate(doc);
293             setAlbum(album);
294             String ex_Performer = "DIDL-Lite/item/artist[@role='Performer']";
295             String performer = xPath.compile(ex_Performer).evaluate(doc);
296             setPerformer(performer);
297             String ex_artist = "DIDL-Lite/item/artist[@role='AlbumArtist']";
298             String artist = xPath.compile(ex_artist).evaluate(doc);
299             setArtist(artist);
300         } catch (Exception e) {
301             LOG.error("Erorr TidyMetaData", e);
302         }
303     }
304 
305     public void getTrackDetails() {
306         try {
307             Document doc = getDocument();
308             Node node = doc.getFirstChild();
309             Node item = node.getFirstChild();
310             NodeList childs = item.getChildNodes();
311             for (int i = 0; i < childs.getLength(); i++) {
312                 Node n = childs.item(i);
313                 if ("dc:title".equals(n.getNodeName())) {
314                     setTitle(n.getTextContent());
315                 }
316                 else if ("upnp:album".equals(n.getNodeName())) {
317                     setAlbum(n.getTextContent());
318                 }
319                 else if ("upnp:artist".equals(n.getNodeName())) {
320                     NamedNodeMap map = n.getAttributes();
321                     Node role = map.getNamedItem("role");
322                     if (role != null) {
323                         String role_type = role.getTextContent();
324                         if (role_type.equalsIgnoreCase("AlbumArtist")) {
325                             setArtist(n.getTextContent());
326                         }
327                         else if (role_type.equalsIgnoreCase("Performer")) {
328                             setPerformer(n.getTextContent());
329                         }
330                         else if(role_type.equalsIgnoreCase("Composer")) {
331                             setComposer(n.getTextContent());
332                         }
333                         else if(role_type.equalsIgnoreCase("Conductor")) {
334                             setConductor(n.getTextContent());
335                         }
336                     }
337                     else {
338                         setArtist(n.getTextContent());
339                     }
340                 }
341                 else if ("dc:date".equals(n.getNodeName())) {
342                     setDate(n.getTextContent());
343                 }
344                 else if ("upnp:originalDiscNumber".equals(n.getNodeName())) {
345                     disc_number = n.getTextContent();
346                 }
347                 else if ("upnp:albumArtURI".equals(n.getNodeName())) {
348                     setAlbumArtUri(n.getTextContent());
349                 }
350             }
351         } catch (Exception e) {
352             LOG.error("Error GetTrackDetails", e);
353         }
354     }
355 
356     private void setDate(String date) {
357         this.date = date;
358     }
359 
360     public String getDate()
361     {
362         return date;
363     }
364 
365     private void setComposer(String composer) {
366         this.composer.append(composer);
367         this.composer.append(",");
368     }
369 
370     public String getComposer(){
371         String text = composer.toString();
372         if(text.endsWith(","))
373             text = text.substring(0,text.length()-1);
374         return text;
375     }
376 
377     public void setMetaText(String metatext) {
378         this.metatext = metatext;
379 
380     }
381 
382     public String getMetaText() {
383         return metatext;
384     }
385 
386     public void setTime(long duration) {
387         // TODO Auto-generated method stub
388         this.time = duration;
389     }
390 
391     public long getTime() {
392         return time;
393     }
394 
395     public String getTitle() {
396         String mTitle = title.trim();
397         if(disc_number!=null)
398         {
399             if(!disc_number.equalsIgnoreCase(""))
400             {
401                 if(mTitle.startsWith(disc_number))
402                 {
403                     mTitle = mTitle.substring(disc_number.length());
404                     if(mTitle.trim().startsWith("."))
405                     {
406                         mTitle = mTitle.substring(1);
407                     }
408                 }
409             }
410         }
411         return mTitle.trim();
412     }
413 
414     public void setTitle(String title) {
415         this.title = title.trim();
416     }
417 
418     public String getAlbum() {
419         return album;
420     }
421 
422     public void setAlbum(String album) {
423         this.album = album.trim();
424     }
425 
426     public String getArtist() {
427 //        String text = artist.toString();
428 //        if(text.endsWith(","))
429 //            text = text.substring(0,text.length()-1);
430 //        return text;
431         return getPerformer();
432     }
433 
434     public void setArtist(String artist) {
435         this.artist.append(artist.trim());
436         this.artist.append(",");
437     }
438 
439     public String getPerformer() {
440         String text = performer.toString();
441         if(text.equalsIgnoreCase(""))
442         {
443             text = artist.toString();
444         }
445         if(text.endsWith(","))
446             text = text.substring(0,text.length()-1);
447         return text;
448     }
449 
450     public void setPerformer(String performer) {
451         this.performer.append(performer.trim());
452         this.performer.append(",");
453     }
454 
455     public String getConductor() {
456         String text = conductor.toString();
457         if(text.endsWith(","))
458             text = text.substring(0,text.length()-1);
459         return text;
460     }
461 
462     private void setConductor(String conductor) {
463         this.conductor.append(conductor);
464         this.conductor.append(",");
465     }
466 
467     private void setFullDetails() {
468         StringBuffer sb = new StringBuffer();
469         sb.append(getTitle());
470         sb.append(" - ");
471         if (!getPerformer().equalsIgnoreCase("")) {
472             sb.append(getPerformer());
473             sb.append(" - ");
474         }
475         if (!getPerformer().equalsIgnoreCase(getArtist())) {
476             sb.append(getArtist());
477             sb.append(" - ");
478         }
479         sb.append(getAlbum());
480         full_details = sb.toString();
481         if (full_details.endsWith(" - ")) {
482             full_details = full_details.substring(0, full_details.length() - 3);
483             full_details.trim();
484         }
485     }
486 
487     public String getFullDetails() {
488         return full_details;
489     }
490 
491     public boolean isICYReverse() {
492         return icy_reverse;
493     }
494 
495     public void setICYReverse(boolean icy_reverse) {
496         this.icy_reverse = icy_reverse;
497     }
498 
499     public String getAlbumArtUri() {
500         return albumArtUri;
501     }
502 
503     public void setAlbumArtUri(String albumArtUri) {
504         this.albumArtUri = albumArtUri;
505     }
506 
507     // public void updateTitle(String title) {
508     // // title = WordUtils.capitalizeFully(title);
509     // String meta_data = Metadata;
510     // String sStart =
511     // "<dc:title xmlns:dc=\"http://purl.org/dc/elements/1.1/\">";
512     // String sEnd = "</dc:title>";
513     // int start = meta_data.indexOf(sStart);
514     // int end = meta_data.indexOf(sEnd);
515     // if (start > 0) {
516     // if (end > 0) {
517     // String s = meta_data.substring(start, end);
518     // LOG.debug("Found Title: " + s);
519     // LOG.debug("Replace With: " + sStart + title);
520     //
521     // meta_data = meta_data.replace(s, sStart + title);
522     // LOG.debug(meta_data);
523     // Metadata = meta_data;
524     // }
525     // }
526     // }
527 
528     // public void updateArtist(String artist) {
529     // // Probably need to replace "<item id="...
530     // // artist = WordUtils.capitalizeFully(artist);
531     // String meta_data = Metadata;
532     // String sStart =
533     // "<upnp:artist role=\"Performer\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\">";
534     // String sEnd = "</upnp:artist>";
535     // int start = meta_data.indexOf(sStart);
536     // int end = meta_data.indexOf(sEnd);
537     // if (start > 0) {
538     // if (end > 0) {
539     // String s = meta_data.substring(start, end);
540     // LOG.debug("Found Artist: " + s);
541     // LOG.debug("Replace With: " + sStart + title);
542     //
543     // meta_data = meta_data.replace(s, sStart + title);
544     // LOG.debug(meta_data);
545     // Metadata = meta_data;
546     // }
547     // } else {
548     // String first_part = meta_data.substring(0,
549     // meta_data.indexOf("</item></DIDL-Lite>"));
550     // meta_data = first_part + sStart + artist + sEnd + "</item></DIDL-Lite>";
551     // Metadata = meta_data;
552     // }
553     // }
554 }