ffmpeg aar and Build Gradle Files Cleaned.

Targets sdk 30.
Respects Scoped Storage.
This commit is contained in:
Shabinder 2020-11-14 17:53:45 +05:30
parent 04b6f13b22
commit d80821f759
23 changed files with 160 additions and 166 deletions

View File

@ -12,11 +12,9 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/mobile-ffmpeg" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings>
</option>
</component>

View File

@ -8,7 +8,7 @@
<component name="ProjectPlainTextFileTypeManager">
<file url="file://$PROJECT_DIR$/app/src/main/java/com/shabinder/spotiflyer/testing/YoutubeInterface.kt.backup" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -15,42 +15,33 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'dagger.hilt.android.plugin'
apply plugin: 'kotlinx-serialization'
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlin-android-extensions'
id 'androidx.navigation.safeargs.kotlin'
id 'dagger.hilt.android.plugin'
id 'kotlinx-serialization'
}
android {
compileSdkVersion 29
compileSdkVersion 30
buildToolsVersion "30.0.2"
buildFeatures{
//dataBinding = true
viewBinding = true
}
defaultConfig {
applicationId 'com.shabinder.spotiflyer'
minSdkVersion 22
targetSdkVersion 29
targetSdkVersion 30
versionCode 8
versionName "1.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
exclude("META-INF/*.kotlin_module")
}
buildTypes {
release {
minifyEnabled false
@ -62,26 +53,42 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
lintOptions {
abortOnError false
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8.toString()
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
exclude("META-INF/*.kotlin_module")
}
}
dependencies {
implementation fileTree(dir: 'libs', include:['*.jar'])
//Android
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.4.10"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.browser:browser:1.2.0'
implementation 'androidx.webkit:webkit:1.3.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
@ -89,46 +96,49 @@ dependencies {
implementation 'androidx.navigation:navigation-ui-ktx:2.3.1'
implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.1'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1"
//FFmpeg
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
//Room: Local SQL-lite Database
implementation "androidx.room:room-runtime:2.2.5"
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
kapt "androidx.room:room-compiler:2.2.5"
implementation "androidx.room:room-ktx:2.2.5"
//Hilt: Dependency Injection
implementation "com.google.dagger:hilt-android:$hilt_version"
kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
implementation project(path: ':mobile-ffmpeg')
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
transitive = true
}
kapt ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {
transitive = true
}
//Glide-Image Loading
implementation ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {transitive = true}
kapt ("com.github.bumptech.glide:recyclerview-integration:4.11.0") {transitive = true}
//HTTP
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
//Json
implementation 'com.squareup.moshi:moshi:1.11.0'
implementation 'com.squareup.moshi:moshi-kotlin:1.11.0'
implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"
implementation 'com.beust:klaxon:5.4'
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
//Extras
implementation 'me.xdrop:fuzzywuzzy:1.3.1'
implementation 'com.mpatric:mp3agic:0.9.1'
implementation 'com.shreyaspatil:EasyUpiPayment:3.0.0'
implementation 'com.github.sealedtx:java-youtube-downloader:2.4.4'
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5"
implementation 'com.github.javiersantos:AppUpdater:2.7'
implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5"
implementation 'com.github.sealedtx:java-youtube-downloader:2.4.4'
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
testImplementation 'junit:junit:4.13.1'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

BIN
app/libs/mobile-ffmpeg.aar Executable file

Binary file not shown.

View File

@ -24,8 +24,10 @@
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_STORAGE_PERMISSION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
@ -38,9 +40,11 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:forceDarkAllowed="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme"
android:requestLegacyExternalStorage="true"
tools:ignore="AllowBackup"
tools:targetApi="q">
<!--android:requestLegacyExternalStorage="true" For SDK 28-->
<activity android:name="com.shabinder.spotiflyer.MainActivity"
android:launchMode="singleTask">

View File

@ -39,7 +39,10 @@ import com.shabinder.spotiflyer.databinding.MainActivityBinding
import com.shabinder.spotiflyer.downloadHelper.DownloadHelper
import com.shabinder.spotiflyer.networking.SpotifyService
import com.shabinder.spotiflyer.networking.SpotifyServiceTokenRequest
import com.shabinder.spotiflyer.utils.*
import com.shabinder.spotiflyer.utils.NetworkInterceptor
import com.shabinder.spotiflyer.utils.createDirectories
import com.shabinder.spotiflyer.utils.showMessage
import com.shabinder.spotiflyer.utils.startService
import com.squareup.moshi.Moshi
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@ -53,7 +56,6 @@ import javax.inject.Inject
/*
* This is App's God Activity
* */
@Suppress("DEPRECATION")
@AndroidEntryPoint
class MainActivity : AppCompatActivity(){
private var spotifyService : SpotifyService? = null
@ -75,15 +77,15 @@ class MainActivity : AppCompatActivity(){
snackBarAnchor = binding.snackBarPosition
DownloadHelper.youtubeMusicApi = sharedViewModel.youtubeMusicApi
//starting Notification and Downloader Service!
startService(this)
authenticateSpotify()
requestPermission()
disableDozeMode()
checkIfLatestVersion()
createDirectories()
Log.i("Connection Status", isOnline().toString())
//starting Notification and Downloader Service!
startService(this)
handleIntentFromExternalActivity()
}

View File

@ -18,7 +18,6 @@
package com.shabinder.spotiflyer.downloadHelper
import android.annotation.SuppressLint
import android.os.Environment
import android.os.Handler
import android.util.Log
import android.view.View
@ -99,7 +98,6 @@ object DownloadHelper {
if(videoId.isNullOrBlank()) {notFound++ ; updateStatusBar()}
else {//Found Youtube Video ID
val outputFile: String =
Environment.getExternalStorageDirectory().toString() + File.separator +
defaultDir +
removeIllegalChars(type) + File.separator +
(if (subFolder == null) { "" }

View File

@ -17,7 +17,6 @@
package com.shabinder.spotiflyer.downloadHelper
import android.os.Environment
import android.util.Log
import android.widget.Toast
import com.shabinder.spotiflyer.models.DownloadObject
@ -44,9 +43,7 @@ object YTDownloadHelper {
showNoConnectionAlert()
return
}
val outputFile: String =
Environment.getExternalStorageDirectory().toString() + File.separator +
defaultDir +
val outputFile: String = defaultDir +
removeIllegalChars(type) + File.separator +
(if (subFolder == null) { "" }
else { removeIllegalChars(subFolder) + File.separator }

View File

@ -18,7 +18,6 @@
package com.shabinder.spotiflyer.models.gaana
data class GaanaPlaylist (
val tags : String?,
val modified_on : String,
val count : Int,
val created_on : String,

View File

@ -17,7 +17,6 @@
package com.shabinder.spotiflyer.ui.gaana
import android.os.Environment
import androidx.hilt.lifecycle.ViewModelInject
import com.shabinder.spotiflyer.database.DatabaseDAO
import com.shabinder.spotiflyer.database.DownloadRecord
@ -165,8 +164,7 @@ class GaanaViewModel @ViewModelInject constructor(
artists = it.artist.map { artist -> artist?.name.toString() },
durationSec = it.duration,
albumArt = File(
Environment.getExternalStorageDirectory(),
Provider.defaultDir +".Images/" + (it.artworkLink.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg"),
Provider.imageDir + (it.artworkLink.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg"),
albumName = it.album_title,
year = it.release_date,
comment = "Genres:${it.genre?.map { genre -> genre?.name }?.reduceOrNull { acc, s -> acc + s }}",

View File

@ -17,7 +17,6 @@
package com.shabinder.spotiflyer.ui.spotify
import android.os.Environment
import android.util.Log
import androidx.hilt.lifecycle.ViewModelInject
import com.shabinder.spotiflyer.database.DatabaseDAO
@ -29,7 +28,7 @@ import com.shabinder.spotiflyer.models.spotify.Image
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.models.spotify.Track
import com.shabinder.spotiflyer.networking.SpotifyService
import com.shabinder.spotiflyer.utils.Provider
import com.shabinder.spotiflyer.utils.Provider.imageDir
import com.shabinder.spotiflyer.utils.TrackListViewModel
import com.shabinder.spotiflyer.utils.finalOutputDir
import kotlinx.coroutines.Dispatchers
@ -200,8 +199,7 @@ class SpotifyViewModel @ViewModelInject constructor(
artists = it.artists?.map { artist -> artist?.name.toString() } ?: listOf(),
durationSec = (it.duration_ms/1000).toInt(),
albumArt = File(
Environment.getExternalStorageDirectory(),
Provider.defaultDir +".Images/" + (it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString()).substringAfterLast('/') + ".jpeg"),
imageDir + (it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString()).substringAfterLast('/') + ".jpeg"),
albumName = it.album?.name,
year = it.album?.release_date,
comment = "Genres:${it.album?.genres?.joinToString()}",

View File

@ -68,7 +68,7 @@ class YoutubeFragment : TrackListFragment<YoutubeViewModel,YoutubeFragmentArgs>(
if(link.contains(sampleDomain1,true) ){
searchId = link.substringAfterLast("=","error")
}
if(link.contains(sampleDomain2,true) && !link.contains("playlist",true) ){
if(link.contains(sampleDomain2,true) ){
searchId = link.substringAfterLast("/","error")
}
if(searchId != "error") {

View File

@ -18,7 +18,6 @@
package com.shabinder.spotiflyer.ui.youtube
import android.annotation.SuppressLint
import android.os.Environment
import android.util.Log
import androidx.hilt.lifecycle.ViewModelInject
import com.github.kiulian.downloader.YoutubeDownloader
@ -28,7 +27,7 @@ import com.shabinder.spotiflyer.models.DownloadStatus
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.utils.*
import com.shabinder.spotiflyer.utils.Provider.defaultDir
import com.shabinder.spotiflyer.utils.Provider.imageDir
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -36,7 +35,7 @@ import java.io.File
class YoutubeViewModel @ViewModelInject constructor(
val databaseDAO: DatabaseDAO,
val ytDownloader: YoutubeDownloader
private val ytDownloader: YoutubeDownloader
) : TrackListViewModel(){
/*
* YT Album Art Schema
@ -67,8 +66,7 @@ class YoutubeViewModel @ViewModelInject constructor(
artists = listOf(it.author().toString()),
durationSec = it.lengthSeconds(),
albumArt = File(
Environment.getExternalStorageDirectory(),
defaultDir + ".Images/" + it.videoId() + ".jpeg"
imageDir + it.videoId() + ".jpeg"
),
source = Source.YouTube,
albumArtURL = "https://i.ytimg.com/vi/${it.videoId()}/hqdefault.jpg",
@ -121,10 +119,7 @@ class YoutubeViewModel @ViewModelInject constructor(
title = name,
artists = listOf(detail?.author().toString()),
durationSec = detail?.lengthSeconds()?:0,
albumArt = File(
Environment.getExternalStorageDirectory(),
"$defaultDir.Images/$searchId.jpeg"
),
albumArt = File(imageDir,"$searchId.jpeg"),
source = Source.YouTube,
albumArtURL = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg"
)

View File

@ -49,13 +49,21 @@ import javax.inject.Singleton
@Module
object Provider {
/*
* mainActivity Instance to use whereEver Needed , as Its God Activity.
* (i.e, Active Through out App' Lifecycle )
* */
// mainActivity Instance to use whereEver Needed , as Its God Activity.
// (i.e, Active Through out App' Lifecycle )
val mainActivity: MainActivity = MainActivity.getInstance()
val defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator
//Default Directory to save Media in their Own Categorized Folders
@Suppress("DEPRECATION")// We Do Have Media Access (But Just Media in Media Directory,Not Anything Else)
val defaultDir = Environment.getExternalStorageDirectory().toString() + File.separator +
Environment.DIRECTORY_MUSIC + File.separator +
"SpotiFlyer"+ File.separator
//Default Cache Directory to save Album Art to use them for writing in Media Later
val imageDir:String
get() = mainActivity.externalCacheDir?.absolutePath + File.separator +
".Images" + File.separator
@Provides

View File

@ -22,6 +22,7 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@ -57,6 +58,7 @@ abstract class TrackListFragment<VM : TrackListViewModel , args: NavArgs> : Frag
showNoConnectionAlert()
mainActivity.navController.popBackStack()
}
Handler()
sharedViewModel = ViewModelProvider(this.requireActivity()).get(SharedViewModel::class.java)
}

View File

@ -22,7 +22,6 @@ import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Environment
import android.util.Log
import android.view.View
import android.view.animation.Animation
@ -42,6 +41,7 @@ import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.models.DownloadObject
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.utils.Provider.defaultDir
import com.shabinder.spotiflyer.utils.Provider.imageDir
import com.shabinder.spotiflyer.utils.Provider.mainActivity
import com.shabinder.spotiflyer.worker.ForegroundService
import kotlinx.coroutines.CoroutineScope
@ -63,8 +63,7 @@ fun startService(context:Context?,objects:ArrayList<DownloadObject>? = null ) {
}
fun finalOutputDir(itemName:String? = null,type:String, subFolder:String?=null,extension:String? = ".mp3"): String{
return Environment.getExternalStorageDirectory().toString() + File.separator +
defaultDir + removeIllegalChars(type) + File.separator +
return defaultDir + removeIllegalChars(type) + File.separator +
(if(subFolder == null){""}else{ removeIllegalChars(subFolder) + File.separator}
+ itemName?.let { removeIllegalChars(it) + extension})
}
@ -121,7 +120,7 @@ fun rotateAnim(view: View){
0F, 360F,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f
)
rotate.duration = 1000
rotate.duration = 2000
rotate.repeatCount = Animation.INFINITE
rotate.repeatMode = Animation.INFINITE
rotate.interpolator = LinearInterpolator()
@ -172,26 +171,22 @@ fun bindImage(imgView: ImageView, imgUrl: String?,source: Source?) {
val file = when(source){
Source.Spotify->{
File(
Environment.getExternalStorageDirectory(),
defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
imageDir + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
)
}
Source.YouTube->{
//Url Format: https://i.ytimg.com/vi/$searchId/maxresdefault.jpg"
// We Are Naming using "$searchId"
File(
Environment.getExternalStorageDirectory(),
defaultDir+".Images/" + imgUrl.substringBeforeLast('/',imgUrl).substringAfterLast('/',imgUrl) + ".jpeg"
imageDir + imgUrl.substringBeforeLast('/',imgUrl).substringAfterLast('/',imgUrl) + ".jpeg"
)
}
Source.Gaana -> {
File(
Environment.getExternalStorageDirectory(),
Provider.defaultDir +".Images/" + (imgUrl.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg")
imageDir + (imgUrl.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg")
}
else -> File(
Environment.getExternalStorageDirectory(),
defaultDir+".Images/" + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
imageDir + imgUrl.substringAfterLast('/',imgUrl) + ".jpeg"
)
}
// the File to save , append increasing numeric counter to prevent files from getting overwritten.
@ -221,18 +216,17 @@ fun File.copyTo(file: File) {
}
}
fun createDirectory(dir:String){
val yourAppDir = File(Environment.getExternalStorageDirectory(),
dir)
val yourAppDir = File(dir)
if(!yourAppDir.exists() && !yourAppDir.isDirectory)
{ // create empty directory
if (yourAppDir.mkdirs())
{Log.i("CreateDir","App dir created")}
{Log.i("CreateDir","$dir created")}
else
{Log.w("CreateDir","Unable to create app dir!")}
{Log.w("CreateDir","Unable to create Dir: $dir!")}
}
else
{Log.i("CreateDir","App dir already exists")}
{Log.i("CreateDir","$dir already exists")}
}
/**
* Removing Illegal Chars from File Name
@ -277,7 +271,7 @@ fun removeIllegalChars(fileName: String): String? {
fun createDirectories() {
createDirectory(defaultDir)
createDirectory(defaultDir + ".Images/")
createDirectory(imageDir)
createDirectory(defaultDir + "Tracks/")
createDirectory(defaultDir + "Albums/")
createDirectory(defaultDir + "Playlists/")
@ -286,19 +280,3 @@ fun createDirectories() {
fun getEmojiByUnicode(unicode: Int): String? {
return String(Character.toChars(unicode))
}
/*
internal val nullOnEmptyConverterFactory = object : Converter.Factory() {
fun converterFactory() = this
override fun responseBodyConverter(
type: Type,
annotations: Array<out Annotation>,
retrofit: Retrofit
) = object : Converter<ResponseBody, Any?> {
val nextResponseBodyConverter =
retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
override fun convert(value: ResponseBody) =
if (value.contentLength() != 0L) nextResponseBodyConverter.convert(value) else null
}
}*/

View File

@ -25,7 +25,10 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.*
import android.os.Build
import android.os.Handler
import android.os.IBinder
import android.os.PowerManager
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
@ -50,6 +53,7 @@ import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.models.DownloadObject
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.utils.Provider
import com.shabinder.spotiflyer.utils.Provider.imageDir
import com.shabinder.spotiflyer.utils.copyTo
import com.tonyodev.fetch2.*
import com.tonyodev.fetch2core.DownloadBlock
@ -59,7 +63,6 @@ import java.io.FileInputStream
import java.io.IOException
import java.util.*
@Suppress("DEPRECATION")
class ForegroundService : Service(){
private val tag = "Foreground Service"
private val channelId = "ForegroundDownloaderService"
@ -73,19 +76,13 @@ class ForegroundService : Service(){
private var serviceJob = Job()
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)
private val requestMap = mutableMapOf<Request, TrackDetails>()
private var speed :Long = 0
private var defaultDir = Environment.DIRECTORY_MUSIC + File.separator + "SpotiFlyer" + File.separator
private val parentDirectory = File(Environment.getExternalStorageDirectory(),
defaultDir +File.separator
)
private var defaultDir = Provider.defaultDir
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
var notificationLine = 0
val messageList = mutableListOf("","","","")
private var pendingIntent:PendingIntent? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
@ -201,7 +198,7 @@ class ForegroundService : Service(){
if(converted == total){
Handler().postDelayed({
Log.i(tag,"Service destroyed.")
deleteFile(parentDirectory)
cleanFiles(File(defaultDir))
releaseWakeLock()
stopForeground(true)
},2000)
@ -212,7 +209,7 @@ class ForegroundService : Service(){
super.onTaskRemoved(rootIntent)
if(converted == total ){
Log.i(tag,"Service Removed.")
deleteFile(parentDirectory)
cleanFiles(File(defaultDir))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
stopForeground(true)
} else {
@ -303,8 +300,6 @@ class ForegroundService : Service(){
requestMap.remove(download.request)
}
}
speed = 0
// updateNotification()
}
override fun onDeleted(download: Download) {
@ -342,7 +337,6 @@ class ForegroundService : Service(){
) {
val track = requestMap[download.request]
Log.i(tag,"${track?.title} ETA: ${etaInMilliSeconds/1000} sec")
speed = (downloadedBytesPerSecond/1000)
// updateNotification()
}
@ -361,9 +355,7 @@ class ForegroundService : Service(){
.setAllowedOverRoaming(false)
.setTitle(track.title)
.setDescription("Spotify Downloader Working Up here...")
.setDestinationInExternalPublicDir(Environment.DIRECTORY_MUSIC, outputDir.removePrefix(
Environment.getExternalStorageDirectory().toString() + Environment.DIRECTORY_MUSIC + File.separator
))
.setDestinationUri(File(outputDir).toUri())
.setNotificationVisibility(VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
//Start Download
val downloadID = downloadManager.enqueue(request)
@ -562,18 +554,18 @@ class ForegroundService : Service(){
}
/**
* Deleting All Residual Files except Mp3 Files
* Cleaning All Residual Files except Mp3 Files
**/
private fun deleteFile(dir:File) {
Log.i(tag,"Starting Deletions in ${dir.path} ")
private fun cleanFiles(dir:File) {
Log.i(tag,"Starting Cleaning in ${dir.path} ")
val fList = dir.listFiles()
fList?.let {
for (file in fList) {
if (file.isDirectory) {
deleteFile(file)
cleanFiles(file)
} else if(file.isFile) {
if(file.path.toString().substringAfterLast(".") != "mp3"){
Log.i(tag,"deleting ${file.path}")
Log.i(tag,"Cleaning ${file.path}")
file.delete()
}
}
@ -618,25 +610,16 @@ class ForegroundService : Service(){
try {
val file = when(source){
"spotify" ->{
File(
Environment.getExternalStorageDirectory(),
defaultDir +".Images/" + url.substringAfterLast('/') + ".jpeg"
)
File(imageDir, url.substringAfterLast('/') + ".jpeg")
}
"youtube" ->{
File(
Environment.getExternalStorageDirectory(),
defaultDir +".Images/" + url.substringBeforeLast('/',url).substringAfterLast('/',url) + ".jpeg"
)
File(imageDir, url.substringBeforeLast('/',url).substringAfterLast('/',url) + ".jpeg")
}
"gaana" -> {
File(
Environment.getExternalStorageDirectory(),
Provider.defaultDir +".Images/" + (url.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg")
File(imageDir, (url.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg")
}
else -> File(
Environment.getExternalStorageDirectory(),
defaultDir +".Images/" + url.substringAfterLast('/') + ".jpeg")
else -> File(imageDir, url.substringAfterLast('/') + ".jpeg")
}
resource?.copyTo(file)
} catch (e: IOException) {

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2020 Shabinder Singh
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false">
<solid android:color="@color/colorPrimary"/>
</shape>

View File

@ -15,8 +15,8 @@
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="26dp"
android:height="22dp" android:viewportWidth="512" android:viewportHeight="512">
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="36dp"
android:height="32dp" android:viewportWidth="512" android:viewportHeight="512">
<path android:fillColor="#516AEC" android:pathData="m296,288 l60,-60c7.73,-7.73 17.86,-11.6 28,-11.6 10.055,0 20.101,3.806 27.806,11.407 15.612,15.402 15.207,41.18 -0.3,56.687l-134.293,134.293c-11.716,11.716 -30.711,11.716 -42.426,0l-134.787,-134.787c-7.73,-7.73 -11.6,-17.86 -11.6,-28 0,-10.055 3.806,-20.101 11.407,-27.806 15.402,-15.612 41.18,-15.207 56.687,0.3l59.506,59.506v-232c0,-22.091 17.909,-40 40,-40 22.091,0 40,17.909 40,40z"/>
<path android:fillColor="#EC7EBA" android:pathData="m411.51,284.49 l-134.3,134.3c-11.71,11.71 -30.71,11.71 -42.42,0l-12.74,-12.74c10.69,4.06 23.23,1.77 31.84,-6.84l134.29,-134.29c12.51,-12.51 15.19,-31.7 7.57,-46.74 5.86,1.81 11.39,5.03 16.06,9.63 15.61,15.4 15.2,41.18 -0.3,56.68z"/>
<path android:fillColor="#EC7EBA" android:pathData="m251.88,27.72c-3.46,-3.46 -7.55,-6.29 -12.08,-8.3 4.95,-2.2 10.43,-3.42 16.2,-3.42 11.04,0 21.04,4.48 28.28,11.72s11.72,17.24 11.72,28.28v232l-15.329,15.329c-6.3,6.3 -17.071,1.838 -17.071,-7.071v-240.258c0,-11.04 -4.48,-21.04 -11.72,-28.28z"/>

View File

@ -41,10 +41,9 @@
android:layout_height="wrap_content"
android:layout_marginBottom="48dp"
android:background="@drawable/text_background_accented"
android:fontFamily="@font/raleway_semibold"
android:foreground="@drawable/rounded_gradient"
android:padding="7dp"
android:text="Developer: Shabinder Singh"
android:text=" Developer: Shabinder Singh "
android:textColor="@color/white"
android:textSize="16sp"
android:visibility="visible"

View File

@ -19,14 +19,14 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_height="70dp"
android:layout_marginBottom="12dp"
android:background="#000000">
<ImageView
android:id="@+id/imageUrl"
android:layout_width="100dp"
android:layout_height="80dp"
android:layout_width="90dp"
android:layout_height="70dp"
android:contentDescription="Track Image"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
@ -41,6 +41,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="8dp"
android:fontFamily="@font/raleway_semibold"
android:letterSpacing="0.04"
android:lines="1"
@ -50,7 +51,7 @@
android:textColor="#9AB3FF"
android:textSize="18sp"
app:layout_constraintEnd_toStartOf="@+id/btn_download"
app:layout_constraintStart_toStartOf="@+id/artist"
app:layout_constraintStart_toEndOf="@+id/imageUrl"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@ -61,7 +62,6 @@
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:paddingLeft="9dp"
android:text="Alan Walker"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="parent"
@ -75,8 +75,7 @@
style="@style/TextAppearance.AppCompat.Body2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="3dp"
android:paddingLeft="9dp"
android:layout_marginEnd="8dp"
android:text="4 minutes, 20 sec"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/artist"
@ -88,8 +87,9 @@
android:id="@+id/btn_download"
android:layout_width="60dp"
android:layout_height="0dp"
android:background="@drawable/circular_background"
android:backgroundTint="@color/black"
android:scaleType="fitCenter"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"

View File

@ -28,11 +28,13 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:4.2.0-alpha16'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
//safe-Args
//Safe-Args
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
//Hilt
classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
//Kotlinx-Serialization
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@ -45,9 +47,6 @@ allprojects {
jcenter()
mavenCentral()
maven { url "https://jitpack.io" }
flatDir {
dirs 'libs'
}
}
}

View File

@ -14,7 +14,5 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
include ':mobile-ffmpeg'
include ':app'
rootProject.name = "spotiflyer"