mirror of
https://github.com/Shabinder/SpotiFlyer.git
synced 2024-11-22 17:14:32 +01:00
Image caching
This commit is contained in:
parent
3ae3b404b1
commit
e63a5d97fd
@ -9,12 +9,30 @@ import androidx.compose.runtime.MutableState
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.res.vectorResource
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
|
import com.shabinder.common.Picture
|
||||||
import com.shabinder.common.database.appContext
|
import com.shabinder.common.database.appContext
|
||||||
import dev.chrisbanes.accompanist.coil.CoilImage
|
import dev.chrisbanes.accompanist.coil.CoilImage
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
actual fun ImageLoad(
|
||||||
|
pic: Picture?,
|
||||||
|
modifier: Modifier
|
||||||
|
){
|
||||||
|
Image(pic?.image?.asImageBitmap(), vectorResource(R.drawable.music) ,"Image",modifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Image(pic: ImageBitmap?, placeholder:ImageVector, desc: String,modifier:Modifier = Modifier) {
|
||||||
|
if(pic == null) Image(placeholder,desc,modifier) else Image(pic,desc,modifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Composable
|
@Composable
|
||||||
actual fun ImageLoad(
|
actual fun ImageLoad(
|
||||||
url:String,
|
url:String,
|
||||||
@ -31,6 +49,7 @@ actual fun ImageLoad(
|
|||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun Toast(
|
actual fun Toast(
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package com.shabinder.common.list
|
package com.shabinder.common.list
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||||
import com.shabinder.common.FetchPlatformQueryResult
|
import com.shabinder.common.*
|
||||||
import com.shabinder.common.PlatformQueryResult
|
|
||||||
import com.shabinder.common.TrackDetails
|
|
||||||
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
import com.shabinder.common.list.integration.SpotiFlyerListImpl
|
||||||
import com.shabinder.common.utils.Consumer
|
import com.shabinder.common.utils.Consumer
|
||||||
import com.shabinder.database.Database
|
import com.shabinder.database.Database
|
||||||
@ -28,9 +27,15 @@ interface SpotiFlyerList {
|
|||||||
* */
|
* */
|
||||||
fun onBackPressed()
|
fun onBackPressed()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load Image from cache/Internet and cache it
|
||||||
|
* */
|
||||||
|
fun loadImage(url:String):Picture?
|
||||||
|
|
||||||
interface Dependencies {
|
interface Dependencies {
|
||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val fetchQuery: FetchPlatformQueryResult
|
val fetchQuery: FetchPlatformQueryResult
|
||||||
|
val dir: Dir
|
||||||
val link: String
|
val link: String
|
||||||
fun listOutput(finished: Output.Finished): Consumer<Output>
|
fun listOutput(finished: Output.Finished): Consumer<Output>
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.shabinder.common.list
|
package com.shabinder.common.list
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.CircularProgressIndicator
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
@ -18,6 +19,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.shabinder.common.DownloadStatus
|
import com.shabinder.common.DownloadStatus
|
||||||
|
import com.shabinder.common.Picture
|
||||||
import com.shabinder.common.TrackDetails
|
import com.shabinder.common.TrackDetails
|
||||||
import com.shabinder.common.ui.ImageLoad
|
import com.shabinder.common.ui.ImageLoad
|
||||||
import com.shabinder.spotiflyer.ui.SpotiFlyerTypography
|
import com.shabinder.spotiflyer.ui.SpotiFlyerTypography
|
||||||
@ -40,12 +42,13 @@ fun SpotiFlyerListContent(
|
|||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
content = {
|
content = {
|
||||||
item {
|
item {
|
||||||
CoverImage(result.title, result.coverUrl, coroutineScope)
|
CoverImage(result.title, result.coverUrl, coroutineScope,component::loadImage)
|
||||||
}
|
}
|
||||||
itemsIndexed(result.trackList) { index, item ->
|
itemsIndexed(result.trackList) { index, item ->
|
||||||
TrackCard(
|
TrackCard(
|
||||||
track = item,
|
track = item,
|
||||||
downloadTrack = { component.onDownloadClicked(result.trackList,index) },
|
downloadTrack = { component.onDownloadClicked(result.trackList,index) },
|
||||||
|
loadImage = component::loadImage
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -62,10 +65,12 @@ fun SpotiFlyerListContent(
|
|||||||
fun TrackCard(
|
fun TrackCard(
|
||||||
track: TrackDetails,
|
track: TrackDetails,
|
||||||
downloadTrack:()->Unit,
|
downloadTrack:()->Unit,
|
||||||
|
loadImage:(String)->Picture?
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
Row(verticalAlignment = Alignment.CenterVertically,modifier = Modifier.fillMaxWidth().padding(horizontal = 8.dp)) {
|
||||||
|
val pic:Picture? = loadImage(track.albumArtURL)
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
url = track.albumArtURL,
|
pic = pic,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.preferredWidth(75.dp)
|
.preferredWidth(75.dp)
|
||||||
.preferredHeight(90.dp)
|
.preferredHeight(90.dp)
|
||||||
@ -112,14 +117,16 @@ fun CoverImage(
|
|||||||
title: String,
|
title: String,
|
||||||
coverURL: String,
|
coverURL: String,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
|
loadImage: (String) -> Picture?,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
modifier.padding(vertical = 8.dp).fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
|
val pic = loadImage(coverURL)
|
||||||
ImageLoad(
|
ImageLoad(
|
||||||
url = coverURL,
|
pic,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.preferredWidth(210.dp)
|
.preferredWidth(210.dp)
|
||||||
.preferredHeight(230.dp)
|
.preferredHeight(230.dp)
|
||||||
|
@ -2,6 +2,7 @@ package com.shabinder.common.list.integration
|
|||||||
|
|
||||||
import com.arkivanov.decompose.ComponentContext
|
import com.arkivanov.decompose.ComponentContext
|
||||||
import com.arkivanov.mvikotlin.extensions.coroutines.states
|
import com.arkivanov.mvikotlin.extensions.coroutines.states
|
||||||
|
import com.shabinder.common.Picture
|
||||||
import com.shabinder.common.TrackDetails
|
import com.shabinder.common.TrackDetails
|
||||||
import com.shabinder.common.list.SpotiFlyerList
|
import com.shabinder.common.list.SpotiFlyerList
|
||||||
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
import com.shabinder.common.list.SpotiFlyerList.Dependencies
|
||||||
@ -38,4 +39,6 @@ internal class SpotiFlyerListImpl(
|
|||||||
override fun onBackPressed(){
|
override fun onBackPressed(){
|
||||||
listOutput(SpotiFlyerList.Output.Finished)
|
listOutput(SpotiFlyerList.Output.Finished)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun loadImage(url: String): Picture? = dir.loadImage(url)
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ import com.arkivanov.decompose.ComponentContext
|
|||||||
import com.arkivanov.decompose.RouterState
|
import com.arkivanov.decompose.RouterState
|
||||||
import com.arkivanov.decompose.value.Value
|
import com.arkivanov.decompose.value.Value
|
||||||
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
import com.arkivanov.mvikotlin.core.store.StoreFactory
|
||||||
|
import com.shabinder.common.Dir
|
||||||
import com.shabinder.common.FetchPlatformQueryResult
|
import com.shabinder.common.FetchPlatformQueryResult
|
||||||
import com.shabinder.common.list.SpotiFlyerList
|
import com.shabinder.common.list.SpotiFlyerList
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
import com.shabinder.common.main.SpotiFlyerMain
|
||||||
@ -24,6 +25,7 @@ interface SpotiFlyerRoot {
|
|||||||
val storeFactory: StoreFactory
|
val storeFactory: StoreFactory
|
||||||
val database: Database
|
val database: Database
|
||||||
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
val fetchPlatformQueryResult: FetchPlatformQueryResult
|
||||||
|
val directories: Dir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import com.arkivanov.decompose.router
|
|||||||
import com.arkivanov.decompose.statekeeper.Parcelable
|
import com.arkivanov.decompose.statekeeper.Parcelable
|
||||||
import com.arkivanov.decompose.statekeeper.Parcelize
|
import com.arkivanov.decompose.statekeeper.Parcelize
|
||||||
import com.arkivanov.decompose.value.Value
|
import com.arkivanov.decompose.value.Value
|
||||||
|
import com.shabinder.common.Dir
|
||||||
import com.shabinder.common.list.SpotiFlyerList
|
import com.shabinder.common.list.SpotiFlyerList
|
||||||
import com.shabinder.common.main.SpotiFlyerMain
|
import com.shabinder.common.main.SpotiFlyerMain
|
||||||
import com.shabinder.common.root.SpotiFlyerRoot
|
import com.shabinder.common.root.SpotiFlyerRoot
|
||||||
@ -48,6 +49,7 @@ internal class SpotiFlyerRootImpl(
|
|||||||
componentContext = componentContext,
|
componentContext = componentContext,
|
||||||
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by this {
|
dependencies = object : SpotiFlyerList.Dependencies, Dependencies by this {
|
||||||
override val fetchQuery = fetchPlatformQueryResult
|
override val fetchQuery = fetchPlatformQueryResult
|
||||||
|
override val dir: Dir = directories
|
||||||
override val link: String = link
|
override val link: String = link
|
||||||
|
|
||||||
override fun listOutput(finished: SpotiFlyerList.Output.Finished): Consumer<SpotiFlyerList.Output> =
|
override fun listOutput(finished: SpotiFlyerList.Output.Finished): Consumer<SpotiFlyerList.Output> =
|
||||||
|
@ -3,13 +3,13 @@ package com.shabinder.common.ui
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import com.shabinder.common.Picture
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
expect fun ImageLoad(
|
expect fun ImageLoad(
|
||||||
url:String,
|
pic: Picture?,
|
||||||
loadingResource: ImageBitmap? = null,
|
|
||||||
errorResource: ImageBitmap? = null,
|
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -2,14 +2,11 @@ package com.shabinder.common.ui
|
|||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import com.shabinder.common.Picture
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
actual fun ImageLoad(
|
actual fun ImageLoad(
|
||||||
url:String,
|
pic: Picture?,
|
||||||
loadingResource: ImageBitmap?,
|
|
||||||
errorResource: ImageBitmap?,
|
|
||||||
modifier: Modifier
|
modifier: Modifier
|
||||||
){
|
){
|
||||||
|
|
||||||
|
21
common/compose-ui/src/main/res/drawable/music.xml
Normal file
21
common/compose-ui/src/main/res/drawable/music.xml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) 2021 Shabinder Singh
|
||||||
|
~ This program is free software: you can redistribute it and/or modify
|
||||||
|
~ it under the terms of the GNU General Public License as published by
|
||||||
|
~ the Free Software Foundation, either version 3 of the License, or
|
||||||
|
~ (at your option) any later version.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
~ GNU General Public License for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU General Public License
|
||||||
|
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="42dp"
|
||||||
|
android:height="42dp" android:viewportWidth="512" android:viewportHeight="512">
|
||||||
|
<path android:fillColor="#A3787878" android:pathData="m511.739,103.734 l-257,50.947v233.725c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c34.684,0 63.329,-26.299 67.073,-60h0.427v-182.682l197,-39.053v98.141c-10.733,-7.199 -23.633,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c39.927,0 71.547,-34.762 67.073,-75h0.427zM217.239,482c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM444.239,422c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.822,37.5 -37.5,37.5zM481.739,199.682 L284.739,238.735v-59.416l197,-39.053z"/>
|
||||||
|
<path android:fillColor="#A3787878" android:pathData="m182.179,159.75h30c0,-31.002 4.415,-66.799 -24.144,-95.356 -8.968,-8.968 -17.455,-16.07 -24.942,-22.336 -19.798,-16.57 -27.832,-24.012 -27.832,-42.058h-30v221.406c-10.734,-7.199 -23.634,-11.406 -37.5,-11.406 -37.22,0 -67.5,30.28 -67.5,67.5s30.28,67.5 67.5,67.5c34.684,0 63.329,-26.299 67.073,-60h0.427v-227.219c9.458,8.262 20.077,16.341 31.562,27.825 19.029,19.031 15.356,44.009 15.356,74.144zM67.761,315c-20.678,0 -37.5,-16.822 -37.5,-37.5s16.822,-37.5 37.5,-37.5 37.5,16.822 37.5,37.5 -16.823,37.5 -37.5,37.5z"/>
|
||||||
|
</vector>
|
@ -2,11 +2,15 @@ package com.shabinder.common
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.mpatric.mp3agic.Mp3File
|
import com.mpatric.mp3agic.Mp3File
|
||||||
import com.shabinder.common.database.appContext
|
import com.shabinder.common.database.appContext
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
actual open class Dir actual constructor(
|
actual open class Dir actual constructor(
|
||||||
@ -87,4 +91,69 @@ actual open class Dir actual constructor(
|
|||||||
.setId3v1Tags(trackDetails)
|
.setId3v1Tags(trackDetails)
|
||||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual fun loadImage(url: String, cachePath: String):Picture? {
|
||||||
|
var picture: Picture? = loadCachedImage(cachePath)
|
||||||
|
if (picture == null) picture = freshImage(url,cachePath)
|
||||||
|
return picture
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadCachedImage(cachePath: String): Picture? {
|
||||||
|
return try {
|
||||||
|
val read = BufferedReader(
|
||||||
|
InputStreamReader(
|
||||||
|
FileInputStream(cachePath + cacheImagePostfix()),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val source = read.readLine()
|
||||||
|
val width = read.readLine().toInt()
|
||||||
|
val height = read.readLine().toInt()
|
||||||
|
|
||||||
|
read.close()
|
||||||
|
|
||||||
|
val result: Bitmap? = BitmapFactory.decodeFile(cachePath)
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
Picture(
|
||||||
|
source,
|
||||||
|
getNameURL(source),
|
||||||
|
result,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
}else null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun freshImage(url:String,cachePath: String):Picture?{
|
||||||
|
return try {
|
||||||
|
val source = URL(url)
|
||||||
|
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
||||||
|
connection.connectTimeout = 5000
|
||||||
|
connection.connect()
|
||||||
|
|
||||||
|
val input: InputStream = connection.inputStream
|
||||||
|
val result: Bitmap? = BitmapFactory.decodeStream(input)
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
val picture = Picture(
|
||||||
|
url,
|
||||||
|
getNameURL(url),
|
||||||
|
result,
|
||||||
|
result.width,
|
||||||
|
result.height
|
||||||
|
)
|
||||||
|
|
||||||
|
cacheImage(picture)
|
||||||
|
picture
|
||||||
|
} else null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -18,31 +18,11 @@ expect open class Dir(
|
|||||||
fun imageCacheDir(): String
|
fun imageCacheDir(): String
|
||||||
fun createDirectory(dirPath:String)
|
fun createDirectory(dirPath:String)
|
||||||
fun cacheImage(picture: Picture)
|
fun cacheImage(picture: Picture)
|
||||||
|
fun loadImage(url:String, cachePath:String = imageCacheDir() + getNameURL(url)):Picture?
|
||||||
suspend fun clearCache()
|
suspend fun clearCache()
|
||||||
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails)
|
suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, path: String, trackDetails: TrackDetails)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun Dir.downloadFile(url: String): Flow<DownloadResult> {
|
|
||||||
return flow {
|
|
||||||
val client = createHttpClient()
|
|
||||||
val response = client.get<HttpStatement>(url).execute()
|
|
||||||
val data = ByteArray(response.contentLength()!!.toInt())
|
|
||||||
var offset = 0
|
|
||||||
do {
|
|
||||||
val currentRead = response.content.readAvailable(data, offset, data.size)
|
|
||||||
offset += currentRead
|
|
||||||
val progress = (offset * 100f / data.size).roundToInt()
|
|
||||||
emit(DownloadResult.Progress(progress))
|
|
||||||
} while (currentRead > 0)
|
|
||||||
if (response.status.isSuccess()) {
|
|
||||||
emit(DownloadResult.Success(data))
|
|
||||||
} else {
|
|
||||||
emit(DownloadResult.Error("File not downloaded"))
|
|
||||||
}
|
|
||||||
client.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
||||||
return flow {
|
return flow {
|
||||||
val client = createHttpClient()
|
val client = createHttpClient()
|
||||||
@ -65,7 +45,7 @@ suspend fun downloadFile(url: String): Flow<DownloadResult> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun Dir.cacheImagePostfix():String = "info"
|
fun Dir.cacheImagePostfix():String = "info"
|
||||||
fun Dir.getNameURL(url: String): String {
|
fun getNameURL(url: String): String {
|
||||||
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
return url.substring(url.lastIndexOf('/') + 1, url.length)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -20,6 +20,7 @@ class YoutubeMusic constructor(
|
|||||||
val youtubeTracks = mutableListOf<YoutubeTrack>()
|
val youtubeTracks = mutableListOf<YoutubeTrack>()
|
||||||
|
|
||||||
val responseObj = Json.parseToJsonElement(getYoutubeMusicResponse(query))
|
val responseObj = Json.parseToJsonElement(getYoutubeMusicResponse(query))
|
||||||
|
|
||||||
val contentBlocks = responseObj.jsonObject["contents"]
|
val contentBlocks = responseObj.jsonObject["contents"]
|
||||||
?.jsonObject?.get("sectionListRenderer")
|
?.jsonObject?.get("sectionListRenderer")
|
||||||
?.jsonObject?.get("contents")?.jsonArray
|
?.jsonObject?.get("contents")?.jsonArray
|
||||||
|
@ -2,7 +2,11 @@ package com.shabinder.common
|
|||||||
|
|
||||||
import co.touchlab.kermit.Kermit
|
import co.touchlab.kermit.Kermit
|
||||||
import com.mpatric.mp3agic.Mp3File
|
import com.mpatric.mp3agic.Mp3File
|
||||||
|
import java.awt.image.BufferedImage
|
||||||
import java.io.*
|
import java.io.*
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import javax.imageio.ImageIO
|
import javax.imageio.ImageIO
|
||||||
|
|
||||||
@ -77,4 +81,69 @@ actual open class Dir actual constructor(private val logger: Kermit) {
|
|||||||
.setId3v1Tags(trackDetails)
|
.setId3v1Tags(trackDetails)
|
||||||
.setId3v2TagsAndSaveFile(trackDetails,path)
|
.setId3v2TagsAndSaveFile(trackDetails,path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actual fun loadImage(url: String, cachePath: String):Picture? {
|
||||||
|
var picture: Picture? = loadCachedImage(cachePath)
|
||||||
|
if (picture == null) picture = freshImage(url,cachePath)
|
||||||
|
return picture
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadCachedImage(cachePath: String): Picture? {
|
||||||
|
return try {
|
||||||
|
val read = BufferedReader(
|
||||||
|
InputStreamReader(
|
||||||
|
FileInputStream(cachePath + cacheImagePostfix()),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val source = read.readLine()
|
||||||
|
val width = read.readLine().toInt()
|
||||||
|
val height = read.readLine().toInt()
|
||||||
|
|
||||||
|
read.close()
|
||||||
|
|
||||||
|
val result: BufferedImage? = ImageIO.read(File(cachePath))
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
Picture(
|
||||||
|
source,
|
||||||
|
getNameURL(source),
|
||||||
|
result,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
)
|
||||||
|
}else null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private fun freshImage(url:String,cachePath: String):Picture?{
|
||||||
|
return try {
|
||||||
|
val source = URL(url)
|
||||||
|
val connection: HttpURLConnection = source.openConnection() as HttpURLConnection
|
||||||
|
connection.connectTimeout = 5000
|
||||||
|
connection.connect()
|
||||||
|
|
||||||
|
val input: InputStream = connection.inputStream
|
||||||
|
val result: BufferedImage? = ImageIO.read(input)
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
val picture = Picture(
|
||||||
|
url,
|
||||||
|
getNameURL(url),
|
||||||
|
result,
|
||||||
|
result.width,
|
||||||
|
result.height
|
||||||
|
)
|
||||||
|
|
||||||
|
cacheImage(picture)
|
||||||
|
picture
|
||||||
|
} else null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user