summaryrefslogtreecommitdiff
path: root/Sora/Data/Booru/Post
diff options
context:
space:
mode:
authorFuwn <[email protected]>2025-02-24 00:39:40 -0800
committerFuwn <[email protected]>2025-02-24 00:39:40 -0800
commit65d76a2b4393f4addb9dc66e0565cb4fd137be71 (patch)
treecc45f72f059f6a404f700a7362619516a3b1cf26 /Sora/Data/Booru/Post
parentfeat: Development commit (diff)
downloadsora-testing-65d76a2b4393f4addb9dc66e0565cb4fd137be71.tar.xz
sora-testing-65d76a2b4393f4addb9dc66e0565cb4fd137be71.zip
feat: Development commit
Diffstat (limited to 'Sora/Data/Booru/Post')
-rw-r--r--Sora/Data/Booru/Post/BooruPost.swift27
-rw-r--r--Sora/Data/Booru/Post/BooruPostFileType.swift5
-rw-r--r--Sora/Data/Booru/Post/BooruPostLoadingState.swift5
-rw-r--r--Sora/Data/Booru/Post/BooruPostXMLParser.swift124
4 files changed, 161 insertions, 0 deletions
diff --git a/Sora/Data/Booru/Post/BooruPost.swift b/Sora/Data/Booru/Post/BooruPost.swift
new file mode 100644
index 0000000..e2e043e
--- /dev/null
+++ b/Sora/Data/Booru/Post/BooruPost.swift
@@ -0,0 +1,27 @@
+import Foundation
+
+struct BooruPost: Identifiable, Hashable {
+ let id: String
+ let height: Int
+ let score: String
+ let fileURL: URL
+ let parentID: String
+ let sampleURL: URL
+ let sampleWidth: Int
+ let sampleHeight: Int
+ let previewURL: URL
+ let rating: BooruRating
+ let tags: [String]
+ let width: Int
+ let change: String
+ let md5: String
+ let creatorID: String
+ let hasChildren: Bool
+ let createdAt: Date
+ let status: String
+ let source: String
+ let hasNotes: Bool
+ let hasComments: Bool
+ let previewWidth: Int
+ let previewHeight: Int
+}
diff --git a/Sora/Data/Booru/Post/BooruPostFileType.swift b/Sora/Data/Booru/Post/BooruPostFileType.swift
new file mode 100644
index 0000000..f1f98b7
--- /dev/null
+++ b/Sora/Data/Booru/Post/BooruPostFileType.swift
@@ -0,0 +1,5 @@
+enum BooruPostFileType: String, CaseIterable {
+ case original = "Original"
+ case preview = "Preview"
+ case sample = "Sample"
+}
diff --git a/Sora/Data/Booru/Post/BooruPostLoadingState.swift b/Sora/Data/Booru/Post/BooruPostLoadingState.swift
new file mode 100644
index 0000000..c413ee4
--- /dev/null
+++ b/Sora/Data/Booru/Post/BooruPostLoadingState.swift
@@ -0,0 +1,5 @@
+enum BooruPostLoadingState {
+ case loaded
+ case loadingFile
+ case loadingPreview
+}
diff --git a/Sora/Data/Booru/Post/BooruPostXMLParser.swift b/Sora/Data/Booru/Post/BooruPostXMLParser.swift
new file mode 100644
index 0000000..d316177
--- /dev/null
+++ b/Sora/Data/Booru/Post/BooruPostXMLParser.swift
@@ -0,0 +1,124 @@
+import Foundation
+
+class BooruPostXMLParser: NSObject, XMLParserDelegate {
+ private var posts: [BooruPost] = []
+ private var currentPost: BooruPost?
+ private var parser: XMLParser
+
+ init(data: Data) {
+ parser = XMLParser(data: data)
+
+ super.init()
+
+ parser.delegate = self
+ }
+
+ func parse() -> [BooruPost] {
+ parser.parse()
+
+ return posts
+ }
+
+ func parser(
+ _: XMLParser,
+ didStartElement elementName: String,
+ namespaceURI _: String?,
+ qualifiedName _: String?,
+ 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
+ }
+
+ 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(
+ _: XMLParser,
+ didEndElement elementName: String,
+ namespaceURI _: String?,
+ qualifiedName _: String?
+ ) {
+ if elementName == "post", let post = currentPost {
+ posts.append(post)
+
+ currentPost = nil
+ }
+ }
+
+ #if DEBUG
+ func parser(_: XMLParser, parseErrorOccurred parseError: any Error) {
+ print("parser: \(parseError)")
+ }
+ #endif
+
+ func parseCreatedAt(_ input: String) -> Date? {
+ let dateFormatter = DateFormatter()
+
+ dateFormatter.dateFormat = "EEE MMM dd HH:mm:ss Z yyyy"
+ dateFormatter.locale = Locale(identifier: "en_US_POSIX")
+
+ if let date = dateFormatter.date(from: input) {
+ return date
+ }
+
+ if let timestamp = Double(input) {
+ return Date(timeIntervalSince1970: timestamp)
+ }
+
+ return nil
+ }
+}