summaryrefslogtreecommitdiff
path: root/Sora/Data
diff options
context:
space:
mode:
Diffstat (limited to 'Sora/Data')
-rw-r--r--Sora/Data/Booru/BooruManager.swift28
-rw-r--r--Sora/Data/Booru/BooruProvider.swift1
-rw-r--r--Sora/Data/Booru/Post/BooruPostXMLParser.swift227
3 files changed, 179 insertions, 77 deletions
diff --git a/Sora/Data/Booru/BooruManager.swift b/Sora/Data/Booru/BooruManager.swift
index 3c9c5ca..45a2240 100644
--- a/Sora/Data/Booru/BooruManager.swift
+++ b/Sora/Data/Booru/BooruManager.swift
@@ -9,7 +9,7 @@ class BooruManager: ObservableObject {
@Published var searchText = ""
@Published var endOfData: Bool = false
private var currentTask: Task<Void, Never>?
- let provider: BooruProvider?
+ let provider: BooruProvider
var tags: [String] {
if searchText.isEmpty {
return []
@@ -26,7 +26,7 @@ class BooruManager: ObservableObject {
@Published var selectedPost: BooruPost?
#endif
- init(_ provider: BooruProvider? = nil) {
+ init(_ provider: BooruProvider) {
self.provider = provider
fetchAllTags()
@@ -35,7 +35,6 @@ class BooruManager: ObservableObject {
func fetchPosts(page: Int = 1, limit: Int = 100, tags: [String] = [], replace: Bool = false) async
{
guard !isLoading else { return }
- guard provider != nil else { return }
currentTask?.cancel()
@@ -63,7 +62,10 @@ class BooruManager: ObservableObject {
if Task.isCancelled { return }
DispatchQueue.main.async {
- let newPosts = Array(Set(BooruPostXMLParser(data: data).parse())).sorted { $0.id > $1.id }
+ let newPosts = Array(Set(BooruPostXMLParser(data: data, provider: self.provider).parse()))
+ .sorted { lhs, rhs in
+ lhs.id > rhs.id
+ }
if newPosts.isEmpty {
self.endOfData = true
@@ -102,8 +104,6 @@ class BooruManager: ObservableObject {
}
func fetchAllTags(limit: Int = 100_000) {
- guard provider != nil else { return }
-
Task {
guard let url = urlForTags(limit: limit) else { return }
@@ -129,6 +129,13 @@ class BooruManager: ObservableObject {
URL(string: "https://\(domain)/post.xml?page=\(page)&limit=\(limit)&tags=\(tagString)")
}
+ private func gelbooruURL(domain: String, page: Int, limit: Int, tagString: String) -> URL? {
+ URL(
+ string:
+ "https://\(domain)/index.php?page=dapi&s=post&q=index&pid=\(page)&limit=\(limit)&tags=\(tagString)"
+ )
+ }
+
private func urlForPosts(page: Int, limit: Int, tags: [String]) -> URL? {
let tagString = tags.joined(separator: "+")
@@ -143,13 +150,10 @@ class BooruManager: ObservableObject {
return moebooruURL(domain: "sakugabooru.com", page: page, limit: limit, tagString: tagString)
case .safebooru:
- return URL(
- string:
- "https://safebooru.org/index.php?page=dapi&s=post&q=index&pid=\(page)&limit=\(limit)&tags=\(tagString)"
- )
+ return gelbooruURL(domain: "safebooru.org", page: page, limit: limit, tagString: tagString)
- default:
- return nil
+ case .gelbooru:
+ return gelbooruURL(domain: "gelbooru.com", page: page, limit: limit, tagString: tagString)
}
}
diff --git a/Sora/Data/Booru/BooruProvider.swift b/Sora/Data/Booru/BooruProvider.swift
index 2aa9238..3a743ec 100644
--- a/Sora/Data/Booru/BooruProvider.swift
+++ b/Sora/Data/Booru/BooruProvider.swift
@@ -1,4 +1,5 @@
enum BooruProvider: String, CaseIterable, Decodable, Encodable {
+ case gelbooru = "Gelbooru"
case konachan = "Konachan.com"
case safebooru = "Safebooru"
case sakugabooru = "sakugabooru"
diff --git a/Sora/Data/Booru/Post/BooruPostXMLParser.swift b/Sora/Data/Booru/Post/BooruPostXMLParser.swift
index d316177..41ad25d 100644
--- a/Sora/Data/Booru/Post/BooruPostXMLParser.swift
+++ b/Sora/Data/Booru/Post/BooruPostXMLParser.swift
@@ -4,9 +4,14 @@ class BooruPostXMLParser: NSObject, XMLParserDelegate {
private var posts: [BooruPost] = []
private var currentPost: BooruPost?
private var parser: XMLParser
+ private let provider: BooruProvider
+ private var currentPostData: [String: String] = [:]
+ private var currentElementName: String?
+ private var currentText: String = ""
- init(data: Data) {
+ init(data: Data, provider: BooruProvider) {
parser = XMLParser(data: data)
+ self.provider = provider
super.init()
@@ -20,82 +25,174 @@ class BooruPostXMLParser: NSObject, XMLParserDelegate {
}
func parser(
- _: XMLParser,
+ _ parser: XMLParser, // swiftlint:disable:this unused_parameter
didStartElement elementName: String,
- namespaceURI _: String?,
- qualifiedName _: String?,
+ namespaceURI: String?, // swiftlint:disable:this unused_parameter
+ qualifiedName qName: String?, // swiftlint:disable:this unused_parameter
attributes attributeDict: [String: String] = [:]
) {
- if elementName == "post" {
- guard let id = attributeDict["id"],
- let heightStr = attributeDict["height"],
- let height = Int(heightStr),
- let score = attributeDict["score"],
- let fileUrl = attributeDict["file_url"],
- let parentId = attributeDict["parent_id"],
- let sampleUrl = attributeDict["sample_url"],
- let sampleWidthStr = attributeDict["sample_width"],
- let sampleWidth = Int(sampleWidthStr),
- let sampleHeightStr = attributeDict["sample_height"],
- let sampleHeight = Int(sampleHeightStr),
- let previewUrl = attributeDict["preview_url"],
- let rating = attributeDict["rating"],
- let tags = attributeDict["tags"],
- let widthStr = attributeDict["width"],
- let width = Int(widthStr),
- let change = attributeDict["change"],
- let md5 = attributeDict["md5"],
- let creatorId = attributeDict["creator_id"],
- let hasChildrenStr = attributeDict["has_children"],
- let createdAt = attributeDict["created_at"],
- let status = attributeDict["status"],
- let source = attributeDict["source"],
- let previewWidthStr = attributeDict["preview_width"],
- let previewWidth = Int(previewWidthStr),
- let previewHeightStr = attributeDict["preview_height"],
- let previewHeight = Int(previewHeightStr)
- else {
- return
+ if provider == .gelbooru {
+ if elementName == "post" {
+ currentPostData = [:]
+ } else {
+ currentElementName = elementName
+ currentText = ""
}
+ } else {
+ if elementName == "post" {
+ guard let id = attributeDict["id"],
+ let heightStr = attributeDict["height"],
+ let height = Int(heightStr),
+ let score = attributeDict["score"],
+ let fileUrl = attributeDict["file_url"],
+ let parentId = attributeDict["parent_id"],
+ let sampleUrl = attributeDict["sample_url"],
+ let sampleWidthStr = attributeDict["sample_width"],
+ let sampleWidth = Int(sampleWidthStr),
+ let sampleHeightStr = attributeDict["sample_height"],
+ let sampleHeight = Int(sampleHeightStr),
+ let previewUrl = attributeDict["preview_url"],
+ let rating = attributeDict["rating"],
+ let tags = attributeDict["tags"],
+ let widthStr = attributeDict["width"],
+ let width = Int(widthStr),
+ let change = attributeDict["change"],
+ let md5 = attributeDict["md5"],
+ let creatorId = attributeDict["creator_id"],
+ let hasChildrenStr = attributeDict["has_children"],
+ let createdAt = attributeDict["created_at"],
+ let status = attributeDict["status"],
+ let source = attributeDict["source"],
+ let previewWidthStr = attributeDict["preview_width"],
+ let previewWidth = Int(previewWidthStr),
+ let previewHeightStr = attributeDict["preview_height"],
+ let previewHeight = Int(previewHeightStr)
+ else {
+ return
+ }
+
+ currentPost = BooruPost(
+ id: id,
+ height: height,
+ score: score,
+ fileURL: URL(string: fileUrl)!,
+ parentID: parentId,
+ sampleURL: URL(string: sampleUrl)!,
+ sampleWidth: sampleWidth,
+ sampleHeight: sampleHeight,
+ previewURL: URL(string: previewUrl)!,
+ rating: BooruRating(rating),
+ tags: tags.components(separatedBy: " ").filter { !$0.isEmpty },
+ width: width,
+ change: change,
+ md5: md5,
+ creatorID: creatorId,
+ hasChildren: hasChildrenStr == "true",
+ createdAt: parseCreatedAt(createdAt)!,
+ status: status,
+ source: source,
+ hasNotes: (attributeDict["has_notes"] ?? "false") == "true",
+ hasComments: (attributeDict["has_comments"] ?? "false") == "true",
+ previewWidth: previewWidth,
+ previewHeight: previewHeight
+ )
+ }
+ }
+ }
- currentPost = BooruPost(
- id: id,
- height: height,
- score: score,
- fileURL: URL(string: fileUrl)!,
- parentID: parentId,
- sampleURL: URL(string: sampleUrl)!,
- sampleWidth: sampleWidth,
- sampleHeight: sampleHeight,
- previewURL: URL(string: previewUrl)!,
- rating: BooruRating(rating),
- tags: tags.components(separatedBy: " ").filter { !$0.isEmpty },
- width: width,
- change: change,
- md5: md5,
- creatorID: creatorId,
- hasChildren: hasChildrenStr == "true",
- createdAt: parseCreatedAt(createdAt)!,
- status: status,
- source: source,
- hasNotes: (attributeDict["has_notes"] ?? "false") == "true",
- hasComments: (attributeDict["has_comments"] ?? "false") == "true",
- previewWidth: previewWidth,
- previewHeight: previewHeight
- )
+ func parser(
+ _ parser: XMLParser, // swiftlint:disable:this unused_parameter
+ foundCharacters string: String
+ ) {
+ if provider == .gelbooru, currentElementName != nil {
+ currentText += string
}
}
func parser(
- _: XMLParser,
+ _ parser: XMLParser, // swiftlint:disable:this unused_parameter
didEndElement elementName: String,
- namespaceURI _: String?,
- qualifiedName _: String?
+ namespaceURI: String?, // swiftlint:disable:this unused_parameter
+ qualifiedName qName: String? // swiftlint:disable:this unused_parameter
) {
- if elementName == "post", let post = currentPost {
- posts.append(post)
+ if provider == .gelbooru {
+ if elementName == "post" {
+ guard let id = currentPostData["id"],
+ let heightStr = currentPostData["height"],
+ let height = Int(heightStr),
+ let score = currentPostData["score"],
+ let fileUrlStr = currentPostData["file_url"],
+ let fileUrl = URL(string: fileUrlStr),
+ let parentId = currentPostData["parent_id"],
+ let sampleUrlStr = currentPostData["sample_url"],
+ let sampleUrl = URL(string: sampleUrlStr),
+ let sampleWidthStr = currentPostData["sample_width"],
+ let sampleWidth = Int(sampleWidthStr),
+ let sampleHeightStr = currentPostData["sample_height"],
+ let sampleHeight = Int(sampleHeightStr),
+ let previewUrlStr = currentPostData["preview_url"],
+ let previewUrl = URL(string: previewUrlStr),
+ let rating = currentPostData["rating"],
+ let tagsString = currentPostData["tags"],
+ let widthStr = currentPostData["width"],
+ let width = Int(widthStr),
+ let change = currentPostData["change"],
+ let md5 = currentPostData["md5"],
+ let creatorId = currentPostData["creator_id"],
+ let hasChildrenStr = currentPostData["has_children"],
+ let createdAtStr = currentPostData["created_at"],
+ let createdAt = parseCreatedAt(createdAtStr),
+ let status = currentPostData["status"],
+ let source = currentPostData["source"],
+ let previewWidthStr = currentPostData["preview_width"],
+ let previewWidth = Int(previewWidthStr),
+ let previewHeightStr = currentPostData["preview_height"],
+ let previewHeight = Int(previewHeightStr)
+ else {
+ return
+ }
+
+ posts.append(
+ BooruPost(
+ id: id,
+ height: height,
+ score: score,
+ fileURL: fileUrl,
+ parentID: parentId,
+ sampleURL: sampleUrl,
+ sampleWidth: sampleWidth,
+ sampleHeight: sampleHeight,
+ previewURL: previewUrl,
+ rating: BooruRating(rating),
+ tags: tagsString.components(separatedBy: CharacterSet.whitespacesAndNewlines)
+ .filter { !$0.isEmpty },
+ width: width,
+ change: change,
+ md5: md5,
+ creatorID: creatorId,
+ hasChildren: hasChildrenStr == "true",
+ createdAt: createdAt,
+ status: status,
+ source: source,
+ hasNotes: (currentPostData["has_notes"] ?? "false") == "true",
+ hasComments: (currentPostData["has_comments"] ?? "false") == "true",
+ previewWidth: previewWidth,
+ previewHeight: previewHeight
+ )
+ )
+ } else if let currentElement = currentElementName {
+ currentPostData[currentElement] = currentText.trimmingCharacters(
+ in: .whitespacesAndNewlines
+ )
+ currentElementName = nil
+ currentText = ""
+ }
+ } else {
+ if elementName == "post", let post = currentPost {
+ posts.append(post)
- currentPost = nil
+ currentPost = nil
+ }
}
}