From 870195bdfd9a0d21adb433ce9000e5ce45d84f2b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 14 Aug 2026 17:29:25 +0600 Subject: [PATCH] feat: improve NewPipe video rank matching --- .../newpipe_yt/RealNewPipeAudioAPI.kt | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/zipline/plugin_apis/newpipe_yt/RealNewPipeAudioAPI.kt b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/zipline/plugin_apis/newpipe_yt/RealNewPipeAudioAPI.kt index 4d2fbe17..adc839cd 100644 --- a/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/zipline/plugin_apis/newpipe_yt/RealNewPipeAudioAPI.kt +++ b/composeApp/src/commonMain/kotlin/dev/krtirtho/spotube/core/zipline/plugin_apis/newpipe_yt/RealNewPipeAudioAPI.kt @@ -40,12 +40,21 @@ class RealNewPipeAudioAPI : AudioAPI, KoinComponent { private fun transformVideo(track: MetadataTrack, video: VideoSearchResult): AudioSource.Basic { var confidence = 0f - if (track.title.lowercase() in video.title.lowercase()) confidence += 0.3f - if (track.artists.any { it.name.lowercase() in video.title.lowercase() }) confidence += 0.3f - if ((track.album != null && track.album!!.title.lowercase() in video.title.lowercase()) || video.uploader.lowercase() in (track.artists.firstOrNull()?.name?.lowercase() - ?: "") - ) confidence += 0.2f - if (video.durationMs in (track.durationMs - 30_000)..(track.durationMs + 30_000)) confidence += 0.2f // Duration within ±30 seconds + + val isTitleMatch = track.title.lowercase() in video.title.lowercase() + val isArtistInTitle = track.artists.any { it.name.lowercase() in video.title.lowercase() } + val isAlbumInTitle = + track.album != null && track.album!!.title.lowercase() in video.title.lowercase() + val isUploaderMatch = + video.uploader.lowercase() in (track.artists.firstOrNull()?.name?.lowercase() ?: "") + val isDurationMatch = + video.durationMs in (track.durationMs - 30_000)..(track.durationMs + 30_000) // Duration within ±30 seconds + + if (isTitleMatch) confidence += 0.3f + if (isUploaderMatch) confidence += 0.3f + if (isDurationMatch) confidence += 0.2f // Duration within ±30 seconds + if (isArtistInTitle) confidence += 0.1f + if (isAlbumInTitle) confidence += 0.1f return AudioSource.Basic( id = video.id, @@ -66,19 +75,14 @@ class RealNewPipeAudioAPI : AudioAPI, KoinComponent { override val supportedQualities: List = listOf( AudioFormat( - codec = "opus", - container = "webm", - qualities = listOf( + codec = "opus", container = "webm", qualities = listOf( AudioQuality.Lossy(bitrate = 44_000), AudioQuality.Lossy(bitrate = 96_000), AudioQuality.Lossy(bitrate = 128_000), AudioQuality.Lossy(bitrate = 256_000), ) - ), - AudioFormat( - codec = "aac", - container = "mp4", - qualities = listOf( + ), AudioFormat( + codec = "aac", container = "mp4", qualities = listOf( AudioQuality.Lossy(bitrate = 44_000), AudioQuality.Lossy(bitrate = 96_000), AudioQuality.Lossy(bitrate = 128_000), @@ -89,9 +93,9 @@ class RealNewPipeAudioAPI : AudioAPI, KoinComponent { override suspend fun getStreamsByTrack(track: MetadataTrack): List { val isYouTubeUrl = - track.externalUri != null && - (track.externalUri!!.contains("youtube.com") || - track.externalUri!!.contains("youtu.be")) + track.externalUri != null && (track.externalUri!!.contains("youtube.com") || track.externalUri!!.contains( + "youtu.be" + )) val isYouTubeID = track.id.matches(youtubeIDRegex) @@ -129,19 +133,17 @@ class RealNewPipeAudioAPI : AudioAPI, KoinComponent { logger.i { "No YouTube ID or URL found, performing search with track metadata" } val isrcCode = track.isrcCode ?: isrcProvider.auto(track) - val searchQuery ="${track.title} - ${track.artists.joinToString(", ") { it.name }}".trim() + val searchQuery = "${track.title} - ${track.artists.joinToString(", ") { it.name }}".trim() logger.i { "Searching for video with query: $searchQuery" } - val videos = - newPipeService.searchVideos(isrcCode ?: searchQuery) + val videos = newPipeService.searchVideos(isrcCode ?: searchQuery) logger.i { "Found ${videos.size} videos with query: $searchQuery" } var sources = videos.map { transformVideo(track, it) } if (isrcCode != null && ((sources.size < 2 && sources.any { it.confidence < 0.3f }) || sources.isEmpty())) { logger.i { "ISRC search failed, fallback to title search" } - val videos = - newPipeService.searchVideos(searchQuery) + val videos = newPipeService.searchVideos(searchQuery) sources = videos.map { transformVideo(track, it) } }