diff --git a/app/build.gradle b/app/build.gradle index 728b02f73..e526dfe86 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -78,7 +78,7 @@ android { targetCompatibility JavaVersion.VERSION_14 } namespace 'ru.vtosters.lite' - ndkVersion '25.2.9519653' + ndkVersion '26.1.10909125' buildFeatures { aidl true } @@ -97,6 +97,8 @@ dependencies { implementation 'net.sourceforge.streamsupport:streamsupport-minifuture:1.7.4' implementation 'com.google.guava:guava:32.0.0-android' + implementation 'com.mpatric:mp3agic:0.9.1' + implementation fileTree(dir: 'libs', include: ['*.aar']) compileOnly fileTree(dir: 'libs', include: ['*.jar']) } diff --git a/app/libs/ffmpeg-kit.aar b/app/libs/ffmpeg-kit.aar deleted file mode 100644 index 178c2affc..000000000 Binary files a/app/libs/ffmpeg-kit.aar and /dev/null differ diff --git a/app/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java b/app/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java deleted file mode 100755 index cdd3afa48..000000000 --- a/app/src/main/java/com/arthenica/ffmpegkit/NativeLoader.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.arthenica.ffmpegkit; - -import android.os.Build; -import android.util.Log; -import com.arthenica.smartexception.java.Exceptions; - -import java.util.Collections; -import java.util.List; - -public class NativeLoader { - static final String[] FFMPEG_LIBRARIES = {"avutil", "swresample", "avcodec", "avformat", "avfilter", "avdevice"}; - - private static void loadLibrary(String libraryName) { - System.loadLibrary(libraryName); - } - - private static List loadExternalLibraries() { - //return Packages.getExternalLibraries(); - return Collections.emptyList(); - } - - private static String loadNativeAbi() { - return AbiDetect.getNativeAbi(); - } - - static String loadAbi() { - return AbiDetect.getAbi(); - } - - static String loadPackageName() { - return Packages.getPackageName(); - } - - static String loadVersion() { - return FFmpegKitConfig.getVersion(); - } - - static boolean loadIsLTSBuild() { - return AbiDetect.isNativeLTSBuild(); - } - - static int loadLogLevel() { - return FFmpegKitConfig.getNativeLogLevel(); - } - - static String loadBuildDate() { - return FFmpegKitConfig.getBuildDate(); - } - - static void enableRedirection() { - FFmpegKitConfig.enableRedirection(); - } - - static void loadFFmpegKitAbiDetect() { - loadLibrary("ffmpegkit_abidetect"); - } - - static boolean loadFFmpeg() { - boolean nativeFFmpegLoaded = false; - boolean nativeFFmpegTriedAndFailed = false; - - if (AbiDetect.ARM_V7A.equals(loadNativeAbi())) { - try { - for (String ffmpegLibrary : FFMPEG_LIBRARIES) { - loadLibrary(ffmpegLibrary + "_neon"); - } - nativeFFmpegLoaded = true; - } catch (final Error e) { - android.util.Log.i(FFmpegKitConfig.TAG, String.format("NEON supported armeabi-v7a ffmpeg library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); - nativeFFmpegTriedAndFailed = true; - } - } - - if (!nativeFFmpegLoaded) { - for (String ffmpegLibrary : FFMPEG_LIBRARIES) { - loadLibrary(ffmpegLibrary); - } - } - return nativeFFmpegTriedAndFailed; - } - - static void loadFFmpegKit(boolean nativeFFmpegTriedAndFailed) { - boolean nativeFFmpegKitLoaded = false; - if (!nativeFFmpegTriedAndFailed && "arm-v7a".equals(loadNativeAbi())) { - try { - loadLibrary("ffmpegkit_armv7a_neon"); - nativeFFmpegKitLoaded = true; - AbiDetect.setArmV7aNeonLoaded(); - } catch (Error e) { - Log.i("ffmpeg-kit", String.format("NEON supported armeabi-v7a ffmpegkit library not found. Loading default armeabi-v7a library.%s", Exceptions.getStackTraceString(e))); - } - } - if (!nativeFFmpegKitLoaded) { - loadLibrary("ffmpegkit"); - } - } - - - static String getDeviceDebugInformation() { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("brand: "); - stringBuilder.append(Build.BRAND); - stringBuilder.append(", model: "); - stringBuilder.append(Build.MODEL); - stringBuilder.append(", device: "); - stringBuilder.append(Build.DEVICE); - stringBuilder.append(", api level: "); - stringBuilder.append(Build.VERSION.SDK_INT); - if (Build.VERSION.SDK_INT >= 21) { - stringBuilder.append(", abis: "); - stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_ABIS)); - stringBuilder.append(", 32bit abis: "); - stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_32_BIT_ABIS)); - stringBuilder.append(", 64bit abis: "); - stringBuilder.append(FFmpegKitConfig.argumentsToString(Build.SUPPORTED_64_BIT_ABIS)); - } else { - stringBuilder.append(", cpu abis: "); - stringBuilder.append(Build.CPU_ABI); - stringBuilder.append(", cpu abi2s: "); - stringBuilder.append(Build.CPU_ABI2); - } - return stringBuilder.toString(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/arthenica/smartexception/AbstractExceptions.java b/app/src/main/java/com/arthenica/smartexception/AbstractExceptions.java deleted file mode 100755 index f0759d34d..000000000 --- a/app/src/main/java/com/arthenica/smartexception/AbstractExceptions.java +++ /dev/null @@ -1,732 +0,0 @@ -/* - * BSD 3-Clause License - * - * Copyright (c) 2020, Taner Sener - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.arthenica.smartexception; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -/** - *

Abstract class that includes common variables and methods for different Exceptions implementations. - * - * @author Taner Sener - * @since 0.1.0 - */ -public abstract class AbstractExceptions { - - /** - *

Default max depth used in methods which do not have a maxDepth argument. - */ - public static final int DEFAULT_MAX_DEPTH = 10; - - /** - *

Default value for ignoring all causes when stack trace elements are printed or converted to string. - */ - public static final boolean DEFAULT_IGNORE_ALL_CAUSES = false; - - /** - *

Stores global root package names. - */ - public static final Set rootPackageSet = Collections.synchronizedSet(new HashSet()); - - /** - *

Stores global group package names. - */ - public static final Set groupPackageSet = Collections.synchronizedSet(new HashSet()); - - /** - *

Stores global ignore package names. - */ - public static final Set ignorePackageSet = Collections.synchronizedSet(new HashSet()); - - /** - *

Stores global ignore cause package names. - */ - public static final Set ignoreCausePackageSet = Collections.synchronizedSet(new HashSet()); - - /** - *

Stores the value of global ignore all causes option. - */ - public static boolean ignoreAllCauses = DEFAULT_IGNORE_ALL_CAUSES; - - /** - *

Stores the global stack trace serializer implementation. - */ - public static StackTraceElementSerializer stackTraceElementSerializer; - - /** - *

Registers a new root package. - * - * @param packageString root package name to register - */ - public static void registerRootPackage(final String packageString) { - rootPackageSet.add(packageString); - } - - /** - *

Clears previously registered root packages. - */ - public static void clearRootPackages() { - rootPackageSet.clear(); - } - - /** - *

Registers a new group package. - * - * @param packageString group package name to register - */ - public static void registerGroupPackage(final String packageString) { - groupPackageSet.add(packageString); - } - - /** - *

Clears previously registered group packages. - */ - public static void clearGroupPackages() { - groupPackageSet.clear(); - } - - /** - *

Returns the global stack trace serializer implementation which is used to serialize {@link StackTraceElement} - * objects in getStackTraceString methods. - * - * @return current stack trace serializer implementation - */ - public static StackTraceElementSerializer getStackTraceElementSerializer() { - return stackTraceElementSerializer; - } - - /** - *

Sets the global stack trace serializer implementation which is used to serialize {@link StackTraceElement} - * objects in getStackTraceString methods. - * - * @param stackTraceElementSerializer new stack trace serializer implementation - */ - public static void setStackTraceElementSerializer(final StackTraceElementSerializer stackTraceElementSerializer) { - AbstractExceptions.stackTraceElementSerializer = stackTraceElementSerializer; - } - - /** - *

Registers a new ignore package. - * - * @param packageString ignore package name to register - * @param ignoreCauseClasses ignore cause classes from this package too - */ - public static void registerIgnorePackage(final String packageString, final boolean ignoreCauseClasses) { - ignorePackageSet.add(packageString); - if (ignoreCauseClasses) { - ignoreCausePackageSet.add(packageString); - } - } - - /** - *

Clears previously registered ignore packages. - */ - public static void clearIgnorePackages() { - ignorePackageSet.clear(); - ignoreCausePackageSet.clear(); - } - - /** - *

Returns the value of ignore all causes option. - * - * @return the value of global ignore all causes option. If value is true then stack trace elements printed or - * converted to string will not include causes. If value is false causes will be appended to the stack trace of - * the main throwable. - */ - public static boolean getIgnoreAllCauses() { - return ignoreAllCauses; - } - - /** - *

Sets the value of ignore all causes option. - * - * @param ignoreAllCauses new global ignore all causes option. If value is true then stack trace elements printed - * or converted to string will not include causes. If value is false causes will be appended to the stack trace of - * the main throwable. - */ - public static void setIgnoreAllCauses(final boolean ignoreAllCauses) { - AbstractExceptions.ignoreAllCauses = ignoreAllCauses; - } - - /** - *

Returns the smart stack trace for the given throwable. - * - *

This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered - * by {@link #registerGroupPackage(String)} and ignore packages registered by - * {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace. - * - * @param throwable parent throwable - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable) { - return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable. - * - *

This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered - * by {@link #registerGroupPackage(String)} and ignore packages registered by - * {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace. - * - * @param throwable parent throwable - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final boolean ignoreAllCauses) { - return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using packages provided. - * - * @param throwable parent throwable - * @param rootPackageSet root packages to use for building the stack trace - * @param groupPackageSet group packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final Set rootPackageSet, final Set groupPackageSet, final Set ignorePackageSet) { - return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using packages provided. - * - * @param throwable parent throwable - * @param rootPackageSet root packages to use for building the stack trace - * @param groupPackageSet group packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final Set rootPackageSet, final Set groupPackageSet, final Set ignorePackageSet, final boolean ignoreAllCauses) { - return getStackTraceString(throwable, false, rootPackageSet, groupPackageSet, ignorePackageSet, 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using root package provided. - * - * @param throwable parent throwable - * @param rootPackage root package to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final String rootPackage) { - return getStackTraceString(throwable, false, Collections.singleton(rootPackage), new HashSet(), new HashSet(), 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using root package provided. - * - * @param throwable parent throwable - * @param rootPackage root package to use for building the stack trace - * @param groupPackage group package to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final String rootPackage, final String groupPackage) { - return getStackTraceString(throwable, false, Collections.singleton(rootPackage), Collections.singleton(groupPackage), new HashSet(), 0, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using elements found until the maxDepth. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be used - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final int maxDepth) { - return getStackTraceString(throwable, false, new HashSet(), new HashSet(), new HashSet(), maxDepth, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using elements found until the maxDepth. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be used - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final int maxDepth, final boolean ignoreAllCauses) { - return getStackTraceString(throwable, false, new HashSet(), new HashSet(), new HashSet(), maxDepth, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using parameters provided. - * - * @param throwable parent throwable - * @param isCause throwable is a cause or not - * @param rootPackageSet root packages to use for building the stack trace - * @param groupPackageSet group packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @param maxDepth max depth in exception chain that will be used - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final boolean isCause, final Set rootPackageSet, final Set groupPackageSet, final Set ignorePackageSet, final int maxDepth, final boolean ignoreAllCauses) { - final StringBuilder builder = new StringBuilder(); - - if (throwable == null) { - return ""; - } - - final String className = throwable.getClass().getName(); - - final StackTraceElement[] stackTraceElements; - if (maxDepth > 0) { - stackTraceElements = getStackTrace(throwable, maxDepth); - } else { - stackTraceElements = getStackTrace(throwable, rootPackageSet, ignorePackageSet); - } - String message = throwable.getLocalizedMessage(); - if (isEmpty(message)) { - message = throwable.getMessage(); - } - - /* PRINT MESSAGE */ - if (isCause) { - builder.append(System.lineSeparator()); - builder.append("Caused by: "); - builder.append(className); - if (!isEmpty(message)) { - builder.append(": "); - builder.append(message); - } - } else { - builder.append(System.lineSeparator()); - builder.append(className); - if (!isEmpty(message)) { - builder.append(": "); - builder.append(message); - } - } - - /* PRINT SHORT STACK TRACE */ - String currentGroupPackage = null; - StackTraceElement firstStackTraceElementInTheGroup = null; - int currentGroupCount = 0; - for (StackTraceElement traceElement : stackTraceElements) { - String traceElementClassName = traceElement.getClassName(); - String groupPackageMatch = getContainingPackage(traceElementClassName, groupPackageSet); - - if (groupPackageMatch != null) { - if (!groupPackageMatch.equals(currentGroupPackage)) { - appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup); - - builder.append(System.lineSeparator()); - builder.append("\tat "); - - currentGroupPackage = groupPackageMatch; - firstStackTraceElementInTheGroup = traceElement; - currentGroupCount = 1; - } else { - currentGroupCount++; - } - } else { - currentGroupCount = appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup); - - builder.append(System.lineSeparator()); - builder.append("\tat "); - if (stackTraceElementSerializer == null) { - throw new IllegalArgumentException("Stack trace element serializer not initialized."); - } else { - builder.append(stackTraceElementSerializer.toString(traceElement)); - } - currentGroupPackage = null; - } - } - - appendStackTraceGroupElement(builder, currentGroupPackage, currentGroupCount, firstStackTraceElementInTheGroup); - - final Throwable cause = throwable.getCause(); - if (cause != null && !containsPackage(className, ignoreCausePackageSet) && !ignoreAllCauses) { - builder.append(getStackTraceString(cause, true, rootPackageSet, groupPackageSet, ignorePackageSet, maxDepth, ignoreAllCauses)); - } - - return builder.toString(); - } - - /** - *

Appends stack trace group information for the given parameters. - * - * @param stringBuilder string builder that group stack trace information will be appended - * @param currentGroupPackage package name of the current group - * @param numberOfElementsInTheCurrentGroup number of elements in the current group - * @param firstStackTraceElementInTheGroup first stack trace element of this group - * @return new value for the group element count - */ - public static int appendStackTraceGroupElement(final StringBuilder stringBuilder, final String currentGroupPackage, final int numberOfElementsInTheCurrentGroup, final StackTraceElement firstStackTraceElementInTheGroup) { - if (numberOfElementsInTheCurrentGroup > 0) { - if (stackTraceElementSerializer == null) { - throw new IllegalArgumentException("Stack trace element serializer not initialized."); - } else { - stringBuilder.append((numberOfElementsInTheCurrentGroup == 1) ? stackTraceElementSerializer.toString(firstStackTraceElementInTheGroup) : String.format("%s%s ... %d more", stackTraceElementSerializer.getModuleName(firstStackTraceElementInTheGroup), currentGroupPackage, (numberOfElementsInTheCurrentGroup - 1))); - } - } - - return 0; - } - - /** - *

Returns true if package of the given class name matches one of package names provided in - * packageSet. - * - * @param fullClassName fully qualified class name - * @param packageSet set containing package names - * @return true if package of the given class name matches one of package names provided in packageSet, - * false otherwise - */ - public static boolean containsPackage(final String fullClassName, final Set packageSet) { - return getContainingPackage(fullClassName, packageSet) != null; - } - - /** - *

Checks if one of the package names in the packageSet matches the package of the given class name - * and returns the matching package name. - * - * @param fullClassName fully qualified class name - * @param packageSet set containing package names - * @return one of the package names in the packageSet that matches the package of the given class name - * or null if no matching package name is found in the packageSet - */ - public static String getContainingPackage(final String fullClassName, final Set packageSet) { - for (final String parentExceptionPackage : packageSet) { - if (fullClassName.startsWith(parentExceptionPackage)) { - return parentExceptionPackage; - } - } - - return null; - } - - /** - *

Returns all messages found in the exception chain of the throwable as a single string. - * - * @param throwable parent throwable - * @return a string containing all messages found in the exception chain - */ - public static String getAllMessages(final Throwable throwable) { - final StringBuilder messageBuilder = new StringBuilder(); - getAllMessages(throwable, messageBuilder); - return messageBuilder.toString(); - } - - /** - *

Adds all messages found in the exception chain of the throwable into the given message builder. - * - * @param throwable parent throwable - * @param messageBuilder message builder - */ - public static void getAllMessages(final Throwable throwable, final StringBuilder messageBuilder) { - if (throwable != null) { - final String message = throwable.getMessage(); - if (!isEmpty(message)) { - if (messageBuilder.length() != 0) { - messageBuilder.append(System.lineSeparator()); - messageBuilder.append(" - Caused by: "); - } - messageBuilder.append(message); - } - getAllMessages(throwable.getCause(), messageBuilder); - } - } - - /** - *

Builds a smart stack trace for the given throwable using elements found until the maxDepth and - * elements of it. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be returned - * @return an array containing stack trace elements - */ - public static StackTraceElement[] getStackTrace(final Throwable throwable, final int maxDepth) { - final ArrayList list = new ArrayList(); - - if (throwable != null) { - StackTraceElement[] stackTrace = throwable.getStackTrace(); - for (int i = 0; (i < stackTrace.length) && (i < maxDepth); i++) { - list.add(stackTrace[i]); - } - } - - return list.toArray(new StackTraceElement[0]); - } - - /** - *

Builds a smart stack trace for the given throwable using packages provided and returns elements - * of it. - * - * @param throwable parent throwable - * @param rootPackageSet root packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @return an array containing stack trace elements - */ - public static StackTraceElement[] getStackTrace(final Throwable throwable, final Set rootPackageSet, final Set ignorePackageSet) { - final ArrayList list = new ArrayList(); - final ArrayList partialList = new ArrayList(); - - if (throwable != null) { - for (StackTraceElement stackTraceElement : throwable.getStackTrace()) { - final String className = stackTraceElement.getClassName(); - if (!isEmpty(className)) { - if (containsPackage(className, rootPackageSet)) { - list.addAll(partialList); - list.add(stackTraceElement); - } else if (!containsPackage(className, ignorePackageSet)) { - partialList.add(stackTraceElement); - } - } - } - } - - if (list.isEmpty()) { - list.addAll(partialList); - } - - return list.toArray(new StackTraceElement[0]); - } - - /** - *

Returns true if the given cause class is found in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link #DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @return true if the given cause class is found in the exception chain of the throwable, false - * otherwise - */ - public static boolean containsCause(final Throwable throwable, final Class causeClass) { - return containsCause(throwable, causeClass, null); - } - - /** - *

Returns true if the given cause class and cause message is found in the exception chain of the - * throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link #DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @return true if the given cause class and cause message is found in the exception chain of the - * throwable, false otherwise - */ - public static boolean containsCause(final Throwable throwable, final Class causeClass, final String causeMessage) { - return (searchCause(throwable, causeClass, causeMessage, DEFAULT_MAX_DEPTH) != null); - } - - /** - *

Returns the cause of the throwable by walking through the exception chain. - * - * @param throwable parent throwable - * @return the cause of the throwable found or null if throwable does not have a cause - */ - public static Throwable getCause(final Throwable throwable) { - return getCause(throwable, DEFAULT_MAX_DEPTH); - } - - /** - *

Returns the cause of the throwable by walking through the exception chain. - *
- *
- *

Note that this method walks through the exception chain up to given maxDepth. If exception chain - * includes more items than maxDepth, cause found at maxDepth level is returned. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be searched - * @return the cause of the throwable found until maxDepth is reached in the exception - * chain or null if throwable does not have a cause - */ - public static Throwable getCause(final Throwable throwable, final int maxDepth) { - if (throwable == null) { - return null; - } - - if (maxDepth <= 0) { - return throwable; - } - - final Throwable cause = throwable.getCause(); - if (cause == null) { - return throwable; - } else { - return getCause(cause, maxDepth - 1); - } - } - - /** - *

Searches for the given cause class in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link #DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @return the throwable found or null if no class in exception chain matches the given cause class - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass) { - return searchCause(throwable, causeClass, null, DEFAULT_MAX_DEPTH); - } - - /** - *

Searches for the given cause class and cause message in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link #DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @return the throwable found or null if no class in exception chain matches the given cause class - * and cause message - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final String causeMessage) { - return searchCause(throwable, causeClass, causeMessage, DEFAULT_MAX_DEPTH); - } - - /** - *

Searches for the given cause class and cause message in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until the given - * maxDepth. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @param maxDepth max depth in exception chain that will be searched - * @return the throwable found or null if no class in exception chain matches the given cause class - * and cause message - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final String causeMessage, final int maxDepth) { - if (throwable == null) { - return null; - } - - if (isEmpty(causeMessage)) { - if (throwable.getClass().equals(causeClass)) { - return throwable; - } - } else { - if (throwable.getClass().equals(causeClass) && getAllMessages(throwable).toLowerCase().contains(causeMessage.toLowerCase())) { - return throwable; - } - } - - if (maxDepth <= 0) { - return null; - } - - final Throwable cause = throwable.getCause(); - if (cause == null) { - return null; - } else { - return searchCause(cause, causeClass, causeMessage, maxDepth - 1); - } - } - - /** - *

Searches for the given cause class in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until the given - * maxDepth. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param maxDepth max depth in exception chain that will be searched - * @return the throwable found or null if no class in exception chain matches the given cause class - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final int maxDepth) { - if (throwable == null) { - return null; - } - - if (throwable.getClass().equals(causeClass)) { - return throwable; - } - - if (maxDepth <= 0) { - return null; - } - - final Throwable cause = throwable.getCause(); - if (cause == null) { - return null; - } else { - return searchCause(cause, causeClass, maxDepth - 1); - } - } - - /** - *

Checks if given string is empty or not. - * - * @param value string to check - * @return true if given string is null or has zero length after trim(), false otherwise - */ - public static boolean isEmpty(final String value) { - if (value == null) { - return true; - } - - return value.trim().length() == 0; - } - - /** - *

Returns the package name of this class. - * - * @param className fully qualified class name - * @return name of the package - */ - public static String packageName(final String className) { - if (className == null) { - return ""; - } - - int index = className.lastIndexOf("."); - if (index >= 0) { - return className.substring(0, index); - } else { - return ""; - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/arthenica/smartexception/StackTraceElementSerializer.java b/app/src/main/java/com/arthenica/smartexception/StackTraceElementSerializer.java deleted file mode 100755 index 9e1d548da..000000000 --- a/app/src/main/java/com/arthenica/smartexception/StackTraceElementSerializer.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * BSD 3-Clause License - * - * Copyright (c) 2020, Taner Sener - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.arthenica.smartexception; - -/** - *

Base interface for classes which can serialize {@link StackTraceElement} objects. - * - * @author Taner Sener - * @since 0.1.0 - */ -public interface StackTraceElementSerializer { - - /** - *

Converts the given stackTraceElement into a string. - * - * @param stackTraceElement stack trace element to convert - * @return string representing the given stackTraceElement - */ - String toString(final StackTraceElement stackTraceElement); - - /** - *

Returns module name for the given stackTraceElement. - * - * @param stackTraceElement stack trace element to use - * @return module name of the given stackTraceElement or an empty string if implementation does not - * support printing module names - */ - String getModuleName(final StackTraceElement stackTraceElement); - - /** - *

Returns string definition used to print native methods. - * - * @return string definition used to print native methods - */ - String getNativeMethodDefinition(); - - /** - *

Returns string definition used to print methods with unknown source. - * - * @return string definition used to print methods with unknown source - */ - String getUnknownSourceDefinition(); - -} \ No newline at end of file diff --git a/app/src/main/java/com/arthenica/smartexception/java/Exceptions.java b/app/src/main/java/com/arthenica/smartexception/java/Exceptions.java deleted file mode 100755 index a94458842..000000000 --- a/app/src/main/java/com/arthenica/smartexception/java/Exceptions.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * BSD 3-Clause License - * - * Copyright (c) 2020, Taner Sener - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package com.arthenica.smartexception.java; - -import com.arthenica.smartexception.AbstractExceptions; -import com.arthenica.smartexception.StackTraceElementSerializer; - -import java.util.Set; - -/** - *

Utility class to handle Throwable objects and stack traces. This implementation is compatible with all Java and - * Android versions. - * - * @author Taner Sener - * @since 0.1.0 - */ -public class Exceptions { - - static { - AbstractExceptions.setStackTraceElementSerializer(new StackTraceElementSerializer() { - - @Override - public String toString(StackTraceElement stackTraceElement) { - final StringBuilder stringBuilder = new StringBuilder(); - - stringBuilder.append(stackTraceElement.getClassName()); - stringBuilder.append("."); - stringBuilder.append(stackTraceElement.getMethodName()); - - if (stackTraceElement.isNativeMethod()) { - stringBuilder.append("(Native Method)"); - } else if ((stackTraceElement.getFileName() != null) && (stackTraceElement.getFileName().length() > 0)) { - stringBuilder.append("("); - stringBuilder.append(stackTraceElement.getFileName()); - if (stackTraceElement.getLineNumber() >= 0) { - stringBuilder.append(":"); - stringBuilder.append(stackTraceElement.getLineNumber()); - } - stringBuilder.append(")"); - } else { - stringBuilder.append("(Unknown Source)"); - } - - return stringBuilder.toString(); - } - - @Override - public String getModuleName(StackTraceElement stackTraceElement) { - return ""; - } - - @Override - public String getNativeMethodDefinition() { - return "(Native Method)"; - } - - @Override - public String getUnknownSourceDefinition() { - return "(Unknown Source)"; - } - }); - } - - /** - *

Registers a new root package. - * - * @param packageString root package name to register - */ - public static void registerRootPackage(final String packageString) { - AbstractExceptions.registerRootPackage(packageString); - } - - /** - *

Clears previously registered root packages. - */ - public static void clearRootPackages() { - AbstractExceptions.clearRootPackages(); - } - - /** - *

Registers a new group package. - * - * @param packageString group package name to register - */ - public static void registerGroupPackage(final String packageString) { - AbstractExceptions.registerGroupPackage(packageString); - } - - /** - *

Clears previously registered group packages. - */ - public static void clearGroupPackages() { - AbstractExceptions.clearGroupPackages(); - } - - /** - *

Returns the global stack trace serializer implementation which is used to serialize {@link StackTraceElement} - * objects in getStackTraceString methods. - * - * @return current stack trace serializer implementation - */ - public static StackTraceElementSerializer getStackTraceElementSerializer() { - return AbstractExceptions.getStackTraceElementSerializer(); - } - - /** - *

Sets the global stack trace serializer implementation which is used to serialize {@link StackTraceElement} - * objects in getStackTraceString methods. - * - * @param stackTraceElementSerializer new stack trace serializer implementation - */ - public static void setStackTraceElementSerializer(final StackTraceElementSerializer stackTraceElementSerializer) { - AbstractExceptions.setStackTraceElementSerializer(stackTraceElementSerializer); - } - - /** - *

Registers a new ignore package. - * - * @param packageString ignore package name to register - * @param ignoreCauseClasses ignore cause classes from this package too - */ - public static void registerIgnorePackage(final String packageString, final boolean ignoreCauseClasses) { - AbstractExceptions.registerIgnorePackage(packageString, ignoreCauseClasses); - } - - /** - *

Clears previously registered ignore packages. - */ - public static void clearIgnorePackages() { - AbstractExceptions.clearIgnorePackages(); - } - - /** - *

Returns the value of ignore all causes option. - * - * @return the value of global ignore all causes option. If value is true then stack trace elements printed or - * converted to string will not include causes. If value is false causes will be appended to the stack trace of - * the main throwable. - */ - public static boolean getIgnoreAllCauses() { - return AbstractExceptions.getIgnoreAllCauses(); - } - - /** - *

Sets the value of ignore all causes option. - * - * @param ignoreAllCauses new global ignore all causes option. If value is true then stack trace elements printed - * or converted to string will not include causes. If value is false causes will be appended to the stack trace of - * the main throwable. - */ - public static void setIgnoreAllCauses(final boolean ignoreAllCauses) { - AbstractExceptions.setIgnoreAllCauses(ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable. - * - *

This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered - * by {@link #registerGroupPackage(String)} and ignore packages registered by - * {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace. - * - * @param throwable parent throwable - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable) { - return AbstractExceptions.getStackTraceString(throwable); - } - - /** - *

Returns the smart stack trace for the given throwable. - * - *

This method uses root packages registered by {@link #registerRootPackage(String)}, group packages registered - * by {@link #registerGroupPackage(String)} and ignore packages registered by - * {@link #registerIgnorePackage(String, boolean)} to build the smart stack trace. - * - * @param throwable parent throwable - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final boolean ignoreAllCauses) { - return AbstractExceptions.getStackTraceString(throwable, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using packages provided. - * - * @param throwable parent throwable - * @param rootPackageSet root packages to use for building the stack trace - * @param groupPackageSet group packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final Set rootPackageSet, final Set groupPackageSet, final Set ignorePackageSet) { - return AbstractExceptions.getStackTraceString(throwable, rootPackageSet, groupPackageSet, ignorePackageSet); - } - - /** - *

Returns the smart stack trace for the given throwable using packages provided. - * - * @param throwable parent throwable - * @param rootPackageSet root packages to use for building the stack trace - * @param groupPackageSet group packages to use for building the stack trace - * @param ignorePackageSet ignore packages to use for building the stack trace - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final Set rootPackageSet, final Set groupPackageSet, final Set ignorePackageSet, final boolean ignoreAllCauses) { - return AbstractExceptions.getStackTraceString(throwable, rootPackageSet, groupPackageSet, ignorePackageSet, ignoreAllCauses); - } - - /** - *

Returns the smart stack trace for the given throwable using root package provided. - * - * @param throwable parent throwable - * @param rootPackage root package to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final String rootPackage) { - return AbstractExceptions.getStackTraceString(throwable, rootPackage); - } - - /** - *

Returns the smart stack trace for the given throwable using root package provided. - * - * @param throwable parent throwable - * @param rootPackage root package to use for building the stack trace - * @param groupPackage group package to use for building the stack trace - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final String rootPackage, final String groupPackage) { - return AbstractExceptions.getStackTraceString(throwable, rootPackage, groupPackage); - } - - /** - *

Returns the smart stack trace for the given throwable using elements found until the maxDepth. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be used - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final int maxDepth) { - return AbstractExceptions.getStackTraceString(throwable, maxDepth); - } - - /** - *

Returns the smart stack trace for the given throwable using elements found until the maxDepth. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be used - * @param ignoreAllCauses ignore all causes in the exception chain - * @return a string containing the smart stack trace for the given throwable - */ - public static String getStackTraceString(final Throwable throwable, final int maxDepth, final boolean ignoreAllCauses) { - return AbstractExceptions.getStackTraceString(throwable, maxDepth, ignoreAllCauses); - } - - /** - *

Returns all messages found in the exception chain of the throwable as a single string. - * - * @param throwable parent throwable - * @return a string containing all messages found in the exception chain - */ - public static String getAllMessages(final Throwable throwable) { - return AbstractExceptions.getAllMessages(throwable); - } - - /** - *

Returns true if the given cause class is found in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link AbstractExceptions#DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @return true if the given cause class is found in the exception chain of the throwable, false - * otherwise - */ - public static boolean containsCause(final Throwable throwable, final Class causeClass) { - return AbstractExceptions.containsCause(throwable, causeClass); - } - - /** - *

Returns true if the given cause class and cause message is found in the exception chain of the - * throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link AbstractExceptions#DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @return true if the given cause class and cause message is found in the exception chain of the - * throwable, false otherwise - */ - public static boolean containsCause(final Throwable throwable, final Class causeClass, final String causeMessage) { - return AbstractExceptions.containsCause(throwable, causeClass, causeMessage); - } - - /** - *

Returns the cause of the throwable by walking through the exception chain. - * - * @param throwable parent throwable - * @return the cause of the throwable found or null if throwable does not have a cause - */ - public static Throwable getCause(final Throwable throwable) { - return AbstractExceptions.getCause(throwable); - } - - /** - *

Returns the cause of the throwable by walking through the exception chain. - *
- *
- *

Note that this method walks through the exception chain up to given maxDepth. If exception chain - * includes more items than maxDepth, cause found at maxDepth level is returned. - * - * @param throwable parent throwable - * @param maxDepth max depth in exception chain that will be searched - * @return the cause of the throwable found until maxDepth is reached in the exception - * chain or null if throwable does not have a cause - */ - public static Throwable getCause(final Throwable throwable, final int maxDepth) { - return AbstractExceptions.getCause(throwable, maxDepth); - } - - /** - *

Searches for the given cause class in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link AbstractExceptions#DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @return the throwable found or null if no class in exception chain matches the given cause class - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass) { - return AbstractExceptions.searchCause(throwable, causeClass); - } - - /** - *

Searches for the given cause class and cause message in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until - * {@link AbstractExceptions#DEFAULT_MAX_DEPTH}. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @return the throwable found or null if no class in exception chain matches the given cause class - * and cause message - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final String causeMessage) { - return AbstractExceptions.searchCause(throwable, causeClass, causeMessage); - } - - /** - *

Searches for the given cause class and cause message in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until the given - * maxDepth. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param causeMessage message to search for - * @param maxDepth max depth in exception chain that will be searched - * @return the throwable found or null if no class in exception chain matches the given cause class - * and cause message - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final String causeMessage, final int maxDepth) { - return AbstractExceptions.searchCause(throwable, causeClass, causeMessage, maxDepth); - } - - /** - *

Searches for the given cause class in the exception chain of the throwable. - *
- *
- *

Search starts from the throwable itself and goes through the exception chain up until the given - * maxDepth. - * - * @param throwable parent throwable - * @param causeClass class to search for - * @param maxDepth max depth in exception chain that will be searched - * @return the throwable found or null if no class in exception chain matches the given cause class - */ - public static Throwable searchCause(final Throwable throwable, final Class causeClass, final int maxDepth) { - return AbstractExceptions.searchCause(throwable, causeClass, maxDepth); - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/vk/medianative/MediaNative.java b/app/src/main/java/com/vk/medianative/MediaNative.java index 9821748e8..22e6cf5e7 100644 --- a/app/src/main/java/com/vk/medianative/MediaNative.java +++ b/app/src/main/java/com/vk/medianative/MediaNative.java @@ -248,7 +248,6 @@ public final class MediaNative { if (isMediaLoaded) { return; } - NativeLibLoader.loadLibrary("ffmpeg"); isMediaLoaded = NativeLibLoader.loadLibrary("vkmedia"); isMediaLoaded = NativeLibLoader.loadLibrary("vkmediaencoder"); } diff --git a/app/src/main/java/ru/vtosters/hooks/other/Preferences.java b/app/src/main/java/ru/vtosters/hooks/other/Preferences.java index 03866a488..efcdbd0e4 100644 --- a/app/src/main/java/ru/vtosters/hooks/other/Preferences.java +++ b/app/src/main/java/ru/vtosters/hooks/other/Preferences.java @@ -358,4 +358,12 @@ public class Preferences { public static int compress(int origquality) { return MediaImageEncoder.needToCompress() ? origquality : 100; } + + public static String metadataSeparator() { + return getPreferences().getString("metadata_separator", "; "); + } + + public static void setMetadataSeparator(String separator) { + getPreferences().edit().putString("metadata_separator", separator).apply(); + } } diff --git a/app/src/main/java/ru/vtosters/lite/music/converter/ts/FFMpeg.java b/app/src/main/java/ru/vtosters/lite/music/converter/ts/FFMpeg.java deleted file mode 100644 index 324227dfe..000000000 --- a/app/src/main/java/ru/vtosters/lite/music/converter/ts/FFMpeg.java +++ /dev/null @@ -1,45 +0,0 @@ -package ru.vtosters.lite.music.converter.ts; - -import com.arthenica.ffmpegkit.FFmpegKit; -import com.vk.dto.music.Artist; -import com.vk.dto.music.MusicTrack; -import ru.vtosters.hooks.other.Preferences; -import ru.vtosters.lite.music.downloader.M3UDownloader; -import ru.vtosters.lite.utils.IOUtils; - -import java.io.File; -import java.util.stream.Collectors; - -public class FFMpeg { - - /** - * @param in Merged .ts file via {@link ru.vtosters.lite.music.converter.ts.TSMerger} - * @param out Output .mp3 file - * @param track Track to be converted - * @return True if success, else false - */ - public static void convert(File in, String out, MusicTrack track) { - // convert .ts file to .mp3 file via ffmpeg - var cmd = " -y -i \"" + in.getAbsolutePath() + '"' - + " -map 0 -dn" - + " -loglevel error" - + " -hide_banner" - + " -write_id3v2 1" - + setMetadata(track) - + " -c copy \"" + out + '"'; - var ses = FFmpegKit.execute(cmd); - if (ses.getReturnCode().isValueCancel()) throw new RuntimeException(ses.getLogsAsString()); - } - - private static String setMetadata(MusicTrack track) { - return Preferences.getBoolValue("setMetaData", true) ? " -metadata title=\"" + IOUtils.getValidFileName(M3UDownloader.getTitle(track)) + '"' - + (track.L == null || track.I == null - ? " -metadata artist=\"" + normalizeMetadata(track.C) + '"' - : " -metadata artist=\"" + normalizeMetadata(track.L.stream().map(Artist::w1).collect(Collectors.joining(", "))) + '"' - + " -metadata album=\"" + normalizeMetadata(track.I.getTitle()) + '"') : ""; - } - - private static String normalizeMetadata(String in) { - return in.replaceAll("[\\\\/:*?\"<>|]", ""); - } -} diff --git a/app/src/main/java/ru/vtosters/lite/music/converter/ts/MpegDemuxer.java b/app/src/main/java/ru/vtosters/lite/music/converter/ts/MpegDemuxer.java new file mode 100644 index 000000000..f7302df06 --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/music/converter/ts/MpegDemuxer.java @@ -0,0 +1,75 @@ +package ru.vtosters.lite.music.converter.ts; + +import android.util.Log; + +import com.vk.dto.music.MusicTrack; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class MpegDemuxer { + public static void convert(File in, String out, MusicTrack track) throws IOException { + int packetSize = 188; + int desiredPid = 256; + + var buffer = new byte[packetSize]; + var packet = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN); + + try (var fis = new BufferedInputStream(new FileInputStream(in)); var fos = new BufferedOutputStream(new FileOutputStream(out))) { + while (fis.read(buffer) != -1) { + packet.clear(); + + int firstByte = packet.get() & 0xFF; + int secondByte = packet.get() & 0xFF; + int thirdByte = packet.get() & 0xFF; + int fourthByte = packet.get() & 0xFF; + + int syncByte = firstByte; + int transportErrorIndicator = (secondByte & 0x80) >> 7; + int payloadUnitStartIndicator = (secondByte & 0x40) >> 6; + + int pid = ((secondByte & 0x1F) << 8) | (thirdByte & 0xFF); + + int adaptationFieldControl = (fourthByte & 0x30) >> 4; + + if (syncByte != 0x47) { + Log.d("MpegDemuxer", "Invalid sync byte: 0x" + Integer.toHexString(syncByte)); + continue; + } + + if (transportErrorIndicator == 1) { + Log.d("MpegDemuxer", "Transport error indicator is set"); + continue; + } + + if (adaptationFieldControl == 2 || adaptationFieldControl == 3) { + int adaptationFieldLength = packet.get() & 0xFF; + packet.position(packet.position() + adaptationFieldLength); + } + + if (pid == desiredPid) { + if (payloadUnitStartIndicator == 1) { + packet.position(packet.position() + 4); + int pesPacketLength = packet.getShort() & 0xFFFF; + + if (pesPacketLength != 0) { + packet.position(packet.position() + 2); + int pesHeaderDataLength = packet.get() & 0xFF; + packet.position(packet.position() + pesHeaderDataLength); + } else { + Log.v("MpegDemuxer", "PES packet length is zero, that shouldn't happen in audio stream"); + } + } + + fos.write(packet.array(), packet.position(), packetSize - packet.position()); + } + } + } + } +} diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/ID3Tagger.java b/app/src/main/java/ru/vtosters/lite/music/downloader/ID3Tagger.java new file mode 100644 index 000000000..f7c47e58b --- /dev/null +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/ID3Tagger.java @@ -0,0 +1,55 @@ +package ru.vtosters.lite.music.downloader; + +import android.util.Log; + +import com.mpatric.mp3agic.ID3v23Tag; +import com.mpatric.mp3agic.InvalidDataException; +import com.mpatric.mp3agic.Mp3File; +import com.mpatric.mp3agic.NotSupportedException; +import com.mpatric.mp3agic.UnsupportedTagException; +import com.vk.dto.music.MusicTrack; +import com.vk.dto.music.Artist; + +import java.io.File; +import java.io.IOException; +import java.util.stream.Collectors; + +import ru.vtosters.hooks.other.Preferences; + +public class ID3Tagger { + public static void tag(File file, MusicTrack track) { + try { + // https://github.com/mpatric/mp3agic/issues/69#issuecomment-57897874 + var oldFile = new File(file.getAbsolutePath().replace(".mp3", "_old.mp3")); + if (!file.renameTo(oldFile)) { + Log.e("ID3Tagger", "Failed to rename file"); + return; + } + + var mp3File = new Mp3File(oldFile); + if (mp3File.hasId3v2Tag()) { + var id3v2Tag = new ID3v23Tag(); + + if (track.L == null || track.I == null) { + id3v2Tag.setArtist(track.C); + } else { + var artists = track.L.stream().map(Artist::w1).collect(Collectors.joining(Preferences.metadataSeparator())); + id3v2Tag.setArtist(artists); + id3v2Tag.setAlbum(track.I.getTitle()); + } + + id3v2Tag.setTitle(M3UDownloader.getTitle(track)); + + mp3File.setId3v2Tag(id3v2Tag); + mp3File.save(file.getAbsolutePath()); + + if (!oldFile.delete()) { + Log.e("ID3Tagger", "Failed to delete file"); + } + } + } catch (IOException | UnsupportedTagException | InvalidDataException | + NotSupportedException e) { + Log.e("ID3Tagger", "Failed to tag file", e); + } + } +} diff --git a/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java b/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java index 06b49b095..4a6b0ed58 100644 --- a/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java +++ b/app/src/main/java/ru/vtosters/lite/music/downloader/M3UDownloader.java @@ -10,8 +10,9 @@ import com.vk.dto.music.Artist; import com.vk.dto.music.MusicTrack; import java8.util.concurrent.CompletableFuture; import java8.util.concurrent.CompletionException; +import ru.vtosters.hooks.other.Preferences; import ru.vtosters.lite.music.cache.MusicCacheImpl; -import ru.vtosters.lite.music.converter.ts.FFMpeg; +import ru.vtosters.lite.music.converter.ts.MpegDemuxer; import ru.vtosters.lite.music.converter.ts.TSMerger; import ru.vtosters.lite.music.interfaces.Callback; import ru.vtosters.lite.music.interfaces.ITrackDownloader; @@ -68,12 +69,17 @@ public class M3UDownloader }) .thenRun(() -> { try { - FFMpeg.convert(resultTs, resultMp3.getAbsolutePath(), track); + MpegDemuxer.convert(resultTs, resultMp3.getAbsolutePath(), track); } catch (Throwable e) { - throw new RuntimeException("FFmpeg error", e); + throw new RuntimeException("MpegDemuxer error", e); } }) .thenRun(() -> callback.onProgress(10 + Math.round(80.0f * progress.addAndGet(1) / segments.size()))) + .thenRun(() -> { + if (Preferences.getBoolValue("setMetaData", true)) { + ID3Tagger.tag(resultMp3, track); + } + }) .thenRun(() -> { if (cache) { MusicCacheImpl.addTrack(track); diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java index c81077add..bf8fee0a7 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/MediaFragment.java @@ -4,8 +4,11 @@ import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.Gravity; +import android.view.ViewGroup; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.LinearLayout; + import androidx.preference.Preference; import com.vk.core.dialogs.alert.VkAlertDialog; import com.vk.core.network.Network; @@ -91,6 +94,41 @@ public class MediaFragment extends TrackedMaterialPreferenceToolbarFragment { }); findPreference("maxquality").setEnabled(Preferences.isEnableExternalOpening()); + + findPreference("metadataSeparator").setOnPreferenceClickListener(preference -> { + LinearLayout linearLayout = new LinearLayout(requireContext()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + + + EditText separator = new EditText(requireContext()); + separator.setHint("По-умолчанию: ; с пробелом"); + separator.setTextColor(ThemesUtils.getTextAttr()); + separator.setHintTextColor(ThemesUtils.getSTextAttr()); + separator.setBackgroundTintList(ThemesUtils.getAccenedColorStateList()); + separator.setText(Preferences.metadataSeparator()); + linearLayout.addView(separator); + separator.getLayoutParams().width = ViewGroup.LayoutParams.MATCH_PARENT; + ViewGroup.MarginLayoutParams margin = ((ViewGroup.MarginLayoutParams) separator.getLayoutParams()); + margin.setMargins(AndroidUtils.dp2px(20f), 0, AndroidUtils.dp2px(20f), 0); + separator.setLayoutParams(margin); + + + var t = new VkAlertDialog.Builder(requireContext()) + .setTitle("Разделитель") + .setView(linearLayout) + .setPositiveButton("Сохранить", (dialog, which) -> { + if (separator.getText().toString().isEmpty()) { + AndroidUtils.sendToast("Разделитель не может быть пустым"); + return; + } + Preferences.setMetadataSeparator(separator.getText().toString()); + }) + .setNegativeButton("Отмена", (dialog, which) -> dialog.cancel()) + .show(); + + + return true; + }); } @Override diff --git a/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java b/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java index 0e7c5bfba..130a86a02 100644 --- a/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java +++ b/app/src/main/java/ru/vtosters/lite/ui/fragments/MusicFragment.java @@ -103,18 +103,6 @@ public class MusicFragment extends TrackedMaterialPreferenceToolbarFragment { } ); - PreferenceFragmentUtils.addMaterialSwitchPreference( - getPreferenceScreen(), - "setMetaData", - "Сохранять метадату песен", - "Сохранять id3v2 теги для песен для MP3", - null, - true, - (preference, o) -> { - Preferences.getPreferences().edit().putBoolean("setMetaData", (boolean) o).apply(); - return true; - } - ); if (!Preferences.serverFeaturesDisable()) { PreferenceFragmentUtils.addPreferenceCategory(getPreferenceScreen(), "Интеграция Genius"); diff --git a/smali/lib/arm64-v8a/libavcodec.so b/smali/lib/arm64-v8a/libavcodec.so deleted file mode 100644 index 0020d36c4..000000000 Binary files a/smali/lib/arm64-v8a/libavcodec.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libavdevice.so b/smali/lib/arm64-v8a/libavdevice.so deleted file mode 100644 index 3738424bb..000000000 Binary files a/smali/lib/arm64-v8a/libavdevice.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libavfilter.so b/smali/lib/arm64-v8a/libavfilter.so deleted file mode 100644 index cc6d54e20..000000000 Binary files a/smali/lib/arm64-v8a/libavfilter.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libavformat.so b/smali/lib/arm64-v8a/libavformat.so deleted file mode 100644 index c865ca776..000000000 Binary files a/smali/lib/arm64-v8a/libavformat.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libavutil.so b/smali/lib/arm64-v8a/libavutil.so deleted file mode 100644 index b9d8cf7c0..000000000 Binary files a/smali/lib/arm64-v8a/libavutil.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libffmpegkit.so b/smali/lib/arm64-v8a/libffmpegkit.so deleted file mode 100644 index 7f6abd97b..000000000 Binary files a/smali/lib/arm64-v8a/libffmpegkit.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libffmpegkit_abidetect.so b/smali/lib/arm64-v8a/libffmpegkit_abidetect.so deleted file mode 100644 index 2b6598060..000000000 Binary files a/smali/lib/arm64-v8a/libffmpegkit_abidetect.so and /dev/null differ diff --git a/smali/lib/arm64-v8a/libswresample.so b/smali/lib/arm64-v8a/libswresample.so deleted file mode 100644 index a5328c3dd..000000000 Binary files a/smali/lib/arm64-v8a/libswresample.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libavcodec.so b/smali/lib/armeabi-v7a/libavcodec.so deleted file mode 100644 index cdc63c1d4..000000000 Binary files a/smali/lib/armeabi-v7a/libavcodec.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libavdevice.so b/smali/lib/armeabi-v7a/libavdevice.so deleted file mode 100644 index dead2a91e..000000000 Binary files a/smali/lib/armeabi-v7a/libavdevice.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libavfilter.so b/smali/lib/armeabi-v7a/libavfilter.so deleted file mode 100644 index d44c4e9a2..000000000 Binary files a/smali/lib/armeabi-v7a/libavfilter.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libavformat.so b/smali/lib/armeabi-v7a/libavformat.so deleted file mode 100644 index b12ed2dbc..000000000 Binary files a/smali/lib/armeabi-v7a/libavformat.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libavutil.so b/smali/lib/armeabi-v7a/libavutil.so deleted file mode 100644 index 0173b48b8..000000000 Binary files a/smali/lib/armeabi-v7a/libavutil.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libffmpegkit.so b/smali/lib/armeabi-v7a/libffmpegkit.so deleted file mode 100644 index 4660cc22b..000000000 Binary files a/smali/lib/armeabi-v7a/libffmpegkit.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libffmpegkit_abidetect.so b/smali/lib/armeabi-v7a/libffmpegkit_abidetect.so deleted file mode 100644 index b2760a599..000000000 Binary files a/smali/lib/armeabi-v7a/libffmpegkit_abidetect.so and /dev/null differ diff --git a/smali/lib/armeabi-v7a/libswresample.so b/smali/lib/armeabi-v7a/libswresample.so deleted file mode 100644 index 14c3f554e..000000000 Binary files a/smali/lib/armeabi-v7a/libswresample.so and /dev/null differ diff --git a/smali/res/xml/preferences_media.xml b/smali/res/xml/preferences_media.xml index 6820a9462..16ee5f562 100644 --- a/smali/res/xml/preferences_media.xml +++ b/smali/res/xml/preferences_media.xml @@ -11,6 +11,72 @@ android:key="compressVideos" android:summary="@string/sett_compress_video_summ" android:title="@string/sett_compress_videos"/> + + + + + + + + + + + + + + + + +