package com.sleazyweasel.applescriptifier; import com.google.gson.Gson; import javax.imageio.ImageIO; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; public class RdioServlet extends HttpServlet { private static final Logger logger = Logger.getLogger(RdioServlet.class.getName()); private final AppleScriptTemplate appleScriptTemplate = new AppleScriptTemplateFactory().getActiveTemplate(); private final RdioSupport rdioSupport = new RdioSupport(appleScriptTemplate); @Override protected void doGet(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException { // Set to expire far in the past. response.setHeader("Expires", "Sat, 6 May 1995 12:00:00 GMT"); // Set standard HTTP/1.1 no-cache headers. response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate"); // Set IE extended HTTP/1.1 no-cache headers (use addHeader). response.addHeader("Cache-Control", "post-check=0, pre-check=0"); // Set standard HTTP/1.0 no-cache header. response.setHeader("Pragma", "no-cache"); response.setContentType("application/json; charset=utf-8"); response.setCharacterEncoding("UTF-8"); String pathInfo = req.getPathInfo(); if (pathInfo.startsWith("/status")) { appendStatus(response); } else if (pathInfo.startsWith("/playpause")) { rdioSupport.playPause(); appendStatus(response); } else if (pathInfo.startsWith("/next")) { rdioSupport.next(); appendStatus(response); } else if (pathInfo.startsWith("/previous")) { rdioSupport.previous(); appendStatus(response); } else if (pathInfo.startsWith("/artwork")) { try { Thread.sleep(500L); } catch (InterruptedException e) { Thread.interrupted(); return; } appleScriptTemplate.execute(Application.RDIO(), imageCommand); BufferedImage image = ImageIO.read(new File("/tmp/rdio.tiff")); response.setContentType("image/png"); ImageIO.write(image, "PNG", response.getOutputStream()); response.setStatus(HttpServletResponse.SC_OK); } else if (pathInfo.startsWith("/setVolume")) { String value = req.getParameter("value"); Integer volume = Integer.valueOf(value); rdioSupport.setVolume(volume); appendStatus(response); } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); } } private void appendStatus(HttpServletResponse response) throws IOException { Map<String, Object> currentTrack = new HashMap<String, Object>(); Map<String, Object> playerState = new HashMap<String, Object>(); try { List<List<Object>> data = appleScriptTemplate.execute(Application.RDIO(), "[get [name, artist, album, duration, rdio url] of current track, get [player position, sound volume]]"); List<Object> trackData = data.get(0); currentTrack.put("title", trackData.get(0)); currentTrack.put("artist", trackData.get(1)); currentTrack.put("album", trackData.get(2)); currentTrack.put("duration", trackData.get(3)); currentTrack.put("rdioUrl", trackData.get(4)); List<Object> playerData = data.get(1); Double position = (Double) playerData.get(0); playerState.put("playerPosition", position.isNaN() || position.isInfinite() ? 0 : position); playerState.put("volume", playerData.get(1)); } catch (Exception e) { logger.log(Level.WARNING, "Exception caught.", e); List<List<Object>> data = appleScriptTemplate.execute(Application.RDIO(), "[get [player position, sound volume]]"); currentTrack.put("title", ""); currentTrack.put("artist", ""); currentTrack.put("album", ""); currentTrack.put("duration", ""); currentTrack.put("rdioUrl", ""); List<Object> playerData = data.get(0); // Double position = (Double) playerData.get(0); playerState.put("playerPosition", 0); playerState.put("volume", playerData.get(1)); } try { String running = appleScriptTemplate.execute(Application.RDIO(), "get player state as string"); playerState.put("playing", "playing".equalsIgnoreCase(running) ? "YES" : "NO"); } catch (Exception e) { playerState.put("playing", "NO"); } Map<String, Object> status = new HashMap<String, Object>(); status.put("currentTrack", currentTrack); status.put("playerState", playerState); status.put("version", ControlServlet.CURRENT_VERSION); response.getWriter().append(new Gson().toJson(status)); response.setStatus(HttpServletResponse.SC_OK); } //this has got to be the *hardest* possible way to accomplish this. private static final String[] imageCommand = { "set imagedata to artwork of current track", "set the_file to \"/tmp/rdio.tiff\"", "try", " open for access the_file with write permission", " set eof of the_file to 0", " write (imagedata) to the_file starting at eof", " close access the_file", "on error", " try", " close access the_file", " end try", "end try" }; }