/* * Copyright (c) 2006-2011 Chris Smith, Shane Mc Cormack, Gregory Holmes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.dmdirc.addons.mediasource_vlc; import com.dmdirc.addons.nowplaying.MediaSource; import com.dmdirc.addons.nowplaying.MediaSourceState; import com.dmdirc.config.IdentityManager; import com.dmdirc.config.prefs.PluginPreferencesCategory; import com.dmdirc.config.prefs.PreferencesCategory; import com.dmdirc.config.prefs.PreferencesDialogModel; import com.dmdirc.config.prefs.PreferencesSetting; import com.dmdirc.config.prefs.PreferencesType; import com.dmdirc.plugins.Plugin; import com.dmdirc.util.Downloader; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Retrieves information from VLC using its HTTP interface. * * @author chris */ public class VlcMediaSourcePlugin extends Plugin implements MediaSource { /** The information obtained from VLC. */ private final Map information = new HashMap(); /** {@inheritDoc} */ @Override public MediaSourceState getState() { if (fetchInformation()) { final String output = information.get("state"); if (output.equalsIgnoreCase("stop")) { return MediaSourceState.STOPPED; } else if (output.equalsIgnoreCase("playing")) { return MediaSourceState.PLAYING; } else if (output.equalsIgnoreCase("paused")) { return MediaSourceState.PAUSED; } else { return MediaSourceState.NOTKNOWN; } } else { return MediaSourceState.CLOSED; } } /** {@inheritDoc} */ @Override public String getAppName() { return "VLC"; } /** {@inheritDoc} */ @Override public String getArtist() { return information.containsKey("artist") ? information.get("artist") : getFallbackArtist(); } /** * Retrieves the fallback artist (parsed from the file name). * * @return The fallback artist */ private String getFallbackArtist() { String result = "unknown"; if (information.containsKey("playlist_current")) { try { final int item = Integer.parseInt(information.get( "playlist_current")); String[] bits = information.get("playlist_item_" + item).split( (File.separatorChar == '\\' ? "\\\\" : File.separator)); result = bits[bits.length - 1]; bits = result.split("-"); if (bits.length > 1) { result = bits[0]; } else { // Whole filename is the title, so no artist is known. result = "unknown"; } } catch (NumberFormatException nfe) { // DO nothing } } return result; } /** {@inheritDoc} */ @Override public String getTitle() { return information.containsKey("title") ? information.get("title") : getFallbackTitle(); } /** * Retrieves the fallback title (parsed from the file name). * * @return The fallback title */ private String getFallbackTitle() { String result = "unknown"; // Title is unknown, lets guess using the filename if (information.containsKey("playlist_current")) { try { final int item = Integer.parseInt(information.get( "playlist_current")); result = information.get("playlist_item_" + item); final int sepIndex = result.lastIndexOf(File.separatorChar); final int extIndex = result.lastIndexOf('.'); result = result.substring(sepIndex, extIndex > sepIndex ? extIndex : result.length()); final int offset = result.indexOf('-'); if (offset > -1) { result = result.substring(offset + 1).trim(); } } catch (NumberFormatException nfe) { // Do nothing } } return result; } /** {@inheritDoc} */ @Override public String getAlbum() { return information.containsKey("album/movie/show title") ? information.get("album/movie/show title") : "unknown"; } /** {@inheritDoc} */ @Override public String getLength() { // This is just seconds, could do with formatting. return information.containsKey("length") ? information.get("length") : "unknown"; } /** {@inheritDoc} */ @Override public String getTime() { // This is just seconds, could do with formatting. return information.containsKey("time") ? information.get("time") : "unknown"; } /** {@inheritDoc} */ @Override public String getFormat() { return information.containsKey("codec") ? information.get("codec") : "unknown"; } /** {@inheritDoc} */ @Override public String getBitrate() { return information.containsKey("bitrate") ? information.get("bitrate") : "unknown"; } /** {@inheritDoc} */ @Override public void onLoad() { // Do nothing } /** {@inheritDoc} */ @Override public void onUnload() { // Do nothing } /** {@inheritDoc} */ @Override public void showConfig(final PreferencesDialogModel manager) { final PreferencesCategory general = new PluginPreferencesCategory( getPluginInfo(), "VLC Media Source", "", "category-vlc"); final PreferencesSetting setting = new PreferencesSetting( PreferencesType.LABEL, getDomain(), "", "Instructions", "Instructions"); setting.setValue("

" + "The VLC media source requires that VLC's web interface is" + " enabled. To do this, follow the steps below:

" + "
    " + "
  1. Open VLC's preferences dialog (found in the 'Tools' " + "menu)" + "
  2. Set the 'Show settings' option to 'All'" + "
  3. Expand the 'Interface' category by clicking on the plus " + "sign next to it" + "
  4. Select the 'Main interfaces' category" + "
  5. Check the box next to 'HTTP remote control interface'" + "
  6. Expand the 'Main interfaces' category" + "
  7. Select the 'HTTP' category" + "
  8. In the 'Host address' field, enter 'localhost:8082'" + "
  9. In the 'Source directory' field enter the path to VLC's" + " http directory
      " + "
    • For Linux users this may be " + "/usr/share/vlc/http/" + "
    • For Windows users this will be under the main VLC " + "directory, e.g. C:\\Program Files\\VLC\\http
  10. Click " + "'Save'
  11. Restart VLC
"); general.addSetting(setting); general.addSetting(new PreferencesSetting(PreferencesType.TEXT, getDomain(), "host", "Hostname and port", "The host and port that VLC listens on for web connections")); manager.getCategory("Plugins").addSubCategory(general); } /** * Attempts to fetch information from VLC's web interface. * * @return True on success, false otherwise */ private boolean fetchInformation() { information.clear(); List res; List res2; try { res = Downloader.getPage("http://" + IdentityManager.getGlobalConfig().getOption(getDomain(), "host") + "/old/info.html"); res2 = Downloader.getPage("http://" + IdentityManager.getGlobalConfig().getOption(getDomain(), "host") + "/old/"); parseInformation(res, res2); return true; } catch (MalformedURLException ex) { return false; } catch (IOException ex) { return false; } } /** * Parses the information from the two pages obtained from VLC's web * interface. * * @param res The first page of VLC info (/old/info.html) * @param res2 The second page of VLC info (/old/) */ protected void parseInformation(final List res, final List res2) { for (String line : res) { final String tline = line.trim(); if (tline.startsWith("
  • ")) { final int colon = tline.indexOf(':'); final String key = tline.substring(5, colon).trim() .toLowerCase(); final String value = tline.substring(colon + 1, tline.length() - 5).trim(); information.put(key, value); } } boolean isPlaylist = false; boolean isCurrent = false; boolean isItem = false; int playlistItem = 0; for (String line : res2) { final String tline = line.trim(); if (isPlaylist) { if (tline.startsWith("")) { isPlaylist = false; information.put("playlist_items", Integer.toString( playlistItem)); } else if (tline.equalsIgnoreCase("")) { isCurrent = true; } else if (tline.equalsIgnoreCase("")) { isCurrent = false; } else if (tline.startsWith("")) { itemname = itemname.substring(0, itemname.length() - 4); } if (!itemname.isEmpty()) { if (isCurrent) { information.put("playlist_current", Integer .toString(playlistItem)); } information.put("playlist_item_" + Integer.toString( playlistItem++), itemname); } isItem = false; } } else if (tline.equalsIgnoreCase("")) { isPlaylist = true; } else if (tline.startsWith("State:")) { information.put("state", tline.substring(6, tline.indexOf('<')) .trim()); } else if (tline.startsWith("got_")) { final int equals = tline.indexOf('='); information.put(tline.substring(4, equals).trim(), tline.substring(equals + 1, tline.length() - 1).trim()); } } } }