Service Integrated

This commit is contained in:
shabinder 2021-01-02 01:32:26 +05:30
parent 5c0ec20e1b
commit fd2a1cf46b
7 changed files with 100 additions and 100 deletions

View File

@ -56,6 +56,6 @@
android:value="rzp_live_3ZQeoFYOxjmXye"
/>
<service android:name=".worker.ForegroundService"/>
</application>
</manifest>

View File

@ -24,14 +24,11 @@ import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.jetcaster.util.verticalGradientScrim
import com.shabinder.spotiflyer.models.spotify.Token
import com.shabinder.spotiflyer.navigation.ComposeNavigation
import com.shabinder.spotiflyer.navigation.navigateToTrackList
import com.shabinder.spotiflyer.networking.SpotifyService
import com.shabinder.spotiflyer.networking.SpotifyServiceTokenRequest
import com.shabinder.spotiflyer.ui.ComposeLearnTheme
import com.shabinder.spotiflyer.ui.appNameStyle
@ -41,17 +38,7 @@ import com.squareup.moshi.Moshi
import dagger.hilt.android.AndroidEntryPoint
import dev.chrisbanes.accompanist.insets.ProvideWindowInsets
import dev.chrisbanes.accompanist.insets.statusBarsHeight
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import javax.inject.Inject
import com.shabinder.spotiflyer.utils.showDialog as showDialog1
/*
* This is App's God Activity

View File

@ -1,6 +1,7 @@
package com.shabinder.spotiflyer.ui.tracklist
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.ExtendedFloatingActionButton
@ -25,14 +26,18 @@ import androidx.compose.ui.unit.sp
import androidx.core.net.toUri
import androidx.navigation.NavController
import com.shabinder.spotiflyer.R
import com.shabinder.spotiflyer.models.DownloadStatus
import com.shabinder.spotiflyer.models.PlatformQueryResult
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.models.spotify.Source
import com.shabinder.spotiflyer.ui.SpotiFlyerTypography
import com.shabinder.spotiflyer.ui.colorAccent
import com.shabinder.spotiflyer.providers.queryGaana
import com.shabinder.spotiflyer.providers.querySpotify
import com.shabinder.spotiflyer.providers.queryYoutube
import com.shabinder.spotiflyer.ui.utils.calculateDominantColor
import com.shabinder.spotiflyer.utils.downloadTracks
import com.shabinder.spotiflyer.utils.loadAllImages
import com.shabinder.spotiflyer.utils.sharedViewModel
import com.shabinder.spotiflyer.utils.showDialog
import dev.chrisbanes.accompanist.coil.CoilImage
@ -83,14 +88,35 @@ fun TrackList(
item {
CoverImage(it.title,it.coverUrl,coroutineScope)
}
items(it.trackList) {
TrackCard(track = it)
items(it.trackList) { item ->
TrackCard(
track = item,
onDownload = {
showDialog("Downloading ${it.title}")
downloadTracks(arrayListOf(it))
}
)
}
},
modifier = Modifier.fillMaxSize(),
)
DownloadAllButton(
onClick = {},
onClick = {
loadAllImages(
it.trackList.map { it.albumArtURL },
Source.Spotify
)
val finalList = it.trackList.filter{it.downloaded == DownloadStatus.NotDownloaded}
if (finalList.isNullOrEmpty()) showDialog("Not Downloading Any Song")
else downloadTracks(finalList as ArrayList<TrackDetails>)
for (track in it.trackList) {
if (track.downloaded == DownloadStatus.NotDownloaded) {
track.downloaded = DownloadStatus.Queued
//adapter.notifyItemChanged(viewModel.trackList.value!!.indexOf(track))
}
}
showDialog("Downloading All Tracks")
},
modifier = Modifier.padding(bottom = 24.dp).align(Alignment.BottomCenter)
)
}
@ -140,7 +166,10 @@ fun DownloadAllButton(onClick: () -> Unit, modifier: Modifier = Modifier) {
}
@Composable
fun TrackCard(track:TrackDetails) {
fun TrackCard(
track:TrackDetails,
onDownload:(TrackDetails)->Unit
) {
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
val imgUri = track.albumArtURL.toUri().buildUpon().scheme("https").build()
CoilImage(
@ -163,7 +192,7 @@ fun TrackCard(track:TrackDetails) {
Text("${track.durationSec/60} minutes, ${track.durationSec%60} sec",fontSize = 13.sp)
}
}
Image(vectorResource(id = R.drawable.ic_arrow))
Image(vectorResource(id = R.drawable.ic_arrow), Modifier.clickable(onClick = { onDownload(track) }))
}
}

View File

@ -3,6 +3,7 @@ package com.shabinder.spotiflyer.utils
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.util.Log
@ -11,6 +12,7 @@ import com.github.kiulian.downloader.model.formats.Format
import com.github.kiulian.downloader.model.quality.AudioQuality
import com.shabinder.spotiflyer.BuildConfig
import com.shabinder.spotiflyer.MainActivity
import java.io.File
/*
@ -29,6 +31,12 @@ fun MainActivity.requestStoragePermission() {
)
}
}
fun File.writeBitmap(bitmap: Bitmap, format: Bitmap.CompressFormat = Bitmap.CompressFormat.JPEG , quality: Int = 90) {
outputStream().use { out ->
bitmap.compress(format, quality, out)
out.flush()
}
}
fun YoutubeVideo.getData(): Format?{
return try {
findAudioWithQuality(AudioQuality.medium)?.get(0) as Format

View File

@ -45,7 +45,7 @@ val mainActivity
val sharedViewModel
get() = MainActivity.getSharedViewModel()
fun loadAllImages(context: Context? = mainActivity, images:List<String>? = null,source: Source) {
fun loadAllImages( images:List<String>? = null,source: Source, context: Context? = mainActivity) {
val serviceIntent = Intent(context, ForegroundService::class.java)
images?.let { serviceIntent.putStringArrayListExtra("imagesList",(it + source.name) as ArrayList<String>) }
context?.let { ContextCompat.startForegroundService(it, serviceIntent) }
@ -105,7 +105,9 @@ fun isOnline(): Boolean {
fun showDialog(title:String? = null, message: String? = null,response: String = "Ok"){
//TODO
Toast.makeText(mainActivity,title ?: "No Internet",Toast.LENGTH_SHORT).show()
CoroutineScope(Dispatchers.Main).launch {
Toast.makeText(mainActivity,title ?: "No Internet",Toast.LENGTH_SHORT).show()
}
}
/**

View File

@ -20,6 +20,7 @@ package com.shabinder.spotiflyer.worker
import android.annotation.SuppressLint
import android.app.*
import android.app.DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
@ -28,21 +29,15 @@ import android.media.MediaScannerConnection
import android.net.Uri
import android.os.*
import androidx.annotation.RequiresApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Cancel
import androidx.compose.material.icons.rounded.CloudDownload
import androidx.core.app.NotificationCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.net.toUri
import coil.Coil
import coil.request.ImageRequest
import com.arthenica.mobileffmpeg.Config
import com.arthenica.mobileffmpeg.Config.RETURN_CODE_CANCEL
import com.arthenica.mobileffmpeg.Config.RETURN_CODE_SUCCESS
import com.arthenica.mobileffmpeg.FFmpeg
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.github.kiulian.downloader.YoutubeDownloader
import com.mpatric.mp3agic.Mp3File
import com.shabinder.spotiflyer.R
@ -64,7 +59,6 @@ import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
import java.io.IOException
import java.util.*
import javax.inject.Inject
@ -97,6 +91,7 @@ class ForegroundService : Service(){
override fun onBind(intent: Intent): IBinder? = null
@SuppressLint("UnspecifiedImmutableFlag")
override fun onCreate() {
super.onCreate()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -106,7 +101,7 @@ class ForegroundService : Service(){
this,
ForegroundService::class.java
).apply{action = "kill"}
cancelIntent = PendingIntent.getService (this, 0 , intent , PendingIntent.FLAG_CANCEL_CURRENT )
cancelIntent = PendingIntent.getService (this, 0 , intent , FLAG_CANCEL_CURRENT )
downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
initialiseFetch()
}
@ -535,75 +530,50 @@ class ForegroundService : Service(){
/**
* Function to fetch all Images for use in mp3 tags.
**/
fun downloadAllImages(urlList: ArrayList<String>, func: ((resource:File) -> Unit)? = null) {
suspend fun downloadAllImages(urlList: ArrayList<String>, func: ((resource:File) -> Unit)? = null) {
/*
* Last Element of this List defines Its Source
* */
val source = urlList.last()
for (url in urlList.subList(0, urlList.size - 2)) {
val imgUri = url.toUri().buildUpon().scheme("https").build()
Glide
.with(this@ForegroundService)
.asFile()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(imgUri)
.listener(object : RequestListener<File> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<File>?,
isFirstResource: Boolean
): Boolean {
log("Glide", "LoadFailed")
return false
}
withContext(Dispatchers.IO) {
val imgUri = url.toUri().buildUpon().scheme("https").build()
override fun onResourceReady(
resource: File?,
model: Any?,
target: Target<File>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
try {
serviceScope.launch {
val file = when (source) {
Source.Spotify.name -> {
File(imageDir, url.substringAfterLast('/') + ".jpeg")
}
Source.YouTube.name -> {
File(
imageDir,
url.substringBeforeLast('/', url)
.substringAfterLast(
'/',
url
) + ".jpeg"
)
}
Source.Gaana.name -> {
File(
imageDir,
(url.substringBeforeLast('/').substringAfterLast(
'/'
)) + ".jpeg"
)
}
val r = ImageRequest.Builder(this@ForegroundService)
.data(imgUri)
.build()
else -> File(
imageDir,
url.substringAfterLast('/') + ".jpeg"
)
}
resource?.copyTo(file)
func?.let { it(file) }
}
} catch (e: IOException) {
e.printStackTrace()
}
return false
val bitmap = Coil.execute(r).drawable?.toBitmap()
val file = when (source) {
Source.Spotify.name -> {
File(imageDir, url.substringAfterLast('/') + ".jpeg")
}
}).submit()
Source.YouTube.name -> {
File(
imageDir,
url.substringBeforeLast('/', url)
.substringAfterLast(
'/',
url
) + ".jpeg"
)
}
Source.Gaana.name -> {
File(
imageDir,
(url.substringBeforeLast('/').substringAfterLast(
'/'
)) + ".jpeg"
)
}
else -> File(imageDir, url.substringAfterLast('/') + ".jpeg")
}
if (bitmap != null) {
file.writeBitmap(bitmap)
func?.let { it(file) }
} else log("Foreground Service", "Album Art Could Not be Fetched")
}
}
}
@ -660,7 +630,7 @@ class ForegroundService : Service(){
private fun getNotification():Notification = NotificationCompat.Builder(this, channelId).run {
setSmallIcon(R.drawable.ic_download_arrow)
setContentTitle("Total: $total Completed:$converted Failed:$failed")
setNotificationSilent()
setSilent(true)
setStyle(
NotificationCompat.InboxStyle().run {
addLine(messageList[messageList.size - 1])

View File

@ -22,6 +22,8 @@ import com.mpatric.mp3agic.ID3v24Tag
import com.mpatric.mp3agic.Mp3File
import com.shabinder.spotiflyer.models.TrackDetails
import com.shabinder.spotiflyer.utils.log
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.FileInputStream
/**
@ -59,12 +61,14 @@ fun setId3v2Tags(mp3file: Mp3File, track: TrackDetails,service: ForegroundServic
try {
//Image Still Not Downloaded!
//Lets Download Now and Write it into Album Art
service.downloadAllImages(arrayListOf(track.albumArtURL, track.source.name)){
val bytesArray = ByteArray(it.length().toInt())
val fis = FileInputStream(it)
fis.read(bytesArray) //read file into bytes[]
fis.close()
id3v2Tag.setAlbumImage(bytesArray, "image/jpeg")
GlobalScope.launch {
service.downloadAllImages(arrayListOf(track.albumArtURL, track.source.name)) {
val bytesArray = ByteArray(it.length().toInt())
val fis = FileInputStream(it)
fis.read(bytesArray) //read file into bytes[]
fis.close()
id3v2Tag.setAlbumImage(bytesArray, "image/jpeg")
}
}
}catch (e: Exception){log("Error", "Couldn't Write Mp3 Album Art, error: ${e.stackTrace}")}
}