Desktop Analytics, CORS Fixes , Deps Update

This commit is contained in:
Shabinder Singh 2021-05-31 20:32:10 +05:30
parent cab7213c0e
commit 477536981f
12 changed files with 104 additions and 29 deletions

View File

@ -79,8 +79,7 @@ class MainActivity : ComponentActivity() {
private val fetcher: FetchPlatformQueryResult by inject() private val fetcher: FetchPlatformQueryResult by inject()
private val dir: Dir by inject() private val dir: Dir by inject()
private lateinit var root: SpotiFlyerRoot private lateinit var root: SpotiFlyerRoot
private val callBacks: SpotiFlyerRootCallBacks private val callBacks: SpotiFlyerRootCallBacks get() = root.callBacks
get() = root.callBacks
private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1) private val trackStatusFlow = MutableSharedFlow<HashMap<String, DownloadStatus>>(1)
private var permissionGranted = mutableStateOf(true) private var permissionGranted = mutableStateOf(true)
private lateinit var updateUIReceiver: BroadcastReceiver private lateinit var updateUIReceiver: BroadcastReceiver

View File

@ -35,7 +35,7 @@ object Versions {
const val kermit = "0.1.9" const val kermit = "0.1.9"
// Internet // Internet
const val ktor = "1.5.4" const val ktor = "1.6.0"
const val kotlinxSerialization = "1.2.1" const val kotlinxSerialization = "1.2.1"
@ -135,7 +135,7 @@ object Ktor {
} }
object Extras { object Extras {
const val youtubeDownloader = "io.github.shabinder:youtube-api-dl:1.0" const val youtubeDownloader = "io.github.shabinder:youtube-api-dl:1.2"
const val fuzzyWuzzy = "io.github.shabinder:fuzzywuzzy:1.1" const val fuzzyWuzzy = "io.github.shabinder:fuzzywuzzy:1.1"
const val mp3agic = "com.mpatric:mp3agic:0.9.0" const val mp3agic = "com.mpatric:mp3agic:0.9.0"
const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0" const val jaudioTagger = "com.github.Shabinder:JAudioTagger-Android:1.0"

View File

@ -31,8 +31,8 @@ kotlin {
implementation(project(":common:data-models")) implementation(project(":common:data-models"))
implementation(project(":common:database")) implementation(project(":common:database"))
implementation("org.jetbrains.kotlinx:atomicfu:0.16.1") implementation("org.jetbrains.kotlinx:atomicfu:0.16.1")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.2.1")
implementation("com.russhwolf:multiplatform-settings-no-arg:0.7.6") implementation("com.russhwolf:multiplatform-settings-no-arg:0.7.7")
implementation(Extras.youtubeDownloader) implementation(Extras.youtubeDownloader)
implementation(Extras.fuzzyWuzzy) implementation(Extras.fuzzyWuzzy)
implementation(MVIKotlin.rx) implementation(MVIKotlin.rx)

View File

@ -78,7 +78,11 @@ fun createHttpClient(enableNetworkLogs: Boolean = false) = HttpClient {
install(JsonFeature) { install(JsonFeature) {
serializer = KotlinxSerializer(globalJson) serializer = KotlinxSerializer(globalJson)
} }
install(HttpTimeout) install(HttpTimeout) {
socketTimeoutMillis = 520_000
requestTimeoutMillis = 360_000
connectTimeoutMillis = 360_000
}
// WorkAround for Freezing // WorkAround for Freezing
// Use httpClient.getData / httpClient.postData Extensions // Use httpClient.getData / httpClient.postData Extensions
/*install(JsonFeature) { /*install(JsonFeature) {

View File

@ -76,12 +76,14 @@ fun Dir.firstLaunchDone() {
* Call this function at startup! * Call this function at startup!
* */ * */
fun Dir.createDirectories() { fun Dir.createDirectories() {
createDirectory(defaultDir()) try {
createDirectory(imageCacheDir()) createDirectory(defaultDir())
createDirectory(defaultDir() + "Tracks/") createDirectory(imageCacheDir())
createDirectory(defaultDir() + "Albums/") createDirectory(defaultDir() + "Tracks/")
createDirectory(defaultDir() + "Playlists/") createDirectory(defaultDir() + "Albums/")
createDirectory(defaultDir() + "YT_Downloads/") createDirectory(defaultDir() + "Playlists/")
createDirectory(defaultDir() + "YT_Downloads/")
} catch (e:Exception){}
} }
fun Dir.finalOutputDir(itemName: String, type: String, subFolder: String, defaultDir: String, extension: String = ".mp3"): String = fun Dir.finalOutputDir(itemName: String, type: String, subFolder: String, defaultDir: String, extension: String = ".mp3"): String =

View File

@ -18,10 +18,8 @@ package com.shabinder.common.di.providers
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.di.Dir import com.shabinder.common.di.Dir
import com.shabinder.common.di.currentPlatform
import com.shabinder.common.di.finalOutputDir import com.shabinder.common.di.finalOutputDir
import com.shabinder.common.di.utils.removeIllegalChars import com.shabinder.common.di.utils.removeIllegalChars
import com.shabinder.common.models.AllPlatforms
import com.shabinder.common.models.DownloadStatus import com.shabinder.common.models.DownloadStatus
import com.shabinder.common.models.PlatformQueryResult import com.shabinder.common.models.PlatformQueryResult
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
@ -37,8 +35,10 @@ class YoutubeProvider(
private val logger: Kermit, private val logger: Kermit,
private val dir: Dir, private val dir: Dir,
) { ) {
// Youtube Downloader isn't fully compatible with JS Yet val ytDownloader: YoutubeDownloader = YoutubeDownloader(
val ytDownloader: YoutubeDownloader? = if (currentPlatform == AllPlatforms.Js) null else YoutubeDownloader() enableCORSProxy = true,
CORSProxyAddress = "https://kind-grasshopper-73.telebit.io/cors/"
)
/* /*
* YT Album Art Schema * YT Album Art Schema
@ -95,7 +95,7 @@ class YoutubeProvider(
) )
result.apply { result.apply {
try { try {
val playlist = ytDownloader?.getPlaylist(searchId) ?: return null val playlist = ytDownloader.getPlaylist(searchId)
val playlistDetails = playlist.details val playlistDetails = playlist.details
val name = playlistDetails.title val name = playlistDetails.title
subFolder = removeIllegalChars(name) subFolder = removeIllegalChars(name)
@ -154,7 +154,7 @@ class YoutubeProvider(
).apply { ).apply {
try { try {
logger.i { searchId } logger.i { searchId }
val video = ytDownloader?.getVideo(searchId) ?: return null val video = ytDownloader.getVideo(searchId)
coverUrl = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg" coverUrl = "https://i.ytimg.com/vi/$searchId/hqdefault.jpg"
val detail = video.videoDetails val detail = video.videoDetails
val name = detail.title?.replace(detail.author?.toUpperCase() ?: "", "", true) val name = detail.title?.replace(detail.author?.toUpperCase() ?: "", "", true)

View File

@ -2,6 +2,7 @@ package com.shabinder.common.di.saavn
import co.touchlab.kermit.Kermit import co.touchlab.kermit.Kermit
import com.shabinder.common.di.audioToMp3.AudioToMp3 import com.shabinder.common.di.audioToMp3.AudioToMp3
import com.shabinder.common.di.gaana.corsApi
import com.shabinder.common.di.globalJson import com.shabinder.common.di.globalJson
import com.shabinder.common.models.saavn.SaavnAlbum import com.shabinder.common.models.saavn.SaavnAlbum
import com.shabinder.common.models.saavn.SaavnPlaylist import com.shabinder.common.models.saavn.SaavnPlaylist
@ -282,10 +283,10 @@ interface JioSaavnRequests {
companion object { companion object {
// EndPoints // EndPoints
const val search_base_url = "https://www.jiosaavn.com/api.php?__call=autocomplete.get&_format=json&_marker=0&cc=in&includeMetaTags=1&query=" val search_base_url = "${corsApi}https://www.jiosaavn.com/api.php?__call=autocomplete.get&_format=json&_marker=0&cc=in&includeMetaTags=1&query="
const val song_details_base_url = "https://www.jiosaavn.com/api.php?__call=song.getDetails&cc=in&_marker=0%3F_marker%3D0&_format=json&pids=" val song_details_base_url = "${corsApi}https://www.jiosaavn.com/api.php?__call=song.getDetails&cc=in&_marker=0%3F_marker%3D0&_format=json&pids="
const val album_details_base_url = "https://www.jiosaavn.com/api.php?__call=content.getAlbumDetails&_format=json&cc=in&_marker=0%3F_marker%3D0&albumid=" val album_details_base_url = "${corsApi}https://www.jiosaavn.com/api.php?__call=content.getAlbumDetails&_format=json&cc=in&_marker=0%3F_marker%3D0&albumid="
const val playlist_details_base_url = "https://www.jiosaavn.com/api.php?__call=playlist.getDetails&_format=json&cc=in&_marker=0%3F_marker%3D0&listid=" val playlist_details_base_url = "${corsApi}https://www.jiosaavn.com/api.php?__call=playlist.getDetails&_format=json&cc=in&_marker=0%3F_marker%3D0&listid="
const val lyrics_base_url = "https://www.jiosaavn.com/api.php?__call=lyrics.getLyrics&ctx=web6dot0&api_version=4&_format=json&_marker=0%3F_marker%3D0&lyrics_id=" val lyrics_base_url = "${corsApi}https://www.jiosaavn.com/api.php?__call=lyrics.getLyrics&ctx=web6dot0&api_version=4&_format=json&_marker=0%3F_marker%3D0&lyrics_id="
} }
} }

View File

@ -53,7 +53,7 @@ actual class Dir actual constructor(
actual fun imageCacheDir(): String = System.getProperty("user.home") + actual fun imageCacheDir(): String = System.getProperty("user.home") +
fileSeparator() + "SpotiFlyer/.images" + fileSeparator() fileSeparator() + "SpotiFlyer/.images" + fileSeparator()
private val defaultBaseDir = System.getProperty("user.home")!! private val defaultBaseDir = System.getProperty("user.home")
actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) + fileSeparator() + actual fun defaultDir(): String = (settings.getStringOrNull(DirKey) ?: defaultBaseDir) + fileSeparator() +
"SpotiFlyer" + fileSeparator() "SpotiFlyer" + fileSeparator()

View File

@ -52,6 +52,9 @@ kotlin {
// Koin // Koin
implementation(Koin.core) implementation(Koin.core)
// Matomo
implementation("org.piwik.java.tracking:matomo-java-tracker:1.6")
} }
} }
val jvmTest by getting val jvmTest by getting

View File

@ -31,8 +31,10 @@ import com.shabinder.common.di.Dir
import com.shabinder.common.di.DownloadProgressFlow import com.shabinder.common.di.DownloadProgressFlow
import com.shabinder.common.di.FetchPlatformQueryResult import com.shabinder.common.di.FetchPlatformQueryResult
import com.shabinder.common.di.initKoin import com.shabinder.common.di.initKoin
import com.shabinder.common.di.isFirstLaunch
import com.shabinder.common.di.isInternetAccessible import com.shabinder.common.di.isInternetAccessible
import com.shabinder.common.di.setDownloadDirectory import com.shabinder.common.di.setDownloadDirectory
import com.shabinder.common.di.toggleAnalytics
import com.shabinder.common.models.Actions import com.shabinder.common.models.Actions
import com.shabinder.common.models.PlatformActions import com.shabinder.common.models.PlatformActions
import com.shabinder.common.models.TrackDetails import com.shabinder.common.models.TrackDetails
@ -44,6 +46,9 @@ import com.shabinder.common.uikit.SpotiFlyerTypography
import com.shabinder.common.uikit.colorOffWhite import com.shabinder.common.uikit.colorOffWhite
import com.shabinder.database.Database import com.shabinder.database.Database
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.piwik.java.tracking.PiwikTracker
import utils.trackAsync
import utils.trackScreenAsync
import java.awt.Desktop import java.awt.Desktop
import java.net.URI import java.net.URI
import javax.swing.JFileChooser import javax.swing.JFileChooser
@ -51,12 +56,15 @@ import javax.swing.JFileChooser.APPROVE_OPTION
private val koin = initKoin(enableNetworkLogs = true).koin private val koin = initKoin(enableNetworkLogs = true).koin
private lateinit var showToast: (String)->Unit private lateinit var showToast: (String)->Unit
private lateinit var tracker: PiwikTracker
fun main() { fun main() {
val lifecycle = LifecycleRegistry() val lifecycle = LifecycleRegistry()
lifecycle.resume() lifecycle.resume()
tracker = PiwikTracker("https://kind-grasshopper-73.telebit.io/matomo/matomo.php")
Window("SpotiFlyer",size = IntSize(450,800)) { Window("SpotiFlyer",size = IntSize(450,800)) {
Surface( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
@ -73,6 +81,8 @@ fun main() {
} }
} }
} }
// Download Tracking for Desktop Apps for Now will be measured using `Github Releases`
// https://tooomm.github.io/github-release-stats/?username=Shabinder&repository=SpotiFlyer
} }
private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot = private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
@ -137,13 +147,38 @@ private fun spotiFlyerRoot(componentContext: ComponentContext): SpotiFlyerRoot =
} }
} }
override val analytics = object: SpotiFlyerRoot.Analytics { override val analytics = object: SpotiFlyerRoot.Analytics {
override fun appLaunchEvent() {} override fun appLaunchEvent() {
// Enable Analytics
directories.toggleAnalytics(true)
tracker.trackAsync {
eventName = "App Launch"
eventAction = "App_Launch"
}
}
override fun homeScreenVisit() {} override fun homeScreenVisit() {
tracker.trackScreenAsync(
screenAddress = "/main_activity/home_screen"
) {
actionName = "HomeScreen"
}
}
override fun listScreenVisit() {} override fun listScreenVisit() {
tracker.trackScreenAsync(
screenAddress = "/main_activity/list_screen"
) {
actionName = "ListScreen"
}
}
override fun donationDialogVisit() {} override fun donationDialogVisit() {
tracker.trackScreenAsync(
screenAddress = "/main_activity/donation_dialog"
) {
actionName = "DonationDialog"
}
}
} }
} }
) )

View File

@ -0,0 +1,30 @@
package utils
import org.piwik.java.tracking.PiwikRequest
import org.piwik.java.tracking.PiwikTracker
import java.net.URL
fun PiwikTracker.trackAsync(
baseURL:String = "https://com.shabinder.spotiflyer/",
requestBuilder: PiwikRequest.() -> Unit = {}
) {
val req = PiwikRequest(
1,
URL(baseURL)
).apply { requestBuilder() }
// Send Request
sendRequestAsync(req)
}
fun PiwikTracker.trackScreenAsync(
screenAddress:String,
requestBuilder: PiwikRequest.() -> Unit = {}
) {
val req = PiwikRequest(
1,
URL("https://com.shabinder.spotiflyer/" + screenAddress.removeSurrounding("/"))
).apply { requestBuilder() }
// Send Request
sendRequestAsync(req)
}

View File

@ -49,6 +49,7 @@ dependencies {
implementation(project(":common:dependency-injection")) implementation(project(":common:dependency-injection"))
implementation("co.touchlab:stately-common:1.1.7") implementation("co.touchlab:stately-common:1.1.7")
implementation("dev.icerock.moko:parcelize:0.6.1") implementation("dev.icerock.moko:parcelize:0.6.1")
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") {
// https://youtrack.jetbrains.com/issue/KTOR-2670 // https://youtrack.jetbrains.com/issue/KTOR-2670
isForce = true isForce = true