refactored last.fm scrobbler
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.Preferences;
|
||||
|
||||
public class LastFMScrobbler {
|
||||
private static final String KEY = "5965d63402414776c54c266db0211746";
|
||||
private static final String KEY_SECRET = "d982180eed13275bb948e41cf225f88f";
|
||||
private static final String URL = "https://ws.audioscrobbler.com/2.0/";
|
||||
private static final OkHttpClient CLIENT = new OkHttpClient();
|
||||
private static final List<String> SCROBBLED_UUIDS = new ArrayList<>();
|
||||
|
||||
public static void grabMusicTrack(MusicTrack musictrack) {
|
||||
var uid = musictrack.y1();
|
||||
var artist = musictrack.C;
|
||||
var title = musictrack.f;
|
||||
var duration = musictrack.h;
|
||||
var track_id = musictrack.d;
|
||||
var owner_id = musictrack.e;
|
||||
var access_key = !TextUtils.isEmpty(musictrack.J) ? musictrack.J : "";
|
||||
var album_id = musictrack.I;
|
||||
var album = album_id != null ? album_id.getTitle() : null;
|
||||
|
||||
if (TextUtils.isEmpty(uid) || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0) {
|
||||
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Preferences.autocache() && !CacheDatabaseDelegate.isCached(uid)) {
|
||||
if (LibVKXClient.isIntegrationEnabled()){
|
||||
LibVKXClient.getInstance().runOnService(service -> {
|
||||
try {
|
||||
service.addTrackToCache(track_id, owner_id, access_key);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
AudioDownloader.cacheTrack(musictrack);
|
||||
}
|
||||
}
|
||||
|
||||
scrobbleTrack(duration, artist, title, uid, album);
|
||||
}
|
||||
|
||||
public static void scrobbleTrack(
|
||||
long duration,
|
||||
String artist,
|
||||
String title,
|
||||
String uid,
|
||||
@Nullable String album
|
||||
) {
|
||||
Log.d("Scrobbler", "scrobbleTrack: " + title + " - " + artist + " - " + duration + " - " + uid);
|
||||
|
||||
if (!needScrobbling(uid) || !isLoggedIn() || TextUtils.isEmpty(artist) || TextUtils.isEmpty(title) || duration == 0)
|
||||
return;
|
||||
|
||||
SCROBBLED_UUIDS.add(uid);
|
||||
|
||||
var params = new TreeMap<String, String>();
|
||||
params.put("api_key", KEY);
|
||||
params.put("method", "track.scrobble");
|
||||
params.put("sk", getSessionKey());
|
||||
params.put("artist[0]", artist);
|
||||
params.put("track[0]", title);
|
||||
if (!TextUtils.isEmpty(album))
|
||||
params.put("album[0]", album);
|
||||
params.put("duration[0]", String.valueOf(duration));
|
||||
params.put("timestamp[0]", String.valueOf(System.currentTimeMillis() / 1000));
|
||||
|
||||
|
||||
fetch(params, new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d("Scrobbler", e+"");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
Log.d("Scrobbler", "Scrobbled: " + artist + " - " + title);
|
||||
Log.d("Scrobbler", "Response scrobble: " + response.a().g());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void authenticate(String username, String password) {
|
||||
if (TextUtils.isEmpty(username) || TextUtils.isEmpty(password)) {
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("lastfm_credentials_empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
var params = new TreeMap<String, String>();
|
||||
params.put("api_key", KEY);
|
||||
params.put("method", "auth.getMobileSession");
|
||||
params.put("username", username);
|
||||
params.put("password", password);
|
||||
|
||||
fetch(params, new Callback() {
|
||||
@Override
|
||||
public void a(Call call, IOException e) {
|
||||
Log.d("Scrobbler", "Auth failed", e);
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("auth_error_vtl"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void a(Call call, Response response) throws IOException {
|
||||
try {
|
||||
var resBody = response.a().g();
|
||||
var json = new JSONObject(resBody);
|
||||
fetchSession(json);
|
||||
Log.d("Scrobbler", "Auth response " + resBody);
|
||||
} catch (JSONException e) {
|
||||
Log.d("Scrobbler", "Auth failed", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String generateMD5(Map<String, String> params) {
|
||||
var sb = new StringBuilder();
|
||||
for (var entry : params.entrySet())
|
||||
sb.append(entry.getKey()).append(entry.getValue());
|
||||
return AndroidUtils.MD5(sb.append(KEY_SECRET).toString());
|
||||
}
|
||||
|
||||
private static void fetch(TreeMap<String, String> params, Callback callback) {
|
||||
// Each call must be signed with md5.
|
||||
// For more information check https://www.last.fm/api
|
||||
params.put("api_sig", generateMD5(params));
|
||||
params.put("format", "json");
|
||||
|
||||
var reqBodyBuilder = new FormBody.a(StandardCharsets.UTF_8);
|
||||
for (var entry : params.entrySet())
|
||||
reqBodyBuilder.a(entry.getKey(), entry.getValue());
|
||||
|
||||
var req = new Request.a()
|
||||
.b(URL)
|
||||
.a(reqBodyBuilder.a())
|
||||
.a();
|
||||
|
||||
CLIENT.a(req).a(callback);
|
||||
}
|
||||
|
||||
public static void fetchSession(JSONObject json) throws JSONException {
|
||||
if (!json.has("session")) {
|
||||
Log.d("Scrobbler", "Auth failed - no session");
|
||||
return;
|
||||
}
|
||||
|
||||
var session = json.getJSONObject("session");
|
||||
var name = session.getString("name");
|
||||
var key = session.getString("key");
|
||||
|
||||
AndroidUtils.edit()
|
||||
.putString("username", name)
|
||||
.putString("sessionKey", key)
|
||||
.putBoolean("lastfm_enabled", true)
|
||||
.apply();
|
||||
|
||||
Log.d("Scrobbler", "Auth success as " + name + ", key " + key);
|
||||
}
|
||||
|
||||
public static void logout() {
|
||||
AndroidUtils.edit()
|
||||
.remove("username")
|
||||
.remove("sessionKey")
|
||||
.putBoolean("lastfm_enabled", false)
|
||||
.apply();
|
||||
SCROBBLED_UUIDS.clear();
|
||||
AndroidUtils.sendToast(AndroidUtils.getString("lastfm_logout_success"));
|
||||
}
|
||||
|
||||
public static boolean needScrobbling(String uid) {
|
||||
return isLoggedIn() && isScrobblingEnabled() && !SCROBBLED_UUIDS.contains(uid);
|
||||
}
|
||||
|
||||
public static boolean isLoggedIn() {
|
||||
return !TextUtils.isEmpty(getSessionKey());
|
||||
}
|
||||
|
||||
public static boolean isScrobblingEnabled() {
|
||||
return AndroidUtils.getPreferences().getBoolean("lastfm_enabled", false);
|
||||
}
|
||||
|
||||
public static String getUserName() {
|
||||
return AndroidUtils.getDefaultPrefs().getString("username", null);
|
||||
}
|
||||
|
||||
private static String getSessionKey() {
|
||||
return AndroidUtils.getDefaultPrefs().getString("sessionKey", null);
|
||||
}
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import static java.lang.String.valueOf;
|
||||
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.getInstance;
|
||||
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.*;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.MD5;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getDefaultPrefs;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.getPreferences;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.sendToast;
|
||||
import static ru.vtosters.lite.utils.Preferences.autocache;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.vk.dto.music.MusicTrack;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import bruhcollective.itaysonlab.libvkx.client.LibVKXClient;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.net.NetCall;
|
||||
import ru.vtosters.lite.net.NetCallback;
|
||||
import ru.vtosters.lite.net.NetClient;
|
||||
import ru.vtosters.lite.net.NetRequest;
|
||||
import ru.vtosters.lite.net.NetResponse;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
|
||||
public class Scrobbler {
|
||||
private static final String key = "5965d63402414776c54c266db0211746";
|
||||
private static final String keysecret = "d982180eed13275bb948e41cf225f88f";
|
||||
private static final String url = "https://ws.audioscrobbler.com/2.0/";
|
||||
private static final NetClient client = new NetClient.Builder().build();
|
||||
private static final ArrayList<String> scrobbled = new ArrayList<>();
|
||||
|
||||
public static void scrobbleTrack(long duration, String artist, String title, String uid, @Nullable String album) {
|
||||
var string = getDefaultPrefs().getString("sessionKey", null);
|
||||
var timestamp = System.currentTimeMillis() / 1000;
|
||||
|
||||
Log.d("Scrobbler", "scrobbleTrack: " + title + " - " + artist + " - " + duration + " - " + uid);
|
||||
|
||||
if (!needToBeScrobble(uid) ||
|
||||
string == null ||
|
||||
string.isEmpty() ||
|
||||
artist == null ||
|
||||
artist.isEmpty() ||
|
||||
title == null ||
|
||||
title.isEmpty() ||
|
||||
duration == 0) return;
|
||||
|
||||
scrobbled.add(uid); // add to scrobbled list
|
||||
|
||||
TreeMap<String, String> treeMap = new TreeMap<>(); // create map for request
|
||||
treeMap.put("method", "track.scrobble");
|
||||
treeMap.put("sk", string);
|
||||
treeMap.put("artist[0]", artist);
|
||||
treeMap.put("track[0]", title);
|
||||
if (album != null && !album.isEmpty())
|
||||
treeMap.put("album[0]", album);
|
||||
treeMap.put("timestamp[0]", valueOf(timestamp));
|
||||
treeMap.put("api_key", key);
|
||||
treeMap.put("duration[0]", valueOf(duration));
|
||||
treeMap.put("api_sig", signMD5(treeMap));
|
||||
treeMap.put("format", "json");
|
||||
|
||||
client.newCall(new NetRequest.Builder().url(url).post().params(treeMap).build()).enqueue(new NetCallback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
Log.d("Scrobbler", "Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) {
|
||||
Log.d("Scrobbler", "Scrobbled: " + artist + " - " + title);
|
||||
Log.d("Scrobbler", "Response scrobble: " + response.getDataString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void grabMusicTrack(MusicTrack musictrack) {
|
||||
var uid = musictrack.y1();
|
||||
var artist = musictrack.C;
|
||||
var title = musictrack.f;
|
||||
var duration = musictrack.h;
|
||||
var track_id = musictrack.d;
|
||||
var owner_id = musictrack.e;
|
||||
var access_key = musictrack.J;
|
||||
var albumid = musictrack.I;
|
||||
String album;
|
||||
|
||||
if (albumid != null) {
|
||||
album = albumid.getTitle();
|
||||
} else {
|
||||
album = null;
|
||||
}
|
||||
|
||||
if (uid.isEmpty() || artist == null || artist.isEmpty() || title == null || title.isEmpty() || duration == 0) {
|
||||
Log.d("Scrobbler", "grabTrackInfo: " + "Empty track, info: " + artist + " - " + title + " - " + duration + " - " + uid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (autocache() && !isCached(uid)) {
|
||||
if (LibVKXClient.isIntegrationEnabled()){
|
||||
getInstance().runOnService(service -> {
|
||||
try {
|
||||
service.addTrackToCache(track_id, owner_id, (access_key != null) ? access_key : "");
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
AudioDownloader.cacheTrack(musictrack);
|
||||
}
|
||||
}
|
||||
|
||||
scrobbleTrack(duration, artist, title, uid, album);
|
||||
}
|
||||
|
||||
private static String signMD5(Map<String, String> map) {
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
sb.append(entry.getKey());
|
||||
sb.append(entry.getValue());
|
||||
}
|
||||
|
||||
sb.append(keysecret);
|
||||
|
||||
return MD5(sb.toString());
|
||||
}
|
||||
|
||||
public static void auth(String login, String pass) {
|
||||
if (login == null || pass == null) {
|
||||
sendToast(AndroidUtils.getString("lastfm_credentials_empty"));
|
||||
return;
|
||||
}
|
||||
|
||||
TreeMap<String, String> treeMap = new TreeMap<>(); // create map for request
|
||||
treeMap.put("method", "auth.getMobileSession");
|
||||
treeMap.put("api_key", key);
|
||||
treeMap.put("username", login);
|
||||
treeMap.put("password", pass);
|
||||
treeMap.put("api_sig", signMD5(treeMap));
|
||||
treeMap.put("format", "json");
|
||||
|
||||
client.newCall(new NetRequest.Builder().url(url).post().params(treeMap).build()).enqueue(new NetCallback() {
|
||||
@Override
|
||||
public void onFailure(NetCall call, IOException e) {
|
||||
Log.d("Scrobbler", "Auth failed", e);
|
||||
sendToast(AndroidUtils.getString("auth_error_vtl"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(NetCall call, NetResponse response) {
|
||||
try {
|
||||
var jSONObject = new JSONObject(response.getDataString());
|
||||
sessionFetcher(jSONObject);
|
||||
Log.d("Scrobbler", "Auth response " + response.getDataString());
|
||||
} catch (JSONException e) {
|
||||
Log.d("Scrobbler", "Auth failed", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void sessionFetcher(JSONObject jsonObject) throws JSONException {
|
||||
if (!jsonObject.has("session")) {
|
||||
Log.d("Scrobbler", "Auth failed - no session");
|
||||
return;
|
||||
}
|
||||
|
||||
var session = jsonObject.getJSONObject("session");
|
||||
var name = session.getString("name");
|
||||
var key = session.getString("key");
|
||||
|
||||
getDefaultPrefs().edit().putString("username", name).
|
||||
putString("sessionKey", key).apply();
|
||||
|
||||
Log.d("Scrobbler", "Auth success as " + name + ", key " + key);
|
||||
}
|
||||
|
||||
public static void logout() {
|
||||
edit().remove("username").apply();
|
||||
edit().remove("sessionKey").apply();
|
||||
scrobbled.clear();
|
||||
sendToast(AndroidUtils.getString("lastfm_logout_success"));
|
||||
}
|
||||
|
||||
public static boolean needToBeScrobble(String uid) {
|
||||
return isLoggedIn() && isScrobblingEnabled() && !scrobbled.contains(uid);
|
||||
}
|
||||
|
||||
public static boolean isLoggedIn() {
|
||||
return getDefaultPrefs().getString("sessionKey", null) != null;
|
||||
}
|
||||
|
||||
public static boolean isScrobblingEnabled() {
|
||||
return getPreferences().getBoolean("lastfm_enabled", false);
|
||||
}
|
||||
|
||||
public static String getUserName() {
|
||||
return getDefaultPrefs().getString("username", null);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package ru.vtosters.lite.ui.fragments;
|
||||
|
||||
import static bruhcollective.itaysonlab.libvkx.client.LibVKXClient.isVkxInstalled;
|
||||
import static ru.vtosters.lite.music.Scrobbler.isLoggedIn;
|
||||
import static ru.vtosters.lite.music.LastFMScrobbler.isLoggedIn;
|
||||
import static ru.vtosters.lite.proxy.ProxyUtils.getApi;
|
||||
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserToken;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.dp2px;
|
||||
@@ -44,7 +44,7 @@ import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import ru.vtosters.lite.downloaders.AudioDownloader;
|
||||
import ru.vtosters.lite.downloaders.VideoDownloader;
|
||||
import ru.vtosters.lite.music.Scrobbler;
|
||||
import ru.vtosters.lite.music.LastFMScrobbler;
|
||||
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
|
||||
import ru.vtosters.lite.ui.adapters.ImagineArrayAdapter;
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
@@ -107,7 +107,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
});
|
||||
|
||||
if (isLoggedIn()) {
|
||||
findPreference("lastfm_auth").setSummary(AndroidUtils.getString("lastfm_authorized_as") + " " + Scrobbler.getUserName());
|
||||
findPreference("lastfm_auth").setSummary(AndroidUtils.getString("lastfm_authorized_as") + " " + LastFMScrobbler.getUserName());
|
||||
} else {
|
||||
findPreference("lastfm_enabled").setEnabled(false);
|
||||
}
|
||||
@@ -181,7 +181,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
(dialog, which) -> {
|
||||
String login = fn.getText().toString();
|
||||
String pass = ln.getText().toString();
|
||||
Scrobbler.auth(login, pass);
|
||||
LastFMScrobbler.authenticate(login, pass);
|
||||
}
|
||||
)
|
||||
.setView(linearLayout)
|
||||
@@ -193,7 +193,7 @@ public class MediaFragment extends MaterialPreferenceToolbarFragment {
|
||||
.setTitle(AndroidUtils.getString("lastfm_logout_title"))
|
||||
.setMessage(AndroidUtils.getString("lastfm_logout_confirm"))
|
||||
.setPositiveButton(AndroidUtils.getString("vkim_yes"),
|
||||
(dialog, which) -> Scrobbler.logout())
|
||||
(dialog, which) -> LastFMScrobbler.logout())
|
||||
.setNeutralButton(AndroidUtils.getString("vkim_no"),
|
||||
(dialog, which) -> dialog.cancel())
|
||||
.show();
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
package ru.vtosters.lite.utils;
|
||||
|
||||
import static ru.vtosters.lite.hooks.DateHook.getLocale;
|
||||
import static ru.vtosters.lite.utils.Preferences.preferences;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.vk.core.util.Screen;
|
||||
import com.vk.core.util.ToastUtils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
import ru.vtosters.lite.hooks.DateHook;
|
||||
|
||||
public class AndroidUtils {
|
||||
|
||||
public static SharedPreferences getDefaultPrefs() {
|
||||
if (preferences == null)
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(getGlobalContext());
|
||||
return preferences;
|
||||
if (Preferences.preferences == null)
|
||||
Preferences.preferences = PreferenceManager.getDefaultSharedPreferences(getGlobalContext());
|
||||
return Preferences.preferences;
|
||||
}
|
||||
|
||||
public static SharedPreferences getPreferences() {
|
||||
@@ -90,7 +89,7 @@ public class AndroidUtils {
|
||||
}
|
||||
|
||||
public static Context setDefaultLocale(Context context) {
|
||||
Locale locale = new Locale(getLocale());
|
||||
Locale locale = new Locale(DateHook.getLocale());
|
||||
Locale.setDefault(locale);
|
||||
|
||||
var resources = context.getResources();
|
||||
@@ -123,26 +122,25 @@ public class AndroidUtils {
|
||||
}
|
||||
|
||||
public static void sendToast(String text) {
|
||||
Toast.makeText(getGlobalContext(), text, Toast.LENGTH_SHORT).show();
|
||||
ToastUtils.a(text);
|
||||
}
|
||||
|
||||
public static String MD5(String s) {
|
||||
try {
|
||||
var messageDigest = MessageDigest.getInstance("MD5");
|
||||
var md = MessageDigest.getInstance("MD5");
|
||||
md.update(s.getBytes());
|
||||
var md5 = md.digest();
|
||||
var sb = new StringBuilder();
|
||||
messageDigest.update(s.getBytes());
|
||||
byte[] digest = messageDigest.digest();
|
||||
for (byte b : digest) {
|
||||
StringBuilder hexString = new StringBuilder(Integer.toHexString(b & 255));
|
||||
while (hexString.length() < 2) {
|
||||
hexString.insert(0, "0");
|
||||
}
|
||||
sb.append(hexString);
|
||||
for (var b : md5) {
|
||||
var hex = Integer.toHexString(b & 0xFF);
|
||||
if (hex.length() == 1)
|
||||
sb.append(0);
|
||||
sb.append(hex);
|
||||
}
|
||||
return sb.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -703,7 +703,7 @@
|
||||
|
||||
.line 17
|
||||
:cond_0
|
||||
invoke-static {p1}, Lru/vtosters/lite/music/Scrobbler;->grabMusicTrack(Lcom/vk/dto/music/MusicTrack;)V
|
||||
invoke-static {p1}, Lru/vtosters/lite/music/LastFMScrobbler;->grabMusicTrack(Lcom/vk/dto/music/MusicTrack;)V
|
||||
|
||||
invoke-virtual {p1}, Lcom/vk/dto/music/MusicTrack;->y1()Ljava/lang/String;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user