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
59 setUri(uri);
60 setMetadata(metadata);
61 setId(id);
62 full_text = getXmlString();
63 if (!metadata.equalsIgnoreCase("")) {
64 getTrackDetails();
65 setFullDetails();
66 }
67
68
69
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
130
131
132
133
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
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
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
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
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
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
428
429
430
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
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554 }