mirror of
https://git.ryujinx.app/kenji-nx/ryujinx.git
synced 2025-12-13 04:37:02 +00:00
feat: Refactor autoloadContent to streamline directory scanning for NSPs
This commit is contained in:
parent
42fa39672b
commit
4e94f4731b
1 changed files with 65 additions and 75 deletions
|
|
@ -15,8 +15,8 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import org.kenjinx.android.KenjinxNative
|
||||
import org.kenjinx.android.KeyboardMode
|
||||
import org.kenjinx.android.MainActivity
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
|
@ -125,7 +125,7 @@ class HomeViewModel(
|
|||
|
||||
// Helper function to compare update versions from filenames
|
||||
// Returns true if newPath represents a newer version than currentPath
|
||||
private fun shouldSelectNewerUpdate(currentPath: String, newPath: String, allPaths: List<String>): Boolean {
|
||||
private fun shouldSelectNewerUpdate(currentPath: String, newPath: String): Boolean {
|
||||
// Extract version numbers from filenames using regex pattern [vXXXXXX]
|
||||
val versionPattern = Regex("\\[v(\\d+)]")
|
||||
|
||||
|
|
@ -135,21 +135,13 @@ class HomeViewModel(
|
|||
return newVersion > currentVersion
|
||||
}
|
||||
|
||||
// Scans configured directories for NSPs containing DLCs/Updates and associates them to known titles.
|
||||
// Scans configured directory for NSPs containing DLCs/Updates and associates them to known titles.
|
||||
private fun autoloadContent() {
|
||||
val prefs = sharedPref ?: return
|
||||
|
||||
// Prefer a single, explicitly selected updates/DLC folder (updatesFolder). Fallback to legacy autoloadDirs.
|
||||
val updatesFolder = prefs.getString("updatesFolder", "") ?: ""
|
||||
val dirs: List<String> = if (updatesFolder.isNotBlank()) {
|
||||
listOf(updatesFolder.trim())
|
||||
} else {
|
||||
// Legacy: semicolon-separated list under key autoloadDirs
|
||||
val raw = prefs.getString("autoloadDirs", "") ?: ""
|
||||
if (raw.isBlank()) emptyList() else raw.split(';').map { it.trim() }.filter { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
if (dirs.isEmpty()) return
|
||||
if (updatesFolder.isEmpty()) return
|
||||
|
||||
// Build a map of titleId -> helpers
|
||||
val gamesByTitle = loadedCache.mapNotNull { g ->
|
||||
|
|
@ -160,85 +152,83 @@ class HomeViewModel(
|
|||
var updatesAdded = 0
|
||||
var dlcAdded = 0
|
||||
|
||||
for (dir in dirs) {
|
||||
val base = java.io.File(dir)
|
||||
if (!base.exists() || !base.isDirectory) continue
|
||||
val base = File(updatesFolder)
|
||||
if (!base.exists() || !base.isDirectory) return
|
||||
|
||||
base.walkTopDown().forEach fileLoop@{ f ->
|
||||
if (!f.isFile) return@fileLoop
|
||||
val name = f.name.lowercase(Locale.getDefault())
|
||||
if (!name.endsWith(".nsp")) return@fileLoop
|
||||
base.walkTopDown().forEach fileLoop@{ f ->
|
||||
if (!f.isFile) return@fileLoop
|
||||
val name = f.name.lowercase(Locale.getDefault())
|
||||
if (!name.endsWith(".nsp")) return@fileLoop
|
||||
|
||||
// Extract title ID from filename
|
||||
val tidPattern = Regex("\\[([0-9a-fA-F]{16})]")
|
||||
val tidMatch = tidPattern.find(name) ?: return@fileLoop
|
||||
val fileTid = tidMatch.groupValues[1].lowercase(Locale.getDefault())
|
||||
// Extract title ID from filename
|
||||
val tidPattern = Regex("\\[([0-9a-fA-F]{16})]")
|
||||
val tidMatch = tidPattern.find(name) ?: return@fileLoop
|
||||
val fileTid = tidMatch.groupValues[1].lowercase(Locale.getDefault())
|
||||
|
||||
// Try to find DLC content for all games
|
||||
var isDlc = false
|
||||
try {
|
||||
for ((_, tidOrig) in gamesByTitle) {
|
||||
val contents = KenjinxNative.deviceGetDlcContentList(f.absolutePath, tidOrig.toLong(16))
|
||||
// Try to find DLC content for all games
|
||||
var isDlc = false
|
||||
try {
|
||||
for ((_, tidOrig) in gamesByTitle) {
|
||||
val contents = KenjinxNative.deviceGetDlcContentList(f.absolutePath, tidOrig.toLong(16))
|
||||
|
||||
if (contents.isNotEmpty()) {
|
||||
isDlc = true
|
||||
val containerPath = f.absolutePath
|
||||
val vm = DlcViewModel(tidOrig)
|
||||
val already = vm.data?.any { it.path == containerPath } == true
|
||||
if (contents.isNotEmpty()) {
|
||||
isDlc = true
|
||||
val containerPath = f.absolutePath
|
||||
val vm = DlcViewModel(tidOrig)
|
||||
val already = vm.data?.any { it.path == containerPath } == true
|
||||
|
||||
if (!already) {
|
||||
val container = DlcContainerList(containerPath)
|
||||
for (content in contents) {
|
||||
container.dlc_nca_list.add(
|
||||
DlcContainer(
|
||||
true,
|
||||
KenjinxNative.deviceGetDlcTitleId(containerPath, content).toLong(16),
|
||||
content
|
||||
)
|
||||
if (!already) {
|
||||
val container = DlcContainerList(containerPath)
|
||||
for (content in contents) {
|
||||
container.dlc_nca_list.add(
|
||||
DlcContainer(
|
||||
true,
|
||||
KenjinxNative.deviceGetDlcTitleId(containerPath, content).toLong(16),
|
||||
content
|
||||
)
|
||||
}
|
||||
vm.data?.add(container)
|
||||
vm.saveChanges()
|
||||
dlcAdded++
|
||||
)
|
||||
}
|
||||
break
|
||||
vm.data?.add(container)
|
||||
vm.saveChanges()
|
||||
dlcAdded++
|
||||
}
|
||||
break
|
||||
}
|
||||
} catch (_: Throwable) { }
|
||||
|
||||
if (isDlc) return@fileLoop
|
||||
|
||||
// Treat as Title Update - convert update ID to base ID
|
||||
// Update title IDs end in 800, base game IDs end in 000
|
||||
val baseTid = if (fileTid.endsWith("800")) {
|
||||
fileTid.substring(0, fileTid.length - 3) + "000"
|
||||
} else {
|
||||
fileTid
|
||||
}
|
||||
} catch (_: Throwable) { }
|
||||
|
||||
val originalTid = gamesByTitle[baseTid]
|
||||
if (originalTid != null) {
|
||||
val vm = TitleUpdateViewModel(originalTid)
|
||||
val path = f.absolutePath
|
||||
val exists = (vm.data?.paths?.contains(path) == true)
|
||||
if (isDlc) return@fileLoop
|
||||
|
||||
if (!exists) {
|
||||
// Add the new update path
|
||||
vm.data?.paths?.add(path)
|
||||
// Treat as Title Update - convert update ID to base ID
|
||||
// Update title IDs end in 800, base game IDs end in 000
|
||||
val baseTid = if (fileTid.endsWith("800")) {
|
||||
fileTid.substring(0, fileTid.length - 3) + "000"
|
||||
} else {
|
||||
fileTid
|
||||
}
|
||||
|
||||
// Auto-select this update if it's newer than the currently selected one
|
||||
// or if no update is currently selected
|
||||
val currentSelected = vm.data?.selected ?: ""
|
||||
val shouldSelect = currentSelected.isEmpty() ||
|
||||
shouldSelectNewerUpdate(currentSelected, path, vm.data?.paths ?: mutableListOf())
|
||||
val originalTid = gamesByTitle[baseTid]
|
||||
if (originalTid != null) {
|
||||
val vm = TitleUpdateViewModel(originalTid)
|
||||
val path = f.absolutePath
|
||||
val exists = (vm.data?.paths?.contains(path) == true)
|
||||
|
||||
if (shouldSelect) {
|
||||
vm.data?.selected = path
|
||||
}
|
||||
if (!exists) {
|
||||
// Add the new update path
|
||||
vm.data?.paths?.add(path)
|
||||
|
||||
vm.saveChanges()
|
||||
updatesAdded++
|
||||
// Auto-select this update if it's newer than the currently selected one
|
||||
// or if no update is currently selected
|
||||
val currentSelected = vm.data?.selected ?: ""
|
||||
val shouldSelect = currentSelected.isEmpty() ||
|
||||
shouldSelectNewerUpdate(currentSelected, path)
|
||||
|
||||
if (shouldSelect) {
|
||||
vm.data?.selected = path
|
||||
}
|
||||
|
||||
vm.saveChanges()
|
||||
updatesAdded++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue