001/* 002 * $URL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/MusicbrainzRestRequester.java $ 003 * $Author: tgutwin $ 004 * $Revision: 1219 $ 005 * $Date: 2018-03-02 22:12:45 -0800 (Fri, 02 Mar 2018) $ 006 */ 007/* 008 * 009 * Written by Tom Gutwin - WebARTS Design. 010 * Copyright (C) 2014-2016 WebARTS Design, North Vancouver Canada 011 * http://www.webarts.ca 012 * 013 * This program is free software; you can redistribute it and/or modify 014 * it under the terms of the GNU General Public License as published by 015 * the Free Software Foundation; version 3 of the License, or 016 * (at your option) any later version. 017 * 018 * This program is distributed in the hope that it will be useful, 019 * but WITHOUT ANY WARRANTY; without_ even the implied warranty of 020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 021 * GNU General Public License for more details. 022 * 023 * You should have received a copy of the GNU General Public License 024 * along with this program; if not, write to the Free Software 025 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 026 */ 027 028package ca.bc.webarts.tools.musicbrainz; 029 030import java.io.IOException; 031import java.io.File; 032import java.io.FileNotFoundException; 033import java.lang.Integer; 034import java.net.HttpURLConnection; 035import java.net.MalformedURLException; 036import java.net.URL; 037import java.net.URLEncoder; 038import java.util.Arrays; 039import java.util.Comparator; 040import java.util.Hashtable; 041import java.util.Set; 042import java.util.Vector; 043 044 045import ca.bc.webarts.tools.RestRequester; 046import ca.bc.webarts.widgets.Util; 047import ca.bc.webarts.widgets.Quick; 048 049import org.apache.commons.codec.binary.Base64; 050 051import nu.xom.Attribute; 052import nu.xom.Builder; 053import nu.xom.Document; 054import nu.xom.Element; 055import nu.xom.Elements; 056import nu.xom.Node; 057import nu.xom.ParsingException; 058import nu.xom.ValidityException; 059import nu.xom.Serializer; 060import nu.xom.XPathException; 061 062 063/** 064 * This class wraps the communication to the <a href="https://wiki.musicbrainz.org/Development">REST interface to Musicbrainz</a>. 065 * The web service root URL is https://musicbrainz.org/ws/2/<br> 066 * There are 12 resources on our web service which represent core entities in our database: 067 * <ul><li>area,</li><li>artist,</li><li>event,</li><li>instrument,</li><li>label,</li><li>place,</li><li>recording,</li><li>release,</li><li>release-group,</li><li>series,</li><li>work,</li><li>url</li></ul> 068 * We also provide a web service interface for the following non-core resources: 069 * <ul><li>rating,</li><li>tag,</li><li>collection</li></ul> 070 * You can perform lookups based on other unique identifiers with these resources: 071 * <code>discid, isrc, iswc</code><br> 072 * On each entity resource, you can perform three different GET requests: 073 * <ul> 074 * <li>lookup: /<ENTITY>/<MBID>?inc=<INC></li> 075 * <li>browse: /<ENTITY>?<ENTITY>=<MBID>&limit=<LIMIT>&offset=<OFFSET>&inc=<INC></li> 076 * <li>search: /<ENTITY>?query=<QUERY>&limit=<LIMIT>&offset=<OFFSET></li> 077 * ... except that search is not implemented for URL entities at this time.</ul><br /> 078 * The request looks like this...<br> 079 * <a href="http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake">http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake</a><br> 080 * or this... <a href="http://musicbrainz.org/ws/2/release/?query=country:US">http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake%20AND%20country:US</a><br> 081 * or this... <a href="http://musicbrainz.org/ws/2/release/?query=release:X%20AND%20country:CA%20AND%20artist:Inxs">http://musicbrainz.org/ws/2/release/?query=release:X%20AND%20country:CA%20AND%20artist:Inxs</a><br> 082 *<br> 083 * 084 * Written by Tom Gutwin - WebARTS Design.<br /> 085 * Copyright © 2018 WebARTS Design, North Vancouver Canada<br /> 086 * <a href="http://www.webarts.ca">http://www.webarts.ca</a> 087 * 088 * @author Tom B. Gutwin 089 **/ 090public class MusicbrainzRestRequester extends ca.bc.webarts.tools.RestRequester 091{ 092 protected static final String CLASSNAME = "ca.bc.webarts.tools.musicbrainz.MusicbrainzRestRequester"; //ca.bc.webarts.widgets.Util.getCurrentClassName(); 093 public static final String LOG_TAG = "\n"+CLASSNAME; //+"."+ca.bc.webarts.android.Util.getCurrentClassName(); 094 095 /** DEFAULT MUSICBRAINZ IP address to use: 10.0.0.207 .**/ 096 protected static final String DEFAULT_MUSICBRAINZ_IP = "musicbrainz.org"; 097 /** DEFAULT CoverArt Archive server used by MUSICBRAINZ .**/ 098 protected static final String DEFAULT_COVERARTARCHIVE_IP = "coverartarchive.org"; 099 /** DEFAULT MUSICBRAINZ username to use: admin .**/ 100 protected static final String DEFAULT_MUSICBRAINZ_USERNAME = "admin"; 101 /** DEFAULT MUSICBRAINZ password to use: admin .**/ 102 protected static final String DEFAULT_MUSICBRAINZ_PASSWORD = "admin"; 103 /** DEFAULT MUSICBRAINZ rest URL to start the URL path: /rest .**/ 104 protected static final String DEFAULT_MUSICBRAINZ_REST_URL_PATHSTR = "/ws/2"; 105 /** DEFAULT CoverArt Archive rest URL to start the URL path: /rest .**/ 106 protected static final String DEFAULT_COVERARTARCHIVE_REST_URL_PATHSTR = "release"; // /release/{mbid}/front 107 /** A default Release MRID to use for testing. Barenaked Ladies, Gordon. **/ 108 protected static final String DEFAULT_MUSICBRAINZ_TEST_RELEASE_MRID = "38e73fee-7420-4f3a-805a-6fdfac011ac2"; 109 protected static final String DEFAULT_COVERARTARCHIVE_TEST_IMAGE_ID = "15241341638"; 110 protected static final String DEFAULT_MUSICBRAINZ_TEST_ARTIST_MRID = "86e736b4-93e2-40ff-9e1c-fb7c63fef5f6"; 111 112 113 protected static StringBuilder helpMsg_ = new StringBuilder(SYSTEM_LINE_SEPERATOR); 114 protected static boolean debugOut_ = false; 115 protected static boolean doWrites_ = true; 116 117 protected String metaDataDirFilename_ = "."; 118 protected String metaDataFilename_ = "mbData.props"; 119 120 /** The start path to use in therest URL. Over-ride this if you extend this class. **/ 121 protected String restUrlPath_ = DEFAULT_MUSICBRAINZ_REST_URL_PATHSTR; 122 123 /** 124 The URL for the CoverArt for any MRID looked up release. Various Coverart API calls are 125 available to get different images: 126 see <a href="https://musicbrainz.org/doc/Cover_Art_Archive/API">https://musicbrainz.org/doc/Cover_Art_Archive/API</a> 127 **/ 128 protected String coverartImageUrl_="http://"+DEFAULT_COVERARTARCHIVE_IP+"/" 129 +DEFAULT_COVERARTARCHIVE_REST_URL_PATHSTR+"/" 130 +DEFAULT_MUSICBRAINZ_TEST_RELEASE_MRID+"/front"; 131 132 Builder xmlBuilder_ = new Builder(); 133 134 /** 135 * Default constructor . 136 * 137 * @see #DEFAULT_MUSICBRAINZ_IP 138 * @see #DEFAULT_MUSICBRAINZ_USERNAME 139 * @see #DEFAULT_MUSICBRAINZ_PASSWORD 140 **/ 141 public MusicbrainzRestRequester() 142 { 143 authenticating_=false; 144 setBaseUrl( "https://"+DEFAULT_MUSICBRAINZ_IP+restUrlPath_); 145 setUsername( DEFAULT_MUSICBRAINZ_USERNAME); 146 setPassword( DEFAULT_MUSICBRAINZ_PASSWORD); 147 } 148 149 150 /** 151 * Constructor to customize all connection settings. 152 * 153 **/ 154 public MusicbrainzRestRequester(String server, String user, String pass) 155 { 156 setBaseUrl( "https://"+server+restUrlPath_); 157 authenticating_=true; 158 setUsername(user); 159 setPassword( pass); 160 } 161 162 /** 163 * Set Method for class field 'restUrlPath_'. 164 * 165 * @param restUrlPath is the value to set this class field to. 166 * 167 **/ 168 public void setRestUrlPath(String restUrlPath) 169 { 170 restUrlPath_ = restUrlPath; 171 } // setRestUrlPath Method 172 173 174 /** 175 * Get Method for class field 'restUrlPath_'. 176 * 177 * @return String - The value the class field 'restUrlPath_'. 178 * 179 **/ 180 public String getRestUrlPath() 181 { 182 return restUrlPath_; 183 } // getRestUrlPath Method 184 185 186 public String getCoverArtImageUrlStrByRelease(String artName, String albName) 187 { 188 StringBuilder releaseResults = searchRelease(artName, albName); 189 nu.xom.Document releaseDoc = parseXMLResponse(releaseResults.toString()); 190 String mrid = parseSearchResultsForMRID(releaseDoc,0); 191 192 return "http://"+DEFAULT_COVERARTARCHIVE_IP+"/" 193 +DEFAULT_COVERARTARCHIVE_REST_URL_PATHSTR+"/" 194 +mrid+"/front"; 195 } 196 197 198 public String getCoverArtImageUrlStrByMbid(String mrid) 199 { 200 return "http://"+DEFAULT_COVERARTARCHIVE_IP+"/" 201 +DEFAULT_COVERARTARCHIVE_REST_URL_PATHSTR+"/" 202 +mrid+"/front"; 203 } 204 205 206 /** Check connectivity to the MusicBrainz URL specified by the class parms. 207 * @return true or false 208 **/ 209 public boolean canConnect() 210 { 211 if(debugOut_) System.out.println(LOG_TAG+".canConnect("+getBaseUrl()+", "+getUsername()+", "+getPassword()+")"); 212 213 boolean retVal = false; 214 if(isInit()) 215 { 216 try 217 { 218 if(debugOut_) System.out.println(LOG_TAG+".init = true"); 219 String usrlStr = (baseUrl_+"/release/"+DEFAULT_MUSICBRAINZ_TEST_RELEASE_MRID).replace(" " ,"%20"); 220 URL url = new URL(usrlStr); 221 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 222 conn.setRequestMethod("GET"); 223 if(acceptJSON_) 224 conn.setRequestProperty("Accept", "application/json"); 225 else 226 conn.setRequestProperty("Accept", "application/xml"); 227 228 conn.setRequestProperty("User-Agent", USER_AGENT+" ( tgutwin@webarts.ca )"); 229 230 if (authenticating_) 231 { 232 //BASE64Encoder enc = new sun.misc.BASE64Encoder(); 233 String userpassword = username_ + ":" + password_; 234 //String encodedAuthorization = android.util.Base64.encodeToString( userpassword.getBytes(), android.util.Base64.DEFAULT ); 235 String encodedAuthorization = new String(Base64.encodeBase64( (userpassword.getBytes()) )); 236 conn.setRequestProperty("Authorization", "Basic "+ encodedAuthorization); 237 } 238 239 if (conn.getResponseCode() == 200) 240 { 241 retVal=true; 242 } // valid http response code 243 conn.disconnect(); 244 } 245 catch (MalformedURLException e) 246 { 247 e.printStackTrace(); 248 } 249 catch (IOException e) 250 { 251 e.printStackTrace(); 252 } 253 } 254 return retVal; 255 } 256 257 258 /** returns the status for all the nodes. **/ 259 public StringBuilder getStatus() 260 { 261 return serviceGet("/status"); 262 } 263 264 265 /** queries all the nodes. **/ 266 public StringBuilder getQuery() 267 { 268 return serviceGet("/query"); 269 } 270 271 272 273 274 /** returns config. **/ 275 public StringBuilder getConfig() 276 { 277 return serviceGet("/config"); 278 } 279 280 281 282 /** 283 * Class main commandLine entry method that has a test command and some convienience commands, as well as a pure rest command. 284 * 285 * <br>Commandline:<br> 286 * java ca.bc.webarts.tools.musicbrainz.MusicbrainzRestRequester command or {restCommand}<br> 287 * <br> 288 * Available commands:<br> 289 * test<br> 290 * 291 * parseDir Creates MusicBrainz Meta-data files for all subdirectories.<br> 292 * <br> 293 * Available restCommands:<br> 294 * see: <a href="https://musicbrainz.org/doc/Development/XML_Web_Service/Version_2"> 295 * https://musicbrainz.org/doc/Development/XML_Web_Service/Version_2</a><br> 296 * Example: java ca.bc.webarts.tools.musicbrainz.MusicbrainzRestRequester test <br> 297 * 298 **/ 299 public static void main(String [] args) 300 { 301 final String methodName = CLASSNAME + ": main()"; 302 int cmdStart = 0; 303 String cmdArgs = ""; 304 305 MusicbrainzRestRequester instance = null; 306 307 if (args.length>4) /* Possible User/Pass added on the commandline */ 308 { 309 if ( (args[cmdStart].equalsIgnoreCase("-u") && args[cmdStart+2].equalsIgnoreCase("-p") ) || 310 (args[cmdStart+2].equalsIgnoreCase("-u") && args[cmdStart].equalsIgnoreCase("-p") ) 311 ) 312 { 313 instance = new MusicbrainzRestRequester(DEFAULT_MUSICBRAINZ_IP, 314 (args[cmdStart].equalsIgnoreCase("-u")?args[cmdStart+1]:args[cmdStart+3]), 315 (args[cmdStart].equalsIgnoreCase("-p")?args[cmdStart+1]:args[cmdStart+3]) 316 ); 317 cmdStart += 4; 318 } 319 } 320 321 if (instance==null) 322 instance = new MusicbrainzRestRequester(); 323 324 instance.setAcceptJSON(false); 325 326 /* Simple way af parsing the args */ 327 if (args ==null || args.length<1) 328 System.out.println(getHelpMsgStr()); 329 /* *************************************** */ 330 else 331 { 332 if (args[cmdStart].equalsIgnoreCase("-xml")) 333 { 334 instance.setAcceptJSON(false); // false means get XML 335 cmdStart++; 336 } 337 if (args[cmdStart].equalsIgnoreCase("-json")) 338 { 339 instance.setAcceptJSON(true); // true means get JSON 340 cmdStart++; 341 } 342 343 if (args[cmdStart].equalsIgnoreCase("test")) 344 { 345 instance.debugOut_=false; 346 347 System.out.println("Can Connect? "+(instance.canConnect()?"Yes":"No")); 348 System.out.println("\n**************************\nLookup Barenaked Ladies - Gordon "); 349 String [] incs = {"artists"}; 350 String releaseResults = instance.lookupRelease(DEFAULT_MUSICBRAINZ_TEST_RELEASE_MRID, incs).toString(); 351 String artistResults = instance.lookupArtist(DEFAULT_MUSICBRAINZ_TEST_ARTIST_MRID).toString(); 352 String searchResults = instance.searchRelease("Barenaked Ladies", "Gordon").toString(); 353 try 354 { 355 System.out.println("\n\n"+"Release\n~~~~~~~~~~~~~~~~"); 356 System.out.println(Util.xmlToPrettyString(releaseResults, 2)); 357 nu.xom.Document releaseDoc = instance.parseXMLResponse(releaseResults); 358 System.out.println("\nRelease Date: "+instance.parseFirstReleaseDate(releaseDoc)); 359 System.out.println("\nRelease Year: "+instance.parseFirstReleaseYear(releaseDoc)); 360 361 System.out.println("\n\n"+"Artist\n~~~~~~~~~~~~~~~~"); 362 System.out.println(Util.xmlToPrettyString(artistResults, 2)); 363 nu.xom.Document artistDoc = instance.parseXMLResponse(artistResults); 364 365 System.out.println("\n\n"+"Search\n~~~~~~~~~~~~~~~~"); 366 System.out.println(Util.xmlToPrettyString(searchResults, 2)); 367 nu.xom.Document searchDoc = instance.parseXMLResponse(searchResults); 368 } 369 catch (Exception ex) 370 { 371 ex.printStackTrace(); 372 System.out.println("\nParsing error - raw results:"); 373 System.out.println(releaseResults); 374 } 375 } 376 /* *************************************** */ 377 else if (args[cmdStart].equalsIgnoreCase("searchRelease")) 378 { 379 for (int i=cmdStart+2; i<args.length; i++ ) cmdArgs+=" "+args[i]; 380 cmdArgs = cmdArgs.trim(); 381 382 String releaseResults = instance.searchRelease(args[cmdStart+1], cmdArgs).toString(); 383 try 384 { 385 System.out.println("\n\n"+"Release\n~~~~~~~~~~~~~~~~"); 386 if(debugOut_) System.out.println(Util.xmlToPrettyString(releaseResults, 2)); 387 nu.xom.Document releaseDoc = instance.parseXMLResponse(releaseResults); 388 System.out.println("\nRelease MRID: "+instance.parseSearchResultsForMRID(releaseDoc,0)); 389 System.out.println("\nRelease Date: "+instance.parseFirstReleaseDate(releaseDoc)); 390 System.out.println("\nRelease Year: "+instance.parseFirstReleaseYear(releaseDoc)); 391 392 } 393 catch (Exception ex) 394 { 395 ex.printStackTrace(); 396 System.out.println("\nParsing error - raw results:"); 397 System.out.println(releaseResults); 398 } 399 } 400 /* *************************************** */ 401 else if (args[cmdStart].equalsIgnoreCase("searchArtist")) 402 { 403 for (int i=cmdStart+1; i<args.length; i++ ) cmdArgs+=" "+args[i]; 404 cmdArgs = cmdArgs.trim(); 405 406 String artistResults = instance.searchArtist(cmdArgs).toString(); 407 try 408 { 409 System.out.println("\n\n"+"Artist\n~~~~~~~~~~~~~~~~"); 410 System.out.println(Util.xmlToPrettyString(artistResults, 2)); 411 nu.xom.Document artistDoc = instance.parseXMLResponse(artistResults); 412 413 /* use the artistDoc to find the artist with attribute ns2:score="100" */ 414 415 } 416 catch (Exception ex) 417 { 418 ex.printStackTrace(); 419 System.out.println("\nParsing error - raw results:"); 420 System.out.println(artistResults); 421 } 422 } 423 /* *************************************** */ 424 // Looks up the MRID 425 else if (args[cmdStart].equalsIgnoreCase("lookupArtist")) // expecting an MRID 426 { 427 428 String searchResults = ""; 429 try 430 { 431 instance.debugOut_=true; 432 433 instance.setAcceptJSON(false); // false means get XML 434 System.out.println("Can Connect? "+(instance.canConnect()?"Yes":"No")); 435 StringBuilder sb = instance.lookupArtist(args[cmdStart+1]); 436 if(sb!=null) 437 { 438 searchResults = sb.toString(); 439 System.out.println(Util.xmlToPrettyString(searchResults, 2)); 440 nu.xom.Document searchDoc = instance.parseXMLResponse(searchResults); 441 } 442 } 443 catch (Exception ex) 444 { 445 ex.printStackTrace(); 446 System.out.println("\nParsing error - raw results:"); 447 System.out.println(searchResults); 448 } 449 } 450 /* *************************************** */ 451 else if (args[cmdStart].equalsIgnoreCase("lookupRelease")) // expecting an MRID 452 { 453 String searchResults = ""; 454 try 455 { 456 instance.debugOut_=false; 457 458 instance.setAcceptJSON(false); // false means get XML 459 System.out.println("Can Connect? "+(instance.canConnect()?"Yes":"No")); 460 searchResults = instance.lookupRelease(args[cmdStart+1]).toString(); 461 System.out.println(Util.xmlToPrettyString(searchResults, 2)); 462 nu.xom.Document searchDoc = instance.parseXMLResponse(searchResults); 463 } 464 catch (Exception ex) 465 { 466 ex.printStackTrace(); 467 System.out.println("\nParsing error - raw results:"); 468 System.out.println(searchResults); 469 } 470 } 471 /* *************************************** */ 472 else if (args[cmdStart].equalsIgnoreCase("parseDir")) 473 { 474 System.out.println(" Parsing current dir AND creating meta-data files for all subDir Artists."); 475 instance.parseTunesDir("."); 476 } 477 /* *************************************** */ 478 else if (args[cmdStart].equalsIgnoreCase("parseArtistDir")) 479 { 480 instance.debugOut_=true; 481 482 System.out.println(" Parsing current dir AND creating meta-data files for all subDir Albums."); 483 instance.parseArtistDir("."); 484 } 485 /* *************************************** */ 486 else 487 { 488 instance.restCMD(args); 489 } 490 } 491 } // main 492 493 494 495 /** Parses the tunes dir and reads in all the artists. **/ 496 public void parseArtistDir(String artistDirPath) 497 { 498 final String methodName = CLASSNAME + ": parseArtistDir(String )"; 499 500 if(debugOut_) System.out.println(" >> "+methodName); 501 File artistDirFile = new File( artistDirPath); 502 //java.util.List<Track> pagedLovedTracks = (java.util.List<Track>)lastFmLovedTracks_.getPageResults(); 503 if(artistDirFile!=null) 504 { 505 try 506 { 507 String artName = artistDirFile.getCanonicalPath().substring(artistDirFile.getCanonicalPath().lastIndexOf("/")+1); 508 if(artName.equals("54•40") ) artName="54-40"; 509 // check if the artist dir has ANY album dirs, then add 510 File[] albumFiles = (new File(artistDirFile.getAbsolutePath())).listFiles(); 511 boolean valid = false; 512 String artNameSpaced = ""; 513 for(int i=0; !valid&&i<albumFiles.length; i++) 514 { 515 // check if there are ANY album dirs 516 if(albumFiles[i].isDirectory() 517 && albumFiles[i].canRead() 518 && albumFiles[i].listFiles().length>0 519 ) valid= true; 520 } 521 if(valid) 522 { 523 artNameSpaced = Util.capsToSpacesInString(artName); 524 artNameSpaced = Util.tokenReplace(artNameSpaced,"_"," "); 525 if(debugOut_) System.out.println(" >>"+methodName+"\n Creating a MusicbrainzArtist("+artNameSpaced+")"); 526 MusicbrainzArtist art = new MusicbrainzArtist(artNameSpaced, 527 artistDirFile.getAbsolutePath(), 528 false); // last false means DONT use cache only ie. query MB 529 530 //art.writeMetaData(); 531 art.parseAlbumDirs(); 532 } 533 } 534 catch ( Exception ex) 535 { 536 System.out.println(" *!What The Fudge (parseArtistDir()) : "+ex.getMessage()); 537 ex.printStackTrace(); 538 } 539 } 540 } 541 542 543 /** Parses the tunes dir and reads in all the artists. **/ 544 public void parseTunesDir(String tunesDirPath) 545 { 546 final String methodName = CLASSNAME + ": parseTunesDir(String )"; 547 548 if(debugOut_) System.out.println(" >>"+methodName); 549 File[] artistDirFiles = (new File( tunesDirPath)).listFiles(); 550 //java.util.List<Track> pagedLovedTracks = (java.util.List<Track>)lastFmLovedTracks_.getPageResults(); 551 if(artistDirFiles!=null) 552 { 553 Vector <MusicbrainzArtist> artists = new Vector <MusicbrainzArtist>(); 554 try 555 { 556 for(File currAristDirFile : artistDirFiles) 557 if(currAristDirFile.isDirectory() 558 && currAristDirFile.canRead() ) 559 { 560 String artName = currAristDirFile.getAbsolutePath().substring(currAristDirFile.getAbsolutePath().lastIndexOf("/")+1); 561 if(artName.equals("54•40") ) artName="54-40"; 562 // check if the artist dir has ANY album dirs, then add 563 File[] albumFiles = (new File(currAristDirFile.getAbsolutePath())).listFiles(); 564 boolean valid = false; 565 String artNameSpaced = ""; 566 try 567 { 568 for(int i=0; !valid&&i<albumFiles.length; i++) 569 { 570 // check if there are ANY album dirs 571 if(albumFiles[i].isDirectory() 572 && albumFiles[i].canRead() 573 && albumFiles[i].listFiles().length>0 574 ) valid= true; 575 } 576 if(valid) 577 { 578 artNameSpaced = Util.capsToSpacesInString(artName); 579 artNameSpaced = Util.tokenReplace(artNameSpaced,"_"," "); 580 if(debugOut_) System.out.println(" >>"+methodName+"\n Creating a MusicbrainzArtist("+artNameSpaced+")"); 581 MusicbrainzArtist art = new MusicbrainzArtist(artNameSpaced, 582 currAristDirFile.getAbsolutePath(), 583 false); // last false means DONT use cache only ie. query MB 584 585 artists.add(art); 586 //art.writeMetaData(); 587 art.parseAlbumDirs(); 588 } 589 } 590 catch ( Exception ex) 591 { 592 System.out.println(" *!What The Fudge (parseTunesDir()) : "+ex.getMessage()); 593 ex.printStackTrace(); 594 } 595 } 596 } 597 catch(Exception ex) { /* ignore error dirs */ } 598 artists.sort(MusicbrainzArtist.ArtistComparatorIgnoreCase ); 599 } 600 } 601 602 603 /** 604 * commandLine command executor method for the test Command. 605 * @param args the array of commandLine args that got passed in 606 **/ 607 protected void testCMD(String [] args) 608 { 609 final String methodName = CLASSNAME + ": testCMD(String [])"; 610 611 System.out.println("Testing MusicBrainz Rest Service: "+ "/sys"); 612 StringBuilder resp = serviceGet("/sys"); 613 System.out.println(resp.toString()); System.out.println(); 614 } 615 616 617 protected StringBuilder lookupRelease(String mrid){return lookupRelease(mrid, null);} 618 /** 619 * commandLine command executor method for the test Command. 620 * @param mrid the MusicBrainz Release ID to lookup 621 * @param incs the optional array of associated includes to add to the lookup, null to not add any extra includes 622 **/ 623 public StringBuilder lookupRelease(String mrid, String [] incs) 624 { 625 final String methodName = CLASSNAME + ": lookupRelease(String )"; 626 627 if(debugOut_) System.out.println(" MusicBrainz Rest Service: "+ "lookup a RELEASE"); 628 String inc = ""; 629 if(incs!=null && incs.length >0 && !"".equals(incs[0])) 630 { 631 int cnt = 0; 632 inc = "?inc="; 633 for (String i : incs) 634 { 635 if(cnt++>0) inc+="+"; 636 inc+=i; 637 } 638 if(debugOut_) System.out.println(" with includes="+inc); 639 } 640 StringBuilder resp = serviceGet("/release/"+mrid+inc.replace(" " ,"+")); 641 //if(debugOut_) System.out.println(resp.toString()); if(debugOut_) System.out.println(); 642 return resp; 643 } 644 645 646 public StringBuilder searchRelease(String artist, String release) 647 { 648 return searchRelease( artist, release,1); 649 } 650 651 652 /** 653 * Wraps the MusicBrainz search, specifically for a release ; example: https://musicbrainz.org/ws/2/release/?query=release:Gordon%20AND%20artist:Barenaked%20Ladies . 654 * if you want only area=Canada : ID=71bbafaa-e825-3e15-8ca9-017dcad1748b<br> 655 * try https://musicbrainz.org/ws/2/release/?query=release:Gordon%20AND%20country:CA%20AND%20artist:Barenaked+Ladies 656 * @param artist the artistName of teh release 657 * @param release the name of the release 658 * @param limit the maximum number of returned results 659 * @return the search results in MMD - MusicBrainz XML Metadata Format (https://musicbrainz.org/doc/MusicBrainz_XML_Meta_Data) 660 **/ 661 public StringBuilder searchRelease(String artist, String release, int limit) 662 { 663 final String methodName = CLASSNAME + ": searchRelease(String , String)"; 664 StringBuilder resp = null; 665 //debugOut_=true; 666 667 String limitStr="&limit="+limit; 668 669 if(debugOut_) System.out.println(" MusicBrainz Rest Service: "+ "search for a RELEASE"); 670 if(artist!=null && release!=null 671 && !"".equals(artist) && !"".equals(release) ) 672 { 673 try 674 { 675 String searchRequest = "/release/?query=release:"+ 676 URLEncoder.encode(release, "UTF-8")+ 677 "%20AND%20artist:"+ 678 URLEncoder.encode(artist, "UTF-8")+ 679 limitStr; 680 if(debugOut_) System.out.println(" searchRequest= "+searchRequest); 681 resp = serviceGet(searchRequest); 682 683 } 684 catch(java.io.UnsupportedEncodingException ueEx) 685 { 686 ueEx.printStackTrace(); 687 } 688 } 689 //if(debugOut_) System.out.println(resp.toString()); if(debugOut_) System.out.println(); 690 //debugOut_=false; 691 return resp; 692 } 693 694 695 public StringBuilder searchArtist(String artist) 696 { 697 return searchArtist( artist, 1); 698 } 699 700 701 /** 702 * Wraps the MusicBrainz search, specifically for an Artist ; example: https://musicbrainz.org/ws/2/release/?query=release:Gordon%20AND%20artist:Barenaked%20Ladies . 703 * if you want only area=Canada : ID=71bbafaa-e825-3e15-8ca9-017dcad1748b<br> 704 * try https://musicbrainz.org/ws/2/release/?query=release:Gordon%20AND%20country:CA%20AND%20artist:Barenaked+Ladies 705 * @param artist the artistName of teh release 706 * @param limit the maximum number of returned results 707 * @return the search results in MMD - MusicBrainz XML Metadata Format (https://musicbrainz.org/doc/MusicBrainz_XML_Meta_Data) 708 **/ 709 public StringBuilder searchArtist(String artist, int limit) 710 { 711 final String methodName = CLASSNAME + ": searchArtist("+artist+")"; 712 StringBuilder resp = null; 713 714 String limitStr="&limit="+limit; 715 716 if(debugOut_) System.out.println(" MusicBrainz Rest Service: "+ "search for an ARTIST"); 717 if(artist!=null 718 && !"".equals(artist) ) 719 { 720 try 721 { 722 String searchRequest = "/artist/?query=artist:"+ 723 URLEncoder.encode(artist, "UTF-8")+ 724 limitStr; 725 if(debugOut_) System.out.println(" searchRequest= "+searchRequest); 726 resp = serviceGet(searchRequest); 727 728 } 729 catch(java.io.UnsupportedEncodingException ueEx) 730 { 731 ueEx.printStackTrace(); 732 } 733 } 734 //if(debugOut_) System.out.println(resp.toString()); if(debugOut_) System.out.println(); 735 //debugOut_=false; 736 return resp; 737 } 738 739 740 protected StringBuilder lookupArtist(String mrid){return lookupArtist(mrid, null);} 741 /** 742 * commandLine command executor method for the test Command. 743 * @param mrid the MusicBrainz Release ID to lookup 744 * @param incs the optional array of associated includes to add to the lookup, null to not add any extra includes 745 **/ 746 public StringBuilder lookupArtist(String mrid, String [] incs) 747 { 748 final String methodName = CLASSNAME + ": lookupArtist(String )"; 749 750 if(debugOut_) System.out.println(" MusicBrainz Rest Service: "+ "lookup an ARTIST"); 751 String inc = ""; 752 if(incs!=null && incs.length >0 && !"".equals(incs[0])) 753 { 754 int cnt = 0; 755 inc = "?inc="; 756 for (String i : incs) 757 { 758 if(cnt++>0) inc+="+"; 759 inc+=i; 760 } 761 } 762 StringBuilder resp = serviceGet("/artist/"+mrid+inc.replace(" " ,"+")); 763 //if(debugOut_) System.out.println(resp.toString()); if(debugOut_) System.out.println(); 764 return resp; 765 } 766 767 768 public nu.xom.Document parseXMLResponse(String respXmlStr) 769 { 770 //String methodName = className_+"."+Util.getCurrentMethodName(); 771 //log_.startMethod(methodName); 772 if(debugOut_) System.out.println(" parseXMLResponse(String) "); 773 774 nu.xom.Document respDoc = null; 775 nu.xom.Element rootElem = null; 776 try 777 { 778 respDoc = xmlBuilder_.build(respXmlStr,null); 779 } 780 catch (nu.xom.ParsingException xomEx) 781 { 782 xomEx.printStackTrace(); 783 System.out.println("MAJor Error: parsing respXmlStr"); 784 System.out.println(respXmlStr); 785 } 786 catch (IOException ioEx) 787 { 788 ioEx.printStackTrace(); 789 System.out.println("MAJor Error: IOException respXmlStr"); 790 System.out.println(respXmlStr); 791 } 792 return respDoc; 793 } 794 795 796 public java.util.Date parseFirstReleaseDate(nu.xom.Document respDoc){return parseReleaseDate(respDoc, 0);} 797 public java.util.Date parseReleaseDate(nu.xom.Document respDoc, int releaseIndex) 798 { 799 java.util.Date retVal = null; 800 nu.xom.Element rootElem = null; 801 nu.xom.Element dateXpathElem = null; 802 String dateStr = ""; 803 804 if(debugOut_) System.out.println(" > parseReleaseDate not null?"+(respDoc!=null)); 805 if (respDoc!=null) 806 { 807 rootElem = respDoc.getRootElement(); 808 809 nu.xom.Elements releaseListElems = parseReleaseListElems(respDoc); 810 nu.xom.Element releaseListElem = null; 811 nu.xom.Element dateElem = null; 812 int numReleases = 0; 813 if(debugOut_) System.out.println(" > releaseListElems not null?"+(releaseListElems!=null)); 814 if(debugOut_) System.out.println( " > Searching For Index "+releaseIndex +" of " +releaseListElems.size()); 815 for (int i=0; i< releaseListElems.size(); i++) 816 { 817 releaseListElem = releaseListElems.get(i); //release-event 818 if(releaseListElem.getLocalName().equalsIgnoreCase("date") ) 819 { 820 dateElem = releaseListElem; 821 } 822 } 823 if (dateElem!=null) 824 { 825 if(debugOut_) System.out.print(" ."); 826 dateStr = dateElem.getValue(); 827 if(debugOut_) System.out.print(" "+dateStr); 828 if(debugOut_) System.out.println(" "+Integer.parseInt(dateStr.substring(0,4))+" "+ 829 Integer.parseInt(dateStr.substring(5,7))+" "+ 830 Integer.parseInt(dateStr.substring(8,10))); 831 if (dateElem!=null ) 832 { 833 if(dateStr.length()>4) 834 retVal = new java.util.Date(Integer.parseInt(dateStr.substring(0,4))-1900, 835 Integer.parseInt(dateStr.substring(5,7)), 836 Integer.parseInt(dateStr.substring(8,10))); 837 else if(dateStr.length()>0) 838 retVal = new java.util.Date(Integer.parseInt(dateStr.substring(0,4))-1900, 839 1,1); 840 } 841 } 842 else 843 { 844 System.out.println(" ERROR> parseReleaseDate numReleases = "+numReleases); 845 System.out.println(" releaseEventElems.size = "+releaseListElems.size()); 846 } 847 } 848 if(debugOut_) System.out.println(); 849 return retVal; 850 } 851 852 853 public int parseFirstReleaseYear(nu.xom.Document respDoc){return parseReleaseYear(respDoc, 0);} 854 public int parseReleaseYear(nu.xom.Document respDoc, int releaseIndex) 855 { 856 int retVal = 0; 857 858 java.util.Date relDate = parseReleaseDate(respDoc, releaseIndex); 859 if (relDate!=null) retVal = Integer.parseInt(right(relDate.toString().trim(),4)); // dow mon dd hh:mm:ss zzz yyyy 860 if(debugOut_) System.out.println(retVal); 861 return retVal; 862 } 863 864 865 public String right(String value, int length) 866 { 867 // To get right characters from a string, change the begin index. 868 return value.substring(value.length() - length); 869 } 870 871 872 public nu.xom.Elements parseReleaseEventElems(nu.xom.Document respDoc) 873 { 874 nu.xom.Elements retVal = null; 875 nu.xom.Element rootElem = null; 876 877 if(debugOut_) System.out.println(" > parseReleaseEventElems not null?"+(respDoc!=null)); 878 if (respDoc!=null) 879 { 880 rootElem = respDoc.getRootElement(); 881 // load the data 882 if (rootElem != null && rootElem instanceof Element && rootElem.getLocalName().equals("metadata")) 883 { 884 if(debugOut_) System.out.print(" ."); 885 nu.xom.Elements releaseElems = rootElem.getChildElements(); 886 nu.xom.Element releaseElem = releaseElems.get(0); 887 if (releaseElem!=null ) 888 { 889 if(debugOut_) System.out.print(" ."); 890 nu.xom.Elements releaseEventListElems = releaseElem.getChildElements(); 891 nu.xom.Element releaseEventListElem = null; 892 for (int i=0; i< releaseEventListElems.size(); i++) 893 { 894 releaseEventListElem = releaseEventListElems.get(i); //release-event-list 895 if(releaseEventListElem.getLocalName().equalsIgnoreCase("release-event-list")) 896 i=releaseEventListElems.size(); 897 //releaseEventListElem = releaseElem.getFirstChildElement("release-event-list"); 898 } 899 if (releaseEventListElem!=null ) 900 { 901 if(debugOut_) System.out.print(" ." ); 902 retVal = releaseEventListElem.getChildElements(); 903 } 904 } 905 } 906 } 907 return retVal; 908 } 909 910 911 public nu.xom.Elements parseReleaseListElems(nu.xom.Document respDoc) 912 { 913 nu.xom.Elements retVal = null; 914 nu.xom.Element rootElem = null; 915 916 if(debugOut_) System.out.println(" > parseReleaseListElems not null?"+(respDoc!=null)); 917 if (respDoc!=null) 918 { 919 rootElem = respDoc.getRootElement(); 920 if (rootElem != null && rootElem instanceof Element && rootElem.getLocalName().equals("metadata")) 921 { 922 if(debugOut_) System.out.print(" ."); 923 nu.xom.Elements releaseElems = rootElem.getChildElements(); 924 nu.xom.Element releaseElem = releaseElems.get(0); 925 if (releaseElem!=null ) 926 { 927 if(debugOut_) System.out.print(" ."); 928 nu.xom.Elements releaseEventListElems = releaseElem.getChildElements(); 929 nu.xom.Element releaseEventListElem = null; 930 for (int i=0; i< releaseEventListElems.size(); i++) 931 { 932 releaseEventListElem = releaseEventListElems.get(i); //release-list 933 if(releaseEventListElem.getLocalName().equalsIgnoreCase("release-list")) 934 i=releaseEventListElems.size(); 935 //releaseEventListElem = releaseElem.getFirstChildElement("release-event-list"); 936 } 937 if (releaseEventListElem!=null ) 938 { 939 if(debugOut_) System.out.print(" ." ); 940 retVal = releaseEventListElem.getChildElements(); 941 } 942 } 943 } 944 } 945 return retVal; 946 } 947 948 949 public nu.xom.Element parseFirstReleaseEventElem(nu.xom.Document respDoc){return parseReleaseEventElem(respDoc, 0);} 950 public nu.xom.Element parseReleaseEventElem(nu.xom.Document respDoc, int releaseIndex) 951 { 952 nu.xom.Element retVal = null; 953 nu.xom.Element rootElem = null; 954 955 if(debugOut_) System.out.println(" > parseReleaseEventElem not null?"+(respDoc!=null)); 956 if (respDoc!=null) 957 { 958 rootElem = respDoc.getRootElement(); 959 960 nu.xom.Elements releaseEventElems = parseReleaseEventElems(respDoc); 961 nu.xom.Element releaseEventElem = null; //("release-event"); 962 int numReleases = 0; 963 for (int i=0; i< releaseEventElems.size(); i++) 964 { 965 releaseEventElem = releaseEventElems.get(i); //release-event 966 if(releaseEventElem.getLocalName().equalsIgnoreCase("release-event") ) 967 { 968 if(numReleases==releaseIndex) 969 { 970 i=releaseEventElems.size(); 971 retVal = releaseEventElem; 972 } 973 numReleases++; 974 } 975 } 976 } 977 978 return retVal; 979 } 980 981 982 /** parses through a returned responseResult doc and looks for the 1st "release" element. 983 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2</a> 984 * 985 * @param respDoc is the MB responseResult XML document from a release query request 986 * @return the release Element located at index releaseIndex 987 **/ 988 public nu.xom.Element parseFirstReleaseListElem(nu.xom.Document respDoc){return parseReleaseListElem(respDoc, 0);} 989 990 991 992 /** parses through a returned responseResult doc and looks for the releaseIndex "release" element. 993 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2</a> 994 * 995 * @param respDoc is the MB responseResult XML document from a release query request 996 * @param releaseIndex is the zero based release element to return 997 * @return the release Element located at index releaseIndex 998 **/ 999 public nu.xom.Element parseReleaseListElem(nu.xom.Document respDoc, int releaseIndex) 1000 { 1001 nu.xom.Element retVal = null; 1002 nu.xom.Element rootElem = null; 1003 1004 if(debugOut_) System.out.println(" > parseReleaseListElem not null?"+(respDoc!=null)); 1005 if (respDoc!=null) 1006 { 1007 rootElem = respDoc.getRootElement(); 1008 1009 nu.xom.Elements releaseListElems = parseReleaseListElems(respDoc); 1010 nu.xom.Element releaseListElem = null; //("release-event"); 1011 int numReleases = 0; 1012 for (int i=0; i< releaseListElems.size(); i++) 1013 { 1014 releaseListElem = releaseListElems.get(i); //release-event 1015 if(releaseListElem.getLocalName().equalsIgnoreCase("release") ) 1016 { 1017 if(numReleases==releaseIndex) 1018 { 1019 i=releaseListElems.size(); 1020 retVal = releaseListElem; 1021 } 1022 numReleases++; 1023 } 1024 } 1025 } 1026 1027 return retVal; 1028 } 1029 1030 1031 public int parseSearchResultsForReleaseYear(nu.xom.Document respDoc) 1032 { 1033 int retVal = 1900; 1034 nu.xom.Element rootElem = null; 1035 1036 if(debugOut_) System.out.println(" > parseReleaseEventElems not null?"+(respDoc!=null)); 1037 if (respDoc!=null) 1038 { 1039 rootElem = respDoc.getRootElement(); 1040 // load the data 1041 if (rootElem != null && rootElem instanceof Element && rootElem.getLocalName().equals("metadata")) 1042 { 1043 if(debugOut_) System.out.print(" ."); 1044 nu.xom.Elements releaseListElems = rootElem.getChildElements(); 1045 nu.xom.Element releaseListElem = releaseListElems.get(0); 1046 if (releaseListElem!=null ) 1047 { 1048 if(debugOut_) System.out.print(" ."); 1049 nu.xom.Elements releaseElems = releaseListElem.getChildElements(); 1050 nu.xom.Element releaseElem = null; 1051 //for (int i=0; i< releaseElems.size(); i++) 1052 //{ 1053 releaseElem = releaseElems.get(0); //release-event-list 1054 if (releaseElem!=null ) 1055 { 1056 if(debugOut_) System.out.print(" ."); 1057 if(debugOut_) System.out.print(" ("+releaseElem.getLocalName()+")"); 1058 nu.xom.Elements releaseSubElems = releaseElem.getChildElements(); 1059 nu.xom.Element dateElem = null; 1060 boolean foundIt = false; 1061 for (int i=0; i< releaseSubElems.size(); i++) 1062 { 1063 dateElem = releaseSubElems.get(i); 1064 if(dateElem.getLocalName().equalsIgnoreCase("date")) 1065 { 1066 foundIt = true; 1067 i=releaseSubElems.size(); 1068 } 1069 } 1070 if (foundIt) 1071 { 1072 if(debugOut_) System.out.print(" ." ); 1073 String dateStr = dateElem.getValue(); 1074 if(debugOut_) System.out.print(" "+dateStr); 1075 retVal = Integer.parseInt(dateStr.substring(0,4)); 1076 } 1077 } 1078 } 1079 } 1080 } 1081 if(debugOut_) System.out.println("\n >>>>>>>>>>>>>>>>>>>>>>>>>>"); 1082 return retVal; 1083 } 1084 1085 1086 /** loops through a returned responseResult doc and looks for the 1st result. 1087 * @return null if not found, else it returns the release element 1088 **/ 1089 public nu.xom.Element parseSearchResultsForFirstReleaseElem(nu.xom.Document respDoc) 1090 { 1091 return parseSearchResultsForReleaseElem(respDoc, 0); 1092 } 1093 1094 1095 /** loops through a returned responseResult doc and looks for the 'releaseIndex' result. 1096 * responses from a release query have multiple releases in them. 1097 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Release">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Release</a> 1098 * 1099 * @param respDoc is the MB responseResult XML document from a release query request 1100 * @param releaseIndex is the zero based release element to return 1101 * @return the relese located at index releaseIndex 1102 **/ 1103 public nu.xom.Element parseSearchResultsForReleaseElem(nu.xom.Document respDoc, int releaseIndex) 1104 { 1105 nu.xom.Element retVal = null; 1106 nu.xom.Element rootElem = null; 1107 1108 if(debugOut_) System.out.println(" > parseSearchResultsForReleaseElem["+releaseIndex+"] not null?"+(respDoc!=null)); 1109 if (respDoc!=null) 1110 { 1111 rootElem = respDoc.getRootElement(); 1112 // load the data 1113 if (rootElem != null && rootElem instanceof Element && rootElem.getLocalName().equals("metadata")) 1114 { 1115 if(debugOut_) System.out.print(" ."); 1116 try 1117 { 1118 nu.xom.Elements releaseListElems = rootElem.getChildElements(); 1119 nu.xom.Element releaseListElem = releaseListElems.get(0); 1120 if (releaseListElem!=null ) 1121 { 1122 if(debugOut_) System.out.print(" ."); 1123 nu.xom.Elements releaseElems = releaseListElem.getChildElements(); 1124 nu.xom.Element releaseElem = null; 1125 releaseElem = releaseElems.get(releaseIndex); //release 1126 1127 if(debugOut_) System.out.print(" . found: "+releaseElem.getLocalName()); 1128 retVal = releaseElem; 1129 } 1130 } 1131 catch (Exception ex) 1132 { 1133 System.out.print(" NOT found: ["+releaseIndex+"]"); 1134 retVal = null; 1135 ex.printStackTrace(); 1136 } 1137 } 1138 } 1139 if(debugOut_) System.out.println("\n >>>>>>>>>>>>>>>>>>>>>>>>>>"); 1140 return retVal; 1141 } 1142 1143 1144 /** 1145 * Parses through the Release search results doc, gets the 1st release 1146 * and looks for the status subElement. 1147 * 1148 * @return null if not found, else t returns the elementName's value 1149 **/ 1150 public String parseSearchResultsForFirstReleaseStatus(nu.xom.Document respDoc) 1151 { 1152 return parseSearchResultsForReleaseStatus(respDoc, 0); 1153 } 1154 1155 1156 /** 1157 * Parses through the Release search results doc, gets the 'releaseIndex' release element 1158 * and looks for the status subElement. 1159 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search#Release">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search#Release</a> 1160 * 1161 * @param respDoc is the MB responseResult XML document from a release query request 1162 * @param releaseIndex is the zero based release element' status sub-element to return 1163 * @return null if not found, else t returns the elementName's value 1164 **/ 1165 public String parseSearchResultsForReleaseStatus(nu.xom.Document respDoc, int releaseIndex) 1166 { 1167 return parseSearchResultsForReleaseSubElement(respDoc, releaseIndex, "status"); 1168 } 1169 1170 1171 /** 1172 * Parses through the Release search results doc, gets the 'releaseIndex' release element 1173 * and looks for its MRID. 1174 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search</a> 1175 * 1176 * @param respDoc is the MB responseResult XML document from a release query request 1177 * @param releaseIndex is the zero based release to return 1178 * @return null if not found, else t returns the elementName's value 1179 **/ 1180 public String parseSearchResultsForMRID(nu.xom.Document respDoc, int releaseIndex) 1181 { 1182 return parseSearchResultsForReleaseElem(respDoc, releaseIndex).getAttributeValue("id"); 1183 } 1184 1185 1186 /** 1187 * Parses through the Release search results doc, gets the 1st release element 1188 * and looks for the subElement named elemntName passed into this method. 1189 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search</a> 1190 * 1191 * @return null if not found, else t returns the elementName's value 1192 **/ 1193 public String parseSearchResultsForFirstReleaseSubElement(nu.xom.Document respDoc, String elementName) 1194 { 1195 return parseSearchResultsForReleaseSubElement(respDoc, 0, elementName); 1196 } 1197 1198 1199 /** 1200 * Parses through the search results doc, gets the releaseIndex specified release 1201 * and looks for the subElement named elemntName passed into this method. 1202 * The request looks like this...<br> 1203 * <a href="http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake">http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake</a><br> 1204 * or this... <a href="http://musicbrainz.org/ws/2/release/?query=country:US">http://musicbrainz.org/ws/2/release/?query=release:Schneider%20AND%20Shake%20AND%20country:US</a><br> 1205 * or this... <a href="http://musicbrainz.org/ws/2/release/?query=release:X%20AND%20country:CA%20AND%20artist:Inxs">http://musicbrainz.org/ws/2/release/?query=release:X%20AND%20country:CA%20AND%20artist:Inxs</a><br> 1206 *<br> 1207 * see <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search#Release">https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search#Release</a> 1208 * 1209 * <ul><li>title</li><li>status</li><li>packaging</li><li>text-representation</li><li>artist-credit</li><li>release-group</li> 1210 * <li>date</li><li>country</li><li>release-event-list</li><li>barcode</li><li>label-info-list</li><li>medium-list</li> 1211 * <li> more at <a href="https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2/Search#Release"> Musicbrainz search relese page</a></li> 1212 * </ul> 1213 * 1214 * @param respDoc is the MB responseResult XML document from a release query request 1215 * @param releaseIndex is the zero based release to return 1216 * @param elementName the sub-element name to look for 1217 * @return null if not found, else t returns the elementName's value 1218 **/ 1219 public String parseSearchResultsForReleaseSubElement(nu.xom.Document respDoc, int releaseIndex, String elementName) 1220 { 1221 String retVal = null; 1222 nu.xom.Element rootElem = null; 1223 1224 if(debugOut_) System.out.println(" > parseSearchResultsForReleaseSubElement not null?"+(respDoc!=null)); 1225 if (respDoc!=null) 1226 { 1227 rootElem = respDoc.getRootElement(); 1228 // load the data 1229 if (rootElem != null && rootElem instanceof Element && rootElem.getLocalName().equals("metadata")) 1230 { 1231 if(debugOut_) System.out.print(" ."); 1232 nu.xom.Elements releaseListElems = rootElem.getChildElements(); 1233 nu.xom.Element releaseListElem = releaseListElems.get(0); 1234 if (releaseListElem!=null ) 1235 { 1236 if(debugOut_) System.out.print(" ."); 1237 nu.xom.Elements releaseElems = releaseListElem.getChildElements(); 1238 nu.xom.Element releaseElem = null; 1239 //for (int i=0; i< releaseElems.size(); i++) 1240 //{ 1241 releaseElem = releaseElems.get(releaseIndex); //release-event-list 1242 if (releaseElem!=null ) 1243 { 1244 if(debugOut_) System.out.print(" ."); 1245 if(debugOut_) System.out.print(" ( "+releaseElem.getLocalName()); 1246 nu.xom.Elements releaseSubElems = releaseElem.getChildElements(); 1247 nu.xom.Element subElem = null; 1248 boolean foundIt = false; 1249 for (int i=0; i< releaseSubElems.size(); i++) 1250 { 1251 subElem = releaseSubElems.get(i); 1252 if(subElem.getLocalName().equalsIgnoreCase(elementName)) 1253 { 1254 foundIt = true; 1255 i=releaseSubElems.size(); 1256 } 1257 } 1258 if (foundIt) 1259 { 1260 if(debugOut_) System.out.print("/"+elementName+" ) - " ); 1261 String elemValueStr = subElem.getValue(); 1262 if(debugOut_) System.out.print(" "+elemValueStr); 1263 retVal = elemValueStr; 1264 } 1265 } 1266 } 1267 } 1268 } 1269 if(debugOut_) System.out.println("\n >>>>>>>>>>>>>>>>>>>>>>>>>>"); 1270 return retVal; 1271 } 1272 1273 1274 /** 1275 * commandLine command executor method for the default rest Command. 1276 * It treats each arg as a part of a single rest command and passes it along to the ISY. 1277 * @param args the array of commandLine args that got passed in 1278 **/ 1279 protected void restCMD(String [] args) 1280 { 1281 final String methodName = CLASSNAME + ": restCMD(String [])"; 1282 // Parse the command 1283 String allcommands = args[0]; 1284 for (int i=1;i< args.length;i++) allcommands+=" "+args[i]; 1285 if (debugOut_) System.out.print("Sending MusicBrainz Rest Service: "+allcommands); 1286 String passedCommand = (allcommands.startsWith(restUrlPath_+"/")?allcommands.substring(restUrlPath_.length()):allcommands); 1287 if(debugOut_) System.out.println(" ("+passedCommand+")"); 1288 passedCommand = (passedCommand.startsWith("/")?passedCommand:"/"+passedCommand); 1289 StringBuilder resp = serviceGet(passedCommand); 1290 if (resp!=null) 1291 { 1292 System.out.println(responseIndenter(resp).toString()); 1293 System.out.println(); 1294 } 1295 else 1296 { 1297 System.out.println("Response Error"); 1298 System.out.println(); 1299 } 1300 1301 } 1302 1303 1304 /** 1305 * Template method for future commandLine command executor methods. 1306 * @param args the array of commandLine args that got passed in 1307 **/ 1308 protected void templateCMD(String [] args) 1309 { 1310 final String methodName = CLASSNAME + ": testCMD(String [])"; 1311 1312 } 1313 1314 1315 /** gets the help as a String. 1316 * @return the helpMsg in String form 1317 **/ 1318 protected static String getHelpMsgStr() {return getHelpMsg().toString();} 1319 1320 1321 /** Makes the JSON string pretty with indenting. **/ 1322 public static String prettyJson(String jsonStr) 1323 { 1324 String retVal = jsonStr; 1325 retVal = retVal.replace("[", " [\n"); 1326 retVal = retVal.replace("]", " ]" + SYSTEM_LINE_SEPERATOR); 1327 retVal = retVal.replace("]\n\"", " ]\"" + SYSTEM_LINE_SEPERATOR); 1328 retVal = retVal.replace("{", " {" + SYSTEM_LINE_SEPERATOR + " "); 1329 retVal = retVal.replace("}", "}" + SYSTEM_LINE_SEPERATOR); 1330 retVal = retVal.replace(",", "," + SYSTEM_LINE_SEPERATOR + " "); 1331 retVal = retVal.replace("}" + SYSTEM_LINE_SEPERATOR + "," + SYSTEM_LINE_SEPERATOR, " }," + SYSTEM_LINE_SEPERATOR); 1332 retVal = retVal.replace("[\n", " [ "); 1333 retVal = retVal.replace(" {", " {"); 1334 retVal = retVal.replace("[ {", "[\n {"); 1335 retVal = retVal.replace("\n}", "\n }"); 1336 return retVal; 1337 } 1338 1339 1340 1341 /** initializes and gets the helpMsg_ 1342 class var. 1343 * @return the class var helpMsg_ 1344 **/ 1345 protected static StringBuilder getHelpMsg() 1346 { 1347 helpMsg_ = new StringBuilder(SYSTEM_LINE_SEPERATOR); 1348 helpMsg_.append("--- WebARTS "+CLASSNAME+" Class -----------------------------------------------------"); 1349 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1350 helpMsg_.append("--- + $Revision: 1219 $ $Date: 2020-03-02 22:12:45 -0800 (Fri, 02 Mar 2020) $ ---"); 1351 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1352 helpMsg_.append("-------------------------------------------------------------------------------"); 1353 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1354 helpMsg_.append("WebARTS ca.bc.webarts.tools.musicbrainz.MusicbrainzRestRequester Class"); 1355 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1356 helpMsg_.append("SYNTAX:"); 1357 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1358 helpMsg_.append(" java "); 1359 helpMsg_.append(CLASSNAME); 1360 helpMsg_.append(" [-xml or -json]"); 1361 helpMsg_.append(" [-u MBuserid -p passwd]"); 1362 helpMsg_.append(" command or {restCommand}"); 1363 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1364 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1365 helpMsg_.append("Available commands:"); 1366 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1367 helpMsg_.append(" test"); 1368 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1369 helpMsg_.append(" runs a few default test commands"); 1370 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1371 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1372 helpMsg_.append(" parseDir"); 1373 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1374 helpMsg_.append(" Uses current dir as starting point and"); 1375 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1376 helpMsg_.append(" Creates MusicBrainz Meta-data files for all Artist subdirectories."); 1377 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1378 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1379 helpMsg_.append(" parseArtistDir"); 1380 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1381 helpMsg_.append(" Uses current dir as starting point and"); 1382 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1383 helpMsg_.append(" Creates MusicBrainz Meta-data files for all Album subdirectories."); 1384 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1385 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1386 helpMsg_.append(" searchArtist ArtistName"); 1387 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1388 helpMsg_.append(" duh"); 1389 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1390 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1391 helpMsg_.append(" searchRelease \"ArtistName\" ReleaseName"); 1392 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1393 helpMsg_.append(" duh"); 1394 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1395 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1396 helpMsg_.append(" lookupRelease MBID"); 1397 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1398 helpMsg_.append(" looks-up the release with Musicbrain ID = MBID"); 1399 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1400 helpMsg_.append(" example: lookupRelease "+DEFAULT_MUSICBRAINZ_TEST_RELEASE_MRID); 1401 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1402 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1403 helpMsg_.append(" lookupArtist MBID"); 1404 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1405 helpMsg_.append(" looks-up the release with Musicbrain ID = MBID"); 1406 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1407 helpMsg_.append(" example: lookupArtist "+DEFAULT_MUSICBRAINZ_TEST_ARTIST_MRID); 1408 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1409 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1410 helpMsg_.append("Available restCommands:"); 1411 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1412 helpMsg_.append(" see: https://musicbrainz.org/doc/Development/XML_Web_Service/Version_2"); 1413 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1414 helpMsg_.append(" Example: java ca.bc.webarts.tools.musicbrainz.MusicbrainzRestRequester test "); 1415 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1416 helpMsg_.append("---------------------------------------------------------"); 1417 helpMsg_.append("----------------------"); 1418 helpMsg_.append(SYSTEM_LINE_SEPERATOR); 1419 1420 return helpMsg_; 1421 } 1422 1423} // MusicbrainzRestRequester