mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-21 16:54:33 +01:00
FFmpeg -> jniLibs Fix
This commit is contained in:
parent
9d445fe34b
commit
4dda5037dd
@ -36,7 +36,6 @@ repositories {
|
||||
|
||||
android {
|
||||
val props = gradleLocalProperties(rootDir)
|
||||
|
||||
if (props.containsKey("storeFileDir")) {
|
||||
signingConfigs {
|
||||
create("release") {
|
||||
|
@ -49,11 +49,13 @@
|
||||
android:usesCleartextTraffic="true"
|
||||
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:hardwareAccelerated="true"
|
||||
android:largeHeap="true"
|
||||
android:label="SpotiFlyer"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:forceDarkAllowed="true"
|
||||
android:extractNativeLibs="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
tools:targetApi="q">
|
||||
<activity android:name=".MainActivity"
|
||||
|
@ -102,6 +102,7 @@ class MainActivity : ComponentActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
preferenceManager.analyticsManager = analyticsManager
|
||||
// This app draws behind the system bars, so we want to handle fitting system windows
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
rootComponent = spotiFlyerRoot(defaultComponentContext())
|
||||
@ -137,9 +138,7 @@ class MainActivity : ComponentActivity() {
|
||||
AnalyticsDialog(
|
||||
askForAnalyticsPermission,
|
||||
enableAnalytics = {
|
||||
preferenceManager.toggleAnalytics(true) {
|
||||
analyticsManager.giveConsent()
|
||||
}
|
||||
preferenceManager.toggleAnalytics(true)
|
||||
preferenceManager.firstLaunchDone()
|
||||
},
|
||||
dismissDialog = {
|
||||
|
@ -46,6 +46,7 @@ import com.shabinder.common.translations.Strings
|
||||
import com.shabinder.spotiflyer.R
|
||||
import com.shabinder.spotiflyer.utils.autoclear.AutoClear
|
||||
import com.shabinder.spotiflyer.utils.autoclear.autoClear
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
@ -184,7 +185,14 @@ class ForegroundService : LifecycleService() {
|
||||
addToNotification(Message(track.title, DownloadStatus.Converting))
|
||||
|
||||
// All Processing Completed for this Track
|
||||
job.invokeOnCompletion {
|
||||
job.invokeOnCompletion { throwable ->
|
||||
if(throwable != null && throwable !is CancellationException) {
|
||||
// handle error
|
||||
failed++
|
||||
trackStatusFlowMap[track.title] = DownloadStatus.Failed(throwable)
|
||||
removeFromNotification(Message(track.title, DownloadStatus.Converting))
|
||||
return@invokeOnCompletion
|
||||
}
|
||||
converted++
|
||||
trackStatusFlowMap[track.title] = DownloadStatus.Downloaded
|
||||
removeFromNotification(Message(track.title, DownloadStatus.Converting))
|
||||
|
@ -16,14 +16,13 @@
|
||||
|
||||
@file:Suppress("MayBeConstant", "SpellCheckingInspection")
|
||||
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo
|
||||
|
||||
object Versions {
|
||||
// App's Version (To be bumped at each update)
|
||||
const val versionName = "3.2.5"
|
||||
const val versionName = "3.3.0"
|
||||
|
||||
const val versionCode = 24
|
||||
|
||||
|
@ -20,6 +20,7 @@ class AndroidMediaConverter(private val appContext: Context) : MediaConverter()
|
||||
progressCallbacks: (Long) -> Unit,
|
||||
) = executeSafelyInPool {
|
||||
var progressing = true
|
||||
var error = ""
|
||||
var timeout = 600_000L * 2 // 20 min
|
||||
val progressDelayCheck = 500L
|
||||
// 192 is Default
|
||||
@ -47,17 +48,19 @@ class AndroidMediaConverter(private val appContext: Context) : MediaConverter()
|
||||
}
|
||||
|
||||
override fun onFailure(message: String?) {
|
||||
Log.d("FFmpeg Command", "Failed $message")
|
||||
error = "Failed: $message $inputFilePath"
|
||||
error += "FFmpeg Support" + FFmpeg.getInstance(appContext).isSupported.toString()
|
||||
Log.d("FFmpeg Error", error)
|
||||
progressing = false
|
||||
throw SpotiFlyerException.MP3ConversionFailed(message = "Android FFmpeg Failed: $message")
|
||||
}
|
||||
}
|
||||
)
|
||||
while (progressing) {
|
||||
if (timeout < 0) throw SpotiFlyerException.MP3ConversionFailed("Conversion Timeout for $inputFilePath")
|
||||
if (timeout < 0) throw SpotiFlyerException.MP3ConversionFailed("$error Conversion Timeout for $inputFilePath")
|
||||
delay(progressDelayCheck)
|
||||
timeout -= progressDelayCheck
|
||||
}
|
||||
if(error.isNotBlank()) throw SpotiFlyerException.MP3ConversionFailed(error)
|
||||
// Return output file path after successful conversion
|
||||
outputFilePath
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import io.ktor.client.request.*
|
||||
import io.ktor.client.statement.*
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import org.koin.core.module.Module
|
||||
import kotlin.math.roundToInt
|
||||
@ -102,28 +103,26 @@ fun getNameURL(url: String): String {
|
||||
|
||||
suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
||||
return flow {
|
||||
try {
|
||||
val client = createHttpClient()
|
||||
val response = client.get<HttpStatement>(url).execute()
|
||||
val data = ByteArray(response.contentLength()!!.toInt())
|
||||
var offset = 0
|
||||
do {
|
||||
// Set Length optimally, after how many kb you want a progress update, now it 0.25mb
|
||||
val currentRead = response.content.readAvailable(data, offset, 2_50_000)
|
||||
offset += currentRead
|
||||
val progress = (offset * 100f / data.size).roundToInt()
|
||||
emit(DownloadResult.Progress(progress))
|
||||
} while (currentRead > 0)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(DownloadResult.Success(data))
|
||||
} else {
|
||||
emit(DownloadResult.Error("File not downloaded"))
|
||||
}
|
||||
client.close()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
emit(DownloadResult.Error(e.message ?: "File not downloaded"))
|
||||
val client = createHttpClient()
|
||||
val response = client.get<HttpStatement>(url).execute()
|
||||
val data = ByteArray(response.contentLength()!!.toInt())
|
||||
var offset = 0
|
||||
do {
|
||||
// Set Length optimally, after how many kb you want a progress update, now it 0.25mb
|
||||
val currentRead = response.content.readAvailable(data, offset, 2_50_000)
|
||||
offset += currentRead
|
||||
val progress = (offset * 100f / data.size).roundToInt()
|
||||
emit(DownloadResult.Progress(progress))
|
||||
} while (currentRead > 0)
|
||||
if (response.status.isSuccess()) {
|
||||
emit(DownloadResult.Success(data))
|
||||
} else {
|
||||
emit(DownloadResult.Error("File not downloaded"))
|
||||
}
|
||||
client.close()
|
||||
}.catch { e ->
|
||||
e.printStackTrace()
|
||||
emit(DownloadResult.Error(e.message ?: "File not downloaded"))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
package com.shabinder.common.core_components.preference_manager
|
||||
|
||||
import com.russhwolf.settings.Settings
|
||||
import com.shabinder.common.core_components.analytics.AnalyticsManager
|
||||
import com.shabinder.common.models.AudioQuality
|
||||
|
||||
class PreferenceManager(
|
||||
settings: Settings
|
||||
settings: Settings,
|
||||
) : Settings by settings {
|
||||
|
||||
companion object {
|
||||
@ -15,11 +16,15 @@ class PreferenceManager(
|
||||
const val PREFERRED_AUDIO_QUALITY = "preferredAudioQuality"
|
||||
}
|
||||
|
||||
lateinit var analyticsManager: AnalyticsManager
|
||||
|
||||
/* ANALYTICS */
|
||||
val isAnalyticsEnabled get() = getBooleanOrNull(ANALYTICS_KEY) ?: false
|
||||
fun toggleAnalytics(enabled: Boolean,f: () -> Unit = {}) {
|
||||
fun toggleAnalytics(enabled: Boolean) {
|
||||
putBoolean(ANALYTICS_KEY, enabled)
|
||||
f()
|
||||
if (this::analyticsManager.isInitialized) {
|
||||
if (enabled) analyticsManager.giveConsent() else analyticsManager.revokeConsent()
|
||||
}
|
||||
}
|
||||
|
||||
/* DOWNLOAD DIRECTORY */
|
||||
|
@ -82,9 +82,7 @@ internal class SpotiFlyerMainStoreProvider(dependencies: SpotiFlyerMain.Dependen
|
||||
is Intent.SelectCategory -> dispatch(Result.CategoryChanged(intent.category))
|
||||
is Intent.ToggleAnalytics -> {
|
||||
dispatch(Result.AnalyticsToggled(intent.enabled))
|
||||
preferenceManager.toggleAnalytics(intent.enabled) {
|
||||
if (intent.enabled) analyticsManager.giveConsent() else analyticsManager.revokeConsent()
|
||||
}
|
||||
preferenceManager.toggleAnalytics(intent.enabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,9 +61,7 @@ internal class SpotiFlyerPreferenceStoreProvider(
|
||||
is Intent.ShareApp -> methods.value.shareApp()
|
||||
is Intent.ToggleAnalytics -> {
|
||||
dispatch(Result.AnalyticsToggled(intent.enabled))
|
||||
preferenceManager.toggleAnalytics(intent.enabled) {
|
||||
if (intent.enabled) analyticsManager.giveConsent() else analyticsManager.revokeConsent()
|
||||
}
|
||||
preferenceManager.toggleAnalytics(intent.enabled)
|
||||
}
|
||||
is Intent.SetDownloadDirectory -> {
|
||||
dispatch(Result.DownloadPathSet(intent.path))
|
||||
|
@ -105,8 +105,10 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
|
||||
override val fetchQuery: FetchPlatformQueryResult = koin.get()
|
||||
override val fileManager: FileManager = koin.get()
|
||||
override val database: Database? = fileManager.db
|
||||
override val preferenceManager: PreferenceManager = koin.get()
|
||||
override val analyticsManager: AnalyticsManager = koin.get()
|
||||
override val preferenceManager: PreferenceManager = koin.get<PreferenceManager>().also {
|
||||
it.analyticsManager = analyticsManager
|
||||
}
|
||||
override val downloadProgressFlow = DownloadProgressFlow
|
||||
override val actions: Actions = object : Actions {
|
||||
override val platformActions = object : PlatformActions {}
|
||||
|
73
ffmpeg/android-ffmpeg/build.gradle.bak
Normal file
73
ffmpeg/android-ffmpeg/build.gradle.bak
Normal file
@ -0,0 +1,73 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
publishedGroupId = 'nl.bravobit'
|
||||
libraryName = 'Android FFmpeg'
|
||||
artifact = 'android-ffmpeg'
|
||||
|
||||
libraryDescription = 'FFmpeg/FFprobe compiled for Android. Execute FFmpeg and FFprobe commands with ease in your Android project.'
|
||||
|
||||
siteUrl = 'https://github.com/bravobit/FFmpeg-Android'
|
||||
gitUrl = 'https://github.com/bravobit/FFmpeg-Android.git'
|
||||
|
||||
libraryVersion = '1.1.7'
|
||||
|
||||
developerId = 'Bravobit'
|
||||
developerName = 'Bravobit'
|
||||
developerEmail = 'info@bravobit.nl'
|
||||
|
||||
licenseName = 'GNU General Public License v3.0'
|
||||
licenseUrl = 'https://github.com/bravobit/FFmpeg-Android/blob/master/LICENSE'
|
||||
allLicenses = ["GPL-3.0"]
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
versionCode 18
|
||||
versionName "1.2.1"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar) {
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
source = android.sourceSets.main.java.srcDirs
|
||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives javadocJar
|
||||
archives sourcesJar
|
||||
}
|
2
ffmpeg/android-ffmpeg/proguard-rules.pro
vendored
2
ffmpeg/android-ffmpeg/proguard-rules.pro
vendored
@ -1,6 +1,6 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.kts.
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
@ -0,0 +1,5 @@
|
||||
package nl.bravobit.ffmpeg;
|
||||
|
||||
public enum CpuArch {
|
||||
ARMv7, x86, x86_64, ARM_64, NONE
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package nl.bravobit.ffmpeg;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
public class CpuArchHelper {
|
||||
public static final String X86_CPU = "x86";
|
||||
public static final String X86_64_CPU = "x86_64";
|
||||
public static final String ARM_64_CPU = "arm64-v8a";
|
||||
public static final String ARM_V7_CPU = "armeabi-v7a";
|
||||
|
||||
public static CpuArch getCpuArch() {
|
||||
Log.d("Build.CPU_ABI : " + Build.CPU_ABI);
|
||||
|
||||
switch (Build.CPU_ABI) {
|
||||
case X86_CPU:
|
||||
return CpuArch.x86;
|
||||
case X86_64_CPU:
|
||||
return CpuArch.x86_64;
|
||||
case ARM_64_CPU:
|
||||
return CpuArch.ARM_64;
|
||||
case ARM_V7_CPU:
|
||||
return CpuArch.ARMv7;
|
||||
default:
|
||||
return CpuArch.NONE;
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
public class FFmpeg implements FFbinaryInterface {
|
||||
@ -34,7 +35,6 @@ public class FFmpeg implements FFbinaryInterface {
|
||||
|
||||
@Override
|
||||
public boolean isSupported() {
|
||||
|
||||
// get ffmpeg file
|
||||
File ffmpeg = FileUtils.getFFmpeg(context.provide());
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
package nl.bravobit.ffmpeg
|
||||
|
||||
import android.content.Context
|
||||
|
||||
object FFmpegConfig {
|
||||
fun versionFFmpeg(context: Context) {
|
||||
FFmpeg.getInstance(context).execute(arrayOf("-version"), object : ExecuteBinaryResponseHandler() {
|
||||
override fun onSuccess(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
|
||||
override fun onProgress(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun codecsFFmpeg(context: Context) {
|
||||
FFmpeg.getInstance(context).execute(arrayOf("-codecs"), object : ExecuteBinaryResponseHandler() {
|
||||
override fun onSuccess(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
|
||||
override fun onProgress(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun versionFFprobe(context: Context) {
|
||||
Log.d("version ffprobe")
|
||||
FFprobe.getInstance(context).execute(arrayOf("-version"), object : ExecuteBinaryResponseHandler() {
|
||||
override fun onSuccess(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
|
||||
override fun onProgress(message: String) {
|
||||
Log.d(message)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -39,6 +39,7 @@ public class FFprobe implements FFbinaryInterface {
|
||||
|
||||
// check if ffprobe can be executed
|
||||
if (!ffprobe.canExecute()) {
|
||||
// try to make executable
|
||||
Log.e("ffprobe cannot execute");
|
||||
return false;
|
||||
}
|
||||
|
@ -5,8 +5,8 @@ import android.content.Context;
|
||||
import java.io.File;
|
||||
|
||||
class FileUtils {
|
||||
private static final String FFMPEG_FILE_NAME = "ffmpeg";
|
||||
private static final String FFPROBE_FILE_NAME = "ffprobe";
|
||||
private static final String FFMPEG_FILE_NAME = "lib..ffmpeg..so";
|
||||
private static final String FFPROBE_FILE_NAME = "lib..ffprobe..so";
|
||||
|
||||
static File getFFmpeg(Context context) {
|
||||
File folder = new File(context.getApplicationInfo().nativeLibraryDir);
|
||||
|
@ -6,5 +6,6 @@ cd "$(dirname "$0")" || echo "cd to $(dirname "$0") Failed"
|
||||
# Copy ffmpeg executables for all targets
|
||||
for target in arm64-v8a armeabi-v7a x86 x86_64
|
||||
do
|
||||
cp ./ffmpeg-android-maker/build/ffmpeg/$target/bin/ffmpeg ./android-ffmpeg/src/main/resources/lib/$target/
|
||||
mkdir -p ./android-ffmpeg/src/main/jniLibs/$target/
|
||||
cp ./ffmpeg-android-maker/build/ffmpeg/$target/bin/ffmpeg ./android-ffmpeg/src/main/jniLibs/$target/lib..ffmpeg.so
|
||||
done
|
Loading…
Reference in New Issue
Block a user