summaryrefslogtreecommitdiff
path: root/Sora/Data/Booru/BooruPostXMLParser.swift
blob: 30207bc6bc03347b6fbbc2223eaa555ec3808039 (plain) (blame)
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
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
    }
}