diff options
Diffstat (limited to 'Sora/Data/Booru')
| -rw-r--r-- | Sora/Data/Booru/BooruManager.swift | 40 | ||||
| -rw-r--r-- | Sora/Data/Booru/Tag/GelbooruAutocompleteTagParser.swift | 83 |
2 files changed, 104 insertions, 19 deletions
diff --git a/Sora/Data/Booru/BooruManager.swift b/Sora/Data/Booru/BooruManager.swift index 8f055af..0909885 100644 --- a/Sora/Data/Booru/BooruManager.swift +++ b/Sora/Data/Booru/BooruManager.swift @@ -309,9 +309,13 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng guard !Task.isCancelled else { return [] } let parsedTags = - flavor == .danbooru - ? DanbooruTagParser(data: data).parse() - : BooruTagXMLParser(data: data).parse() + if flavor == .danbooru { + DanbooruTagParser(data: data).parse() + } else if flavor == .gelbooru, provider != .safebooru { + GelbooruAutocompleteTagParser(data: data).parse() + } else { + BooruTagXMLParser(data: data).parse() + } return parsedTags.sorted { $0.count > $1.count } } catch { @@ -500,24 +504,22 @@ class BooruManager: ObservableObject { // swiftlint:disable:this type_body_leng components.host = domain components.path = "/index.php" - var queryItems = [ - URLQueryItem(name: "page", value: "dapi"), - URLQueryItem(name: "s", value: "tag"), - URLQueryItem(name: "q", value: "index"), - URLQueryItem(name: "name_pattern", value: "%\(name)%"), - URLQueryItem(name: "orderby", value: "count"), - ] - - if let validCredentials = credentials, - !validCredentials.apiKey.isEmpty, - validCredentials.userID != 0 - { - queryItems.append(URLQueryItem(name: "api_key", value: validCredentials.apiKey)) - queryItems.append(URLQueryItem(name: "user_id", value: String(validCredentials.userID))) + if provider == .safebooru { + components.queryItems = [ + URLQueryItem(name: "page", value: "dapi"), + URLQueryItem(name: "s", value: "tag"), + URLQueryItem(name: "q", value: "index"), + URLQueryItem(name: "name_pattern", value: "%\(name)%"), + URLQueryItem(name: "orderby", value: "count"), + ] + } else { + components.queryItems = [ + URLQueryItem(name: "page", value: "autocomplete2"), + URLQueryItem(name: "type", value: "tag_query"), + URLQueryItem(name: "term", value: name), + ] } - components.queryItems = queryItems - return components.url case .danbooru: diff --git a/Sora/Data/Booru/Tag/GelbooruAutocompleteTagParser.swift b/Sora/Data/Booru/Tag/GelbooruAutocompleteTagParser.swift new file mode 100644 index 0000000..c69cd9b --- /dev/null +++ b/Sora/Data/Booru/Tag/GelbooruAutocompleteTagParser.swift @@ -0,0 +1,83 @@ +import Foundation + +nonisolated class GelbooruAutocompleteTagParser { + private let data: Data + + init(data: Data) { + self.data = data + } + + func parse() -> [BooruTag] { + do { + guard let decodedTags = try JSONSerialization.jsonObject(with: data) as? [[String: Any]] else { + debugPrint("GelbooruAutocompleteTagParser.parse: failed to decode top-level tag array.") + + return [] + } + + var parsedTags: [BooruTag] = [] + var droppedRecordCount = 0 + + parsedTags.reserveCapacity(decodedTags.count) + + for tag in decodedTags { + guard let name = tag["value"] as? String, !name.isEmpty else { + droppedRecordCount += 1 + + continue + } + + let count: Int + + if let postCount = tag["post_count"] as? String { + count = Int(postCount) ?? 0 + } else if let postCount = tag["post_count"] as? Int { + count = postCount + } else { + count = 0 + } + + parsedTags.append( + BooruTag( + id: name, + name: name, + count: count, + type: tagType(for: tag["category"] as? String), + ambiguous: false + ) + ) + } + + if droppedRecordCount > 0 { + debugPrint( + "GelbooruAutocompleteTagParser.parse: dropped \(droppedRecordCount) malformed records while decoding tags." + ) + } + + return parsedTags + } catch { + debugPrint("GelbooruAutocompleteTagParser.parse: failed to decode response: \(error)") + + return [] + } + } + + private func tagType(for category: String?) -> Int { + switch category?.lowercased() { + case "artist": + 1 + + case "copyright": + 3 + + case "character": + 4 + + case "metadata", "meta": + 5 + + default: + 0 + } + } +} |