1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
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
}
let hasNotesStr = attributeDict["has_notes"] ?? "false"
let hasCommentsStr = attributeDict["has_comments"] ?? "false"
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: 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: hasNotesStr == "true",
hasComments: hasCommentsStr == "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
}
}
|