mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-25 10:24:31 +01:00
Added SoundCloud Logo & Fixed JioSaavn Link Parsing
This commit is contained in:
parent
1a7124bb60
commit
dd654e36ad
@ -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>
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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")
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
14
common/data-models/src/main/res/drawable/ic_soundcloud.xml
Normal file
14
common/data-models/src/main/res/drawable/ic_soundcloud.xml
Normal 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>
|
@ -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)
|
||||||
|
@ -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++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user