random bug fixes

This commit is contained in:
deniscerri 2025-10-05 22:31:50 +02:00
parent 0ac4ab20e3
commit 4699cb46e1
No known key found for this signature in database
GPG key ID: 95C43D517D830350
13 changed files with 85 additions and 57 deletions

View file

@ -9,6 +9,7 @@ import androidx.room.Update
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import kotlinx.coroutines.flow.Flow
@Dao
@ -83,6 +84,9 @@ interface HistoryDao {
@Query("SELECT * FROM history WHERE url=:url")
fun getAllHistoryByURL(url: String) : List<HistoryItem>
@Query("SELECT * FROM history WHERE url=:url and type=:type")
fun getAllHistoryByURLAndType(url: String, type: DownloadViewModel.Type) : List<HistoryItem>
@Query("SELECT * FROM history WHERE id in (:ids)")
fun getAllHistoryByIDs(ids: List<Long>) : List<HistoryItem>

View file

@ -9,6 +9,7 @@ import androidx.paging.filter
import com.deniscerri.ytdl.database.DBManager.SORTING
import com.deniscerri.ytdl.database.dao.HistoryDao
import com.deniscerri.ytdl.database.models.HistoryItem
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
import com.deniscerri.ytdl.database.viewmodel.HistoryViewModel
import com.deniscerri.ytdl.util.FileUtil
import kotlinx.coroutines.flow.Flow
@ -37,6 +38,10 @@ class HistoryRepository(private val historyDao: HistoryDao) {
return historyDao.getAllHistoryByURL(url)
}
fun getAllByURLAndType(url: String, type: DownloadViewModel.Type) : List<HistoryItem> {
return historyDao.getAllHistoryByURLAndType(url, type)
}
fun getAllByIDs(ids: List<Long>) : List<HistoryItem> {
return historyDao.getAllHistoryByIDs(ids)
}

View file

@ -11,6 +11,7 @@ import androidx.work.WorkManager
import com.deniscerri.ytdl.R
import com.deniscerri.ytdl.database.dao.ObserveSourcesDao
import com.deniscerri.ytdl.database.models.observeSources.ObserveSourcesItem
import com.deniscerri.ytdl.util.Extensions.calculateNextTimeForObserving
import com.deniscerri.ytdl.work.ObserveSourceWorker
import kotlinx.coroutines.flow.Flow
import java.util.Calendar

View file

@ -1002,11 +1002,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val currentCommand = ytdlpUtil.buildYoutubeDLRequest(it)
val parsedCurrentCommand = ytdlpUtil.parseYTDLRequestString(currentCommand)
val existingDownload = activeAndQueuedDownloads.firstOrNull{d ->
d.id = 0
d.logID = null
d.customFileNameTemplate = it.customFileNameTemplate
d.status = DownloadRepository.Status.Queued.toString()
d.toString() == it.toString()
val normalized = d.copy(
id = 0,
logID = null,
customFileNameTemplate = it.customFileNameTemplate,
status = DownloadRepository.Status.Queued.toString()
)
normalized.toString() == it.toString()
}
if (existingDownload != null){

View file

@ -255,7 +255,7 @@ class FormatViewModel(private val application: Application) : AndroidViewModel(a
_noFreeSpace.emit(null)
if (size > 10L) {
File(FileUtil.formatPath(path)).apply {
if (size > this.freeSpace) {
if (size > this.freeSpace && this.freeSpace >= 10L) {
val warningTxt = application.getString(R.string.no_free_space_warning) +
"\n" + "${application.getString(R.string.file_size)}:\t${FileUtil.convertFileSize(size)}" +
"\n" + "${application.getString(R.string.freespace)}:\t${FileUtil.convertFileSize(this.freeSpace)}"

View file

@ -18,6 +18,7 @@ import android.widget.RadioButton
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.edit
import androidx.core.view.children
import androidx.core.view.isVisible
@ -53,6 +54,7 @@ import com.google.android.material.tabs.TabLayout
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.text.SimpleDateFormat
import java.util.Calendar
@ -471,7 +473,8 @@ class ObserveSourcesBottomSheetDialog : BottomSheetDialogFragment() {
retryMissingDownloads.isChecked = currentItem?.retryMissingDownloads ?: false
getOnlyNewUploads.isChecked = currentItem?.getOnlyNewUploads ?: false
syncWithSource.isChecked = currentItem?.syncWithSource ?: false
resetProcessedLinks.isVisible = currentItem != null
view.findViewById<ConstraintLayout>(R.id.resetProcessedLinksConstraint).isVisible = currentItem != null
if (currentItem != null) okButton.text = getString(R.string.update)
okButton.setOnClickListener {
@ -489,7 +492,7 @@ class ObserveSourcesBottomSheetDialog : BottomSheetDialogFragment() {
endsAfterCount = endsAfterNr.editText!!.text.toString().toInt()
}
val category = ObserveSourcesRepository.EveryCategory.values()[categoryAdapter.getPosition(everyCat.text.toString())]
val category = ObserveSourcesRepository.EveryCategory.entries[categoryAdapter.getPosition(everyCat.text.toString())]
val observeItem = ObserveSourcesItem(
id = currentItem?.id ?: 0,

View file

@ -297,7 +297,7 @@ object Extensions {
val badge = BadgeDrawable.create(context).apply {
number = nr
backgroundColor = context.getColor(R.color.white)
verticalOffset = 30
verticalOffset = 25
horizontalOffset =
if (nr < 10) dp(App.instance.resources, 16f)
else if (nr < 100) dp(App.instance.resources, 19f)

View file

@ -25,7 +25,7 @@ class CleanUpLeftoverDownloads(
val id = System.currentTimeMillis().toInt()
val notification = notificationUtil.createDeletingLeftoverDownloadsNotification()
if (Build.VERSION.SDK_INT > 33) {
if (Build.VERSION.SDK_INT >= 33) {
setForegroundAsync(ForegroundInfo(id, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
}else{
setForegroundAsync(ForegroundInfo(id, notification))

View file

@ -41,7 +41,7 @@ class MoveCacheFilesWorker(
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = notificationUtil.createMoveCacheFilesNotification(pendingIntent, NotificationUtil.DOWNLOAD_MISC_CHANNEL_ID)
if (Build.VERSION.SDK_INT > 33) {
if (Build.VERSION.SDK_INT >= 33) {
setForegroundAsync(ForegroundInfo(id, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
}else{
setForegroundAsync(ForegroundInfo(id, notification))

View file

@ -17,6 +17,7 @@ import androidx.work.WorkerParameters
import com.deniscerri.ytdl.App
import com.deniscerri.ytdl.database.DBManager
import com.deniscerri.ytdl.database.models.DownloadItem
import com.deniscerri.ytdl.database.models.ResultItem
import com.deniscerri.ytdl.database.repository.DownloadRepository
import com.deniscerri.ytdl.database.repository.HistoryRepository
import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository
@ -36,9 +37,10 @@ class ObserveSourceWorker(
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {
override suspend fun doWork(): Result {
val notificationUtil = NotificationUtil(App.instance)
val sourceID = inputData.getLong("id", 0)
if (sourceID == 0L) return Result.failure()
if (sourceID == 0L) return Result.success()
val notificationUtil = NotificationUtil(App.instance)
val dbManager = DBManager.getInstance(context)
val workManager = WorkManager.getInstance(context)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
@ -46,17 +48,18 @@ class ObserveSourceWorker(
val historyRepo = HistoryRepository(dbManager.historyDao)
val downloadRepo = DownloadRepository(dbManager.downloadDao)
val commandTemplateDao = dbManager.commandTemplateDao
val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
val resultRepository = ResultRepository(dbManager.resultDao, commandTemplateDao, context)
val ytdlpUtil = YTDLPUtil(context, commandTemplateDao)
val item = repo.getByID(sourceID)
if (item.status == ObserveSourcesRepository.SourceStatus.STOPPED){
return Result.failure()
return Result.success()
}
val workerID = System.currentTimeMillis().toInt()
val notification = notificationUtil.createObserveSourcesNotification(item.name)
if (Build.VERSION.SDK_INT > 33) {
if (Build.VERSION.SDK_INT >= 33) {
setForegroundAsync(ForegroundInfo(workerID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
}else{
setForegroundAsync(ForegroundInfo(workerID, notification))
@ -68,7 +71,8 @@ class ObserveSourceWorker(
Log.e("observe", it.toString())
}.getOrElse { listOf() }
if (list.isNotEmpty() && item.syncWithSource && item.alreadyProcessedLinks.isNotEmpty()){
//delete downloaded items not present in source if sync is enabled
if (item.syncWithSource && item.alreadyProcessedLinks.isNotEmpty()){
val processedLinks = item.alreadyProcessedLinks
val incomingLinks = list.map { it.url }
@ -81,37 +85,42 @@ class ObserveSourceWorker(
}
}
val res = list
.filter { result ->
//if first run and get new items only is preferred then dont get anything on first run
if (item.getOnlyNewUploads && item.runCount == 0){
item.ignoredLinks.add(result.url)
false
}else{
true
}
val toProcess = mutableListOf<ResultItem>()
//filter what results need to be downloaded, ignored
for (result in list) {
if (item.ignoredLinks.contains(result.url)) {
continue
}
.filter { result ->
val history = historyRepo.getAllByURL(result.url)
!item.ignoredLinks.contains(result.url) &&
// if first run and get only new items, ignore
if (item.getOnlyNewUploads && item.runCount == 0) {
item.ignoredLinks.add(result.url)
continue
}
if (item.retryMissingDownloads){
//all items that are not present in history
history.none { hi -> hi.downloadPath.any { path -> FileUtil.exists(path) } }
}else{
//all items that are not already processed
if(item.alreadyProcessedLinks.isEmpty()){
!history.map { it.url }.contains(result.url)
}else{
!item.alreadyProcessedLinks.contains(result.url)
}
val history = historyRepo.getAllByURLAndType(result.url, item.downloadItemTemplate.type)
//if history is empty or all history items are deleted, add for retry
if (item.retryMissingDownloads && (history.isEmpty() || history.none { hi -> hi.downloadPath.any { path -> FileUtil.exists(path) } })) {
toProcess.add(result)
continue
}
if (item.alreadyProcessedLinks.isEmpty()) {
if (history.isEmpty()) {
toProcess.add(result)
continue
}
}
val items = mutableListOf<DownloadItem>()
res.forEach {
if (item.alreadyProcessedLinks.contains(result.url)) {
continue
}
toProcess.add(result)
}
val downloadItems = mutableListOf<DownloadItem>()
toProcess.forEach {
val string = Gson().toJson(item.downloadItemTemplate, DownloadItem::class.java)
val downloadItem = Gson().fromJson(string, DownloadItem::class.java)
downloadItem.title = it.title
@ -125,12 +134,11 @@ class ObserveSourceWorker(
downloadItem.playlistURL = it.playlistURL
downloadItem.playlistIndex = it.playlistIndex
downloadItem.id = 0L
items.add(downloadItem)
downloadItems.add(downloadItem)
}
if (items.isNotEmpty()){
if (downloadItems.isNotEmpty()){
//QUEUE DOWNLOADS
//COPY OF QUEUE DOWNLOADS IN DOWNLOAD VIEW MODEL. NEEDS TO BE UPDATED IF THAT IS UPDATED
val context = App.instance
@ -146,16 +154,18 @@ class ObserveSourceWorker(
// items.forEachIndexed { index, it -> it.playlistTitle = "Various[${index+1}]" }
// }
items.forEach {
downloadItems.forEach {
it.status = DownloadRepository.Status.Queued.toString()
val currentCommand = ytdlpUtil.buildYoutubeDLRequest(it)
val parsedCurrentCommand = ytdlpUtil.parseYTDLRequestString(currentCommand)
val existingDownload = activeAndQueuedDownloads.firstOrNull{d ->
d.id = 0
d.logID = null
d.customFileNameTemplate = it.customFileNameTemplate
d.status = DownloadRepository.Status.Queued.toString()
d.toString() == it.toString()
val normalized = d.copy(
id = 0,
logID = null,
customFileNameTemplate = it.customFileNameTemplate,
status = DownloadRepository.Status.Queued.toString()
)
normalized.toString() == it.toString()
}
if (existingDownload != null) {
it.id = existingDownload.id
@ -191,14 +201,15 @@ class ObserveSourceWorker(
downloadRepo.startDownloadWorker(queuedItems, context)
}
item.alreadyProcessedLinks.removeAll(items.map { it.url })
item.alreadyProcessedLinks.addAll(items.map { it.url })
item.alreadyProcessedLinks.addAll(downloadItems.map { it.url })
}
item.runCount += 1
val currentTime = System.currentTimeMillis()
val isFinished = (item.endsAfterCount > 0 && item.runCount >= item.endsAfterCount) || item.endsDate >= currentTime
val isFinished =
(item.endsAfterCount > 0 && item.runCount >= item.endsAfterCount) ||
(item.endsDate > 0 && currentTime >= item.endsDate)
if (isFinished) {
item.status = ObserveSourcesRepository.SourceStatus.STOPPED
withContext(Dispatchers.IO){

View file

@ -52,7 +52,7 @@ class TerminalDownloadWorker(
val intent = Intent(context, TerminalActivity::class.java)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, command.take(65), NotificationUtil.DOWNLOAD_TERMINAL_RUNNING_NOTIFICATION_ID)
if (Build.VERSION.SDK_INT > 33) {
if (Build.VERSION.SDK_INT >= 33) {
setForegroundAsync(ForegroundInfo(itemId, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
}else{
setForegroundAsync(ForegroundInfo(itemId, notification))

View file

@ -33,7 +33,7 @@ class UpdateMultipleDownloadsFormatsWorker(
val notification = notificationUtil.createFormatsUpdateNotification()
if (Build.VERSION.SDK_INT > 33) {
if (Build.VERSION.SDK_INT >= 33) {
setForegroundAsync(ForegroundInfo(workID, notification, FOREGROUND_SERVICE_TYPE_DATA_SYNC))
}else{
setForegroundAsync(ForegroundInfo(workID, notification))

View file

@ -224,6 +224,7 @@
app:chipSpacingVertical="0dp"
android:paddingVertical="5dp"
android:paddingHorizontal="10dp"
app:selectionRequired="true"
android:layout_height="wrap_content">
<com.google.android.material.chip.Chip
@ -589,6 +590,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/resetProcessedLinksConstraint"
android:layout_width="match_parent"
android:layout_marginTop="10dp"
android:layout_height="wrap_content">