You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VlcMediaSourcePlugin.java 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * Copyright (c) 2006-2010 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.mediasource_vlc;
  23. import com.dmdirc.addons.nowplaying.MediaSource;
  24. import com.dmdirc.addons.nowplaying.MediaSourceState;
  25. import com.dmdirc.config.IdentityManager;
  26. import com.dmdirc.config.prefs.PreferencesCategory;
  27. import com.dmdirc.config.prefs.PreferencesManager;
  28. import com.dmdirc.config.prefs.PreferencesSetting;
  29. import com.dmdirc.config.prefs.PreferencesType;
  30. import com.dmdirc.plugins.Plugin;
  31. import com.dmdirc.util.Downloader;
  32. import java.io.File;
  33. import java.io.IOException;
  34. import java.net.MalformedURLException;
  35. import java.util.HashMap;
  36. import java.util.List;
  37. import java.util.Map;
  38. /**
  39. * Retrieves information from VLC using its HTTP interface.
  40. *
  41. * @author chris
  42. */
  43. public class VlcMediaSourcePlugin extends Plugin implements MediaSource {
  44. /** The information obtained from VLC. */
  45. private final Map<String, String> information
  46. = new HashMap<String, String>();
  47. /** {@inheritDoc} */
  48. @Override
  49. public MediaSourceState getState() {
  50. if (fetchInformation()) {
  51. final String output = information.get("state");
  52. if (output.equalsIgnoreCase("stop")) {
  53. return MediaSourceState.STOPPED;
  54. } else if (output.equalsIgnoreCase("playing")) {
  55. return MediaSourceState.PLAYING;
  56. } else if (output.equalsIgnoreCase("paused")) {
  57. return MediaSourceState.PAUSED;
  58. } else {
  59. return MediaSourceState.NOTKNOWN;
  60. }
  61. } else {
  62. return MediaSourceState.CLOSED;
  63. }
  64. }
  65. /** {@inheritDoc} */
  66. @Override
  67. public String getAppName() {
  68. return "VLC";
  69. }
  70. /** {@inheritDoc} */
  71. @Override
  72. public String getArtist() {
  73. return information.containsKey("artist") ? information.get("artist") :
  74. getFallbackArtist();
  75. }
  76. /**
  77. * Retrieves the fallback artist (parsed from the file name).
  78. *
  79. * @return The fallback artist
  80. */
  81. private String getFallbackArtist() {
  82. String result = "unknown";
  83. if (information.containsKey("playlist_current")) {
  84. try {
  85. final int item = Integer.parseInt(information.get("playlist_current"));
  86. String[] bits = information.get("playlist_item_" + item).split(
  87. (File.separatorChar=='\\' ? "\\\\" : File.separator));
  88. result = bits[bits.length-1];
  89. bits = result.split("-");
  90. if (bits.length > 1) {
  91. result = bits[0];
  92. } else {
  93. // Whole filename is the title, so no artist is known.
  94. result = "unknown";
  95. }
  96. } catch (NumberFormatException nfe) {
  97. // DO nothing
  98. }
  99. }
  100. return result;
  101. }
  102. /** {@inheritDoc} */
  103. @Override
  104. public String getTitle() {
  105. return information.containsKey("title") ? information.get("title")
  106. : getFallbackTitle();
  107. }
  108. /**
  109. * Retrieves the fallback title (parsed from the file name).
  110. *
  111. * @return The fallback title
  112. */
  113. private String getFallbackTitle() {
  114. String result = "unknown";
  115. // Title is unknown, lets guess using the filename
  116. if (information.containsKey("playlist_current")) {
  117. try {
  118. final int item = Integer.parseInt(information.get("playlist_current"));
  119. result = information.get("playlist_item_" + item);
  120. final int sepIndex = result.lastIndexOf(File.separatorChar);
  121. final int extIndex = result.lastIndexOf('.');
  122. result = result.substring(sepIndex,
  123. extIndex > sepIndex ? extIndex : result.length());
  124. final int offset = result.indexOf('-');
  125. if (offset > -1) {
  126. result = result.substring(offset + 1).trim();
  127. }
  128. } catch (NumberFormatException nfe) {
  129. // Do nothing
  130. }
  131. }
  132. return result;
  133. }
  134. /** {@inheritDoc} */
  135. @Override
  136. public String getAlbum() {
  137. return information.containsKey("album/movie/show title")
  138. ? information.get("album/movie/show title") : "unknown";
  139. }
  140. /** {@inheritDoc} */
  141. @Override
  142. public String getLength() {
  143. // This is just seconds, could do with formatting.
  144. return information.containsKey("length") ? information.get("length")
  145. : "unknown";
  146. }
  147. /** {@inheritDoc} */
  148. @Override
  149. public String getTime() {
  150. // This is just seconds, could do with formatting.
  151. return information.containsKey("time") ? information.get("time")
  152. : "unknown";
  153. }
  154. /** {@inheritDoc} */
  155. @Override
  156. public String getFormat() {
  157. return information.containsKey("codec") ? information.get("codec")
  158. : "unknown";
  159. }
  160. /** {@inheritDoc} */
  161. @Override
  162. public String getBitrate() {
  163. return information.containsKey("bitrate") ? information.get("bitrate")
  164. : "unknown";
  165. }
  166. /** {@inheritDoc} */
  167. @Override
  168. public void onLoad() {
  169. // Do nothing
  170. }
  171. /** {@inheritDoc} */
  172. @Override
  173. public void onUnload() {
  174. // Do nothing
  175. }
  176. /** {@inheritDoc} */
  177. @Override
  178. public void showConfig(final PreferencesManager manager) {
  179. final PreferencesCategory general = new PreferencesCategory("VLC Media Source",
  180. "", "category-vlc");
  181. final PreferencesCategory instr = new PreferencesCategory("Instructions",
  182. "", new InstructionsPanel());
  183. general.addSetting(new PreferencesSetting(PreferencesType.TEXT,
  184. getDomain(), "host", "Hostname and port",
  185. "The host and port that VLC listens on for web connections"));
  186. manager.getCategory("Plugins").addSubCategory(general);
  187. general.addSubCategory(instr.setInline());
  188. }
  189. /**
  190. * Attempts to fetch information from VLC's web interface.
  191. *
  192. * @return True on success, false otherwise
  193. */
  194. private boolean fetchInformation() {
  195. information.clear();
  196. List<String> res;
  197. List<String> res2;
  198. try {
  199. res = Downloader.getPage("http://" +
  200. IdentityManager.getGlobalConfig().getOption(getDomain(),
  201. "host") + "/old/info.html");
  202. res2 = Downloader.getPage("http://" +
  203. IdentityManager.getGlobalConfig().getOption(getDomain(),
  204. "host") + "/old/");
  205. } catch (MalformedURLException ex) {
  206. return false;
  207. } catch (IOException ex) {
  208. return false;
  209. }
  210. parseInformation(res, res2);
  211. return true;
  212. }
  213. /**
  214. * Parses the information from the two pages obtained from VLC's web
  215. * interface.
  216. *
  217. * @param res The first page of VLC info (/old/info.html)
  218. * @param res2 The second page of VLC info (/old/)
  219. */
  220. protected void parseInformation(final List<String> res,
  221. final List<String> res2) {
  222. for (String line : res) {
  223. final String tline = line.trim();
  224. if (tline.startsWith("<li>")) {
  225. final int colon = tline.indexOf(':');
  226. final String key = tline.substring(5, colon).trim().toLowerCase();
  227. final String value = tline.substring(colon + 1, tline.length() - 5).trim();
  228. information.put(key, value);
  229. }
  230. }
  231. boolean isPlaylist = false;
  232. boolean isCurrent = false;
  233. boolean isItem = false;
  234. int playlistItem = 0;
  235. for (String line : res2) {
  236. final String tline = line.trim();
  237. if (isPlaylist) {
  238. if (tline.startsWith("</ul>")) {
  239. isPlaylist = false;
  240. information.put("playlist_items", Integer.toString(playlistItem));
  241. } else if (tline.equalsIgnoreCase("<strong>")) {
  242. isCurrent = true;
  243. } else if (tline.equalsIgnoreCase("</strong>")) {
  244. isCurrent = false;
  245. } else if (tline.startsWith("<a href=\"?control=play&amp")) {
  246. isItem = true;
  247. } else if (isItem) {
  248. String itemname = tline;
  249. if (itemname.endsWith("</a>")) {
  250. itemname = itemname.substring(0, itemname.length()-4);
  251. }
  252. if (!itemname.isEmpty()) {
  253. if (isCurrent) {
  254. information.put("playlist_current", Integer.toString(playlistItem));
  255. }
  256. information.put("playlist_item_"+Integer.toString(playlistItem++),
  257. itemname);
  258. }
  259. isItem = false;
  260. }
  261. } else if (tline.equalsIgnoreCase("<!-- Playlist -->")) {
  262. isPlaylist = true;
  263. } else if (tline.startsWith("State:")) {
  264. information.put("state", tline.substring(6, tline.indexOf('<')).trim());
  265. } else if (tline.startsWith("got_")) {
  266. final int equals = tline.indexOf('=');
  267. information.put(tline.substring(4, equals).trim(),
  268. tline.substring(equals + 1, tline.length() - 1).trim());
  269. }
  270. }
  271. }
  272. }