summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-06-16 09:37:27 -0700
committerFuwn <[email protected]>2025-06-16 09:37:27 -0700
commitd292e582910c990cae8481c966366b34dc7041b3 (patch)
treefe11aa49917d793e363094644d6c1662886ece88
parentfeat: Development commit (diff)
downloadsora-testing-d292e582910c990cae8481c966366b34dc7041b3.tar.xz
sora-testing-d292e582910c990cae8481c966366b34dc7041b3.zip
feat: Development commit
-rw-r--r--Localizable.xcstrings6
-rw-r--r--Sora/Data/Booru/BooruManager.swift17
-rw-r--r--Sora/Data/Booru/Provider/BooruProviderCredentials.swift40
-rw-r--r--Sora/Data/Settings/SettingsManager.swift42
-rw-r--r--Sora/Views/MainView.swift7
-rw-r--r--Sora/Views/Settings/Section/SettingsProviderView.swift52
6 files changed, 160 insertions, 4 deletions
diff --git a/Localizable.xcstrings b/Localizable.xcstrings
index 590727c..c3f38df 100644
--- a/Localizable.xcstrings
+++ b/Localizable.xcstrings
@@ -25,6 +25,9 @@
"All" : {
},
+ "API Key" : {
+
+ },
"Are you sure you want to remove all bookmarks? This action cannot be undone." : {
},
@@ -412,6 +415,9 @@
},
"Uncategorised" : {
+ },
+ "User ID" : {
+
}
},
"version" : "1.0"
diff --git a/Sora/Data/Booru/BooruManager.swift b/Sora/Data/Booru/BooruManager.swift
index 12d96f0..ce61644 100644
--- a/Sora/Data/Booru/BooruManager.swift
+++ b/Sora/Data/Booru/BooruManager.swift
@@ -28,6 +28,7 @@ class BooruManager: ObservableObject {
.appendingPathComponent("\(BooruProvider.safebooru.asFileNameComponent)_tags.json")
private let pageCache = NSCache<NSString, BooruPageCacheEntry>() // swiftlint:disable:this legacy_objc_type
private let cacheDuration: TimeInterval = 300
+ private let credentials: BooruProviderCredentials?
// MARK: - Computed Properties
var tags: [String] {
@@ -42,10 +43,11 @@ class BooruManager: ObservableObject {
var canGoForwardInHistory: Bool { historyIndex < searchHistory.count - 1 }
// MARK: - Initialisation
- init(_ provider: BooruProvider) {
+ init(_ provider: BooruProvider, credentials: BooruProviderCredentials? = nil) {
self.provider = provider
self.flavor = BooruProviderFlavor(provider: provider)
self.domain = provider.domain
+ self.credentials = credentials
pageCache.countLimit = 50
pageCache.totalCostLimit = 50 * 1_024 * 1_024
@@ -226,9 +228,18 @@ class BooruManager: ObservableObject {
return URL(string: "https://\(domain)/post.xml?page=\(page)&limit=\(limit)&tags=\(tagString)")
case .gelbooru:
+ var urlString =
+ "https://\(domain)/index.php?page=dapi&s=post&q=index&pid=\(page)&limit=\(limit)&tags=\(tagString)"
+
+ if let validCredentials = credentials,
+ !validCredentials.apiKey.isEmpty,
+ validCredentials.userID != 0
+ {
+ urlString += "&api_key=\(validCredentials.apiKey)&user_id=\(validCredentials.userID)"
+ }
+
return URL(
- string:
- "https://\(domain)/index.php?page=dapi&s=post&q=index&pid=\(page)&limit=\(limit)&tags=\(tagString)"
+ string: urlString
)
}
}
diff --git a/Sora/Data/Booru/Provider/BooruProviderCredentials.swift b/Sora/Data/Booru/Provider/BooruProviderCredentials.swift
new file mode 100644
index 0000000..898201a
--- /dev/null
+++ b/Sora/Data/Booru/Provider/BooruProviderCredentials.swift
@@ -0,0 +1,40 @@
+import Foundation
+
+struct BooruProviderCredentials: Codable, Identifiable, Equatable {
+ let id: UUID
+ let provider: BooruProvider
+ var apiKey: String
+ var userID: Int
+
+ init(provider: BooruProvider, apiKey: String, userID: Int, id: UUID = UUID()) {
+ self.id = id
+ self.provider = provider
+ self.apiKey = apiKey
+ self.userID = userID
+ }
+
+ static func from(
+ // swiftlint:disable:next large_tuple
+ _ rawCredentials: [(provider: BooruProvider, apiKey: String, userID: Int)],
+ existingCredentials: [Self]
+ ) -> [Self] {
+ rawCredentials.map { credentials in
+ if let existingKey = existingCredentials.first(
+ where: { $0.provider == credentials.provider }
+ ) {
+ return Self(
+ provider: credentials.provider,
+ apiKey: credentials.apiKey,
+ userID: credentials.userID,
+ id: existingKey.id
+ )
+ }
+
+ return Self(
+ provider: credentials.provider,
+ apiKey: credentials.apiKey,
+ userID: credentials.userID
+ )
+ }
+ }
+}
diff --git a/Sora/Data/Settings/SettingsManager.swift b/Sora/Data/Settings/SettingsManager.swift
index 98ea00c..c824cff 100644
--- a/Sora/Data/Settings/SettingsManager.swift
+++ b/Sora/Data/Settings/SettingsManager.swift
@@ -60,6 +60,9 @@ class SettingsManager: ObservableObject { // swiftlint:disable:this type_body_l
@AppStorage("folders")
private var foldersData = Data()
+ @AppStorage("providerCredentials")
+ private var providerCredentialsData = Data()
+
// MARK: - Computed Properties
var bookmarks: [SettingsBookmark] {
get {
@@ -167,6 +170,45 @@ class SettingsManager: ObservableObject { // swiftlint:disable:this type_body_l
}
}
+ // MARK: Provider Credentials
+ var providerCredentials: [BooruProviderCredentials] {
+ get {
+ syncableData(
+ key: "providerAPIKeys",
+ localData: providerCredentialsData,
+ sort: { $0 },
+ identifier: { $0.id }
+ )
+ }
+
+ set {
+ let existingCredentials: [BooruProviderCredentials] =
+ Self.decode([BooruProviderCredentials].self, from: providerCredentialsData) ?? []
+ let rawCredentials = newValue.map { credentials in
+ (provider: credentials.provider, apiKey: credentials.apiKey, userID: credentials.userID)
+ }
+ let mergedCredentials = BooruProviderCredentials.from(
+ rawCredentials, existingCredentials: existingCredentials
+ )
+
+ syncableData(
+ key: "providerAPIKeys",
+ localData: $providerCredentialsData,
+ newValue: mergedCredentials,
+ sort: { $0 },
+ identifier: { $0.id }
+ )
+ }
+ }
+
+ var providerAPIKeys: [BooruProvider: String] {
+ Dictionary(uniqueKeysWithValues: providerCredentials.map { ($0.provider, $0.apiKey) })
+ }
+
+ var providerUserIDs: [BooruProvider: Int] {
+ Dictionary(uniqueKeysWithValues: providerCredentials.map { ($0.provider, $0.userID) })
+ }
+
// MARK: - Initialisation
init() {
syncObservation = NotificationCenter.default.addObserver(
diff --git a/Sora/Views/MainView.swift b/Sora/Views/MainView.swift
index c3a8c66..81cede8 100644
--- a/Sora/Views/MainView.swift
+++ b/Sora/Views/MainView.swift
@@ -21,6 +21,7 @@ struct MainView: View {
manager.selectedPost = nil
}
.onAppear(perform: initializeManager)
+ .onChange(of: settings.providerCredentials) { initializeManager() }
}
@ViewBuilder private var tabViewContent: some View {
@@ -90,7 +91,11 @@ struct MainView: View {
}
private func initializeManager() {
- manager = BooruManager(settings.preferredBooru)
+ manager = BooruManager(
+ settings.preferredBooru,
+ credentials: settings.providerCredentials
+ .first { $0.provider == settings.preferredBooru }
+ )
refreshTags()
diff --git a/Sora/Views/Settings/Section/SettingsProviderView.swift b/Sora/Views/Settings/Section/SettingsProviderView.swift
index 606fe64..82834b9 100644
--- a/Sora/Views/Settings/Section/SettingsProviderView.swift
+++ b/Sora/Views/Settings/Section/SettingsProviderView.swift
@@ -20,6 +20,33 @@ struct SettingsProviderView: View {
}
}
+ SecureField(
+ "API Key",
+ text: Binding(
+ get: { settings.providerAPIKeys[settings.preferredBooru] ?? "" },
+ set: { updateCredentials(apiKey: $0) }
+ )
+ )
+ .autocorrectionDisabled(true)
+
+ TextField(
+ "User ID",
+ text: Binding(
+ get: {
+ String(settings.providerUserIDs[settings.preferredBooru] ?? 0)
+ },
+ set: { newValue in
+ let userID = Int(newValue) ?? 0
+
+ updateCredentials(userID: userID)
+ }
+ )
+ )
+ .autocorrectionDisabled(true)
+ #if os(iOS)
+ .keyboardType(.numberPad)
+ #endif
+
Button("Add Custom Provider") {
showingCustomBooruSheet = true
}
@@ -145,6 +172,31 @@ struct SettingsProviderView: View {
return true
}
+ private func updateCredentials(apiKey: String? = nil, userID: Int? = nil) {
+ var allCredentials = settings.providerCredentials
+
+ if let index = allCredentials.firstIndex(where: { $0.provider == settings.preferredBooru }) {
+ let credentials = allCredentials[index]
+
+ allCredentials[index] = BooruProviderCredentials(
+ provider: credentials.provider,
+ apiKey: apiKey ?? credentials.apiKey,
+ userID: userID ?? credentials.userID,
+ id: credentials.id
+ )
+ } else {
+ allCredentials.append(
+ BooruProviderCredentials(
+ provider: settings.preferredBooru,
+ apiKey: apiKey ?? "",
+ userID: userID ?? 0
+ )
+ )
+ }
+
+ settings.providerCredentials = allCredentials
+ }
+
private func removeCustomProviderButtonContent(_ provider: BooruProviderCustom) -> some View {
Button("Remove Custom Provider") {
settings.customProviders.removeAll { $0.id == provider.id }