Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GameImporter Rewrite #2358

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e62d74d
first version of game importer queue screen - not hooked up to actual…
proskd Nov 3, 2024
78b1e7b
broke apart game importer files into smaller extensions in preparatio…
proskd Nov 4, 2024
9011703
huge WIP refactor of GameImporter
proskd Nov 6, 2024
a2c602a
Adds a construct for ImportQueueItem that will support CDROMs - an Im…
proskd Nov 6, 2024
8294179
implement queue pre-sort functions that ensure proper parenting to re…
proskd Nov 7, 2024
73dce60
bunch more cleanup, extraction to some smaller classes. almost there…
proskd Nov 7, 2024
21cef9c
Added artwork importer code to try and handle artwork properly.
proskd Nov 7, 2024
470bf55
[For Now] - expose the concept of getting artwork via the game import…
proskd Nov 7, 2024
9805f4e
commenting out some code for now that we need to. update per the new …
proskd Nov 7, 2024
f154a77
don't forget to set valid systems when determined on the import item
proskd Nov 7, 2024
1405996
make sure we move rom to correct directory and not an extra directory
proskd Nov 7, 2024
52c0f6a
skip hidden files on importer
proskd Nov 7, 2024
3909ec9
Fix toolbar items for game import status view
proskd Nov 7, 2024
8cfa524
fixed some systems detection, simplified to allow a list when we can'…
proskd Nov 8, 2024
658565b
conflicts now detected properly and able to select a chosen system to…
proskd Nov 8, 2024
bc64ace
start to add support for BIOS import processing
proskd Nov 8, 2024
b1ec580
fixes another case where looking up in openvgb would fail
proskd Nov 8, 2024
0c3c399
bios file copy works, but crashing on finalizing the import
proskd Nov 8, 2024
23485fa
removing auto-import start to slow things down
proskd Nov 9, 2024
c2fac65
include handling for multi-bin cue files (not tested yet)
proskd Nov 9, 2024
58fc84d
fixes some issues with duplicate queue item detection (adds some unit…
proskd Nov 9, 2024
82db386
adds a lock to prevent re-entry and duplicate adds to the importqueue
proskd Nov 10, 2024
ab29bb1
ImportStatus ui shows number of systems for conflict file, correct sy…
proskd Nov 11, 2024
f20bbb3
[kinda hacky but] dismiss the import status view before showing the i…
proskd Nov 11, 2024
374ce6a
remove system from view because realm crashes
proskd Nov 11, 2024
90e5a64
fixes pull to referesh
proskd Nov 11, 2024
5eaafc4
Fix game more info flow and (untested) db migration
proskd Nov 11, 2024
d5d423d
swipe to delete works now
proskd Nov 11, 2024
2ea4cf1
fixes a realm threading crash when importing roms into the DB
proskd Nov 11, 2024
b213e74
adds in auto-start for the queue after the processing of files for ad…
proskd Nov 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -365,68 +365,6 @@ public extension PVEmulatorConfiguration {
}
}
}

class func cmpSpecialExt(obj1Extension: String, obj2Extension: String) -> Bool {
if obj1Extension == "m3u" && obj2Extension != "m3u" {
return obj1Extension > obj2Extension
} else if obj1Extension == "m3u" {
return false
} else if obj2Extension == "m3u" {
return true
}
if Extensions.artworkExtensions.contains(obj1Extension) {
return false
} else if Extensions.artworkExtensions.contains(obj2Extension) {
return true
}
return obj1Extension > obj2Extension
}

class func cmp(obj1: URL, obj2: URL) -> Bool {
let obj1Filename = obj1.lastPathComponent
let obj2Filename = obj2.lastPathComponent
let obj1Extension = obj1.pathExtension.lowercased()
let obj2Extension = obj2.pathExtension.lowercased()
let name1=PVEmulatorConfiguration.stripDiscNames(fromFilename: obj1Filename)
let name2=PVEmulatorConfiguration.stripDiscNames(fromFilename: obj2Filename)
if name1 == name2 {
// Standard sort
if obj1Extension == obj2Extension {
return obj1Filename < obj2Filename
}
return obj1Extension > obj2Extension
} else {
return name1 < name2
}
}

class func sortImportURLs(urls: [URL]) -> [URL] {
var ext:[String:[URL]] = [:]
// separate array by file extension
urls.forEach({ (url) in
if var urls = ext[url.pathExtension.lowercased()] {
urls.append(url)
ext[url.pathExtension.lowercased()]=urls
} else {
ext[url.pathExtension.lowercased()]=[url]
}
})
// sort
var sorted: [URL] = []
ext.keys
.sorted(by: cmpSpecialExt)
.forEach {
if let values = ext[$0] {
let values = values.sorted { (obj1, obj2) -> Bool in
return cmp(obj1: obj1, obj2: obj2)
}
sorted.append(contentsOf: values)
ext[$0] = values
}
}
VLOG(sorted.map { $0.lastPathComponent }.joined(separator: ", "))
return sorted
}
}

// MARK: System queries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ public extension RomDatabase {
game.title = title
if game.releaseID == nil || game.releaseID!.isEmpty {
ILOG("Game isn't already matched, going to try to re-match after a rename")
GameImporter.shared.lookupInfo(for: game, overwrite: false)
//TODO: figure out when this happens and fix
//GameImporter.shared.lookupInfo(for: game, overwrite: false)
}
}
} catch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ public enum GameImporterError: Error, Sendable {
case systemNotDetermined
case failedToMoveCDROM(Error)
case failedToMoveROM(Error)
case unsupportedFile
case noBIOSMatchForBIOSFileType
case unsupportedCDROMFile
case incorrectDestinationURL
case conflictDetected
}

This file was deleted.

118 changes: 118 additions & 0 deletions PVLibrary/Sources/PVLibrary/Importer/Models/ImportQueueItem.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// ImportStatus.swift
// PVLibrary
//
// Created by David Proskin on 11/3/24.
//

import SwiftUI
import PVPrimitives

// Enum to define the possible statuses of each import
public enum ImportStatus: String {
case queued
case processing
case success
case failure
case conflict // Indicates additional action needed by user after successful import

public var description: String {
switch self {
case .queued: return "Queued"
case .processing: return "Processing"
case .success: return "Completed"
case .failure: return "Failed"
case .conflict: return "Conflict"
}
}

public var color: Color {
switch self {
case .queued: return .gray
case .processing: return .blue
case .success: return .green
case .failure: return .red
case .conflict: return .yellow
}
}
}

// Enum to define file types for each import
public enum FileType {
case bios, artwork, game, cdRom, unknown
}

// Enum to track processing state
public enum ProcessingState {
case idle
case processing
}

// ImportItem model to hold each file's metadata and progress
@Observable
public class ImportQueueItem: Identifiable, ObservableObject {
public let id = UUID()
public var url: URL
public var fileType: FileType
public var systems: [PVSystem] // Can be set to the specific system type
public var userChosenSystem: PVSystem?
public var destinationUrl: URL?

//this is used when a single import has child items - e.g., m3u, cue, directory
public var childQueueItems:[ImportQueueItem]

// Observable status for individual imports
public var status: ImportStatus = .queued

public init(url: URL, fileType: FileType = .unknown) {
self.url = url
self.fileType = fileType
self.systems = []
self.userChosenSystem = nil
self.childQueueItems = []
}

public var md5: String? {
if let cached = cache.md5 {
return cached
} else {
let computed = FileManager.default.md5ForFile(atPath: url.path, fromOffset: 0)
cache.md5 = computed
return computed
}
}

// Store a cache in a nested class.
// The struct only contains a reference to the class, not the class itself,
// so the struct cannot prevent the class from mutating.
private final class Cache: Codable {
var md5: String?
}

public func targetSystem() -> PVSystem? {
guard !systems.isEmpty else {
return nil
}

if (systems.count == 1) {
return systems.first!
}

if let chosenSystem = userChosenSystem {

var target:PVSystem? = nil

for system in systems {
if (chosenSystem.identifier == system.identifier) {
target = system
}
}

return target
}

return nil
}

private var cache = Cache()
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

enum MatchHashType: String, Codable, Equatable, Hashable, Sendable {
package enum MatchHashType: String, Codable, Equatable, Hashable, Sendable {
case MD5
case CRC
case SHA1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import Foundation

enum MatchType: Sendable {
package enum MatchType: Sendable {
case byExtension
case byHash(MatchHashType)
case byFolder
Expand Down
Loading
Loading