WIP:Download Impl

This commit is contained in:
shabinder 2021-02-15 03:34:37 +05:30
parent 5ceb58e6de
commit 50fa91fbca
20 changed files with 158 additions and 57 deletions

View File

@ -20,6 +20,7 @@ internal class SpotiFlyerListImpl(
private val store = private val store =
instanceKeeper.getStore { instanceKeeper.getStore {
SpotiFlyerListStoreProvider( SpotiFlyerListStoreProvider(
dir = this.dir,
storeFactory = storeFactory, storeFactory = storeFactory,
fetchQuery = fetchQuery, fetchQuery = fetchQuery,
link = link link = link

View File

@ -2,6 +2,7 @@ package com.shabinder.common.list.store
import com.arkivanov.mvikotlin.core.store.* import com.arkivanov.mvikotlin.core.store.*
import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor import com.arkivanov.mvikotlin.extensions.coroutines.SuspendExecutor
import com.shabinder.common.di.Dir
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.downloadTracks import com.shabinder.common.di.downloadTracks
import com.shabinder.common.list.SpotiFlyerList.State import com.shabinder.common.list.SpotiFlyerList.State
@ -9,8 +10,10 @@ import com.shabinder.common.list.store.SpotiFlyerListStore.Intent
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.ui.showPopUpMessage
internal class SpotiFlyerListStoreProvider( internal class SpotiFlyerListStoreProvider(
private val dir: Dir,
private val storeFactory: StoreFactory, private val storeFactory: StoreFactory,
private val fetchQuery: FetchPlatformQueryResult, private val fetchQuery: FetchPlatformQueryResult,
private val link: String private val link: String
@ -45,8 +48,8 @@ internal class SpotiFlyerListStoreProvider(
is Intent.StartDownloadAll -> { is Intent.StartDownloadAll -> {
val finalList = val finalList =
intent.trackList.filter { it.downloaded == DownloadStatus.NotDownloaded } intent.trackList.filter { it.downloaded == DownloadStatus.NotDownloaded }
if (finalList.isNullOrEmpty()) //TODO showDialog("All Songs are Processed") if (finalList.isNullOrEmpty()) showPopUpMessage("All Songs are Processed")
else downloadTracks(finalList) else downloadTracks(finalList,fetchQuery.youtubeMusic::getYTIDBestMatch,dir::saveFileWithMetadata)
val list = intent.trackList.map { val list = intent.trackList.map {
if (it.downloaded == DownloadStatus.NotDownloaded) { if (it.downloaded == DownloadStatus.NotDownloaded) {

View File

@ -25,9 +25,11 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.shabinder.common.di.giveDonation
import com.shabinder.common.models.DownloadRecord import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
import com.shabinder.common.di.openPlatform import com.shabinder.common.di.openPlatform
import com.shabinder.common.di.shareApp
import com.shabinder.common.ui.* import com.shabinder.common.ui.*
import com.shabinder.common.ui.SpotiFlyerTypography import com.shabinder.common.ui.SpotiFlyerTypography
@ -73,10 +75,9 @@ fun HomeTabBar(
) )
} }
@Suppress("USELESS_CAST")//Showing Error in Latest Android Studio Canary
TabRow( TabRow(
selectedTabIndex = selectedIndex, selectedTabIndex = selectedIndex,
indicator = indicator as @Composable (List<TabPosition>) -> Unit, indicator = indicator,
modifier = modifier, modifier = modifier,
) { ) {
categories.forEachIndexed { index, category -> categories.forEachIndexed { index, category ->
@ -245,51 +246,44 @@ fun AboutColumn(modifier: Modifier = Modifier) {
) )
} }
} }
/*Row( Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp) modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(onClick = { startPayment(mainActivity) }), .clickable(onClick = { giveDonation() }),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(Icons.Rounded.MailOutline.copy(defaultHeight = 32.dp,defaultWidth = 32.dp)) Icon(Icons.Rounded.MailOutline,"Support Developer")
Spacer(modifier = Modifier.padding(start = 16.dp)) Spacer(modifier = Modifier.padding(start = 16.dp))
Column { Column {
Text( Text(
text = stringResource(R.string.donate), text = "Donate",
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = stringResource(R.string.donate_subtitle), text = "If you think I deserve to get paid for my work, you can leave me some money here.",
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
}*/ }
/*Row( Row(
modifier = modifier.fillMaxWidth().padding(vertical = 6.dp) modifier = modifier.fillMaxWidth().padding(vertical = 6.dp)
.clickable(onClick = { .clickable(onClick = {
val sendIntent: Intent = Intent().apply { shareApp()
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "Hey, checkout this excellent Music Downloader http://github.com/Shabinder/SpotiFlyer")
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
ctx.startActivity(shareIntent)
}), }),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Icon(Icons.Rounded.Share.copy(defaultHeight = 32.dp,defaultWidth = 32.dp)) Icon(Icons.Rounded.Share,"Share SpotiFlyer App")
Spacer(modifier = Modifier.padding(start = 16.dp)) Spacer(modifier = Modifier.padding(start = 16.dp))
Column { Column {
Text( Text(
text = stringResource(R.string.share), text = "Share",
style = SpotiFlyerTypography.h6 style = SpotiFlyerTypography.h6
) )
Text( Text(
text = stringResource(R.string.share_subtitle), text = "Share this app with your friends and family.",
style = SpotiFlyerTypography.subtitle2 style = SpotiFlyerTypography.subtitle2
) )
} }
}*/ }
} }
} }
} }

View File

@ -34,15 +34,16 @@ data class TrackDetails(
var source: Source, var source: Source,
var downloaded: DownloadStatus = DownloadStatus.NotDownloaded, var downloaded: DownloadStatus = DownloadStatus.NotDownloaded,
var progress: Int = 2,//2 for visual progress bar hint var progress: Int = 2,//2 for visual progress bar hint
var outputFile: String, var outputFilePath: String,
var videoID:String? = null var videoID:String? = null
) )
enum class DownloadStatus{ @Serializable
Downloaded, sealed class DownloadStatus {
Downloading, object Downloaded :DownloadStatus()
Queued, data class Downloading(val progress: Int = 0):DownloadStatus()
NotDownloaded, object Queued :DownloadStatus()
Converting, object NotDownloaded :DownloadStatus()
Failed object Converting :DownloadStatus()
object Failed :DownloadStatus()
} }

View File

@ -22,13 +22,24 @@ actual fun openPlatform(packageID:String, platformLink:String){
} }
actual fun shareApp(){ actual fun shareApp(){
//TODO val sendIntent: Intent = Intent().apply {
action = Intent.ACTION_SEND
putExtra(Intent.EXTRA_TEXT, "Hey, checkout this excellent Music Downloader http://github.com/Shabinder/SpotiFlyer")
type = "text/plain"
}
val shareIntent = Intent.createChooser(sendIntent, null)
appContext.startActivity(shareIntent)
} }
actual fun giveDonation(){ actual fun giveDonation(){
//TODO //TODO
} }
actual fun downloadTracks(list: List<TrackDetails>){ actual suspend fun downloadTracks(
list: List<TrackDetails>,
getYTIDBestMatch:suspend (String,TrackDetails)->String?,
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
){
//TODO //TODO
} }

View File

@ -32,7 +32,7 @@ fun Mp3File.setId3v1Tags(track: TrackDetails): Mp3File {
} }
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String){ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails){
val id3v2Tag = ID3v24Tag().apply { val id3v2Tag = ID3v24Tag().apply {
artist = track.artists.joinToString(",") artist = track.artists.joinToString(",")
title = track.title title = track.title
@ -50,7 +50,7 @@ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String
fis.close() fis.close()
id3v2Tag.setAlbumImage(bytesArray, "image/jpeg") id3v2Tag.setAlbumImage(bytesArray, "image/jpeg")
this.id3v2Tag = id3v2Tag this.id3v2Tag = id3v2Tag
saveFile(filePath) saveFile(track.outputFilePath)
}catch (e: java.io.FileNotFoundException){ }catch (e: java.io.FileNotFoundException){
try { try {
//Image Still Not Downloaded! //Image Still Not Downloaded!
@ -61,7 +61,7 @@ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String
is DownloadResult.Success -> { is DownloadResult.Success -> {
id3v2Tag.setAlbumImage(it.byteArray, "image/jpeg") id3v2Tag.setAlbumImage(it.byteArray, "image/jpeg")
this.id3v2Tag = id3v2Tag this.id3v2Tag = id3v2Tag
saveFile(filePath) saveFile(track.outputFilePath)
} }
is DownloadResult.Progress -> {}//Nothing for Now , no progress bar to show is DownloadResult.Progress -> {}//Nothing for Now , no progress bar to show
} }

View File

@ -125,7 +125,7 @@ actual class YoutubeProvider actual constructor(
else { else {
DownloadStatus.NotDownloaded DownloadStatus.NotDownloaded
}, },
outputFile = dir.finalOutputDir(it.title(), folderType, subFolder, dir.defaultDir(),".m4a"), outputFilePath = dir.finalOutputDir(it.title(), folderType, subFolder, dir.defaultDir(),".m4a"),
videoID = it.videoId() videoID = it.videoId()
) )
} }
@ -195,7 +195,7 @@ actual class YoutubeProvider actual constructor(
else { else {
DownloadStatus.NotDownloaded DownloadStatus.NotDownloaded
}, },
outputFile = dir.finalOutputDir(name, folderType, subFolder, dir.defaultDir(),".m4a"), outputFilePath = dir.finalOutputDir(name, folderType, subFolder, dir.defaultDir(),".m4a"),
videoID = searchId videoID = searchId
) )
) )

View File

@ -33,7 +33,7 @@ fun commonModule(enableNetworkLogs: Boolean) = module {
single { SpotifyProvider(get(),get(),get(),get()) } single { SpotifyProvider(get(),get(),get(),get()) }
single { GaanaProvider(get(),get(),get(),get()) } single { GaanaProvider(get(),get(),get(),get()) }
single { YoutubeProvider(get(),get(),get(),get()) } single { YoutubeProvider(get(),get(),get(),get()) }
single { FetchPlatformQueryResult(get(),get(),get(),get()) } single { FetchPlatformQueryResult(get(),get(),get(),get(),get()) }
single { createHttpClient(enableNetworkLogs = enableNetworkLogs) } single { createHttpClient(enableNetworkLogs = enableNetworkLogs) }
} }

View File

@ -2,6 +2,7 @@ package com.shabinder.common.di
import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.ImageBitmap
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.di.providers.YoutubeMusic
import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import io.ktor.client.request.* import io.ktor.client.request.*
@ -13,7 +14,7 @@ import kotlinx.coroutines.flow.flow
import kotlin.math.roundToInt import kotlin.math.roundToInt
expect class Dir( expect class Dir(
logger: Kermit, logger: Kermit
) { ) {
fun isPresent(path:String):Boolean fun isPresent(path:String):Boolean
fun fileSeparator(): String fun fileSeparator(): String
@ -23,7 +24,7 @@ expect class Dir(
suspend fun cacheImage(image: Any,path: String) // in Android = ImageBitmap, Desktop = BufferedImage suspend fun cacheImage(image: Any,path: String) // in Android = ImageBitmap, Desktop = BufferedImage
suspend fun loadImage(url:String): ImageBitmap? suspend fun loadImage(url:String): ImageBitmap?
suspend fun clearCache() suspend fun clearCache()
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails) suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, trackDetails: TrackDetails)
} }
suspend fun downloadFile(url: String): Flow<DownloadResult> { suspend fun downloadFile(url: String): Flow<DownloadResult> {

View File

@ -8,4 +8,8 @@ expect fun shareApp()
expect fun giveDonation() expect fun giveDonation()
expect fun downloadTracks(list: List<TrackDetails>) expect suspend fun downloadTracks(
list: List<TrackDetails>,
getYTIDBestMatch:suspend (String,TrackDetails)->String?,
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
)

View File

@ -4,6 +4,7 @@ import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.database.DownloadRecordDatabaseQueries import com.shabinder.common.database.DownloadRecordDatabaseQueries
import com.shabinder.common.di.providers.GaanaProvider import com.shabinder.common.di.providers.GaanaProvider
import com.shabinder.common.di.providers.SpotifyProvider import com.shabinder.common.di.providers.SpotifyProvider
import com.shabinder.common.di.providers.YoutubeMusic
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -12,6 +13,7 @@ class FetchPlatformQueryResult(
private val gaanaProvider: GaanaProvider, private val gaanaProvider: GaanaProvider,
private val spotifyProvider: SpotifyProvider, private val spotifyProvider: SpotifyProvider,
private val youtubeProvider: YoutubeProvider, private val youtubeProvider: YoutubeProvider,
val youtubeMusic: YoutubeMusic,
private val database: Database private val database: Database
) { ) {
private val db:DownloadRecordDatabaseQueries private val db:DownloadRecordDatabaseQueries

View File

@ -1,5 +1,7 @@
package com.shabinder.common.di package com.shabinder.common.di
/** /**
* Removing Illegal Chars from File Name * Removing Illegal Chars from File Name
* **/ * **/

View File

@ -220,7 +220,7 @@ class GaanaProvider(
downloaded = it.downloaded ?: DownloadStatus.NotDownloaded, downloaded = it.downloaded ?: DownloadStatus.NotDownloaded,
source = Source.Gaana, source = Source.Gaana,
albumArtURL = it.artworkLink, albumArtURL = it.artworkLink,
outputFile = dir.finalOutputDir(it.track_title,type, subFolder,dir.defaultDir(),".m4a") outputFilePath = dir.finalOutputDir(it.track_title,type, subFolder,dir.defaultDir(),".m4a")
) )
} }
} }

View File

@ -23,7 +23,6 @@ import com.shabinder.common.di.TokenStore
import com.shabinder.common.di.finalOutputDir import com.shabinder.common.di.finalOutputDir
import com.shabinder.common.di.kotlinxSerializer import com.shabinder.common.di.kotlinxSerializer
import com.shabinder.common.di.spotify.SpotifyRequests import com.shabinder.common.di.spotify.SpotifyRequests
import com.shabinder.common.di.spotify.authenticateSpotify
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.spotify.Album import com.shabinder.common.models.spotify.Album
@ -35,7 +34,6 @@ import io.ktor.client.*
import io.ktor.client.features.* import io.ktor.client.features.*
import io.ktor.client.features.json.* import io.ktor.client.features.json.*
import io.ktor.client.request.* import io.ktor.client.request.*
import io.ktor.http.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -273,7 +271,7 @@ class SpotifyProvider(
downloaded = it.downloaded, downloaded = it.downloaded,
source = Source.Spotify, source = Source.Spotify,
albumArtURL = it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString(), albumArtURL = it.album?.images?.elementAtOrNull(1)?.url ?: it.album?.images?.firstOrNull()?.url.toString(),
outputFile = dir.finalOutputDir(it.name.toString(),type, subFolder,dir.defaultDir(),".m4a") outputFilePath = dir.finalOutputDir(it.name.toString(),type, subFolder,dir.defaultDir(),".m4a")
) )
} }
} }

View File

@ -1,6 +1,7 @@
package com.shabinder.common.di.providers package com.shabinder.common.di.providers
import co.touchlab.kermit.Logger import co.touchlab.kermit.Logger
import com.shabinder.common.models.TrackDetails
import com.shabinder.common.models.YoutubeTrack import com.shabinder.common.models.YoutubeTrack
import com.willowtreeapps.fuzzywuzzy.diffutils.FuzzySearch import com.willowtreeapps.fuzzywuzzy.diffutils.FuzzySearch
import io.ktor.client.* import io.ktor.client.*
@ -16,6 +17,15 @@ class YoutubeMusic constructor(
private val httpClient:HttpClient, private val httpClient:HttpClient,
) { ) {
private val tag = "YT Music" private val tag = "YT Music"
suspend fun getYTIDBestMatch(query: String,trackDetails: TrackDetails):String?{
return sortByBestMatch(
getYTTracks(query),
trackName = trackDetails.title,
trackArtists = trackDetails.artists,
trackDurationSec = trackDetails.durationSec
).keys.firstOrNull()
}
suspend fun getYTTracks(query: String):List<YoutubeTrack>{ suspend fun getYTTracks(query: String):List<YoutubeTrack>{
val youtubeTracks = mutableListOf<YoutubeTrack>() val youtubeTracks = mutableListOf<YoutubeTrack>()

View File

@ -1,6 +1,16 @@
package com.shabinder.common.di package com.shabinder.common.di
import com.github.kiulian.downloader.YoutubeDownloader
import com.github.kiulian.downloader.model.YoutubeVideo
import com.github.kiulian.downloader.model.formats.Format
import com.github.kiulian.downloader.model.quality.AudioQuality
import com.shabinder.common.models.DownloadResult
import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
actual fun openPlatform(packageID:String, platformLink:String){ actual fun openPlatform(packageID:String, platformLink:String){
//TODO //TODO
@ -14,6 +24,71 @@ actual fun giveDonation(){
//TODO //TODO
} }
actual fun downloadTracks(list: List<TrackDetails>){ val DownloadProgressFlow = MutableStateFlow(Pair<String,DownloadStatus>("",DownloadStatus.Queued))
//TODO
actual suspend fun downloadTracks(
list: List<TrackDetails>,
getYTIDBestMatch:suspend (String,TrackDetails)->String?,
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
){
list.forEach {
if (!it.videoID.isNullOrBlank()) {//Video ID already known!
downloadTrack(it.videoID!!, it,saveFileWithMetaData)
} else {
val searchQuery = "${it.title} - ${it.artists.joinToString(",")}"
val videoId = getYTIDBestMatch(searchQuery,it)
if (videoId.isNullOrBlank()) {
DownloadProgressFlow.emit(Pair(it.title,DownloadStatus.Failed))
} else {//Found Youtube Video ID
downloadTrack(videoId, it,saveFileWithMetaData)
}
}
}
}
val ytDownloader = YoutubeDownloader()
suspend fun downloadTrack(
videoID: String,
trackDetails: TrackDetails,
saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit
) {
try {
val audioData = ytDownloader.getVideo(videoID).getData()
audioData?.let { format ->
val url: String = format.url()
downloadFile(url).collect {
when(it){
is DownloadResult.Error -> {
//TODO()
}
is DownloadResult.Progress -> {
DownloadProgressFlow.emit(Pair(trackDetails.title,DownloadStatus.Downloading(it.progress)))
}
is DownloadResult.Success -> {
saveFileWithMetaData(it.byteArray,trackDetails)
DownloadProgressFlow.emit(Pair(trackDetails.title,DownloadStatus.Downloaded))
}
}
}
}
}catch (e: java.lang.Exception){
e.printStackTrace()
}
}
fun YoutubeVideo.getData(): Format?{
return try {
findAudioWithQuality(AudioQuality.medium)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
try {
findAudioWithQuality(AudioQuality.high)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
try {
findAudioWithQuality(AudioQuality.low)?.get(0) as Format
} catch (e: java.lang.IndexOutOfBoundsException) {
null
}
}
}
} }

View File

@ -61,16 +61,15 @@ actual class Dir actual constructor(private val logger: Kermit) {
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
actual suspend fun saveFileWithMetadata( actual suspend fun saveFileWithMetadata(
mp3ByteArray: ByteArray, mp3ByteArray: ByteArray,
path: String,
trackDetails: TrackDetails trackDetails: TrackDetails
) { ) {
val file = File(path) val file = File(trackDetails.outputFilePath)
file.writeBytes(mp3ByteArray) file.writeBytes(mp3ByteArray)
Mp3File(file) Mp3File(file)
.removeAllTags() .removeAllTags()
.setId3v1Tags(trackDetails) .setId3v1Tags(trackDetails)
.setId3v2TagsAndSaveFile(trackDetails,path) .setId3v2TagsAndSaveFile(trackDetails)
} }
actual suspend fun loadImage(url: String): ImageBitmap? { actual suspend fun loadImage(url: String): ImageBitmap? {

View File

@ -33,7 +33,7 @@ fun Mp3File.setId3v1Tags(track: TrackDetails): Mp3File {
} }
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String){ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails){
val id3v2Tag = ID3v24Tag().apply { val id3v2Tag = ID3v24Tag().apply {
artist = track.artists.joinToString(",") artist = track.artists.joinToString(",")
title = track.title title = track.title
@ -51,7 +51,7 @@ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String
fis.close() fis.close()
id3v2Tag.setAlbumImage(bytesArray, "image/jpeg") id3v2Tag.setAlbumImage(bytesArray, "image/jpeg")
this.id3v2Tag = id3v2Tag this.id3v2Tag = id3v2Tag
saveFile(filePath) saveFile(track.outputFilePath)
}catch (e: java.io.FileNotFoundException){ }catch (e: java.io.FileNotFoundException){
try { try {
//Image Still Not Downloaded! //Image Still Not Downloaded!
@ -62,7 +62,7 @@ suspend fun Mp3File.setId3v2TagsAndSaveFile(track: TrackDetails, filePath:String
is DownloadResult.Success -> { is DownloadResult.Success -> {
id3v2Tag.setAlbumImage(it.byteArray, "image/jpeg") id3v2Tag.setAlbumImage(it.byteArray, "image/jpeg")
this.id3v2Tag = id3v2Tag this.id3v2Tag = id3v2Tag
saveFile(filePath) saveFile(track.outputFilePath)
} }
is DownloadResult.Progress -> {}//Nothing for Now , no progress bar to show is DownloadResult.Progress -> {}//Nothing for Now , no progress bar to show
} }

View File

@ -126,7 +126,7 @@ actual class YoutubeProvider actual constructor(
else { else {
DownloadStatus.NotDownloaded DownloadStatus.NotDownloaded
}, },
outputFile = dir.finalOutputDir(it.title(), folderType, subFolder, dir.defaultDir(),".m4a"), outputFilePath = dir.finalOutputDir(it.title(), folderType, subFolder, dir.defaultDir(),".m4a"),
videoID = it.videoId() videoID = it.videoId()
) )
} }
@ -196,7 +196,7 @@ actual class YoutubeProvider actual constructor(
else { else {
DownloadStatus.NotDownloaded DownloadStatus.NotDownloaded
}, },
outputFile = dir.finalOutputDir(name, folderType, subFolder, dir.defaultDir(),".m4a"), outputFilePath = dir.finalOutputDir(name, folderType, subFolder, dir.defaultDir(),".m4a"),
videoID = searchId videoID = searchId
) )
) )

View File

@ -21,6 +21,6 @@
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="#FFFFFF"
android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2L12,2zM13,12l0,-4h-2l0,4H8l4,4l4,-4H13z"/> android:pathData="M12,4c4.41,0 8,3.59 8,8s-3.59,8 -8,8s-8,-3.59 -8,-8S7.59,4 12,4M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2L12,2zM13,12l0,-4h-2l0,4H8l4,4l4,-4H13z"/>
</vector> </vector>