001/* 002 * 003 * $Revision: 1314 $ 004 * $Date: 2020-03-19 09:11:27 -0700 (Thu, 19 Mar 2020) $ 005 * $URL: svn://fred.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/widgets/tunes/Album.java $ 006 * 007 * Written by Tom Gutwin - WebARTS Design. 008 * http://www.webarts.bc.ca 009 * Copyright (C) 2016-2019 WebARTS Design, North Vancouver Canada 010 * This program is free software; you can redistribute it and/or modify 011 * it under the terms of the GNU General Public License as published by 012 * the Free Software Foundation; either version 2 of the License, or 013 * (at your option) any later version. 014 * 015 * This program is distributed in the hope that it will be useful, 016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 018 * GNU General Public License for more details. 019 * 020 * You should have received a copy of the GNU General Public License 021 * along with this program; if not, write to the Free Software 022 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 023 */ 024 025package ca.bc.webarts.widgets.tunes; 026 027import ca.bc.webarts.widgets.Quick; 028import ca.bc.webarts.widgets.Util; 029import ca.bc.webarts.tools.musicbrainz.*; 030 031import java.io.File; 032import java.util.Vector; 033 034import javax.json.Json; 035import javax.json.JsonArray; 036import javax.json.JsonArrayBuilder; 037import javax.json.JsonObject; 038import javax.json.JsonWriter; 039import javax.json.JsonWriterFactory; 040import javax.json.stream.JsonParser; 041 042import org.apache.commons.codec.DecoderException; 043import org.apache.commons.codec.binary.Hex; 044 045/** Class to hold an album as a java object. **/ 046 public class Album implements java.lang.Comparable<Album> 047 { 048 private String name_ = ""; 049 private String artistName_ = ""; 050 private String albumArtistName_ = ""; 051 private String artistDir_ = ""; 052 private File albumDirFile_ = null; 053 Vector <Song> songs = new Vector <Song>(); 054 private String downloadLink_ = ""; 055 private de.umass.lastfm.Album lastFmAlbum_ = null; 056 private java.util.Date releaseDate_ = null; 057 int releaseYear_ = 1900; 058 private String mbid_ = ""; 059 private MusicbrainzRestRequester mbRR_ = null; 060 private MusicbrainzRelease mb_ = null; 061 /** Flag to control if this class should use Musibrainz lookups to augment the information about this Artist. **/ 062 private boolean useMusicBrainz_ = Artist.useMusicBrainz_; 063 064 /** The 2 digit HEX char/byte Reference KEY for this Albub . 065 * Example 0a. <br> 066 * Each artist should have a unique key based on the parsing of the tunes root directory. It is created each time the roor directory is parsed. 067 * It is based on an alpha nemeric sorted list of Artist Full (non hashed) spaceRemoved DirNames. (ie. VelvetRevolver ) 068 **/ 069 private char[] refKEY_ = {'0','0'}; 070 private char[] artistRefKEY_ = {'0','0','0','0'}; 071 072 073 074 /** A holder for this clients System File Separator. */ 075 public final static String SYSTEM_FILE_SEPERATOR = java.io.File.separator; 076 077 /** A holder for this clients System line termination separator. */ 078 public final static String SYSTEM_LINE_SEPERATOR = 079 System.getProperty("line.separator"); 080 081 082 /** 083 * Constructor for Album. 084 * 085 * @throws Exception if the artist file dir does not exist of can't read as a dir. 086 **/ 087 public Album(String albumFileDirPath, boolean useMusicbrainz, int albumRefKey, char[] artistRefKEY) throws Exception 088 { 089 if( ! ( albumRefKey < (16*16) && albumRefKey >-1) ) throw new Exception("invalid refKey"); 090 if(artistRefKEY!=null && artistRefKEY_.length==4) artistRefKEY_ = artistRefKEY; 091 092 refKEY_ = Util.toHEXChars(albumRefKey, refKEY_.length); 093 File albumDirFile = new File(albumFileDirPath); 094 useMusicBrainz_ = useMusicbrainz; 095 if(albumDirFile!=null && albumDirFile.isDirectory() && albumDirFile.canRead()) 096 this.albumDirFile_ = albumDirFile; 097 else 098 throw new java.lang.Exception("Error with Album dirFilePath: "+albumFileDirPath); 099 100 String artistDirName = albumDirFile_.getAbsolutePath().substring(0, albumDirFile_.getAbsolutePath().lastIndexOf("/")); 101 albumArtistName_ = Song.removeExplicit(artistDirName.substring(artistDirName.lastIndexOf("/")+1).trim()); 102 if( 103 !"VariousArtists".equalsIgnoreCase(albumArtistName_) && 104 !"randyBachman&BurtonCummings".equalsIgnoreCase(albumArtistName_) 105 ) artistName_ = Util.capsToSpacesInString(albumArtistName_).trim(); 106 else artistName_ = ""; 107 readSongs(); 108 //retrieveLastFmAlbum 109 if(useMusicBrainz_) 110 { 111 try 112 { 113 mb_ = new MusicbrainzRelease(artistName_, albumTitle(false), albumFileDirPath, true); 114 releaseYear_ = mb_.getYear(); 115 setReleaseDate(new java.util.Date(releaseYear_,1,1)); 116 } 117 catch(Exception ex) 118 { 119 /* ignore error dirs */ 120 System.out.println("Can't Read Musicbrainz: "+artistName_ +" for dir="+albumFileDirPath); 121 setReleaseDate(new java.util.Date(1900,1,1)); 122 } 123 } 124 else 125 setReleaseDate(new java.util.Date(1900,1,1)); 126 127 } // -- Constructor 128 129 130 /** Reads the song files in the dir and loads the songs vector. It is called from the constructor.**/ 131 private void readSongs() 132 { 133 File[] songDirFiles = albumDirFile_.listFiles(); 134 String currFilePath = ""; 135 int songCount = 0; 136 Song currSong = null; 137 if(songDirFiles!=null) 138 for(File currFile : songDirFiles) 139 { 140 try 141 { 142 currFilePath = currFile.getAbsolutePath(); 143 if(!currFile.isDirectory() && currFile.canRead()&& 144 (currFilePath.endsWith(".ogg") || currFilePath.endsWith(".oga") || 145 currFilePath.endsWith(".mp3") || currFilePath.endsWith(".flac"))) 146 { 147 songCount++; 148 currSong = new Song(currFile.getAbsolutePath(), 149 "<a class=\"Song"+songCount+"\" id=\"Song"+songCount+"\" name=\"Song"+songCount+"\" href=\"#\" >", 150 "</a>", 151 refKEY_); 152 currSong.setLibraryIndex(songCount); 153 currSong.setArtistRefKEY(getArtistRefKEY()); 154 this.songs.add(currSong); 155 if(artistDir_==null || "".equals(artistDir_)) setArtistDir(currSong.artistDir()); 156 } 157 } 158 catch(Exception ex) { /* ignore error dirs */System.out.println("Can't Read Song: "+currFilePath);ex.printStackTrace(); } 159 } 160 161 } 162 163 164 /** 165 * Set Method for class field 'artistDir_'. 166 * 167 * @param artistDir is the value to set this class field to. 168 * 169 **/ 170 public void setArtistDir(String artistDir) 171 { 172 this.artistDir_ = artistDir; 173 } // setArtistDir Method 174 175 176 /** 177 * Get Method for class field 'artistDir_'. 178 * 179 * @return String - The value the class field 'artistDir_'. 180 * 181 **/ 182 public String getArtistDir() 183 { 184 String retVal = ""; name(true); 185 if(artistDir_!=null && !artistDir_.equals("")) retVal = artistDir_; 186 return retVal; 187 } // getArtistDir Method 188 189 190 public void setDownloadLink(String linkStr) 191 { 192 downloadLink_ = linkStr; 193 } 194 195 196 public String getDownloadLink() 197 { 198 return downloadLink_; 199 } 200 201 202 /** gets the refKey_ as a HEX String (ie. 0b ) . **/ 203 public String getRefKeyString() 204 { 205 String retVal = ""; 206 207 //System.out.println("getRefKeyString() refKEY_="+java.util.Arrays.toString(refKEY_)); 208 try 209 { 210 //System.out.println("getRefKeyString() Hex.decodeHex(refKEY_)="+Hex.decodeHex(refKEY_)); 211 //System.out.println("getRefKeyString() Hex.encodeHexString(refKEY_)="+Hex.encodeHexString(Hex.decodeHex(refKEY_))); 212 retVal = Hex.encodeHexString(Hex.decodeHex(refKEY_)); //only takes EVENnumber of chars 213 } 214 catch (DecoderException dEx) 215 { 216 //send back an empty String 217 System.out.println("getRefKeyString() Crapped Out: "+dEx.getMessage()); 218 } 219 return retVal; 220 } 221 222 223 /** 224 * Set Method for class field 'refKEY_' for this Album. 225 * 226 * @param refKEY is the value to set this class field to. 227 * 228 **/ 229 public void setRefKEY(char[] refKEY) 230 { 231 this.refKEY_ = refKEY; 232 } // setRefKEY_ Method 233 234 235 /** 236 * Set Method for class field 'artistRefKEY_' for this Album. 237 * 238 * @param artistRefKEY is the value to set this class field to. 239 * 240 **/ 241 public void setArtistRefKEY(char[] artistRefKEY) 242 { 243 this.artistRefKEY_ = artistRefKEY; 244 } // setartistRefKEY_ Method 245 246 247 /** 248 * Get Method for class field 'refKEY_' for this Album. 249 * 250 * @return char[] - The value the class field 'refKEY_'. 251 * 252 **/ 253 public char[] getRefKEY() 254 { 255 return refKEY_; 256 } // getrefKEY Method 257 258 259 /** 260 * Get Method for class field 'artistRefKEY_' for this Album. 261 * 262 * @return char[] - The value the class field 'artistRefKEY_'. 263 * 264 **/ 265 public char[] getArtistRefKEY() 266 { 267 return artistRefKEY_; 268 } // getartistRefKEY Method 269 270 271 public String getArtistRefKeyString() 272 { 273 String retVal = ""; 274 try 275 { 276 retVal = Hex.encodeHexString(Hex.decodeHex(artistRefKEY_)); //only takes EVENnumber of chars 277 } 278 catch (DecoderException dEx) 279 { 280 //send back an empty String 281 System.out.println("getArtistRefKeyString() Crapped Out: "+dEx.getMessage()); 282 } 283 return retVal; 284 } 285 286 287 public boolean isArtistRefKEYEmpty() 288 { 289 return (artistRefKEY_[0]=='0' && artistRefKEY_[1]=='0' && artistRefKEY_[2]=='0' && artistRefKEY_[3]=='0' ) ; 290 } // getartistRefKEY Method 291 292 293 294 public char[] retrieveArtistRefKey() 295 { 296 String artistDirName = albumDirFile_.getAbsolutePath().substring(0, albumDirFile_.getAbsolutePath().lastIndexOf("/")); 297 String jsonStr = Util.readFileToString(artistDirName+SYSTEM_FILE_SEPERATOR+"MetaData.json"); 298 int indx = jsonStr.indexOf("refKey")+10; 299 System.out.println("DEBUG: retrieveArtistRefKey : artist.refKey.json.indx="+indx); 300 if(indx>10) 301 { 302 artistRefKEY_[0] = jsonStr.charAt(indx); 303 artistRefKEY_[1] = jsonStr.charAt(indx+1); 304 artistRefKEY_[2] = jsonStr.charAt(indx+2); 305 artistRefKEY_[3] = jsonStr.charAt(indx+3); 306 System.out.println("DEBUG: retrieveArtistRefKey : artistRefKEY_ " +artistRefKEY_[0]+artistRefKEY_[1]+artistRefKEY_[2]+artistRefKEY_[3]); 307 } 308 309 return artistRefKEY_; 310 } // retrieveArtistRefKey Method 311 312 313 /** Cobbles together the meta-data information about this Artist Directory in a JSON string. **/ 314 public String toMetaJson() 315 { 316 String retVal = ""; 317 318 retVal = MusicMakerTunesHelper.prettyPrint(toMetaJsonObject()); 319 320 return retVal; 321 } 322 323 324 /** Cobbles together the meta-data information about this Artist Directory in a JSON Object. **/ 325 public JsonObject toMetaJsonObject() 326 { 327 328 int songNum = 0; 329 JsonArrayBuilder arrayBuilder = Json.createArrayBuilder(); 330 String songRefKey = ""; 331 //songNamesSortByTrackNum(true).trim(); 332 String currSongStr = "null"; 333 for(Song currSong : getSongArraySortedByTrackNum2()) 334 { 335 currSongStr = "null"; 336 if(currSong!=null && !"".equals(currSongStr)) 337 currSongStr = currSong.name(true); 338 //Song currSong = new Song(albumDirFile_.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+ 339 try 340 { 341 //songRefKey = ""+ currSong.getNumber(); 342 songRefKey = Hex.encodeHexString(Hex.decodeHex(Util.toHEXChars(currSong.getNumber(),2))); 343 songNum++; 344 JsonObject jsonObject = Json.createObjectBuilder() 345 .add("dirFile", currSong.getSongFilePath().substring(currSong.getSongFilePath().lastIndexOf(SYSTEM_FILE_SEPERATOR)+1)) 346 .add("dirType", DirFileRef.DirType.RELEASE.typeStr) 347 .add("dirState", DirFileRef.DirState.LONG.stateStr) 348 .add("title", currSong.songTitle()) 349 .add("trackNum", currSong.getNumber()) 350 .add("musicBrainzID", "???") 351 .add("refKey", songRefKey) 352 .add("albumRefKey", currSong.getAlbumRefKeyString()) 353 .add("artistRefKey", currSong.getArtistRefKeyString()) 354 .build(); 355 arrayBuilder.add( jsonObject); 356 } 357 catch (DecoderException dEx) 358 { 359 //send back an empty String 360 System.out.println(albumTitle(true)+" toMetaJsonObject() Crapped Out: "+dEx.getMessage()); 361 System.out.println(" SKIPPING Song["+songNum+"] "+currSongStr); 362 } 363 catch (Exception ex) 364 { 365 //send back an empty String 366 System.out.println(albumTitle(true)+" toMetaJsonObject() Crapped Out: "); 367 System.out.println(" songRefKey = "+songRefKey); 368 System.out.println(" currSong = "+currSongStr); 369 ex.printStackTrace(); 370 } 371 } 372 JsonArray songArray = arrayBuilder.build(); 373 374 JsonObject json = Json.createObjectBuilder() 375 .add("dirFile", albumDirFile_.getAbsolutePath() ) 376 .add("dirType", DirFileRef.DirType.ALBUM.typeStr ) 377 .add("dirState", DirFileRef.DirState.LONG.stateStr) 378 .add("refKey", getRefKeyString() ) 379 .add("albumName", albumTitle(false) ) 380 .add("shortAlbumName", albumTitle(true) ) 381 .add("artistRefKey", getArtistRefKeyString()) 382 .add("musicBrainzID", getMbid()) 383 .add("numSongs", getNumberOfSongs() ) 384 .add("songs", songArray ) 385 .build(); 386 387 return json; 388 } 389 390 391 public void writeMetaJsonFile() 392 { 393 String metaStr = toMetaJson(); 394 System.out.println("\nWriting ALBUM MetaJson\n"+albumDirFile_.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+"MetaData.json"); 395 Util.writeStringToFile(metaStr, albumDirFile_.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+"MetaData.json"); 396 } 397 398 399 public void writeHtmlDivFile() 400 { 401 String htmlStr = toMusicMakerHtmlDivString(); 402 System.out.println("\nWriting ALBUM HTML Div\n"+albumDirFile_.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+"Album.html"); 403 Util.writeStringToFile(htmlStr, albumDirFile_.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+"Album.html"); 404 } 405 406 407 public String toMusicMakerHtmlDivString() 408 { 409 String albDirName = Util.tokenReplace(name(true),"%2f","%252f"); 410 411 String retVal = "<div id="+albumArtistName_+" class=musicmakeralbum >"; 412 String lastFmAlbumUrl = retrieveLastFmAlbumUrl(albumArtistName_, albumTitle()).replace("#","%23"); 413 lastFmAlbumUrl = Util.tokenReplace(lastFmAlbumUrl,"#","%23"); 414 retVal+= " <ol>"; 415 retVal+= SYSTEM_LINE_SEPERATOR; 416 retVal+= " <img id=\""+albumArtistName_.trim()+" " +albumTitle(true)+"\" alt=\""+albumTitle()+" Album Cover Thumbnail\" src=\""+ 417 getArtistDir()+"/"+albDirName+ 418 "/cover.jpg"+"\" class=\"\" style=\"margin:0px;\" height=\"32px\" width=\"32px\"/>"; 419 retVal+= " <b><u> "; 420 if(!"".equals(lastFmAlbumUrl))retVal+= " <a href=\""+lastFmAlbumUrl+"\" target=\"_blank\"> "; 421 retVal+= albumTitle(); 422 if(!"".equals(lastFmAlbumUrl))retVal+= " </a> "; 423 retVal+= "</u></b>"; 424 retVal+= " <span style=\"font-size: 0.7em;\">"; 425 retVal+= " ("+ getReleaseYear() + ")</span>"; 426 retVal+= SYSTEM_LINE_SEPERATOR; 427 String [] sNames = songNames(true,true,("VariousArtists".equalsIgnoreCase(artistDir_)?1:0)); // songNames(true,true,1); the last sortType=1 sorts by trackNum, sortType=0 sorts by name 428 429 int songNum = 0; 430 String songRefKey = ""; 431 //songNamesSortByTrackNum(true).trim(); 432 String currSongStr = "null"; 433 String artistDirName = albumDirFile_.getAbsolutePath().substring(0, albumDirFile_.getAbsolutePath().lastIndexOf("/")); 434 // work with the sorted list 435 for (String currSongName : sNames) 436 for (Song currSong : songs) 437 if (currSong.name(true).equals(currSongName) ) 438 { 439 String url = albumDirFile_.getAbsolutePath(); 440 url += Util.tokenReplace(name(true),"?","%3F"); 441 url = Util.tokenReplace(url,"&","%26"); 442 url = Util.tokenReplace(url,"!","%21"); 443 url = Util.tokenReplace(url,"%2f","%252f"); 444 url = Util.tokenReplace(url,"%2F","%252F"); 445 446 retVal+= " <li><a href=\""; 447 retVal+= currSong.getSongFilePath(); 448 retVal+= "\">"+currSong.songTitle(false); 449 retVal+= "</li>\n"; 450 //retVal+= currSong.toString(html); 451 } 452 retVal+= " </ol>"; 453 retVal+= SYSTEM_LINE_SEPERATOR; 454 retVal += "</div>"; 455 return retVal; 456 } 457 458 459 /** 460 * Set Method for class field 'mbid_'. 461 * 462 * @param mbid is the value to set this class field to. 463 * 464 **/ 465 public void setMbid(String mbid) 466 { 467 this.mbid_ = mbid; 468 } // setMbid Method 469 470 471 /** 472 * Get Method for class field 'mbid_'. 473 * 474 * @return String - The value the class field 'mbid_'. 475 * 476 **/ 477 public String getMbid() 478 { 479 return mbid_; 480 } // getMbid_ Method 481 482 483 public boolean contains(String SongNameNoSpaces) 484 { 485 boolean retVal = false; 486 for(Song currSong : this.songs) if(currSong.name(false).equals(SongNameNoSpaces)) retVal = true; 487 return retVal; 488 } 489 490 491 /** 492 * Sorted song file Names alphabetically with spaces in names . 493 * @return an array of song names 494 **/ 495 public String [] songNames(){return songNames(false,true);} 496 497 498 /** 499 * Sorted song file Names alphabetically with spaces in names . 500 * 501 * @param removeSpaces flags to remove Spaces from the songName or return CamelCase 502 * @return an array of song names 503 **/ 504 public String [] songNames(boolean removeSpaces){return songNames(removeSpaces,true);} 505 506 507 /** 508 * song file Names allowing you to contol sorting and spacing. 509 * 510 * @param removeSpaces flags to remove Spaces from the songName or return CamelCase 511 * @param sorted flags to sort or not sort using default sortByNumbers 512 * @return an array of song names 513 **/ 514 public String [] songNames(boolean removeSpaces, boolean sorted){return songNames(removeSpaces, sorted, 1);} 515 516 517 /** 518 * song file Names allowing you to contol sorting and spacing. 519 * 520 * @param removeSpaces flags to remove Spaces from the songName ie. CamelCase 521 * @param sorted flags to sort or not sort 522 * @param sortBy signals what to sortby - 0=alphabetical Name or by 1=trackNumber 523 * @return an array of song names 524 **/ 525 public String [] songNames(boolean removeSpaces, boolean sorted, int sortBy) 526 { 527 /* sortBy signals what to sortby - 0=name or by 1=trackNumber */ 528 String[] songNames = new String[songs.size()]; 529 for(int i=0; i< songNames.length; i++) songNames[i]=songs.get(i).name(removeSpaces); // name returns the songs filename with no path 530 if (sorted) 531 if(sortBy==1) songNames = songNamesSortedByTrackNum(removeSpaces); 532 else Quick.sort(songNames); 533 String[] retVal = songNames; 534 if(!removeSpaces) for(int i=0; i< songNames.length; i++) retVal[i] = Util.capsToSpacesInString(songNames[i]); 535 return retVal; 536 } 537 538 539 /** Sorted songTitles with spaces in names . **/ 540 public String [] songTitles(){return songTitles(false,true);} 541 public String [] songTitles(boolean removeSpaces){return songTitles(removeSpaces,true);} 542 public String [] songTitles(boolean removeSpaces, boolean sorted) 543 { 544 String[] songTitles = new String[songs.size()]; 545 for(int i=0; i< songTitles.length; i++) songTitles[i]=songs.get(i).songTitle(removeSpaces); 546 if (sorted) Quick.sort(songTitles); 547 String[] retVal = songTitles; 548 if(!removeSpaces) for(int i=0; i< songTitles.length; i++) retVal[i] = Util.capsToSpacesInString(songTitles[i]); 549 return retVal; 550 } 551 552 553 /** 554 * Sorts the Passed in songNames by their track number on this album. 555 * SongName part of the filename including extension with or without thw spaces in name . 556 * @deprecated 557 **/ 558 @Deprecated 559 public String [] songNamesSortByTrackNum(boolean removeSpaces) 560 { 561 //System.out.println(" }} Album.songNamesSortByTrackNum("+(removeSpaces?"removeSpaces)":"NOT removeSpaces)")); 562 String[] songNames = new String[songs.size()]; 563 int [] songNums = new int[songs.size()]; 564 int [] songCDNums = new int[songs.size()]; 565 Song sn = null; 566 int maxCDNum = 1; 567 int i=0; 568 for(i=0; i< songNames.length; i++) 569 { 570 sn = songs.get(i); 571 songNames[i]=sn.name(removeSpaces); // name returns the songs filename with no path 572 songNums[i]=sn.getNumber(); 573 songCDNums[i]=sn.getCdNumber(); 574 if(songCDNums[i]>maxCDNum) maxCDNum = songCDNums[i]; 575 } 576 String[] retVal = new String[maxCDNum*songs.size()]; 577 int j=0; 578 int numMissing = 0; 579 boolean validNums = true; 580 boolean done = false; 581 boolean busted = false; 582 int cdNum=1; 583 int lastCD = 1; 584 //if(maxCDNum>1) System.out.print(" }} cdNum/maxCDNum ="+cdNum+"/"+maxCDNum); 585 for(i=0; i< songNames.length && validNums && cdNum<=maxCDNum; i++) 586 { 587 while(cdNum<=maxCDNum && !done && !busted) 588 { 589 retVal[i]=""; 590 if(maxCDNum>1) System.out.print(" cdNum="+cdNum+"/"+maxCDNum); 591 if(maxCDNum>1) System.out.println(" ."+songCDNums[i]+" "+numMissing); 592 if(cdNum==songCDNums[i]) 593 { 594 done = false; 595 while(!done && !busted) 596 { 597 for(j=0; j< songNames.length && !done; j++) 598 { 599 if(maxCDNum>1) System.out.print(":"+songCDNums[j]+"."+songNums[j]); 600 if(cdNum==songCDNums[j] && songNums[j]==i+1+numMissing) 601 { 602 retVal[i+((cdNum-1)*songNames.length)]=songNames[j]; 603 done = true; 604 if(maxCDNum>1) System.out.println("!!"); 605 } 606 } 607 if(!done) //"".equals(retVal[i])) 608 { 609 numMissing++; 610 if(numMissing>=100) 611 { 612 validNums = false; 613 busted=true; 614 cdNum++; 615 System.out.println("\n }}}"+name()+" cdNum/maxCDNum ="+cdNum+"/"+maxCDNum); 616 System.out.println("\n BUSTED }}} looking for CD "+songCDNums[i]+":songNum["+i+"]="+songNums[i]+": choked on ["+j+"-1] of "+songNames.length); 617 System.out.println("\n BUSTED }}} too many missing songs: "+numMissing); 618 } 619 } 620 } 621 //cdNum++; 622 } 623 else cdNum++; 624 } 625 } 626 if(!validNums) 627 { 628 System.out.println(" }} : "+name() ); 629 System.out.println(" }} CD: "+java.util.Arrays.toString(songCDNums)); 630 System.out.println(" }} NUMS: "+java.util.Arrays.toString(songNums)); 631 System.out.println(" }} IN: "+java.util.Arrays.toString(songNames)); 632 System.out.println(" }} --> missing songs: "+numMissing); 633 System.out.println(" }} OUT: "+java.util.Arrays.toString(retVal)+"\n"); 634 } 635 636 return (validNums?retVal:songNames(removeSpaces, true,0)); 637 } 638 639 640 /** 641 Sorts the Passed in songNames by their track number on this album. 642 SongName part of the filename including extension with or without thw spaces in name . 643 **/ 644 public String [] songNamesSortedByTrackNum(boolean removeSpaces) 645 { 646 //System.out.println(" }} Album.songNamesSortByTrackNum("+(removeSpaces?"removeSpaces)":"NOT removeSpaces)")); 647 String[] songNames = new String[songs.size()]; 648 int [] songNums = new int[songs.size()]; 649 int [] songCDNums = new int[songs.size()]; 650 Song sn = null; 651 int maxCDNum = 1; 652 int i=0; 653 for(i=0; i< songNames.length; i++) 654 { 655 sn = songs.get(i); 656 songNames[i]=sn.name(removeSpaces); // name returns the songs filename with no path 657 songNums[i]=sn.getNumber(); 658 songCDNums[i]=sn.getCdNumber(); 659 if(songCDNums[i]>maxCDNum) maxCDNum = songCDNums[i]; 660 } 661 String[] retVal = new String[maxCDNum*songs.size()]; 662 int j=0; 663 int nextIndex = 0; 664 int nextSongNum = 0; 665 boolean validNums = true; 666 boolean done = false; 667 int cdNum=1; 668 669 for(int currCD=1; currCD<=maxCDNum; currCD++) 670 { 671 for(nextSongNum=1; nextSongNum< 150 && nextIndex<songNames.length; nextSongNum++) 672 { 673 done = false; 674 for(j=0; j< songNames.length && !done; j++) 675 if(currCD==songCDNums[j] && songNums[j]==nextSongNum) 676 { 677 retVal[nextIndex++]=songNames[j]; 678 done = true; 679 } 680 } 681 } 682 683 validNums = (nextIndex==songNames.length); 684 return (validNums?retVal:songNames(removeSpaces, true,0)); 685 } 686 687 688 public Song[] getSongArray(){ return songs.toArray(new Song[songs.size()]);} 689 public Song[] getSongArraySortedByTrackNum() 690 { 691 String[] songNames = new String[songs.size()]; 692 int [] songNums = new int[songs.size()]; 693 int [] songCDNums = new int[4]; 694 Song sng = null; 695 int maxCDNum = 1; 696 int i=0; 697 for(i=0; i< songs.size(); i++) 698 { 699 sng = songs.get(i); 700 songNames[i]=sng.name(true); // name returns the songs filename with no path 701 songNums[i]=sng.getNumber(); 702 songCDNums[i]=sng.getCdNumber(); 703 if(songCDNums[i]>maxCDNum) maxCDNum = songCDNums[i]; 704 } 705 Song[] retVal = new Song[maxCDNum*songs.size()]; 706 int j=0; 707 int nextIndex = 0; 708 int nextSongNum = 0; 709 boolean validNums = true; 710 boolean done = false; 711 int cdNum=1; 712 713 for(int currCD=1; currCD<=maxCDNum; currCD++) 714 { 715 for(nextSongNum=1; nextSongNum< 150 && nextIndex<songNames.length; nextSongNum++) 716 { 717 done = false; 718 for(j=0; j< songNames.length && !done; j++) 719 if(currCD==songCDNums[j] && songNums[j]==nextSongNum) 720 { 721 retVal[nextIndex++]=songs.get(j); 722 done = true; 723 } 724 } 725 } 726 727 validNums = (nextIndex==songNames.length); 728 729 return (validNums?retVal:getSongArray()); 730 } 731 732 733 public Song[] getSongArraySortedByTrackNum2() 734 { 735 Song[] retVal = getSongArray(); 736 ca.bc.webarts.widgets.Quick.sort(retVal); 737 //java.util.Arrays.sort(retVal); 738 return retVal; 739 } 740 741 public Vector<Song> getSongs(){ return songs;} 742 public int getNumberOfSongs() {return songs.size(); } 743 /** A single string listing one songname per line ( with spaces in names) . **/ 744 public String listSongs(){return listSongs(false);} 745 public String listSongs(boolean removeSpaces) 746 { 747 StringBuilder retVal = new StringBuilder(); 748 for(String currSongTitle : songTitles(removeSpaces)) retVal.append(currSongTitle+SYSTEM_LINE_SEPERATOR); 749 return retVal.toString(); 750 } 751 752 753 /** AlbumName part of the filename <b>with</b> spaces in name . **/ 754 public String name(){return name(false);} 755 /** AlbumName part of the filename with or without spaces in name . **/ 756 public String name(boolean removeSpaces) 757 { 758 String retVal = albumDirFile_.getAbsolutePath().substring(albumDirFile_.getAbsolutePath().lastIndexOf("/")+1); 759 if (!removeSpaces) retVal = Util.capsToSpacesInString(retVal); 760 return retVal.trim(); 761 } 762 763 764 /** The actual fully expanded, cleaned of underscores and explicits / usable Album Title. **/ 765 public String albumTitle() 766 { 767 return albumTitle(false); 768 } 769 770 771 /** The actual cleaned of underscores and explicits / usable Album Title. **/ 772 public String albumTitle(boolean removeSpaces) 773 { 774 String title = name(); 775 title = Song.removeExplicit(title); 776 title = Util.tokenReplace(title," <","<"); 777 title = Util.tokenReplace(title," "," "); 778 title = Util.tokenReplace(title,"+"," +"); 779 title = Util.tokenReplace(title,"++","+"); 780 title = Util.tokenReplace(title,"x &y","x&y"); 781 title = Util.tokenReplace(title,"x & y","x&y"); 782 title = Util.tokenReplace(title,"X &Y","X&Y"); 783 title = Util.tokenReplace(title,"X & Y","X&Y"); 784 title = Util.tokenReplace(title,"_"," "); 785 title = Util.tokenReplace(title,"%23","#"); 786 title = Util.tokenReplace(title,"%2f","/"); 787 title = Util.tokenReplace(title,"%2F","/"); 788 title = Util.tokenReplace(title,"A & M","A&M"); 789 title = Util.tokenReplace(title,"A & M","A&M"); 790 title = Util.tokenReplace(title,"A& M","A&M"); 791 title = Util.tokenReplace(title,"A &M","A&M"); 792 if (removeSpaces) title=Util.spacesToCapsInString(title); 793 return title.trim(); 794 } 795 796 797 /** loops thropugh all Album Songs and test and marks them as Last.fm loved if they are. **/ 798 public void markLovedSongs(Vector<String> lovedTrackNames) 799 { 800 //System.out.println(" >> Album.lastFmLovedTrackNames_=\n"+ lovedTrackNames+"\n"); 801 String currSongTitle = ""; 802 boolean currLoved = false; 803 try 804 { 805 for(Song currSong : getSongs() ) 806 { 807 currLoved = false; 808 currSongTitle = currSong.songTitle(); 809 for(int i=0; i<lovedTrackNames.size(); i++) 810 if(lovedTrackNames.get(i).equalsIgnoreCase(currSongTitle)){currLoved=true;currSong.setLastFmLoved();i=lovedTrackNames.size();} 811 //if(albumTitle().equalsIgnoreCase("Greatest Hits - The Real Thing")) 812 // System.out.println(" >> Album.markLovedSongs: "+currSongTitle +" : "+(currLoved?"YES":"no")); 813 } 814 } 815 catch ( Exception ex) 816 { 817 System.out.println(" *! Album Fudge markLovedSongs ("+name()+", "+currSongTitle+") : "+ex.getMessage()); 818 //ex.printStackTrace(); 819 } 820 821 } 822 823 824 /** Returns a wrapper for this Album's LastFM Album or null if not valid name. It also loads the releaseDate.**/ 825 public de.umass.lastfm.Album retrieveLastFmAlbum(){ return retrieveLastFmAlbum(false);} 826 public de.umass.lastfm.Album retrieveLastFmAlbum(boolean reRetrieve) 827 { 828 if(lastFmAlbum_==null || reRetrieve) 829 { 830 de.umass.lastfm.Album lastFmAlbum_ = retrieveLastFmAlbum(Util.capsToSpacesInString(albumArtistName_).trim(), albumTitle()); 831 if(lastFmAlbum_!=null) 832 { 833 //setReleaseDate(lastFmAlbum_.getReleaseDate()); // Last.fm release date is always non-existant 834 setMbid(lastFmAlbum_.getMbid()); 835 } 836 //System.out.println("\n >> ReleaseDate: " + getReleaseDate()); 837 } 838 return lastFmAlbum_; 839 } 840 841 842 /** Returns a wrapper for the LastFM Album or null if not valid name. Use the Album.getUrl() if needed. **/ 843 public static de.umass.lastfm.Album retrieveLastFmAlbum(String art, String albumName) 844 { 845 // this call is not reliable 846 //System.out.println("\n >> retrieveLastFmAlbum: " + art +" / " + albumName); 847 // http://ws.audioscrobbler.com/2.0/?method=album.getInfo&artist=Pearl+Jam&api_key=93df6c849563eef04d7d48db5950d0c7&album=Ten 848 de.umass.lastfm.Album lastFmAlbum_ = de.umass.lastfm.Album.getInfo(art, albumName , TunesHelper.LASTFM_API_KEY); 849 return lastFmAlbum_; 850 } 851 852 public int retrieveMusicBrainzReleaseYear() { return retrieveMusicBrainzReleaseYear(artistName_, albumTitle());} 853 public int retrieveMusicBrainzReleaseYear(String artistName, String albumTitle) 854 { 855 //System.out.println("\n --> retrieveMusicBrainzReleaseYear: " + artistName +" : " + albumTitle); 856 int retVal = 1900; 857 858 String searchResults = mbRR_.searchRelease(artistName, albumTitle ).toString(); 859 nu.xom.Document releaseDoc = mbRR_.parseXMLResponse(searchResults); 860 retVal = mbRR_.parseSearchResultsForReleaseYear(releaseDoc); 861 System.out.println(" --> " + retVal); 862 863 return retVal; 864 } 865 866 867 /** Returns a wrapper for the LastFM Album or null if not valid name. Use the Album.getUrl() if needed. **/ 868 public static String retrieveLastFmAlbumUrl(String art, String albumName) 869 { 870 String retVal = ""; 871 if(false) 872 { 873 de.umass.lastfm.Album al = retrieveLastFmAlbum( art, albumName); 874 if(al!=null) 875 { 876 //System.out.println("\n >>>> retrieveLastFmAlbumUrl: " + art +"_" +albumName); 877 retVal = al.getUrl() ; 878 } 879 } 880 else 881 { 882 //if(albumName.contains("+") || albumName.contains("<") ) System.out.println("\n >>>>>> albumName: " + albumName.trim()); 883 retVal = "https://www.last.fm/music/"+Util.capsToSpacesInString(art).trim().replace("+","%252B").replace("_"," ").replace(" ","+").replace("++","+")+ 884 "/"+albumName.trim().replace("+"," %252B").replace("_"," ").replace(" ","+").replace("++","+").replace("/","%2f").replace("'","%27").replace("#","%23") ; 885 } 886 return retVal; 887 } 888 889 890 /** 891 * Set Method for class field 'releaseDate_'. 892 * 893 * @param releaseDate is the value to set this class field to. 894 * 895 **/ 896 public void setReleaseDate(java.util.Date releaseDate) 897 { 898 this.releaseDate_ = releaseDate; 899 } // setReleaseDate Method 900 901 902 /** 903 * Get Method for class field 'releaseDate_'. 904 * 905 * @return java.util.Date - The value the class field 'releaseDate_'. 906 * 907 **/ 908 public java.util.Date getReleaseDate() 909 { 910 return releaseDate_; 911 } // getReleaseDate Method 912 913 914 /** 915 * Get releaseDate as a String. 916 * 917 * @return String - The value the class field 'releaseDate_' as a String. 918 * 919 **/ 920 public String getReleaseDateStr() 921 { 922 return releaseDate_.toString(); 923 } // getReleaseDate Method 924 925 926 /** 927 * Get releaseDate YEAR as an int. 928 * 929 * @return int - The value the class field 'releaseDate_' YEAR as an int. 930 * 931 **/ 932 public int getReleaseYear() 933 { 934 return releaseYear_; 935 /* 936 int retVal = releaseYear_; 937 938 if(mb_!=null) retVal = mb_.getYear(); 939 else if(getReleaseDate()!=null) 940 { 941 java.util.Calendar cal = java.util.Calendar.getInstance(); 942 cal.setTime(getReleaseDate()); 943 retVal=cal.get(java.util.Calendar.YEAR); 944 } 945 return retVal; 946 */ 947 } // getReleaseYear Method 948 949 950 public int compareTo(Album a2) 951 { 952 return compareToReleaseDate( a2); 953 } 954 955 956 /** Implements the Comparator and sorts by Date of album. **/ 957 public int compareToReleaseDate(Album a2) 958 { 959 int retVal = 0; 960 java.util.Date a1R = this.getReleaseDate(); 961 java.util.Date a2R = a2.getReleaseDate(); 962 if(a1R!=null && a2R!=null) 963 if(a1R.after(a2R)) retVal = 1; 964 else if(a2R.after(a1R)) retVal = -1; 965 return retVal; 966 } 967 968 969 /** Compares the Album Titles. **/ 970 public int compareToAlbumTitle(Album o) 971 { 972 return this.albumTitle().compareTo(o.albumTitle()); 973 } 974 975 976 /** The Song Title. **/ 977 public String toString() 978 { 979 return this.albumTitle(); 980 } 981 982 983 /** lists all songs in a JSON string. **/ 984 public String toJsonString(int songIndex) 985 { 986 StringBuilder retVal = new StringBuilder(""); 987 String artDirName = Util.tokenReplace(getArtistDir(),"%2f","%252f"); 988 artDirName = Util.tokenReplace(artDirName,"%2F","%252F"); 989 artDirName = Util.tokenReplace(artDirName,"'","%27"); 990 991 int songCount = 0; int tot = songs.size();boolean matched = false; 992 993 // setup a SORTED list 994 String [] sNames = songNames(true,true,("VariousArtists".equalsIgnoreCase(artDirName)?1:0)); // songNames(true,true,1); the last sortType=1 sorts by trackNum, sortType=0 sorts by name 995 for (String currSongName : sNames) 996 { 997 matched = false; 998 // Cycle through and pick them in SORTED order 999 for (Song currSong : songs) 1000 { 1001 if ( !matched && currSong.name(true).equals(currSongName) ) 1002 { 1003 retVal.append(currSong.toJsonString(songIndex+songCount)); 1004 if(songCount++<tot-1) 1005 retVal.append(","); // //"+ songCount+" / "+tot); 1006 //else 1007 // retVal.append("// "+ songCount+" / "+tot +" End Of Album='"+albumTitle()+"'"); 1008 retVal.append(SYSTEM_LINE_SEPERATOR); 1009 matched = true; 1010 } 1011 } 1012 if(!matched) 1013 retVal.append("// Strange: No Match for currSongName='"+currSongName+"'\n"); 1014 } 1015 return retVal.toString(); 1016 } 1017 1018 1019 public String toString(boolean html) 1020 { 1021 String lastFmAlbumUrl = retrieveLastFmAlbumUrl(albumArtistName_, albumTitle()).replace("#","%23"); 1022 lastFmAlbumUrl = Util.tokenReplace(lastFmAlbumUrl,"#","%23"); 1023 String retVal = ""; 1024 if(html)retVal+= " <ol>"; 1025 if(html)retVal+= SYSTEM_LINE_SEPERATOR; 1026 String albDirName = Util.tokenReplace(name(true),"%2f","%252f"); 1027 albDirName = Util.tokenReplace(albDirName,"%2F","%252F"); 1028 albDirName = Util.tokenReplace(albDirName,"'","%27"); 1029 albDirName = Util.tokenReplace(albDirName,"#","%23"); 1030 String artDirName = Util.tokenReplace(getArtistDir(),"%2f","%252f"); 1031 artDirName = Util.tokenReplace(artDirName,"%2F","%252F"); 1032 artDirName = Util.tokenReplace(artDirName,"'","%27"); 1033 artDirName = Util.tokenReplace(artDirName,":","%3a"); 1034 if(albumTitle(true).contains("Wembley"))System.out.println(" DEBUG: Album.toString artDirName="+artDirName); 1035 1036 String songsHtml = ""; 1037 int firstSongLibraryIndex = -1; 1038 1039 String [] sNames = songNames(true,true,("VariousArtists".equalsIgnoreCase(artDirName)?1:0)); // songNames(true,true,1); the last sortType=1 sorts by trackNum, sortType=0 sorts by name 1040 // work with the sorted list 1041 for (String currSongName : sNames) 1042 for (Song currSong : songs) 1043 if (currSong.name(true).equals(currSongName) ) 1044 { 1045 songsHtml+= currSong.toString(html); 1046 if(firstSongLibraryIndex==-1) 1047 firstSongLibraryIndex = currSong.getLibraryIndex(); 1048 } 1049 1050 // This makes a call to a function in jplayer.js 1051 String playAlbumOnPiURL = "javascript:playPirateArtistAlbum('"+artDirName+"/"+albDirName+"', 'album', "+firstSongLibraryIndex+")"; 1052 1053 if(html && !"".equals(lastFmAlbumUrl))retVal+= " <a href=\""+lastFmAlbumUrl+"\" target=\"_blank\"> "; 1054 if(html)retVal+= " <img id=\""+albumArtistName_.trim()+" " +albumTitle(true)+"\" alt=\""+albumTitle()+" Album Cover Thumbnail\" src=\""+ 1055 TunesHelper.getTunesSubPath()+"/"+artDirName+"/"+albDirName+ 1056 "/cover.jpg"+"\" class=\"\" style=\"margin:0px;\" height=\"32px\" width=\"32px\"/>"; 1057 if(html && !"".equals(lastFmAlbumUrl))retVal+= " </a> "; 1058 1059 if(html)retVal+= " <b><u> "; 1060 if(html)retVal+= " <a href=\""+playAlbumOnPiURL+"\" > "; 1061 retVal+= albumTitle(); 1062 if(html )retVal+= " </a> "; 1063 //if(name().contains("+")) System.out.println("\n >>>>>> Album.albumName: " + name() +" - "+albumTitle()); 1064 if(html)retVal+= "</u></b>"; 1065 if(html)retVal+= " <span style=\"font-size: 0.7em;\">"; 1066 if(html)retVal+= " ("+ getReleaseYear() + ")"; 1067 if(html)retVal+= " [<a href=\""+downloadLink_+"\">zip</a>]</span>"; 1068 retVal+= SYSTEM_LINE_SEPERATOR; 1069 if(html)retVal+= songsHtml; 1070 if(html)retVal+= " </ol>"; 1071 retVal+= SYSTEM_LINE_SEPERATOR; 1072 1073 return retVal; 1074 } 1075}