package com.deniscerri.ytdlnis.util import android.app.Activity import android.app.DownloadManager import android.content.Context import android.content.DialogInterface import android.net.Uri import android.os.Build import android.os.Environment import android.util.Log import android.widget.Toast import com.deniscerri.ytdlnis.BuildConfig import com.deniscerri.ytdlnis.R import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL.UpdateStatus import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.json.JSONException import org.json.JSONObject import java.io.BufferedReader import java.io.InputStreamReader import java.net.HttpURLConnection import java.net.URL import java.util.concurrent.atomic.AtomicReference class UpdateUtil(var context: Context) { private val tag = "UpdateUtil" private val downloadManager: DownloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager private val compositeDisposable = CompositeDisposable() private val ytdlpNightly = "https://api.github.com/repos/yt-dlp/yt-dlp-nightly-builds/releases/latest" fun updateApp(): Boolean { if (updatingApp) { Toast.makeText( context, context.getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG ).show() return true } val res = AtomicReference(JSONObject()) try { val thread = Thread { res.set(checkForAppUpdate()) } thread.start() thread.join() } catch (e: Exception) { Log.e(tag, e.toString()) } val version: String val body: String? try { version = res.get().getString("tag_name") body = res.get().getString("body") } catch (ignored: JSONException) { return false } val versionNameInt = version.split("v")[1].replace(".","").toInt() val currentVersionNameInt = BuildConfig.VERSION_NAME.replace(".","").toInt() if (currentVersionNameInt > versionNameInt) { return false } val updateDialog = MaterialAlertDialogBuilder(context) .setTitle(version) .setMessage(body) .setIcon(R.drawable.ic_update_app) .setNegativeButton("Cancel") { _: DialogInterface?, _: Int -> } .setPositiveButton("Update") { _: DialogInterface?, _: Int -> startAppUpdate( res.get() ) } updateDialog.show() return true } private fun checkForAppUpdate(): JSONObject { val url = "https://api.github.com/repos/deniscerri/ytdlnis/releases/latest" val reader: BufferedReader var line: String? val responseContent = StringBuilder() val conn: HttpURLConnection var json = JSONObject() try { val req = URL(url) conn = req.openConnection() as HttpURLConnection conn.requestMethod = "GET" conn.connectTimeout = 10000 conn.readTimeout = 5000 if (conn.responseCode < 300) { reader = BufferedReader(InputStreamReader(conn.inputStream)) while (reader.readLine().also { line = it } != null) { responseContent.append(line) } reader.close() json = JSONObject(responseContent.toString()) if (json.has("error")) { throw Exception() } } conn.disconnect() } catch (e: Exception) { Log.e(tag, e.toString()) } return json } private fun startAppUpdate(updateInfo: JSONObject) { try { val versions = updateInfo.getJSONArray("assets") var url = "" var appName = "" for (i in 0 until versions.length()) { val tmp = versions.getJSONObject(i) if (tmp.getString("name").contains(Build.SUPPORTED_ABIS[0])) { url = tmp.getString("browser_download_url") appName = tmp.getString("name") break } } if (url.isEmpty()) { Toast.makeText(context, R.string.couldnt_find_apk, Toast.LENGTH_SHORT).show() return } val uri = Uri.parse(url) Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) .mkdirs() downloadManager.enqueue( DownloadManager.Request(uri) .setAllowedNetworkTypes( DownloadManager.Request.NETWORK_WIFI or DownloadManager.Request.NETWORK_MOBILE ) .setAllowedOverRoaming(true) .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) .setTitle(context.getString(R.string.downloading_update)) .setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, appName) ) } catch (ignored: Exception) { } } suspend fun updateYoutubeDL() : UpdateStatus? = withContext(Dispatchers.IO){ val sharedPreferences = context.getSharedPreferences("root_preferences", Activity.MODE_PRIVATE) val editor = sharedPreferences.edit() if (updatingYTDL) { withContext(Dispatchers.Main){ Toast.makeText( context, context.getString(R.string.ytdl_already_updating), Toast.LENGTH_LONG ).show() } UpdateStatus.ALREADY_UP_TO_DATE } withContext(Dispatchers.Main){ Toast.makeText( context, context.getString(R.string.ytdl_updating_started), Toast.LENGTH_SHORT ).show() } updatingYTDL = true YoutubeDL.getInstance().updateYoutubeDL( context, if (sharedPreferences.getBoolean("nightly_ytdl", false) ) ytdlpNightly else null ).apply { updatingYTDL = false } // .onFailure { // if (BuildConfig.DEBUG) Log.e(tag, context.getString(R.string.ytdl_update_failed), e) // Toast.makeText( // context, // context.getString(R.string.ytdl_update_failed), // Toast.LENGTH_LONG // ).show() // updatingYTDL = false // } //} } companion object { var updatingYTDL = false var updatingApp = false } }