Restart po token server when background jobs run in the app. Useful for scheduled jobs when app is closed and server is also closed.

pull/1312/head
deniscerri 1 month ago
parent 19677a6af2
commit 168f7c3362
No known key found for this signature in database
GPG Key ID: 95C43D517D830350

@ -48,6 +48,7 @@
android:supportsRtl="true"
android:theme="@style/BaseTheme"
tools:ignore="DataExtractionRules"
android:networkSecurityConfig="@xml/network_security_config"
tools:targetApi="tiramisu"
android:memtagMode="async">
<profileable

@ -44,6 +44,7 @@ import com.google.android.material.slider.Slider
import com.termux.terminal.TerminalSession
import com.termux.view.TerminalView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.text.toInt
@ -213,7 +214,6 @@ class TerminalFragment : Fragment() {
@SuppressLint("UseKtx")
private fun initMenu() {
topAppBar.menu?.findItem(R.id.export_clipboard)?.isVisible = true
topAppBar.menu?.findItem(R.id.delete)?.isVisible = true
topAppBar.setOnMenuItemClickListener { menuItem: MenuItem ->
when (menuItem.itemId) {
@ -221,11 +221,6 @@ class TerminalFragment : Fragment() {
findNavController().navigate(R.id.terminalFragment, bundleOf(Pair("new", true)),
NavOptions.Builder().setPopUpTo(R.id.terminalFragment, true).build())
}
R.id.delete -> {
sessionId?.apply {
terminalViewModel.sessionBinder?.terminateSession(this)
}
}
R.id.wrap -> {
// var scrollView = requireView().findViewById<HorizontalScrollView>(R.id.horizontalscroll_output)
// if(scrollView != null){
@ -267,6 +262,7 @@ class TerminalFragment : Fragment() {
val activity = requireActivity() as TerminalActivity
val client = TerminalBackEnd(terminalView, activity) {
if (isAdded) {
terminalViewModel.sessionBinder?.terminateSession(sessionId!!)
requireActivity().onBackPressedDispatcher.onBackPressed()
}
}

@ -14,7 +14,6 @@ import android.util.DisplayMetrics
import android.util.Log
import android.widget.Toast
import androidx.preference.PreferenceManager
import androidx.work.CoroutineWorker
import androidx.work.ForegroundInfo
import androidx.work.WorkManager
import androidx.work.WorkerParameters
@ -57,7 +56,7 @@ import kotlin.random.Random
class DownloadWorker(
private val context: Context,
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
) : YTDLPCoroutineWorker(context, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
val workNotif = NotificationUtil(App.Companion.instance).createDefaultWorkerNotification()
@ -77,7 +76,7 @@ class DownloadWorker(
@OptIn(ExperimentalStdlibApi::class)
@SuppressLint("RestrictedApi")
override suspend fun doWork(): Result {
override suspend fun runWork(): Result {
val workManager = WorkManager.Companion.getInstance(context)
if (workManager.isRunning("download") || isStopped) return Result.Failure()

@ -0,0 +1,84 @@
package com.deniscerri.ytdl.work
import android.app.ActivityManager
import android.content.Context
import android.preference.PreferenceManager
import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.deniscerri.ytdl.services.BgUtilsPoTokenGeneratorService
import com.deniscerri.ytdl.util.BgUtilsPoTokenGeneratorUtil
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import java.net.HttpURLConnection
import java.net.URL
abstract class YTDLPCoroutineWorker(
private val context: Context,
params: WorkerParameters
) : CoroutineWorker(context, params) {
abstract suspend fun runWork(): Result
override suspend fun doWork(): Result {
return try {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val useBgUtilPoTokenServer = sharedPreferences.getBoolean("use_bgutils_potoken_generator", false)
if (useBgUtilPoTokenServer) {
// 1. Ensure service is active before starting child worker logic
if (!isBgUtilsServerAlive()) {
val serviceRunning = isBgUtilsServiceRunning(context)
if (!serviceRunning) {
BgUtilsPoTokenGeneratorUtil.runServer(context)
}
// Wait for local HTTP server to become responsive
val ready = waitForServerReady(timeoutMs = 10000)
if (!ready) {
return Result.retry()
}
}
}
runWork()
} catch (e: Exception) {
Result.failure()
}
}
@Suppress("DEPRECATION")
fun isBgUtilsServiceRunning(context: Context): Boolean {
val manager = context.getSystemService(Context.ACTIVITY_SERVICE) as? ActivityManager ?: return false
return manager.getRunningServices(Int.MAX_VALUE).any {
BgUtilsPoTokenGeneratorService::class.java.name == it.service.className
}
}
private suspend fun isBgUtilsServerAlive(): Boolean = withContext(Dispatchers.IO) {
var connection: HttpURLConnection? = null
try {
val url = URL("http://localhost:4416/ping")
connection = (url.openConnection() as HttpURLConnection).apply {
connectTimeout = 1000
readTimeout = 1000
useCaches = false
}
val code = connection.responseCode
code == 200
} catch (e: Exception) {
// Temporarily log the exact error to logcat
android.util.Log.e("YTDLWorker", "Ping failed: ${e.message}", e)
false
} finally {
connection?.disconnect()
}
}
private suspend fun waitForServerReady(timeoutMs: Long): Boolean {
val start = System.currentTimeMillis()
while (System.currentTimeMillis() - start < timeoutMs) {
if (isBgUtilsServerAlive()) return true
delay(500)
}
return false
}
}

@ -29,6 +29,7 @@ import com.deniscerri.ytdl.util.FileUtil
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.util.ObserveAlarmScheduler
import com.deniscerri.ytdl.util.extractors.ytdlp.YTDLPUtil
import com.deniscerri.ytdl.work.YTDLPCoroutineWorker
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@ -37,24 +38,19 @@ import java.util.concurrent.TimeUnit
class ObserveSourceWorker(
private val context: Context,
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
) : YTDLPCoroutineWorker(context, workerParams) {
override suspend fun runWork(): Result {
val sourceID = inputData.getLong("id", 0)
if (sourceID == 0L) return Result.success()
val notificationUtil = NotificationUtil(App.Companion.instance)
val dbManager = DBManager.Companion.getInstance(context)
val workManager = WorkManager.Companion.getInstance(context)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val notificationUtil = NotificationUtil(App.instance)
val dbManager = DBManager.getInstance(context)
val repo =
ObserveSourcesRepository(dbManager.observeSourcesDao)
val historyRepo = HistoryRepository(dbManager.historyDao)
val downloadRepo = DownloadRepository(dbManager.downloadDao)
val commandTemplateDao = dbManager.commandTemplateDao
val resultRepository = ResultRepository(dbManager.resultDao, commandTemplateDao, context)
val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
val item = runCatching { repo.getByID(sourceID) }.getOrNull() ?: return Result.success()
if (item.status == ObserveSourcesRepository.SourceStatus.STOPPED) return Result.success()

@ -10,10 +10,14 @@ import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.work.YTDLPCoroutineWorker
import com.deniscerri.ytdl.work.setForegroundSafely
import kotlinx.coroutines.runBlocking
class UpdateMultipleDownloadsDataWorker(private val context: Context, workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {
class UpdateMultipleDownloadsDataWorker(
private val context: Context,
workerParams: WorkerParameters
) : YTDLPCoroutineWorker(context, workerParams) {
override suspend fun getForegroundInfo(): ForegroundInfo {
val workNotif = NotificationUtil(App.Companion.instance).createDataUpdateNotification()
@ -30,7 +34,7 @@ class UpdateMultipleDownloadsDataWorker(private val context: Context, workerPara
}
override suspend fun doWork(): Result {
override suspend fun runWork(): Result {
val dbManager = DBManager.Companion.getInstance(context)
val dao = dbManager.downloadDao
val resDao = dbManager.resultDao

@ -11,13 +11,14 @@ import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.repository.ResultRepository
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.util.NotificationUtil
import com.deniscerri.ytdl.work.YTDLPCoroutineWorker
import kotlinx.coroutines.runBlocking
class UpdateMultipleDownloadsFormatsWorker(
private val context: Context,
workerParams: WorkerParameters
) : Worker(context, workerParams) {
override fun doWork(): Result {
) : YTDLPCoroutineWorker(context, workerParams) {
override suspend fun runWork(): Result {
val dbManager = DBManager.Companion.getInstance(context)
val dao = dbManager.downloadDao
val resDao = dbManager.resultDao

@ -7,11 +7,6 @@
app:showAsAction="always"
android:id="@+id/add"/>
<item android:title="@string/Remove"
android:icon="@drawable/baseline_delete"
app:showAsAction="always"
android:id="@+id/delete"/>
<!-- <item android:title="@string/wrap_text"-->
<!-- android:icon="@drawable/baseline_wrap_text_24"-->
<!-- app:showAsAction="always"-->

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- Keep HTTPS mandatory for standard network traffic -->
<base-config cleartextTrafficPermitted="false" />
<!-- Grant cleartext HTTP permission ONLY for local server loopbacks -->
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
<domain includeSubdomains="true">localhost</domain>
</domain-config>
</network-security-config>
Loading…
Cancel
Save