/* * file: com.fivevoltlogic.mytunes.sync.Export.java * author: davidfmiller http://www.fivevoltlogic.com * version: v0.1.1 * about: creates an XML file that can be parsed * by com.fivevoltlogic.mytunes.sync.LiteLibrary with the intention * of having the playlists described in the file duplicated in another * iTunes library * * * history: v0.1 December 1, 2004 * - initial release complete * * v0.1.1 march 12, 2005 * - changed default name of output file from "mytunes.xml" to * "playlists.xml" * - changed default beahviour; now sends the document to stdout if * no destination has been specified (Export now takes an * OutputStream object instead of a File in the constructor) */ package com.fivevoltlogic.mytunes.sync; /* core java libraries */ import org.w3c.dom.*; import javax.xml.parsers.*; import java.io.*; import java.util.*; import java.net.*; /* apache libs */ import org.apache.commons.cli.*; /* fvl libraries */ import com.fivevoltlogic.mytunes.filters.*; import com.fivevoltlogic.mytunes.*; import com.fivevoltlogic.tools.xml.*; import com.fivevoltlogic.tools.*; public class Export extends com.fivevoltlogic.mytunes.Chord { private Document doc; // the XML document that will be creaated private Element tunes; // reference to the document element public static String version = "0.2"; private String id; // the id of the user (defaults to UNIX username) private OutputStream out; // the file that will be saved private File xslt; // the file that will be used as an XSLT stylesheet (optional) /** Default constructor. The document's id and path are set to their defaults, and no XSLT file is used */ public Export(String id, OutputStream out) throws MyTunesException { super(); this.id = id; this.out = out; } /** * Constructor. Same as above, except for the inclusion of the XSLT file. */ public Export(String id, OutputStream out, File xslt) throws MyTunesException { super(); this.id = id; this.out = out; this.xslt = xslt; } public static void main(String[] args) { InputStream in = System.in; // used to read in the source library file String pathToLib = ""; // location of source library file String id = new SandBox().getUserName(); // who created this file? String pathToFile = ""; // where should it be created? String pathToXSLT = ""; // should an xslt stylesheet be // added to the document? // if so, where is it located? Options options = new Options(); options.addOption( OptionBuilder.withArgName("path/to/library.xml") .hasArg() .hasOptionalArg() .withLongOpt("library") .withDescription("path to the source library XML file") .create("l") ); options.addOption( OptionBuilder.withArgName("/path/to/stylesheet.xslt") .hasArg() .withLongOpt("xslt") .withDescription("path to the xslt stylesheet") .create("x") ); options.addOption( OptionBuilder.withArgName("path/to/playlists.xml") .hasArg() .withLongOpt("destination") .withDescription("path to the resulting playlists.xml file") .create("d") ); options.addOption( OptionBuilder.withArgName("name") .hasArg() .withLongOpt("id") .withDescription("the person who created the playlist file") .create("id") ); options.addOption( OptionBuilder.withLongOpt("help") .withDescription("Show program help") .create("?") ); try { // try to load in the xml properties file located at ~/.mytunes.xml XMLProperties props = new XMLProperties( new File(FileTools.getHomeFolder(), ".mytunes.xml") ); // where the file should be located; if property sync.export.destination // doesn't exist, defaults to your desktop (~/Desktop/playlists.xml) pathToFile = props.getProperty("sync.export.destination", pathToFile); // who created this export file; if property sync.export.id doesn't exist, // defaults to your username) id = props.getProperty("sync.export.id", id); // path to XSLT file; if specifed, adds a processing directive to the // playlists.xml file to specify an XSLT stylesheet for the document if (props.containsKey("sync.export.xslt")) { pathToXSLT = props.getProperty("sync.export.xslt", ""); } if (props.containsKey("library")) { pathToLib = props.getProperty("library", ""); } } catch (Exception e) { // no properties file found; use default values } // now command-line arguments // create the parser CommandLineParser parser = new PosixParser(); try { CommandLine line = parser.parse(options, args); if (line.hasOption("?")) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("com.fivevoltlogic.mytunes.sync.Export [options] playlist1 [playlist 2 ...]",options); System.exit(0); } if (line.hasOption("l")) { pathToLib = line.getOptionValue("l"); } if (line.hasOption("x")) { pathToXSLT = line.getOptionValue("x"); } if (line.hasOption("d")) { pathToFile = line.getOptionValue("d"); } if (pathToLib == null) { in = new FileInputStream(MyTunesLibrary.getDefaultLibrary()); } else if (pathToLib == "") { in = System.in; } else { // is it a URL? if (StringTools.isURL(pathToLib)) { in = new URL(pathToLib).openStream();} // otherwise assume it's a path to a file else { in = new FileInputStream(new File(pathToLib)); } } if (line.hasOption("id")) { id = line.getOptionValue("id"); } MyTunesLibrary lib = new MyTunesLibrary(in); // for each command-line argument, create a new NameFilter object with the // arg as the parameter passed; this allows you to only export certain // playlists String filters[] = line.getArgs(); for (int i = 0; i < filters.length; i++) { lib.addFilter(new NameFilter(filters[i])); } OutputStream out; // if pathToFile has changed, use it as the destination for the document if (pathToFile == null || pathToFile == "") { out = System.out; } else { out = new FileOutputStream(new File(pathToFile)); } // if pathToXSLT has changed, add a stylesheet argument to the constructor if (! pathToXSLT.equals("")) { lib.setHandler(new Export(id, out, new File(pathToXSLT))); } else { lib.setHandler(new Export(id, out)); } lib.parse(); } catch(Exception e) { e.printStackTrace(); } } // all work is done in the onPlaylist method, so nothing is required here public void onTrack(Track t) { // do nothing } public void onStart() throws MyTunesException { try { // create a new XML document DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder domBuilder = domFactory.newDocumentBuilder(); doc = domBuilder.newDocument(); // create the root element and set its attributes Element root = doc.createElement("mytunes"); doc.appendChild(root); tunes = doc.getDocumentElement(); tunes.setAttribute("id", this.id); tunes.setAttribute("version", Export.version); tunes.setAttribute("date", new Date().toString()); } catch (ParserConfigurationException e) { throw new MyTunesException(e.getMessage()); } } public void onPlaylist(Playlist p) { // create a playlist element and append all the tracks (elements) to it Element pe = doc.createElement("playlist"); pe.setAttribute("name", p.getName()); pe.setAttribute("smart", p.isSmart() ? "true" : "false"); java.util.Iterator i = p.iterator(); while (i.hasNext()) { Track t = (Track) i.next(); Element te = doc.createElement("track"); te.setAttribute("artist", XMLTools.encode(t.getArtist())); te.setAttribute("album", XMLTools.encode(t.getAlbum())); te.setAttribute("name", XMLTools.encode(t.getName())); pe.appendChild(te); } tunes.appendChild(pe); } public void onFinish() throws MyTunesException { // if the xslt stylesheet has been specified... if (this.xslt != null) { // add it to the document as a processing instruction Node xslt = doc.createProcessingInstruction( "xml-stylesheet", "href=\"" + this.xslt + "\" type=\"text/xsl\"" ); doc.insertBefore(xslt, doc.getFirstChild()); } // send the document to its destination try { DOMSerializer s = new DOMSerializer(); s.serialize(this.doc, this.out); } catch (IOException e) { System.err.println("Error serializing document: " + e.getMessage()); } } }