Skip to content

Instantly share code, notes, and snippets.

@kirmartuk
Last active October 15, 2020 10:57
Show Gist options
  • Save kirmartuk/caa5a8ad5812994ace7b4dca4a97f189 to your computer and use it in GitHub Desktop.
Save kirmartuk/caa5a8ad5812994ace7b4dca4a97f189 to your computer and use it in GitHub Desktop.
Android(Kotlin) VideoRepository
//Sealed class for showing result in progressBar, mainThread
sealed class DownloadResult {
object Success : DownloadResult()
data class Error(val message: String) : DownloadResult()
data class Progress(val progress: Int) : DownloadResult()
}
private val PROJECTION = arrayOf(MediaStore.Video.Media._ID)
private const val QUERY = MediaStore.Video.Media.DISPLAY_NAME + " = ?"
private const val AUTHORITY = "${BuildConfig.APPLICATION_ID}.provider"
class VideoRepository(private val context: Context) {
private val ok = OkHttpClient()
private val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL
) else MediaStore.Video.Media.EXTERNAL_CONTENT_URI
suspend fun getLocalUri(filename: String): Uri? =
withContext(Dispatchers.IO) {
val resolver = context.contentResolver
resolver.query(collection, PROJECTION, QUERY, arrayOf(filename), null)
?.use { cursor ->
if (cursor.count > 0) {
cursor.moveToFirst()
return@withContext ContentUris.withAppendedId(
collection,
cursor.getLong(0)
)
}
}
null
}
suspend fun download(url: String, name: String): Flow<DownloadResult> {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) downloadQ(
url,
name
)
else downloadLegacy(url, name)
}
private suspend fun downloadQ(url: String, name: String): Flow<DownloadResult> {
return flow {
try {
val response = ok.newCall(Request.Builder().url(url).build()).execute()
if (response.isSuccessful) {
val values = ContentValues().apply {
put(MediaStore.Video.Media.DISPLAY_NAME, name)
put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/YourFolder")
put(MediaStore.Video.Media.MIME_TYPE, "video/mp4")
put(MediaStore.Video.Media.IS_PENDING, 2)
}
val resolver = context.contentResolver
val uri = resolver.insert(collection, values)
uri?.let {
resolver.openOutputStream(uri)?.use { outputStream ->
val sink = Okio.buffer(Okio.sink(outputStream))
response.body()?.source()?.let {
sink.writeAll(it)
}
sink.close()
}
values.clear()
values.put(MediaStore.Video.Media.IS_PENDING, 0)
resolver.update(uri, values, null, null)
emit(DownloadResult.Success)
} ?: throw RuntimeException("MediaStore failed for some reason")
uri
} else {
emit(DownloadResult.Error("Error"))
throw RuntimeException("OkHttp failed for some reason")
}
} catch (exception: Exception) {
emit(DownloadResult.Error("Error"))
}
}
}
private suspend fun downloadLegacy(
url: String,
name: String
): Flow<DownloadResult> {
return flow {
try {
val dir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_MOVIES + "/YourFolder"
)
dir.mkdirs()
val file = File(
dir,
"$name.mp4"
)
file.createNewFile()
val response = ok.newCall(Request.Builder().url(url).build()).execute()
if (response.isSuccessful) {
val sink = Okio.buffer(Okio.sink(file))
response.body()?.source()?.let { sink.writeAll(it) }
sink.close()
emit(DownloadResult.Success)
} else {
throw RuntimeException("OkHttp failed for some reason")
}
} catch (exception: Exception) {
Log.e("error", exception.toString())
emit(DownloadResult.Error("Error"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment