using Soup; namespace MpdNotify { class AlbumArt { private const string LASTFM_API_KEY = "929dc7a1779b10b09f9c3e375b43463c"; private const string LASTFM_API_URL = "http://ws.audioscrobbler.com/2.0"; private static static Mutex mtx = Mutex(); private static string cache_dir = Path.build_path( Path.DIR_SEPARATOR_S, Environment.get_user_cache_dir(), "album-art" ); public signal void download_complete(bool success); public string artist { get; private set; } public string album { get; private set; } public string filename { get; private set; } public bool cached { get { return FileUtils.test(filename, FileTest.EXISTS); } } public AlbumArt(string artist, string album) { this.artist = artist; this.album = album; var key = string.join(":", artist, album); this.filename = Path.build_filename( cache_dir, Checksum.compute_for_string(ChecksumType.SHA1, key) ); } public void fetch() { uint response; URI url; Soup.Session session; Soup.Message message; if (!mtx.trylock()) { return; } session = new Soup.Session(); url = new URI(LASTFM_API_URL); var data = Datalist(); data.set_data("method", "album.getInfo"); data.set_data("api_key", LASTFM_API_KEY); data.set_data("artist", artist); data.set_data("album", album); data.set_data("format", "json"); url.set_query(Form.encode_datalist(data)); message = new Soup.Message("GET", url.to_string(false)); response = session.send_message(message); if (response < 200 || response >= 300) { stderr.printf("Last.fm API call failed with status %u\b", response); finish(false); return; } var parser = new Json.Parser(); try { parser.load_from_data((string) message.response_body.data); } catch { stderr.printf("Failed to parse Last.fm album info response\n"); finish(false); return; } unowned Json.Object root = parser.get_root().get_object(); unowned Json.Object alb = root.get_object_member("album"); unowned Json.Array images = alb.get_array_member("image"); string img_url = null; foreach (unowned Json.Node n in images.get_elements()) { unowned Json.Object img = n.get_object(); unowned string size = img.get_string_member("size"); unowned string text = img.get_string_member("#text"); if (size != "large" || text == null || text == "") { continue; } else { img_url = text; break; } } if (img_url == null || img_url == "") { stderr.printf("No album art available for %s - %s\n", artist, album); finish(false); return; } message = new Soup.Message("GET", img_url); response = session.send_message(message); if (response < 200 || response >= 300) { stderr.printf("Fetching album art failed with status %u\n", response); finish(false); return; } var stream = FileStream.open(filename, "w"); stream.write(message.response_body.data); finish(true); } private void finish(bool success) { Idle.add(() => { download_complete(success); return false; }); mtx.unlock(); } } }