From 86e6a9f3a809b40937b3a7d389acea374a5e5b46 Mon Sep 17 00:00:00 2001 From: shabinder Date: Thu, 2 Sep 2021 23:51:11 +0530 Subject: [PATCH] AudioQuality Parsing Improv --- .../spotiflyer/service/ForegroundService.kt | 4 +- buildSrc/buildSrc/src/main/kotlin/Versions.kt | 4 +- .../file_manager/AndroidFileManager.kt | 1 + .../file_manager/DesktopFileManager.kt | 1 + .../shabinder/common/models/DownloadObject.kt | 1 + .../common/models/saavn/SaavnSong.kt | 5 ++- .../FetchPlatformQueryResult.kt | 39 ++++++++++++++----- .../saavn/SaavnProvider.kt | 6 +-- .../saavn/requests/JioSaavnRequests.kt | 7 +++- .../youtube_music/YoutubeMusic.kt | 4 +- .../common/providers/DesktopActual.kt | 5 ++- .../WebActual.kt | 5 ++- 12 files changed, 56 insertions(+), 26 deletions(-) diff --git a/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt b/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt index 1a314084..c5755a31 100644 --- a/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt +++ b/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt @@ -139,8 +139,8 @@ class ForegroundService : LifecycleService() { lifecycleScope.launch { downloadService.value.executeSuspending { fetcher.findBestDownloadLink(track).fold( - success = { url -> - enqueueDownload(url, track) + success = { res -> + enqueueDownload(res.first, track.apply { audioQuality = res.second }) }, failure = { error -> failed++ diff --git a/buildSrc/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/buildSrc/src/main/kotlin/Versions.kt index ae985a32..ed2c5299 100644 --- a/buildSrc/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/buildSrc/src/main/kotlin/Versions.kt @@ -23,9 +23,9 @@ import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo object Versions { // App's Version (To be bumped at each update) - const val versionName = "3.2.11" + const val versionName = "3.3" - const val versionCode = 23 + const val versionCode = 24 // Kotlin const val kotlinVersion = "1.5.21" diff --git a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt index e938f683..52c67f4e 100644 --- a/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt +++ b/common/core-components/src/androidMain/kotlin/com/shabinder/common/core_components/file_manager/AndroidFileManager.kt @@ -131,6 +131,7 @@ class AndroidFileManager( val conversionResult = mediaConverter.convertAudioFile( inputFilePath = songFile.absolutePath, outputFilePath = convertedFilePath, + trackDetails.audioQuality ) conversionResult.map { outputFilePath -> diff --git a/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt b/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt index 5e88d7a0..682f872c 100644 --- a/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt +++ b/common/core-components/src/desktopMain/kotlin/com.shabinder.common.core_components/file_manager/DesktopFileManager.kt @@ -142,6 +142,7 @@ class DesktopFileManager( val conversionResult = mediaConverter.convertAudioFile( inputFilePath = songFile.absolutePath, outputFilePath = convertedFilePath, + trackDetails.audioQuality ) conversionResult.map { outputFilePath -> diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/DownloadObject.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/DownloadObject.kt index 88c31806..14233056 100644 --- a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/DownloadObject.kt +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/DownloadObject.kt @@ -41,6 +41,7 @@ data class TrackDetails( val progress: Int = 2, val downloadLink: String? = null, val downloaded: DownloadStatus = DownloadStatus.NotDownloaded, + var audioQuality: AudioQuality = AudioQuality.KBPS192, var outputFilePath: String, // UriString in Android var videoID: String? = null, ) : Parcelable { diff --git a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/saavn/SaavnSong.kt b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/saavn/SaavnSong.kt index dd24883f..c4cfae65 100644 --- a/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/saavn/SaavnSong.kt +++ b/common/data-models/src/commonMain/kotlin/com/shabinder/common/models/saavn/SaavnSong.kt @@ -1,5 +1,6 @@ package com.shabinder.common.models.saavn +import com.shabinder.common.models.AudioQuality import com.shabinder.common.models.DownloadStatus import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.Serializable @@ -43,4 +44,6 @@ data class SaavnSong @OptIn(ExperimentalSerializationApi::class) constructor( val vlink: String? = null, val year: String, var downloaded: DownloadStatus = DownloadStatus.NotDownloaded -) +) { + val audioQuality get() = if (is320Kbps) AudioQuality.KBPS320 else AudioQuality.KBPS160 +} diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/FetchPlatformQueryResult.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/FetchPlatformQueryResult.kt index 8cc97bfe..0cfcbfb9 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/FetchPlatformQueryResult.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/FetchPlatformQueryResult.kt @@ -91,27 +91,35 @@ class FetchPlatformQueryResult( suspend fun findBestDownloadLink( track: TrackDetails, preferredQuality: AudioQuality = preferenceManager.audioQuality - ): SuspendableEvent { + ): SuspendableEvent, Throwable> { var downloadLink: String? = null + var audioQuality = AudioQuality.KBPS192 val errorTrace = buildString(track) { if (track.videoID != null) { // We Already have VideoID downloadLink = when (track.source) { Source.JioSaavn -> { - saavnProvider.getSongFromID(track.videoID.requireNotNull()).component1()?.media_url + saavnProvider.getSongFromID(track.videoID.requireNotNull()).component1() + ?.also { audioQuality = it.audioQuality } + ?.media_url } Source.YouTube -> { - youtubeMp3.getMp3DownloadLink(track.videoID.requireNotNull(), preferredQuality) - .let { ytMp3Link -> - if (ytMp3Link is SuspendableEvent.Failure || ytMp3Link.component1().isNullOrBlank()) { + youtubeMp3.getMp3DownloadLink( + track.videoID.requireNotNull(), + preferredQuality + ).let { ytMp3Link -> + if (ytMp3Link is SuspendableEvent.Failure || ytMp3Link.component1() + .isNullOrBlank() + ) { appendPadded( "Yt1sMp3 Failed for ${track.videoID}:", ytMp3Link.component2() ?: "couldn't fetch link for ${track.videoID} ,trying manual extraction" ) appendLine("Trying Local Extraction") - youtubeProvider.ytDownloader.getVideo(track.videoID!!).get()?.url + youtubeProvider.ytDownloader.getVideo(track.videoID!!) + .get()?.url } else ytMp3Link.component1() } } @@ -137,24 +145,35 @@ class FetchPlatformQueryResult( appendPadded("Fetching From Saavn Failed:", saavnError.stackTraceToString()) // Saavn Failed, Lets Try Fetching Now From Youtube Music youtubeMusic.findMp3SongDownloadURLYT(track, preferredQuality).also { + // Append Error To StackTrace if (it is SuspendableEvent.Failure) - appendPadded("Fetching From YT-Music Failed:", it.component2()?.stackTraceToString()) + appendPadded( + "Fetching From YT-Music Failed:", + it.component2()?.stackTraceToString() + ) } } - downloadLink = queryResult.component1() + queryResult.component1()?.let { + downloadLink = it.first + audioQuality = it.second + } } } return if (downloadLink.isNullOrBlank()) SuspendableEvent.error( SpotiFlyerException.DownloadLinkFetchFailed(errorTrace) - ) else SuspendableEvent.success(downloadLink.requireNotNull()) + ) else SuspendableEvent.success(Pair(downloadLink.requireNotNull(),audioQuality)) } @OptIn(DelicateCoroutinesApi::class) private fun addToDatabaseAsync(link: String, result: PlatformQueryResult) { GlobalScope.launch(dispatcherIO) { db?.add( - result.folderType, result.title, link, result.coverUrl, result.trackList.size.toLong() + result.folderType, + result.title, + link, + result.coverUrl, + result.trackList.size.toLong() ) } } diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/SaavnProvider.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/SaavnProvider.kt index 6ae9d43e..4c807462 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/SaavnProvider.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/SaavnProvider.kt @@ -3,10 +3,7 @@ package com.shabinder.common.providers.saavn import co.touchlab.kermit.Kermit import com.shabinder.common.core_components.file_manager.FileManager import com.shabinder.common.core_components.file_manager.finalOutputDir -import com.shabinder.common.models.DownloadStatus -import com.shabinder.common.models.PlatformQueryResult -import com.shabinder.common.models.SpotiFlyerException -import com.shabinder.common.models.TrackDetails +import com.shabinder.common.models.* import com.shabinder.common.models.event.coroutines.SuspendableEvent import com.shabinder.common.models.saavn.SaavnSong import com.shabinder.common.models.spotify.Source @@ -81,6 +78,7 @@ class SaavnProvider( albumArtURL = it.image.replace("http:", "https:"), lyrics = it.lyrics ?: it.lyrics_snippet, source = Source.JioSaavn, + audioQuality = if(it.is320Kbps) AudioQuality.KBPS320 else AudioQuality.KBPS160, outputFilePath = fileManager.finalOutputDir(it.song, type, subFolder, fileManager.defaultDir() /*".m4a"*/) ) } diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/requests/JioSaavnRequests.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/requests/JioSaavnRequests.kt index f1e35a6f..a9d6faec 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/requests/JioSaavnRequests.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/saavn/requests/JioSaavnRequests.kt @@ -32,18 +32,21 @@ interface JioSaavnRequests { trackName: String, trackArtists: List, preferredQuality: AudioQuality - ): SuspendableEvent = searchForSong(trackName).map { songs -> + ): SuspendableEvent, Throwable> = searchForSong(trackName).map { songs -> val bestMatch = sortByBestMatch(songs, trackName, trackArtists).keys.firstOrNull() ?: throw SpotiFlyerException.DownloadLinkFetchFailed("No SAAVN Match Found for $trackName") + var audioQuality: AudioQuality = AudioQuality.KBPS160 val m4aLink: String by getSongFromID(bestMatch).map { song -> val optimalQuality = if (song.is320Kbps && ((preferredQuality.kbps.toIntOrNull() ?: 0) > 160) ) AudioQuality.KBPS320 else AudioQuality.KBPS160 + audioQuality = optimalQuality + song.media_url.requireNotNull().replaceAfterLast("_", "${optimalQuality.kbps}.mp4") } - m4aLink + Pair(m4aLink,audioQuality) } suspend fun searchForSong( diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube_music/YoutubeMusic.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube_music/YoutubeMusic.kt index 1ff59d24..0ca73069 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube_music/YoutubeMusic.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube_music/YoutubeMusic.kt @@ -50,7 +50,7 @@ class YoutubeMusic constructor( suspend fun findMp3SongDownloadURLYT( trackDetails: TrackDetails, preferredQuality: AudioQuality = fileManager.preferenceManager.audioQuality - ): SuspendableEvent { + ): SuspendableEvent, Throwable> { return getYTIDBestMatch(trackDetails).flatMap { videoID -> // As YT compress Audio hence there is no benefit of quality for more than 192 val optimalQuality = @@ -67,6 +67,8 @@ class YoutubeMusic constructor( message = "Caught Following Errors While Finding Downloadable Link for $videoID : \n${it.stackTraceToString()}" ) } + }.map { + Pair(it,optimalQuality) } } } diff --git a/common/providers/src/desktopMain/kotlin/com/shabinder/common/providers/DesktopActual.kt b/common/providers/src/desktopMain/kotlin/com/shabinder/common/providers/DesktopActual.kt index 388e5305..a635f474 100644 --- a/common/providers/src/desktopMain/kotlin/com/shabinder/common/providers/DesktopActual.kt +++ b/common/providers/src/desktopMain/kotlin/com/shabinder/common/providers/DesktopActual.kt @@ -34,8 +34,9 @@ actual suspend fun downloadTracks( list.forEach { trackDetails -> DownloadScope.executeSuspending { // Send Download to Pool. fetcher.findBestDownloadLink(trackDetails).fold( - success = { url -> - downloadFile(url).collect { + success = { res -> + trackDetails.audioQuality = res.second + downloadFile(res.first).collect { when (it) { is DownloadResult.Error -> { DownloadProgressFlow.emit( diff --git a/common/providers/src/jsMain/kotlin/com.shabinder.common.providers/WebActual.kt b/common/providers/src/jsMain/kotlin/com.shabinder.common.providers/WebActual.kt index 803e8043..82fc06ee 100644 --- a/common/providers/src/jsMain/kotlin/com.shabinder.common.providers/WebActual.kt +++ b/common/providers/src/jsMain/kotlin/com.shabinder.common.providers/WebActual.kt @@ -33,8 +33,9 @@ actual suspend fun downloadTracks( withContext(dispatcherIO) { allTracksStatus[track.title] = DownloadStatus.Queued fetcher.findBestDownloadLink(track).fold( - success = { url -> - downloadFile(url).collect { + success = { res -> + track.audioQuality = res.second + downloadFile(res.first).collect { when (it) { is DownloadResult.Success -> { println("Download Completed")