alot of stuff

This commit is contained in:
deniscerri 2026-01-25 15:49:43 +01:00
parent e849b21e9b
commit 9a615777ad
No known key found for this signature in database
GPG key ID: 95C43D517D830350
19 changed files with 115 additions and 53 deletions

View file

@ -156,7 +156,7 @@ class MainActivity : BaseActivity() {
navController.navigate(R.id.downloadQueueMainFragment)
}else{
kotlin.runCatching {
(navHostFragment.childFragmentManager.primaryNavigationFragment!! as HistoryFragment).scrollToTop()
(navHostFragment.childFragmentManager.primaryNavigationFragment!! as HistoryFragment).openSearchView()
}
}
}

View file

@ -19,7 +19,7 @@ interface LogDao {
fun getAllLogsFlow() : Flow<List<LogItem>>
@Query("SELECT * FROM logs WHERE id=:id LIMIT 1")
fun getLogFlowByID(id: Long) : Flow<LogItem>
fun getLogFlowByID(id: Long) : Flow<LogItem?>
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(item: LogItem) : Long
@ -56,5 +56,5 @@ interface LogDao {
suspend fun update(item: LogItem)
@Query("SELECT * FROM logs WHERE id=:id LIMIT 1")
fun getByID(id: Long) : LogItem
fun getByID(id: Long) : LogItem?
}

View file

@ -11,7 +11,7 @@ class LogRepository(private val logDao: LogDao) {
return logDao.getAllLogs()
}
fun getLogFlowByID(id: Long) : Flow<LogItem> {
fun getLogFlowByID(id: Long) : Flow<LogItem?> {
return logDao.getLogFlowByID(id)
}
@ -33,7 +33,7 @@ class LogRepository(private val logDao: LogDao) {
logDao.deleteAll()
}
fun getItem(id: Long) : LogItem{
fun getItem(id: Long) : LogItem? {
return logDao.getByID(id)
}

View file

@ -264,6 +264,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val saveSubs = sharedPreferences.getBoolean("write_subtitles", false)
val saveAutoSubs = sharedPreferences.getBoolean("write_auto_subtitles", false)
val recodeVideo = sharedPreferences.getBoolean("recode_video", false)
val compatibilityMode = sharedPreferences.getBoolean("compatible_video", false)
val removeAudio = sharedPreferences.getBoolean("remove_audio", false)
val alsoDownloadAudio = sharedPreferences.getBoolean("also_download_audio", false)
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
@ -309,7 +312,10 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
subsLanguages,
audioFormatIDs = preferredAudioFormats,
recodeVideo = recodeVideo,
embedThumbnail = videoEmbedThumb
compatibilityMode = compatibilityMode,
embedThumbnail = videoEmbedThumb,
removeAudio = removeAudio,
alsoDownloadAsAudio = alsoDownloadAudio
)
val extraCommands = when(type){
@ -448,6 +454,9 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
val saveSubs = sharedPreferences.getBoolean("write_subtitles", false)
val saveAutoSubs = sharedPreferences.getBoolean("write_auto_subtitles", false)
val recodeVideo = sharedPreferences.getBoolean("recode_video", false)
val removeAudio = sharedPreferences.getBoolean("remove_audio", false)
val compatibilityMode = sharedPreferences.getBoolean("compatible_video", false)
val alsoDownloadAudio = sharedPreferences.getBoolean("also_download_audio", false)
val addChapters = sharedPreferences.getBoolean("add_chapters", false)
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
@ -486,8 +495,25 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
}
}.joinToString(" ") { it.content }
val audioPreferences = AudioPreferences(embedThumb, cropThumb,false, ArrayList(sponsorblock!!), audioBitrate!!)
val videoPreferences = VideoPreferences(embedSubs, addChapters, false, ArrayList(sponsorblock), saveSubs, saveAutoSubs, subsLanguages, recodeVideo = recodeVideo)
val audioPreferences = AudioPreferences(
embedThumb = embedThumb,
cropThumb = cropThumb,
splitByChapters = false,
sponsorBlockFilters = ArrayList(sponsorblock!!),
bitrate = audioBitrate!!
)
val videoPreferences = VideoPreferences(
embedSubs = embedSubs,
addChapters = addChapters,
splitByChapters = false,
sponsorBlockFilters = ArrayList(sponsorblock),
writeSubs = saveSubs,
writeAutoSubs = saveAutoSubs,
subsLanguages = subsLanguages,
recodeVideo = recodeVideo,
compatibilityMode = compatibilityMode,
removeAudio = removeAudio,
alsoDownloadAsAudio = alsoDownloadAudio)
var path = defaultPath
historyItem.downloadPath.first().apply {
File(this).parent?.apply {

View file

@ -28,11 +28,11 @@ class LogViewModel(private val application: Application) : AndroidViewModel(appl
}
fun getLogFlowByID(id: Long) : LiveData<LogItem> {
fun getLogFlowByID(id: Long) : LiveData<LogItem?> {
return repository.getLogFlowByID(id).asLiveData()
}
fun getItemById(id: Long): LogItem{
fun getItemById(id: Long): LogItem? {
return repository.getItem(id)
}

View file

@ -218,10 +218,17 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
}
}
fun openSearchView() {
topAppBar.menu.performIdentifierAction(R.id.search_history, 0)
}
private fun initMenu() {
val searchView = topAppBar.menu.findItem(R.id.search_history).actionView as SearchView?
val onActionExpandListener: MenuItem.OnActionExpandListener =
object : MenuItem.OnActionExpandListener {
override fun onMenuItemActionExpand(menuItem: MenuItem): Boolean {
searchView?.requestFocus()
return true
}
@ -231,7 +238,7 @@ class HistoryFragment : Fragment(), HistoryPaginatedAdapter.OnItemClickListener{
}
topAppBar.menu.findItem(R.id.search_history)
.setOnActionExpandListener(onActionExpandListener)
val searchView = topAppBar.menu.findItem(R.id.search_history).actionView as SearchView?
searchView!!.inputType = InputType.TYPE_CLASS_TEXT
searchView.queryHint = getString(R.string.search_history_hint)
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {

View file

@ -125,7 +125,6 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
}
private fun initMenu() {
topAppBar.menu.getItem(1).isChecked = preferences.getBoolean("use_header", false)
topAppBar.setOnMenuItemClickListener { m: MenuItem ->
when (m.itemId) {
R.id.delete_cookies -> {
@ -143,10 +142,6 @@ class CookiesFragment : Fragment(), CookieAdapter.OnItemClickListener {
}
deleteDialog.show()
}
R.id.use_header -> {
m.isChecked = !m.isChecked
preferences.edit().putBoolean("use_header", m.isChecked).apply()
}
R.id.import_clipboard -> {
lifecycleScope.launch(Dispatchers.IO){
cookiesViewModel.importFromClipboard()

View file

@ -113,7 +113,7 @@ class DownloadLogFragment : Fragment() {
CoroutineScope(Dispatchers.IO).launch {
runCatching {
val logItem = logViewModel.getItemById(logID!!)
val logItem = logViewModel.getItemById(logID!!) ?: throw Exception()
withContext(Dispatchers.Main){
topAppBar.title = logItem.title
}

View file

@ -236,16 +236,19 @@ class DownloadLogListFragment : Fragment(), DownloadLogsAdapter.OnItemClickListe
when (direction) {
ItemTouchHelper.LEFT -> {
lifecycleScope.launch {
val deletedItem = withContext(Dispatchers.IO){
val toDelete = withContext(Dispatchers.IO){
logViewModel.getItemById(items[position].id)
}
logViewModel.delete(deletedItem)
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + deletedItem.title, Snackbar.LENGTH_INDEFINITE)
.setAction(getString(R.string.undo)) {
lifecycleScope.launch(Dispatchers.IO){
logViewModel.insert(deletedItem)
}
}.show()
toDelete?.apply {
logViewModel.delete(this)
Snackbar.make(recyclerView, getString(R.string.you_are_going_to_delete) + ": " + this.title, Snackbar.LENGTH_INDEFINITE)
.setAction(getString(R.string.undo)) {
lifecycleScope.launch(Dispatchers.IO){
logViewModel.insert(this@apply)
}
}.show()
}
}
}

View file

@ -216,7 +216,7 @@ class GenerateYoutubePoTokensFragment : Fragment() {
regenerateBtn.isEnabled = false
editText.doOnTextChanged { text, start, before, count ->
regenerateBtn.isEnabled = editText.text.toString().getIDFromYoutubeURL() != null
regenerateBtn.isEnabled = editText.text.toString().isYoutubeURL()
}
regenerateBtn.setOnClickListener {
@ -224,7 +224,7 @@ class GenerateYoutubePoTokensFragment : Fragment() {
val intent = Intent(requireContext(), PoTokenWebViewLoginActivity::class.java)
intent.putExtra("url", "https://www.youtube.com")
intent.putExtra("redirect_url", "https://www.youtube.com/embed/${editText.text.toString().getIDFromYoutubeURL()}")
//intent.putExtra("redirect_url", "https://www.youtube.com/embed/${editText.text.toString().getIDFromYoutubeURL()}")
intent.putExtra("no_auth", true)
webPoTokenResultLauncher.launch(intent)
}

View file

@ -472,6 +472,19 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
}
if (!request.hasOption("--no-check-certificates")) request.addOption("--no-check-certificates")
val canUseWriteInfoJson =
!sharedPreferences.getBoolean("disable_write_info_json", false) &&
!request.toString().contains("--download-sections")
if (canUseWriteInfoJson) {
val infoJsonFile = getInfoJsonFile(url)
//ignore info file if its older than 5 hours. puny measure to prevent expired formats in some cases
if (infoJsonFile != null && System.currentTimeMillis() - infoJsonFile.lastModified() <= (1000 * 60 * 60 * 5)) {
request.addOption("--load-info-json", infoJsonFile.absolutePath)
}else {
request.addWriteInfoJson(url)
}
}
val res = YoutubeDL.getInstance().execute(request)
val results: Array<String?> = try {
res.out.split(System.lineSeparator()).toTypedArray()
@ -610,6 +623,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
val infoJsonName = hash(id)
//yt-dlp doesnt overwrite info json, so delete manually
File("${cachePath}/${infoJsonName}video.info.json").delete()
this.addOption("--no-clean-info-json")
this.addCommands(listOf("--print-to-file", "video:%()j", "${cachePath}/${infoJsonName}${System.currentTimeMillis()}video.info.json"))
}
@ -645,7 +659,6 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
request.addOption("--print", "%(filename)s")
request.addOption("--skip-download")
request.addOption("--simulate")
request.addOption("--no-check-certificates")
request.addOption("--no-check-formats")
request.addOption("--quiet")
@ -1161,8 +1174,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
metadataCommands.addOption("--parse-metadata", "%(album_artist,first_artist|)s:%(album_artist)s")
metadataCommands.addOption("--parse-metadata", "description:(?:.+?Released\\ on\\s*:\\s*(?P<dscrptn_year>\\d{4}))?")
metadataCommands.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P<meta_date>\\d+)")
metadataCommands.addOption("--parse-metadata", "%(release_year,release_date>%Y,upload_date>%Y)s:(?P<meta_date>\\d+)")
if (isPlaylistItem) {
metadataCommands.addOption("--parse-metadata", "%(track_number,playlist_index)d:(?P<track_number>\\d+)")
@ -1214,6 +1226,12 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
var cont = ""
val outputContainer = downloadItem.container
if (downloadItem.videoPreferences.compatibilityMode) {
request.addOption("--recode-video", "mp4")
request.addOption("--merge-output-format", "mp4/mkv")
request.addOption("--ppa", "VideoConvertor+ffmpeg_o:-c:v libx264 -c:a aac -profile:v baseline")
}
if(outputContainer.isNotEmpty() && outputContainer != "Default" && outputContainer != context.getString(
R.string.defaultValue) && supportedContainers.contains(outputContainer)){
cont = outputContainer
@ -1221,14 +1239,8 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
val cantRecode = listOf("avi")
if (downloadItem.videoPreferences.recodeVideo && !cantRecode.contains(cont)) {
request.addOption("--recode-video", outputContainer.lowercase())
}else{
if (downloadItem.videoPreferences.compatibilityMode) {
request.addOption("--recode-video", "mp4")
request.addOption("--merge-output-format", "mp4/mkv")
}
else {
request.addOption("--merge-output-format", outputContainer.lowercase())
}
}else if (!downloadItem.videoPreferences.compatibilityMode){
request.addOption("--merge-output-format", outputContainer.lowercase())
}
if (!listOf("webm", "avi", "flv", "gif").contains(outputContainer.lowercase())) {
@ -1258,6 +1270,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
} ?: f
}.ifBlank { "ba" }
val preferredAudioLanguage = sharedPreferences.getString("audio_language", "")!!
val preferDRCAudio = sharedPreferences.getBoolean("prefer_drc_audio", false)
if (downloadItem.videoPreferences.removeAudio) audioF = ""
var abrSort = ""
@ -1293,6 +1306,8 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
if (!f.contains("$videoF+ba")) {
if (preferredAudioLanguage.isNotEmpty()) {
f.append("$videoF+ba[language^=$preferredAudioLanguage]/")
} else if (preferDRCAudio) {
f.append("$videoF+ba[format_id$=-drc]/")
}else {
f.append("$videoF+ba/")
}
@ -1328,6 +1343,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co
.filter { it.isNotBlank() }
.ifEmpty {
val list = mutableListOf<String>()
if (preferDRCAudio) list.add("ba[format_id$=-drc]")
if (preferredAudioLanguage.isNotEmpty() && !downloadItem.videoPreferences.removeAudio) list.add("ba[language^=$preferredAudioLanguage]")
list.add(audioF)
list

View file

@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
<path android:fillColor="@android:color/white" android:pathData="M647,520L160,520L160,440L647,440L423,216L480,160L800,480L480,800L423,744L647,520Z"/>
</vector>

View file

@ -276,8 +276,7 @@
android:checked="true"
android:textSize="16sp"
android:textStyle="bold"
android:text="Use Visitor Data"
tools:ignore="HardcodedText" />
android:text="@string/visitor_data" />
<!-- <TextView-->
<!-- android:layout_width="wrap_content"-->

View file

@ -6,11 +6,6 @@
android:title="@string/delete_all_cookies"
app:showAsAction="never" />
<item
android:id="@+id/use_header"
android:title="@string/user_agent_header"
android:checkable="true"
app:showAsAction="never" />
<item
android:id="@+id/import_clipboard"

View file

@ -133,7 +133,7 @@
<string-array name="language_entries">
<item>System</item>
<item>@string/system</item>
<item>English</item>
<item>العربية</item>
<item>Azərbaycanca</item>
@ -1591,6 +1591,4 @@
<item>smallest</item>
<item>largest</item>
</string-array>
<string name="sponsorblock_hook">Hook</string>
</resources>

View file

@ -509,4 +509,5 @@
<string name="app_icon">App Icon</string>
<string name="show_quick_download_share_menu">Show option to download immediately in the share menu</string>
<string name="quick_download_title">Don\'t fetch data</string>
<string name="sponsorblock_hook">Hook</string>
</resources>

View file

@ -84,6 +84,14 @@
android:icon="@drawable/baseline_note_24"
android:key="no_check_certificates"
app:title="@string/no_check_certificates" />
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"
android:icon="@drawable/if_file_rename"
android:key="use_header"
app:title="@string/user_agent_header" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/misc">

View file

@ -211,11 +211,6 @@
/>
</PreferenceCategory>
<Preference
app:defaultValue=""
android:key="use_header"
app:isPreferenceVisible="false" />
<Preference
app:defaultValue=""
android:key="useragent_header"

View file

@ -294,6 +294,20 @@
app:summary="@string/preferred_format_id_summary"
app:title="@string/preferred_format_id" />
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"
app:icon="@drawable/baseline_delete_24"
app:key="remove_audio"
app:title="@string/remove_audio" />
<SwitchPreferenceCompat
android:widgetLayout="@layout/preferece_material_switch"
app:defaultValue="false"
app:icon="@drawable/ic_plus"
app:key="also_download_audio"
app:title="@string/also_download_audio" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/format">