Created
September 22, 2015 22:40
-
-
Save RomanTruba/d9cec6687fe623ac888f to your computer and use it in GitHub Desktop.
Download music from VK
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import com.sun.istack.internal.Nullable; | |
import org.apache.commons.lang.StringUtils; | |
import org.json.simple.JSONArray; | |
import org.json.simple.JSONObject; | |
import org.json.simple.parser.JSONParser; | |
import org.json.simple.parser.ParseException; | |
import java.io.BufferedReader; | |
import java.io.File; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.InputStreamReader; | |
import java.net.URL; | |
import java.net.URLConnection; | |
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.Locale; | |
import java.util.Map; | |
import java.util.zip.GZIPInputStream; | |
public class MainClass | |
{ | |
//retrieve access_token here https://vk.com/app35569 | |
public static final String VK_ACCESS_TOKEN = ""; | |
//leave empty for self | |
public static final String VK_TARGET_USER_ID = ""; | |
//set audio id, where need to stop | |
public static final long VK_TARGET_AUDIO_ID = 0; | |
public static final int VK_PAGE_SIZE = 50; | |
public long mOverallBytesLoaded = 0; | |
//Mac OS path setup | |
public static final String MUSIC_DEST_FOLDER = System.getProperty("user.home") + "/Desktop/music_result"; | |
public static void main(String[] args) | |
{ | |
new MainClass().run(); | |
} | |
public static final String VK_API_URL = "https://api.vk.com/method"; | |
public String joinParams(Map<String, String> params) | |
{ | |
ArrayList<String> pairs = new ArrayList<String>(); | |
for (String key : params.keySet()) | |
{ | |
pairs.add(key + "=" + params.get(key)); | |
} | |
return StringUtils.join(pairs, "&"); | |
} | |
public String constructUrlForPageWithOffset(int offset) | |
{ | |
Map<String, String> params = new HashMap<String, String>(); | |
params.put("count", "" + VK_PAGE_SIZE); | |
params.put("offset", "" + offset); | |
params.put("user_id", VK_TARGET_USER_ID); | |
params.put("access_token", VK_ACCESS_TOKEN); | |
params.put("v", "5.35"); | |
return String.format(Locale.getDefault(), "%s/%s?%s", VK_API_URL, "audio.get", | |
joinParams(params)); | |
} | |
@Nullable | |
public String loadPage(String pageUrl) { | |
try | |
{ | |
URLConnection connection = new URL(pageUrl).openConnection(); | |
connection.setRequestProperty("Accept-Encoding", "gzip"); | |
InputStream input = connection.getInputStream(); | |
if ("gzip".equals(connection.getContentEncoding())) { | |
input = new GZIPInputStream(input); | |
} | |
BufferedReader reader = new BufferedReader(new InputStreamReader(input)); | |
StringBuilder builder = new StringBuilder(""); | |
String inputLine; | |
while ((inputLine = reader.readLine()) != null) | |
{ | |
builder.append(inputLine); | |
} | |
reader.close(); | |
return builder.toString(); | |
} | |
catch (IOException e) | |
{ | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
public boolean saveContentAtUrlToFile(String contentUrl, File targetFile) { | |
try | |
{ | |
URLConnection connection = new URL(contentUrl).openConnection(); | |
InputStream inputStream = connection.getInputStream(); | |
FileOutputStream outputStream = new FileOutputStream(targetFile); | |
int contentLen = connection.getContentLength(); | |
int maxLevel = 20, level = 1; | |
int BUFFER_SIZE = contentLen / maxLevel; | |
int bytesRead; | |
int totalBytesRead = 0; | |
byte[] buffer = new byte[BUFFER_SIZE]; | |
System.out.println("Start: " + contentUrl); | |
System.out.print("0."); | |
while ((bytesRead = inputStream.read(buffer)) != -1) { | |
outputStream.write(buffer, 0, bytesRead); | |
totalBytesRead += bytesRead; | |
if (totalBytesRead > BUFFER_SIZE * level) | |
{ | |
System.out.print("."); | |
level++; | |
} | |
} | |
mOverallBytesLoaded += totalBytesRead; | |
System.out.println("Done (" + humanReadableByteCount(totalBytesRead, true) + ")"); | |
inputStream.close(); | |
outputStream.close(); | |
return true; | |
} | |
catch (IOException e) | |
{ | |
e.printStackTrace(); | |
} | |
return false; | |
} | |
public static String humanReadableByteCount(long bytes, boolean si) { | |
int unit = si ? 1000 : 1024; | |
if (bytes < unit) return bytes + " B"; | |
int exp = (int) (Math.log(bytes) / Math.log(unit)); | |
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); | |
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); | |
} | |
public void run() { | |
int currentOffset = 0; | |
int totalSongsLoaded = 0; | |
boolean canLoadNextPage = true; | |
JSONParser parser=new JSONParser(); | |
File targetDir = new File(MUSIC_DEST_FOLDER); | |
boolean b = targetDir.mkdirs(); | |
if (b) { | |
System.out.println("Directory prepared"); | |
} | |
do { | |
System.out.println("Loading page for user: " + VK_TARGET_USER_ID + " with offset: " + currentOffset); | |
String request = constructUrlForPageWithOffset(currentOffset); | |
String rawJson = loadPage(request); | |
if (rawJson == null) { | |
System.out.println("Can't load request: " + request); | |
break; | |
} | |
try | |
{ | |
JSONObject wholeResponse = (JSONObject)parser.parse(rawJson); | |
Object response = wholeResponse.get("response"); | |
if (response == null) { | |
System.out.println("Failed to parse response: " + rawJson); | |
break; | |
} | |
JSONObject responseData = (JSONObject)response; | |
JSONArray items = (JSONArray)responseData.get("items"); | |
if (items == null) { | |
System.out.println("Failed to receive items: " + rawJson); | |
break; | |
} | |
int size = items.size(); | |
for (Object item : items) { | |
VKAudio audio = new VKAudio((JSONObject) item); | |
canLoadNextPage = VK_TARGET_AUDIO_ID != audio.id; | |
String fileName = String.format("%s - %s.mp3", audio.artist, audio.title); | |
File targetFile = new File(targetDir + File.separator + fileName); | |
System.out.println("Downloading: " + audio.toString()); | |
if (!saveContentAtUrlToFile(audio.url, targetFile)) { | |
System.out.println("Failed to load audio: " + audio.toString()); | |
} else { | |
totalSongsLoaded++; | |
} | |
System.out.println(); | |
if (!canLoadNextPage) { | |
System.out.println("Target song reached"); | |
break; | |
} | |
} | |
currentOffset += size; | |
} | |
catch (ParseException e) | |
{ | |
e.printStackTrace(); | |
} | |
} while (canLoadNextPage); | |
System.out.println("Finished loading. Songs loaded: " + totalSongsLoaded + ". Bytes loaded: " + humanReadableByteCount(mOverallBytesLoaded, true)); | |
} | |
public static class VKAudio { | |
public Long id; | |
public String artist; | |
public String title; | |
public String url; | |
public VKAudio(JSONObject data) | |
{ | |
this.id = (Long) data.get("id"); | |
this.artist = ((String) data.get("artist")).trim(); | |
this.title = ((String) data.get("title")).trim(); | |
this.url = (String) data.get("url"); | |
} | |
@Override | |
public String toString() | |
{ | |
return String.format("Audio(id %d): %s - %s", id, artist, title); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment