Compare commits

...
15 Commits
25 changed files with 488 additions and 750 deletions
@@ -11,7 +11,6 @@ import com.vk.api.sdk.exceptions.VKApiExecutionException;
import com.vk.common.k.PodcastTimeCodeClickListener;
import com.vk.common.links.LinkParser;
import com.vk.core.util.ContextExtKt;
import com.vk.dto.music.Artist;
import com.vk.dto.music.MusicTrack;
import com.vk.music.artists.chooser.MusicArtistSelector;
import com.vk.music.common.MusicPlaybackLaunchContext;
@@ -24,6 +23,8 @@ import com.vtosters.lite.R;
import com.vtosters.lite.ViewUtils;
import com.vtosters.lite.ui.MusicErrorViewHelper;
import com.vtosters.lite.ui.holder.RecyclerHolder;
import ru.vtosters.lite.music.Genius;
import ru.vtosters.lite.utils.Preferences;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -155,6 +156,14 @@ public class LyricsHolder extends RecyclerHolder<PlayerInfo> implements View.OnC
@Override // com.vk.api.base.ApiCallback
public void a(VKApiExecutionException vKApiExecutionException) {
if (Preferences.getBoolValue("useGenius", false)) {
var text = Genius.getTextMusic(a);
var lyrics = new AudioGetLyrics.a();
lyrics.a = text;
a(lyrics);
return;
}
LyricsHolder.this.B.set(false);
LyricsHolder.this.f18328f.a(vKApiExecutionException);
LyricsHolder.this.f18328f.b(0);
@@ -6,12 +6,14 @@ import com.vk.dto.music.MusicTrack;
import com.vtosters.lite.R;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.utils.AndroidUtils;
import java.io.IOException;
import java.net.URLEncoder;
public class Genius {
private static final String KEY = "Bearer ZTejoT_ojOEasIkT9WrMBhBQOz6eYKK5QULCMECmOhvwqjRZ6WbpamFe3geHnvp3";
@@ -38,10 +40,8 @@ public class Genius {
return null;
}
Log.d("Genius", "/search/multi?q=" + artist + "%20" + track + "&from_background=0");
var request = new Request.a()
.b(URL + "/search/multi?q=" + artist + "%20" + track + "&from_background=0")
Request request = new Request.a()
.b(URL + "/search/multi?q=" + URLEncoder.encode(artist + " " + track) + "&from_background=0")
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
.a("Authorization", KEY)
.a("x-genius-app-background-request", "0")
@@ -51,26 +51,29 @@ public class Genius {
.b()
.a();
try {
var payload = client.a(request).execute().a().g();
var sections = new JSONObject(payload).getJSONObject("response").getJSONArray("sections");
Log.d("Genius", payload);
String payload = client.a(request).execute().a().g();
JSONArray sections = new JSONObject(payload).getJSONObject("response").getJSONArray("sections");
for (int i = 0; i < sections.length(); i++) {
var json = sections.optJSONObject(i);
JSONObject json = sections.optJSONObject(i);
if (json.optString("type").equals("song")) {
var path = json.getJSONArray("hits").getJSONObject(0).getJSONObject("result").getString("api_path");
JSONArray hits = json.getJSONArray("hits");
Log.d("Genius", path);
for (int j = 0; j < hits.length(); j++) {
JSONObject json2 = hits.optJSONObject(j);
JSONObject result = json2.getJSONObject("result");
return getText(path);
if (json2.optString("index").equals("song") && result.optString("path").contains("lyrics")) {
return getText(result.getString("api_path"));
}
}
}
}
return AndroidUtils.getString("error_no_text");
} catch (JSONException | IOException e) {
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getLocalizedMessage();
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getMessage();
}
}
@@ -80,7 +83,7 @@ public class Genius {
return null;
}
var request = new Request.a()
Request request = new Request.a()
.b(URL + track + "?text_format=plain")
.a("User-Agent", "Genius/5.14.0 (Android; Android 13; Google Pixel 4 XL)")
.a("Authorization", KEY)
@@ -91,16 +94,15 @@ public class Genius {
.b()
.a();
try {
var payload = new JSONObject(client.a(request).execute().a().g());
Log.d("Genius", String.valueOf(payload));
JSONObject payload = new JSONObject(client.a(request).execute().a().g());
if (!payload.has("response")) {
return AndroidUtils.getString("error_no_text");
}
return " " + payload.getJSONObject("response").getJSONObject("song").getJSONObject("lyrics").getString("plain");
return payload.getJSONObject("response").getJSONObject("song").getJSONObject("lyrics").getString("plain");
} catch (JSONException | IOException e) {
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getLocalizedMessage();
return AndroidUtils.getString("error_no_text") + "\n\n" + AndroidUtils.getString(R.string.error) + ": \n" + e.getMessage();
}
}
}
@@ -6,6 +6,7 @@ import java8.util.concurrent.CompletableFuture;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import ru.vtosters.lite.di.singleton.VtOkHttpClient;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.converter.ts.FFMpeg;
import ru.vtosters.lite.music.converter.ts.TSMerger;
import ru.vtosters.lite.music.downloader.ThumbnailDownloader;
@@ -18,7 +19,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
@@ -53,9 +53,9 @@ public class M3UDownloader implements ITrackDownloader {
return;
}
var request = new Request.a().b(track.D).a();
try {
var response = client.a(request).execute().a().g();
Request request = new Request.a().b(track.D).a();
String response = client.a(request).execute().a().g();
parse(response, outDir, callback, track, cache);
} catch (IOException e) {
e.printStackTrace();
@@ -64,61 +64,91 @@ public class M3UDownloader implements ITrackDownloader {
}
private void parse(String payload, File outDir, Callback callback, MusicTrack track, boolean cache) throws UnsupportedEncodingException {
if (cache) try {
if (cache) downloadThumbnails(track);
VKM3UParser parser = new VKM3UParser(track.D.substring(0, track.D.lastIndexOf("/") + 1), payload);
AtomicInteger progress = new AtomicInteger(0);
List<CompletableFuture<Void>> futures = createFutures(parser, progress, callback, track);
var resultTs = getResultTsFile(track);
var resultMp3 = getResultMp3File(outDir, cache, track);
callback.onProgress(5);
var future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
future.join();
future.exceptionally(throwable -> {
callback.onFailure();
return null;
}).thenApply(v -> TSMerger.merge(getTsesDir(track), resultTs))
.thenApply(mergeResult -> mergeResult && FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track))
.thenApply(convertResult -> {
if (convertResult)
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / parser.mTransportStreams.size()));
else callback.onFailure();
return convertResult;
}).thenRun(() -> IOUtils.deleteRecursive(getTsesDir(track))).thenRun(() -> {
callback.onSuccess();
if (cache) CacheDatabaseDelegate.insertTrack(track);
});
}
private void downloadThumbnails(MusicTrack track) {
try {
ThumbnailDownloader.downloadThumbnails(track);
} catch (IOException e) {
e.printStackTrace();
}
}
VKM3UParser parser = new VKM3UParser(payload);
List<TransportStream> tses = parser.getTransportStreams();
AtomicInteger progress = new AtomicInteger(0);
List<CompletableFuture<Void>> futures = new ArrayList<>(tses.size());
private List<CompletableFuture<Void>> createFutures(VKM3UParser parser, AtomicInteger progress, Callback callback, MusicTrack track) {
List<CompletableFuture<Void>> futures = new ArrayList<>(parser.mTransportStreams.size());
var tses = parser.mTransportStreams;
for (var i = 0; i < tses.size(); ++i) {
final var ts = tses.get(i);
final var filename = i + ".ts";
futures.add(CompletableFuture.runAsync(() -> processTransportStream(parser, ts, filename, progress, tses.size(), callback, track)));
}
return futures;
}
private void processTransportStream(VKM3UParser parser, TransportStream ts, String filename, AtomicInteger progress, int size, Callback callback, MusicTrack track) {
try {
InputStream mediaIs = IOUtils.openStream(ts.getMediaSegmentUri());
byte[] content;
if (ts.needDecoding()) {
InputStream keyPubIs = IOUtils.openStream(ts.getKeyURL());
content = IOUtils.decodeStream(mediaIs, IOUtils.readFully(keyPubIs));
keyPubIs.close();
} else {
content = IOUtils.readFully(mediaIs);
}
File tsDump = new File(getTsesDir(track), filename);
IOUtils.writeToFile(tsDump, content);
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / size));
callback.onSizeReceived((long) content.length * size, parser.mHeapSize);
mediaIs.close();
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | InvalidKeyException e) {
callback.onFailure();
throw new RuntimeException(e);
}
}
private File getTsesDir(MusicTrack track) {
var filesDir = AndroidUtils.getGlobalContext().getFilesDir();
var tsesDir = new File(filesDir, String.valueOf(track.d));
tsesDir.mkdirs();
var resultTs = new File(tsesDir, "result.ts");
return tsesDir;
}
private File getResultTsFile(MusicTrack track) {
return new File(getTsesDir(track), "result.ts");
}
private File getResultMp3File(File outDir, boolean cache, MusicTrack track) {
var fileName = IOUtils.getValidFileName((cache ? "track" : track.C + " - " + getTitle(track)) + ".mp3");
var resultMp3 = new File(outDir, fileName);
callback.onProgress(5);
for (TransportStream ts : tses) {
String tsURL = parser.getBaseUrl() + URLEncoder.encode(ts.getName(), "UTF-8");
futures.add(CompletableFuture.runAsync(() -> {
try {
InputStream is = IOUtils.openStream(tsURL);
byte[] content;
if (TransportStream.METHOD_AES128.equals(ts.getMethod())) {
String key = IOUtils.readAllLines(IOUtils.openStream(ts.getKeyURL()));
content = IOUtils.decodeStream(is, key);
} else {
content = IOUtils.readFully(is);
}
File tsDump = new File(tsesDir, ts.getName());
IOUtils.writeToFile(tsDump, content);
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
callback.onSizeReceived((long) content.length * tses.size(), parser.getHeapSize());
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException |
InvalidAlgorithmParameterException | InvalidKeyException e) {
callback.onFailure();
throw new RuntimeException(e);
}
}));
}
var future = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
future.join();
future.exceptionally(throwable -> {
callback.onFailure();
return null;
}).thenApply(v -> TSMerger.merge(tsesDir, resultTs)).thenApply(mergeResult -> mergeResult && FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track)).thenApply(convertResult -> {
if (convertResult)
callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()));
else callback.onFailure();
return convertResult;
}).thenRun(() -> IOUtils.deleteRecursive(tsesDir)).thenRun(callback::onSuccess);
return new File(outDir, fileName);
}
// Initialization-on-demand
@@ -1,36 +1,36 @@
package ru.vtosters.lite.music;
import android.text.TextUtils;
public class TransportStream {
public static final String METHOD_NONE = "NONE";
public static final String METHOD_AES128 = "AES-128";
private String mKeyUri;
private final String mMediaSegmentUri;
private String mMediaSegmentName;
private final String mMethod;
private String mName;
private String mKeyURL;
public TransportStream() {
this.mMethod = METHOD_NONE;
public TransportStream(String baseURI, String mediaSegmentName) {
this.mMediaSegmentUri = baseURI + mediaSegmentName;
}
public TransportStream(String method, String keyURL) {
this.mMethod = method;
this.mKeyURL = keyURL;
public TransportStream(String keyURI, String baseURI, String mediaSegmentName) {
this.mKeyUri = keyURI;
this.mMediaSegmentUri = baseURI + mediaSegmentName;
this.mMediaSegmentName = mediaSegmentName;
}
public String getMethod() {
return mMethod;
}
public String getName() {
return mName;
}
public void setName(String name) {
mName = name;
public boolean needDecoding() {
return !TextUtils.isEmpty(mKeyUri);
}
public String getKeyURL() {
return mKeyURL;
return mKeyUri;
}
public String getMediaSegmentUri() {
return this.mMediaSegmentUri;
}
public String getMediaSegmentName() {
return this.mMediaSegmentName;
}
}
@@ -1,69 +1,127 @@
package ru.vtosters.lite.music;
import android.text.TextUtils;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* The parser for extended M3U playlist format used by VK.
*
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#ref-M3U">M3U</a>
**/
public class VKM3UParser {
//Playlist types
static public int PLAYLIST_TYPE_VOD = 0;
static public int PLAYLIST_TYPE_EVENT = 1;
//region Extended M3U global extensions
public List<TransportStream> mTransportStreams = new ArrayList<>();
private final String mData;
private final List<TransportStream> mTransportStreams = new ArrayList<>();
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.1.2">EXT-X-VERSION</a>
**/
public int mVersion = -1;
/**
* The EXT-X-ALLOW-CACHE tag is used in protocol version 6 or lower.
* If the protocol version is upgraded by VK, we will not support that.
**/
public boolean mAllowCache = false;
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.1">EXT-X-TARGETDURATION</a>
**/
public int mTargetDuration = -1;
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.2">EXT-X-MEDIA-SEQUENCE</a>
**/
public int mMediaSequence = -1;
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.3">EXT-X-DISCONTINUITY-SEQUENCE</a>
**/
public int mDiscontinuitySequence = -1;
//endregion
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.5">EXT-X-PLAYLIST-TYPE</a>
**/
public int mPlaylistType = -1;
/**
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.6">EXT-X-I-FRAMES-ONLY</a>
**/
public boolean mIFramesOnly = false;
public long mHeapSize = 0;
// maybe will be used
private int mDuration;
private int mHeapSize = 0;
private String mBaseURL;
public VKM3UParser(String data) {
public VKM3UParser(String baseUri, String data) {
mData = data;
init();
init(baseUri);
}
public static boolean isM3U8(String str) {
return str.endsWith(".ts") || str.endsWith(".tp") || str.endsWith(".mpeg-ts") || str.endsWith(".m2ts");
public static boolean isTS(String str) {
return str.matches(".+\\.ts.*");
}
private void init() {
int i = 0;
private void init(String baseUri) {
if (TextUtils.isEmpty(mData)) throw new NullPointerException("mData==null");
Scanner scanner = new Scanner(mData);
while (scanner.hasNext()) {
String line = scanner.nextLine();
mHeapSize += line.getBytes().length;
if (line.startsWith("#EXT-X-TARGETDURATION")) {
mDuration = Integer.parseInt(getDirectiveValue(line));
} else if (line.startsWith("#EXT-X-KEY")) {
String base = getDirectiveValue(line);
final TransportStream ts;
if (!base.startsWith("METHOD=NONE")) {
String keyURL = base.substring(base.indexOf("\"") + 1, base.lastIndexOf("\""));
mBaseURL = keyURL.substring(0, keyURL.lastIndexOf("/") + 1);
ts = new TransportStream(TransportStream.METHOD_AES128, keyURL);
} else {
ts = new TransportStream();
String line = scanner.nextLine();
if (!"#EXTM3U".equals(line)) throw new IllegalStateException(String.format("Unknown initial M3U tag: %s", line));
boolean aes128 = false;
String keyUri = "";
while (scanner.hasNextLine()) {
line = scanner.nextLine();
if ('#' == line.charAt(0)) {
parseTag(line);
if (line.startsWith("#EXT-X-KEY:") && line.contains("METHOD=AES-128")) {
aes128 = true;
keyUri = getKeyUri(line, baseUri);
}
mTransportStreams.add(ts);
} else if (line.startsWith("#EXTINF")) {
if (mTransportStreams.size() == i)
mTransportStreams.add(new TransportStream());
} else if (isM3U8(line)) {
mTransportStreams.get(i).setName(line.substring(line.lastIndexOf("/") + 1));
++i;
} else if (isTS(line)) {
addTransportStream(aes128, keyUri, baseUri, line);
aes128 = false;
} else {
throw new RuntimeException(String.format("Failed to parse: %s", line));
}
mHeapSize += line.getBytes().length;;
}
}
private String getDirectiveValue(String directive) {
return directive.substring(directive.indexOf(":") + 1);
private void parseTag(String line) {
if (line.startsWith("#EXT-X-VERSION:"))
mVersion = Integer.parseInt(line.substring(15));
else if (line.startsWith("#EXT-X-ALLOW-CACHE:"))
mAllowCache = "YES".equalsIgnoreCase(line.substring(19));
else if (line.startsWith("#EXT-X-TARGETDURATION:"))
mTargetDuration = Integer.parseInt(line.substring(22));
else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE:"))
mMediaSequence = Integer.parseInt(line.substring(22));
else if (line.startsWith("#EXT-X-DISCONTINUITY-SEQUENCE:"))
mDiscontinuitySequence = Integer.parseInt(line.substring(30));
else if (line.startsWith("#EXT-X-PLAYLIST-TYPE:"))
parsePlaylistType(line.substring(21));
else if (line.startsWith("#EXT-X-I-FRAMES-ONLY"))
mIFramesOnly = true;
}
public int getHeapSize() {
return mHeapSize;
private void parsePlaylistType(String type) {
switch (type) {
case "VOD" -> mPlaylistType = PLAYLIST_TYPE_VOD;
case "EVENT" -> mPlaylistType = PLAYLIST_TYPE_EVENT;
default -> throw new IllegalStateException(String.format("Unknown playlist type: %s", type));
}
}
public String getBaseUrl() {
return mBaseURL;
private String getKeyUri(String line, String baseUri) {
String substr = line.substring(11);
substr = substr.substring(substr.indexOf('"') + 1, substr.lastIndexOf('"'));
//TODO: supposed endpoint
return substr.startsWith("http") ? substr : baseUri + substr;
}
public List<TransportStream> getTransportStreams() {
return mTransportStreams;
private void addTransportStream(boolean aes128, String keyUri, String baseUri, String line) {
TransportStream ts = aes128
? new TransportStream(keyUri, baseUri, line)
: new TransportStream(baseUri, line);
mTransportStreams.add(ts);
}
}
@@ -83,7 +83,6 @@ public class PlaylistHelper {
}
public static JSONObject getPlaylist() throws JSONException {
return new JSONObject()
.put("id", -1)
.put("owner_id", getUserId())
@@ -11,9 +11,13 @@ import ru.vtosters.lite.music.cache.FileCacheImplementation;
import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
public class TracklistHelper {
public static List<MusicTrack> getMyCachedMusicTracks() {
return getTracksWithThumbnails(TracklistHelper.getTracks());
}
public static List<MusicTrack> getTracks() {
return CacheDatabaseDelegate.getTracks();
@@ -50,6 +54,21 @@ public class TracklistHelper {
return arr;
}
public static List<MusicTrack> getTracksWithThumbnails(List<MusicTrack> list) {
List<MusicTrack> tracks = new ArrayList<>();
for (MusicTrack track : list) {
var json = track.J();
var folder = FileCacheImplementation.getThumbnailsFolder(LibVKXClient.asId(track));
try {
addCachedThumbnails(json, folder);
} catch (JSONException | MalformedURLException e) {
Log.d("TracklistHelper", e.getMessage());
}
tracks.add(new MusicTrack(json));
}
return tracks;
}
private static void addCachedThumbnails(JSONObject target, File thumbnailsDir)
throws JSONException, MalformedURLException {
var sizes = new JSONArray();
@@ -83,7 +83,7 @@ public class PlaylistInjector {
}
if (isVirtualPlaylist) {
response.c = (ArrayList<MusicTrack>) TracklistHelper.getTracks();
response.c = (ArrayList<MusicTrack>) TracklistHelper.getMyCachedMusicTracks();
response.b = PlaylistHelper.createCachedPlaylistMetadata();
} else {
response.c = (ArrayList<MusicTrack>) TracklistHelper.getTracks(requestArgs.get("owner_id"));
@@ -0,0 +1,25 @@
package ru.vtosters.lite.music.cache.injectors;
import com.vk.dto.music.MusicTrack;
import com.vk.music.model.IpcPlayerModelImpl;
import com.vk.music.model.PlayerModelImpl;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
import java.util.Collections;
import java.util.List;
public class ShuffleInjector {
public static void shuffleTracks(IpcPlayerModelImpl ipcPlayerModel) {
ipcPlayerModel.a(getShuffledList());
}
public static void shuffleTracks(PlayerModelImpl playerModelImpl) {
playerModelImpl.a(getShuffledList());
}
private static List<MusicTrack> getShuffledList() {
List<MusicTrack> shuffled = TracklistHelper.getMyCachedMusicTracks();
Collections.shuffle(shuffled);
return shuffled;
}
}
@@ -12,17 +12,13 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import ru.vtosters.lite.music.cache.CacheDatabaseDelegate;
import ru.vtosters.lite.music.cache.helpers.PlaylistHelper;
import ru.vtosters.lite.music.cache.helpers.TracklistHelper;
import ru.vtosters.lite.utils.AccountManagerUtils;
import ru.vtosters.lite.utils.AndroidUtils;
import ru.vtosters.lite.utils.NetworkUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import static ru.vtosters.lite.music.cache.CacheDatabaseDelegate.hasTracks;
import static ru.vtosters.lite.music.cache.helpers.PlaylistHelper.*;
import static ru.vtosters.lite.utils.AccountManagerUtils.getUserId;
import java.util.*;
public class TracklistInjector {
@@ -58,7 +54,7 @@ public class TracklistInjector {
}
});
} else {
if (!hasTracks()) {
if (!CacheDatabaseDelegate.hasTracks()) {
observableEmitter.b(parser.c(getEmptyCatalog()));
} else {
observableEmitter.b(parser.c(createVirtualCatalog(TracklistHelper.getTracks())));
@@ -68,66 +64,114 @@ public class TracklistInjector {
}
private static JSONObject getEmptyCatalog() throws JSONException {
return new JSONObject("{\"catalog\":{\"default_section\":\"cache\",\"sections\":[{\"id\":\"cache\",\"title\":\"" + AndroidUtils.getString(R.string.cached_content_title) + "\",\"blocks\":[{\"data_type\":\"placeholder\",\"id\":\"0\",\"layout\":{\"name\":\"placeholder_big\"},\"placeholder_ids\":[\"_synth_trackEmpty\"]}]}]},\"audios\":[],\"playlists\":[],\"placeholders\":[{\"id\":\"_synth_trackEmpty\",\"title\":\"" + AndroidUtils.getString(R.string.cached_content_empty) + "\",\"text\":\"" + AndroidUtils.getString(R.string.cached_content_empty_desc) + "\",\"buttons\":[]}]}");
JSONObject emptyCatalog = new JSONObject();
JSONObject catalog = new JSONObject();
catalog.put("default_section", "cache");
JSONArray sections = new JSONArray();
JSONObject section = new JSONObject();
section.put("id", "cache");
section.put("title", AndroidUtils.getString(R.string.cached_content_title));
JSONArray blocks = new JSONArray();
JSONObject block = new JSONObject();
block.put("data_type", "placeholder");
block.put("id", "0");
JSONObject layout = new JSONObject();
layout.put("name", "placeholder_big");
block.put("layout", layout);
JSONArray placeholderIds = new JSONArray();
placeholderIds.put("_synth_trackEmpty");
block.put("placeholder_ids", placeholderIds);
blocks.put(block);
section.put("blocks", blocks);
sections.put(section);
catalog.put("sections", sections);
emptyCatalog.put("catalog", catalog);
emptyCatalog.put("audios", new JSONArray());
emptyCatalog.put("playlists", new JSONArray());
JSONArray placeholders = new JSONArray();
JSONObject placeholder = new JSONObject();
placeholder.put("id", "_synth_trackEmpty");
placeholder.put("title", AndroidUtils.getString(R.string.cached_content_empty));
placeholder.put("text", AndroidUtils.getString(R.string.cached_content_empty_desc));
placeholder.put("buttons", new JSONArray());
placeholders.put(placeholder);
emptyCatalog.put("placeholders", placeholders);
return emptyCatalog;
}
private static JSONObject getShuffleButton() throws JSONException {
JSONObject shuffleButton = new JSONObject();
shuffleButton.put("id", getRandomId());
shuffleButton.put("data_type", "action");
JSONObject layout = new JSONObject();
layout.put("name", "horizontal_buttons");
layout.put("owner_id", AccountManagerUtils.getUserId());
shuffleButton.put("layout", layout);
JSONArray listenEvents = new JSONArray();
listenEvents.put("music_audios_remove");
listenEvents.put("music_audios_add");
shuffleButton.put("listen_events", listenEvents);
JSONArray buttons = new JSONArray();
JSONObject button = new JSONObject();
JSONObject action = new JSONObject();
action.put("type", "play_shuffled_audios_from_block");
button.put("action", action);
button.put("block_id", "shuffle");
button.put("ref_items_count", CacheDatabaseDelegate.getTrackCount());
button.put("ref_layout_name", "list");
button.put("ref_data_type", "music_audios");
buttons.put(button);
shuffleButton.put("buttons", buttons);
return shuffleButton;
}
public static void injectIntoExistingCatalog(JSONObject catalogNode) {
Log.d("TracklistInjector", "injectIntoExistingCatalog");
try {
var catalog = catalogNode.getJSONObject("catalog");
var sectionsNode = catalog.getJSONArray("sections");
var firstSection = sectionsNode.getJSONObject(0);
JSONObject catalog = catalogNode.getJSONObject("catalog");
JSONArray sectionsNode = catalog.getJSONArray("sections");
JSONObject firstSection = sectionsNode.getJSONObject(0);
if (!firstSection.getString("url").equals("https://vk.com/audios" + getUserId() + "?section=all"))
if (!isFirstSectionUrlValid(firstSection)) {
return;
}
var blocks = firstSection.getJSONArray("blocks");
JSONArray blocks = firstSection.getJSONArray("blocks");
if (CacheDatabaseDelegate.hasTracks() && !LibVKXClient.isIntegrationEnabled()) { // inj in playlist list
var noPlaylists = blocks.optJSONObject(0).optJSONArray("buttons").optJSONObject(0).optJSONObject("action").optString("type").equals("create_playlist");
boolean noPlaylists = hasNoPlaylists(blocks);
if (noPlaylists) {
catalogNode.put("playlists", new JSONArray().put(getPlaylist()));
Log.d("catalogInjector", "added new pl");
catalogNode.put("playlists", new JSONArray().put(PlaylistHelper.getPlaylist()));
var newBlocks = new JSONArray();
newBlocks
.put(getCatalogHeader())
.put(getCatalogPlaylist())
.put(getCatalogSeparator());
JSONArray newBlocks = createNewBlocks(blocks);
Log.d("catalogInjector", "added cache catalog playlist");
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
firstSection.put("blocks", newBlocks);
} else {
try {
catalogNode.optJSONArray("playlists").put(getPlaylist());
Log.d("catalogInjector", "added to exist pl");
catalogNode.optJSONArray("playlists").put(PlaylistHelper.getPlaylist());
for (int i = 0; i < blocks.length(); i++) {
var j = blocks.optJSONObject(i);
var type = j.optString("data_type");
if (type.equals("music_playlists") && j.has("playlists_ids")) {
var newarr = new JSONArray();
var playlists_ids = j.optJSONArray("playlists_ids");
newarr.put(getUserId() + "_-1");
for (int n = 0; n < playlists_ids.length(); n++) {
newarr.put(playlists_ids.optString(n));
}
j.put("playlists_ids", newarr);
break;
}
}
updatePlaylistsIds(blocks);
} catch (Exception e) {
Log.d("catalogInjector", e.toString());
}
@@ -138,24 +182,49 @@ public class TracklistInjector {
}
}
public static JSONObject createVirtualCatalog(List<MusicTrack> tracks)
throws JSONException {
Log.d("TracklistInjector", "createVirtualCatalog");
private static boolean isFirstSectionUrlValid(JSONObject firstSection) throws JSONException {
return firstSection.getString("url").equals("https://vk.com/audios" + AccountManagerUtils.getUserId() + "?section=all");
}
var clickAction = new JSONObject()
.put("type", "open_url")
.put("target", "internal")
.put("url", "https://vkx.app/index.html?app=vt_ctg");
private static boolean hasNoPlaylists(JSONArray blocks) throws JSONException {
return blocks.optJSONObject(0).optJSONArray("buttons").optJSONObject(0).optJSONObject("action").optString("type").equals("create_playlist");
}
var catalogBanner = new JSONObject()
.put("id", 1234)
.put("image_mode", "cover")
.put("title", AndroidUtils.getString(R.string.vkx_integration_title))
.put("text", AndroidUtils.getString(R.string.vkx_integration_desc))
.put("click_action", new JSONObject().put("action", clickAction));
var catalogBanners = new JSONArray()
.put(catalogBanner);
private static JSONArray createNewBlocks(JSONArray blocks) throws JSONException {
JSONArray newBlocks = new JSONArray();
newBlocks
.put(PlaylistHelper.getCatalogHeader())
.put(PlaylistHelper.getCatalogPlaylist())
.put(PlaylistHelper.getCatalogSeparator());
for (int i = 0; i < blocks.length(); i++) {
newBlocks.put(blocks.optJSONObject(i));
}
return newBlocks;
}
private static void updatePlaylistsIds(JSONArray blocks) throws JSONException {
for (int i = 0; i < blocks.length(); i++) {
JSONObject j = blocks.optJSONObject(i);
String type = j.optString("data_type");
if (type.equals("music_playlists") && j.has("playlists_ids")) {
JSONArray newarr = new JSONArray();
JSONArray playlists_ids = j.optJSONArray("playlists_ids");
newarr.put(AccountManagerUtils.getUserId() + "_-1");
for (int n = 0; n < playlists_ids.length(); n++) {
newarr.put(playlists_ids.optString(n));
}
j.put("playlists_ids", newarr);
break;
}
}
}
public static JSONObject createVirtualCatalog(List<MusicTrack> tracks) throws JSONException {
var audiosBlock = new JSONObject()
.put("id", getRandomId())
.put("data_type", "music_audios")
@@ -164,28 +233,12 @@ public class TracklistInjector {
var layout = new JSONObject()
.put("name", "list")
.put("owner_id", getUserId());
.put("owner_id", AccountManagerUtils.getUserId());
audiosBlock.put("layout", layout);
var blocks = new JSONArray()
.put(audiosBlock);
var blocks = new JSONArray().put(getShuffleButton()).put(audiosBlock);
// var vkxPostirony = new JSONObject()
// .put("id", getRandomId())
// .put("data_type", "catalog_banners")
// .put("url", "synth:cache:vkx")
// .put("catalog_banner_ids", new JSONArray().put(1234));
//
// var vkxlayout = new JSONObject()
// .put("name", "large_list")
// .put("owner_id", Globals.getUserId())
// .put("infinite_repeat", true);
//
// vkxPostirony.put("layout", vkxlayout);
//
// if (eligibleForVkxAd())
// blocks.put(vkxPostirony);
var randomId = getRandomId();
var section = new JSONObject()
@@ -203,8 +256,7 @@ public class TracklistInjector {
return new JSONObject()
.put("catalog", catalog)
.put("audios", TracklistHelper.tracksToJsons(tracks))
.put("catalog_banners", catalogBanners);
.put("audios", TracklistHelper.tracksToJsons(tracks));
}
private static String getRandomId() {
@@ -26,11 +26,7 @@ public class TSMerger {
var mergedByteArrayStream = new ByteArrayOutputStream();
Arrays.sort(tsesList, (o1, o2) -> {
var index1 = Integer.parseInt(o1.getName().split("-")[1]);
var index2 = Integer.parseInt(o2.getName().split("-")[1]);
return index1 - index2;
});
sortTsesList(tsesList);
for (var file : tsesList) {
if (file.getName().endsWith(".ts")) {
@@ -43,6 +39,20 @@ public class TSMerger {
}
}
return writeOutputFile(out, mergedByteArrayStream);
}
private static void sortTsesList(File[] tsesList) {
Arrays.sort(tsesList, (ts1, ts2) -> {
String ts1Name = ts1.getName();
String ts2Name = ts2.getName();
int i1 = Integer.parseInt(ts1Name.substring(0, ts1Name.indexOf('.', 1)));
int i2 = Integer.parseInt(ts2Name.substring(0, ts2Name.indexOf('.', 1)));
return Integer.compare(i1, i2);
});
}
private static boolean writeOutputFile(File out, ByteArrayOutputStream mergedByteArrayStream) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Files.write(out.toPath(), mergedByteArrayStream.toByteArray());
@@ -35,7 +35,6 @@ public class TrackDownloader {
var path = FileCacheImplementation.getTrackFolder(LibVKXClient.asId(track)).getAbsolutePath();
download(track, path, callback, M3UDownloader.getInstance(), true);
CacheDatabaseDelegate.insertTrack(track);
}
private static void download(MusicTrack track, String path, Callback callback, ITrackDownloader downloader, boolean cache) {
@@ -19,11 +19,12 @@ public class ImBanner {
var user_id = orig.getJSONObject("peer").getInt("id");
if (!UsersList.hasBanner(user_id) || user_id == 0) {
if (getBoolValue("convBarRecomm", false)) {
return null;
} else {
return orig.optJSONObject("conversation_bar");
}
// if (getBoolValue("convBarRecomm", false)) {
// return null;
// } else {
// return orig.optJSONObject("conversation_bar");
// }
return null;
}
try {
@@ -18,17 +18,16 @@ import java.util.Arrays;
public class IOUtils {
public static final int BUFFER_SIZE = 8192;
public static byte[] decodeStream(InputStream encIs, String keyURL)
public static byte[] decodeStream(InputStream encIs,byte[] aesKey)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
CipherInputStream cip = new CipherInputStream(encIs, getCipher(keyURL));
CipherInputStream cip = new CipherInputStream(encIs, getCipher(aesKey));
return readFully(cip);
}
public static Cipher getCipher(String key)
public static Cipher getCipher(byte[] aesKey)
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Key keySpec = new SecretKeySpec(key.getBytes(), "AES");
// bypassing ecb
Key keySpec = new SecretKeySpec(aesKey, "AES");
byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x0);
IvParameterSpec ivps = new IvParameterSpec(iv);
+1 -3
View File
@@ -155,6 +155,7 @@
android:resizeableActivity="true"
android:roundIcon="@mipmap/vt_launcher_round"
android:supportsRtl="true"
android:appCategory="social"
android:theme="@style/VkLightStyle">
<meta-data
android:name="com.google.android.geo.API_KEY"
@@ -165,9 +166,6 @@
<meta-data
android:name="com.google.android.geo.API_SECRET"
android:value="yu6ZAA0OWO3kmr4es7fGtSmiyfk=" />
<meta-data
android:name="com.vk.safetynet.API_SECRET"
android:value="AIzaSyBf_eM-cgRbg1gOkyEc2Il5gHqgsnFyVug" />
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/fb_app_id" />
-5
View File
@@ -17,11 +17,6 @@
android:entryValues="@array/animations_values"
android:key="anim_rtrn_type"
android:title="@string/franimation"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="useGenius"
android:summary="@string/useGenius_summ"
android:title="@string/useGenius_title"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="true"
android:key="useNewSettings"
+5
View File
@@ -21,6 +21,11 @@
android:key="autocache"
android:summary="@string/autocache_summ"
android:title="@string/autocache_title"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="useGenius"
android:summary="@string/useGenius_summ"
android:title="@string/useGenius_title"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="useOldAppVer"
+5 -5
View File
@@ -20,11 +20,11 @@
android:key="voice"
android:summary="@string/vtlvoicesummary"
android:title="@string/vtlvoice"/>
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="convBarRecomm"
android:summary="@string/convBarRecomm_summ"
android:title="@string/convBarRecomm_title"/>
<!-- <com.vtosters.lite.ui.MaterialSwitchPreference-->
<!-- android:defaultValue="false"-->
<!-- android:key="convBarRecomm"-->
<!-- android:summary="@string/convBarRecomm_summ"-->
<!-- android:title="@string/convBarRecomm_title"/>-->
<com.vtosters.lite.ui.MaterialSwitchPreference
android:defaultValue="false"
android:key="wbios"
@@ -1,99 +0,0 @@
.class final Lcom/vk/common/VKSafetyNet$a;
.super Ljava/lang/Object;
.source "VKSafetyNet.kt"
# interfaces
.implements Lcom/google/android/gms/tasks/e;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/vk/common/VKSafetyNet;->a()Lkotlin/Triple;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x18
name = null
.end annotation
.annotation system Ldalvik/annotation/Signature;
value = {
"<TResult:",
"Ljava/lang/Object;",
">",
"Ljava/lang/Object;",
"Lcom/google/android/gms/tasks/e<",
"Lcom/google/android/gms/safetynet/c$a;",
">;"
}
.end annotation
# instance fields
.field final synthetic a:Ljava/util/concurrent/atomic/AtomicReference;
.field final synthetic b:Ljava/lang/Object;
# direct methods
.method constructor <init>(Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)V
.locals 0
iput-object p1, p0, Lcom/vk/common/VKSafetyNet$a;->a:Ljava/util/concurrent/atomic/AtomicReference;
iput-object p2, p0, Lcom/vk/common/VKSafetyNet$a;->b:Ljava/lang/Object;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public final a(Lcom/google/android/gms/safetynet/c$a;)V
.locals 1
.line 2
iget-object v0, p0, Lcom/vk/common/VKSafetyNet$a;->a:Ljava/util/concurrent/atomic/AtomicReference;
invoke-virtual {v0, p1}, Ljava/util/concurrent/atomic/AtomicReference;->set(Ljava/lang/Object;)V
.line 3
iget-object p1, p0, Lcom/vk/common/VKSafetyNet$a;->b:Ljava/lang/Object;
monitor-enter p1
.line 4
:try_start_0
iget-object v0, p0, Lcom/vk/common/VKSafetyNet$a;->b:Ljava/lang/Object;
invoke-virtual {v0}, Ljava/lang/Object;->notifyAll()V
.line 5
sget-object v0, Lkotlin/Unit;->a:Lkotlin/Unit;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.line 6
monitor-exit p1
return-void
:catchall_0
move-exception v0
monitor-exit p1
throw v0
.end method
.method public bridge synthetic a(Ljava/lang/Object;)V
.locals 0
.line 1
check-cast p1, Lcom/google/android/gms/safetynet/c$a;
invoke-virtual {p0, p1}, Lcom/vk/common/VKSafetyNet$a;->a(Lcom/google/android/gms/safetynet/c$a;)V
return-void
.end method
@@ -1,76 +0,0 @@
.class final Lcom/vk/common/VKSafetyNet$b;
.super Ljava/lang/Object;
.source "VKSafetyNet.kt"
# interfaces
.implements Lcom/google/android/gms/tasks/d;
# annotations
.annotation system Ldalvik/annotation/EnclosingMethod;
value = Lcom/vk/common/VKSafetyNet;->a()Lkotlin/Triple;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
accessFlags = 0x18
name = null
.end annotation
# instance fields
.field final synthetic a:Ljava/util/concurrent/atomic/AtomicReference;
.field final synthetic b:Ljava/lang/Object;
# direct methods
.method constructor <init>(Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)V
.locals 0
iput-object p1, p0, Lcom/vk/common/VKSafetyNet$b;->a:Ljava/util/concurrent/atomic/AtomicReference;
iput-object p2, p0, Lcom/vk/common/VKSafetyNet$b;->b:Ljava/lang/Object;
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
# virtual methods
.method public final onFailure(Ljava/lang/Exception;)V
.locals 1
.line 1
iget-object v0, p0, Lcom/vk/common/VKSafetyNet$b;->a:Ljava/util/concurrent/atomic/AtomicReference;
invoke-virtual {v0, p1}, Ljava/util/concurrent/atomic/AtomicReference;->set(Ljava/lang/Object;)V
.line 2
iget-object p1, p0, Lcom/vk/common/VKSafetyNet$b;->b:Ljava/lang/Object;
monitor-enter p1
.line 3
:try_start_0
iget-object v0, p0, Lcom/vk/common/VKSafetyNet$b;->b:Ljava/lang/Object;
invoke-virtual {v0}, Ljava/lang/Object;->notifyAll()V
.line 4
sget-object v0, Lkotlin/Unit;->a:Lkotlin/Unit;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.line 5
monitor-exit p1
return-void
:catchall_0
move-exception v0
monitor-exit p1
throw v0
.end method
@@ -1,316 +0,0 @@
.class public final Lcom/vk/common/VKSafetyNet;
.super Ljava/lang/Object;
.source "VKSafetyNet.kt"
# static fields
.field public static final a:Lcom/vk/common/VKSafetyNet;
# direct methods
.method static constructor <clinit>()V
.locals 1
.line 1
new-instance v0, Lcom/vk/common/VKSafetyNet;
invoke-direct {v0}, Lcom/vk/common/VKSafetyNet;-><init>()V
sput-object v0, Lcom/vk/common/VKSafetyNet;->a:Lcom/vk/common/VKSafetyNet;
return-void
.end method
.method private constructor <init>()V
.locals 0
.line 1
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method private final a(Landroid/content/Context;)Ljava/lang/String;
.locals 5
const/4 v0, 0x0
.line 21
:try_start_0
invoke-virtual {p1}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v1
invoke-virtual {p1}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
move-result-object p1
const/16 v2, 0x80
invoke-virtual {v1, p1, v2}, Landroid/content/pm/PackageManager;->getApplicationInfo(Ljava/lang/String;I)Landroid/content/pm/ApplicationInfo;
move-result-object p1
iget-object p1, p1, Landroid/content/pm/ApplicationInfo;->metaData:Landroid/os/Bundle;
const-string v1, "com.vk.safetynet.API_SECRET"
.line 22
invoke-virtual {p1, v1, v0}, Landroid/os/Bundle;->getString(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
:try_end_0
.catch Landroid/content/pm/PackageManager$NameNotFoundException; {:try_start_0 .. :try_end_0} :catch_0
goto :goto_0
:catch_0
move-exception p1
const/4 v1, 0x1
new-array v1, v1, [Ljava/lang/Object;
const/4 v2, 0x0
.line 23
new-instance v3, Ljava/lang/StringBuilder;
invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V
const-string v4, "can\'t get key "
invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v3, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/Object;)Ljava/lang/StringBuilder;
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object p1
aput-object p1, v1, v2
invoke-static {v1}, Lcom/vk/log/L;->e([Ljava/lang/Object;)V
:goto_0
return-object v0
.end method
.method private final b()[B
.locals 4
const/16 v0, 0x10
new-array v0, v0, [B
.line 1
new-instance v1, Ljava/util/Random;
invoke-static {}, Landroid/os/SystemClock;->currentThreadTimeMillis()J
move-result-wide v2
invoke-direct {v1, v2, v3}, Ljava/util/Random;-><init>(J)V
invoke-virtual {v1, v0}, Ljava/util/Random;->nextBytes([B)V
return-object v0
.end method
# virtual methods
.method public final a()Lkotlin/Triple;
.locals 7
.annotation system Ldalvik/annotation/Signature;
value = {
"()",
"Lkotlin/Triple<",
"Ljava/lang/String;",
"[B",
"Ljava/lang/Long;",
">;"
}
.end annotation
.line 1
invoke-static {}, Lcom/google/android/gms/common/c;->a()Lcom/google/android/gms/common/c;
move-result-object v0
.line 2
sget-object v1, Lcom/vk/core/util/AppContextHolder;->a:Landroid/content/Context;
invoke-virtual {v0, v1}, Lcom/google/android/gms/common/c;->c(Landroid/content/Context;)I
move-result v0
if-nez v0, :cond_3
.line 3
sget-object v0, Lcom/vk/core/util/AppContextHolder;->a:Landroid/content/Context;
const-string v1, "AppContextHolder.context"
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/String;)V
invoke-direct {p0, v0}, Lcom/vk/common/VKSafetyNet;->a(Landroid/content/Context;)Ljava/lang/String;
move-result-object v0
if-eqz v0, :cond_2
.line 4
new-instance v1, Ljava/util/concurrent/atomic/AtomicReference;
invoke-direct {v1}, Ljava/util/concurrent/atomic/AtomicReference;-><init>()V
.line 5
new-instance v2, Ljava/util/concurrent/atomic/AtomicReference;
invoke-direct {v2}, Ljava/util/concurrent/atomic/AtomicReference;-><init>()V
.line 6
new-instance v3, Ljava/lang/Object;
invoke-direct {v3}, Ljava/lang/Object;-><init>()V
.line 7
invoke-direct {p0}, Lcom/vk/common/VKSafetyNet;->b()[B
move-result-object v4
.line 8
sget-object v5, Lcom/vk/core/util/AppContextHolder;->a:Landroid/content/Context;
invoke-static {v5}, Lcom/google/android/gms/safetynet/b;->a(Landroid/content/Context;)Lcom/google/android/gms/safetynet/d;
move-result-object v5
invoke-virtual {v5, v4, v0}, Lcom/google/android/gms/safetynet/d;->a([BLjava/lang/String;)Lcom/google/android/gms/tasks/g;
move-result-object v0
.line 9
new-instance v5, Lcom/vk/common/VKSafetyNet$a;
invoke-direct {v5, v1, v3}, Lcom/vk/common/VKSafetyNet$a;-><init>(Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)V
invoke-virtual {v0, v5}, Lcom/google/android/gms/tasks/g;->a(Lcom/google/android/gms/tasks/e;)Lcom/google/android/gms/tasks/g;
.line 10
new-instance v5, Lcom/vk/common/VKSafetyNet$b;
invoke-direct {v5, v2, v3}, Lcom/vk/common/VKSafetyNet$b;-><init>(Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/Object;)V
invoke-virtual {v0, v5}, Lcom/google/android/gms/tasks/g;->a(Lcom/google/android/gms/tasks/d;)Lcom/google/android/gms/tasks/g;
.line 11
monitor-enter v3
const-wide/16 v5, 0x2710
.line 12
:try_start_0
invoke-virtual {v3, v5, v6}, Ljava/lang/Object;->wait(J)V
.line 13
sget-object v0, Lkotlin/Unit;->a:Lkotlin/Unit;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
.line 14
monitor-exit v3
.line 15
invoke-virtual {v1}, Ljava/util/concurrent/atomic/AtomicReference;->get()Ljava/lang/Object;
move-result-object v0
if-eqz v0, :cond_0
new-instance v0, Lkotlin/Triple;
invoke-virtual {v1}, Ljava/util/concurrent/atomic/AtomicReference;->get()Ljava/lang/Object;
move-result-object v1
const-string v2, "resultRef.get()"
invoke-static {v1, v2}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/String;)V
check-cast v1, Lcom/google/android/gms/safetynet/c$a;
invoke-virtual {v1}, Lcom/google/android/gms/safetynet/c$a;->b()Ljava/lang/String;
move-result-object v1
sget-object v2, Lcom/vk/core/network/TimeProvider;->f:Lcom/vk/core/network/TimeProvider;
invoke-virtual {v2}, Lcom/vk/core/network/TimeProvider;->b()J
move-result-wide v2
invoke-static {v2, v3}, Ljava/lang/Long;->valueOf(J)Ljava/lang/Long;
move-result-object v2
invoke-direct {v0, v1, v4, v2}, Lkotlin/Triple;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
return-object v0
.line 16
:cond_0
invoke-virtual {v2}, Ljava/util/concurrent/atomic/AtomicReference;->get()Ljava/lang/Object;
move-result-object v0
if-eqz v0, :cond_1
invoke-virtual {v2}, Ljava/util/concurrent/atomic/AtomicReference;->get()Ljava/lang/Object;
move-result-object v0
const-string v1, "errorRef.get()"
invoke-static {v0, v1}, Lkotlin/jvm/internal/Intrinsics;->a(Ljava/lang/Object;Ljava/lang/String;)V
check-cast v0, Ljava/lang/Throwable;
throw v0
.line 17
:cond_1
new-instance v0, Ljava/io/IOException;
const-string v1, "Can\'t cat result from SafetyNet"
invoke-direct {v0, v1}, Ljava/io/IOException;-><init>(Ljava/lang/String;)V
throw v0
:catchall_0
move-exception v0
.line 18
monitor-exit v3
throw v0
.line 19
:cond_2
new-instance v0, Ljava/io/IOException;
const-string v1, "SafetyNet unavailable"
invoke-direct {v0, v1}, Ljava/io/IOException;-><init>(Ljava/lang/String;)V
throw v0
.line 20
:cond_3
new-instance v0, Ljava/io/IOException;
const-string v1, "SafetyNet unavailable"
invoke-direct {v0, v1}, Ljava/io/IOException;-><init>(Ljava/lang/String;)V
throw v0
.end method
@@ -2983,7 +2983,26 @@
invoke-virtual {v0, v2}, Lorg/json/JSONObject;->optInt(Ljava/lang/String;)I
move-result v14
###
const-string v2, "useGenius"
const/4 v3, 0x0
invoke-static {v3}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean;
move-result-object v3
invoke-static {v2, v3}, Lru/vtosters/lite/utils/Preferences;->getBoolValue(Ljava/lang/String;Ljava/lang/Boolean;)Z
move-result v3
if-eqz v3, :cond_37
invoke-static {}, Lru/vtosters/lite/utils/NetworkUtils;->isNetworkConnected()Z
move-result v14
###
:cond_37
const-string v2, "album"
.line 44
@@ -1780,6 +1780,18 @@
.line 90
:cond_3
invoke-static {}, Lru/vtosters/lite/music/cache/injectors/TracklistInjector;->eligibleForOfflineCaching()Z
move-result v0
if-eqz v0, :cond_4
invoke-static {p0}, Lru/vtosters/lite/music/cache/injectors/ShuffleInjector;->shuffleTracks(Lcom/vk/music/model/IpcPlayerModelImpl;)V
return-void
.line 90
:cond_4
new-instance v0, Lcom/vk/api/audio/AudioGetButtonTracks;
const/16 v1, 0x64
@@ -1362,6 +1362,18 @@
.line 44
:cond_0
invoke-static {}, Lru/vtosters/lite/music/cache/injectors/TracklistInjector;->eligibleForOfflineCaching()Z
move-result v0
if-eqz v0, :cond_1
invoke-static {p0}, Lru/vtosters/lite/music/cache/injectors/ShuffleInjector;->shuffleTracks(Lcom/vk/music/model/PlayerModelImpl;)V
return-void
.line 90
:cond_1
new-instance v0, Lcom/vk/api/audio/AudioGetButtonTracks;
const/16 v1, 0x64
@@ -31,20 +31,6 @@
}
.end annotation
.line 1
:try_start_0
sget-object v0, Lcom/vk/common/VKSafetyNet;->a:Lcom/vk/common/VKSafetyNet;
invoke-virtual {v0}, Lcom/vk/common/VKSafetyNet;->a()Lkotlin/Triple;
move-result-object v0
:try_end_0
.catch Ljava/lang/Exception; {:try_start_0 .. :try_end_0} :catch_0
goto :goto_0
.line 2
:catch_0
new-instance v0, Lkotlin/Triple;
const/4 v1, 0x0
@@ -61,7 +47,6 @@
invoke-direct {v0, v3, v1, v2}, Lkotlin/Triple;-><init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
:goto_0
return-object v0
.end method