Added SoundCloud Logo & Fixed JioSaavn Link Parsing

This commit is contained in:
Shabinder Singh 2021-10-11 03:04:43 +05:30
parent 1a7124bb60
commit dd654e36ad
9 changed files with 63 additions and 16 deletions

View File

@ -23,6 +23,7 @@
<package android:name="com.gaana" /> <package android:name="com.gaana" />
<package android:name="com.spotify.music" /> <package android:name="com.spotify.music" />
<package android:name="com.jio.media.jiobeats" /> <package android:name="com.jio.media.jiobeats" />
<package android:name="com.soundcloud.android" />
<package android:name="com.google.android.youtube" /> <package android:name="com.google.android.youtube" />
<package android:name="com.google.android.apps.youtube.music" /> <package android:name="com.google.android.apps.youtube.music" />
</queries> </queries>

View File

@ -81,6 +81,9 @@ actual fun SpotifyLogo() = getCachedPainter(R.drawable.ic_spotify_logo)
@Composable @Composable
actual fun SaavnLogo() = getCachedPainter(R.drawable.ic_jio_saavn_logo) actual fun SaavnLogo() = getCachedPainter(R.drawable.ic_jio_saavn_logo)
@Composable
actual fun SoundCloudLogo() = getCachedPainter(R.drawable.ic_soundcloud)
@Composable @Composable
actual fun GaanaLogo() = getCachedPainter(R.drawable.ic_gaana) actual fun GaanaLogo() = getCachedPainter(R.drawable.ic_gaana)

View File

@ -58,6 +58,9 @@ expect fun SpotifyLogo(): Painter
@Composable @Composable
expect fun SaavnLogo(): Painter expect fun SaavnLogo(): Painter
@Composable
expect fun SoundCloudLogo(): Painter
@Composable @Composable
expect fun YoutubeLogo(): Painter expect fun YoutubeLogo(): Painter

View File

@ -83,12 +83,14 @@ import com.shabinder.common.main.SpotiFlyerMain
import com.shabinder.common.main.SpotiFlyerMain.HomeCategory import com.shabinder.common.main.SpotiFlyerMain.HomeCategory
import com.shabinder.common.models.DownloadRecord import com.shabinder.common.models.DownloadRecord
import com.shabinder.common.models.Actions import com.shabinder.common.models.Actions
import com.shabinder.common.models.spotify.Source
import com.shabinder.common.translations.Strings import com.shabinder.common.translations.Strings
import com.shabinder.common.uikit.GaanaLogo import com.shabinder.common.uikit.GaanaLogo
import com.shabinder.common.uikit.GithubLogo import com.shabinder.common.uikit.GithubLogo
import com.shabinder.common.uikit.ImageLoad import com.shabinder.common.uikit.ImageLoad
import com.shabinder.common.uikit.SaavnLogo import com.shabinder.common.uikit.SaavnLogo
import com.shabinder.common.uikit.ShareImage import com.shabinder.common.uikit.ShareImage
import com.shabinder.common.uikit.SoundCloudLogo
import com.shabinder.common.uikit.SpotifyLogo import com.shabinder.common.uikit.SpotifyLogo
import com.shabinder.common.uikit.VerticalScrollbar import com.shabinder.common.uikit.VerticalScrollbar
import com.shabinder.common.uikit.YoutubeLogo import com.shabinder.common.uikit.YoutubeLogo
@ -319,6 +321,17 @@ fun AboutColumn(
) )
) )
} }
Spacer(modifier = Modifier.padding(top = 8.dp))
Row(horizontalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth()) {
Icon(
SoundCloudLogo(),
"${Strings.open()} Sound Cloud",
tint = Color.Unspecified,
modifier = Modifier.clip(SpotiFlyerShapes.medium).clickable(
onClick = { Actions.instance.openPlatform("com.soundcloud.android", "https://soundcloud.com/") }
)
)
}
} }
} }
Spacer(modifier = Modifier.padding(top = 8.dp)) Spacer(modifier = Modifier.padding(top = 8.dp))

View File

@ -86,6 +86,10 @@ actual fun SpotifyLogo() =
actual fun SaavnLogo() = actual fun SaavnLogo() =
getCachedPainter("drawable/ic_jio_saavn_logo.xml") getCachedPainter("drawable/ic_jio_saavn_logo.xml")
@Composable
actual fun SoundCloudLogo() =
getCachedPainter("drawable/ic_soundcloud.xml")
@Composable @Composable
actual fun YoutubeLogo() = actual fun YoutubeLogo() =
getCachedPainter("drawable/ic_youtube.xml") getCachedPainter("drawable/ic_youtube.xml")

View File

@ -107,9 +107,11 @@ class DesktopFileManager(
override suspend fun cacheImage(image: Any, path: String): Unit = withContext(dispatcherIO) { override suspend fun cacheImage(image: Any, path: String): Unit = withContext(dispatcherIO) {
try { try {
val file = File(path)
if(!file.parentFile.exists()) createDirectories()
(image as? BufferedImage)?.let { (image as? BufferedImage)?.let {
ImageIO.write(it, "jpeg", File(path)) ImageIO.write(it, "jpeg", file)
} }
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} }

View File

@ -0,0 +1,14 @@
<vector android:height="32dp" android:viewportHeight="1386"
android:viewportWidth="2500" android:width="58dp"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:android="http://schemas.android.com/apk/res/android">
<path android:pathData="M0,1137.74c0,31.02 11.25,54.48 33.74,70.38 22.49,15.9 46.53,21.52 72.13,16.87 24.04,-4.65 40.91,-13.19 50.61,-25.59 9.69,-12.41 14.54,-32.96 14.54,-61.66L171.01,800.37c0,-24.04 -8.34,-44.4 -25.01,-61.08 -16.67,-16.68 -37.03,-25.01 -61.07,-25.01 -23.27,0 -43.24,8.34 -59.91,25.01C8.34,755.97 0,776.33 0,800.37zM267.57,1281.99c0,22.5 7.95,39.36 23.85,50.61 15.9,11.25 36.26,16.87 61.08,16.87 25.59,0 46.34,-5.62 62.24,-16.87 15.9,-11.24 23.85,-28.11 23.85,-50.61L438.58,495.58c0,-23.27 -8.34,-43.24 -25.01,-59.91 -16.67,-16.67 -37.03,-25.01 -61.08,-25.01 -23.27,0 -43.24,8.34 -59.91,25.01 -16.68,16.68 -25.01,36.65 -25.01,59.91zM533.97,1319.22c0,22.49 8.14,39.36 24.43,50.61 16.29,11.24 37.23,16.87 62.82,16.87 24.82,0 45.17,-5.62 61.07,-16.87 15.9,-11.25 23.85,-28.11 23.85,-50.61L706.14,601.44c0,-24.04 -8.34,-44.6 -25.01,-61.66 -16.67,-17.06 -36.64,-25.59 -59.91,-25.59 -24.04,0 -44.6,8.53 -61.66,25.59 -17.06,17.06 -25.59,37.62 -25.59,61.66v717.78zM801.54,1322.71c0,42.66 28.69,63.99 86.09,63.99 57.39,0 86.08,-21.33 86.08,-63.99L973.71,159.38c0,-65.15 -19.78,-101.99 -59.33,-110.52 -25.59,-6.2 -50.8,1.16 -75.62,22.1 -24.82,20.94 -37.23,50.41 -37.23,88.41v1163.33zM1073.76,1356.44L1073.76,90.74c0,-40.33 12.02,-64.37 36.06,-72.13C1161.78,6.2 1213.36,0 1264.54,0c118.66,0 229.18,27.92 331.55,83.76 102.37,55.84 185.16,132.04 248.37,228.59 63.21,96.56 99.85,203 109.94,319.34 47.31,-20.17 97.72,-30.25 151.23,-30.25 108.58,0 201.45,38.39 278.62,115.17 77.17,76.78 115.75,169.07 115.75,276.88 0,108.58 -38.59,201.26 -115.75,278.04 -77.17,76.78 -169.65,115.17 -277.45,115.17l-1012.1,-1.16c-6.98,-2.33 -12.22,-6.59 -15.71,-12.8s-5.23,-11.64 -5.23,-16.29z">
<aapt:attr name="android:fillColor">
<gradient android:endX="1252.675" android:endY="1359.0215"
android:startX="1252.675" android:startY="37.73211" android:type="linear">
<item android:color="#FFFF8800" android:offset="0"/>
<item android:color="#FFFF3300" android:offset="1"/>
</gradient>
</aapt:attr>
</path>
</vector>

View File

@ -29,7 +29,7 @@ class SaavnProvider(
).apply { ).apply {
val pageLink = fullLink.substringAfter("saavn.com/").substringBefore("?") val pageLink = fullLink.substringAfter("saavn.com/").substringBefore("?")
when { when {
pageLink.contains("/song/", true) -> { pageLink.contains("song/", true) -> {
getSong(fullLink).value.let { getSong(fullLink).value.let {
folderType = "Tracks" folderType = "Tracks"
subFolder = "" subFolder = ""
@ -38,7 +38,7 @@ class SaavnProvider(
coverUrl = it.image.replace("http:", "https:") coverUrl = it.image.replace("http:", "https:")
} }
} }
pageLink.contains("/album/", true) -> { pageLink.contains("album/", true) -> {
getAlbum(fullLink).value.let { getAlbum(fullLink).value.let {
folderType = "Albums" folderType = "Albums"
subFolder = removeIllegalChars(it.title) subFolder = removeIllegalChars(it.title)
@ -47,7 +47,7 @@ class SaavnProvider(
coverUrl = it.image.replace("http:", "https:") coverUrl = it.image.replace("http:", "https:")
} }
} }
pageLink.contains("/featured/", true) -> { // Playlist pageLink.contains("featured/", true) -> { // Playlist
getPlaylist(fullLink).value.let { getPlaylist(fullLink).value.let {
folderType = "Playlists" folderType = "Playlists"
subFolder = removeIllegalChars(it.listname) subFolder = removeIllegalChars(it.listname)

View File

@ -18,9 +18,16 @@ import io.github.shabinder.utils.getBoolean
import io.github.shabinder.utils.getJsonArray import io.github.shabinder.utils.getJsonArray
import io.github.shabinder.utils.getJsonObject import io.github.shabinder.utils.getJsonObject
import io.github.shabinder.utils.getString import io.github.shabinder.utils.getString
import io.ktor.client.* import io.ktor.client.HttpClient
import io.ktor.client.request.* import io.ktor.client.request.get
import kotlinx.serialization.json.* import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.put
import kotlin.collections.set import kotlin.collections.set
interface JioSaavnRequests { interface JioSaavnRequests {
@ -32,9 +39,9 @@ interface JioSaavnRequests {
trackName: String, trackName: String,
trackArtists: List<String>, trackArtists: List<String>,
preferredQuality: AudioQuality preferredQuality: AudioQuality
): SuspendableEvent<Pair<String,AudioQuality>, Throwable> = searchForSong(trackName).map { songs -> ): SuspendableEvent<Pair<String, AudioQuality>, Throwable> = searchForSong(trackName).map { songs ->
val bestMatch = sortByBestMatch(songs, trackName, trackArtists).keys.firstOrNull() ?: val bestMatch = sortByBestMatch(songs, trackName, trackArtists).keys.firstOrNull()
throw SpotiFlyerException.DownloadLinkFetchFailed("No SAAVN Match Found for $trackName") ?: throw SpotiFlyerException.DownloadLinkFetchFailed("No SAAVN Match Found for $trackName")
var audioQuality: AudioQuality = AudioQuality.KBPS160 var audioQuality: AudioQuality = AudioQuality.KBPS160
val m4aLink: String by getSongFromID(bestMatch).map { song -> val m4aLink: String by getSongFromID(bestMatch).map { song ->
@ -46,7 +53,7 @@ interface JioSaavnRequests {
song.media_url.requireNotNull().replaceAfterLast("_", "${optimalQuality.kbps}.mp4") song.media_url.requireNotNull().replaceAfterLast("_", "${optimalQuality.kbps}.mp4")
} }
Pair(m4aLink,audioQuality) Pair(m4aLink, audioQuality)
} }
suspend fun searchForSong( suspend fun searchForSong(
@ -235,8 +242,8 @@ interface JioSaavnRequests {
for (result in tracks) { for (result in tracks) {
var hasCommonWord = false var hasCommonWord = false
val resultName = result.title.lowercase().replace("/", " ") val resultName = result.title.toLowerCase().replace("/", " ")
val trackNameWords = trackName.lowercase().split(" ") val trackNameWords = trackName.toLowerCase().split(" ")
for (nameWord in trackNameWords) { for (nameWord in trackNameWords) {
if (nameWord.isNotBlank() && FuzzySearch.partialRatio(nameWord, resultName) > 85) hasCommonWord = true if (nameWord.isNotBlank() && FuzzySearch.partialRatio(nameWord, resultName) > 85) hasCommonWord = true
@ -256,11 +263,11 @@ interface JioSaavnRequests {
// String Containing All Artist Names from JioSaavn Search Result // String Containing All Artist Names from JioSaavn Search Result
val artistListString = mutableSetOf<String>().apply { val artistListString = mutableSetOf<String>().apply {
result.more_info?.singers?.split(",")?.let { addAll(it) } result.more_info?.singers?.split(",")?.let { addAll(it) }
result.more_info?.primary_artists?.lowercase()?.split(",")?.let { addAll(it) } result.more_info?.primary_artists?.toLowerCase()?.split(",")?.let { addAll(it) }
}.joinToString(" , ") }.joinToString(" , ")
for (artist in trackArtists) { for (artist in trackArtists) {
if (FuzzySearch.partialRatio(artist.lowercase(), artistListString) > 85) if (FuzzySearch.partialRatio(artist.toLowerCase(), artistListString) > 85)
artistMatchNumber++ artistMatchNumber++
} }