📜 ⬆️ ⬇️

An example of integration of Last.FM API and VK.COM API to update the contents of its player

Hello!

I think most of you are familiar with the social networks " VKontakte " and " Last.fm ". In this article we will look at a small example of integration between the APIs of both services. To be more precise, we will receive a list of favorite tracks from last.fm, search for binary content in VC and save it to HDD.
The article will be more interesting to beginners than to professionals, however, it requires some technical training. The test project is implemented using Java tools.

If the reader is interested in what came out of this, please welcome under cat.
')


Disclaimer


In our terrible time, when corporations are trying to sue each other billion for a few lines of code . When you can get the problem on "one-two" , I just have to say the following.
Software implementation within this article has purely informational motivations and does not pursue any commercial motives.

Intro


I will not delay for a long time. We define our goals.
  1. Get a list of favorite tracks on last.fm
  2. Find tracks on vk.com servers
  3. Download tracks to the player


But first of all, it is necessary to get access to the API of both services.
On Habré there were already articles, for example, this . I will not describe everything in detail, so the links immediately:
API last.fm key
API key vk.com
Further, we carefully study the specification ( last.fm , vk.com ) and decide what exactly we want.
Actually, we need the audio.search and user.getLovedTracks methods .

Test requests


After the application is already created, you need to check with what we will work.
With last.fm, it's simple. We make the usual html request in the browser line:
http: // ws.audioscrobbler.com/2.0/?method=user.getlovedtracks&user= USER & api_key = API_KEY
If all the parameters have been entered correctly, then you can see the xml, in which in addition to the name of the track, as well as its authors, you can find any additional information.
With vk.com, everything is almost the same, with the only exception that without the access_token parameter, we will not be able to access the audio recordings.
Make a request:
http: // api.vk.com/oauth/authorize?client_id= ID & redirect_uri = http: //api.vk.com/blank.html&scope= audio & display = page & response_type = token
As a result, the redirect will send us to the link of the form:
http: // api.vk.com/blank.html#access_token= XYZ & expires_in = 86400 & user_id = ID
XYZ is what we need.
Now request of the form:
https: // api.vk.com/method/audio.search.xml?q=AC/DC%20-%20Highway%20to%20Hell&access_token= XYZ should give xml'ku where you can see the physical address of the binary music file.
If everything has “taken off”, we can move on.

Software implementation


Let's get a Configuration.properties file where the current settings will be stored.
last_fm_api=
last_fm_user=
last_fm_ws_address=http://ws.audioscrobbler.com/2.0/
vk_com_access_token=
vk_com_ws_address=https://api.vk.com/method/

For simplicity, decided on the GUI to bother. Data is conveniently stored in a collection of POJO bins of this type:
 public class LovedTrackBean { public LovedTrackBean(String trackName, String trackArtist) { this.trackName = trackName; this.trackArtist = trackArtist; } //GETTERS & SETTERS public String toString() { return trackArtist + " - " + trackName; } private String trackName = null; private String trackArtist = null; private String trackURL = null; } 

Now we need to use the last.fm API and get a list of favorite tracks.
Something like this:
 public class TrackLover { public TrackLover() { StringBuffer buff = new StringBuffer(); buff.append(PropertyLoader.getProperties().get(PropertyLoader.LAST_FM_WS_ADDRESS)); buff.append("?method="); buff.append(LAST_FM_API_METHOD); buff.append("&user="); buff.append(PropertyLoader.getProperties().get(PropertyLoader.LAST_FM_USER)); buff.append("&api_key="); buff.append(PropertyLoader.getProperties().get(PropertyLoader.LAST_FM_API)); connectToUrl = buff.toString(); } public List<LovedTrackBean> getLovedTracks() throws IOException, ParserConfigurationException, SAXException { if(lovedTracks == null) { URL url = new URL(connectToUrl); URLConnection conn = url.openConnection(); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); Document doc = docBuilder.parse(conn.getInputStream()); doc.getDocumentElement().normalize(); NodeList listOfLovedTracks = doc.getElementsByTagName("track"); int tracksTotal = listOfLovedTracks.getLength(); lovedTracks = new ArrayList<LovedTrackBean>(tracksTotal); //... //  //... System.out.println("######### AFTER LAST.FM RESPONSE #########"); for(LovedTrackBean track: lovedTracks) { System.out.println(track.toString()); } return lovedTracks; } else { lovedTracks = new ArrayList<LovedTrackBean>(1); lovedTracks.add(new LovedTrackBean("Wish you were here", "Pink Floyd")); return lovedTracks; } } private String connectToUrl = null; private List<LovedTrackBean> lovedTracks = null; public static final String LAST_FM_API_METHOD = "user.getlovedtracks"; } 

This code should return us a collection with your favorite tracks.
Next stop is vk.com.
Let's try in pairs “Author - Composition” to get audio recording. For simplicity, let's take the first one.
 public class TrackURLFinder { public TrackURLFinder(LovedTrackBean lovedTrack) { this.lovedTrack = lovedTrack; StringBuffer buff = new StringBuffer(); buff.append(PropertyLoader.getProperties().get(PropertyLoader.VK_COM_WS_ADDRESS)); buff.append(VK_COM_API_METHOD); buff.append("?q="); buff.append(lovedTrack.toString()); buff.append("&"); buff.append("access_token="); buff.append(PropertyLoader.getProperties().get(PropertyLoader.VK_COM_ACCESS_TOKEN)); connectToUrl = buff.toString(); connectToUrl = connectToUrl.replaceAll(" ", "%20"); System.out.println(connectToUrl); } public void addUrlToLovedTrack() throws SAXException, IOException, ParserConfigurationException { if(lovedTrack != null) { URL url = new URL(connectToUrl); URLConnection conn = url.openConnection(); DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); Document doc = docBuilder.parse(conn.getInputStream()); doc.getDocumentElement().normalize(); NodeList audioList = doc.getElementsByTagName("audio"); Node currentNode = audioList.item(0); Element currentElement = (Element) currentNode; NodeList urlList = currentElement.getElementsByTagName("url"); Element urlElement = (Element) urlList.item(0); NodeList urlFormattedList = urlElement.getChildNodes(); String urlAddressOfTheMP3File = urlFormattedList.item(0).getNodeValue().trim(); lovedTrack.setTrackURL(urlAddressOfTheMP3File); System.out.println(urlAddressOfTheMP3File); } } private String connectToUrl = null; private LovedTrackBean lovedTrack = null; public static final String VK_COM_API_METHOD = "audio.search.xml"; } 

And finally, we get the content:
 public class MP3MusicContentDownloader { public MP3MusicContentDownloader(String urlAddress, String fileName) throws MalformedURLException { this.fileName = fileName; url = new URL(urlAddress); } public void download() throws IOException { conn = url.openConnection(); System.out.println("Started downloading of " + fileName); String contentType = conn.getContentType(); int contentLength = conn.getContentLength(); if (contentType.startsWith("text/") || contentLength == -1) { throw new IOException("This is not a binary file."); } File folder = new File(DEFAULT_DIRECTORY_NAME); if (!folder.exists() || !folder.isDirectory()) { folder.mkdir(); } File binaryFile = new File(DEFAULT_DIRECTORY_NAME + File.separator + fileName); if (!binaryFile.exists()) { BufferedInputStream in = new BufferedInputStream(conn.getInputStream()); byte[] data = new byte[contentLength]; int bytesRead = 0; int offset = 0; while (offset < contentLength) { bytesRead = in.read(data, offset, data.length - offset); if (bytesRead == -1) break; offset += bytesRead; } in.close(); if (offset != contentLength) { throw new IOException("Only read " + offset + " bytes; Expected " + contentLength + " bytes"); } FileOutputStream out = new FileOutputStream(binaryFile); out.write(data); out.flush(); out.close(); } else { return; } } private String fileName = null; private URL url = null; private URLConnection conn = null; private static final String DEFAULT_DIRECTORY_NAME = "music"; } 

That's all. Launch, I hope, is not difficult.

TODOs


Since this is just a test case, which, by the way, was performed for self-study purposes, I am almost sure that it contains a number of bugs / shortcomings. Nevertheless, the example on my tracks worked. Specifically, in this case, it would be possible to implement multithreading, or, for example, a full scan of all compositions of the favorites (the first 50 are now being collected), or, for example, checking access_token's validity (suddenly, the validity period has expired). Yes, a lot of things. But, if you already understood, the meaning of the article was not that :)

Thank you all, who had the patience to reach these lines!

Source: https://habr.com/ru/post/143657/


All Articles