001/*
002 *
003 *  $Revision: 1329 $
004 *  $Date: 2020-04-28 18:54:54 -0700 (Tue, 28 Apr 2020) $
005 *  $URL: svn://fred.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/widgets/tunes/MusicMakerTunesHelper.java $
006 *
007 *  Written by Tom Gutwin - WebARTS Design.
008 *  http://www.webarts.bc.ca
009 *  Copyright (C) 2020 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.Util;
028import ca.bc.webarts.tools.JOrbisComment;
029import ca.bc.webarts.tools.MusicBrainzRestRequester;
030
031import java.io.File;
032import java.text.SimpleDateFormat;
033import java.util.Date;
034import java.util.ArrayList;
035import java.util.Calendar;
036import java.util.Collections;
037import java.util.HashMap;
038import java.util.Iterator;
039import java.util.Locale;
040import java.util.StringTokenizer ;
041import java.util.Vector;
042import java.text.NumberFormat;
043import javax.servlet.http.HttpSession;
044
045import javax.json.*;
046import javax.json.stream.JsonGenerator;
047import javax.json.stream.JsonParser;
048
049import org.apache.commons.codec.DecoderException;
050import org.apache.commons.codec.binary.Hex;
051
052import com.google.gson.Gson;
053import com.google.gson.GsonBuilder;
054import com.google.gson.JsonArray;
055import com.google.gson.JsonObject;
056import com.google.gson.JsonPrimitive;
057
058/**
059 *  A helper class for the WebARTS MusicMaker (from AdaFruit) Tunes Web Application. It performs pre-processing
060 *  of dirctories and adds {@link  DirFileRef metaData JSON files} and html files to
061 * annotate all the directories. It uses the Tunes Package {@link  Artist Artist}, {@link  Album Album}, {@link  Song Song} classes to deserialize the files and directory structures.
062 *
063 * @author    TGutwin
064 */
065public class MusicMakerTunesHelper
066{
067  /**  A holder for this clients System File Separator.  */
068  public final static String SYSTEM_FILE_SEPERATOR = java.io.File.separator;
069
070  /**  A holder for this clients System line termination separator.  */
071  public final static String SYSTEM_LINE_SEPERATOR =
072                                           System.getProperty("line.separator");
073  public final static String DEFAULT_COLUMN_DELIMITOR = "|";
074  public final static String DEFAULT_MUSICMAKER_IP = "10.0.0.98";
075
076  private String columnDelimitor = DEFAULT_COLUMN_DELIMITOR;
077  private String musicMakerIP_ = DEFAULT_MUSICMAKER_IP;
078  private String tunesNasRootPath_ = "/volume1/snd/";
079  private String tunesFredRootPath_ = "/mnt/nas/snd/";
080  private String tunesRootPath_ = tunesNasRootPath_;
081  private static String tunesSubPath_ = "ogg";
082  private static String imagesSubPath_ = "images";
083  private static String metadataFilename_ = "MetaData.json";
084
085  /**  The users pwd ditrectory.  */
086  public static String USERDIR = System.getProperty("user.dir");
087  public static boolean testing_ = false;
088  public static boolean toShorts_ = false;
089  public static boolean toLongs_ = false;
090  public static boolean albumHtml_ = false;
091  public static boolean verboseOut = false;
092  public static boolean debug_info_ = false;
093  public static boolean debug_dir_ = true;
094  public static boolean debug_song_ = true;
095  public static boolean debug_all_ = false;
096
097  /** The file extension (type) to load **/
098  public String FILETYPE = "ogg";
099  public String fileType = FILETYPE;
100
101  public File tunesRootDirMetaFile_ = null;
102
103  public int numSndDirs_ = 0;
104  public File[] sndDirFiles_ =null;
105  public Vector<File> songDuds = new Vector();
106  public short numArt_ = 0;
107  public short numAlb_ = 0;
108  public short numSongs_ = 0;
109
110  public Vector <Artist> artists_ = new Vector <Artist>();
111
112  /** The 1 digit HEX char/byte Reference KEY for this root sub-dir .
113    * Example 1. <br>
114    * Eachsub-dir (ogg, mp3, flac etc.) should have a unique key based on the parsing of the root directory. It is created each time the roor directory is parsed.
115    * It is based on an alpha nemeric sorted list of Full (non hashed) spaceRemoved DirNames. (ie. VelvetRevolver )
116    **/
117  private char[] refKEY_ = {'0'};
118
119
120    /**  Constructor for the MusicMakerTunesHelper object. */
121  public MusicMakerTunesHelper()
122  {
123    System.out.println("[ca.bc.webarts.widgets.tunes > MusicMakerTunesHelper()] " +
124      (new java.util.Date()).toString());
125  }// -- Constructor
126
127
128  /**  Constructor for the TunesHelper object to allow custom root path, but uses the default context = 'tunes'. */
129  public MusicMakerTunesHelper(String tunesRootPath )
130  {
131    System.out.println("[ca.bc.webarts.widgets.tunes > MusicMakerTunesHelper("+tunesRootPath+")] " +
132      (new java.util.Date()).toString());
133
134    tunesRootPath_ = tunesRootPath;
135    tunesRootDirMetaFile_ = new File(tunesRootPath_+SYSTEM_FILE_SEPERATOR+metadataFilename_);
136  }// -- Constructor
137
138
139  /** Main **/
140  public static void main (String [] args)
141  {
142    boolean topDirIsArtistDir = false;
143    boolean reParseAllDirs = false;
144    int cmdStart = 0;
145    String cmdArgs = "";
146    String topDirFilename = "";
147
148    if (args.length >0)
149    {
150      if (args[0].equalsIgnoreCase("-testing")) { testing_ = true; cmdStart++;}
151      if (args[0].equalsIgnoreCase("-toShorts")) {toShorts_ = true; cmdStart++;}
152      if (args[0].equalsIgnoreCase("-toLongs")) {toLongs_ = true; cmdStart++;}
153      if (args[0].equalsIgnoreCase("-albumHtml")) {albumHtml_ = true; cmdStart++;}
154      if (args.length >1 && args[1].equalsIgnoreCase("-testing")) { testing_ = true; cmdStart++;}
155      if (args.length >1 && args[1].equalsIgnoreCase("-toShorts")) {toShorts_ = true; toLongs_ = false;cmdStart++;}
156      if (args.length >1 && args[1].equalsIgnoreCase("-toLongs"))  {toLongs_ = true; toShorts_ = false;cmdStart++;}
157      if (args.length >1 && args[1].equalsIgnoreCase("-albumHtml"))  {albumHtml_ = true; cmdStart++;}
158
159      if (testing_) System.out.println(" TESTING ONLY ");
160
161      if (toShorts_ || toLongs_)
162      {
163        if (args.length >1)
164        {
165          topDirFilename = args[cmdStart];  // args[args.length-1];
166          MusicMakerTunesHelper instance = new MusicMakerTunesHelper(topDirFilename);
167
168          System.out.println(" Renaming "+topDirFilename+" to "+(toShorts_?"SHort":"LONG")+" Filenames ");
169          //File topDirMetaFile = new File(topDirFilename+SYSTEM_FILE_SEPERATOR+metadataFilename_);
170
171          if ( reParseAllDirs || instance.tunesRootDirMetaFile_ == null ||  !instance.tunesRootDirMetaFile_.canRead() )
172          {
173            // ONLY create when DirState is LONG
174            instance.createMetadataFiles();
175          }
176
177          if(toShorts_)
178          {
179            instance.renameToShorts(topDirFilename, "");
180            instance.writeArtistAlbumHtmlFiles(true);
181          }
182          else
183          {
184            instance.renameToLongs(topDirFilename, "");
185            instance.writeArtistAlbumHtmlFiles(false);
186          }
187        }
188        else
189          System.out.println(" ERROR: You gotta give me a directoryPath to start in.");
190      }
191      else if(args[0].equalsIgnoreCase("-clean"))
192      {
193        if(args.length >1 )
194        {
195          MusicMakerTunesHelper instance = new MusicMakerTunesHelper(args[1]);
196          instance.cleanDir(args[1]);
197        }
198        else System.out.println(" Error on commandline:  You gotta provide a directoryPath to clean.");
199
200      }
201      else if(albumHtml_)
202      {
203        System.out.println(" Create Album HTML Files only");
204        topDirFilename = args[cmdStart];  // args[args.length-1];
205        MusicMakerTunesHelper instance = new MusicMakerTunesHelper(topDirFilename);
206            String jsonStr = Util.readFileToString(instance.tunesRootPath_+SYSTEM_FILE_SEPERATOR+metadataFilename_);
207            TopSndDirMetadata metaOBJ = new Gson().fromJson(jsonStr, TopSndDirMetadata.class);
208            //System.out.println("            TopSndDirMetadataJSON="+jsonStr);
209            //System.out.println("\n----------------------------");
210            //System.out.println("            TopSndDirMetadata="+metaOBJ);
211            if(metaOBJ.getDirState()==DirFileRef.DirState.LONG ) instance.writeArtistAlbumHtmlFiles(false);
212            else  instance.writeArtistAlbumHtmlFiles(true);
213      }
214      else
215      {
216        System.out.println(" CreateMetadataFiles only");
217        // ONLY create when DirState is LONG
218        topDirFilename = args[cmdStart];  // args[args.length-1];
219        MusicMakerTunesHelper instance = new MusicMakerTunesHelper(topDirFilename);
220
221        if ( reParseAllDirs || instance.tunesRootDirMetaFile_ == null ||  !instance.tunesRootDirMetaFile_.canRead() )
222        {
223          System.out.println("   - "+(reParseAllDirs?" ReParsing":"Initial") + " Metadata File Creation");
224          instance.createMetadataFiles();
225          System.out.println("   -! DONE "+(reParseAllDirs?" ReParsing":"Initial") + " Metadata File Creation\n\n");
226          instance.writeArtistAlbumHtmlFiles(false);
227        }
228        else
229        {
230          if ( instance.tunesRootDirMetaFile_ != null &&  instance.tunesRootDirMetaFile_.canRead() )
231          {
232            System.out.println("   - RE-CREATING Metadata Files");
233            // Check the DirState
234            // ONLY create when DirState is LONG
235            String jsonStr = Util.readFileToString(instance.tunesRootPath_+SYSTEM_FILE_SEPERATOR+metadataFilename_);
236            TopSndDirMetadata metaOBJ = new Gson().fromJson(jsonStr, TopSndDirMetadata.class);
237            //System.out.println("            TopSndDirMetadataJSON="+jsonStr);
238            //System.out.println("\n----------------------------");
239            //System.out.println("            TopSndDirMetadata="+metaOBJ);
240            if(metaOBJ.getDirState()!=DirFileRef.DirState.LONG )
241            {
242              System.out.println("       - Switching backTo LONGS 1st...");
243              System.out.println("            metaOBJ.dirState="+metaOBJ.dirState);
244              System.out.println("            DirFileRef.DirState.LONG="+DirFileRef.DirState.LONG);
245              //instance.renameToLongs(topDirFilename, "");
246            }
247            System.out.println("       - LONG ...");
248            instance.createMetadataFiles();
249            if(metaOBJ.getDirState()==DirFileRef.DirState.LONG ) instance.writeArtistAlbumHtmlFiles(false);
250            else  instance.writeArtistAlbumHtmlFiles(true);
251          }
252          else
253            System.out.println(" ERROR Processing. Cannot create MetaData Files");
254        }
255      }
256    }
257    else
258    {
259      System.out.println(" Parse the music/snd subdirectories to collect and save meta-data for each Artist/album directories.");
260      System.out.println("\n You must supply a TOP directory on the commandline that holds parent snd directories ");
261      System.out.println(" The dir should be the the TOP dir holding parenting snd directorie so it can parse the sub-artist dirs.");
262      System.out.println("     a second argument can be specified ");
263      System.out.println("        - if second argument is '-testing' to allow no actual writes");
264      System.out.println("        - if second argument is '-toShorts' it will renames files to short refKey equivalents");
265      System.out.println("        - if second argument is '-toLongs' it will renames files to long nospacess equivalents");
266      System.out.println("        - if second argument is '-albumHtml' it creates the albumHtml files WITHOUT any file renaming");
267      if (args.length >1) System.out.println(" arg1=" + args[1]);
268      if (args.length >2) System.out.println(" arg2=" + args[2]);
269      if (args.length >3) System.out.println(" arg3=" + args[3]);
270    }
271  }
272
273
274  /** Parses the TOP dir and reads in all the snd subirs creating Metadata files as is recurses. **/
275  public void createMetadataFiles()   {createMetadataFiles(tunesRootPath_);}
276
277  /** Parses the TOP dir and reads in all the snd subirs creating Metadata files as is recurses. **/
278  private void createMetadataFiles(String topDirFilename)
279  {
280    System.out.println("\n******** MusicMakerTunesHelper ********");
281    System.out.println("         topDirFilename = "+ topDirFilename);
282    File topDirFile = new File(topDirFilename);
283
284    //String [] topDirSubdirs = topDirFile.list();
285    //String [] topArtistDirfilenames = topDirFile.list();
286    if (topDirFile != null &&
287        topDirFile.isDirectory() &&
288        topDirFile.canRead() )
289    {
290      cleanDir(topDirFilename);
291      parseTopTunesDir(topDirFilename);
292    }
293    // Now save the JSON RootDir Meta Data file
294    String metaStr = toMetaJsonTopDir();
295    System.out.println("\n"+metaStr);
296    if (testing_) System.out.println("TESTING: fileWrite "+topDirFilename+SYSTEM_FILE_SEPERATOR+metadataFilename_);
297    else Util.writeStringToFile(metaStr, topDirFilename+SYSTEM_FILE_SEPERATOR+metadataFilename_);
298
299    // Then the snd sub-dirs
300    int sndDirNum = 0;
301    for(File currSnd : sndDirFiles_)
302    {
303      parseTunesDir(currSnd);
304      metaStr = toMetaJsonSndDir(currSnd.getAbsolutePath(), sndDirNum++);
305      System.out.println("\n"+metaStr);
306      if (testing_) System.out.println("TESTING: fileWrite "+currSnd.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+metadataFilename_);
307      else Util.writeStringToFile(metaStr, currSnd.getAbsolutePath()+SYSTEM_FILE_SEPERATOR+metadataFilename_);
308
309      // // Then recurse and save Each Artist dir Meta Data File
310      Artist[] arts = getArtists(true).toArray(new Artist[getArtists(true).size()]);
311      java.util.Arrays.sort(arts);
312      for(Artist currArt : arts)
313      {
314        if (testing_) System.out.println("TESTING: writeMetaJsonFile "+currArt.artistName());
315        else currArt.writeMetaJsonFile();
316
317        Album[] artAlbums = currArt.getAlbums(true).toArray(new Album[currArt.getAlbums(true).size()]);
318        java.util.Arrays.sort(artAlbums);
319        for(Album currAlb : artAlbums)
320        {
321          if (testing_) System.out.println("TESTING: writeMetaJsonFile "+currAlb.albumTitle());
322          else
323          {
324            currAlb.writeMetaJsonFile();
325            currAlb.writeHtmlDivFile();
326          }
327        }
328      }
329    }
330  }
331
332
333  public void cleanDir(String dirToClean){cleanDir(dirToClean, true);}
334
335  /** Parses the dir (recursive is optional) and removes non-song files and any useless subdirs (like @eadirs). **/
336  public void cleanDir(String dirToClean, boolean recurse)
337  {
338    File[] subDirFiles = (new File(dirToClean)).listFiles();
339    if(subDirFiles!=null)
340    {
341      try
342      {
343        for(File currFile : subDirFiles)
344        {
345          if(currFile.isDirectory()
346             && currFile.canRead()
347             && recurse)
348          {
349            if(currFile.getAbsolutePath().endsWith("@eaDir")
350               || currFile.getAbsolutePath().contains(".trash"))
351              ca.bc.webarts.widgets.Util.removeDir(currFile.getAbsolutePath());
352            else
353              cleanDir(currFile.getAbsolutePath(), true);
354          }
355          else
356          {
357            // its a file so delete it if not needed
358            if(currFile.getAbsolutePath().endsWith(metadataFilename_))
359              currFile.delete();
360
361          }
362        }
363      }
364      catch(Exception ex) { System.out.println("ERROR Cleaning/Reading Dir: "+dirToClean); ex.printStackTrace();}
365    }
366  }
367
368
369  /** Parses the TOP tunes dir and reads in all the snd subirs. **/
370  public void parseTopTunesDir(String tunesRootDir)
371  {
372    numSndDirs_ = 0;
373    Vector<File> sndDirs = new Vector();
374    sndDirFiles_ = (new File(tunesRootDir)).listFiles();
375    if(sndDirFiles_!=null)
376    {
377      try
378      {
379        for(File currFile : sndDirFiles_)
380          if(currFile.isDirectory()
381             && currFile.canRead() )
382          {
383            numSndDirs_++;
384            sndDirs.add(currFile);
385            //parseTunesDir(currFile);
386          }
387          sndDirFiles_= sndDirs.toArray(new File[sndDirs.size()]);  // reset it using only valid dirs
388          System.out.print("  parsing found sndDirs: [");
389          for(int i=0; i<sndDirFiles_.length;i++) System.out.print(sndDirFiles_[i].getName()+(i<sndDirFiles_.length-1?", ":"]"));
390      }
391      catch(Exception ex) { System.out.println("ERROR Reading tunesRootDir: "+tunesRootDir); ex.printStackTrace();}
392    }
393  }
394
395
396  /** Parses the tunes sub-dirs and reads in all the artists_. **/
397  public void parseTunesDir(File artistRootDirFile)
398  {
399    parseTunesDir(artistRootDirFile.getAbsolutePath());
400  }
401
402
403  /** Parses the tunes sub-dirs and reads in all the artists_. **/
404  public void parseTunesDir(String artistRootDir)
405  {
406    int numValidArtDirs = 0;
407    File[] artistDirFiles = (new File(artistRootDir)).listFiles();
408    java.util.Arrays.sort(artistDirFiles);
409    boolean useMusicBrainz = true;  // now rely on the MB settings for useCacheOnly
410    //java.util.List<Track> pagedLovedTracks = (java.util.List<Track>)lastFmLovedTracks_.getPageResults();
411    if(artistDirFiles!=null)
412    {
413      //if(artists_==null)
414        artists_ = new Vector <Artist>();
415      try
416      {
417        for(File currFile : artistDirFiles)
418        {
419          if(currFile.isDirectory()
420             && currFile.canRead() )
421          {
422            // check if the artist dir has ANY album dirs, then add
423            File[] subFiles = (new File(currFile.getAbsolutePath())).listFiles();
424            boolean valid = false;
425            try
426            {
427              for(int i=0; !valid&&i<subFiles.length; i++)
428              {
429                if(subFiles[i].isDirectory()
430                   && subFiles[i].canRead()
431                   && subFiles[i].listFiles().length>0
432                  ) valid= true;
433              }
434              if(valid)
435              {
436                numValidArtDirs++;
437                //System.out.print("\n    [ca.bc.webarts.widgets > MusicMakerTunesHelper.parseTunesDir() ");
438                //System.out.println("["+numValidArtDirs+"] "+currFile.getAbsolutePath());
439                Artist art = new Artist(currFile.getAbsolutePath(), useMusicBrainz, artists_.size());
440                artists_.add(art);
441              }
442            }
443            catch ( Exception ex)
444            {
445              System.out.println(" *!What The Fudge (parseTunesDir()) : "+ex.getMessage());
446              ex.printStackTrace();
447            }
448          }
449        }
450      }
451      catch(Exception ex) { /* ignore error dirs */ }
452      artists_.sort(Artist.ArtistComparatorIgnoreCase );
453    }
454  }
455
456
457  public String getRefKeyString()
458  {
459    String retVal = "0";
460
461    try
462    {
463      Hex.encodeHexString(Hex.decodeHex(refKEY_));
464    }
465    catch (DecoderException dEx)
466    {
467      //send back an empty String
468    }
469    return retVal;
470  }
471
472
473  private void renameToShorts(String topDir , String parentRefKey)
474  {
475    renameTo(true, topDir , parentRefKey);
476  }
477
478
479  private void renameToLongs(String topDir , String parentRefKey)
480  {
481    renameTo(false, topDir , parentRefKey);
482  }
483
484
485  private void renameTo(boolean toShorts, String topDir , String parentRefKey)
486  {
487    String jsonStr = Util.readFileToString(topDir+SYSTEM_FILE_SEPERATOR+metadataFilename_);
488
489    File topDirFile = new File(topDir);
490
491    if(debug_info_ && toShorts) System.out.print("    > "+(testing_?"renameToShorts from ":"... ")+topDir+SYSTEM_FILE_SEPERATOR+metadataFilename_+" ");
492    if(debug_info_ && !toShorts) System.out.print("    > "+(testing_?"renameToLongs from ":"... ")+topDir+SYSTEM_FILE_SEPERATOR+metadataFilename_+" ");
493    if (topDirFile != null)
494    {
495      String[] files = topDirFile.list();
496      File tempFile;
497      DirFileRef metaOBJ = new Gson().fromJson(jsonStr, DirFileRef.class);
498
499      if(debug_info_ && metaOBJ.dirType==SndDirMetadata.DirType.TOPDIR) System.out.println("\nI#I#I#I#\nI#I#I#I#\nI#I#I#I#\nI#I#I#I#\n READ IN:"+jsonStr);
500      if(debug_info_ && metaOBJ.dirType==SndDirMetadata.DirType.TOPDIR) System.out.println(metaOBJ);
501      if(debug_info_) System.out.print("\n      DirType = "+metaOBJ.getDirType().typeStr);
502      if(debug_info_) System.out.println("   FULL refKey = "+parentRefKey+metaOBJ.getRefKey());
503
504      TopSndDirMetadata topDirMetaObj = null;
505      SndDirMetadata sndMetaObj = null;
506      ArtistDirRef artistMetaObj = null;
507      AlbumDirRef albumMetaObj = null;
508      SongRef [] songsMetaObj = null;
509      SongRef currSongMetaObj = null;
510      try
511      {
512        if(metaOBJ.getDirType().typeStr.equals("ARTIST"))
513        {
514          artistMetaObj = new Gson().fromJson(jsonStr, ArtistDirRef.class);
515        }
516        else if(metaOBJ.getDirType().typeStr.equals("SNDROOT"))
517        {
518          sndMetaObj = new Gson().fromJson(jsonStr, SndDirMetadata.class);
519        }
520        else if(metaOBJ.getDirType().typeStr.equals("TOPDIR"))
521        {
522          topDirMetaObj = new Gson().fromJson(jsonStr, TopSndDirMetadata.class);
523        }
524        else if(metaOBJ.getDirType().typeStr.equals("ALBUM"))
525        {
526          albumMetaObj = new Gson().fromJson(jsonStr, AlbumDirRef.class);
527          songsMetaObj = albumMetaObj.getSongs();
528          if(debug_info_) System.out.println("     ALBUM numSongs= "+albumMetaObj.getNumSongs() + "["+songsMetaObj.length+"]");
529        }
530        System.out.print("\n      ");
531
532        String shortFilename = "";
533        String shortFilenameNoPeriods = "";
534        String longFilename = "";
535        //loop through all the files in the dir RENAMING them
536        // use the Songs Objects
537        for (int i = 0; i < files.length; i++)
538        {
539          currSongMetaObj = null;
540          tempFile = new File(topDir + SYSTEM_FILE_SEPERATOR + files[i]);
541          if (tempFile.isDirectory() && !files[i].startsWith("@"))
542          {
543            // recurse on the subdirectory 1st
544            if(debug_dir_) System.out.println("  >> Recursing");
545            renameTo(toShorts, topDir + SYSTEM_FILE_SEPERATOR + files[i], parentRefKey+metaOBJ.getRefKey()+".");
546
547          }
548          else if(files[i].endsWith(".ogg") || files[i].endsWith(".OGG") ||
549                  files[i].endsWith(".mp3") || files[i].endsWith(".MP3") ||
550                  files[i].endsWith(".flac") || files[i].endsWith(".FLAC")    )
551          {
552            if(songsMetaObj!=null)
553            {
554              System.out.print("|-> ");
555              for(SongRef currObj : songsMetaObj)
556              {
557                if(toShorts && files[i].equals(currObj.getDirFile())) currSongMetaObj = currObj;
558                if(!toShorts )
559                {
560                  shortFilename = parentRefKey.substring(2,4);
561                  shortFilename += Util.right(parentRefKey,4);
562                  shortFilename += albumMetaObj.getRefKey()+".";
563                  shortFilename += currObj.getRefKey();
564                  shortFilename = ca.bc.webarts.widgets.Util.tokenReplace(shortFilename,".","") ;
565                  shortFilename += Util.right(files[i],4);
566                  if(files[i].equals(shortFilename)) currSongMetaObj = currObj;
567                }
568                //System.out.println("chk "+files[i]+" "+currObj.getDirFile());
569              }
570              if(currSongMetaObj!=null)
571              {
572                // leave the periods in for now
573                shortFilename = parentRefKey.substring(2,4);
574                shortFilename += Util.right(parentRefKey,4);
575                shortFilename += albumMetaObj.getRefKey()+".";
576                shortFilename += currSongMetaObj.getRefKey();
577
578                shortFilenameNoPeriods = ca.bc.webarts.widgets.Util.tokenReplace(shortFilename,".","") ;
579                shortFilenameNoPeriods += Util.right(files[i],4);
580
581                shortFilename += Util.right(files[i],4);
582                longFilename = currSongMetaObj.getDirFile();
583                longFilename.substring(longFilename.lastIndexOf(SYSTEM_FILE_SEPERATOR)+1);
584              }
585            }
586
587            if(!testing_)
588            {
589              if(songsMetaObj!=null)
590              {
591                // process all the files
592                if(debug_song_) System.out.print(".");
593                if(toShorts)
594                {
595                  // rename totoShortslongs
596                  if(debug_song_) System.out.println(topDir + SYSTEM_FILE_SEPERATOR + files[i] + "\n          -->  " +
597                                                     shortFilename+"        ");
598                  ca.bc.webarts.widgets.Util.renameFile(topDir + SYSTEM_FILE_SEPERATOR + files[i], shortFilenameNoPeriods);
599
600                }
601                else
602                {
603                  // rename tolongs
604                  if(debug_song_) System.out.println(topDir + SYSTEM_FILE_SEPERATOR + files[i] + "\n          -->  " +
605                                                     longFilename+"        ");
606                  ca.bc.webarts.widgets.Util.renameFile(topDir + SYSTEM_FILE_SEPERATOR + files[i], longFilename);
607                }
608              }
609            }
610            else
611            {
612              // process all the files
613              if(songsMetaObj!=null)
614              {
615                System.out.print("|-> ");
616                if(toShorts)
617                {
618                  System.out.println(topDir + SYSTEM_FILE_SEPERATOR + files[i] + "\n          -->  " +
619                                     shortFilename+"        ");
620                }
621                else
622                {
623                  // rename tolongs
624                  System.out.println(topDir + SYSTEM_FILE_SEPERATOR + files[i] + "\n          -->  " +
625                                     longFilename+"        ");
626                }
627              }
628            }
629          }
630        } // done Songs
631
632        // Finally Rename topDirFile
633        // now Update the MetaData file & RENAME the subdirectory
634        if(metaOBJ.getDirType().typeStr.equals("ALBUM"))
635        {
636          shortFilename = parentRefKey.substring(2,4);
637          shortFilename += Util.right(parentRefKey,4);
638          shortFilename += metaOBJ.getRefKey();
639        }
640        else if(metaOBJ.getDirType().typeStr.equals("ARTIST"))
641        {
642          System.out.println("   FULL refKey = "+parentRefKey+metaOBJ.getRefKey());
643          shortFilename = parentRefKey.substring(2,4);
644          shortFilename += Util.right(metaOBJ.getRefKey(),3);
645          //shortFilename += metaOBJ.getRefKey();
646        }
647        else if(metaOBJ.getDirType().typeStr.equals("SNDROOT"))
648        {
649          System.out.println("   FULL refKey = "+parentRefKey+metaOBJ.getRefKey());
650          shortFilename = metaOBJ.getRefKey();
651          //shortFilename += Util.right(metaOBJ.getRefKey(),3);
652          //shortFilename += metaOBJ.getRefKey();
653        }
654        longFilename = metaOBJ.getDirFile();
655        longFilename = longFilename.substring(longFilename.lastIndexOf(SYSTEM_FILE_SEPERATOR)+1);
656
657        Gson gson = new Gson();
658        jsonStr = "";
659
660        if(!metaOBJ.getDirType().typeStr.equals("TOPDIR"))
661        {
662          if(!testing_)
663          {
664            // UPDATE the MetaFile DirState
665             if(metaOBJ.getDirType().typeStr.equals("SNDROOT"))
666            {
667              sndMetaObj.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
668              for(ArtistDirRef currArtRef : sndMetaObj.getArtists()) currArtRef.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
669              jsonStr = sndMetaObj.toString();
670            }
671            else if(metaOBJ.getDirType().typeStr.equals("ARTIST"))
672            {
673              artistMetaObj.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
674              for(AlbumDirRef currAlbDirRef : artistMetaObj.getAlbums()) currAlbDirRef.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
675              jsonStr = artistMetaObj.toString();
676            }
677            else if(metaOBJ.getDirType().typeStr.equals("ALBUM"))
678            {
679              albumMetaObj.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
680              for(SongRef currSongRef : albumMetaObj.getSongs()) currSongRef.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
681              jsonStr = albumMetaObj.toString();
682            }
683            System.out.println(" Writing "+metaOBJ.getDirType().typeStr+" MetaData file: "+metaOBJ.getDirFile()+SYSTEM_FILE_SEPERATOR+metadataFilename_);
684            ca.bc.webarts.widgets.Util.writeStringToFile(jsonStr, metaOBJ.getDirFile()+SYSTEM_FILE_SEPERATOR+metadataFilename_);
685            if(metaOBJ.getDirType().typeStr.equals("ALBUM"))
686            {
687              //jsonStr = Util.readFileToString(topDir+SYSTEM_FILE_SEPERATOR+metadataFilename_);
688              //artistMetaObj = new Gson().fromJson(jsonStr, ArtistDirRef.class);
689              char[] refChars = {'0','0','0','0'};
690              if(artistMetaObj!=null)
691              {
692                String ark = artistMetaObj.getRefKey();
693                if(ark.length()>0) refChars[3] = ark.charAt(ark.length()-1);
694                if(ark.length()>1) refChars[2] = ark.charAt(ark.length()-2);
695                if(ark.length()>2) refChars[1] = ark.charAt(ark.length()-3);
696                if(ark.length()>3) refChars[0] = ark.charAt(ark.length()-4);
697              }
698              else System.out.println(" ERROR: no Artist YET for "+metaOBJ.getDirFile());
699
700              try {
701                Album al = new Album(metaOBJ.getDirFile(), false, Integer.parseInt(metaOBJ.getRefKey()), refChars  );
702                if(al.isArtistRefKEYEmpty()) al.retrieveArtistRefKey();
703                al.writeHtmlDivFile();
704              }
705              catch (Exception ex) {System.out.println(" Error Writing Album html: refKey="+metaOBJ.getRefKey());}
706            }
707
708            shortFilenameNoPeriods = ca.bc.webarts.widgets.Util.tokenReplace(shortFilename,".","");
709            // do the RENAME
710            if(toShorts)
711            {
712              // rename toShorts
713              if(debug_dir_) System.out.println(" DIR> "+topDir + "\n          -->  " +
714                                                         shortFilename+"        ");
715              ca.bc.webarts.widgets.Util.renameFile(topDir , shortFilenameNoPeriods);
716            }
717            else
718            {
719              // rename tolongs
720              if(debug_dir_) System.out.println(" <DIR> "+topDir+ "\n          -->  " +
721                                                         longFilename +"        ");
722              metaOBJ.setDirState(DirFileRef.DirState.LONG);
723              ca.bc.webarts.widgets.Util.renameFile(topDir , longFilename);
724            }
725          }
726          else
727          {
728            if(toShorts) System.out.println(" DIR: "+topDir + "\n          -->  " +
729                                                     shortFilename+"        ");
730            else         System.out.println(" DIR: "+topDir+ "\n          -->  " +
731                                                     longFilename +"        ");
732          }
733        }
734        else
735        {
736          // update the TopDirMeta File
737          topDirMetaObj.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
738          for(DirFileRef currRef : topDirMetaObj.getSndDirs()) currRef.setDirState((toShorts?DirFileRef.DirState.SHORT:DirFileRef.DirState.LONG));
739          jsonStr = topDirMetaObj.toString();
740          ca.bc.webarts.widgets.Util.writeStringToFile(jsonStr, topDirMetaObj.getDirFile()+SYSTEM_FILE_SEPERATOR+metadataFilename_);
741
742        }
743
744        if(debug_dir_) System.out.println(" !! " + "done " +"\n");
745      }
746      catch(NullPointerException npEx)
747      {
748        System.out.println(" Crapped out on "+metaOBJ);
749        System.out.println("         created from:  "+jsonStr);
750        npEx.printStackTrace();
751      }
752    }
753
754  }
755
756
757  /** Using this class object's tunesRootPath_ and existing MetaData Files data,
758    * write the album.html file in each Artist Album directory; overwritingexisitng files if needed.
759    *
760    **/
761  public void writeArtistAlbumHtmlFiles()
762  {
763    writeArtistAlbumHtmlFiles( true);
764  }
765
766
767  /** Using this class object's tunesRootPath_ and existing MetaData Files data,
768    * write the album.html file in each Artist Album directory; overwritingexisitng files if needed.
769    *
770    **/
771  public void writeArtistAlbumHtmlFiles(boolean doingRefURLS)
772  {
773    String preUrlStr = "../../../../";
774    String postUrlStr = "\");";
775    if( doingRefURLS) preUrlStr = "javascript:MusicMakerWebSocketMessage("+"\"TUNE/";
776
777    writeArtistAlbumHtmlFiles( tunesRootPath_, preUrlStr, postUrlStr, doingRefURLS);
778  }
779
780
781  /** Using this class object's tunesRootPath_ and existing MetaData Files data,
782    * write the album.html file in each Artist Album directory; overwritingexisitng files if needed.
783    *
784    * @param preUrlStr is a string to pre-pend to all directorys represneting URLs; it can be an empty string to treat them as relative URLs.
785    **/
786  public void writeArtistAlbumHtmlFiles(String preUrlStr, String postUrlStr, boolean doingRefURLS)
787     { writeArtistAlbumHtmlFiles( tunesRootPath_, preUrlStr, postUrlStr, doingRefURLS);}
788
789
790  /** Using existing MetaData Files data, write the album.html file in
791    * each Artist Album directory; overwritingexisitng files if needed.
792    *
793    * @param tunesRootDir is the top tunesdir holding the snd sub-dirs
794    * @param preUrlStr is a string to pre-pend to all directorys represneting URLs; it can be an empty string to treat them as relative URLs.
795    **/
796  public void writeArtistAlbumHtmlFiles(String tunesRootDir , String preUrlStr, String postUrlStr, boolean doingRefURLS)
797  {
798    //String htmlLinkStart = "<a class=\"Song"+songCount+"\" id=\"Song"+songCount+"\" name=\"Song"+songCount+"\" href=\"#\" >";
799    //String htmlLinkEnd ="</a>";
800
801    String relativeURL = "";
802    String tuneURL = "";
803    String urlToUse = "";
804    String urlRootDir = "";
805    Vector <ArtistDirRef> artistRefs = new Vector <ArtistDirRef>();
806
807//    if( doingRefURLS) preUrlStr = "/TUNE/";
808//    else preUrlStr = "../../../../"
809
810    System.out.println(" writeArtistAlbumHtmlFiles("+tunesRootDir+", \""+preUrlStr+"\", \""+postUrlStr+"\", "+doingRefURLS+" )");
811
812    if(tunesRootDir!=null && !"".equals(tunesRootDir))
813    {
814      File topDirFile = new File(tunesRootDir);
815      if (topDirFile != null && topDirFile.canRead())
816      {
817        String jsonStr = Util.readFileToString(tunesRootDir+SYSTEM_FILE_SEPERATOR+metadataFilename_);
818        TopSndDirMetadata topDirRef = new Gson().fromJson(jsonStr, TopSndDirMetadata.class);
819        boolean shorts = topDirRef.getDirState().getStateStr()=="SHORT";
820
821        String tempFileStr = "";
822        File tempFile = null;
823        String[] files = topDirFile.list();
824
825        int artistCountTotal = 0;
826        int albumCountTotal = 0;
827        for (int i = 0; i < files.length; i++)  // snd dirs
828        {
829          /* files = Root snd dirs */
830          tempFileStr = tunesRootDir + SYSTEM_FILE_SEPERATOR + files[i];
831          tempFile = new File(tempFileStr);
832          if (tempFile.isDirectory() && tempFile.canRead()
833              && !files[i].startsWith("@") && !files[i].startsWith("."))
834          {
835            urlRootDir = tunesRootDir.substring(tunesRootDir.lastIndexOf(SYSTEM_FILE_SEPERATOR)+1)
836                         +SYSTEM_FILE_SEPERATOR+files[i]+SYSTEM_FILE_SEPERATOR;
837
838            String tempFileStr2 = "";
839            File tempFile2 = null;
840            String[] files2 = tempFile.list();
841
842            // Loop to count Artists 1st
843            int artistCount = 0;
844            for (int i2 = 0; i2 < files2.length; i2++)
845            {
846              /* files2 [i2] = ARTIST dirs */
847             tempFileStr2 = tempFileStr + SYSTEM_FILE_SEPERATOR + files2[i2];
848             tempFile2 = new File(tempFileStr2);
849             if (tempFile2.isDirectory() && tempFile2.canRead()
850                  && !files2[i2].startsWith("@") && !files2[i2].startsWith("."))
851               artistCount++;
852            }
853            artistCountTotal +=artistCount;
854            String [] artistNames = new String [artistCount];
855            String [] artistUrls = new String [artistCount];
856            String [] artistDivHtml = new String [artistCount];
857            int currArtistCount = -1;
858
859            for (int i2 = 0; i2 < files2.length; i2++)  // Artist dirs
860            {
861              /* files2 [i2] = ARTIST dirs */
862              String currArtDirName = files2[i2];
863              ArtistDirRef currArtDirRef = null;
864              String currArtName = "";
865              tempFileStr2 = tempFileStr + SYSTEM_FILE_SEPERATOR + files2[i2];
866              tempFile2 = new File(tempFileStr2);
867              if (tempFile2.isDirectory() && tempFile2.canRead()
868                  && !files2[i2].startsWith("@") && !files2[i2].startsWith("."))
869              {
870                currArtistCount++;
871                //System.out.println("   DEBUG: reading Artist MetaData from: "+tempFileStr+SYSTEM_FILE_SEPERATOR+currArtDirName+SYSTEM_FILE_SEPERATOR+metadataFilename_);
872                jsonStr = Util.readFileToString(tempFileStr+SYSTEM_FILE_SEPERATOR+currArtDirName+SYSTEM_FILE_SEPERATOR+metadataFilename_);
873                currArtDirRef = new Gson().fromJson(jsonStr, ArtistDirRef.class);
874
875                currArtName =  Util.capsToSpacesInString(currArtDirName);
876                if(currArtDirRef!=null && !"".equals(currArtDirRef.getArtistName())) currArtName = currArtDirRef.getArtistName();
877                tempFileStr2 = tempFileStr + SYSTEM_FILE_SEPERATOR + files2[i2];
878                tempFile2 = new File(tempFileStr2);
879                artistNames[currArtistCount] = currArtName;
880                artistUrls[currArtistCount] = tempFileStr2.substring(tunesRootDir.length()+1);
881                if(currArtDirRef!=null && !"".equals(currArtDirRef.getArtistName()))
882                {
883                  currArtDirRef.setUrlPath(artistUrls[currArtistCount]);
884                  artistRefs.add(currArtDirRef);
885                }
886
887                String tempFileStr3 = "";
888                File tempFile3 = null;
889                String[] files3 = tempFile2.list();
890                // count Albums 1st
891                int albumCount = 0;
892                for (int i3 = 0; i3 < files3.length; i3++)
893                {
894                  // Loop to count ALBUMS 1st
895                 tempFileStr3 = tempFileStr2 + SYSTEM_FILE_SEPERATOR + files3[i3];
896                 tempFile3 = new File(tempFileStr3);
897                 if (tempFile3.isDirectory() && tempFile3.canRead()
898                     && !files3[i3].startsWith("@") && !files3[i3].startsWith("."))
899                   albumCount++;
900                }
901                albumCountTotal+=albumCount;
902
903                String [] albmumUrls = new String [albumCount];
904                String [] albmumDivHtml = new String [albumCount];
905                AlbumDirRef [] albumRefs = new AlbumDirRef[albumCount];
906                int currAlbumCount = -1;
907
908                for (int i3 = 0; i3 < files3.length; i3++)  // Album dirs
909                {
910                  /* files3 [i3] = ALBUM dirs */
911                  //System.out.print("    ReadingAlbum Dir="+tempFileStr2 + SYSTEM_FILE_SEPERATOR);
912                  //System.out.println(files3[i3]);
913                  tempFileStr3 = tempFileStr2 + SYSTEM_FILE_SEPERATOR + files3[i3];
914                  tempFile3 = new File(tempFileStr3);
915                  if (tempFile3.isDirectory() && tempFile3.canRead()
916                      && !files3[i3].startsWith("@") && !files3[i3].startsWith("."))
917                  {
918                    currAlbumCount++;
919                    // Read MetaData.json file
920                    jsonStr = Util.readFileToString(tempFileStr3+SYSTEM_FILE_SEPERATOR+metadataFilename_);
921                    AlbumDirRef currAlbDirRef = new Gson().fromJson(jsonStr, AlbumDirRef.class);
922
923                    String albName = Util.capsToSpacesInString(files3[i3]);
924                    if(currAlbDirRef!=null && !"".equals(currAlbDirRef.getAlbumName()))
925                    {
926                      albName = currAlbDirRef.getAlbumName();
927                      albumRefs[currAlbumCount] = currAlbDirRef;
928                      SongRef [] songRefs =  currAlbDirRef.getSongs();
929
930                      String lastFmAlbumUrl = Album.retrieveLastFmAlbumUrl(currArtName, albName).replace("#","%23");
931                      lastFmAlbumUrl = Util.tokenReplace(lastFmAlbumUrl,"#","%23");
932
933                      // Write album.html
934                      String retVal = "      <div id=\""+
935                                      ca.bc.webarts.widgets.Util.spacesToCapsInString(albName)+
936                                      "\" class=\"albumDiv\"  >\n";
937                      retVal+= "          <ol>\n";
938                      //retVal+= SYSTEM_LINE_SEPERATOR;
939                      retVal+= "            <img id=\""+Util.spacesToCapsInString(currArtName.trim())+"_" +Util.spacesToCapsInString(albName)+"_cover"+
940                               "\" alt=\""+Util.spacesToCapsInString(albName)+" Album Cover Thumbnail\" src=\""+
941                               "../.." + "/" + files[i] + "/" + files2[i2] + "/" + files3[i3] + "/" +
942                               "cover.jpg"+"\" class=\"\" style=\"margin:0px;\" height=\"32px\" width=\"32px\"/>";
943                      retVal+= " <b><u> ";
944                      if( !"".equals(lastFmAlbumUrl))retVal+= " <a href=\""+lastFmAlbumUrl+"\"  target=\"_blank\"> ";
945                      retVal+= albName;
946                      if( !"".equals(lastFmAlbumUrl))retVal+= " </a> ";
947                      retVal+= "</u></b>";
948                      //retVal+= " <span style=\"font-size: 0.7em;\">";
949                      //retVal+= " ("+ getReleaseYear() + ")";
950                      //retVal+= " [<a  href=\""+downloadLink_+"\">zip</a>]</span>";
951                      retVal+= SYSTEM_LINE_SEPERATOR;
952                      for (SongRef currSongRef : songRefs)
953                      {
954                        relativeURL = preUrlStr.trim() +
955                              urlRootDir + files2[i2]+"/"+files3[i3]+"/" +
956                              postUrlStr.trim();
957                        if(shorts)
958                        {
959                          relativeURL += files3[i3]+currSongRef.getRefKey() + currSongRef.getDirFile().substring(currSongRef.getDirFile().lastIndexOf("."));
960                          tuneURL = files3[i3]+currSongRef.getRefKey() + currSongRef.getDirFile().substring(currSongRef.getDirFile().lastIndexOf("."));
961                        }
962                        else
963                          relativeURL += Util.tokenReplace(currSongRef.getDirFile(),"?","%3F");
964                        relativeURL = Util.tokenReplace(relativeURL,"&","%26");
965                        relativeURL = Util.tokenReplace(relativeURL,"!","%21");
966                        relativeURL = Util.tokenReplace(relativeURL,"%2f","%252f");
967                        relativeURL = Util.tokenReplace(relativeURL,"%2F","%252F");
968                        if(doingRefURLS) urlToUse = preUrlStr.trim() + tuneURL +postUrlStr.trim();
969                        else urlToUse = relativeURL;
970
971                        retVal+= "              <li>\n                <div class=\"songtip\">\n                  ";
972                        retVal+= "<a href=\""+urlToUse+"\">";
973                        retVal+= currSongRef.getTitle().trim().replace("_"," ").replace("  "," ").trim();
974                        retVal+= "</a><span class=\"songtiptextTop\">"+urlToUse+"</span>\n";
975                        retVal+= "                </div>\n              </li>";
976                        retVal+= SYSTEM_LINE_SEPERATOR;
977                      }
978
979                      retVal += "          </ol>\n      </div>";
980                      Util.writeStringToFile(retVal, tempFileStr3+SYSTEM_FILE_SEPERATOR+"album.html");
981                      albmumUrls[currAlbumCount] = urlRootDir + files2[i2]+"/"+"album.html";
982                      albmumDivHtml[currAlbumCount] = retVal;
983
984                    }
985                    else
986                    {
987                      System.out.println(" Empty/NULL Album Dir Ref: "+currArtName+" / "+albName);
988                      System.out.println("     trying from: "+ tempFileStr3+SYSTEM_FILE_SEPERATOR+metadataFilename_);
989                      System.out.println("     jsonStr: \n"+jsonStr);
990                    }
991                  } // valid Album Dir
992                } // Album Dirs loop files3[j3]
993
994                //write the artist.html file
995                String artistHtml = "    <script src=\"http://"+musicMakerIP_+"/mmWebSkt.js\"></script>\n";
996                artistHtml += "    <div id=\""+ca.bc.webarts.widgets.Util.spacesToCapsInString(currArtName) +
997                                    "\" class=\"artistDiv\">\n";
998                artistHtml += "      <span class=\"artistTitle\">";
999                artistHtml += currArtName;
1000                artistHtml += "</span>\n";
1001
1002                for(int j=0; j< albmumDivHtml.length; j++)
1003                {
1004                  if(albmumDivHtml[j]!=null && !"".equals(albmumDivHtml[j]))
1005                  {
1006                    artistHtml += ca.bc.webarts.widgets.Util.tokenReplace(
1007                                      albmumDivHtml[j],
1008                                      "../../../../","../../../");
1009                  }
1010                  else artistHtml += "      <!-- empty album dir -->";
1011                    artistHtml += SYSTEM_LINE_SEPERATOR;
1012                }
1013                artistHtml += "    </div>\n";
1014                Util.writeStringToFile(artistHtml, tunesRootDir+SYSTEM_FILE_SEPERATOR + files[i]+SYSTEM_FILE_SEPERATOR + files2[i2]+SYSTEM_FILE_SEPERATOR+"artist.html");
1015
1016              }// valid Artist dir
1017            }// Artist Dirs loop files2[j2]
1018          }
1019        } // snd dirs
1020
1021        // TOP Music Dir
1022            String artistListJson = "{\n  \"artists\": [\n        {\n";
1023            String artistListHtml = "    <div id=\"artistList\">\n      <ul>\n";
1024            ArtistDirRef currArtistRef = null;
1025            for(int j=0; j< artistRefs.size(); j++)
1026              {
1027                currArtistRef = artistRefs.get(j);
1028                if(currArtistRef!=null)
1029                {
1030                  String metaFileStr = currArtistRef.getDirFile()+SYSTEM_FILE_SEPERATOR+".."+SYSTEM_FILE_SEPERATOR+metadataFilename_;
1031                  if(currArtistRef.getDirState()!=DirFileRef.DirState.LONG)
1032                    metaFileStr = tunesRootDir+SYSTEM_FILE_SEPERATOR+currArtistRef.getUrlPath()+SYSTEM_FILE_SEPERATOR+".."+SYSTEM_FILE_SEPERATOR+metadataFilename_;
1033                  //System.out.println("looking for SNDMetaDatain "+metaFileStr);
1034                  jsonStr = Util.readFileToString(metaFileStr);
1035                  SndDirMetadata sndDirRef = new Gson().fromJson(jsonStr, SndDirMetadata.class);
1036                  artistListJson += "              \"name\": \""+currArtistRef.getArtistName()+"\",\n";
1037                  artistListJson += "            \"refKey\": \""+sndDirRef.getRefKey() +"."+ currArtistRef.getRefKey()+"\",\n";
1038                  artistListJson += "               \"url\": \""+currArtistRef.getUrlPath()+"/artist.html\"\n";
1039                  artistListJson += "        }";
1040                  if(j<artistRefs.size()-1)   artistListJson += ",\n        {\n";
1041                  artistListHtml += "        <li><a href=\""+currArtistRef.getUrlPath()+"/artist.html"+"\">"+currArtistRef.getArtistName()+"</a></li>\n";
1042                }
1043              }
1044            artistListJson += "\n  ]\n}";
1045            artistListHtml += "     </ul></div>\n";
1046            System.out.println("Writing Artist List "+tunesRootDir+SYSTEM_FILE_SEPERATOR+"artists.html");
1047            Util.writeStringToFile(artistListHtml, tunesRootDir+SYSTEM_FILE_SEPERATOR+"artists.html");
1048            Util.writeStringToFile(artistListJson, tunesRootDir+SYSTEM_FILE_SEPERATOR+"artists.json");
1049            createCSSFile(tunesRootDir);
1050
1051      }
1052      else  System.out.println(" Error reading tunesRootDir string.");
1053    }
1054    else  System.out.println(" Error writing Album html files due to null/empty tunesRootDir string.");
1055
1056  }
1057
1058
1059  /** . **/
1060  public String createCSSFile(String topDirFilename)
1061  {
1062    String retVal = "header,footer{\n";
1063    retVal += "    color:white;\n";
1064    retVal += "    background-color:#004;\n";
1065    retVal += "    margin-bottom:6px;padding:4px;\n";
1066    retVal += "    font-family:Acme,Tahoma,sans-serif;\n";
1067    retVal += "}\n";
1068    retVal += "h1,h2 {\n";
1069    retVal += "    color:white;\n";
1070    retVal += "    background-color:#338;\n";
1071    retVal += "    padding:2px;\n";
1072    retVal += "    margin-bottom:2px;\n";
1073    retVal += "    font-family:Acme,Tahoma,sans-serif;\n";
1074    retVal += "}\n";
1075    retVal += "h3,h4,h5,h6 {\n";
1076    retVal += "    color:white;\n";
1077    retVal += "    background-color:#55a;\n";
1078    retVal += "    padding-left:2px;padding-right:4px;padding-top:4px;padding-bottom:4px;\n";
1079    retVal += "    margin-left:1px;\n";
1080    retVal += "    margin-right:1px;\n";
1081    retVal += "    margin-bottom:1px;\n";
1082    retVal += "    font-family:Acme,Tahoma,sans-serif;\n";
1083    retVal += "}\n";
1084    retVal += "body {\n";
1085    retVal += "    background-color: #111144; \n";
1086    retVal += "    font-family:'Noto Sans',Tahoma,sans-serif;font-size:0.8em;\n";
1087    retVal += "}\n";
1088    retVal += "section {\n";
1089    retVal += "    margin:1px;margin-bottom:6px;padding:1px;\n";
1090    retVal += "    background-color:#005;\n";
1091    retVal += "    font-family:Acme,Tahoma,sans-serif;\n";
1092    retVal += "}\n";
1093    retVal += "article {\n";
1094    retVal += "    border:1px solid blue;\n";
1095    retVal += "    margin:1px;margin-bottom:4px;margin-top:0px;padding:1px;\n";
1096    retVal += "    background-color:#eee;\n";
1097    retVal += "    font-family:'Noto Sans',Tahoma,sans-serif;\n";
1098    retVal += "}\n";
1099    retVal += "nav ul  {\n";
1100    retVal += "    margin:0;padding:0;font-family:Acme,Tahoma,sans-serif;\n";
1101    retVal += "    list-style-type:none;margin:0;padding:0;overflow:hidden;\n";
1102    retVal += "}\n";
1103    retVal += "nav ul li a{\n";
1104    retVal += "    display:inline; font-family:'Noto Sans',Tahoma,sans-serif;font-size:0.7em;\n";
1105    retVal += "    color:#ddf!important; padding:3px 5px;float: left;\n";
1106    retVal += "}\n";
1107    retVal += "nav ul li a:hover{\n";
1108    retVal += "    color:#fff!important; background-color:#448;text-shadow: 0 0 3px #00F;\n";
1109    retVal += "    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.2);\n";
1110    retVal += "    transition: all 200ms ease-out;\n";
1111    retVal += "}\n";
1112    retVal += "\n";
1113    retVal += "\n";
1114    retVal += "a {text-decoration: none;}\n";
1115    retVal += "a:hover {color:#000!important; background-color:#fafaff;}\n";
1116    retVal += "a:link {text-decoration: none; color: #337; }\n";
1117    retVal += "a:visited { text-decoration:none; color: #404; }\n";
1118    retVal += "a:active { text-decoration:none;color: #228;  }\n";
1119    retVal += "\n";
1120    retVal += "div.inline { float:left; vertical-align: middle; }\n";
1121    retVal += ".middle { left:0;width:50%;text-align:center; vertical-align: middle; }\n";
1122    retVal += ".float-left{ float:left!important}\n";
1123    retVal += ".float-right{ float:right!important}\n";
1124    retVal += ".visibleDiv {\n";
1125    retVal += "    position: fixed;\n";
1126    retVal += "    border: solid 1px #046;\n";
1127    retVal += "    vertical-align: middle;\n";
1128    retVal += "    background: #224;\n";
1129    retVal += "    text-align: center;\n";
1130    retVal += "}\n";
1131    retVal += ".topLeft { top: 5px; left: 5px; }\n";
1132    retVal += ".topRight { top: 5px; right: 76px; } /* this needs to be the same as the album size +5 */\n";
1133    retVal += ".topRightAlbum { top: 5px; right: 5px; margin:0px 0px 0px 0px ;}\n";
1134    retVal += ".shadowed { top: 5px; right: 5px; margin:0px 0px 0px 0px ; box-shadow: -6px 12px 4px 0px RGBA(24, 0, 255, 0.5);}\n";
1135    retVal += ".bottomLeft { bottom: 5px; left: 5px; }\n";
1136    retVal += ".bottomRight {  bottom: 5px; right: 5px;}\n";
1137    retVal += ".playerSpacer{ margin-right: 285px; }\n";
1138    retVal += ".navSpacer{ margin-top: 85px; }\n";
1139    retVal += ".navClosed {  max-height: 55px;overflow:hidden;}\n";
1140    retVal += "\n";
1141    retVal += ".rotate90 {\n";
1142    retVal += "    -webkit-transform: rotate(90deg);\n";
1143    retVal += "    -moz-transform: rotate(90deg);\n";
1144    retVal += "    -o-transform: rotate(90deg);\n";
1145    retVal += "    -ms-transform: rotate(90deg);\n";
1146    retVal += "    transform: rotate(90deg);\n";
1147    retVal += "}.rotate-90 {\n";
1148    retVal += "    -webkit-transform: rotate(270deg);\n";
1149    retVal += "    -moz-transform: rotate(270deg);\n";
1150    retVal += "    -o-transform: rotate(270deg);\n";
1151    retVal += "    -ms-transform: rotate(270deg);\n";
1152    retVal += "    transform: rotate(270deg);\n";
1153    retVal += "}\n";
1154    retVal += "a.coverMetadata:hover {\n";
1155    retVal += "  background:#005;\n";
1156    retVal += "  color:#99f;\n";
1157    retVal += "}\n";
1158    retVal += ".songtip {\n";
1159    retVal += "    position: relative;\n";
1160    retVal += "}\n";
1161    retVal += ".songtip .songtiptextTop {\n";
1162    retVal += "      visibility: hidden;\n";
1163    retVal += "      width: 240px;\n";
1164    retVal += "      bottom: 100%;\n";
1165    retVal += "      left: 50%;\n";
1166    retVal += "      margin-left: -120px; /* Use half of the width (240/2 = 120), to center the tooltip */\n";
1167    retVal += "      background-color: #9999cc;\n";
1168    retVal += "      color: #005;\n";
1169    retVal += "      text-align: center;\n";
1170    retVal += "      border-radius: 6px;\n";
1171    retVal += "      padding: 3px 0;\n";
1172    retVal += "      font-size: 0.7em;\n";
1173    retVal += "  \n";
1174    retVal += "      /* Position the tooltip */\n";
1175    retVal += "      position: absolute;\n";
1176    retVal += "      z-index: 1;\n";
1177    retVal += "}\n";
1178    retVal += ".songtip .songtiptext {\n";
1179    retVal += "      visibility: hidden;\n";
1180    retVal += "      top: -5px;\n";
1181    retVal += "      left: 105%;\n";
1182    retVal += "      background-color: #9999cc;\n";
1183    retVal += "      color: #005;\n";
1184    retVal += "      text-align: center;\n";
1185    retVal += "      border-radius: 6px;\n";
1186    retVal += "      padding: 3px 0;\n";
1187    retVal += "      font-size: 0.6em;\n";
1188    retVal += "  \n";
1189    retVal += "      /* Position the tooltip */\n";
1190    retVal += "      position: absolute;\n";
1191    retVal += "      z-index: 1;\n";
1192    retVal += "}\n";
1193    retVal += ".songtip:hover .songtiptextTop {\n";
1194    retVal += "      visibility: visible;\n";
1195    retVal += "}\n";
1196    retVal += ".songtip:hover .songtiptext {\n";
1197    retVal += "      visibility: visible;\n";
1198    retVal += "}\n";
1199    retVal += ".currentPlayingSong {  background: linear-gradient(141deg, #00f6ff00 0%, #1fdba666 60%, #2c98e8 85%); opacity: 0.95; }\n\n";
1200    retVal += "#coverMetadata {\n";
1201    retVal += "  background-color:#004;\n";
1202    retVal += "  -moz-border-radius:4px;\n";
1203    retVal += "  -webkit-border-radius:4px;\n";
1204    retVal += "  color:#fff;\n";
1205    retVal += "  padding:1px;\n";
1206    retVal += "  font-family:'Noto Sans', tahoma, helvetica, arial, verdana;\n";
1207    retVal += "}\n";
1208    retVal += "#coverMetadata  a {\n";
1209    retVal += "  background:#004;\n";
1210    retVal += "  color:#bbf;\n";
1211    retVal += "}\n";
1212    retVal += "#lastfmRecentPlaysModal {\n";
1213    retVal += "  background-color:#000093;\n";
1214    retVal += "  -moz-border-radius:4px;\n";
1215    retVal += "  -webkit-border-radius:4px;\n";
1216    retVal += "  color:#fff;\n";
1217    retVal += "  padding:1px;\n";
1218    retVal += "  margin-top: 2%;\n";
1219    retVal += "  font-family:'Noto Sans', tahoma, helvetica, arial, verdana;\n";
1220    retVal += "  font-weight:bold;\n";
1221    retVal += "  /*font-size: 80%;*/\n";
1222    retVal += "  /*width:200px;*/\n";
1223    retVal += "  width:60%;\n";
1224    retVal += "  height:90%;\n";
1225    retVal += "  margin-left:20%;\n";
1226    retVal += "}\n";
1227    retVal += "#lastfmRecentPlays{\n";
1228    retVal += "  color:#000;\n";
1229    retVal += "  font-family:'Noto Sans', tahoma, helvetica, arial, verdana;\n";
1230    retVal += "}\n";
1231    retVal += "#lastfmRecentPlaysModal td{\n";
1232    retVal += "  color:#000;\n";
1233    retVal += "  font-family:'Noto Sans', tahoma, helvetica, arial, verdana;\n";
1234    retVal += "}\n";
1235    Util.writeStringToFile(retVal, topDirFilename+SYSTEM_FILE_SEPERATOR+"mMaker.css");
1236    System.out.println("Writing CSS file "+topDirFilename+SYSTEM_FILE_SEPERATOR+"mMaker.css");
1237
1238    retVal = "<link rel=\"stylesheet\"\n";
1239    retVal += "      type=\"text/css\"\n";
1240    retVal += "      href=\"/mMaker.css\"\n";
1241    retVal += "      title=\"mMakerStyle\">";
1242    Util.writeStringToFile(retVal, topDirFilename+SYSTEM_FILE_SEPERATOR+"css.html");
1243
1244    return retVal;
1245  }
1246
1247
1248  /** Parses the TOP dir and reads in all the snd subirs creating Metadata files as is recurses. **/
1249  public void createHtmlFiles(String topDirFilename)
1250  {
1251    String retVal = "<div>\n";
1252
1253    retVal += "</div>";
1254    Util.writeStringToFile(retVal, topDirFilename+SYSTEM_FILE_SEPERATOR+"album.html");
1255
1256  }
1257
1258
1259  /** Parses the TOP dir and reads in all the snd subirs creating Metadata files as is recurses. **/
1260  public String getHtmlDiv(String topDirFilename)
1261  {
1262    String retVal = "";
1263    return retVal;
1264  }
1265
1266
1267  /** Cobbles together the meta-data information about this Artist Directory in a JSON string. **/
1268  public String toMetaJsonTopDir(){return toMetaJsonTopDir(false, DirFileRef.DirState.LONG);}
1269
1270
1271  /** Cobbles together the meta-data information about this TOP Directory in a JSON string.
1272  * The JSON this is representing is as Follows:<pre>
1273  * {
1274  *   "dirFile": "/home/tgutwin/Music",
1275  *   "dirType": "TOPDIR",
1276  *   "dirState": "LONG",
1277  *   "refKey": "0",
1278  *   "numSndDirs": 2,
1279  *   "sndDirs": [
1280  *     {
1281  *         "refKey": "0",
1282  *         "dirFile": "ogg",
1283  *         "dirType": "SNDROOT",
1284  *         "dirState": "LONG"
1285  *     },
1286  *     {
1287  *         "refKey": "1",
1288  *         "dirFile": "mp3",
1289  *         "dirType": "SNDROOT",
1290  *         "dirState": "LONG"
1291  *     }
1292  *   ]
1293  * }
1294  * </pre>
1295    **/
1296  public String toMetaJsonTopDir(boolean recurseDirs, DirFileRef.DirState dirState)
1297  {
1298    String retVal = "";
1299
1300    int sndNum = 0;
1301    int albNum = 0;
1302    javax.json.JsonArrayBuilder sndArrayBuilder = javax.json.Json.createArrayBuilder();
1303    javax.json.JsonArrayBuilder artistArrayBuilder = javax.json.Json.createArrayBuilder();
1304
1305    for(File currSnd : sndDirFiles_)
1306    {
1307      javax.json.JsonObject jsonSndObject = javax.json.Json.createObjectBuilder()
1308                            .add("refKey", ""+sndNum++)
1309                            .add("dirFile", currSnd.getName())
1310                            .add("dirType", DirFileRef.DirType.SNDROOT.typeStr)
1311                            .add("dirState", dirState.getStateStr()) // this needs to be based on parsing
1312                          .build();
1313      sndArrayBuilder.add( jsonSndObject);
1314      //arrayBuilder.add( currArt.toMetaJsonObject());
1315    }
1316    javax.json.JsonArray sndArray = sndArrayBuilder.build();
1317
1318    for(Artist currArt : getArtists(true))
1319    {
1320      javax.json.JsonObject jsonArtistObject = javax.json.Json.createObjectBuilder()
1321                            .add(Util.right(currArt.getRefKeyString(),4), currArt.artistName())
1322                            .add("musicBrainzID", currArt.getMusicBrainzID() )
1323                          .build();
1324      //jsonArtistObject=currArt.toMetaJsonObject();  // get the FULL details from Artists
1325      artistArrayBuilder.add( jsonArtistObject);
1326      //arrayBuilder.add( currArt.toMetaJsonObject());
1327    }
1328
1329    javax.json.JsonArray artArray = artistArrayBuilder.build();
1330
1331    javax.json.JsonObjectBuilder joBuilder = javax.json.Json.createObjectBuilder();
1332        joBuilder.add("dirFile", getTunesDirPath() );
1333        joBuilder.add("dirType", DirFileRef.DirType.TOPDIR.typeStr);
1334        joBuilder.add("dirState", dirState.getStateStr()); // this needs to be based on parsing
1335        joBuilder.add("refKey", getRefKeyString() );
1336        joBuilder.add("numSndDirs", sndNum);
1337        joBuilder.add("sndDirs", sndArray );
1338
1339    if(recurseDirs)
1340    {
1341        joBuilder.add("numArtists", getNumberOfArtists() );
1342        joBuilder.add("artists", artArray );
1343    }
1344    javax.json.JsonObject json = joBuilder.build();
1345
1346    retVal = prettyPrint(json);
1347    //retVal = json.toString();
1348
1349    return retVal;
1350  }
1351
1352
1353  /** Cobbles together the meta-data information about this SND sub-Directory in a JSON string.
1354    **/
1355  public String toMetaJsonSndDir(String currSnd, int refKey)
1356  {
1357    String retVal = "";
1358
1359    int sndNum = 0;
1360    int albNum = 0;
1361
1362    javax.json.JsonArrayBuilder artistArrayBuilder = javax.json.Json.createArrayBuilder();
1363
1364    for(Artist currArt : getArtists(true))
1365    {
1366      javax.json.JsonObject jsonArtistObject = javax.json.Json.createObjectBuilder()
1367                            .add("refKey", Util.right(currArt.getRefKeyString(),4))
1368                            .add("dirFile", currArt.getArtistDir().substring(currArt.getArtistDir().lastIndexOf(SYSTEM_FILE_SEPERATOR)+1))
1369                            .add("dirType", DirFileRef.DirType.ARTIST.typeStr)
1370                            .add("dirState", DirFileRef.DirState.LONG.stateStr)
1371                            .add("name", currArt.artistName())
1372                            .add("shortName", currArt.artistName(true))
1373                            .add("musicBrainzID", currArt.getMusicBrainzID() )
1374                          .build();
1375      //jsonArtistObject=currArt.toMetaJsonObject();  // get the FULL details from Artists
1376      artistArrayBuilder.add( jsonArtistObject);
1377      //arrayBuilder.add( currArt.toMetaJsonObject());
1378    }
1379
1380    javax.json.JsonArray artArray = artistArrayBuilder.build();
1381
1382    javax.json.JsonObject json = javax.json.Json.createObjectBuilder()
1383        .add("dirFile", currSnd )
1384        .add("dirType", DirFileRef.DirType.SNDROOT.typeStr )
1385        .add("dirState",  DirFileRef.DirState.LONG.stateStr )  // this needs to be based on parsing
1386        .add("refKey", ""+refKey )
1387        .add("parentRefKey", ""+refKey )
1388        .add("numArtists", getNumberOfArtists() )
1389        .add("artists", artArray )
1390      .build();
1391
1392    retVal = prettyPrint(json);
1393    //retVal = json.toString();
1394
1395    return retVal;
1396  }
1397
1398
1399  /** NOT USED - See Artist class . Cobbles together the meta-data information about this Artist Directory in a JSON string. **/
1400  public String toMetaJsonArtDir() // NOT USED
1401  {
1402    //
1403    // NOT USED
1404    //
1405    String retVal = "";
1406
1407    int sndNum = 0;
1408    int albNum = 0;
1409    javax.json.JsonArrayBuilder sndArrayBuilder = javax.json.Json.createArrayBuilder();
1410    javax.json.JsonArrayBuilder artistArrayBuilder = javax.json.Json.createArrayBuilder();
1411
1412    for(File currSnd : sndDirFiles_)
1413    {
1414      javax.json.JsonObject jsonSndObject = javax.json.Json.createObjectBuilder()
1415                            .add(""+sndNum++, currSnd.getAbsolutePath())
1416                          .build();
1417      sndArrayBuilder.add( jsonSndObject);
1418      //arrayBuilder.add( currArt.toMetaJsonObject());
1419    }
1420    javax.json.JsonArray sndArray = sndArrayBuilder.build();
1421
1422    for(Artist currArt : getArtists(true))
1423    {
1424      javax.json.JsonObject jsonArtistObject = javax.json.Json.createObjectBuilder()
1425                            .add(Util.right(currArt.getRefKeyString(),3), currArt.artistName())
1426                            .add("musicBrainzID", currArt.getMusicBrainzID() )
1427                          .build();
1428      artistArrayBuilder.add( jsonArtistObject);
1429      //arrayBuilder.add( currArt.toMetaJsonObject());
1430    }
1431
1432    javax.json.JsonArray artArray = artistArrayBuilder.build();
1433
1434    javax.json.JsonObject json = javax.json.Json.createObjectBuilder()
1435        .add("dirFile", getTunesDirPath() )
1436        .add("dirType", DirFileRef.DirType.ARTIST.typeStr )
1437        .add("dirState",  DirFileRef.DirState.LONG.stateStr )  // this needs to be based on parsing
1438        .add("refKey", getRefKeyString() )
1439        .add("numSndDirs", sndNum)
1440        .add("sndDirs", sndArray )
1441        .add("numArtists", getNumberOfArtists() )
1442        .add("artists", artArray )
1443      .build();
1444
1445    retVal = prettyPrint(json);
1446
1447    return retVal;
1448  }
1449
1450
1451  /** helper to format json string - This is the preferredformatter. **/
1452  public static String prettyPrint(JsonStructure json)
1453  {
1454    return jsonFormat(json, JsonGenerator.PRETTY_PRINTING);
1455  }
1456
1457
1458  /** helper to format json string **/
1459  public static String jsonFormat(JsonStructure json, String... options)
1460  {
1461      java.io.StringWriter stringWriter = new java.io.StringWriter();
1462      java.util.Map<String, Boolean> config = buildConfig(options);
1463      JsonWriterFactory writerFactory = Json.createWriterFactory(config);
1464      JsonWriter jsonWriter = writerFactory.createWriter(stringWriter);
1465
1466      jsonWriter.write(json);
1467      jsonWriter.close();
1468
1469      return stringWriter.toString();
1470  }
1471
1472
1473  private static java.util.Map<String, Boolean> buildConfig(String... options)
1474  {
1475      java.util.Map<String, Boolean> config = new HashMap<String, Boolean>();
1476
1477      if (options != null) {
1478          for (String option : options) {
1479              config.put(option, true);
1480          }
1481      }
1482
1483      return config;
1484  }
1485
1486
1487  public Vector <Artist> getArtists(){ return  getArtists(false);}
1488  public Vector <Artist> getArtists(boolean sorted)
1489  {
1490    if(sorted) artists_.sort(Artist.ArtistComparatorIgnoreCase );
1491    return  artists_;
1492  }
1493
1494
1495  public String[] getArtistNames(){return getArtistNames(false);}
1496
1497
1498  public String[] getArtistNames(boolean removeSpaces)
1499  {
1500    String [] retVal = new String[artists_.size()];
1501    for(int i=0;i<artists_.size();i++){retVal[i]=artists_.get(i).artistName(removeSpaces);}
1502    return retVal;
1503  }
1504
1505
1506  public int getNumberOfArtists() {return artists_.size();  }
1507
1508
1509  public int getNumberOfAlbums()
1510  {
1511    int retVal = 0;
1512    for(int i=0;i<artists_.size();i++){retVal+=artists_.get(i).getNumberOfAlbums();}
1513    return retVal;
1514  }
1515
1516
1517  public int getNumberOfAlbums(String artist)
1518  {
1519    int retVal = 0;
1520    // not implemented
1521    //for(int i=0;i<artists_.size();i++){retVal+=artists_.get(i).getNumberOfAlbums();}
1522    return retVal;
1523  }
1524
1525
1526  public int getNumberOfSongs()
1527  {
1528    int retVal = 0;
1529    for(int i=0;i<artists_.size();i++){retVal+=artists_.get(i).getNumberOfSongs();}
1530    return retVal;
1531  }
1532
1533
1534  /**
1535    * Set Method for class field 'tunesSubPath_'.
1536    *
1537    * @param tunesSubPath is the value to set this class field to.
1538    *
1539    **/
1540  public static void setTunesSubPath(String tunesSubPath)
1541  {
1542    tunesSubPath_ = tunesSubPath;
1543  }  // setTunesSubPath Method
1544
1545
1546  /**
1547    * Get Method for class field 'tunesSubPath_'.
1548    *
1549    * @return String - The value the class field 'tunesSubPath_'.
1550    *
1551    **/
1552  public static String getTunesSubPath()
1553  {
1554    return tunesSubPath_;
1555  }  // getTunesSubPath Method
1556
1557
1558  /**
1559    * Gets the full file path to the tunes dir.
1560    *
1561    * @return String - the full file path to the tunes dir.
1562    *
1563    **/
1564  public String getTunesDirPath()
1565  {
1566    return tunesRootPath_;
1567  }  // getWebappHomePath Method
1568
1569
1570  /** Performs some simple removal of extra line seperators. **/
1571  private String cleanJSON(StringBuilder sb)
1572  {
1573    String retVal = sb.toString();
1574    retVal = Util.tokenReplace(retVal, ","+SYSTEM_LINE_SEPERATOR+"   ,", ",");
1575    retVal = Util.tokenReplace(retVal, ","+SYSTEM_LINE_SEPERATOR+"  ,", ",");
1576    retVal = Util.tokenReplace(retVal, ","+SYSTEM_LINE_SEPERATOR+" ,", ",");
1577    retVal = Util.tokenReplace(retVal, ","+SYSTEM_LINE_SEPERATOR+",", ",");
1578    return retVal;
1579  }
1580
1581
1582    /** Lists all songs in all artists albums in a JSON string.
1583      <pre>
1584      [
1585        {
1586   url: "http://warp4.webarts.bc.ca/tunes/mythTunes/3DoorsDown/3DoorsDown/3DoorsDown03-It'sNotMyTime.ogg",
1587   file: "3DoorsDown03-It'sNotMyTime.ogg",
1588   title: "It'sNotMyTime",
1589   album: "3DoorsDown",
1590   artist: "3DoorsDown",
1591   number: "03",
1592   index: "26"
1593  },
1594  {
1595   url: "http://warp4.webarts.bc.ca/tunes/mythTunes/3DoorsDown/3DoorsDown/3DoorsDown04-LetMeBeMyself.ogg",
1596   file: "3DoorsDown04-LetMeBeMyself.ogg",
1597   title: "LetMeBeMyself",
1598   album: "3DoorsDown",
1599   artist: "3DoorsDown",
1600   number: "04",
1601   index: "27"
1602  },
1603  {
1604   url: "http://warp4.webarts.bc.ca/tunes/mythTunes/3DoorsDown/3DoorsDown/3DoorsDown05-Pages.ogg",
1605   file: "3DoorsDown05-Pages.ogg",
1606   title: "Pages",
1607   album: "3DoorsDown",
1608   artist: "3DoorsDown",
1609   number: "05",
1610   index: "28"
1611  }
1612      ]
1613      </pre>
1614    **/
1615    public String toJsonString()
1616    {
1617      StringBuilder retVal = new StringBuilder("[");
1618      int songCount = 0; int artistCount = 0; int tot = artists_.size();
1619      retVal.append(SYSTEM_LINE_SEPERATOR);
1620
1621      for(Artist currArtist : artists_)
1622      {
1623        if(currArtist.getNumberOfSongs()>0)
1624        {
1625          retVal.append(currArtist.toJsonString(songCount));
1626          if(++artistCount<tot)retVal.append("  ,");  // End Artist "+ currArtist.name(true));
1627          retVal.append(SYSTEM_LINE_SEPERATOR);
1628          songCount+=currArtist.getNumberOfSongs();
1629        }
1630        else ++artistCount;
1631      }
1632      retVal.append("]");
1633      return cleanJSON(retVal);
1634    }
1635
1636}
1637
1638
1639/* *************************************** */
1640/**
1641  * DirFileRef a Template/super class Deserialized Object for the MusicMaker music directories JSON meta data - (use it to be extended for specific subdirectories) .
1642  *
1643  * This class included 2 enums to represent a {@link  DirFileRef.DirType  DirType} and a {@link  DirFileRef.DirState  DirState } for use by this object or {@link  DirFileRef.DirType  DirType} and a {@link  MusicMakerTunesHelper  MusicMakerTunesHelper }MusicMaker.<br>
1644  * The JSON this is representing is as Follows:<pre>
1645  * {
1646  *   "dirFile": "/home/tgutwin/Music",
1647  *   "dirType": "TOPDIR",
1648  *   "dirState": "LONG",
1649  *   "refKey": "0"
1650  * }
1651  * </pre>
1652  * NOTE: that the dirType and dirState class vars are represented with the {@link  DirFileRef.DirType  DirType} and a {@link  DirFileRef.DirState  DirState } enum types within this super class.
1653  **/
1654class DirFileRef
1655{
1656  /** An enum TYPE for the allowed Directory Types defining the TYPE for the dirType  class var. **/
1657  public enum DirType
1658  {
1659    UNDEFINED (0),  //calls constructor with value 0 step
1660    TOPDIR (1),  //calls constructor with value 1 step
1661    SNDROOT (2),  //calls constructor with value 2
1662    ARTIST (4),       //calls constructor with value 4
1663    ALBUM (8),     //calls constructor with value 8
1664    RELEASE (16),       //calls constructor with value 16
1665    ; // semicolon needed when fields / methods follow
1666    public final int type ;
1667    public final String typeStr ;
1668    private DirType(int type) {
1669      switch (type) {
1670        case 1: this.type = type;this.typeStr = "TOPDIR"; break;
1671        case 2: this.type = type;this.typeStr = "SNDROOT";  break;
1672        case 4: this.type = type;this.typeStr = "ARTIST";  break;
1673        case 8: this.type = type;this.typeStr = "ALBUM";  break;
1674        case 16: this.type = type;this.typeStr = "RELEASE";  break;
1675        default: this.type = 0; this.typeStr = "UNDEFINED";
1676      }
1677    }
1678    private DirType(String typeStr) {
1679        switch (typeStr) {
1680          case "TOPDIR": this.type = 1; this.typeStr = typeStr; break;
1681          case "SNDROOT": this.type = 2; this.typeStr = typeStr;  break;
1682          case "ARTIST": this.type = 4; this.typeStr = typeStr;  break;
1683          case "ALBUM": this.type = 8; this.typeStr = typeStr;  break;
1684          case "RELEASE":  this.type = 16; this.typeStr = typeStr;  break;
1685          default: this.type = 0; this.typeStr = "UNDEFINED";
1686        }
1687    }
1688    public int getType() {
1689      return this.type;
1690    }
1691    public String getTypeStr() {
1692      return this.typeStr;
1693    }
1694  }
1695
1696  /** An Enum for the allowed states for the directory file - either long or short. It is used to defining the TYPE for the dirState  class var.
1697    **/
1698  public enum DirState
1699  {
1700    UNDEFINED (0),  //calls constructor with value 0 step
1701    SHORT (1),  //calls constructor with value 1 step
1702    LONG (2),  //calls constructor with value 2
1703    ; // semicolon needed when fields / methods follow
1704    public final int state;
1705    public final String stateStr ;
1706    private DirState(int state) {
1707        switch (state) {
1708          case 1: this.state = state;this.stateStr = "SHORT"; break;
1709          case 2: this.state = state;this.stateStr = "LONG";  break;
1710          default: this.state = 0;this.stateStr = "UNDEFINED";
1711        }
1712    }
1713    /*private DirState(String stateStr) {
1714        switch (stateStr) {
1715          case "SHORT": this.state = SHORT; break;
1716          case "LONG": this.state = LONG; break;
1717          default: this.state = UNDEFINED;
1718        }
1719    }*/
1720    public int getState() {
1721      return this.state;
1722    }
1723    public String getStateStr() {
1724      return this.stateStr;
1725    }
1726  }
1727
1728  String refKey = "";
1729  String dirFile = "";
1730  DirType dirType = DirType.UNDEFINED;
1731  DirState dirState = DirState.UNDEFINED;
1732
1733
1734  /** Constructs with default values - UNDEFINED. **/
1735  public DirFileRef(){  }
1736  /** Constructs with passed in values . **/
1737  public DirFileRef(String refKey, String dirFile, DirType dirType, DirState dirState)
1738  {
1739   this.refKey=refKey;
1740   this.dirFile=dirFile;
1741   this.dirType=dirType;
1742   this.dirState=dirState;
1743  }
1744
1745
1746  public void setRefKey(String refKey){this.refKey = refKey;}
1747  public String getRefKey(){return refKey;}
1748  public void setDirFile(String dirFile){this.dirFile = dirFile;}  // setDirFile Method
1749  public String getDirFile(){return dirFile;}  // getDirFile Method
1750  public void setDirType(DirType dirType){this.dirType = dirType;}
1751  public DirType getDirType(){return dirType;}
1752  public void setDirState(DirState dirState){this.dirState = dirState;}
1753  public DirState getDirState(){return dirState;}
1754
1755  @Override
1756  public String toString()
1757  {
1758    String retVal = "";
1759    Gson gson = new GsonBuilder()
1760                     .setPrettyPrinting()
1761                     .create();
1762    retVal = gson.toJson(this);
1763    return retVal;
1764  }
1765}
1766
1767
1768/** The Deserialized object for the MusicMaker Top directory. It extends the Base/Super DirFileRef class.
1769  *
1770  * The JSON this is representing is as Follows:<pre>
1771  * {
1772  *   "dirFile": "/home/tgutwin/Music",
1773  *   "dirType": "TOPDIR",
1774  *   "dirState": "LONG",
1775  *   "refKey": "0",
1776  *   "numSndDirs": 2,
1777  *   "sndDirs": [
1778  *     {
1779  *         "refKey": "0",
1780  *         "dirFile": "ogg",
1781  *         "dirType": "SNDROOT",
1782  *         "dirState": "LONG"
1783  *     },
1784  *     {
1785  *         "refKey": "1",
1786  *         "dirFile": "mp3",
1787  *         "dirType": "SNDROOT",
1788  *         "dirState": "LONG"
1789  *     }
1790  *   ]
1791  * }
1792  * </pre>
1793  **/
1794class TopSndDirMetadata extends DirFileRef
1795{
1796  public int numSndDirs = 0;
1797  public DirFileRef [] sndDirs = null;
1798
1799
1800  public TopSndDirMetadata(){  }
1801  public TopSndDirMetadata(String refKey, String dirFile, DirFileRef.DirType dirType, DirFileRef.DirState dirState, int numSndDirs, DirFileRef [] sndDirs)
1802  {
1803   super(refKey, dirFile, dirType, dirState);
1804
1805   this.dirType=DirFileRef.DirType.TOPDIR; // overRide the default
1806   this.numSndDirs=numSndDirs;
1807   this.sndDirs=sndDirs;
1808  }
1809
1810  public  void setNumSndDirs(int numSndDirs){this.numSndDirs = numSndDirs;}
1811  public int getNumSndDirs(){return numSndDirs;}
1812  public  void setSndDirs(DirFileRef [] sndDirs){this.sndDirs = sndDirs;}
1813  public DirFileRef [] getSndDirs(){return sndDirs;}
1814
1815  @Override
1816  public String toString()
1817  {
1818    String retVal = "";
1819    Gson gson = new GsonBuilder()
1820                     .setPrettyPrinting()
1821                     .create();
1822    retVal = gson.toJson(this);
1823    return retVal;
1824  }
1825}
1826
1827
1828/** The Deserialized object for the MusicMaker SND directory (typically ogg, mp3 or flac sub-dir inside the TOP SND DIR. It extends the Base/Super DirFileRef class. */
1829class SndDirMetadata extends DirFileRef
1830{
1831  public int numArtist = 0;
1832  public ArtistDirRef [] artists = null;
1833
1834  public SndDirMetadata(){  }
1835  public SndDirMetadata(String refKey, String dirFile, DirFileRef.DirType dirType, DirFileRef.DirState dirState, int numArtist, ArtistDirRef [] artists)
1836  {
1837   super(refKey, dirFile, dirType, dirState);
1838
1839   this.dirType=DirFileRef.DirType.SNDROOT;
1840   this.numArtist=numArtist;
1841   this.artists=artists;
1842  }
1843
1844  public  void setNumArtists(int numArtist){this.numArtist = numArtist;}
1845  public int getNumArtists(){return numArtist;}
1846  public  void setArtists(ArtistDirRef [] artists){this.artists = artists;}
1847  public ArtistDirRef [] getArtists(){return artists;}
1848
1849  @Override
1850  public String toString()
1851  {
1852    String retVal = "";
1853    Gson gson = new GsonBuilder()
1854                     .setPrettyPrinting()
1855                     .create();
1856    retVal = gson.toJson(this);
1857    return retVal;
1858  }
1859} // SndDirMetadata class
1860
1861
1862class ArtistDirRef extends DirFileRef
1863{
1864  String artistName = "";
1865  String shortArtistName = "";
1866  String urlPath = "";
1867  String musicBrainzID = "";
1868  int numAlbums = 0;
1869  public AlbumDirRef [] albums = null;
1870
1871  public ArtistDirRef(){  }
1872  public ArtistDirRef(String refKey, String dirFile, DirFileRef.DirType dirType, DirFileRef.DirState dirState,
1873                      String artistName, String shortArtistName, String urlPath, String musicBrainzID ,
1874                      int numAlbums, AlbumDirRef [] albums)
1875  {
1876   super(refKey, dirFile, dirType, dirState);
1877
1878   this.dirType=DirFileRef.DirType.ARTIST;
1879   this.artistName=artistName;
1880   this.shortArtistName=shortArtistName;
1881   this.urlPath=urlPath;
1882   this.musicBrainzID=musicBrainzID;
1883   this.numAlbums=numAlbums;
1884   this.albums=albums;
1885  }
1886
1887  public  void  setArtistName(String artistName){this.artistName = artistName;}
1888  public String getArtistName(){return artistName;}
1889  public  void  setShortArtistName(String shortArtistName){this.shortArtistName = shortArtistName;}
1890  public String getShortArtistName(){return shortArtistName;}
1891  public  void  setUrlPath(String urlPath){this.urlPath = urlPath;}
1892  public String getUrlPath(){return urlPath;}
1893  public  void  setNumAlbums(int numAlbums){this.numAlbums = numAlbums;}
1894  public int    getNumAlbums(){return numAlbums;}
1895  public  void          setAlbums(AlbumDirRef [] albums){this.albums = albums;}
1896  public AlbumDirRef [] getAlbums(){return albums;}
1897
1898  @Override
1899  public String toString()
1900  {
1901    String retVal = "";
1902    Gson gson = new GsonBuilder()
1903                     .setPrettyPrinting()
1904                     .create();
1905    retVal = gson.toJson(this);
1906    return retVal;
1907  }
1908}
1909
1910
1911class AlbumDirRef extends DirFileRef
1912{
1913  String albumName = "";
1914  String shortAlbumName = "";
1915  String musicBrainzID = "";
1916  String artistRefKey = "";
1917  int numSongs = 0;
1918  public SongRef [] songs = null;
1919
1920  public AlbumDirRef(){  }
1921  public AlbumDirRef(String refKey, String dirFile, DirFileRef.DirType dirType, DirFileRef.DirState dirState,
1922                      String albumName, String shortAlbumName, String musicBrainzID ,
1923                      String artistRefKey,
1924                      int numAlbums, SongRef [] songs)
1925  {
1926   super(refKey, dirFile, dirType, dirState);
1927
1928   this.dirType=DirFileRef.DirType.ARTIST;  // over-ride to force this to ARTIST
1929   this.dirType=DirFileRef.DirType.ARTIST;  // over-ride to force this to ARTIST
1930   this.albumName=albumName;
1931   this.shortAlbumName=shortAlbumName;
1932   this.musicBrainzID=musicBrainzID;
1933   this.artistRefKey=artistRefKey;
1934   this.numSongs=numSongs;
1935   this.songs=songs;
1936  }
1937
1938  public void   setAlbumName(String albumName){this.albumName = albumName;}
1939  public String getAlbumName(){return albumName;}
1940  public void   setShortAlbumName(String shortAlbumName){this.shortAlbumName = shortAlbumName;}
1941  public String getShortAlbumName(){return shortAlbumName;}
1942  public void   setMusicBrainzID(String musicBrainzID){this.musicBrainzID = musicBrainzID;}
1943  public String getMusicBrainzID(){return musicBrainzID;}
1944  public void   setArtistRefKey(String artistRefKey){this.artistRefKey = artistRefKey;}
1945  public String getArtistRefKey(){return artistRefKey;}
1946  public void   setNumSongs(int numSongs){this.numSongs = numSongs;}
1947  public int    getNumSongs(){return numSongs;}
1948  public void       setSongs(SongRef [] songs){this.songs = songs;}
1949  public SongRef [] getSongs(){return songs;}
1950
1951  @Override
1952  public String toString()
1953  {
1954    String retVal = "";
1955    Gson gson = new GsonBuilder()
1956                     .setPrettyPrinting()
1957                     .create();
1958    retVal = gson.toJson(this);
1959    return retVal;
1960  }
1961}
1962
1963
1964class SongRef extends DirFileRef
1965{
1966  String title = "";
1967  int trackNum = 0;
1968  String musicBrainzID = "";
1969
1970  public SongRef(){  }
1971  public SongRef(String refKey, String dirFile, DirFileRef.DirType dirType, DirFileRef.DirState dirState,
1972                 String title, int trackNum, String musicBrainzID )
1973  {
1974   super(refKey, dirFile, dirType, dirState);
1975
1976   this.dirType=DirFileRef.DirType.ARTIST;
1977   this.title=title;
1978   this.trackNum=trackNum;
1979   this.musicBrainzID=musicBrainzID;
1980  }
1981
1982  public void   setTitle(String title){this.title = title;}
1983  public String getTitle(){return title;}
1984  public void   setMusicBrainzID(String musicBrainzID){this.musicBrainzID = musicBrainzID;}
1985  public String getMusicBrainzID(){return musicBrainzID;}
1986  public void   setTrackNum(int trackNum){this.trackNum = trackNum;}
1987  public int    getTrackNum(){return trackNum;}
1988
1989  @Override
1990  public String toString()
1991  {
1992    String retVal = "";
1993    Gson gson = new GsonBuilder()
1994                 .setPrettyPrinting()
1995                 .create();
1996    retVal = gson.toJson(this);
1997    return retVal;
1998  }
1999}
2000
2001