Merge branch 'main' into music
This commit is contained in:
+1
-1
@@ -88,8 +88,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation 'androidx.preference:preference:1.2.0'
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
compileOnly fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
@@ -50,11 +50,23 @@ public class AudioDownloader {
|
||||
var downloadPath = musicPath + File.separator + tempId;
|
||||
|
||||
var notification = buildDownloadNotification(track, tempId);
|
||||
|
||||
|
||||
downloadM3U8(track, downloadPath, new Callback() {
|
||||
long startTime = 0;
|
||||
long elapsedTime = 0;
|
||||
|
||||
@Override
|
||||
public void onProgress(int progress) {
|
||||
notification.setProgress(100, progress, false);
|
||||
notificationManager.notify(tempId, notification.build());
|
||||
if (elapsedTime > 1000) {
|
||||
notification.setProgress(100, progress, false);
|
||||
notificationManager.notify(tempId, notification.build());
|
||||
|
||||
startTime = System.currentTimeMillis();
|
||||
elapsedTime = 0;
|
||||
} else {
|
||||
elapsedTime = System.currentTimeMillis() - startTime;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,8 +13,6 @@ import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.network.Network;
|
||||
|
||||
@@ -165,7 +163,7 @@ public class FoafBase {
|
||||
}
|
||||
|
||||
private static String getNormalHumanDate(String str) {
|
||||
String[] split = str.split(ExifInterface.GPS_DIRECTION_TRUE);
|
||||
String[] split = str.split("T");
|
||||
return split[1].split("\\+")[0] + " " + split[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ public class JsonInjectors {
|
||||
}
|
||||
|
||||
public static JSONObject fetchCatalogId(String section) {
|
||||
if (section == null) return null;
|
||||
if (section.isEmpty()) return null;
|
||||
|
||||
var request = new Request.a()
|
||||
.b("https://" + getApi() + "/method/catalog.getAudio"
|
||||
|
||||
@@ -13,6 +13,7 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Arrays;
|
||||
|
||||
import ru.vtosters.lite.utils.AndroidUtils;
|
||||
import ru.vtosters.lite.utils.IOUtils;
|
||||
@@ -52,46 +53,56 @@ public class FFMpeg {
|
||||
public static boolean convert(String in, String out) {
|
||||
checkFFMpegLibs();
|
||||
|
||||
var list = new File(in);
|
||||
var outputTs = new File(in, "all.ts");
|
||||
var tsesList = new File(in).listFiles();
|
||||
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
for (var file : list.listFiles()) {
|
||||
if (tsesList == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var mergedTsFile = new File(in, "all.ts");
|
||||
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;
|
||||
});
|
||||
|
||||
for (var file : tsesList) {
|
||||
if (file.getName().endsWith(".ts")) {
|
||||
try {
|
||||
outputStream.write(IOUtils.readAllBytes(file));
|
||||
mergedByteArrayStream.write(IOUtils.readAllBytes(file));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
try {
|
||||
Files.write(outputTs.toPath(), outputStream.toByteArray());
|
||||
Files.write(mergedTsFile.toPath(), mergedByteArrayStream.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(outputTs);
|
||||
fos.write(outputStream.toByteArray());
|
||||
fos.close();
|
||||
try (FileOutputStream fos = new FileOutputStream(mergedTsFile)) {
|
||||
fos.write(mergedByteArrayStream.toByteArray());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// convert .ts file to .mp3 file via ffmpeg
|
||||
// var session = FFmpegKit.execute("-i " + in + "/all.ts -f mp3 -acodec mp3 -q:a 0 -y '" + out + "'");
|
||||
var session = FFmpegKit.execute("-i " + in + "/all.ts -map 0 -dn -c copy '" + out + "'");
|
||||
|
||||
var session = FFmpegKit.execute("-y -i " + in + "/all.ts -map 0 -dn -c copy '" + out + "'");
|
||||
var rc = session.getReturnCode();
|
||||
|
||||
IOUtils.deleteRecursive(new File(in));
|
||||
if (ReturnCode.isSuccess(rc)) {
|
||||
// remove temp files
|
||||
IOUtils.deleteRecursive(new File(in));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
package ru.vtosters.lite.music;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
import java8.util.concurrent.CompletableFuture;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
@@ -40,31 +41,40 @@ public class M3UDownloader {
|
||||
}
|
||||
|
||||
private static void parse(String payload, File outDir, Callback callback) {
|
||||
try {
|
||||
VKM3UParser parser = new VKM3UParser(payload);
|
||||
List<TransportStream> tses = parser.getTransportStreams();
|
||||
callback.onProgress(5);
|
||||
for (TransportStream ts : tses) {
|
||||
String tsURL = parser.getBaseUrl() + ts.getName();
|
||||
Log.d("M3UDownloader", "Downloading " + tsURL);
|
||||
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.readAllBytes(is);
|
||||
VKM3UParser parser = new VKM3UParser(payload);
|
||||
List<TransportStream> tses = parser.getTransportStreams();
|
||||
AtomicInteger progress = new AtomicInteger(0);
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
|
||||
callback.onProgress(5);
|
||||
for (TransportStream ts : tses) {
|
||||
String tsURL = parser.getBaseUrl() + ts.getName();
|
||||
|
||||
futures.add(CompletableFuture.runAsync(() -> {
|
||||
try {
|
||||
// Log.d("M3UDownloader", "Downloading " + tsURL);
|
||||
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.readAllBytes(is);
|
||||
}
|
||||
File tsDump = new File(outDir, ts.getName());
|
||||
IOUtils.writeToFile(tsDump, content);
|
||||
callback.onSizeReceived((long) content.length * tses.size(), parser.getHeapSize());
|
||||
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
callback.onFailure();
|
||||
}
|
||||
File tsDump = new File(outDir, ts.getName());
|
||||
IOUtils.writeToFile(tsDump, content);
|
||||
callback.onSizeReceived((long) content.length * tses.size(), parser.getHeapSize());
|
||||
callback.onProgress(10 + Math.round(80.0f * tses.indexOf(ts) / tses.size()));
|
||||
}
|
||||
} catch (IOException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
callback.onFailure();
|
||||
return;
|
||||
}).thenRun(() -> callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / tses.size()))));
|
||||
}
|
||||
// wait for all futures
|
||||
for (var future: futures) {
|
||||
future.join();
|
||||
}
|
||||
|
||||
callback.onSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package ru.vtosters.lite.ui.dialogs;
|
||||
import static ru.vtosters.lite.utils.AndroidUtils.edit;
|
||||
import static ru.vtosters.lite.utils.Preferences.getBoolValue;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import com.vk.core.dialogs.alert.VkAlertDialog;
|
||||
import com.vk.core.ui.themes.VKThemeHelper;
|
||||
|
||||
import ru.vtosters.lite.hooks.VKUIHook;
|
||||
|
||||
public class ThemeChanging{
|
||||
public static void changeTheme(Activity activity, float[] f){
|
||||
if (getBoolValue("systemtheme", true)) {
|
||||
new VkAlertDialog.Builder(activity)
|
||||
.setTitle("Внимание!")
|
||||
.setMessage("У вас включена системная тема \n" +
|
||||
"При переключении темы системная тема будет отключена \n\n" +
|
||||
"Вы действительно хотите отключить её?")
|
||||
.setCancelable(false)
|
||||
.setPositiveButton("Отключить", (dialogInterface, i) -> {
|
||||
edit().putBoolean("systemtheme", false).commit();
|
||||
VKThemeHelper.b(activity, f);
|
||||
VKUIHook.clearWebCache();
|
||||
})
|
||||
.setNeutralButton("Отмена", null)
|
||||
.show();
|
||||
} else {
|
||||
VKThemeHelper.b(activity, f);
|
||||
VKUIHook.clearWebCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,12 +59,12 @@ public class ExternalLinkParser {
|
||||
|
||||
if (checkVkVideo(file)) {
|
||||
if (qualities.size() == 1) {
|
||||
startExternalVideo((String) qualities.values().toArray()[0]);
|
||||
startExternalVideo((String) qualities.values().toArray()[0], context);
|
||||
} else {
|
||||
String[] titles = qualities.keySet().toArray(new String[0]);
|
||||
new AlertDialog.Builder(context)
|
||||
.setItems(titles, ((dialog, which) -> {
|
||||
startExternalVideo(qualities.get(titles[which]));
|
||||
startExternalVideo(qualities.get(titles[which]), context);
|
||||
}))
|
||||
.show();
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public class ExternalLinkParser {
|
||||
return qualities.size() > 0;
|
||||
}
|
||||
|
||||
public static boolean startExternalVideo(String url) {
|
||||
public static boolean startExternalVideo(String url, Context ctx) {
|
||||
try {
|
||||
qualities.clear();
|
||||
|
||||
@@ -136,7 +136,7 @@ public class ExternalLinkParser {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
}
|
||||
getGlobalContext().startActivity(intent);
|
||||
ctx.startActivity(intent);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -26,7 +26,10 @@ public class IOUtils {
|
||||
|
||||
public static byte[] decodeStream(InputStream encIs, String keyURL) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IOException {
|
||||
CipherInputStream cip = new CipherInputStream(encIs, getCipher(keyURL));
|
||||
return readAllBytes(cip);
|
||||
var bytes = readAllBytes(cip);
|
||||
cip.close();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static Cipher getCipher(String key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException {
|
||||
@@ -46,7 +49,11 @@ public class IOUtils {
|
||||
}
|
||||
|
||||
public static String readAllLines(File file) throws IOException {
|
||||
return readAllLines(new FileInputStream(file));
|
||||
var is = new FileInputStream(file);
|
||||
var bytes = readAllBytes(is);
|
||||
is.close();
|
||||
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String readAllLines(InputStream is) throws IOException {
|
||||
@@ -54,7 +61,11 @@ public class IOUtils {
|
||||
}
|
||||
|
||||
public static byte[] readAllBytes(File file) throws IOException {
|
||||
return readAllBytes(new FileInputStream(file));
|
||||
var is = new FileInputStream(file);
|
||||
var bytes = readAllBytes(is);
|
||||
is.close();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[] readAllBytes(InputStream is) throws IOException {
|
||||
@@ -63,7 +74,11 @@ public class IOUtils {
|
||||
int len;
|
||||
while ((len = is.read(buffer)) > 0)
|
||||
bos.write(buffer, 0, len);
|
||||
return bos.toByteArray();
|
||||
|
||||
var bytes = bos.toByteArray();
|
||||
bos.close();
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static void writeToFile(File file, String content) throws IOException {
|
||||
@@ -73,6 +88,7 @@ public class IOUtils {
|
||||
public static void writeToFile(File file, byte[] content) throws IOException {
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(content);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
public static void deleteRecursive(File f) {
|
||||
|
||||
@@ -242,9 +242,7 @@
|
||||
if-eqz v0, :cond_0
|
||||
|
||||
.line 6
|
||||
invoke-static {v0, p1}, Lcom/vk/core/ui/themes/VKThemeHelper;->b(Landroid/app/Activity;[F)V
|
||||
|
||||
invoke-static {}, Lru/vtosters/lite/hooks/VKUIHook;->clearWebCache()V
|
||||
invoke-static {v0, p1}, Lru/vtosters/lite/ui/dialogs/ThemeChanging;->changeTheme(Landroid/app/Activity;[F)V
|
||||
|
||||
:cond_0
|
||||
return-void
|
||||
|
||||
Reference in New Issue
Block a user