From f7e38c2c6e92fa7839e8cf49e4f16021e53989f1 Mon Sep 17 00:00:00 2001 From: Shabinder Singh Date: Sun, 10 Oct 2021 21:51:14 +0530 Subject: [PATCH] Caching Fixes --- android/build.gradle.kts | 3 +- .../spotiflyer/service/ForegroundService.kt | 4 +- .../com/shabinder/spotiflyer/service/Utils.kt | 13 +++- .../file_manager/AndroidFileManager.kt | 6 +- .../file_manager/FileManager.kt | 70 ++++++++++++++----- .../file_manager/DesktopFileManager.kt | 5 +- .../common/models/saavn/SaavnSong.kt | 2 +- .../gaana/GaanaProvider.kt | 4 +- .../saavn/SaavnProvider.kt | 3 +- .../sound_cloud/SoundCloudProvider.kt | 5 +- .../spotify/SpotifyProvider.kt | 5 +- .../youtube/YoutubeProvider.kt | 21 ++++-- .../youtube_music/YoutubeMusic.kt | 50 ++++++++----- 13 files changed, 127 insertions(+), 64 deletions(-) diff --git a/android/build.gradle.kts b/android/build.gradle.kts index fb95b215..4a88c08c 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -124,8 +124,9 @@ dependencies { implementation(storage.chooser) with(bundles) { - implementation(androidx.lifecycle) + implementation(ktor) implementation(mviKotlin) + implementation(androidx.lifecycle) implementation(accompanist.inset) } 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 b66853ec..d0eb2034 100644 --- a/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt +++ b/android/src/main/java/com/shabinder/spotiflyer/service/ForegroundService.kt @@ -43,6 +43,7 @@ import com.shabinder.common.models.event.coroutines.failure import com.shabinder.common.providers.FetchPlatformQueryResult import com.shabinder.common.translations.Strings import com.shabinder.spotiflyer.R +import io.ktor.client.HttpClient import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.MutableSharedFlow @@ -62,6 +63,7 @@ class ForegroundService : LifecycleService() { private val fetcher: FetchPlatformQueryResult by inject() private val logger: Kermit by inject() private val dir: FileManager by inject() + private val httpClient: HttpClient by inject() private var messageList = java.util.Collections.synchronizedList(MutableList(5) { emptyMessage }) @@ -170,7 +172,7 @@ class ForegroundService : LifecycleService() { trackStatusFlowMap[track.title] = DownloadStatus.Downloading() // Enqueueing Download - downloadFile(url).collect { + httpClient.downloadFile(url).collect { when (it) { is DownloadResult.Error -> { logger.d(TAG) { it.message } diff --git a/android/src/main/java/com/shabinder/spotiflyer/service/Utils.kt b/android/src/main/java/com/shabinder/spotiflyer/service/Utils.kt index fdd75530..06b015b2 100644 --- a/android/src/main/java/com/shabinder/spotiflyer/service/Utils.kt +++ b/android/src/main/java/com/shabinder/spotiflyer/service/Utils.kt @@ -15,12 +15,19 @@ fun cleanFiles(dir: File) { if (file.isDirectory) { cleanFiles(file) } else if (file.isFile) { - if (file.path.toString().substringAfterLast(".") != "mp3") { - Log.d("Files Cleaning", "Cleaning ${file.path}") + val filePath = file.path.toString() + if (filePath.substringAfterLast(".") != "mp3" || filePath.isTempFile()) { + Log.d("Files Cleaning", "Cleaning $filePath") file.delete() } } } } - } catch (e: Exception) { e.printStackTrace() } + } catch (e: Exception) { + e.printStackTrace() + } +} + +private fun String.isTempFile(): Boolean { + return substringBeforeLast(".").takeLast(5) == ".temp" } 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 43d87554..1b30fc38 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 @@ -117,7 +117,7 @@ class AndroidFileManager( try { // Add Mp3 Tags and Add to Library - if(trackDetails.audioFormat != AudioFormat.MP3) + if (trackDetails.audioFormat != AudioFormat.MP3) throw InvalidDataException("Audio Format is ${trackDetails.audioFormat}, Needs Conversion!") Mp3File(File(songFile.absolutePath)) @@ -166,7 +166,7 @@ class AndroidFileManager( override suspend fun loadImage(url: String, reqWidth: Int, reqHeight: Int): Picture = withContext(dispatcherIO) { - val cachePath = imageCacheDir() + getNameURL(url) + val cachePath = getImageCachePath(url) Picture( image = (loadCachedImage(cachePath, reqWidth, reqHeight) ?: freshImage( url, @@ -214,7 +214,7 @@ class AndroidFileManager( // Decode and Cache Full Sized Image in Background cacheImage( BitmapFactory.decodeByteArray(input, 0, input.size), - imageCacheDir() + getNameURL(url) + getImageCachePath(url) ) } bitmap // return Memory Efficient Bitmap diff --git a/common/core-components/src/commonMain/kotlin/com.shabinder.common.core_components/file_manager/FileManager.kt b/common/core-components/src/commonMain/kotlin/com.shabinder.common.core_components/file_manager/FileManager.kt index 6aedf2eb..d27662e9 100644 --- a/common/core-components/src/commonMain/kotlin/com.shabinder.common.core_components/file_manager/FileManager.kt +++ b/common/core-components/src/commonMain/kotlin/com.shabinder.common.core_components/file_manager/FileManager.kt @@ -25,10 +25,14 @@ import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.event.coroutines.SuspendableEvent import com.shabinder.common.utils.removeIllegalChars +import com.shabinder.common.utils.requireNotNull import com.shabinder.database.Database -import io.ktor.client.request.* -import io.ktor.client.statement.* -import io.ktor.http.* +import io.ktor.client.HttpClient +import io.ktor.client.request.HttpRequestBuilder +import io.ktor.client.request.get +import io.ktor.client.statement.HttpStatement +import io.ktor.http.contentLength +import io.ktor.http.isSuccess import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow @@ -80,12 +84,13 @@ fun FileManager.createDirectories() { if (!defaultDir().contains("null${fileSeparator()}SpotiFlyer")) { createDirectory(defaultDir()) createDirectory(imageCacheDir()) - createDirectory(defaultDir() + "Tracks/") - createDirectory(defaultDir() + "Albums/") - createDirectory(defaultDir() + "Playlists/") - createDirectory(defaultDir() + "YT_Downloads/") + createDirectory(defaultDir() + "Tracks" + fileSeparator()) + createDirectory(defaultDir() + "Albums" + fileSeparator()) + createDirectory(defaultDir() + "Playlists" + fileSeparator()) + createDirectory(defaultDir() + "YT_Downloads" + fileSeparator()) } - } catch (ignored: Exception) { } + } catch (ignored: Exception) { + } } fun FileManager.finalOutputDir( @@ -100,24 +105,50 @@ fun FileManager.finalOutputDir( removeIllegalChars(subFolder) + this.fileSeparator() } + removeIllegalChars(itemName) + extension -/*DIR Specific Operation End*/ -fun getNameURL(url: String): String { - return url.substring(url.lastIndexOf('/', url.lastIndexOf('/') - 1) + 1, url.length) - .replace('/', '_') +fun FileManager.getImageCachePath( + url: String +): String = imageCacheDir() + getNameFromURL(url, isImage = true) + +/*DIR Specific Operation End*/ +private fun getNameFromURL(url: String, isImage: Boolean = false): String { + val startIndex = url.lastIndexOf('/', url.lastIndexOf('/') - 1) + 1 + + var fileName = if (startIndex != -1) + url.substring(startIndex).replace('/', '_') + else url.substringAfterLast("/") + + // Generify File Extensions + if (isImage) { + if (fileName.length - fileName.lastIndexOf(".") > 5) { + fileName += ".jpeg" + } else { + if (fileName.endsWith(".jpg")) + fileName = fileName.substringBeforeLast(".") + ".jpeg" + } + } + + return fileName } -suspend fun downloadFile(url: String): Flow { +suspend fun HttpClient.downloadFile(url: String) = downloadFile(url, this) + +suspend fun downloadFile(url: String, client: HttpClient? = null): Flow { return flow { - val client = createHttpClient() - val response = client.get(url).execute() - val data = ByteArray(response.contentLength()!!.toInt()) + val httpClient = client ?: createHttpClient() + val response = httpClient.get(url).execute() + // Not all requests return Content Length + val data = kotlin.runCatching { + ByteArray(response.contentLength().requireNotNull().toInt()) + }.getOrNull() ?: byteArrayOf() 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() + val progress = data.size.takeIf { it != 0 }?.let { fileSize -> + (offset * 100f / fileSize).roundToInt() + } ?: 0 emit(DownloadResult.Progress(progress)) } while (currentRead > 0) if (response.status.isSuccess()) { @@ -125,7 +156,10 @@ suspend fun downloadFile(url: String): Flow { } else { emit(DownloadResult.Error("File not downloaded")) } - client.close() + + // Close Client if We Created One + if (client == null) + httpClient.close() }.catch { e -> e.printStackTrace() emit(DownloadResult.Error(e.message ?: "File not downloaded")) 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 56efceb7..a355f89e 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 @@ -178,8 +178,7 @@ class DesktopFileManager( override fun addToLibrary(path: String) {} override suspend fun loadImage(url: String, reqWidth: Int, reqHeight: Int): Picture { - val cachePath = imageCacheDir() + getNameURL(url) - var picture: ImageBitmap? = loadCachedImage(cachePath, reqWidth, reqHeight) + var picture: ImageBitmap? = loadCachedImage(getImageCachePath(url), reqWidth, reqHeight) if (picture == null) picture = freshImage(url, reqWidth, reqHeight) return Picture(image = picture) } @@ -208,7 +207,7 @@ class DesktopFileManager( if (result != null) { GlobalScope.launch(Dispatchers.IO) { // TODO Refactor - cacheImage(result, imageCacheDir() + getNameURL(url)) + cacheImage(result, getImageCachePath(url)) } result.toImageBitmap() } else null 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 c4cfae65..6f2e7eb2 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 @@ -20,7 +20,7 @@ data class SaavnSong @OptIn(ExperimentalSerializationApi::class) constructor( // val explicit_content: Int = 0, val has_lyrics: Boolean = false, val id: String, - val image: String, + val image: String = "", val label: String? = null, val label_url: String? = null, val language: String, diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/gaana/GaanaProvider.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/gaana/GaanaProvider.kt index 622524cb..438365ec 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/gaana/GaanaProvider.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/gaana/GaanaProvider.kt @@ -19,6 +19,7 @@ package com.shabinder.common.providers.gaana 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.core_components.file_manager.getImageCachePath import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.SpotiFlyerException @@ -124,8 +125,7 @@ class GaanaProvider( title = it.track_title, artists = it.artist.map { artist -> artist?.name.toString() }, durationSec = it.duration, - albumArtPath = fileManager.imageCacheDir() + (it.artworkLink.substringBeforeLast('/') - .substringAfterLast('/')) + ".jpeg", + albumArtPath = fileManager.getImageCachePath(it.artworkLink), albumName = it.album_title, genre = it.genre?.mapNotNull { genre -> genre?.name } ?: emptyList(), year = it.release_date, 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 4c807462..5568238a 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,6 +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.core_components.file_manager.getImageCachePath import com.shabinder.common.models.* import com.shabinder.common.models.event.coroutines.SuspendableEvent import com.shabinder.common.models.saavn.SaavnSong @@ -68,7 +69,7 @@ class SaavnProvider( artists = it.artistMap.keys.toMutableSet().apply { addAll(it.singers.split(",")) }.toList(), durationSec = it.duration.toInt(), albumName = it.album, - albumArtPath = fileManager.imageCacheDir() + (it.image.substringBeforeLast('/').substringAfterLast('/')) + ".jpeg", + albumArtPath = fileManager.getImageCachePath(it.image), year = it.year, comment = it.copyright_text, trackUrl = it.perma_url, diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/SoundCloudProvider.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/SoundCloudProvider.kt index f78dc085..d74087d5 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/SoundCloudProvider.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/sound_cloud/SoundCloudProvider.kt @@ -3,6 +3,7 @@ package com.shabinder.common.providers.sound_cloud 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.core_components.file_manager.getImageCachePath import com.shabinder.common.models.AudioFormat import com.shabinder.common.models.AudioQuality import com.shabinder.common.models.DownloadStatus @@ -70,9 +71,7 @@ class SoundCloudProvider( artists = /*it.artists?.map { artist -> artist?.name.toString() } ?:*/ listOf(it.user.username.ifBlank { it.genre }), albumArtists = /*it.album?.artists?.mapNotNull { artist -> artist?.name } ?:*/ emptyList(), durationSec = (it.duration / 1000), - albumArtPath = fileManager.imageCacheDir() + (it.artworkUrl.formatArtworkUrl()).substringAfterLast( - '/' - ) + ".jpeg", + albumArtPath = fileManager.getImageCachePath(it.artworkUrl.formatArtworkUrl()), albumName = "", //it.album?.name, year = runCatching { it.displayDate.substring(0, 4) }.getOrNull(), comment = it.caption, diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/spotify/SpotifyProvider.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/spotify/SpotifyProvider.kt index 5f08bafd..1973e890 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/spotify/SpotifyProvider.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/spotify/SpotifyProvider.kt @@ -19,6 +19,7 @@ package com.shabinder.common.providers.spotify 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.core_components.file_manager.getImageCachePath import com.shabinder.common.core_components.utils.createHttpClient import com.shabinder.common.models.* import com.shabinder.common.models.event.coroutines.SuspendableEvent @@ -201,9 +202,7 @@ class SpotifyProvider( artists = it.artists?.map { artist -> artist?.name.toString() } ?: listOf(), albumArtists = it.album?.artists?.mapNotNull { artist -> artist?.name } ?: emptyList(), durationSec = (it.duration_ms / 1000).toInt(), - albumArtPath = fileManager.imageCacheDir() + (it.album?.images?.firstOrNull()?.url.toString()).substringAfterLast( - '/' - ) + ".jpeg", + albumArtPath = fileManager.getImageCachePath(it.album?.images?.firstOrNull()?.url ?: ""), albumName = it.album?.name, year = it.album?.release_date, comment = "Genres:${it.album?.genres?.joinToString()}", diff --git a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube/YoutubeProvider.kt b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube/YoutubeProvider.kt index 4fea8918..7e5714c6 100644 --- a/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube/YoutubeProvider.kt +++ b/common/providers/src/commonMain/kotlin/com.shabinder.common.providers/youtube/YoutubeProvider.kt @@ -19,6 +19,7 @@ package com.shabinder.common.providers.youtube 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.core_components.file_manager.getImageCachePath import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.SpotiFlyerException @@ -30,7 +31,7 @@ import io.github.shabinder.YoutubeDownloader import io.github.shabinder.models.YoutubeVideo import io.github.shabinder.models.formats.Format import io.github.shabinder.models.quality.AudioQuality -import io.ktor.client.* +import io.ktor.client.HttpClient class YoutubeProvider( private val httpClient: HttpClient, @@ -108,13 +109,14 @@ class YoutubeProvider( title = name trackList = videos.map { + val imageURL = "https://i.ytimg.com/vi/${it.videoId}/hqdefault.jpg" TrackDetails( title = it.title ?: "N/A", artists = listOf(it.author ?: "N/A"), durationSec = it.lengthSeconds, - albumArtPath = fileManager.imageCacheDir() + it.videoId + ".jpeg", + albumArtPath = fileManager.getImageCachePath(imageURL), source = Source.YouTube, - albumArtURL = "https://i.ytimg.com/vi/${it.videoId}/hqdefault.jpg", + albumArtURL = imageURL, downloaded = if (fileManager.isPresent( fileManager.finalOutputDir( itemName = it.title ?: "N/A", @@ -155,7 +157,7 @@ class YoutubeProvider( val video = ytDownloader.getVideo(searchId) coverUrl = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg" val detail = video.videoDetails - val name = detail.title?.replace(detail.author?.uppercase() ?: "", "", true) + val name = detail.title?.replace(detail.author?.toUpperCase() ?: "", "", true) ?: detail.title ?: "" // logger.i{ detail.toString() } trackList = listOf( @@ -163,9 +165,9 @@ class YoutubeProvider( title = name, artists = listOf(detail.author ?: "N/A"), durationSec = detail.lengthSeconds, - albumArtPath = fileManager.imageCacheDir() + "$searchId.jpeg", + albumArtPath = fileManager.getImageCachePath(coverUrl), source = Source.YouTube, - albumArtURL = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg", + albumArtURL = coverUrl, downloaded = if (fileManager.isPresent( fileManager.finalOutputDir( itemName = name, @@ -179,7 +181,12 @@ class YoutubeProvider( else { DownloadStatus.NotDownloaded }, - outputFilePath = fileManager.finalOutputDir(name, folderType, subFolder, fileManager.defaultDir()/*,".m4a"*/), + outputFilePath = fileManager.finalOutputDir( + name, + folderType, + subFolder, + fileManager.defaultDir()/*,".m4a"*/ + ), videoID = searchId ) ) 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 7ea1676d..a2c10e54 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 @@ -18,19 +18,33 @@ package com.shabinder.common.providers.youtube_music import co.touchlab.kermit.Kermit import com.shabinder.common.core_components.file_manager.FileManager -import com.shabinder.common.models.* +import com.shabinder.common.models.AudioFormat +import com.shabinder.common.models.AudioQuality +import com.shabinder.common.models.SpotiFlyerException +import com.shabinder.common.models.TrackDetails +import com.shabinder.common.models.YoutubeTrack +import com.shabinder.common.models.corsApi import com.shabinder.common.models.event.coroutines.SuspendableEvent import com.shabinder.common.models.event.coroutines.flatMap -import com.shabinder.common.models.event.coroutines.flatMapError import com.shabinder.common.models.event.coroutines.map import com.shabinder.common.providers.youtube.YoutubeProvider -import com.shabinder.common.providers.youtube.get import com.shabinder.common.providers.youtube_to_mp3.requests.YoutubeMp3 import io.github.shabinder.fuzzywuzzy.diffutils.FuzzySearch -import io.ktor.client.* -import io.ktor.client.request.* -import io.ktor.http.* -import kotlinx.serialization.json.* +import io.ktor.client.HttpClient +import io.ktor.client.request.headers +import io.ktor.client.request.post +import io.ktor.http.ContentType +import io.ktor.http.contentType +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.buildJsonArray +import kotlinx.serialization.json.buildJsonObject +import kotlinx.serialization.json.contentOrNull +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlinx.serialization.json.put +import kotlinx.serialization.json.putJsonObject import kotlin.collections.set import kotlin.math.absoluteValue @@ -50,7 +64,7 @@ class YoutubeMusic constructor( suspend fun findMp3SongDownloadURLYT( trackDetails: TrackDetails, preferredQuality: AudioQuality = fileManager.preferenceManager.audioQuality - ): SuspendableEvent, Throwable> { + ): SuspendableEvent, Throwable> { return getYTIDBestMatch(trackDetails).flatMap { videoID -> // As YT compress Audio hence there is no benefit of quality for more than 192 val optimalQuality = @@ -69,7 +83,7 @@ class YoutubeMusic constructor( } }*/.map { trackDetails.audioFormat = AudioFormat.MP3 - Pair(it,optimalQuality) + Pair(it, optimalQuality) } } } @@ -168,7 +182,7 @@ class YoutubeMusic constructor( ! 4 - Duration (hh:mm:ss) ! ! We blindly gather all the details we get our hands on, then - ! cherry pick the details we need based on their index numbers, + ! cherry-pick the details we need based on their index numbers, ! we do so only if their Type is 'Song' or 'Video */ @@ -180,7 +194,7 @@ class YoutubeMusic constructor( /* Filter Out dummies here itself ! 'musicResponsiveListItemFlexColumnRenderer' should have more that one - ! sub-block, if not its a dummy, why does the YTM response contain dummies? + ! sub-block, if not it is a dummy, why does the YTM response contain dummies? ! I have no clue. We skip these. ! Remember that we appended the linkBlock to result, treating that like the @@ -189,7 +203,7 @@ class YoutubeMusic constructor( */ for (detailArray in result.subList(0, result.size - 1)) { for (detail in detailArray.jsonArray) { - if (detail.jsonObject["musicResponsiveListItemFlexColumnRenderer"]?.jsonObject?.size ?: 0 < 2) continue + if ((detail.jsonObject["musicResponsiveListItemFlexColumnRenderer"]?.jsonObject?.size ?: 0) < 2) continue // if not a dummy, collect All Variables val details = @@ -262,8 +276,8 @@ class YoutubeMusic constructor( // most song results on youtube go by $artist - $songName or artist1/artist2 var hasCommonWord = false - val resultName = result.name?.lowercase()?.replace("-", " ")?.replace("/", " ") ?: "" - val trackNameWords = trackName.lowercase().split(" ") + val resultName = result.name?.toLowerCase()?.replace("-", " ")?.replace("/", " ") ?: "" + val trackNameWords = trackName.toLowerCase().split(" ") for (nameWord in trackNameWords) { if (nameWord.isNotBlank() && FuzzySearch.partialRatio( @@ -287,8 +301,8 @@ class YoutubeMusic constructor( if (result.type == "Song") { for (artist in trackArtists) { if (FuzzySearch.ratio( - artist.lowercase(), - result.artist?.lowercase() ?: "" + artist.toLowerCase(), + result.artist?.toLowerCase() ?: "" ) > 85 ) artistMatchNumber++ @@ -296,8 +310,8 @@ class YoutubeMusic constructor( } else { // i.e. is a Video for (artist in trackArtists) { if (FuzzySearch.partialRatio( - artist.lowercase(), - result.name?.lowercase() ?: "" + artist.toLowerCase(), + result.name?.toLowerCase() ?: "" ) > 85 ) artistMatchNumber++