All Downloads are FREE. Search and download functionalities are using the official Maven repository.

chameleon.AddToPlaylist Maven / Gradle / Ivy

There is a newer version: 1.2.1-RELEASE
Show newest version
/*
 * Copyright (c) 2008, Christophe Delory
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY CHRISTOPHE DELORY ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL CHRISTOPHE DELORY BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package chameleon;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFileChooser;

import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;

import chameleon.content.Content;
import chameleon.content.type.ContentType;
import chameleon.playlist.Media;
import chameleon.playlist.Playlist;
import chameleon.playlist.Sequence;
import chameleon.playlist.SpecificPlaylist;
import chameleon.playlist.SpecificPlaylistFactory;
import chameleon.playlist.SpecificPlaylistProvider;
import chameleon.playlist.m3u.M3U;
import chameleon.playlist.plp.PLP;
import chameleon.playlist.rss.RSSProvider;
import chameleon.xml.Version;

/**
 * Adds URLs, files and/or directories to a single playlist.
 * @version $Revision: 92 $
 * @author Christophe Delory
 */
@SuppressWarnings("PMD.SystemPrintln")
public final class AddToPlaylist
{
    /**
     * Adds a given list of URLs, files and/or directories to a single playlist.
     * 
* Usage: *
     * AddToPlaylist [options] <input-file(s)>
     * 
* @param args the program arguments. * @throws MalformedURLException if at least one of the input strings specifies an unknown protocol. * @throws IOException if an I/O exception occurs. */ public static void main(final String[] args) throws Exception { // Initializes the current project version. Transcode.buildCurrentVersion(); // May throw Exception. System.err.println("*** " + Chameleon.NAME + " AddToPlaylist v" + Version.CURRENT); System.err.println("*** " + Chameleon.COPYRIGHT); System.err.println(); final AddToPlaylist program = new AddToPlaylist(); final CmdLineParser parser = new CmdLineParser(program); try { parser.parseArgument(args); } catch (CmdLineException e) { System.err.println(e.getMessage()); System.err.println(); System.err.println("Adds URLs, files and/or directories to a (possibly new) single playlist"); System.err.println("usage: AddToPlaylist [options] "); parser.printUsage(System.err); System.err.println("Supported playlist provider types: " + program.getSupportedProviderIds()); System.exit(1); } program.run(); // May throw Exception. } /** * The playlist type, if specified. */ @Option(name="-t",usage="The output playlist type\nAllowed values: see below",metaVar="type") private volatile String _type = null; /** * Specifies if the content metadata shall be fetched, if possible. */ @Option(name="-m",usage="Fetch if possible the media content metadata") private volatile boolean _fetchContentMetadata = false; /** * The sub-directories shall be recursively scanned. */ @Option(name="-r",usage="Recursively add sub-directories contents") private volatile boolean _recursive = false; /** * The output file or URL. */ @Option(name="-o",usage="The output file or URL\nIf missing, a file save dialog is prompted\nIf the output playlist type is not specified (-t), it will be inferred from the output file name extension",metaVar="file/URL") private volatile String _output = null; /** * Specifies that the marshalled M3U playlist must use the Extension M3U format. */ @Option(name="-m3u:ext",usage="The output M3U playlist must use the Extension M3U format") private volatile boolean _extM3U = false; /** * Specifies that the output RSS shall make use of the RSS Media extension. */ @Option(name="-rss:media",usage="The output RSS playlist must use the RSS Media format") private volatile boolean _useRSSMedia = false; /** * Specifies the disk identifier of the output PLP playlist. */ @Option(name="-plp:disk",usage="The disk identifier of the output PLP playlist\nExamples: HARP, HDD",metaVar="disk") private volatile String _diskSpecifier = null; /** * The list of input files or directories. */ @Argument(usage="One or more files or directories to add to the output playlist",metaVar="input-files(s)",required=true) private volatile ArrayList _arguments = new ArrayList(); // NOPMD Avoid using implementation types; use the interface instead /** * The default no-arg constructor shall not be publicly available. */ private AddToPlaylist() { } /** * Returns a string representation of all supported {@link SpecificPlaylistProvider playlist providers}, through their identifier. * @return a string representing the list of all supported playlist providers. Shall not be null. * @see SpecificPlaylistProvider#getId */ public String getSupportedProviderIds() { final StringBuilder sb = new StringBuilder(); boolean first = true; for (SpecificPlaylistProvider provider : SpecificPlaylistFactory.getInstance().getProviders()) { if (!first) { sb.append('/'); } first = false; sb.append(provider.getId()); } return sb.toString(); } /** * Executes the required actions. * @throws MalformedURLException if at least one of the input strings specifies an unknown protocol. * @throws IOException if an I/O exception occurs. */ @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") private void run() throws Exception { SpecificPlaylistProvider provider = null; if (_type != null) { provider = SpecificPlaylistFactory.getInstance().findProviderById(_type); // Shall not throw NullPointerException because of _type. if (provider == null) { System.err.println("Unknown specific playlist type <" + _type + '>'); System.exit(1); } } String outputPath = null; File outputFile = null; URL outputUrl; if (_output == null) { final JFileChooser fc = new JFileChooser(); fc.setDialogType(JFileChooser.SAVE_DIALOG); // Shall not throw IllegalArgumentException. fc.setDialogTitle(Chameleon.NAME); fc.setFileHidingEnabled(true); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); // Shall not throw IllegalArgumentException. fc.setMultiSelectionEnabled(false); fc.setApproveButtonText("Save playlist"); //fc.setApproveButtonToolTipText(); fc.setAcceptAllFileFilterUsed(true); if (provider == null) { final ContentTypesFileFilter allFilter = new ContentTypesFileFilter("All Playlists", false); final List providers = SpecificPlaylistFactory.getInstance().getProviders(); for (SpecificPlaylistProvider p : providers) { final ContentTypesFileFilter providerFilter = new ContentTypesFileFilter("All " + p.getId() + "-like", true); providerFilter.setProvider(p); for (ContentType type : p.getContentTypes()) { final ContentTypesFileFilter typeFilter = new ContentTypesFileFilter(type.getDescription(), true); typeFilter.setProvider(p); fc.setFileFilter(typeFilter); typeFilter.addContentType(type); providerFilter.addContentType(type); allFilter.addContentType(type); } if (providerFilter.getContentTypes().size() > 1) { fc.setFileFilter(providerFilter); } } if (allFilter.getContentTypes().size() > 1) { fc.setFileFilter(allFilter); } } else { final ContentTypesFileFilter providerFilter = new ContentTypesFileFilter("All " + provider.getId() + "-like", true); providerFilter.setProvider(provider); for (ContentType type : provider.getContentTypes()) { final ContentTypesFileFilter typeFilter = new ContentTypesFileFilter(type.getDescription(), true); typeFilter.setProvider(provider); fc.setFileFilter(typeFilter); typeFilter.addContentType(type); providerFilter.addContentType(type); } if (providerFilter.getContentTypes().size() > 1) { fc.setFileFilter(providerFilter); } } final String userDir = System.getProperty("user.dir"); // May throw SecurityException. Shall not throw NullPointerException, IllegalArgumentException. if (userDir != null) { fc.setCurrentDirectory(new File(userDir)); } if (fc.showDialog(null, null) != JFileChooser.APPROVE_OPTION) // May throw HeadlessException. { System.exit(2); } outputFile = fc.getSelectedFile(); outputUrl = outputFile.toURI().toURL(); // May throw IllegalArgumentException, MalformedURLException. outputPath = outputFile.getName(); if (provider == null) { final ContentTypesFileFilter f = (ContentTypesFileFilter) fc.getFileFilter(); // Shall not throw ClassCastException. provider = f.getProvider(); // May still be null. } } else { try { outputUrl = new URL(_output); // May throw MalformedURLException. outputPath = outputUrl.getPath(); // May still be null. // Go back to a real file whenever possible, because URLConnection does not support writing to files. if ("file".equals(outputUrl.getProtocol())) { final URI uri = outputUrl.toURI(); // May throw URISyntaxException. outputFile = new File(uri); // May throw IllegalArgumentException. } } catch (MalformedURLException e) { outputFile = new File(_output); outputUrl = outputFile.toURI().toURL(); // May throw IllegalArgumentException, MalformedURLException. } } if (outputFile != null) { outputFile = outputFile.getCanonicalFile(); // May throw SecurityException, IOException. } if (provider == null) { if (outputPath == null) { outputPath = _output; } provider = SpecificPlaylistFactory.getInstance().findProviderByExtension(outputPath); if (provider == null) { System.err.println("Unknown type of specific playlist <" + _output + '>'); System.exit(1); } } Playlist playlist = new Playlist(); try { final SpecificPlaylist inputSpecificPlaylist = SpecificPlaylistFactory.getInstance().readFrom(outputUrl); // May throw IOException. if (inputSpecificPlaylist == null) { System.err.println("ERROR: Invalid playlist format from URL <" + outputUrl + '>'); } else { // Override the generic playlist. playlist = inputSpecificPlaylist.toPlaylist(); } } catch (FileNotFoundException e) { System.err.println("WARNING: Cannot fetch URL <" + outputUrl + '>' + e); } catch (Exception e) { System.err.println("ERROR: Cannot read playlist from URL <" + outputUrl + '>' + e); } for (String arg : _arguments) { final File file = new File(arg); // Caution: the input string can also be an URL. // Check it now. if (file.exists()) { // The file exists: begin the file/directory scan process. addToPlaylist(playlist.getRootSequence(), file, true, outputFile); // May throw SecurityException, IOException. } else { // Add it as it is, even if it's really a local file: // it has been explicitely specified through the command line or through the file chooser. final Media media = new Media(); final Content content = new Content(arg); media.setSource(content); playlist.getRootSequence().addComponent(media); } } // Normalize the generic playlist, in case of an "append to an existing file". playlist.normalize(); final FetchContentMetadata metadataVisitor = new FetchContentMetadata(); metadataVisitor.setConnect(_fetchContentMetadata); playlist.acceptDown(metadataVisitor); if (provider instanceof RSSProvider) { ((RSSProvider) provider).setUseRSSMedia(_useRSSMedia); } final SpecificPlaylist outputSpecificPlaylist = provider.toSpecificPlaylist(playlist); // May throw Exception. Shall not throw NullPointerException because of playlist. if (outputSpecificPlaylist instanceof M3U) { ((M3U) outputSpecificPlaylist).setExtensionM3U(_extM3U); } if ((outputSpecificPlaylist instanceof PLP) && (_diskSpecifier != null)) { ((PLP) outputSpecificPlaylist).setDiskSpecifier(_diskSpecifier); } OutputStream out; if (outputFile == null) { final URLConnection conn = outputUrl.openConnection(); // May throw IOException. conn.setAllowUserInteraction(true); // Shall not throw IllegalStateException. conn.setDoInput(false); // Shall not throw IllegalStateException. conn.setDoOutput(true); // Shall not throw IllegalStateException. conn.connect(); // May throw SocketTimeoutException, IOException. out = conn.getOutputStream(); // May throw IOException, UnknownServiceException. } else { out = new FileOutputStream(outputFile); // May throw FileNotFoundException, SecurityException. } outputSpecificPlaylist.writeTo(out, null); // May throw Exception. out.flush(); // May throw IOException. out.close(); // May throw IOException. } /** * Adds the specified file or directory, and optionally its sub-directories, to the input sequence. * @param sequence the playlist sequence to add to. Shall not be null. * @param file a file or directory. Shall not be null. * @param recurse specifies if the sub-directories of this directory shall be recursively scanned or not. * @param playlistFile an optional file to exclude from the sequence. May be null. * @throws NullPointerException if sequence is null. * @throws NullPointerException if file is null. * @throws SecurityException if a security manager exists and its {@link SecurityManager#checkRead(String)} method denies read access to a file. * @throws IOException if an I/O error occurs. */ private void addToPlaylist(final Sequence sequence, final File file, final boolean recurse, final File playlistFile) throws IOException { if (file.isDirectory()) // Throws NullPointerException if file is null. May throw SecurityException. { if (recurse) { final File[] files = file.listFiles(); // May throw SecurityException. if (files != null) { for (File child : files) { addToPlaylist(sequence, child, _recursive, playlistFile); // Throws NullPointerException if sequence is null. May throw SecurityException, IOException. } } } } else if (file.isFile()) // May throw SecurityException. { boolean include = true; String filePath = file.getPath(); if (playlistFile != null) { final File canonicalFile = file.getCanonicalFile(); // May throw IOException, SecurityException. if (canonicalFile.equals(playlistFile)) { include = false; } else { // Try to make the playlist entry file name RELATIVE to the playlist file. File parentFile = canonicalFile.getParentFile(); // Shall not be null, it is a file, not a directory. final File playlistParentFile = playlistFile.getParentFile(); // Shall not be null, it is a file, not a directory. if (parentFile.equals(playlistParentFile)) { filePath = file.getName(); } else { final StringBuilder sb = new StringBuilder(file.getName()); File previousFile = parentFile; parentFile = previousFile.getParentFile(); while (parentFile != null) { sb.insert(0, '/'); // Shall not throw StringIndexOutOfBoundsException. final String previousFileName = previousFile.getName(); if (!"/".equals(previousFileName) && !"\\".equals(previousFileName)) { sb.insert(0, previousFileName); // Shall not throw StringIndexOutOfBoundsException. } if (parentFile.equals(playlistParentFile)) { filePath = sb.toString(); break; } previousFile = parentFile; parentFile = previousFile.getParentFile(); } } } } if (include) { final Media media = new Media(); final Content content = new Content(filePath); media.setSource(content); sequence.addComponent(media); // Throws NullPointerException if sequence is null. } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy